diff --git a/.github/ISSUE_TEMPLATE/tracking_issue.md b/.github/ISSUE_TEMPLATE/tracking_issue.md
index 0065960507179..24f4321389713 100644
--- a/.github/ISSUE_TEMPLATE/tracking_issue.md
+++ b/.github/ISSUE_TEMPLATE/tracking_issue.md
@@ -5,8 +5,6 @@ title: Tracking Issue for XXX
 labels: C-tracking-issue
 ---
 <!--
-NOTE: For library features, please use the "Library Tracking Issue" template instead.
-
 Thank you for creating a tracking issue! 📜 Tracking issues are for tracking a
 feature from implementation to stabilisation. Make sure to include the relevant
 RFC for the feature if it has one. Otherwise provide a short summary of the
diff --git a/Cargo.lock b/Cargo.lock
index 9d726b240da93..b2ae22b6abd9b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -427,7 +427,6 @@ dependencies = [
  "remove_dir_all",
  "serde_json",
  "tar",
- "toml",
  "url 2.1.1",
 ]
 
@@ -3551,6 +3550,7 @@ version = "0.0.0"
 dependencies = [
  "rustc_ast",
  "rustc_span",
+ "rustc_target",
  "tracing",
 ]
 
@@ -3568,6 +3568,7 @@ dependencies = [
  "rustc_serialize",
  "rustc_session",
  "rustc_span",
+ "version_check",
 ]
 
 [[package]]
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 9ac05f316f034..00354b42ebb7c 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -127,10 +127,14 @@ where
 }
 
 pub trait CreateTokenStream: sync::Send + sync::Sync {
+    fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream>;
     fn create_token_stream(&self) -> TokenStream;
 }
 
 impl CreateTokenStream for TokenStream {
+    fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream> {
+        panic!("Cannot call `add_trailing_semi` on a `TokenStream`!");
+    }
     fn create_token_stream(&self) -> TokenStream {
         self.clone()
     }
@@ -147,6 +151,13 @@ impl LazyTokenStream {
         LazyTokenStream(Lrc::new(Box::new(inner)))
     }
 
+    /// Extends the captured stream by one token,
+    /// which must be a trailing semicolon. This
+    /// affects the `TokenStream` created by `make_tokenstream`.
+    pub fn add_trailing_semi(&self) -> LazyTokenStream {
+        LazyTokenStream(Lrc::new(self.0.add_trailing_semi()))
+    }
+
     pub fn create_token_stream(&self) -> TokenStream {
         self.0.create_token_stream()
     }
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 4d6afd2fe0d08..1b9ccbd850bee 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -10,9 +10,9 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_session::parse::feature_err;
+use rustc_span::hygiene::ForLoopLoc;
 use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
 use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP};
 use rustc_target::asm;
 use std::collections::hash_map::Entry;
 use std::fmt::Write;
@@ -102,7 +102,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         this.lower_block(body, false),
                         opt_label,
                         hir::LoopSource::Loop,
-                        DUMMY_SP,
                     )
                 }),
                 ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
@@ -454,12 +453,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             self.expr_match(span, scrutinee, arena_vec![self; then_arm, else_arm], desugar);
 
         // `[opt_ident]: loop { ... }`
-        hir::ExprKind::Loop(
-            self.block_expr(self.arena.alloc(match_expr)),
-            opt_label,
-            source,
-            span.with_hi(cond.span.hi()),
-        )
+        hir::ExprKind::Loop(self.block_expr(self.arena.alloc(match_expr)), opt_label, source)
     }
 
     /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
@@ -754,7 +748,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // loop { .. }
         let loop_expr = self.arena.alloc(hir::Expr {
             hir_id: loop_hir_id,
-            kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop, span),
+            kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop),
             span,
             attrs: ThinVec::new(),
         });
@@ -776,7 +770,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
         body: &Expr,
         fn_decl_span: Span,
     ) -> hir::ExprKind<'hir> {
-        let (body_id, generator_option) = self.with_new_scopes(move |this| {
+        // Lower outside new scope to preserve `is_in_loop_condition`.
+        let fn_decl = self.lower_fn_decl(decl, None, false, None);
+
+        self.with_new_scopes(move |this| {
             let prev = this.current_item;
             this.current_item = Some(fn_decl_span);
             let mut generator_kind = None;
@@ -788,13 +785,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let generator_option =
                 this.generator_movability_for_fn(&decl, fn_decl_span, generator_kind, movability);
             this.current_item = prev;
-            (body_id, generator_option)
-        });
-
-        // Lower outside new scope to preserve `is_in_loop_condition`.
-        let fn_decl = self.lower_fn_decl(decl, None, false, None);
-
-        hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, generator_option)
+            hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, generator_option)
+        })
     }
 
     fn generator_movability_for_fn(
@@ -840,8 +832,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
     ) -> hir::ExprKind<'hir> {
         let outer_decl =
             FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
+        // We need to lower the declaration outside the new scope, because we
+        // have to conserve the state of being inside a loop condition for the
+        // closure argument types.
+        let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
 
-        let body_id = self.with_new_scopes(|this| {
+        self.with_new_scopes(move |this| {
             // FIXME(cramertj): allow `async` non-`move` closures with arguments.
             if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
                 struct_span_err!(
@@ -872,15 +868,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 this.expr(fn_decl_span, async_body, ThinVec::new())
             });
-            body_id
-        });
-
-        // We need to lower the declaration outside the new scope, because we
-        // have to conserve the state of being inside a loop condition for the
-        // closure argument types.
-        let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
-
-        hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, None)
+            hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, None)
+        })
     }
 
     /// Destructure the LHS of complex assignments.
@@ -1720,12 +1709,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         );
 
         // `[opt_ident]: loop { ... }`
-        let kind = hir::ExprKind::Loop(
-            loop_block,
-            opt_label,
-            hir::LoopSource::ForLoop,
-            e.span.with_hi(orig_head_span.hi()),
-        );
+        let kind = hir::ExprKind::Loop(loop_block, opt_label, hir::LoopSource::ForLoop);
         let loop_expr = self.arena.alloc(hir::Expr {
             hir_id: self.lower_node_id(e.id),
             kind,
diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml
index 6ea942a2f3018..f447bc7f4efba 100644
--- a/compiler/rustc_ast_pretty/Cargo.toml
+++ b/compiler/rustc_ast_pretty/Cargo.toml
@@ -11,3 +11,4 @@ doctest = false
 tracing = "0.1"
 rustc_span = { path = "../rustc_span" }
 rustc_ast = { path = "../rustc_ast" }
+rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml
index dc0711a5b0f30..5f941a0a650f8 100644
--- a/compiler/rustc_attr/Cargo.toml
+++ b/compiler/rustc_attr/Cargo.toml
@@ -18,3 +18,4 @@ rustc_lexer = { path = "../rustc_lexer" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_session = { path = "../rustc_session" }
 rustc_ast = { path = "../rustc_ast" }
+version_check = "0.9"
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 494880701844e..ead90f23ce7a1 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -10,6 +10,7 @@ use rustc_session::Session;
 use rustc_span::hygiene::Transparency;
 use rustc_span::{symbol::sym, symbol::Symbol, Span};
 use std::num::NonZeroU32;
+use version_check::Version;
 
 pub fn is_builtin_attr(attr: &Attribute) -> bool {
     attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
@@ -66,7 +67,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable)]
 pub enum InlineAttr {
     None,
     Hint,
@@ -74,13 +75,13 @@ pub enum InlineAttr {
     Never,
 }
 
-#[derive(Clone, Encodable, Decodable, Debug)]
+#[derive(Clone, Encodable, Decodable)]
 pub enum InstructionSetAttr {
     ArmA32,
     ArmT32,
 }
 
-#[derive(Clone, Encodable, Decodable, Debug)]
+#[derive(Clone, Encodable, Decodable)]
 pub enum OptimizeAttr {
     None,
     Speed,
@@ -525,26 +526,6 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-struct Version {
-    major: u16,
-    minor: u16,
-    patch: u16,
-}
-
-fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
-    let mut components = s.split('-');
-    let d = components.next()?;
-    if !allow_appendix && components.next().is_some() {
-        return None;
-    }
-    let mut digits = d.splitn(3, '.');
-    let major = digits.next()?.parse().ok()?;
-    let minor = digits.next()?.parse().ok()?;
-    let patch = digits.next().unwrap_or("0").parse().ok()?;
-    Some(Version { major, minor, patch })
-}
-
 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
 /// evaluate individual items.
 pub fn eval_condition(
@@ -574,21 +555,16 @@ pub fn eval_condition(
                     return false;
                 }
             };
-            let min_version = match parse_version(&min_version.as_str(), false) {
+            let min_version = match Version::parse(&min_version.as_str()) {
                 Some(ver) => ver,
                 None => {
-                    sess.span_diagnostic
-                        .struct_span_warn(
-                            *span,
-                            "unknown version literal format, assuming it refers to a future version",
-                        )
-                        .emit();
+                    sess.span_diagnostic.struct_span_err(*span, "invalid version literal").emit();
                     return false;
                 }
             };
             let channel = env!("CFG_RELEASE_CHANNEL");
             let nightly = channel == "nightly" || channel == "dev";
-            let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap();
+            let rustc_version = Version::parse(env!("CFG_RELEASE")).unwrap();
 
             // See https://github.com/rust-lang/rust/issues/64796#issuecomment-625474439 for details
             if nightly { rustc_version > min_version } else { rustc_version >= min_version }
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index f82269c4eee4f..bb6d3f6a0076c 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -12,43 +12,27 @@ use rustc_span::{Span, DUMMY_SP};
 
 pub fn expand_assert<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
-    span: Span,
+    sp: Span,
     tts: TokenStream,
 ) -> Box<dyn MacResult + 'cx> {
-    let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) {
+    let Assert { cond_expr, custom_message } = match parse_assert(cx, sp, tts) {
         Ok(assert) => assert,
         Err(mut err) => {
             err.emit();
-            return DummyResult::any(span);
+            return DummyResult::any(sp);
         }
     };
 
     // `core::panic` and `std::panic` are different macros, so we use call-site
     // context to pick up whichever is currently in scope.
-    let sp = cx.with_call_site_ctxt(span);
+    let sp = cx.with_call_site_ctxt(sp);
 
     let panic_call = if let Some(tokens) = custom_message {
-        let path = if span.rust_2021() {
-            // On edition 2021, we always call `$crate::panic!()`.
-            Path {
-                span: sp,
-                segments: cx
-                    .std_path(&[sym::panic])
-                    .into_iter()
-                    .map(|ident| PathSegment::from_ident(ident))
-                    .collect(),
-                tokens: None,
-            }
-        } else {
-            // Before edition 2021, we call `panic!()` unqualified,
-            // such that it calls either `std::panic!()` or `core::panic!()`.
-            Path::from_ident(Ident::new(sym::panic, sp))
-        };
         // Pass the custom message to panic!().
         cx.expr(
             sp,
             ExprKind::MacCall(MacCall {
-                path,
+                path: Path::from_ident(Ident::new(sym::panic, sp)),
                 args: P(MacArgs::Delimited(
                     DelimSpan::from_single(sp),
                     MacDelimiter::Parenthesis,
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 28efd483c8670..f76bbd8381940 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -5,8 +5,7 @@ use rustc_ast::tokenstream::TokenStream;
 use rustc_ast_pretty::pprust;
 use rustc_expand::base::{self, *};
 use rustc_expand::module::DirectoryOwnership;
-use rustc_parse::parser::{ForceCollect, Parser};
-use rustc_parse::{self, new_parser_from_file};
+use rustc_parse::{self, new_parser_from_file, parser::Parser};
 use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
 use rustc_span::symbol::Symbol;
 use rustc_span::{self, Pos, Span};
@@ -140,7 +139,7 @@ pub fn expand_include<'cx>(
         fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
             let mut ret = SmallVec::new();
             while self.p.token != token::Eof {
-                match self.p.parse_item(ForceCollect::No) {
+                match self.p.parse_item() {
                     Err(mut err) => {
                         err.emit();
                         break;
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index a78d692aaa7fb..700f32e15b952 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -13,7 +13,6 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::{OptLevel, SanitizerSet};
 use rustc_session::Session;
-use rustc_target::spec::StackProbeType;
 
 use crate::attributes;
 use crate::llvm::AttributePlace::Function;
@@ -99,6 +98,12 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
 }
 
 fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+    // Only use stack probes if the target specification indicates that we
+    // should be using stack probes
+    if !cx.sess().target.stack_probes {
+        return;
+    }
+
     // Currently stack probes seem somewhat incompatible with the address
     // sanitizer and thread sanitizer. With asan we're already protected from
     // stack overflow anyway so we don't really need stack probes regardless.
@@ -122,31 +127,19 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
         return;
     }
 
-    let attr_value = match cx.sess().target.stack_probes {
-        StackProbeType::None => None,
-        // Request LLVM to generate the probes inline. If the given LLVM version does not support
-        // this, no probe is generated at all (even if the attribute is specified).
-        StackProbeType::Inline => Some(const_cstr!("inline-asm")),
-        // Flag our internal `__rust_probestack` function as the stack probe symbol.
-        // This is defined in the `compiler-builtins` crate for each architecture.
-        StackProbeType::Call => Some(const_cstr!("__rust_probestack")),
-        // Pick from the two above based on the LLVM version.
-        StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
-            if llvm_util::get_version() < min_llvm_version_for_inline {
-                Some(const_cstr!("__rust_probestack"))
-            } else {
-                Some(const_cstr!("inline-asm"))
-            }
-        }
-    };
-    if let Some(attr_value) = attr_value {
-        llvm::AddFunctionAttrStringValue(
-            llfn,
-            llvm::AttributePlace::Function,
-            const_cstr!("probe-stack"),
-            attr_value,
-        );
-    }
+    llvm::AddFunctionAttrStringValue(
+        llfn,
+        llvm::AttributePlace::Function,
+        const_cstr!("probe-stack"),
+        if llvm_util::get_version() < (11, 0, 1) {
+            // Flag our internal `__rust_probestack` function as the stack probe symbol.
+            // This is defined in the `compiler-builtins` crate for each architecture.
+            const_cstr!("__rust_probestack")
+        } else {
+            // On LLVM 11+, emit inline asm for stack probes instead of a function call.
+            const_cstr!("inline-asm")
+        },
+    );
 }
 
 pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 72e049b6d7469..e51904f308dd4 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -885,22 +885,9 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke
 }
 
 fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
-    fn find_sanitizer_runtime(sess: &Session, filename: &String) -> PathBuf {
-        let session_tlib =
-            filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple());
-        let path = session_tlib.join(&filename);
-        if path.exists() {
-            return session_tlib;
-        } else {
-            let default_sysroot = filesearch::get_or_default_sysroot();
-            let default_tlib = filesearch::make_target_lib_path(
-                &default_sysroot,
-                sess.opts.target_triple.triple(),
-            );
-            return default_tlib;
-        }
-    }
-
+    let default_sysroot = filesearch::get_or_default_sysroot();
+    let default_tlib =
+        filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.triple());
     let channel = option_env!("CFG_RELEASE_CHANNEL")
         .map(|channel| format!("-{}", channel))
         .unwrap_or_default();
@@ -911,11 +898,10 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
             // LLVM will link to `@rpath/*.dylib`, so we need to specify an
             // rpath to the library as well (the rpath should be absolute, see
             // PR #41352 for details).
-            let filename = format!("rustc{}_rt.{}", channel, name);
-            let path = find_sanitizer_runtime(&sess, &filename);
-            let rpath = path.to_str().expect("non-utf8 component in path");
+            let libname = format!("rustc{}_rt.{}", channel, name);
+            let rpath = default_tlib.to_str().expect("non-utf8 component in path");
             linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
-            linker.link_dylib(Symbol::intern(&filename));
+            linker.link_dylib(Symbol::intern(&libname));
         }
         "aarch64-fuchsia"
         | "aarch64-unknown-linux-gnu"
@@ -923,7 +909,7 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
         | "x86_64-unknown-freebsd"
         | "x86_64-unknown-linux-gnu" => {
             let filename = format!("librustc{}_rt.{}.a", channel, name);
-            let path = find_sanitizer_runtime(&sess, &filename).join(&filename);
+            let path = default_tlib.join(&filename);
             linker.link_whole_rlib(&path);
         }
         _ => {}
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index b205ea9cf6c9d..2ce5fe5ad504b 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -783,7 +783,7 @@ impl CrateInfo {
     }
 }
 
-pub fn provide(providers: &mut Providers) {
+pub fn provide_both(providers: &mut Providers) {
     providers.backend_optimization_level = |tcx, cratenum| {
         let for_speed = match tcx.sess.opts.optimize {
             // If globally no optimisation is done, #[optimize] has no effect.
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 0307117e1c8b2..e27eac3f69b00 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -160,12 +160,13 @@ pub struct CodegenResults {
 
 pub fn provide(providers: &mut Providers) {
     crate::back::symbol_export::provide(providers);
-    crate::base::provide(providers);
+    crate::base::provide_both(providers);
     crate::target_features::provide(providers);
 }
 
 pub fn provide_extern(providers: &mut Providers) {
     crate::back::symbol_export::provide_extern(providers);
+    crate::base::provide_both(providers);
 }
 
 /// Checks if the given filename ends with the `.rcgu.o` extension that `rustc`
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index fd0ff5b66e607..b1e372afc6501 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -119,7 +119,7 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
                 )
             );
             if is_consume {
-                let base_ty = place_base.ty(self.fx.mir, cx.tcx());
+                let base_ty = mir::PlaceRef::ty(&place_base, self.fx.mir, cx.tcx());
                 let base_ty = self.fx.monomorphize(base_ty);
 
                 // ZSTs don't require any actual memory access.
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 66d9d1a1e0c49..958e4ebd078b6 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -506,7 +506,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
     pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> {
         let tcx = self.cx.tcx();
-        let place_ty = place_ref.ty(self.mir, tcx);
+        let place_ty = mir::PlaceRef::ty(&place_ref, self.mir, tcx);
         self.monomorphize(place_ty.ty)
     }
 }
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index ad62e3c9fc8f4..1cfbce2355e3a 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -8,6 +8,7 @@
 use super::iterate::reverse_post_order;
 use super::ControlFlowGraph;
 use rustc_index::vec::{Idx, IndexVec};
+use std::borrow::BorrowMut;
 use std::cmp::Ordering;
 
 #[cfg(test)]
@@ -19,17 +20,22 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
     dominators_given_rpo(graph, &rpo)
 }
 
-fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Dominators<G::Node> {
-    let start_node = graph.start_node();
+fn dominators_given_rpo<G: ControlFlowGraph + BorrowMut<G>>(
+    mut graph: G,
+    rpo: &[G::Node],
+) -> Dominators<G::Node> {
+    let start_node = graph.borrow().start_node();
     assert_eq!(rpo[0], start_node);
 
     // compute the post order index (rank) for each node
-    let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
+    let mut post_order_rank: IndexVec<G::Node, usize> =
+        (0..graph.borrow().num_nodes()).map(|_| 0).collect();
     for (index, node) in rpo.iter().rev().cloned().enumerate() {
         post_order_rank[node] = index;
     }
 
-    let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes());
+    let mut immediate_dominators: IndexVec<G::Node, Option<G::Node>> =
+        (0..graph.borrow().num_nodes()).map(|_| None).collect();
     immediate_dominators[start_node] = Some(start_node);
 
     let mut changed = true;
@@ -38,7 +44,7 @@ fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Domin
 
         for &node in &rpo[1..] {
             let mut new_idom = None;
-            for pred in graph.predecessors(node) {
+            for pred in graph.borrow_mut().predecessors(node) {
                 if immediate_dominators[pred].is_some() {
                     // (*) dominators for `pred` have been calculated
                     new_idom = Some(if let Some(new_idom) = new_idom {
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 3850c9b74fddc..579eb1cb7da66 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -552,7 +552,6 @@ pub fn hash_stable_hashmap<HCX, K, V, R, SK, F>(
 
 /// A vector container that makes sure that its items are hashed in a stable
 /// order.
-#[derive(Debug)]
 pub struct StableVec<T>(Vec<T>);
 
 impl<T> StableVec<T> {
diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs
index 30f659c2f71bd..7f9e4160fcdde 100644
--- a/compiler/rustc_data_structures/src/steal.rs
+++ b/compiler/rustc_data_structures/src/steal.rs
@@ -21,7 +21,6 @@ use crate::sync::{MappedReadGuard, ReadGuard, RwLock};
 /// -- once the value is stolen -- it will never be read from again.
 //
 // FIXME(#41710): what is the best way to model linear queries?
-#[derive(Debug)]
 pub struct Steal<T> {
     value: RwLock<Option<T>>,
 }
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 5d398935ce815..16913dbb1abf8 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -20,7 +20,7 @@ use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{struct_span_err, Applicability, PResult};
 use rustc_feature::Features;
-use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser};
+use rustc_parse::parser::{AttemptLocalParseRecovery, Parser};
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -913,7 +913,7 @@ pub fn parse_ast_fragment<'a>(
     Ok(match kind {
         AstFragmentKind::Items => {
             let mut items = SmallVec::new();
-            while let Some(item) = this.parse_item(ForceCollect::No)? {
+            while let Some(item) = this.parse_item()? {
                 items.push(item);
             }
             AstFragment::Items(items)
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
index f4fcaf5c0a452..643305f153ccd 100644
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ b/compiler/rustc_expand/src/parse/tests.rs
@@ -8,7 +8,6 @@ use rustc_ast::{self as ast, PatKind};
 use rustc_ast_pretty::pprust::item_to_string;
 use rustc_errors::PResult;
 use rustc_parse::new_parser_from_source_str;
-use rustc_parse::parser::ForceCollect;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::FilePathMapping;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -30,7 +29,7 @@ fn parse_item_from_source_str(
     source: String,
     sess: &ParseSess,
 ) -> PResult<'_, Option<P<ast::Item>>> {
-    new_parser_from_source_str(sess, name, source).parse_item(ForceCollect::No)
+    new_parser_from_source_str(sess, name, source).parse_item()
 }
 
 // Produces a `rustc_span::span`.
@@ -45,7 +44,7 @@ fn string_to_expr(source_str: String) -> P<ast::Expr> {
 
 /// Parses a string, returns an item.
 fn string_to_item(source_str: String) -> Option<P<ast::Item>> {
-    with_error_checking_parse(source_str, &sess(), |p| p.parse_item(ForceCollect::No))
+    with_error_checking_parse(source_str, &sess(), |p| p.parse_item())
 }
 
 #[should_panic]
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 6779734cfc176..02129e9b5e548 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -9,7 +9,6 @@ use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability, ErrorReported};
 use rustc_lexer::is_ident;
 use rustc_parse::nt_to_tokenstream;
-use rustc_parse::parser::ForceCollect;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
 
@@ -118,7 +117,7 @@ impl MultiItemModifier for ProcMacroDerive {
         let mut items = vec![];
 
         loop {
-            match parser.parse_item(ForceCollect::No) {
+            match parser.parse_item() {
                 Ok(None) => break,
                 Ok(Some(item)) => {
                     if is_stmt {
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index cd3c8fded633f..b9d1597c4c65f 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -36,7 +36,7 @@ macro_rules! declare_features {
             ),+];
 
         /// A set of features to be used by later passes.
-        #[derive(Clone, Default, Debug)]
+        #[derive(Clone, Default)]
         pub struct Features {
             /// `#![feature]` attrs for language features, for error reporting.
             pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 6a1b9bdbb9491..d5ade86593e56 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -419,10 +419,6 @@ impl Definitions {
     pub fn add_parent_module_of_macro_def(&mut self, expn_id: ExpnId, module: DefId) {
         self.parent_modules_of_macro_defs.insert(expn_id, module);
     }
-
-    pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
-        self.def_id_to_hir_id.iter_enumerated().map(|(k, _)| k)
-    }
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 35170fa7c1d02..3673e5c8bf3a5 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1617,9 +1617,7 @@ pub enum ExprKind<'hir> {
     /// A conditionless loop (can be exited with `break`, `continue`, or `return`).
     ///
     /// I.e., `'label: loop { <block> }`.
-    ///
-    /// The `Span` is the loop header (`for x in y`/`while let pat = expr`).
-    Loop(&'hir Block<'hir>, Option<Label>, LoopSource, Span),
+    Loop(&'hir Block<'hir>, Option<Label>, LoopSource),
     /// A `match` block, with a source that indicates whether or not it is
     /// the result of a desugaring, and if so, which kind.
     Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource),
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 6c1bee2335a00..8707a84a98fcc 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -1151,7 +1151,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             visitor.visit_expr(then);
             walk_list!(visitor, visit_expr, else_opt);
         }
-        ExprKind::Loop(ref block, ref opt_label, _, _) => {
+        ExprKind::Loop(ref block, ref opt_label, _) => {
             walk_list!(visitor, visit_label, opt_label);
             visitor.visit_block(block);
         }
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 26ce30cb51177..e82ea310b8cc5 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -67,7 +67,7 @@ macro_rules! language_item_table {
             }
         }
 
-        #[derive(HashStable_Generic, Debug)]
+        #[derive(HashStable_Generic)]
         pub struct LanguageItems {
             /// Mappings from lang items to their possibly found `DefId`s.
             /// The index corresponds to the order in `LangItem`.
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index f1c2a6b7e6e85..a3ab1d96e1dfe 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1396,7 +1396,7 @@ impl<'a> State<'a> {
             hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
                 self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e));
             }
-            hir::ExprKind::Loop(ref blk, opt_label, _, _) => {
+            hir::ExprKind::Loop(ref blk, opt_label, _) => {
                 if let Some(label) = opt_label {
                     self.print_ident(label.ident);
                     self.word_space(":");
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 7031234e1089d..ead2512d3b2a5 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -1017,6 +1017,13 @@ pub fn start_codegen<'tcx>(
     tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
     tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
 
+    // We assume that no queries are run past here. If there are new queries
+    // after this point, they'll show up as "<unknown>" in self-profiling data.
+    {
+        let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings");
+        tcx.alloc_self_profile_query_strings();
+    }
+
     info!("Post-codegen\n{:?}", tcx.debug_stats());
 
     if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index ac6b6d0311545..9c49f926d417b 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -417,19 +417,9 @@ impl Compiler {
         let queries = Queries::new(&self);
         let ret = f(&queries);
 
-        // NOTE: intentionally does not compute the global context if it hasn't been built yet,
-        // since that likely means there was a parse error.
-        if let Some(Ok(gcx)) = &mut *queries.global_ctxt.result.borrow_mut() {
-            // We assume that no queries are run past here. If there are new queries
-            // after this point, they'll show up as "<unknown>" in self-profiling data.
-            {
-                let _prof_timer =
-                    queries.session().prof.generic_activity("self_profile_alloc_query_strings");
-                gcx.enter(|tcx| tcx.alloc_self_profile_query_strings());
-            }
-
-            if self.session().opts.debugging_opts.query_stats {
-                gcx.print_stats();
+        if self.session().opts.debugging_opts.query_stats {
+            if let Ok(gcx) = queries.global_ctxt() {
+                gcx.peek_mut().print_stats();
             }
         }
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index b37660e4a90d3..8cdb33ea3175f 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -96,24 +96,18 @@ fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
 
 impl EarlyLintPass for WhileTrue {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
-        if let ast::ExprKind::While(cond, _, label) = &e.kind {
+        if let ast::ExprKind::While(cond, ..) = &e.kind {
             if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
                 if let ast::LitKind::Bool(true) = lit.kind {
                     if !lit.span.from_expansion() {
                         let msg = "denote infinite loops with `loop { ... }`";
-                        let condition_span = e.span.with_hi(cond.span.hi());
+                        let condition_span = cx.sess.source_map().guess_head_span(e.span);
                         cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
                             lint.build(msg)
                                 .span_suggestion_short(
                                     condition_span,
                                     "use `loop`",
-                                    format!(
-                                        "{}loop",
-                                        label.map_or_else(String::new, |label| format!(
-                                            "{}: ",
-                                            label.ident,
-                                        ))
-                                    ),
+                                    "loop".to_owned(),
                                     Applicability::MachineApplicable,
                                 )
                                 .emit();
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index b17765998807f..3971a3099823f 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -387,7 +387,7 @@ impl LintStore {
                 Some(new_name.to_owned()),
             ),
             Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
-                format!("lint `{}` has been removed: {}", complete_name, reason),
+                format!("lint `{}` has been removed: `{}`", complete_name, reason),
                 None,
             ),
             None => match self.lint_groups.get(&*complete_name) {
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index e36af2349360f..08c147ec3ac3f 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -379,9 +379,17 @@ pub fn check_ast_crate<T: EarlyLintPass>(
     // All of the buffered lints should have been emitted at this point.
     // If not, that means that we somehow buffered a lint for a node id
     // that was not lint-checked (perhaps it doesn't exist?). This is a bug.
-    for (_id, lints) in buffered.map {
-        for early_lint in lints {
-            sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
+    //
+    // Rustdoc runs everybody-loops before the early lints and removes
+    // function bodies, so it's totally possible for linted
+    // node ids to not exist (e.g., macros defined within functions for the
+    // unused_macro lint) anymore. So we only run this check
+    // when we're not in rustdoc mode. (see issue #47639)
+    if !sess.opts.actually_rustdoc {
+        for (_id, lints) in buffered.map {
+            for early_lint in lints {
+                sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
+            }
         }
     }
 }
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 18cd25e5d2aa3..fc8f84461f991 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -311,7 +311,8 @@ impl<'s> LintLevelsBuilder<'s> {
                                     |lint| {
                                         let msg = format!(
                                             "lint name `{}` is deprecated \
-                                             and may not have an effect in the future.",
+                                             and may not have an effect in the future. \
+                                             Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
                                             name
                                         );
                                         lint.build(&msg)
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 658372ac336a8..20052ad9bfcbd 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -238,22 +238,41 @@ declare_lint! {
     ///
     /// ```rust,compile_fail
     /// #![allow(unconditional_panic)]
-    /// const C: i32 = 1/0;
+    /// let x: &'static i32 = &(1 / 0);
     /// ```
     ///
     /// {{produces}}
     ///
     /// ### Explanation
     ///
-    /// This lint detects constants that fail to evaluate. Allowing the lint will accept the
-    /// constant declaration, but any use of this constant will still lead to a hard error. This is
-    /// a future incompatibility lint; the plan is to eventually entirely forbid even declaring
-    /// constants that cannot be evaluated.  See [issue #71800] for more details.
+    /// This lint detects code that is very likely incorrect. If this lint is
+    /// allowed, then the code will not be evaluated at compile-time, and
+    /// instead continue to generate code to evaluate at runtime, which may
+    /// panic during runtime.
     ///
-    /// [issue #71800]: https://github.com/rust-lang/rust/issues/71800
+    /// Note that this lint may trigger in either inside or outside of a
+    /// [const context]. Outside of a [const context], the compiler can
+    /// sometimes evaluate an expression at compile-time in order to generate
+    /// more efficient code. As the compiler becomes better at doing this, it
+    /// needs to decide what to do when it encounters code that it knows for
+    /// certain will panic or is otherwise incorrect. Making this a hard error
+    /// would prevent existing code that exhibited this behavior from
+    /// compiling, breaking backwards-compatibility. However, this is almost
+    /// certainly incorrect code, so this is a deny-by-default lint. For more
+    /// details, see [RFC 1229] and [issue #28238].
+    ///
+    /// Note that there are several other more specific lints associated with
+    /// compile-time evaluation, such as [`arithmetic_overflow`],
+    /// [`unconditional_panic`].
+    ///
+    /// [const context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
+    /// [RFC 1229]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md
+    /// [issue #28238]: https://github.com/rust-lang/rust/issues/28238
+    /// [`arithmetic_overflow`]: deny-by-default.html#arithmetic-overflow
+    /// [`unconditional_panic`]: deny-by-default.html#unconditional-panic
     pub CONST_ERR,
     Deny,
-    "constant evaluation encountered erroneous expression",
+    "constant evaluation detected erroneous expression",
     report_in_external_macro
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index e3c3539079857..115569fc60d9f 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -618,6 +618,43 @@ impl MetadataBlob {
     }
 }
 
+impl EntryKind {
+    fn def_kind(&self) -> DefKind {
+        match *self {
+            EntryKind::AnonConst(..) => DefKind::AnonConst,
+            EntryKind::Const(..) => DefKind::Const,
+            EntryKind::AssocConst(..) => DefKind::AssocConst,
+            EntryKind::ImmStatic
+            | EntryKind::MutStatic
+            | EntryKind::ForeignImmStatic
+            | EntryKind::ForeignMutStatic => DefKind::Static,
+            EntryKind::Struct(_, _) => DefKind::Struct,
+            EntryKind::Union(_, _) => DefKind::Union,
+            EntryKind::Fn(_) | EntryKind::ForeignFn(_) => DefKind::Fn,
+            EntryKind::AssocFn(_) => DefKind::AssocFn,
+            EntryKind::Type => DefKind::TyAlias,
+            EntryKind::TypeParam => DefKind::TyParam,
+            EntryKind::ConstParam => DefKind::ConstParam,
+            EntryKind::OpaqueTy => DefKind::OpaqueTy,
+            EntryKind::AssocType(_) => DefKind::AssocTy,
+            EntryKind::Mod(_) => DefKind::Mod,
+            EntryKind::Variant(_) => DefKind::Variant,
+            EntryKind::Trait(_) => DefKind::Trait,
+            EntryKind::TraitAlias => DefKind::TraitAlias,
+            EntryKind::Enum(..) => DefKind::Enum,
+            EntryKind::MacroDef(_) => DefKind::Macro(MacroKind::Bang),
+            EntryKind::ProcMacro(kind) => DefKind::Macro(kind),
+            EntryKind::ForeignType => DefKind::ForeignTy,
+            EntryKind::Impl(_) => DefKind::Impl,
+            EntryKind::Closure => DefKind::Closure,
+            EntryKind::ForeignMod => DefKind::ForeignMod,
+            EntryKind::GlobalAsm => DefKind::GlobalAsm,
+            EntryKind::Field => DefKind::Field,
+            EntryKind::Generator(_) => DefKind::Generator,
+        }
+    }
+}
+
 impl CrateRoot<'_> {
     crate fn is_proc_macro_crate(&self) -> bool {
         self.proc_macro_data.is_some()
@@ -648,6 +685,21 @@ impl CrateRoot<'_> {
 }
 
 impl<'a, 'tcx> CrateMetadataRef<'a> {
+    fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> {
+        self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
+    }
+
+    fn kind(&self, item_id: DefIndex) -> EntryKind {
+        self.maybe_kind(item_id).unwrap_or_else(|| {
+            bug!(
+                "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
+                item_id,
+                self.root.name,
+                self.cnum,
+            )
+        })
+    }
+
     fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
         // DefIndex's in root.proc_macro_data have a one-to-one correspondence
         // with items in 'raw_proc_macros'.
@@ -684,30 +736,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.try_item_ident(item_index, sess).unwrap()
     }
 
-    fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> {
-        self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
-    }
-
-    fn kind(&self, item_id: DefIndex) -> EntryKind {
-        self.maybe_kind(item_id).unwrap_or_else(|| {
-            bug!(
-                "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
-                item_id,
-                self.root.name,
-                self.cnum,
-            )
-        })
-    }
-
-    fn def_kind(&self, item_id: DefIndex) -> DefKind {
-        self.root.tables.def_kind.get(self, item_id).map(|k| k.decode(self)).unwrap_or_else(|| {
-            bug!(
-                "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}",
-                item_id,
-                self.root.name,
-                self.cnum,
-            )
-        })
+    fn def_kind(&self, index: DefIndex) -> DefKind {
+        self.kind(index).def_kind()
     }
 
     fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 828c025d38d0b..17ce4a5f9520e 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -130,7 +130,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     is_foreign_item => { cdata.is_foreign_item(def_id.index) }
     static_mutability => { cdata.static_mutability(def_id.index) }
     generator_kind => { cdata.generator_kind(def_id.index) }
-    opt_def_kind => { Some(cdata.def_kind(def_id.index)) }
+    def_kind => { cdata.def_kind(def_id.index) }
     def_span => { cdata.get_span(def_id.index, &tcx.sess) }
     def_ident_span => {
         cdata.try_item_ident(def_id.index, &tcx.sess).ok().map(|ident| ident.span)
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 3961adacecae8..5e2674254b295 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1,12 +1,13 @@
 use crate::rmeta::table::{FixedSizeEncoding, TableBuilder};
 use crate::rmeta::*;
 
+use rustc_ast as ast;
 use rustc_data_structures::fingerprint::{Fingerprint, FingerprintEncoder};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::{join, Lrc};
 use rustc_hir as hir;
-use rustc_hir::def::{CtorOf, DefKind};
+use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
@@ -436,7 +437,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
     fn encode_info_for_items(&mut self) {
         let krate = self.tcx.hir().krate();
-        self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module);
+        self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module, &krate.item.attrs);
 
         // Proc-macro crates only export proc-macro items, which are looked
         // up using `proc_macro_data`
@@ -579,7 +580,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         // Encode the items.
         i = self.position();
-        self.encode_def_ids();
         self.encode_info_for_items();
         let item_bytes = self.position() - i;
 
@@ -715,107 +715,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 }
 
-fn should_encode_visibility(def_kind: DefKind) -> bool {
-    match def_kind {
-        DefKind::Mod
-        | DefKind::Struct
-        | DefKind::Union
-        | DefKind::Enum
-        | DefKind::Variant
-        | DefKind::Trait
-        | DefKind::TyAlias
-        | DefKind::ForeignTy
-        | DefKind::TraitAlias
-        | DefKind::AssocTy
-        | DefKind::Fn
-        | DefKind::Const
-        | DefKind::Static
-        | DefKind::Ctor(..)
-        | DefKind::AssocFn
-        | DefKind::AssocConst
-        | DefKind::Macro(..)
-        | DefKind::Use
-        | DefKind::ForeignMod
-        | DefKind::OpaqueTy
-        | DefKind::Impl
-        | DefKind::Field => true,
-        DefKind::TyParam
-        | DefKind::ConstParam
-        | DefKind::LifetimeParam
-        | DefKind::AnonConst
-        | DefKind::GlobalAsm
-        | DefKind::Closure
-        | DefKind::Generator
-        | DefKind::ExternCrate => false,
-    }
-}
-
-fn should_encode_stability(def_kind: DefKind) -> bool {
-    match def_kind {
-        DefKind::Mod
-        | DefKind::Ctor(..)
-        | DefKind::Variant
-        | DefKind::Field
-        | DefKind::Struct
-        | DefKind::AssocTy
-        | DefKind::AssocFn
-        | DefKind::AssocConst
-        | DefKind::TyParam
-        | DefKind::ConstParam
-        | DefKind::Static
-        | DefKind::Const
-        | DefKind::Fn
-        | DefKind::ForeignMod
-        | DefKind::TyAlias
-        | DefKind::OpaqueTy
-        | DefKind::Enum
-        | DefKind::Union
-        | DefKind::Impl
-        | DefKind::Trait
-        | DefKind::TraitAlias
-        | DefKind::Macro(..)
-        | DefKind::ForeignTy => true,
-        DefKind::Use
-        | DefKind::LifetimeParam
-        | DefKind::AnonConst
-        | DefKind::GlobalAsm
-        | DefKind::Closure
-        | DefKind::Generator
-        | DefKind::ExternCrate => false,
-    }
-}
-
 impl EncodeContext<'a, 'tcx> {
-    fn encode_def_ids(&mut self) {
-        if self.is_proc_macro {
-            return;
-        }
-        let tcx = self.tcx;
-        let hir = tcx.hir();
-        for local_id in hir.iter_local_def_id() {
-            let def_id = local_id.to_def_id();
-            let def_kind = tcx.opt_def_kind(local_id);
-            let def_kind = if let Some(def_kind) = def_kind { def_kind } else { continue };
-            record!(self.tables.def_kind[def_id] <- match def_kind {
-                // Replace Ctor by the enclosing object to avoid leaking details in children crates.
-                DefKind::Ctor(CtorOf::Struct, _) => DefKind::Struct,
-                DefKind::Ctor(CtorOf::Variant, _) => DefKind::Variant,
-                def_kind => def_kind,
-            });
-            record!(self.tables.span[def_id] <- tcx.def_span(def_id));
-            record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
-            record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
-            if should_encode_visibility(def_kind) {
-                record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
-            }
-            if should_encode_stability(def_kind) {
-                self.encode_stability(def_id);
-                self.encode_const_stability(def_id);
-                self.encode_deprecation(def_id);
-            }
-        }
-    }
-
     fn encode_variances_of(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_variances_of({:?})", def_id);
         record!(self.tables.variances[def_id] <- &self.tcx.variances_of(def_id)[..]);
@@ -840,11 +740,17 @@ impl EncodeContext<'a, 'tcx> {
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+        record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
+        record!(self.tables.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]);
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
         record!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
             assert!(f.did.is_local());
             f.did.index
         }));
         self.encode_ident_span(def_id, variant.ident);
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
@@ -874,6 +780,10 @@ impl EncodeContext<'a, 'tcx> {
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+        record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -889,7 +799,7 @@ impl EncodeContext<'a, 'tcx> {
         self.encode_mir_for_ctfe(def_id.expect_local());
     }
 
-    fn encode_info_for_mod(&mut self, id: hir::HirId, md: &hir::Mod<'_>) {
+    fn encode_info_for_mod(&mut self, id: hir::HirId, md: &hir::Mod<'_>, attrs: &[ast::Attribute]) {
         let tcx = self.tcx;
         let local_def_id = tcx.hir().local_def_id(id);
         let def_id = local_def_id.to_def_id();
@@ -922,6 +832,9 @@ impl EncodeContext<'a, 'tcx> {
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+        record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
+        record!(self.tables.attributes[def_id] <- attrs);
         if self.is_proc_macro {
             record!(self.tables.children[def_id] <- &[]);
         } else {
@@ -929,6 +842,8 @@ impl EncodeContext<'a, 'tcx> {
                 tcx.hir().local_def_id(item_id.id).local_def_index
             }));
         }
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
     }
 
     fn encode_field(
@@ -937,14 +852,24 @@ impl EncodeContext<'a, 'tcx> {
         variant_index: VariantIdx,
         field_index: usize,
     ) {
+        let tcx = self.tcx;
         let variant = &adt_def.variants[variant_index];
         let field = &variant.fields[field_index];
 
         let def_id = field.did;
         debug!("EncodeContext::encode_field({:?})", def_id);
 
+        let variant_id = tcx.hir().local_def_id_to_hir_id(variant.def_id.expect_local());
+        let variant_data = tcx.hir().expect_variant_data(variant_id);
+
         record!(self.tables.kind[def_id] <- EntryKind::Field);
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+        record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
+        record!(self.tables.attributes[def_id] <- variant_data.fields()[field_index].attrs);
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
         self.encode_ident_span(def_id, field.ident);
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         self.encode_generics(def_id);
         self.encode_explicit_predicates(def_id);
@@ -964,6 +889,11 @@ impl EncodeContext<'a, 'tcx> {
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data), adt_def.repr));
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+        record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -1025,25 +955,29 @@ impl EncodeContext<'a, 'tcx> {
             hir::Defaultness::Final => span_bug!(ast_item.span, "traits cannot have final items"),
         };
 
-        match trait_item.kind {
+        record!(self.tables.kind[def_id] <- match trait_item.kind {
             ty::AssocKind::Const => {
                 let rendered = rustc_hir_pretty::to_string(
                     &(&self.tcx.hir() as &dyn intravisit::Map<'_>),
-                    |s| s.print_trait_item(ast_item),
+                    |s| s.print_trait_item(ast_item)
                 );
                 let rendered_const = self.lazy(RenderedConst(rendered));
 
-                record!(self.tables.kind[def_id] <- EntryKind::AssocConst(
+                EntryKind::AssocConst(
                     container,
                     Default::default(),
                     rendered_const,
-                ));
+                )
             }
             ty::AssocKind::Fn => {
                 let fn_data = if let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind {
                     let param_names = match *m {
-                        hir::TraitFn::Required(ref names) => self.encode_fn_param_names(names),
-                        hir::TraitFn::Provided(body) => self.encode_fn_param_names_for_body(body),
+                        hir::TraitFn::Required(ref names) => {
+                            self.encode_fn_param_names(names)
+                        }
+                        hir::TraitFn::Provided(body) => {
+                            self.encode_fn_param_names_for_body(body)
+                        }
                     };
                     FnData {
                         asyncness: m_sig.header.asyncness,
@@ -1053,18 +987,24 @@ impl EncodeContext<'a, 'tcx> {
                 } else {
                     bug!()
                 };
-                record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
+                EntryKind::AssocFn(self.lazy(AssocFnData {
                     fn_data,
                     container,
                     has_self: trait_item.fn_has_self_parameter,
-                })));
+                }))
             }
             ty::AssocKind::Type => {
                 self.encode_explicit_item_bounds(def_id);
-                record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
+                EntryKind::AssocType(container)
             }
-        }
+        });
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+        record!(self.tables.span[def_id] <- ast_item.span);
+        record!(self.tables.attributes[def_id] <- ast_item.attrs);
         self.encode_ident_span(def_id, ast_item.ident);
+        self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
+        self.encode_deprecation(def_id);
         match trait_item.kind {
             ty::AssocKind::Const | ty::AssocKind::Fn => {
                 self.encode_item_type(def_id);
@@ -1128,16 +1068,15 @@ impl EncodeContext<'a, 'tcx> {
             }
         };
 
-        match impl_item.kind {
+        record!(self.tables.kind[def_id] <- match impl_item.kind {
             ty::AssocKind::Const => {
                 if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind {
                     let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id);
 
-                    record!(self.tables.kind[def_id] <- EntryKind::AssocConst(
+                    EntryKind::AssocConst(
                         container,
                         qualifs,
                         self.encode_rendered_const_for_body(body_id))
-                    );
                 } else {
                     bug!()
                 }
@@ -1152,17 +1091,21 @@ impl EncodeContext<'a, 'tcx> {
                 } else {
                     bug!()
                 };
-                record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
+                EntryKind::AssocFn(self.lazy(AssocFnData {
                     fn_data,
                     container,
                     has_self: impl_item.fn_has_self_parameter,
-                })));
+                }))
             }
-            ty::AssocKind::Type => {
-                record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
-            }
-        }
+            ty::AssocKind::Type => EntryKind::AssocType(container)
+        });
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+        record!(self.tables.span[def_id] <- ast_item.span);
+        record!(self.tables.attributes[def_id] <- ast_item.attrs);
         self.encode_ident_span(def_id, impl_item.ident);
+        self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
+        self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if impl_item.kind == ty::AssocKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -1292,12 +1235,15 @@ impl EncodeContext<'a, 'tcx> {
 
         self.encode_ident_span(def_id, item.ident);
 
-        let entry_kind = match item.kind {
+        record!(self.tables.kind[def_id] <- match item.kind {
             hir::ItemKind::Static(_, hir::Mutability::Mut, _) => EntryKind::MutStatic,
             hir::ItemKind::Static(_, hir::Mutability::Not, _) => EntryKind::ImmStatic,
             hir::ItemKind::Const(_, body_id) => {
                 let qualifs = self.tcx.at(item.span).mir_const_qualif(def_id);
-                EntryKind::Const(qualifs, self.encode_rendered_const_for_body(body_id))
+                EntryKind::Const(
+                    qualifs,
+                    self.encode_rendered_const_for_body(body_id)
+                )
             }
             hir::ItemKind::Fn(ref sig, .., body) => {
                 let data = FnData {
@@ -1309,7 +1255,7 @@ impl EncodeContext<'a, 'tcx> {
                 EntryKind::Fn(self.lazy(data))
             }
             hir::ItemKind::Mod(ref m) => {
-                return self.encode_info_for_mod(item.hir_id, m);
+                return self.encode_info_for_mod(item.hir_id, m, &item.attrs);
             }
             hir::ItemKind::ForeignMod { .. } => EntryKind::ForeignMod,
             hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm,
@@ -1326,61 +1272,61 @@ impl EncodeContext<'a, 'tcx> {
                 // Encode def_ids for each field and method
                 // for methods, write all the stuff get_trait_method
                 // needs to know
-                let ctor = struct_def
-                    .ctor_hir_id()
-                    .map(|ctor_hir_id| self.tcx.hir().local_def_id(ctor_hir_id).local_def_index);
-
-                EntryKind::Struct(
-                    self.lazy(VariantData {
-                        ctor_kind: variant.ctor_kind,
-                        discr: variant.discr,
-                        ctor,
-                        is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-                    }),
-                    adt_def.repr,
-                )
+                let ctor = struct_def.ctor_hir_id().map(|ctor_hir_id| {
+                    self.tcx.hir().local_def_id(ctor_hir_id).local_def_index
+                });
+
+                EntryKind::Struct(self.lazy(VariantData {
+                    ctor_kind: variant.ctor_kind,
+                    discr: variant.discr,
+                    ctor,
+                    is_non_exhaustive: variant.is_field_list_non_exhaustive(),
+                }), adt_def.repr)
             }
             hir::ItemKind::Union(..) => {
                 let adt_def = self.tcx.adt_def(def_id);
                 let variant = adt_def.non_enum_variant();
 
-                EntryKind::Union(
-                    self.lazy(VariantData {
-                        ctor_kind: variant.ctor_kind,
-                        discr: variant.discr,
-                        ctor: None,
-                        is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-                    }),
-                    adt_def.repr,
-                )
+                EntryKind::Union(self.lazy(VariantData {
+                    ctor_kind: variant.ctor_kind,
+                    discr: variant.discr,
+                    ctor: None,
+                    is_non_exhaustive: variant.is_field_list_non_exhaustive(),
+                }), adt_def.repr)
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => {
                 let trait_ref = self.tcx.impl_trait_ref(def_id);
                 let polarity = self.tcx.impl_polarity(def_id);
                 let parent = if let Some(trait_ref) = trait_ref {
                     let trait_def = self.tcx.trait_def(trait_ref.def_id);
-                    trait_def.ancestors(self.tcx, def_id).ok().and_then(|mut an| {
-                        an.nth(1).and_then(|node| match node {
-                            specialization_graph::Node::Impl(parent) => Some(parent),
-                            _ => None,
-                        })
-                    })
+                    trait_def.ancestors(self.tcx, def_id).ok()
+                        .and_then(|mut an| an.nth(1).and_then(|node| {
+                            match node {
+                                specialization_graph::Node::Impl(parent) => Some(parent),
+                                _ => None,
+                            }
+                        }))
                 } else {
                     None
                 };
 
                 // if this is an impl of `CoerceUnsized`, create its
                 // "unsized info", else just store None
-                let coerce_unsized_info = trait_ref.and_then(|t| {
-                    if Some(t.def_id) == self.tcx.lang_items().coerce_unsized_trait() {
-                        Some(self.tcx.at(item.span).coerce_unsized_info(def_id))
-                    } else {
-                        None
-                    }
-                });
+                let coerce_unsized_info =
+                    trait_ref.and_then(|t| {
+                        if Some(t.def_id) == self.tcx.lang_items().coerce_unsized_trait() {
+                            Some(self.tcx.at(item.span).coerce_unsized_info(def_id))
+                        } else {
+                            None
+                        }
+                    });
 
-                let data =
-                    ImplData { polarity, defaultness, parent_impl: parent, coerce_unsized_info };
+                let data = ImplData {
+                    polarity,
+                    defaultness,
+                    parent_impl: parent,
+                    coerce_unsized_info,
+                };
 
                 EntryKind::Impl(self.lazy(data))
             }
@@ -1397,11 +1343,13 @@ impl EncodeContext<'a, 'tcx> {
                 EntryKind::Trait(self.lazy(data))
             }
             hir::ItemKind::TraitAlias(..) => EntryKind::TraitAlias,
-            hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {
-                bug!("cannot encode info for item {:?}", item)
-            }
-        };
-        record!(self.tables.kind[def_id] <- entry_kind);
+            hir::ItemKind::ExternCrate(_) |
+            hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item),
+        });
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+        record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
+        record!(self.tables.attributes[def_id] <- item.attrs);
+        record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
         // FIXME(eddyb) there should be a nicer way to do this.
         match item.kind {
             hir::ItemKind::ForeignMod { items, .. } => record!(self.tables.children[def_id] <-
@@ -1435,6 +1383,9 @@ impl EncodeContext<'a, 'tcx> {
             }
             _ => {}
         }
+        self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
+        self.encode_deprecation(def_id);
         match item.kind {
             hir::ItemKind::Static(..)
             | hir::ItemKind::Const(..)
@@ -1515,11 +1466,17 @@ impl EncodeContext<'a, 'tcx> {
     fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef<'_>) {
         let def_id = self.tcx.hir().local_def_id(macro_def.hir_id).to_def_id();
         record!(self.tables.kind[def_id] <- EntryKind::MacroDef(self.lazy(macro_def.ast.clone())));
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+        record!(self.tables.span[def_id] <- macro_def.span);
+        record!(self.tables.attributes[def_id] <- macro_def.attrs);
         self.encode_ident_span(def_id, macro_def.ident);
+        self.encode_stability(def_id);
+        self.encode_deprecation(def_id);
     }
 
     fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) {
         record!(self.tables.kind[def_id] <- kind);
+        record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
         if encode_type {
             self.encode_item_type(def_id);
         }
@@ -1533,18 +1490,18 @@ impl EncodeContext<'a, 'tcx> {
         let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
         let ty = self.tcx.typeck(def_id).node_type(hir_id);
 
-        match ty.kind() {
+        record!(self.tables.kind[def_id.to_def_id()] <- match ty.kind() {
             ty::Generator(..) => {
                 let data = self.tcx.generator_kind(def_id).unwrap();
-                record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Generator(data));
+                EntryKind::Generator(data)
             }
 
-            ty::Closure(..) => {
-                record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Closure);
-            }
+            ty::Closure(..) => EntryKind::Closure,
 
             _ => bug!("closure that is neither generator nor closure"),
-        }
+        });
+        record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id));
+        record!(self.tables.attributes[def_id.to_def_id()] <- &self.tcx.get_attrs(def_id.to_def_id())[..]);
         self.encode_item_type(def_id.to_def_id());
         if let ty::Closure(def_id, substs) = *ty.kind() {
             record!(self.tables.fn_sig[def_id] <- substs.as_closure().sig());
@@ -1568,6 +1525,7 @@ impl EncodeContext<'a, 'tcx> {
         let qualifs = self.tcx.mir_const_qualif(def_id);
 
         record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst(qualifs, const_data));
+        record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id));
         self.encode_item_type(def_id.to_def_id());
         self.encode_generics(def_id.to_def_id());
         self.encode_explicit_predicates(def_id.to_def_id());
@@ -1617,15 +1575,6 @@ impl EncodeContext<'a, 'tcx> {
             let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied();
             let macros = self.lazy(hir.krate().proc_macros.iter().map(|p| p.owner.local_def_index));
 
-            record!(self.tables.def_kind[LOCAL_CRATE.as_def_id()] <- DefKind::Mod);
-            record!(self.tables.span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
-            record!(self.tables.attributes[LOCAL_CRATE.as_def_id()] <- tcx.get_attrs(LOCAL_CRATE.as_def_id()));
-            record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
-            if let Some(stability) = stability {
-                record!(self.tables.stability[LOCAL_CRATE.as_def_id()] <- stability);
-            }
-            self.encode_deprecation(LOCAL_CRATE.as_def_id());
-
             // Normally, this information is encoded when we walk the items
             // defined in this crate. However, we skip doing that for proc-macro crates,
             // so we manually encode just the information that we need
@@ -1657,7 +1606,6 @@ impl EncodeContext<'a, 'tcx> {
                 def_key.disambiguated_data.data = DefPathData::MacroNs(name);
 
                 let def_id = DefId::local(id);
-                record!(self.tables.def_kind[def_id] <- DefKind::Macro(macro_kind));
                 record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
                 record!(self.tables.attributes[def_id] <- attrs);
                 record!(self.tables.def_keys[def_id] <- def_key);
@@ -1825,7 +1773,7 @@ impl EncodeContext<'a, 'tcx> {
 
         debug!("EncodeContext::encode_info_for_foreign_item({:?})", def_id);
 
-        match nitem.kind {
+        record!(self.tables.kind[def_id] <- match nitem.kind {
             hir::ForeignItemKind::Fn(_, ref names, _) => {
                 let data = FnData {
                     asyncness: hir::IsAsync::NotAsync,
@@ -1836,19 +1784,19 @@ impl EncodeContext<'a, 'tcx> {
                     },
                     param_names: self.encode_fn_param_names(names),
                 };
-                record!(self.tables.kind[def_id] <- EntryKind::ForeignFn(self.lazy(data)));
+                EntryKind::ForeignFn(self.lazy(data))
             }
-            hir::ForeignItemKind::Static(_, hir::Mutability::Mut) => {
-                record!(self.tables.kind[def_id] <- EntryKind::ForeignMutStatic);
-            }
-            hir::ForeignItemKind::Static(_, hir::Mutability::Not) => {
-                record!(self.tables.kind[def_id] <- EntryKind::ForeignImmStatic);
-            }
-            hir::ForeignItemKind::Type => {
-                record!(self.tables.kind[def_id] <- EntryKind::ForeignType);
-            }
-        }
+            hir::ForeignItemKind::Static(_, hir::Mutability::Mut) => EntryKind::ForeignMutStatic,
+            hir::ForeignItemKind::Static(_, hir::Mutability::Not) => EntryKind::ForeignImmStatic,
+            hir::ForeignItemKind::Type => EntryKind::ForeignType,
+        });
+        record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+        record!(self.tables.span[def_id] <- nitem.span);
+        record!(self.tables.attributes[def_id] <- nitem.attrs);
         self.encode_ident_span(def_id, nitem.ident);
+        self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
+        self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         self.encode_inherent_implementations(def_id);
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
@@ -1914,12 +1862,15 @@ impl EncodeContext<'a, 'tcx> {
             let def_id = self.tcx.hir().local_def_id(param.hir_id);
             match param.kind {
                 GenericParamKind::Lifetime { .. } => continue,
-                GenericParamKind::Type { default, .. } => {
+                GenericParamKind::Type { ref default, .. } => {
                     self.encode_info_for_generic_param(
                         def_id.to_def_id(),
                         EntryKind::TypeParam,
                         default.is_some(),
                     );
+                    if default.is_some() {
+                        self.encode_stability(def_id.to_def_id());
+                    }
                 }
                 GenericParamKind::Const { .. } => {
                     self.encode_info_for_generic_param(
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index b44c3bfcac647..59a8bc7fac1be 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -6,7 +6,7 @@ use rustc_attr as attr;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::MetadataRef;
 use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, DefKind};
+use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefId, DefIndex, DefPathHash};
 use rustc_hir::definitions::DefKey;
 use rustc_hir::lang_items;
@@ -279,7 +279,6 @@ macro_rules! define_tables {
 }
 
 define_tables! {
-    def_kind: Table<DefIndex, Lazy<DefKind>>,
     kind: Table<DefIndex, Lazy<EntryKind>>,
     visibility: Table<DefIndex, Lazy<ty::Visibility>>,
     span: Table<DefIndex, Lazy<Span>>,
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 1cb75757379c9..62f2874af0493 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -1,17 +1,16 @@
-//! Nodes in the dependency graph.
+//! This module defines the `DepNode` type which the compiler uses to represent
+//! nodes in the dependency graph.
 //!
-//! A node in the [dependency graph] is represented by a [`DepNode`].
-//! A `DepNode` consists of a [`DepKind`] (which
-//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc.)
-//! and a [`Fingerprint`], a 128-bit hash value, the exact meaning of which
+//! A `DepNode` consists of a `DepKind` (which
+//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc)
+//! and a `Fingerprint`, a 128-bit hash value the exact meaning of which
 //! depends on the node's `DepKind`. Together, the kind and the fingerprint
 //! fully identify a dependency node, even across multiple compilation sessions.
 //! In other words, the value of the fingerprint does not depend on anything
 //! that is specific to a given compilation session, like an unpredictable
-//! interning key (e.g., `NodeId`, `DefId`, `Symbol`) or the numeric value of a
+//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a
 //! pointer. The concept behind this could be compared to how git commit hashes
-//! uniquely identify a given commit. The fingerprinting approach has
-//! a few advantages:
+//! uniquely identify a given commit and has a few advantages:
 //!
 //! * A `DepNode` can simply be serialized to disk and loaded in another session
 //!   without the need to do any "rebasing" (like we have to do for Spans and
@@ -52,8 +51,6 @@
 //! than a zeroed out fingerprint. More generally speaking, it relieves the
 //! user of the `DepNode` API of having to know how to compute the expected
 //! fingerprint for a given set of node parameters.
-//!
-//! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html
 
 use crate::ty::TyCtxt;
 
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 1305b5c9f00ab..06bb1347dc1de 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,6 +1,7 @@
 use self::collector::NodeCollector;
 
 use crate::hir::{Owner, OwnerNodes};
+use crate::ty::query::Providers;
 use crate::ty::TyCtxt;
 use rustc_ast as ast;
 use rustc_data_structures::svh::Svh;
@@ -85,13 +86,11 @@ fn is_body_owner<'hir>(node: Node<'hir>, hir_id: HirId) -> bool {
     }
 }
 
-#[derive(Debug)]
 pub(super) struct HirOwnerData<'hir> {
     pub(super) signature: Option<&'hir Owner<'hir>>,
     pub(super) with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
 }
 
-#[derive(Debug)]
 pub struct IndexedHir<'hir> {
     /// The SVH of the local crate.
     pub crate_hash: Svh,
@@ -184,18 +183,14 @@ impl<'hir> Map<'hir> {
         self.tcx.definitions.opt_local_def_id_to_hir_id(def_id)
     }
 
-    pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
-        self.tcx.definitions.iter_local_def_id()
-    }
-
-    pub fn opt_def_kind(&self, local_def_id: LocalDefId) -> Option<DefKind> {
+    pub fn def_kind(&self, local_def_id: LocalDefId) -> DefKind {
         // FIXME(eddyb) support `find` on the crate root.
         if local_def_id.to_def_id().index == CRATE_DEF_INDEX {
-            return Some(DefKind::Mod);
+            return DefKind::Mod;
         }
 
         let hir_id = self.local_def_id_to_hir_id(local_def_id);
-        let def_kind = match self.find(hir_id)? {
+        match self.get(hir_id) {
             Node::Item(item) => match item.kind {
                 ItemKind::Static(..) => DefKind::Static,
                 ItemKind::Const(..) => DefKind::Const,
@@ -254,7 +249,6 @@ impl<'hir> Map<'hir> {
                 GenericParamKind::Type { .. } => DefKind::TyParam,
                 GenericParamKind::Const { .. } => DefKind::ConstParam,
             },
-            Node::Crate(_) => DefKind::Mod,
             Node::Stmt(_)
             | Node::PathSegment(_)
             | Node::Ty(_)
@@ -266,14 +260,9 @@ impl<'hir> Map<'hir> {
             | Node::Arm(_)
             | Node::Lifetime(_)
             | Node::Visibility(_)
-            | Node::Block(_) => return None,
-        };
-        Some(def_kind)
-    }
-
-    pub fn def_kind(&self, local_def_id: LocalDefId) -> DefKind {
-        self.opt_def_kind(local_def_id)
-            .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", local_def_id))
+            | Node::Block(_)
+            | Node::Crate(_) => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)),
+        }
     }
 
     fn find_entry(&self, id: HirId) -> Option<Entry<'hir>> {
@@ -525,7 +514,9 @@ impl<'hir> Map<'hir> {
 
     /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
     pub fn find(&self, hir_id: HirId) -> Option<Node<'hir>> {
-        self.find_entry(hir_id).map(|entry| entry.node)
+        self.find_entry(hir_id).and_then(|entry| {
+            if let Node::Crate(..) = entry.node { None } else { Some(entry.node) }
+        })
     }
 
     /// Similar to `get_parent`; returns the parent HIR Id, or just `hir_id` if there
@@ -857,55 +848,50 @@ impl<'hir> Map<'hir> {
     /// Gets the span of the definition of the specified HIR node.
     /// This is used by `tcx.get_span`
     pub fn span(&self, hir_id: HirId) -> Span {
-        self.opt_span(hir_id)
-            .unwrap_or_else(|| bug!("hir::map::Map::span: id not in map: {:?}", hir_id))
-    }
-
-    pub fn opt_span(&self, hir_id: HirId) -> Option<Span> {
-        let span = match self.find_entry(hir_id)?.node {
-            Node::Param(param) => param.span,
-            Node::Item(item) => match &item.kind {
+        match self.find_entry(hir_id).map(|entry| entry.node) {
+            Some(Node::Param(param)) => param.span,
+            Some(Node::Item(item)) => match &item.kind {
                 ItemKind::Fn(sig, _, _) => sig.span,
                 _ => item.span,
             },
-            Node::ForeignItem(foreign_item) => foreign_item.span,
-            Node::TraitItem(trait_item) => match &trait_item.kind {
+            Some(Node::ForeignItem(foreign_item)) => foreign_item.span,
+            Some(Node::TraitItem(trait_item)) => match &trait_item.kind {
                 TraitItemKind::Fn(sig, _) => sig.span,
                 _ => trait_item.span,
             },
-            Node::ImplItem(impl_item) => match &impl_item.kind {
+            Some(Node::ImplItem(impl_item)) => match &impl_item.kind {
                 ImplItemKind::Fn(sig, _) => sig.span,
                 _ => impl_item.span,
             },
-            Node::Variant(variant) => variant.span,
-            Node::Field(field) => field.span,
-            Node::AnonConst(constant) => self.body(constant.body).value.span,
-            Node::Expr(expr) => expr.span,
-            Node::Stmt(stmt) => stmt.span,
-            Node::PathSegment(seg) => seg.ident.span,
-            Node::Ty(ty) => ty.span,
-            Node::TraitRef(tr) => tr.path.span,
-            Node::Binding(pat) => pat.span,
-            Node::Pat(pat) => pat.span,
-            Node::Arm(arm) => arm.span,
-            Node::Block(block) => block.span,
-            Node::Ctor(..) => match self.find(self.get_parent_node(hir_id))? {
-                Node::Item(item) => item.span,
-                Node::Variant(variant) => variant.span,
+            Some(Node::Variant(variant)) => variant.span,
+            Some(Node::Field(field)) => field.span,
+            Some(Node::AnonConst(constant)) => self.body(constant.body).value.span,
+            Some(Node::Expr(expr)) => expr.span,
+            Some(Node::Stmt(stmt)) => stmt.span,
+            Some(Node::PathSegment(seg)) => seg.ident.span,
+            Some(Node::Ty(ty)) => ty.span,
+            Some(Node::TraitRef(tr)) => tr.path.span,
+            Some(Node::Binding(pat)) => pat.span,
+            Some(Node::Pat(pat)) => pat.span,
+            Some(Node::Arm(arm)) => arm.span,
+            Some(Node::Block(block)) => block.span,
+            Some(Node::Ctor(..)) => match self.find(self.get_parent_node(hir_id)) {
+                Some(Node::Item(item)) => item.span,
+                Some(Node::Variant(variant)) => variant.span,
                 _ => unreachable!(),
             },
-            Node::Lifetime(lifetime) => lifetime.span,
-            Node::GenericParam(param) => param.span,
-            Node::Visibility(&Spanned {
+            Some(Node::Lifetime(lifetime)) => lifetime.span,
+            Some(Node::GenericParam(param)) => param.span,
+            Some(Node::Visibility(&Spanned {
                 node: VisibilityKind::Restricted { ref path, .. },
                 ..
-            }) => path.span,
-            Node::Visibility(v) => bug!("unexpected Visibility {:?}", v),
-            Node::Local(local) => local.span,
-            Node::MacroDef(macro_def) => macro_def.span,
-            Node::Crate(item) => item.span,
-        };
-        Some(span)
+            })) => path.span,
+            Some(Node::Visibility(v)) => bug!("unexpected Visibility {:?}", v),
+            Some(Node::Local(local)) => local.span,
+            Some(Node::MacroDef(macro_def)) => macro_def.span,
+            Some(Node::Crate(item)) => item.span,
+            None => bug!("hir::map::Map::span: id not in map: {:?}", hir_id),
+        }
     }
 
     /// Like `hir.span()`, but includes the body of function items
@@ -921,7 +907,7 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn span_if_local(&self, id: DefId) -> Option<Span> {
-        id.as_local().and_then(|id| self.opt_span(self.local_def_id_to_hir_id(id)))
+        id.as_local().map(|id| self.span(self.local_def_id_to_hir_id(id)))
     }
 
     pub fn res_span(&self, res: Res) -> Option<Span> {
@@ -1115,3 +1101,7 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String {
         None => format!("unknown node{}", id_str),
     }
 }
+
+pub fn provide(providers: &mut Providers) {
+    providers.def_kind = |tcx, def_id| tcx.hir().def_kind(def_id.expect_local());
+}
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 6934e06d4c2e3..ae3b30217cc4a 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -15,9 +15,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
 use rustc_hir::*;
 use rustc_index::vec::IndexVec;
-use rustc_span::DUMMY_SP;
 
-#[derive(Debug)]
 pub struct Owner<'tcx> {
     parent: HirId,
     node: Node<'tcx>,
@@ -33,13 +31,12 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
     }
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct ParentedNode<'tcx> {
     parent: ItemLocalId,
     node: Node<'tcx>,
 }
 
-#[derive(Debug)]
 pub struct OwnerNodes<'tcx> {
     hash: Fingerprint,
     nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
@@ -80,7 +77,6 @@ pub fn provide(providers: &mut Providers) {
     };
     providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature;
     providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref();
-    providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
     providers.fn_arg_names = |tcx, id| {
         let hir = tcx.hir();
         let hir_id = hir.local_def_id_to_hir_id(id.expect_local());
@@ -96,5 +92,5 @@ pub fn provide(providers: &mut Providers) {
             span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
         }
     };
-    providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local());
+    map::provide(providers);
 }
diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs
index 51b650e5adef8..addcb7a14e3a6 100644
--- a/compiler/rustc_middle/src/ich/hcx.rs
+++ b/compiler/rustc_middle/src/ich/hcx.rs
@@ -17,7 +17,6 @@ use rustc_span::{BytePos, CachingSourceMapView, SourceFile, SpanData};
 use rustc_span::def_id::{CrateNum, CRATE_DEF_INDEX};
 use smallvec::SmallVec;
 use std::cmp::Ord;
-use std::thread::LocalKey;
 
 fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
     debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
@@ -243,13 +242,6 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
         hcx.def_path_hash(def_id).hash_stable(hcx, hasher);
     }
 
-    fn expn_id_cache() -> &'static LocalKey<rustc_span::ExpnIdCache> {
-        thread_local! {
-            static CACHE: rustc_span::ExpnIdCache = Default::default();
-        }
-        &CACHE
-    }
-
     fn byte_pos_to_line_and_col(
         &mut self,
         byte: BytePos,
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 0bdccf7b5f073..80c87dddd5614 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -12,7 +12,7 @@ use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
 use rustc_span::{symbol, Span, Symbol, DUMMY_SP};
 
 /// How a lint level was set.
-#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
 pub enum LintLevelSource {
     /// Lint is at the default level as declared
     /// in rustc or a plugin.
@@ -48,13 +48,11 @@ impl LintLevelSource {
 /// A tuple of a lint level and its source.
 pub type LevelAndSource = (Level, LintLevelSource);
 
-#[derive(Debug)]
 pub struct LintLevelSets {
     pub list: Vec<LintSet>,
     pub lint_cap: Level,
 }
 
-#[derive(Debug)]
 pub enum LintSet {
     CommandLine {
         // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
@@ -141,7 +139,6 @@ impl LintLevelSets {
     }
 }
 
-#[derive(Debug)]
 pub struct LintLevelMap {
     pub sets: LintLevelSets,
     pub id_to_set: FxHashMap<HirId, u32>,
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 5f2ffda642cee..a4363bb580a2f 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -3,7 +3,7 @@ use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_session::config::SanitizerSet;
 use rustc_span::symbol::Symbol;
 
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable)]
 pub struct CodegenFnAttrs {
     pub flags: CodegenFnAttrFlags,
     /// Parsed representation of the `#[inline]` attribute
diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs
index 4f1ca968c3018..6d2c43874bc0f 100644
--- a/compiler/rustc_middle/src/middle/cstore.rs
+++ b/compiler/rustc_middle/src/middle/cstore.rs
@@ -96,7 +96,7 @@ pub struct NativeLib {
     pub wasm_import_module: Option<Symbol>,
 }
 
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable)]
 pub struct ForeignModule {
     pub foreign_items: Vec<DefId>,
     pub def_id: DefId,
diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs
index a369e85306b36..9bc9ca6707afe 100644
--- a/compiler/rustc_middle/src/middle/mod.rs
+++ b/compiler/rustc_middle/src/middle/mod.rs
@@ -7,7 +7,7 @@ pub mod lib_features {
     use rustc_data_structures::fx::{FxHashMap, FxHashSet};
     use rustc_span::symbol::Symbol;
 
-    #[derive(HashStable, Debug)]
+    #[derive(HashStable)]
     pub struct LibFeatures {
         // A map from feature to stabilisation version.
         pub stable: FxHashMap<Symbol, Symbol>,
diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
index 1b7d0e620a4c5..3d0144e9c8a99 100644
--- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs
+++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
@@ -68,7 +68,7 @@ pub type ObjectLifetimeDefault = Set1<Region>;
 
 /// Maps the id of each lifetime reference to the lifetime decl
 /// that it corresponds to.
-#[derive(Default, HashStable, Debug)]
+#[derive(Default, HashStable)]
 pub struct ResolveLifetimes {
     /// Maps from every use of a named (not anonymous) lifetime to a
     /// `Region` describing how that region is bound
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 89ca8eed39a9b..4f08057a7e323 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -36,7 +36,7 @@ impl StabilityLevel {
 }
 
 /// An entry in the `depr_map`.
-#[derive(Clone, HashStable, Debug)]
+#[derive(Clone, HashStable)]
 pub struct DeprecationEntry {
     /// The metadata of the attribute associated with this entry.
     pub attr: Deprecation,
@@ -63,7 +63,7 @@ impl DeprecationEntry {
 }
 
 /// A stability index, giving the stability level for items and methods.
-#[derive(HashStable, Debug)]
+#[derive(HashStable)]
 pub struct Index<'tcx> {
     /// This is mostly a cache, except the stabilities of local items
     /// are filled by the annotator.
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index cf931ece712b0..397d2ffd565b1 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -127,8 +127,6 @@ pub enum InvalidProgramInfo<'tcx> {
     Layout(layout::LayoutError<'tcx>),
     /// An invalid transmute happened.
     TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>),
-    /// SizeOf of unsized type was requested.
-    SizeOfUnsizedType(Ty<'tcx>),
 }
 
 impl fmt::Display for InvalidProgramInfo<'_> {
@@ -146,7 +144,6 @@ impl fmt::Display for InvalidProgramInfo<'_> {
                 "transmuting `{}` to `{}` is not possible, because these types do not have the same size",
                 from_ty, to_ty
             ),
-            SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index f288ad8d1d4a3..5e97862ecf2b6 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -13,7 +13,7 @@ use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
 use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic};
 
 /// Represents the result of const evaluation via the `eval_to_allocation` query.
-#[derive(Clone, HashStable, TyEncodable, TyDecodable, Debug)]
+#[derive(Clone, HashStable, TyEncodable, TyDecodable)]
 pub struct ConstAlloc<'tcx> {
     // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory`
     // (so you can use `AllocMap::unwrap_memory`).
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index cd2bea86ea1a7..fab2f2c97e4ae 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -54,7 +54,7 @@ mod type_foldable;
 pub mod visit;
 
 /// Types for locals
-pub type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>;
+type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>;
 
 pub trait HasLocalDecls<'tcx> {
     fn local_decls(&self) -> &LocalDecls<'tcx>;
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index eb13c89544c13..6d5d408f86c15 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -216,7 +216,6 @@ impl<'tcx> fmt::Display for MonoItem<'tcx> {
     }
 }
 
-#[derive(Debug)]
 pub struct CodegenUnit<'tcx> {
     /// A name for this CGU. Incremental compilation requires that
     /// name be unique amongst **all** crates. Therefore, it should
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index c293fbe4ef8ca..a7b847fc5e0ee 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -17,7 +17,7 @@ use std::fmt::{self, Debug};
 
 use super::{Field, SourceInfo};
 
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
 pub enum UnsafetyViolationKind {
     /// Only permitted in regular `fn`s, prohibited in `const fn`s.
     General,
@@ -36,7 +36,7 @@ pub enum UnsafetyViolationKind {
     UnsafeFnBorrowPacked,
 }
 
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
 pub enum UnsafetyViolationDetails {
     CallToUnsafeFunction,
     UseOfInlineAssembly,
@@ -121,7 +121,7 @@ impl UnsafetyViolationDetails {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
 pub struct UnsafetyViolation {
     pub source_info: SourceInfo,
     pub lint_root: hir::HirId,
@@ -129,7 +129,7 @@ pub struct UnsafetyViolation {
     pub details: UnsafetyViolationDetails,
 }
 
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable)]
 pub struct UnsafetyCheckResult {
     /// Violations that are propagated *upwards* from this function.
     pub violations: Lrc<[UnsafetyViolation]>,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d89e3ab4352bb..00ee7b8ec7709 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -782,27 +782,6 @@ rustc_queries! {
     }
 
     Other {
-        /// Check whether the function has any recursion that could cause the inliner to trigger
-        /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the
-        /// current function, just all intermediate functions.
-        query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool {
-            fatal_cycle
-            desc { |tcx|
-                "computing if `{}` (transitively) calls `{}`",
-                key.0,
-                tcx.def_path_str(key.1.to_def_id()),
-            }
-        }
-
-        /// Obtain all the calls into other local functions
-        query mir_inliner_callees(key: ty::InstanceDef<'tcx>) -> &'tcx [(DefId, SubstsRef<'tcx>)] {
-            fatal_cycle
-            desc { |tcx|
-                "computing all local function calls in `{}`",
-                tcx.def_path_str(key.def_id()),
-            }
-        }
-
         /// Evaluates a constant and returns the computed allocation.
         ///
         /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper.
@@ -899,7 +878,7 @@ rustc_queries! {
             cache_on_disk_if { true }
         }
 
-        query opt_def_kind(def_id: DefId) -> Option<DefKind> {
+        query def_kind(def_id: DefId) -> DefKind {
             desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) }
         }
 
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index cb60bfa4c5408..ec6010e6eecf4 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -23,7 +23,7 @@ use rustc_span::symbol::Ident;
 ///   parents of a given specializing impl, which is needed for extracting
 ///   default items amongst other things. In the simple "chain" rule, every impl
 ///   has at most one parent.
-#[derive(TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(TyEncodable, TyDecodable, HashStable)]
 pub struct Graph {
     /// All impls have a parent; the "root" impls have as their parent the `def_id`
     /// of the trait.
@@ -50,7 +50,7 @@ impl Graph {
 
 /// Children of a given impl, grouped into blanket/non-blanket varieties as is
 /// done in `TraitDef`.
-#[derive(Default, TyEncodable, TyDecodable, Debug)]
+#[derive(Default, TyEncodable, TyDecodable)]
 pub struct Children {
     // Impls of a trait (or specializations of a given impl). To allow for
     // quicker lookup, the impls are indexed by a simplified version of their
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
index 275384e227a90..03c8963b0907e 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
@@ -18,7 +18,7 @@ use DefIdForest::*;
 /// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
 /// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
 /// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
-#[derive(Clone, HashStable, Debug)]
+#[derive(Clone, HashStable)]
 pub enum DefIdForest {
     Empty,
     Single(DefId),
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index ef467ed651454..195e840866aec 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2514,7 +2514,7 @@ where
         extra_args: &[Ty<'tcx>],
         caller_location: Option<Ty<'tcx>>,
         codegen_fn_attr_flags: CodegenFnAttrFlags,
-        make_self_ptr_thin: bool,
+        mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
     ) -> Self;
     fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
 }
@@ -2574,7 +2574,9 @@ where
         // Assume that fn pointers may always unwind
         let codegen_fn_attr_flags = CodegenFnAttrFlags::UNWIND;
 
-        call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, false)
+        call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, |ty, _| {
+            ArgAbi::new(cx.layout_of(ty))
+        })
     }
 
     fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
@@ -2588,14 +2590,55 @@ where
 
         let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()).flags;
 
-        call::FnAbi::new_internal(
-            cx,
-            sig,
-            extra_args,
-            caller_location,
-            attrs,
-            matches!(instance.def, ty::InstanceDef::Virtual(..)),
-        )
+        call::FnAbi::new_internal(cx, sig, extra_args, caller_location, attrs, |ty, arg_idx| {
+            let mut layout = cx.layout_of(ty);
+            // Don't pass the vtable, it's not an argument of the virtual fn.
+            // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
+            // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
+            if let (ty::InstanceDef::Virtual(..), Some(0)) = (&instance.def, arg_idx) {
+                let fat_pointer_ty = if layout.is_unsized() {
+                    // unsized `self` is passed as a pointer to `self`
+                    // FIXME (mikeyhew) change this to use &own if it is ever added to the language
+                    cx.tcx().mk_mut_ptr(layout.ty)
+                } else {
+                    match layout.abi {
+                        Abi::ScalarPair(..) => (),
+                        _ => bug!("receiver type has unsupported layout: {:?}", layout),
+                    }
+
+                    // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
+                    // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
+                    // elsewhere in the compiler as a method on a `dyn Trait`.
+                    // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
+                    // get a built-in pointer type
+                    let mut fat_pointer_layout = layout;
+                    'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
+                        && !fat_pointer_layout.ty.is_region_ptr()
+                    {
+                        for i in 0..fat_pointer_layout.fields.count() {
+                            let field_layout = fat_pointer_layout.field(cx, i);
+
+                            if !field_layout.is_zst() {
+                                fat_pointer_layout = field_layout;
+                                continue 'descend_newtypes;
+                            }
+                        }
+
+                        bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
+                    }
+
+                    fat_pointer_layout.ty
+                };
+
+                // we now have a type like `*mut RcBox<dyn Trait>`
+                // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
+                // this is understood as a special case elsewhere in the compiler
+                let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit());
+                layout = cx.layout_of(unit_pointer_ty);
+                layout.ty = fat_pointer_ty;
+            }
+            ArgAbi::new(layout)
+        })
     }
 
     fn new_internal(
@@ -2604,7 +2647,7 @@ where
         extra_args: &[Ty<'tcx>],
         caller_location: Option<Ty<'tcx>>,
         codegen_fn_attr_flags: CodegenFnAttrFlags,
-        force_thin_self_ptr: bool,
+        mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
     ) -> Self {
         debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
 
@@ -2735,23 +2778,7 @@ where
 
         let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
             let is_return = arg_idx.is_none();
-
-            let layout = cx.layout_of(ty);
-            let layout = if force_thin_self_ptr && arg_idx == Some(0) {
-                // Don't pass the vtable, it's not an argument of the virtual fn.
-                // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
-                // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
-                make_thin_self_ptr(cx, layout)
-            } else {
-                layout
-            };
-
-            let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| {
-                let mut attrs = ArgAttributes::new();
-                adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return);
-                attrs
-            });
-
+            let mut arg = mk_arg_type(ty, arg_idx);
             if arg.layout.is_zst() {
                 // For some forsaken reason, x86_64-pc-windows-gnu
                 // doesn't ignore zero-sized struct arguments.
@@ -2767,6 +2794,30 @@ where
                 }
             }
 
+            // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
+            if !is_return && rust_abi {
+                if let Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
+                    let mut a_attrs = ArgAttributes::new();
+                    let mut b_attrs = ArgAttributes::new();
+                    adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, Size::ZERO, false);
+                    adjust_for_rust_scalar(
+                        &mut b_attrs,
+                        b,
+                        arg.layout,
+                        a.value.size(cx).align_to(b.value.align(cx).abi),
+                        false,
+                    );
+                    arg.mode = PassMode::Pair(a_attrs, b_attrs);
+                    return arg;
+                }
+            }
+
+            if let Abi::Scalar(ref scalar) = arg.layout.abi {
+                if let PassMode::Direct(ref mut attrs) = arg.mode {
+                    adjust_for_rust_scalar(attrs, scalar, arg.layout, Size::ZERO, is_return);
+                }
+            }
+
             arg
         };
 
@@ -2843,10 +2894,9 @@ where
                 let max_by_val_size = Pointer.size(cx) * 2;
                 let size = arg.layout.size;
 
-                let is_indirect_not_on_stack =
-                    matches!(arg.mode, PassMode::Indirect { on_stack: false, .. });
-                assert!(is_indirect_not_on_stack, "{:?}", arg);
-                if !arg.layout.is_unsized() && size <= max_by_val_size {
+                if arg.layout.is_unsized() || size > max_by_val_size {
+                    arg.make_indirect();
+                } else {
                     // We want to pass small aggregates as immediates, but using
                     // a LLVM aggregate type for this leads to bad optimizations,
                     // so we pick an appropriately sized integer type instead.
@@ -2865,52 +2915,3 @@ where
         }
     }
 }
-
-fn make_thin_self_ptr<'tcx, C>(cx: &C, mut layout: TyAndLayout<'tcx>) -> TyAndLayout<'tcx>
-where
-    C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
-        + HasTyCtxt<'tcx>
-        + HasParamEnv<'tcx>,
-{
-    let fat_pointer_ty = if layout.is_unsized() {
-        // unsized `self` is passed as a pointer to `self`
-        // FIXME (mikeyhew) change this to use &own if it is ever added to the language
-        cx.tcx().mk_mut_ptr(layout.ty)
-    } else {
-        match layout.abi {
-            Abi::ScalarPair(..) => (),
-            _ => bug!("receiver type has unsupported layout: {:?}", layout),
-        }
-
-        // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
-        // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
-        // elsewhere in the compiler as a method on a `dyn Trait`.
-        // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
-        // get a built-in pointer type
-        let mut fat_pointer_layout = layout;
-        'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
-            && !fat_pointer_layout.ty.is_region_ptr()
-        {
-            for i in 0..fat_pointer_layout.fields.count() {
-                let field_layout = fat_pointer_layout.field(cx, i);
-
-                if !field_layout.is_zst() {
-                    fat_pointer_layout = field_layout;
-                    continue 'descend_newtypes;
-                }
-            }
-
-            bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
-        }
-
-        fat_pointer_layout.ty
-    };
-
-    // we now have a type like `*mut RcBox<dyn Trait>`
-    // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
-    // this is understood as a special case elsewhere in the compiler
-    let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit());
-    layout = cx.layout_of(unit_pointer_ty);
-    layout.ty = fat_pointer_ty;
-    layout
-}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index c4d867161386d..c6970df01785e 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -185,7 +185,7 @@ pub struct ImplHeader<'tcx> {
     pub predicates: Vec<Predicate<'tcx>>,
 }
 
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
 pub enum ImplPolarity {
     /// `impl Trait for Type`
     Positive,
@@ -435,7 +435,7 @@ pub enum Variance {
 /// HIR of every item in the local crate. Instead, use
 /// `tcx.variances_of()` to get the variance for a *particular*
 /// item.
-#[derive(HashStable, Debug)]
+#[derive(HashStable)]
 pub struct CrateVariancesMap<'tcx> {
     /// For each item with generics, maps to a vector of the variance
     /// of its generics. If an item has no generics, it will have no
@@ -1174,7 +1174,7 @@ pub enum PredicateKind<'tcx> {
 /// HIR of every item in the local crate. Instead, use
 /// `tcx.inferred_outlives_of()` to get the outlives for a *particular*
 /// item.
-#[derive(HashStable, Debug)]
+#[derive(HashStable)]
 pub struct CratePredicatesMap<'tcx> {
     /// For each struct with outlive bounds, maps to a vector of the
     /// predicate of its outlive bounds. If an item has no outlives
@@ -3107,7 +3107,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-#[derive(Clone, HashStable, Debug)]
+#[derive(Clone, HashStable)]
 pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]);
 
 /// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition.
diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs
index bfa1581aaae29..a005990264cf1 100644
--- a/compiler/rustc_middle/src/ty/query/keys.rs
+++ b/compiler/rustc_middle/src/ty/query/keys.rs
@@ -127,17 +127,6 @@ impl Key for (DefId, DefId) {
     }
 }
 
-impl Key for (ty::Instance<'tcx>, LocalDefId) {
-    type CacheSelector = DefaultCacheSelector;
-
-    fn query_crate(&self) -> CrateNum {
-        self.0.query_crate()
-    }
-    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
-        self.0.default_span(tcx)
-    }
-}
-
 impl Key for (DefId, LocalDefId) {
     type CacheSelector = DefaultCacheSelector;
 
diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs
index f580cb14dc988..acfa58e511ed1 100644
--- a/compiler/rustc_middle/src/ty/query/mod.rs
+++ b/compiler/rustc_middle/src/ty/query/mod.rs
@@ -130,19 +130,3 @@ mod sealed {
 }
 
 use sealed::IntoQueryParam;
-
-impl TyCtxt<'tcx> {
-    pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
-        let def_id = def_id.into_query_param();
-        self.opt_def_kind(def_id)
-            .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
-    }
-}
-
-impl TyCtxtAt<'tcx> {
-    pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
-        let def_id = def_id.into_query_param();
-        self.opt_def_kind(def_id)
-            .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index f4d7eac0ae2f8..86476dffc0312 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -63,7 +63,7 @@ pub enum TraitSpecializationKind {
     AlwaysApplicable,
 }
 
-#[derive(Default, Debug)]
+#[derive(Default)]
 pub struct TraitImpls {
     blanket_impls: Vec<DefId>,
     /// Impls indexed by their simplified self type, for fast lookup.
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
index cd16a88e5fc3c..8f41bfae2fdf5 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -289,7 +289,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 );
             }
 
-            let ty = used_place.ty(self.body, self.infcx.tcx).ty;
+            let ty = PlaceRef::ty(&used_place, self.body, self.infcx.tcx).ty;
             let needs_note = match ty.kind() {
                 ty::Closure(id, _) => {
                     let tables = self.infcx.tcx.typeck(id.expect_local());
@@ -728,8 +728,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         // Define a small closure that we can use to check if the type of a place
         // is a union.
         let union_ty = |place_base| {
-            // Need to use fn call syntax `PlaceRef::ty` to determine the type of `place_base`;
-            // using a type annotation in the closure argument instead leads to a lifetime error.
             let ty = PlaceRef::ty(&place_base, self.body, self.infcx.tcx).ty;
             ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
         };
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index 7c7edfdb5fbaf..006e05072a7a9 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -1743,7 +1743,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
             place_span.0.last_projection()
         {
-            let place_ty = place_base.ty(self.body(), self.infcx.tcx);
+            let place_ty = PlaceRef::ty(&place_base, self.body(), self.infcx.tcx);
             if let ty::Array(..) = place_ty.ty.kind() {
                 self.check_if_subslice_element_is_moved(
                     location,
@@ -1854,7 +1854,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     // assigning to `P.f` requires `P` itself
                     // be already initialized
                     let tcx = self.infcx.tcx;
-                    let base_ty = place_base.ty(self.body(), tcx).ty;
+                    let base_ty = PlaceRef::ty(&place_base, self.body(), tcx).ty;
                     match base_ty.kind() {
                         ty::Adt(def, _) if def.has_dtor(tcx) => {
                             self.check_if_path_or_subpath_is_moved(
@@ -1951,7 +1951,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // no move out from an earlier location) then this is an attempt at initialization
                 // of the union - we should error in that case.
                 let tcx = this.infcx.tcx;
-                if let ty::Adt(def, _) = base.ty(this.body(), tcx).ty.kind() {
+                if let ty::Adt(def, _) = PlaceRef::ty(&base, this.body(), tcx).ty.kind() {
                     if def.is_union() {
                         if this.move_data.path_map[mpi].iter().any(|moi| {
                             this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
@@ -2173,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             Some((place_base, elem)) => {
                 match elem {
                     ProjectionElem::Deref => {
-                        let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty;
+                        let base_ty = PlaceRef::ty(&place_base, self.body(), self.infcx.tcx).ty;
 
                         // Check the kind of deref to decide
                         match base_ty.kind() {
diff --git a/compiler/rustc_mir/src/borrow_check/prefixes.rs b/compiler/rustc_mir/src/borrow_check/prefixes.rs
index bdf2becb71126..cf04c55eb68c5 100644
--- a/compiler/rustc_mir/src/borrow_check/prefixes.rs
+++ b/compiler/rustc_mir/src/borrow_check/prefixes.rs
@@ -117,7 +117,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
                     // derefs, except we stop at the deref of a shared
                     // reference.
 
-                    let ty = cursor_base.ty(self.body, self.tcx).ty;
+                    let ty = PlaceRef::ty(&cursor_base, self.body, self.tcx).ty;
                     match ty.kind() {
                         ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => {
                             // don't continue traversing over derefs of raw pointers or shared
diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs
index fbc72ad8adc96..95738db1f553c 100644
--- a/compiler/rustc_mir/src/interpret/step.rs
+++ b/compiler/rustc_mir/src/interpret/step.rs
@@ -264,14 +264,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             NullaryOp(mir::NullOp::SizeOf, ty) => {
                 let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty);
                 let layout = self.layout_of(ty)?;
-                if layout.is_unsized() {
-                    // FIXME: This should be a span_bug (#80742)
-                    self.tcx.sess.delay_span_bug(
-                        self.frame().current_span(),
-                        &format!("SizeOf nullary MIR operator called for unsized type {}", ty),
-                    );
-                    throw_inval!(SizeOfUnsizedType(ty));
-                }
+                assert!(
+                    !layout.is_unsized(),
+                    "SizeOf nullary MIR operator called for unsized type"
+                );
                 self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), dest)?;
             }
 
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index 8b3881ef9de10..e6d822086f521 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -57,8 +57,6 @@ pub fn provide(providers: &mut Providers) {
     providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
     providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
     providers.const_caller_location = const_eval::const_caller_location;
-    providers.mir_callgraph_reachable = transform::inline::cycle::mir_callgraph_reachable;
-    providers.mir_inliner_callees = transform::inline::cycle::mir_inliner_callees;
     providers.destructure_const = |tcx, param_env_and_value| {
         let (param_env, value) = param_env_and_value.into_parts();
         const_eval::destructure_const(tcx, param_env, value)
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index 6f98760a7b0ad..99ffb0edce9e1 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -268,20 +268,16 @@ impl NonConstOp for CellBorrow {
 }
 
 #[derive(Debug)]
-/// This op is for `&mut` borrows in the trailing expression of a constant
-/// which uses the "enclosing scopes rule" to leak its locals into anonymous
-/// static or const items.
 pub struct MutBorrow(pub hir::BorrowKind);
 
 impl NonConstOp for MutBorrow {
-    fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
-        Status::Forbidden
-    }
-
-    fn importance(&self) -> DiagnosticImportance {
-        // If there were primary errors (like non-const function calls), do not emit further
-        // errors about mutable references.
-        DiagnosticImportance::Secondary
+    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        // Forbid everywhere except in const fn with a feature gate
+        if ccx.const_kind() == hir::ConstContext::ConstFn {
+            Status::Unstable(sym::const_mut_refs)
+        } else {
+            Status::Forbidden
+        }
     }
 
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
@@ -290,15 +286,25 @@ impl NonConstOp for MutBorrow {
             hir::BorrowKind::Ref => "",
         };
 
-        let mut err = struct_span_err!(
-            ccx.tcx.sess,
-            span,
-            E0764,
-            "{}mutable references are not allowed in the final value of {}s",
-            raw,
-            ccx.const_kind(),
-        );
-
+        let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn {
+            feature_err(
+                &ccx.tcx.sess.parse_sess,
+                sym::const_mut_refs,
+                span,
+                &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()),
+            )
+        } else {
+            let mut err = struct_span_err!(
+                ccx.tcx.sess,
+                span,
+                E0764,
+                "{}mutable references are not allowed in {}s",
+                raw,
+                ccx.const_kind(),
+            );
+            err.span_label(span, format!("`&{}mut` is only allowed in `const fn`", raw));
+            err
+        };
         if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
             err.note(
                 "References in statics and constants may only refer \
@@ -315,29 +321,6 @@ impl NonConstOp for MutBorrow {
     }
 }
 
-#[derive(Debug)]
-pub struct TransientMutBorrow(pub hir::BorrowKind);
-
-impl NonConstOp for TransientMutBorrow {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
-        Status::Unstable(sym::const_mut_refs)
-    }
-
-    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        let raw = match self.0 {
-            hir::BorrowKind::Raw => "raw ",
-            hir::BorrowKind::Ref => "",
-        };
-
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_mut_refs,
-            span,
-            &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()),
-        )
-    }
-}
-
 #[derive(Debug)]
 pub struct MutDeref;
 impl NonConstOp for MutDeref {
@@ -346,7 +329,7 @@ impl NonConstOp for MutDeref {
     }
 
     fn importance(&self) -> DiagnosticImportance {
-        // Usually a side-effect of a `TransientMutBorrow` somewhere.
+        // Usually a side-effect of a `MutBorrow` somewhere.
         DiagnosticImportance::Secondary
     }
 
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index a92997dddac6a..08d969b27bea5 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -466,29 +466,6 @@ impl Validator<'mir, 'tcx> {
             }
         }
     }
-
-    fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) {
-        match self.const_kind() {
-            // In a const fn all borrows are transient or point to the places given via
-            // references in the arguments (so we already checked them with
-            // TransientMutBorrow/MutBorrow as appropriate).
-            // The borrow checker guarantees that no new non-transient borrows are created.
-            // NOTE: Once we have heap allocations during CTFE we need to figure out
-            // how to prevent `const fn` to create long-lived allocations that point
-            // to mutable memory.
-            hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)),
-            _ => {
-                // Locals with StorageDead do not live beyond the evaluation and can
-                // thus safely be borrowed without being able to be leaked to the final
-                // value of the constant.
-                if self.local_has_storage_dead(local) {
-                    self.check_op(ops::TransientMutBorrow(kind));
-                } else {
-                    self.check_op(ops::MutBorrow(kind));
-                }
-            }
-        }
-    }
 }
 
 impl Visitor<'tcx> for Validator<'mir, 'tcx> {
@@ -585,15 +562,15 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
 
                 if !is_allowed {
                     if let BorrowKind::Mut { .. } = kind {
-                        self.check_mut_borrow(place.local, hir::BorrowKind::Ref)
+                        self.check_op(ops::MutBorrow(hir::BorrowKind::Ref));
                     } else {
                         self.check_op(ops::CellBorrow);
                     }
                 }
             }
 
-            Rvalue::AddressOf(Mutability::Mut, ref place) => {
-                self.check_mut_borrow(place.local, hir::BorrowKind::Raw)
+            Rvalue::AddressOf(Mutability::Mut, _) => {
+                self.check_op(ops::MutBorrow(hir::BorrowKind::Raw))
             }
 
             Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place)
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index fd5c2236902a2..354d213689ec2 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -440,15 +440,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     }
 
     fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
-        let mut data = &self.source_scopes[source_info.scope];
-        // FIXME(oli-obk): we should be able to just walk the `inlined_parent_scope`, but it
-        // does not work as I thought it would. Needs more investigation and documentation.
-        while data.inlined.is_some() {
-            trace!(?data);
-            data = &self.source_scopes[data.parent_scope.unwrap()];
-        }
-        trace!(?data);
-        match &data.local_data {
+        match &self.source_scopes[source_info.scope].local_data {
             ClearCrossCrate::Set(data) => Some(data.lint_root),
             ClearCrossCrate::Clear => None,
         }
diff --git a/compiler/rustc_mir/src/transform/coverage/counters.rs b/compiler/rustc_mir/src/transform/coverage/counters.rs
index 272a7bf961799..b5921aac56143 100644
--- a/compiler/rustc_mir/src/transform/coverage/counters.rs
+++ b/compiler/rustc_mir/src/transform/coverage/counters.rs
@@ -32,7 +32,7 @@ impl CoverageCounters {
     }
 
     /// Activate the `DebugCounters` data structures, to provide additional debug formatting
-    /// features when formatting `CoverageKind` (counter) values.
+    /// features when formating `CoverageKind` (counter) values.
     pub fn enable_debug(&mut self) {
         self.debug_counters.enable();
     }
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index dd9a514466d4c..07e637b88f9c0 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -17,8 +17,6 @@ use crate::transform::MirPass;
 use std::iter;
 use std::ops::{Range, RangeFrom};
 
-crate mod cycle;
-
 const INSTR_COST: usize = 5;
 const CALL_PENALTY: usize = 25;
 const LANDINGPAD_PENALTY: usize = 50;
@@ -39,9 +37,6 @@ struct CallSite<'tcx> {
 
 impl<'tcx> MirPass<'tcx> for Inline {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        // If you change this optimization level, also change the level in
-        // `mir_drops_elaborated_and_const_checked` for the call to `mir_inliner_callees`.
-        // Otherwise you will get an ICE about stolen MIR.
         if tcx.sess.opts.debugging_opts.mir_opt_level < 2 {
             return;
         }
@@ -55,8 +50,6 @@ impl<'tcx> MirPass<'tcx> for Inline {
             return;
         }
 
-        let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id()));
-        let _guard = span.enter();
         if inline(tcx, body) {
             debug!("running simplify cfg on {:?}", body.source);
             CfgSimplifier::new(body).simplify();
@@ -97,8 +90,8 @@ struct Inliner<'tcx> {
     codegen_fn_attrs: &'tcx CodegenFnAttrs,
     /// Caller HirID.
     hir_id: hir::HirId,
-    /// Stack of inlined Instances.
-    history: Vec<ty::Instance<'tcx>>,
+    /// Stack of inlined instances.
+    history: Vec<Instance<'tcx>>,
     /// Indicates that the caller body has been modified.
     changed: bool,
 }
@@ -110,28 +103,13 @@ impl Inliner<'tcx> {
                 None => continue,
                 Some(it) => it,
             };
-            let span = trace_span!("process_blocks", %callsite.callee, ?bb);
-            let _guard = span.enter();
-
-            trace!(
-                "checking for self recursion ({:?} vs body_source: {:?})",
-                callsite.callee.def_id(),
-                caller_body.source.def_id()
-            );
-            if callsite.callee.def_id() == caller_body.source.def_id() {
-                debug!("Not inlining a function into itself");
-                continue;
-            }
 
-            if !self.is_mir_available(callsite.callee, caller_body) {
+            if !self.is_mir_available(&callsite.callee, caller_body) {
                 debug!("MIR unavailable {}", callsite.callee);
                 continue;
             }
 
-            let span = trace_span!("instance_mir", %callsite.callee);
-            let instance_mir_guard = span.enter();
             let callee_body = self.tcx.instance_mir(callsite.callee.def);
-            drop(instance_mir_guard);
             if !self.should_inline(callsite, callee_body) {
                 continue;
             }
@@ -159,61 +137,28 @@ impl Inliner<'tcx> {
         }
     }
 
-    #[instrument(skip(self, caller_body))]
-    fn is_mir_available(&self, callee: Instance<'tcx>, caller_body: &Body<'tcx>) -> bool {
-        match callee.def {
-            InstanceDef::Item(_) => {
-                // If there is no MIR available (either because it was not in metadata or
-                // because it has no MIR because it's an extern function), then the inliner
-                // won't cause cycles on this.
-                if !self.tcx.is_mir_available(callee.def_id()) {
-                    return false;
-                }
+    fn is_mir_available(&self, callee: &Instance<'tcx>, caller_body: &Body<'tcx>) -> bool {
+        if let InstanceDef::Item(_) = callee.def {
+            if !self.tcx.is_mir_available(callee.def_id()) {
+                return false;
             }
-            // These have no own callable MIR.
-            InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => return false,
-            // This cannot result in an immediate cycle since the callee MIR is a shim, which does
-            // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we
-            // do not need to catch this here, we can wait until the inliner decides to continue
-            // inlining a second time.
-            InstanceDef::VtableShim(_)
-            | InstanceDef::ReifyShim(_)
-            | InstanceDef::FnPtrShim(..)
-            | InstanceDef::ClosureOnceShim { .. }
-            | InstanceDef::DropGlue(..)
-            | InstanceDef::CloneShim(..) => return true,
-        }
-
-        if self.tcx.is_constructor(callee.def_id()) {
-            trace!("constructors always have MIR");
-            // Constructor functions cannot cause a query cycle.
-            return true;
         }
 
         if let Some(callee_def_id) = callee.def_id().as_local() {
             let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id);
-            // Avoid inlining into generators,
+            // Avoid a cycle here by only using `instance_mir` only if we have
+            // a lower `HirId` than the callee. This ensures that the callee will
+            // not inline us. This trick only works without incremental compilation.
+            // So don't do it if that is enabled. Also avoid inlining into generators,
             // since their `optimized_mir` is used for layout computation, which can
             // create a cycle, even when no attempt is made to inline the function
             // in the other direction.
-            caller_body.generator_kind.is_none()
-                && (
-                    // Avoid a cycle here by only using `instance_mir` only if we have
-                    // a lower `HirId` than the callee. This ensures that the callee will
-                    // not inline us. This trick only works without incremental compilation.
-                    // So don't do it if that is enabled.
-                    !self.tcx.dep_graph.is_fully_enabled()
+            !self.tcx.dep_graph.is_fully_enabled()
                 && self.hir_id < callee_hir_id
-                // If we know for sure that the function we're calling will itself try to
-                // call us, then we avoid inlining that function.
-                || !self.tcx.mir_callgraph_reachable((callee, caller_body.source.def_id().expect_local()))
-                )
+                && caller_body.generator_kind.is_none()
         } else {
-            // This cannot result in an immediate cycle since the callee MIR is from another crate
-            // and is already optimized. Any subsequent inlining may cause cycles, but we do
-            // not need to catch this here, we can wait until the inliner decides to continue
-            // inlining a second time.
-            trace!("functions from other crates always have MIR");
+            // This cannot result in a cycle since the callee MIR is from another crate
+            // and is already optimized.
             true
         }
     }
@@ -258,8 +203,8 @@ impl Inliner<'tcx> {
         None
     }
 
-    #[instrument(skip(self, callee_body))]
     fn should_inline(&self, callsite: CallSite<'tcx>, callee_body: &Body<'tcx>) -> bool {
+        debug!("should_inline({:?})", callsite);
         let tcx = self.tcx;
 
         if callsite.fn_sig.c_variadic() {
@@ -388,9 +333,7 @@ impl Inliner<'tcx> {
                         if let Ok(Some(instance)) =
                             Instance::resolve(self.tcx, self.param_env, def_id, substs)
                         {
-                            if callsite.callee.def_id() == instance.def_id()
-                                || self.history.contains(&instance)
-                            {
+                            if callsite.callee == instance || self.history.contains(&instance) {
                                 debug!("`callee is recursive - not inlining");
                                 return false;
                             }
diff --git a/compiler/rustc_mir/src/transform/inline/cycle.rs b/compiler/rustc_mir/src/transform/inline/cycle.rs
deleted file mode 100644
index e4d403fbf60c0..0000000000000
--- a/compiler/rustc_mir/src/transform/inline/cycle.rs
+++ /dev/null
@@ -1,157 +0,0 @@
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::mir::TerminatorKind;
-use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::{self, subst::SubstsRef, InstanceDef, TyCtxt};
-
-// FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking
-// this query riddiculously often.
-#[instrument(skip(tcx, root, target))]
-crate fn mir_callgraph_reachable(
-    tcx: TyCtxt<'tcx>,
-    (root, target): (ty::Instance<'tcx>, LocalDefId),
-) -> bool {
-    trace!(%root, target = %tcx.def_path_str(target.to_def_id()));
-    let param_env = tcx.param_env_reveal_all_normalized(target);
-    assert_ne!(
-        root.def_id().expect_local(),
-        target,
-        "you should not call `mir_callgraph_reachable` on immediate self recursion"
-    );
-    assert!(
-        matches!(root.def, InstanceDef::Item(_)),
-        "you should not call `mir_callgraph_reachable` on shims"
-    );
-    assert!(
-        !tcx.is_constructor(root.def_id()),
-        "you should not call `mir_callgraph_reachable` on enum/struct constructor functions"
-    );
-    #[instrument(skip(tcx, param_env, target, stack, seen, recursion_limiter, caller))]
-    fn process(
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        caller: ty::Instance<'tcx>,
-        target: LocalDefId,
-        stack: &mut Vec<ty::Instance<'tcx>>,
-        seen: &mut FxHashSet<ty::Instance<'tcx>>,
-        recursion_limiter: &mut FxHashMap<DefId, usize>,
-    ) -> bool {
-        trace!(%caller);
-        for &(callee, substs) in tcx.mir_inliner_callees(caller.def) {
-            let substs = caller.subst_mir_and_normalize_erasing_regions(tcx, param_env, substs);
-            let callee = match ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() {
-                Some(callee) => callee,
-                None => {
-                    trace!(?callee, "cannot resolve, skipping");
-                    continue;
-                }
-            };
-
-            // Found a path.
-            if callee.def_id() == target.to_def_id() {
-                return true;
-            }
-
-            if tcx.is_constructor(callee.def_id()) {
-                trace!("constructors always have MIR");
-                // Constructor functions cannot cause a query cycle.
-                continue;
-            }
-
-            match callee.def {
-                InstanceDef::Item(_) => {
-                    // If there is no MIR available (either because it was not in metadata or
-                    // because it has no MIR because it's an extern function), then the inliner
-                    // won't cause cycles on this.
-                    if !tcx.is_mir_available(callee.def_id()) {
-                        trace!(?callee, "no mir available, skipping");
-                        continue;
-                    }
-                }
-                // These have no own callable MIR.
-                InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => continue,
-                // These have MIR and if that MIR is inlined, substituted and then inlining is run
-                // again, a function item can end up getting inlined. Thus we'll be able to cause
-                // a cycle that way
-                InstanceDef::VtableShim(_)
-                | InstanceDef::ReifyShim(_)
-                | InstanceDef::FnPtrShim(..)
-                | InstanceDef::ClosureOnceShim { .. }
-                | InstanceDef::CloneShim(..) => {}
-                InstanceDef::DropGlue(..) => {
-                    // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to
-                    // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this
-                    // needs some more analysis.
-                    if callee.needs_subst() {
-                        continue;
-                    }
-                }
-            }
-
-            if seen.insert(callee) {
-                let recursion = recursion_limiter.entry(callee.def_id()).or_default();
-                trace!(?callee, recursion = *recursion);
-                if tcx.sess.recursion_limit().value_within_limit(*recursion) {
-                    *recursion += 1;
-                    stack.push(callee);
-                    let found_recursion = ensure_sufficient_stack(|| {
-                        process(tcx, param_env, callee, target, stack, seen, recursion_limiter)
-                    });
-                    if found_recursion {
-                        return true;
-                    }
-                    stack.pop();
-                } else {
-                    // Pessimistically assume that there could be recursion.
-                    return true;
-                }
-            }
-        }
-        false
-    }
-    process(
-        tcx,
-        param_env,
-        root,
-        target,
-        &mut Vec::new(),
-        &mut FxHashSet::default(),
-        &mut FxHashMap::default(),
-    )
-}
-
-crate fn mir_inliner_callees<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    instance: ty::InstanceDef<'tcx>,
-) -> &'tcx [(DefId, SubstsRef<'tcx>)] {
-    let steal;
-    let guard;
-    let body = match (instance, instance.def_id().as_local()) {
-        (InstanceDef::Item(_), Some(def_id)) => {
-            let def = ty::WithOptConstParam::unknown(def_id);
-            steal = tcx.mir_promoted(def).0;
-            guard = steal.borrow();
-            &*guard
-        }
-        // Functions from other crates and MIR shims
-        _ => tcx.instance_mir(instance),
-    };
-    let mut calls = Vec::new();
-    for bb_data in body.basic_blocks() {
-        let terminator = bb_data.terminator();
-        if let TerminatorKind::Call { func, .. } = &terminator.kind {
-            let ty = func.ty(&body.local_decls, tcx);
-            let call = match ty.kind() {
-                ty::FnDef(def_id, substs) => (*def_id, *substs),
-                _ => continue,
-            };
-            // We've seen this before
-            if calls.contains(&call) {
-                continue;
-            }
-            calls.push(call);
-        }
-    }
-    tcx.arena.alloc_slice(&calls)
-}
diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs
index 74dadb2572565..b0c70372b161a 100644
--- a/compiler/rustc_mir/src/transform/instcombine.rs
+++ b/compiler/rustc_mir/src/transform/instcombine.rs
@@ -1,122 +1,329 @@
 //! Performs various peephole optimizations.
 
 use crate::transform::MirPass;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::Mutability;
+use rustc_index::vec::Idx;
 use rustc_middle::mir::{
-    BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
-    StatementKind,
+    visit::PlaceContext,
+    visit::{MutVisitor, Visitor},
+    Statement,
+};
+use rustc_middle::mir::{
+    BinOp, Body, BorrowKind, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem,
+    Rvalue,
 };
 use rustc_middle::ty::{self, TyCtxt};
+use std::mem;
 
 pub struct InstCombine;
 
 impl<'tcx> MirPass<'tcx> for InstCombine {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        let ctx = InstCombineContext { tcx, local_decls };
-        for block in basic_blocks.iter_mut() {
-            for statement in block.statements.iter_mut() {
-                match statement.kind {
-                    StatementKind::Assign(box (_place, ref mut rvalue)) => {
-                        ctx.combine_bool_cmp(&statement.source_info, rvalue);
-                        ctx.combine_ref_deref(&statement.source_info, rvalue);
-                        ctx.combine_len(&statement.source_info, rvalue);
-                    }
-                    _ => {}
-                }
-            }
+        // First, find optimization opportunities. This is done in a pre-pass to keep the MIR
+        // read-only so that we can do global analyses on the MIR in the process (e.g.
+        // `Place::ty()`).
+        let optimizations = {
+            let mut optimization_finder = OptimizationFinder::new(body, tcx);
+            optimization_finder.visit_body(body);
+            optimization_finder.optimizations
+        };
+
+        if !optimizations.is_empty() {
+            // Then carry out those optimizations.
+            MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body);
         }
     }
 }
 
-struct InstCombineContext<'tcx, 'a> {
+pub struct InstCombineVisitor<'tcx> {
+    optimizations: OptimizationList<'tcx>,
     tcx: TyCtxt<'tcx>,
-    local_decls: &'a LocalDecls<'tcx>,
 }
 
-impl<'tcx, 'a> InstCombineContext<'tcx, 'a> {
-    fn should_combine(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool {
+impl<'tcx> InstCombineVisitor<'tcx> {
+    fn should_combine(&self, rvalue: &Rvalue<'tcx>, location: Location) -> bool {
         self.tcx.consider_optimizing(|| {
-            format!("InstCombine - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info)
+            format!("InstCombine - Rvalue: {:?} Location: {:?}", rvalue, location)
         })
     }
+}
+
+impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
 
-    /// Transform boolean comparisons into logical operations.
-    fn combine_bool_cmp(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
-        match rvalue {
-            Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), a, b) => {
-                let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) {
-                    // Transform "Eq(a, true)" ==> "a"
-                    (BinOp::Eq, _, Some(true)) => Some(a.clone()),
-
-                    // Transform "Ne(a, false)" ==> "a"
-                    (BinOp::Ne, _, Some(false)) => Some(a.clone()),
-
-                    // Transform "Eq(true, b)" ==> "b"
-                    (BinOp::Eq, Some(true), _) => Some(b.clone()),
-
-                    // Transform "Ne(false, b)" ==> "b"
-                    (BinOp::Ne, Some(false), _) => Some(b.clone()),
-
-                    // FIXME: Consider combining remaining comparisons into logical operations:
-                    // Transform "Eq(false, b)" ==> "Not(b)"
-                    // Transform "Ne(true, b)" ==> "Not(b)"
-                    // Transform "Eq(a, false)" ==> "Not(a)"
-                    // Transform "Ne(a, true)" ==> "Not(a)"
-                    _ => None,
-                };
-
-                if let Some(new) = new {
-                    if self.should_combine(source_info, rvalue) {
-                        *rvalue = Rvalue::Use(new);
+    fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
+        if self.optimizations.and_stars.remove(&location) && self.should_combine(rvalue, location) {
+            debug!("replacing `&*`: {:?}", rvalue);
+            let new_place = match rvalue {
+                Rvalue::Ref(_, _, place) => {
+                    if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() {
+                        place.projection = self.tcx().intern_place_elems(&[proj_r]);
+
+                        Place {
+                            // Replace with dummy
+                            local: mem::replace(&mut place.local, Local::new(0)),
+                            projection: self.tcx().intern_place_elems(proj_l),
+                        }
+                    } else {
+                        unreachable!();
                     }
                 }
+                _ => bug!("Detected `&*` but didn't find `&*`!"),
+            };
+            *rvalue = Rvalue::Use(Operand::Copy(new_place))
+        }
+
+        if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) {
+            if self.should_combine(rvalue, location) {
+                debug!("replacing `Len([_; N])`: {:?}", rvalue);
+                *rvalue = Rvalue::Use(Operand::Constant(box constant));
+            }
+        }
+
+        if let Some(operand) = self.optimizations.unneeded_equality_comparison.remove(&location) {
+            if self.should_combine(rvalue, location) {
+                debug!("replacing {:?} with {:?}", rvalue, operand);
+                *rvalue = Rvalue::Use(operand);
+            }
+        }
+
+        if let Some(place) = self.optimizations.unneeded_deref.remove(&location) {
+            if self.should_combine(rvalue, location) {
+                debug!("unneeded_deref: replacing {:?} with {:?}", rvalue, place);
+                *rvalue = Rvalue::Use(Operand::Copy(place));
             }
+        }
+
+        // We do not call super_rvalue as we are not interested in any other parts of the tree
+    }
+}
+
+struct MutatingUseVisitor {
+    has_mutating_use: bool,
+    local_to_look_for: Local,
+}
+
+impl MutatingUseVisitor {
+    fn has_mutating_use_in_stmt(local: Local, stmt: &Statement<'tcx>, location: Location) -> bool {
+        let mut _self = Self { has_mutating_use: false, local_to_look_for: local };
+        _self.visit_statement(stmt, location);
+        _self.has_mutating_use
+    }
+}
 
-            _ => {}
+impl<'tcx> Visitor<'tcx> for MutatingUseVisitor {
+    fn visit_local(&mut self, local: &Local, context: PlaceContext, _: Location) {
+        if *local == self.local_to_look_for {
+            self.has_mutating_use |= context.is_mutating_use();
         }
     }
+}
+
+/// Finds optimization opportunities on the MIR.
+struct OptimizationFinder<'b, 'tcx> {
+    body: &'b Body<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    optimizations: OptimizationList<'tcx>,
+}
 
-    fn try_eval_bool(&self, a: &Operand<'_>) -> Option<bool> {
-        let a = a.constant()?;
-        if a.literal.ty.is_bool() { a.literal.val.try_to_bool() } else { None }
+impl OptimizationFinder<'b, 'tcx> {
+    fn new(body: &'b Body<'tcx>, tcx: TyCtxt<'tcx>) -> OptimizationFinder<'b, 'tcx> {
+        OptimizationFinder { body, tcx, optimizations: OptimizationList::default() }
     }
 
-    /// Transform "&(*a)" ==> "a".
-    fn combine_ref_deref(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
-        if let Rvalue::Ref(_, _, place) = rvalue {
-            if let Some((base, ProjectionElem::Deref)) = place.as_ref().last_projection() {
-                if let ty::Ref(_, _, Mutability::Not) =
-                    base.ty(self.local_decls, self.tcx).ty.kind()
-                {
-                    // The dereferenced place must have type `&_`, so that we don't copy `&mut _`.
-                } else {
-                    return;
-                }
+    fn find_deref_of_address(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option<()> {
+        // FIXME(#78192): This optimization can result in unsoundness.
+        if !self.tcx.sess.opts.debugging_opts.unsound_mir_opts {
+            return None;
+        }
+
+        // Look for the sequence
+        //
+        // _2 = &_1;
+        // ...
+        // _5 = (*_2);
+        //
+        // which we can replace the last statement with `_5 = _1;` to avoid the load of `_2`.
+        if let Rvalue::Use(op) = rvalue {
+            let local_being_derefed = match op.place()?.as_ref() {
+                PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local),
+                _ => None,
+            }?;
 
-                if !self.should_combine(source_info, rvalue) {
-                    return;
+            let mut dead_locals_seen = vec![];
+
+            let stmt_index = location.statement_index;
+            // Look behind for statement that assigns the local from a address of operator.
+            // 6 is chosen as a heuristic determined by seeing the number of times
+            // the optimization kicked in compiling rust std.
+            let lower_index = stmt_index.saturating_sub(6);
+            let statements_to_look_in = self.body.basic_blocks()[location.block].statements
+                [lower_index..stmt_index]
+                .iter()
+                .rev();
+            for stmt in statements_to_look_in {
+                match &stmt.kind {
+                    // Exhaustive match on statements to detect conditions that warrant we bail out of the optimization.
+                    rustc_middle::mir::StatementKind::Assign(box (l, r))
+                        if l.local == local_being_derefed =>
+                    {
+                        match r {
+                            // Looking for immutable reference e.g _local_being_deref = &_1;
+                            Rvalue::Ref(
+                                _,
+                                // Only apply the optimization if it is an immutable borrow.
+                                BorrowKind::Shared,
+                                place_taken_address_of,
+                            ) => {
+                                // Make sure that the place has not been marked dead
+                                if dead_locals_seen.contains(&place_taken_address_of.local) {
+                                    return None;
+                                }
+
+                                self.optimizations
+                                    .unneeded_deref
+                                    .insert(location, *place_taken_address_of);
+                                return Some(());
+                            }
+
+                            // We found an assignment of `local_being_deref` that is not an immutable ref, e.g the following sequence
+                            // _2 = &_1;
+                            // _3 = &5
+                            // _2 = _3;  <-- this means it is no longer valid to replace the last statement with `_5 = _1;`
+                            // _5 = (*_2);
+                            _ => return None,
+                        }
+                    }
+
+                    // Inline asm can do anything, so bail out of the optimization.
+                    rustc_middle::mir::StatementKind::LlvmInlineAsm(_) => return None,
+
+                    // Remember `StorageDead`s, as the local being marked dead could be the
+                    // place RHS we are looking for, in which case we need to abort to avoid UB
+                    // using an uninitialized place
+                    rustc_middle::mir::StatementKind::StorageDead(dead) => {
+                        dead_locals_seen.push(*dead)
+                    }
+
+                    // Check that `local_being_deref` is not being used in a mutating way which can cause misoptimization.
+                    rustc_middle::mir::StatementKind::Assign(box (_, _))
+                    | rustc_middle::mir::StatementKind::Coverage(_)
+                    | rustc_middle::mir::StatementKind::Nop
+                    | rustc_middle::mir::StatementKind::FakeRead(_, _)
+                    | rustc_middle::mir::StatementKind::StorageLive(_)
+                    | rustc_middle::mir::StatementKind::Retag(_, _)
+                    | rustc_middle::mir::StatementKind::AscribeUserType(_, _)
+                    | rustc_middle::mir::StatementKind::SetDiscriminant { .. } => {
+                        if MutatingUseVisitor::has_mutating_use_in_stmt(
+                            local_being_derefed,
+                            stmt,
+                            location,
+                        ) {
+                            return None;
+                        }
+                    }
                 }
+            }
+        }
+        Some(())
+    }
 
-                *rvalue = Rvalue::Use(Operand::Copy(Place {
-                    local: base.local,
-                    projection: self.tcx.intern_place_elems(base.projection),
-                }));
+    fn find_unneeded_equality_comparison(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+        // find Ne(_place, false) or Ne(false, _place)
+        // or   Eq(_place, true) or Eq(true, _place)
+        if let Rvalue::BinaryOp(op, l, r) = rvalue {
+            let const_to_find = if *op == BinOp::Ne {
+                false
+            } else if *op == BinOp::Eq {
+                true
+            } else {
+                return;
+            };
+            // (const, _place)
+            if let Some(o) = self.find_operand_in_equality_comparison_pattern(l, r, const_to_find) {
+                self.optimizations.unneeded_equality_comparison.insert(location, o.clone());
+            }
+            // (_place, const)
+            else if let Some(o) =
+                self.find_operand_in_equality_comparison_pattern(r, l, const_to_find)
+            {
+                self.optimizations.unneeded_equality_comparison.insert(location, o.clone());
             }
         }
     }
 
-    /// Transform "Len([_; N])" ==> "N".
-    fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+    fn find_operand_in_equality_comparison_pattern(
+        &self,
+        l: &Operand<'tcx>,
+        r: &'a Operand<'tcx>,
+        const_to_find: bool,
+    ) -> Option<&'a Operand<'tcx>> {
+        let const_ = l.constant()?;
+        if const_.literal.ty == self.tcx.types.bool
+            && const_.literal.val.try_to_bool() == Some(const_to_find)
+        {
+            if r.place().is_some() {
+                return Some(r);
+            }
+        }
+
+        None
+    }
+}
+
+impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
+    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+        if let Rvalue::Ref(_, _, place) = rvalue {
+            if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() {
+                // The dereferenced place must have type `&_`.
+                let ty = place_base.ty(self.body, self.tcx).ty;
+                if let ty::Ref(_, _, Mutability::Not) = ty.kind() {
+                    self.optimizations.and_stars.insert(location);
+                }
+            }
+        }
+
         if let Rvalue::Len(ref place) = *rvalue {
-            let place_ty = place.ty(self.local_decls, self.tcx).ty;
+            let place_ty = place.ty(&self.body.local_decls, self.tcx).ty;
             if let ty::Array(_, len) = place_ty.kind() {
-                if !self.should_combine(source_info, rvalue) {
-                    return;
-                }
+                let span = self.body.source_info(location).span;
+                let constant = Constant { span, literal: len, user_ty: None };
+                self.optimizations.arrays_lengths.insert(location, constant);
+            }
+        }
 
-                let constant = Constant { span: source_info.span, literal: len, user_ty: None };
-                *rvalue = Rvalue::Use(Operand::Constant(box constant));
+        let _ = self.find_deref_of_address(rvalue, location);
+
+        self.find_unneeded_equality_comparison(rvalue, location);
+
+        // We do not call super_rvalue as we are not interested in any other parts of the tree
+    }
+}
+
+#[derive(Default)]
+struct OptimizationList<'tcx> {
+    and_stars: FxHashSet<Location>,
+    arrays_lengths: FxHashMap<Location, Constant<'tcx>>,
+    unneeded_equality_comparison: FxHashMap<Location, Operand<'tcx>>,
+    unneeded_deref: FxHashMap<Location, Place<'tcx>>,
+}
+
+impl<'tcx> OptimizationList<'tcx> {
+    fn is_empty(&self) -> bool {
+        match self {
+            OptimizationList {
+                and_stars,
+                arrays_lengths,
+                unneeded_equality_comparison,
+                unneeded_deref,
+            } => {
+                and_stars.is_empty()
+                    && arrays_lengths.is_empty()
+                    && unneeded_equality_comparison.is_empty()
+                    && unneeded_deref.is_empty()
             }
         }
     }
diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs
index 2786127513d38..e509c35de40b8 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir/src/transform/mod.rs
@@ -419,20 +419,6 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
         tcx.ensure().mir_borrowck(def.did);
     }
 
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
-    use rustc_middle::hir::map::blocks::FnLikeNode;
-    let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
-    if is_fn_like {
-        let did = def.did.to_def_id();
-        let def = ty::WithOptConstParam::unknown(did);
-
-        // Do not compute the mir call graph without said call graph actually being used.
-        // Keep this in sync with the mir inliner's optimization level.
-        if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
-            let _ = tcx.mir_inliner_callees(ty::InstanceDef::Item(def));
-        }
-    }
-
     let (body, _) = tcx.mir_promoted(def);
     let mut body = body.steal();
 
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index d8758e045443c..cac5abb1059a8 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -415,11 +415,10 @@ impl<'tcx> Validator<'_, 'tcx> {
     // FIXME(eddyb) maybe cache this?
     fn validate_local(&self, local: Local) -> Result<(), Unpromotable> {
         if let TempState::Defined { location: loc, .. } = self.temps[local] {
-            let block = &self.body[loc.block];
-            let num_stmts = block.statements.len();
+            let num_stmts = self.body[loc.block].statements.len();
 
             if loc.statement_index < num_stmts {
-                let statement = &block.statements[loc.statement_index];
+                let statement = &self.body[loc.block].statements[loc.statement_index];
                 match &statement.kind {
                     StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
                     _ => {
@@ -431,7 +430,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                     }
                 }
             } else {
-                let terminator = block.terminator();
+                let terminator = self.body[loc.block].terminator();
                 match &terminator.kind {
                     TerminatorKind::Call { func, args, .. } => self.validate_call(func, args),
                     TerminatorKind::Yield { .. } => Err(Unpromotable),
@@ -453,15 +452,22 @@ impl<'tcx> Validator<'_, 'tcx> {
                 match elem {
                     ProjectionElem::Deref => {
                         let mut promotable = false;
-                        // We need to make sure this is a `Deref` of a local with no further projections.
+                        // The `is_empty` predicate is introduced to exclude the case
+                        // where the projection operations are [ .field, * ].
+                        // The reason is because promotion will be illegal if field
+                        // accesses precede the dereferencing.
                         // Discussion can be found at
                         // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
-                        if let Some(local) = place_base.as_local() {
+                        // There may be opportunity for generalization, but this needs to be
+                        // accounted for.
+                        if place_base.projection.is_empty() {
                             // This is a special treatment for cases like *&STATIC where STATIC is a
                             // global static variable.
                             // This pattern is generated only when global static variables are directly
                             // accessed and is qualified for promotion safely.
-                            if let TempState::Defined { location, .. } = self.temps[local] {
+                            if let TempState::Defined { location, .. } =
+                                self.temps[place_base.local]
+                            {
                                 let def_stmt = self.body[location.block]
                                     .statements
                                     .get(location.statement_index);
@@ -499,50 +505,6 @@ impl<'tcx> Validator<'_, 'tcx> {
                     ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {}
 
                     ProjectionElem::Index(local) => {
-                        if !self.explicit {
-                            let mut promotable = false;
-                            // Only accept if we can predict the index and are indexing an array.
-                            let val = if let TempState::Defined { location: loc, .. } =
-                                self.temps[local]
-                            {
-                                let block = &self.body[loc.block];
-                                if loc.statement_index < block.statements.len() {
-                                    let statement = &block.statements[loc.statement_index];
-                                    match &statement.kind {
-                                        StatementKind::Assign(box (
-                                            _,
-                                            Rvalue::Use(Operand::Constant(c)),
-                                        )) => c.literal.try_eval_usize(self.tcx, self.param_env),
-                                        _ => None,
-                                    }
-                                } else {
-                                    None
-                                }
-                            } else {
-                                None
-                            };
-                            if let Some(idx) = val {
-                                // Determine the type of the thing we are indexing.
-                                let ty = place_base.ty(self.body, self.tcx).ty;
-                                match ty.kind() {
-                                    ty::Array(_, len) => {
-                                        // It's an array; determine its length.
-                                        if let Some(len) =
-                                            len.try_eval_usize(self.tcx, self.param_env)
-                                        {
-                                            // If the index is in-bounds, go ahead.
-                                            if idx < len {
-                                                promotable = true;
-                                            }
-                                        }
-                                    }
-                                    _ => {}
-                                }
-                            }
-                            if !promotable {
-                                return Err(Unpromotable);
-                            }
-                        }
                         self.validate_local(local)?;
                     }
 
@@ -627,7 +589,9 @@ impl<'tcx> Validator<'_, 'tcx> {
 
     fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
         match rvalue {
-            Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
+            Rvalue::Use(operand)
+            | Rvalue::Repeat(operand, _)
+            | Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => {
                 self.validate_operand(operand)?;
             }
 
@@ -652,26 +616,10 @@ impl<'tcx> Validator<'_, 'tcx> {
                 self.validate_operand(operand)?;
             }
 
-            Rvalue::NullaryOp(op, _) => match op {
-                NullOp::Box => return Err(Unpromotable),
-                NullOp::SizeOf => {}
-            },
-
-            Rvalue::UnaryOp(op, operand) => {
-                match op {
-                    // These operations can never fail.
-                    UnOp::Neg | UnOp::Not => {}
-                }
-
-                self.validate_operand(operand)?;
-            }
-
             Rvalue::BinaryOp(op, lhs, rhs) | Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
                 let op = *op;
-                let lhs_ty = lhs.ty(self.body, self.tcx);
-
-                if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() {
-                    // Raw and fn pointer operations are not allowed inside consts and thus not promotable.
+                if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() {
+                    // raw pointer operations are not allowed inside consts and thus not promotable
                     assert!(matches!(
                         op,
                         BinOp::Eq
@@ -686,22 +634,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                 }
 
                 match op {
-                    BinOp::Div | BinOp::Rem => {
-                        if !self.explicit && lhs_ty.is_integral() {
-                            // Integer division: the RHS must be a non-zero const.
-                            let const_val = match rhs {
-                                Operand::Constant(c) => {
-                                    c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty)
-                                }
-                                _ => None,
-                            };
-                            match const_val {
-                                Some(x) if x != 0 => {}        // okay
-                                _ => return Err(Unpromotable), // value not known or 0 -- not okay
-                            }
-                        }
-                    }
-                    // The remaining operations can never fail.
+                    // FIXME: reject operations that can fail -- namely, division and modulo.
                     BinOp::Eq
                     | BinOp::Ne
                     | BinOp::Le
@@ -712,6 +645,8 @@ impl<'tcx> Validator<'_, 'tcx> {
                     | BinOp::Add
                     | BinOp::Sub
                     | BinOp::Mul
+                    | BinOp::Div
+                    | BinOp::Rem
                     | BinOp::BitXor
                     | BinOp::BitAnd
                     | BinOp::BitOr
@@ -723,6 +658,11 @@ impl<'tcx> Validator<'_, 'tcx> {
                 self.validate_operand(rhs)?;
             }
 
+            Rvalue::NullaryOp(op, _) => match op {
+                NullOp::Box => return Err(Unpromotable),
+                NullOp::SizeOf => {}
+            },
+
             Rvalue::AddressOf(_, place) => {
                 // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
                 // no problem, only using it is.
diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
index 5144d48750de7..221114eebaa45 100644
--- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
@@ -1,8 +1,9 @@
 //! This pass replaces a drop of a type that does not need dropping, with a goto
 
 use crate::transform::MirPass;
+use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{ParamEnv, TyCtxt};
 
 use super::simplify::simplify_cfg;
 
@@ -11,26 +12,24 @@ pub struct RemoveUnneededDrops;
 impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running RemoveUnneededDrops on {:?}", body.source);
-
-        let did = body.source.def_id();
-        let param_env = tcx.param_env(did);
-        let mut should_simplify = false;
-
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        for block in basic_blocks {
-            let terminator = block.terminator_mut();
-            if let TerminatorKind::Drop { place, target, .. } = terminator.kind {
-                let ty = place.ty(local_decls, tcx);
-                if ty.ty.needs_drop(tcx, param_env) {
-                    continue;
-                }
-                if !tcx.consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", did)) {
-                    continue;
-                }
-                debug!("SUCCESS: replacing `drop` with goto({:?})", target);
-                terminator.kind = TerminatorKind::Goto { target };
-                should_simplify = true;
+        let mut opt_finder = RemoveUnneededDropsOptimizationFinder {
+            tcx,
+            body,
+            param_env: tcx.param_env(body.source.def_id()),
+            optimizations: vec![],
+        };
+        opt_finder.visit_body(body);
+        let should_simplify = !opt_finder.optimizations.is_empty();
+        for (loc, target) in opt_finder.optimizations {
+            if !tcx
+                .consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", body.source.def_id()))
+            {
+                break;
             }
+
+            let terminator = body.basic_blocks_mut()[loc.block].terminator_mut();
+            debug!("SUCCESS: replacing `drop` with goto({:?})", target);
+            terminator.kind = TerminatorKind::Goto { target };
         }
 
         // if we applied optimizations, we potentially have some cfg to cleanup to
@@ -40,3 +39,25 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
         }
     }
 }
+
+impl<'a, 'tcx> Visitor<'tcx> for RemoveUnneededDropsOptimizationFinder<'a, 'tcx> {
+    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
+        match terminator.kind {
+            TerminatorKind::Drop { place, target, .. } => {
+                let ty = place.ty(self.body, self.tcx);
+                let needs_drop = ty.ty.needs_drop(self.tcx, self.param_env);
+                if !needs_drop {
+                    self.optimizations.push((location, target));
+                }
+            }
+            _ => {}
+        }
+        self.super_terminator(terminator, location);
+    }
+}
+pub struct RemoveUnneededDropsOptimizationFinder<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    body: &'a Body<'tcx>,
+    optimizations: Vec<(Location, BasicBlock)>,
+    param_env: ParamEnv<'tcx>,
+}
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 2962cbe8157f6..595458702e9c9 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -546,7 +546,9 @@ fn make_mirror_unadjusted<'a, 'tcx>(
             scrutinee: discr.to_ref(),
             arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
         },
-        hir::ExprKind::Loop(ref body, ..) => ExprKind::Loop { body: block::to_expr_ref(cx, body) },
+        hir::ExprKind::Loop(ref body, _, _) => {
+            ExprKind::Loop { body: block::to_expr_ref(cx, body) }
+        }
         hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
             lhs: source.to_ref(),
             name: Field::new(cx.tcx.field_index(expr.hir_id, cx.typeck_results)),
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index c365acac625a4..62fd6936d210d 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -292,7 +292,7 @@ pub fn nt_to_tokenstream(
     } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) {
         return fake_token_stream(sess, nt);
     } else {
-        panic!("Missing tokens for nt at {:?}: {:?}", nt.span(), pprust::nonterminal_to_string(nt));
+        panic!("Missing tokens for nt {:?}", pprust::nonterminal_to_string(nt));
     }
 }
 
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index f2fcce5c22662..35435baea7019 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2,13 +2,14 @@ use super::ty::AllowPlus;
 use super::TokenType;
 use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType};
 
-use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Lit, LitKind, TokenKind};
 use rustc_ast::util::parser::AssocOp;
-use rustc_ast::{AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec};
-use rustc_ast::{BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item};
-use rustc_ast::{ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty, TyKind};
+use rustc_ast::{
+    self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
+    Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item, ItemKind, Mutability, Param, Pat,
+    PatKind, Path, PathSegment, QSelf, Ty, TyKind,
+};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, struct_span_err};
@@ -219,7 +220,6 @@ impl<'a> Parser<'a> {
         edible: &[TokenKind],
         inedible: &[TokenKind],
     ) -> PResult<'a, bool /* recovered */> {
-        debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
         fn tokens_to_string(tokens: &[TokenType]) -> String {
             let mut i = tokens.iter();
             // This might be a sign we need a connect method on `Iterator`.
@@ -245,7 +245,6 @@ impl<'a> Parser<'a> {
             .collect::<Vec<_>>();
         expected.sort_by_cached_key(|x| x.to_string());
         expected.dedup();
-
         let expect = tokens_to_string(&expected[..]);
         let actual = super::token_descr(&self.token);
         let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
@@ -271,16 +270,6 @@ impl<'a> Parser<'a> {
         };
         self.last_unexpected_token_span = Some(self.token.span);
         let mut err = self.struct_span_err(self.token.span, &msg_exp);
-
-        // Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens
-        // there are unclosed angle brackets
-        if self.unmatched_angle_bracket_count > 0
-            && self.token.kind == TokenKind::Eq
-            && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Gt)))
-        {
-            err.span_label(self.prev_token.span, "maybe try to close unmatched angle bracket");
-        }
-
         let sp = if self.token == token::Eof {
             // This is EOF; don't want to point at the following char, but rather the last token.
             self.prev_token.span
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index cfd7ad48222a2..6db415ead415c 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -472,11 +472,7 @@ impl<'a> Parser<'a> {
     /// Parses a prefix-unary-operator expr.
     fn parse_prefix_expr(&mut self, attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> {
         let attrs = self.parse_or_use_outer_attributes(attrs)?;
-        // FIXME: Use super::attr::maybe_needs_tokens(&attrs) once we come up
-        // with a good way of passing `force_tokens` through from `parse_nonterminal`.
-        // Checking !attrs.is_empty() is correct, but will cause us to unnecessarily
-        // capture tokens in some circumstances.
-        let needs_tokens = !attrs.is_empty();
+        let needs_tokens = super::attr::maybe_needs_tokens(&attrs);
         let do_parse = |this: &mut Parser<'a>| {
             let lo = this.token.span;
             // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
@@ -585,7 +581,7 @@ impl<'a> Parser<'a> {
         lhs_span: Span,
         expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
     ) -> PResult<'a, P<Expr>> {
-        let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| {
+        let mk_expr = |this: &mut Self, rhs: P<Ty>| {
             this.mk_expr(
                 this.mk_expr_sp(&lhs, lhs_span, rhs.span),
                 expr_kind(lhs, rhs),
@@ -597,49 +593,13 @@ impl<'a> Parser<'a> {
         // LessThan comparison after this cast.
         let parser_snapshot_before_type = self.clone();
         let cast_expr = match self.parse_ty_no_plus() {
-            Ok(rhs) => mk_expr(self, lhs, rhs),
+            Ok(rhs) => mk_expr(self, rhs),
             Err(mut type_err) => {
                 // Rewind to before attempting to parse the type with generics, to recover
                 // from situations like `x as usize < y` in which we first tried to parse
                 // `usize < y` as a type with generic arguments.
                 let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
 
-                // Check for typo of `'a: loop { break 'a }` with a missing `'`.
-                match (&lhs.kind, &self.token.kind) {
-                    (
-                        // `foo: `
-                        ExprKind::Path(None, ast::Path { segments, .. }),
-                        TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
-                    ) if segments.len() == 1 => {
-                        let snapshot = self.clone();
-                        let label = Label {
-                            ident: Ident::from_str_and_span(
-                                &format!("'{}", segments[0].ident),
-                                segments[0].ident.span,
-                            ),
-                        };
-                        match self.parse_labeled_expr(label, AttrVec::new(), false) {
-                            Ok(expr) => {
-                                type_err.cancel();
-                                self.struct_span_err(label.ident.span, "malformed loop label")
-                                    .span_suggestion(
-                                        label.ident.span,
-                                        "use the correct loop label format",
-                                        label.ident.to_string(),
-                                        Applicability::MachineApplicable,
-                                    )
-                                    .emit();
-                                return Ok(expr);
-                            }
-                            Err(mut err) => {
-                                err.cancel();
-                                *self = snapshot;
-                            }
-                        }
-                    }
-                    _ => {}
-                }
-
                 match self.parse_path(PathStyle::Expr) {
                     Ok(path) => {
                         let (op_noun, op_verb) = match self.token.kind {
@@ -666,8 +626,7 @@ impl<'a> Parser<'a> {
                             op_noun,
                         );
                         let span_after_type = parser_snapshot_after_type.token.span;
-                        let expr =
-                            mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
+                        let expr = mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path)));
 
                         let expr_str = self
                             .span_to_snippet(expr.span)
@@ -1104,7 +1063,7 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(kw::While) {
             self.parse_while_expr(None, self.prev_token.span, attrs)
         } else if let Some(label) = self.eat_label() {
-            self.parse_labeled_expr(label, attrs, true)
+            self.parse_labeled_expr(label, attrs)
         } else if self.eat_keyword(kw::Loop) {
             self.parse_loop_expr(None, self.prev_token.span, attrs)
         } else if self.eat_keyword(kw::Continue) {
@@ -1265,12 +1224,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse `'label: $expr`. The label is already parsed.
-    fn parse_labeled_expr(
-        &mut self,
-        label: Label,
-        attrs: AttrVec,
-        consume_colon: bool,
-    ) -> PResult<'a, P<Expr>> {
+    fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = label.ident.span;
         let label = Some(label);
         let ate_colon = self.eat(&token::Colon);
@@ -1289,7 +1243,7 @@ impl<'a> Parser<'a> {
             self.parse_expr()
         }?;
 
-        if !ate_colon && consume_colon {
+        if !ate_colon {
             self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
         }
 
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 1ed4d39cd0539..810ae61307c19 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1,8 +1,8 @@
 use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
+use super::{FollowedByType, Parser, PathStyle};
 
-use crate::{maybe_collect_tokens, maybe_whole};
+use crate::maybe_whole;
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, TokenKind};
@@ -69,7 +69,7 @@ impl<'a> Parser<'a> {
         unsafety: Unsafe,
     ) -> PResult<'a, Mod> {
         let mut items = vec![];
-        while let Some(item) = self.parse_item(ForceCollect::No)? {
+        while let Some(item) = self.parse_item()? {
             items.push(item);
             self.maybe_consume_incorrect_semicolon(&items);
         }
@@ -93,17 +93,13 @@ impl<'a> Parser<'a> {
 pub(super) type ItemInfo = (Ident, ItemKind);
 
 impl<'a> Parser<'a> {
-    pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<P<Item>>> {
-        self.parse_item_(|_| true, force_collect).map(|i| i.map(P))
+    pub fn parse_item(&mut self) -> PResult<'a, Option<P<Item>>> {
+        self.parse_item_(|_| true).map(|i| i.map(P))
     }
 
-    fn parse_item_(
-        &mut self,
-        req_name: ReqName,
-        force_collect: ForceCollect,
-    ) -> PResult<'a, Option<Item>> {
+    fn parse_item_(&mut self, req_name: ReqName) -> PResult<'a, Option<Item>> {
         let attrs = self.parse_outer_attributes()?;
-        self.parse_item_common(attrs, true, false, req_name, force_collect)
+        self.parse_item_common(attrs, true, false, req_name)
     }
 
     pub(super) fn parse_item_common(
@@ -112,7 +108,6 @@ impl<'a> Parser<'a> {
         mac_allowed: bool,
         attrs_allowed: bool,
         req_name: ReqName,
-        force_collect: ForceCollect,
     ) -> PResult<'a, Option<Item>> {
         maybe_whole!(self, NtItem, |item| {
             let mut item = item;
@@ -121,12 +116,16 @@ impl<'a> Parser<'a> {
             Some(item.into_inner())
         });
 
+        let needs_tokens = super::attr::maybe_needs_tokens(&attrs);
+
         let mut unclosed_delims = vec![];
-        let item = maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Self| {
+        let parse_item = |this: &mut Self| {
             let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
             unclosed_delims.append(&mut this.unclosed_delims);
-            Ok((item?, TrailingToken::None))
-        })?;
+            item
+        };
+
+        let item = if needs_tokens { self.collect_tokens(parse_item) } else { parse_item(self) }?;
 
         self.unclosed_delims.append(&mut unclosed_delims);
         Ok(item)
@@ -732,22 +731,20 @@ impl<'a> Parser<'a> {
 
     /// Parses associated items.
     fn parse_assoc_item(&mut self, req_name: ReqName) -> PResult<'a, Option<Option<P<AssocItem>>>> {
-        Ok(self.parse_item_(req_name, ForceCollect::No)?.map(
-            |Item { attrs, id, span, vis, ident, kind, tokens }| {
-                let kind = match AssocItemKind::try_from(kind) {
-                    Ok(kind) => kind,
-                    Err(kind) => match kind {
-                        ItemKind::Static(a, _, b) => {
-                            self.struct_span_err(span, "associated `static` items are not allowed")
-                                .emit();
-                            AssocItemKind::Const(Defaultness::Final, a, b)
-                        }
-                        _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"),
-                    },
-                };
-                Some(P(Item { attrs, id, span, vis, ident, kind, tokens }))
-            },
-        ))
+        Ok(self.parse_item_(req_name)?.map(|Item { attrs, id, span, vis, ident, kind, tokens }| {
+            let kind = match AssocItemKind::try_from(kind) {
+                Ok(kind) => kind,
+                Err(kind) => match kind {
+                    ItemKind::Static(a, _, b) => {
+                        self.struct_span_err(span, "associated `static` items are not allowed")
+                            .emit();
+                        AssocItemKind::Const(Defaultness::Final, a, b)
+                    }
+                    _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"),
+                },
+            };
+            Some(P(Item { attrs, id, span, vis, ident, kind, tokens }))
+        }))
     }
 
     /// Parses a `type` alias with the following grammar:
@@ -924,21 +921,19 @@ impl<'a> Parser<'a> {
 
     /// Parses a foreign item (one in an `extern { ... }` block).
     pub fn parse_foreign_item(&mut self) -> PResult<'a, Option<Option<P<ForeignItem>>>> {
-        Ok(self.parse_item_(|_| true, ForceCollect::No)?.map(
-            |Item { attrs, id, span, vis, ident, kind, tokens }| {
-                let kind = match ForeignItemKind::try_from(kind) {
-                    Ok(kind) => kind,
-                    Err(kind) => match kind {
-                        ItemKind::Const(_, a, b) => {
-                            self.error_on_foreign_const(span, ident);
-                            ForeignItemKind::Static(a, Mutability::Not, b)
-                        }
-                        _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"),
-                    },
-                };
-                Some(P(Item { attrs, id, span, vis, ident, kind, tokens }))
-            },
-        ))
+        Ok(self.parse_item_(|_| true)?.map(|Item { attrs, id, span, vis, ident, kind, tokens }| {
+            let kind = match ForeignItemKind::try_from(kind) {
+                Ok(kind) => kind,
+                Err(kind) => match kind {
+                    ItemKind::Const(_, a, b) => {
+                        self.error_on_foreign_const(span, ident);
+                        ForeignItemKind::Static(a, Mutability::Not, b)
+                    }
+                    _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"),
+                },
+            };
+            Some(P(Item { attrs, id, span, vis, ident, kind, tokens }))
+        }))
     }
 
     fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option<T> {
@@ -1520,7 +1515,7 @@ impl<'a> Parser<'a> {
         {
             let kw_token = self.token.clone();
             let kw_str = pprust::token_to_string(&kw_token);
-            let item = self.parse_item(ForceCollect::No)?;
+            let item = self.parse_item()?;
 
             self.struct_span_err(
                 kw_token.span,
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index c575c8219641c..5d7ea5b8d578e 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -54,18 +54,6 @@ enum BlockMode {
     Ignore,
 }
 
-/// Whether or not we should force collection of tokens for an AST node,
-/// regardless of whether or not it has attributes
-pub enum ForceCollect {
-    Yes,
-    No,
-}
-
-pub enum TrailingToken {
-    None,
-    Semi,
-}
-
 /// Like `maybe_whole_expr`, but for things other than expressions.
 #[macro_export]
 macro_rules! maybe_whole {
@@ -277,7 +265,7 @@ impl TokenCursor {
     }
 }
 
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Clone, PartialEq)]
 enum TokenType {
     Token(TokenKind),
     Keyword(Symbol),
@@ -980,8 +968,12 @@ impl<'a> Parser<'a> {
                         }
                     }
 
-                    // Collect tokens because they are used during lowering to HIR.
-                    let expr = self.collect_tokens(|this| this.parse_expr())?;
+                    // The value here is never passed to macros as tokens by itself (not as a part
+                    // of the whole attribute), so we don't collect tokens here. If this changes,
+                    // then token will need to be collected. One catch here is that we are using
+                    // a nonterminal for keeping the expression, but this nonterminal should not
+                    // be wrapped into a group when converting to token stream.
+                    let expr = self.parse_expr()?;
                     let span = expr.span;
 
                     match &expr.kind {
@@ -1226,13 +1218,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    pub fn collect_tokens<R: HasTokens>(
-        &mut self,
-        f: impl FnOnce(&mut Self) -> PResult<'a, R>,
-    ) -> PResult<'a, R> {
-        self.collect_tokens_trailing_token(|this| Ok((f(this)?, TrailingToken::None)))
-    }
-
     /// Records all tokens consumed by the provided callback,
     /// including the current token. These tokens are collected
     /// into a `LazyTokenStream`, and returned along with the result
@@ -1249,9 +1234,9 @@ impl<'a> Parser<'a> {
     /// This restriction shouldn't be an issue in practice,
     /// since this function is used to record the tokens for
     /// a parsed AST item, which always has matching delimiters.
-    pub fn collect_tokens_trailing_token<R: HasTokens>(
+    pub fn collect_tokens<R: HasTokens>(
         &mut self,
-        f: impl FnOnce(&mut Self) -> PResult<'a, (R, TrailingToken)>,
+        f: impl FnOnce(&mut Self) -> PResult<'a, R>,
     ) -> PResult<'a, R> {
         let start_token = (self.token.clone(), self.token_spacing);
         let cursor_snapshot = TokenCursor {
@@ -1264,7 +1249,7 @@ impl<'a> Parser<'a> {
             append_unglued_token: self.token_cursor.append_unglued_token.clone(),
         };
 
-        let (mut ret, trailing_token) = f(self)?;
+        let mut ret = f(self)?;
 
         // Produces a `TokenStream` on-demand. Using `cursor_snapshot`
         // and `num_calls`, we can reconstruct the `TokenStream` seen
@@ -1283,10 +1268,15 @@ impl<'a> Parser<'a> {
             cursor_snapshot: TokenCursor,
             num_calls: usize,
             desugar_doc_comments: bool,
+            trailing_semi: bool,
             append_unglued_token: Option<TreeAndSpacing>,
         }
         impl CreateTokenStream for LazyTokenStreamImpl {
             fn create_token_stream(&self) -> TokenStream {
+                let mut num_calls = self.num_calls;
+                if self.trailing_semi {
+                    num_calls += 1;
+                }
                 // The token produced by the final call to `next` or `next_desugared`
                 // was not actually consumed by the callback. The combination
                 // of chaining the initial token and using `take` produces the desired
@@ -1294,33 +1284,39 @@ impl<'a> Parser<'a> {
                 // and omit the final token otherwise.
                 let mut cursor_snapshot = self.cursor_snapshot.clone();
                 let tokens = std::iter::once(self.start_token.clone())
-                    .chain((0..self.num_calls).map(|_| {
+                    .chain((0..num_calls).map(|_| {
                         if self.desugar_doc_comments {
                             cursor_snapshot.next_desugared()
                         } else {
                             cursor_snapshot.next()
                         }
                     }))
-                    .take(self.num_calls);
+                    .take(num_calls);
 
                 make_token_stream(tokens, self.append_unglued_token.clone())
             }
-        }
-
-        let mut num_calls = self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls;
-        match trailing_token {
-            TrailingToken::None => {}
-            TrailingToken::Semi => {
-                assert_eq!(self.token.kind, token::Semi);
-                num_calls += 1;
+            fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream> {
+                if self.trailing_semi {
+                    panic!("Called `add_trailing_semi` twice!");
+                }
+                if self.append_unglued_token.is_some() {
+                    panic!(
+                        "Cannot call `add_trailing_semi` when we have an unglued token {:?}",
+                        self.append_unglued_token
+                    );
+                }
+                let mut new = self.clone();
+                new.trailing_semi = true;
+                Box::new(new)
             }
         }
 
         let lazy_impl = LazyTokenStreamImpl {
             start_token,
-            num_calls,
+            num_calls: self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls,
             cursor_snapshot,
             desugar_doc_comments: self.desugar_doc_comments,
+            trailing_semi: false,
             append_unglued_token: self.token_cursor.append_unglued_token.clone(),
         };
         ret.finalize_tokens(LazyTokenStream::new(lazy_impl));
@@ -1417,16 +1413,3 @@ fn make_token_stream(
     assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack);
     TokenStream::new(final_buf.inner)
 }
-
-#[macro_export]
-macro_rules! maybe_collect_tokens {
-    ($self:ident, $force_collect:expr, $attrs:expr, $f:expr) => {
-        if matches!($force_collect, ForceCollect::Yes)
-            || $crate::parser::attr::maybe_needs_tokens($attrs)
-        {
-            $self.collect_tokens_trailing_token($f)
-        } else {
-            Ok($f($self)?.0)
-        }
-    };
-}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 012b76d3d1887..97d0c0d874583 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -5,7 +5,7 @@ use rustc_errors::PResult;
 use rustc_span::symbol::{kw, Ident};
 
 use crate::parser::pat::{GateOr, RecoverComma};
-use crate::parser::{FollowedByType, ForceCollect, Parser, PathStyle};
+use crate::parser::{FollowedByType, Parser, PathStyle};
 
 impl<'a> Parser<'a> {
     /// Checks whether a non-terminal may begin with a particular token.
@@ -98,7 +98,7 @@ impl<'a> Parser<'a> {
         // in advance whether or not a proc-macro will be (transitively) invoked,
         // we always capture tokens for any `Nonterminal` which needs them.
         Ok(match kind {
-            NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
+            NonterminalKind::Item => match self.collect_tokens(|this| this.parse_item())? {
                 Some(item) => token::NtItem(item),
                 None => {
                     return Err(self.struct_span_err(self.token.span, "expected an item keyword"));
@@ -107,7 +107,7 @@ impl<'a> Parser<'a> {
             NonterminalKind::Block => {
                 token::NtBlock(self.collect_tokens(|this| this.parse_block())?)
             }
-            NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? {
+            NonterminalKind::Stmt => match self.collect_tokens(|this| this.parse_stmt())? {
                 Some(s) => token::NtStmt(s),
                 None => {
                     return Err(self.struct_span_err(self.token.span, "expected a statement"));
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 4234740b2b15f..dd36122f6a10e 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -185,6 +185,7 @@ impl<'a> Parser<'a> {
 
     pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
         let ident = self.parse_path_segment_ident()?;
+
         let is_args_start = |token: &Token| {
             matches!(
                 token.kind,
@@ -419,10 +420,7 @@ impl<'a> Parser<'a> {
         match arg {
             Some(arg) => {
                 if self.check(&token::Colon) | self.check(&token::Eq) {
-                    let (ident, gen_args) = match self.get_ident_from_generic_arg(arg) {
-                        Ok(ident_gen_args) => ident_gen_args,
-                        Err(arg) => return Ok(Some(AngleBracketedArg::Arg(arg))),
-                    };
+                    let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?;
                     let kind = if self.eat(&token::Colon) {
                         // Parse associated type constraint bound.
 
@@ -563,15 +561,50 @@ impl<'a> Parser<'a> {
     fn get_ident_from_generic_arg(
         &self,
         gen_arg: GenericArg,
-    ) -> Result<(Ident, Option<GenericArgs>), GenericArg> {
-        if let GenericArg::Type(ty) = &gen_arg {
-            if let ast::TyKind::Path(qself, path) = &ty.kind {
-                if qself.is_none() && path.segments.len() == 1 {
-                    let seg = &path.segments[0];
-                    return Ok((seg.ident, seg.args.as_deref().cloned()));
+        lo: Span,
+    ) -> PResult<'a, (Ident, Option<GenericArgs>)> {
+        let gen_arg_span = gen_arg.span();
+        match gen_arg {
+            GenericArg::Type(t) => match t.into_inner().kind {
+                ast::TyKind::Path(qself, mut path) => {
+                    if let Some(qself) = qself {
+                        let mut err = self.struct_span_err(
+                            gen_arg_span,
+                            "qualified paths cannot be used in associated type constraints",
+                        );
+                        err.span_label(
+                            qself.path_span,
+                            "not allowed in associated type constraints",
+                        );
+                        return Err(err);
+                    }
+                    if path.segments.len() == 1 {
+                        let path_seg = path.segments.remove(0);
+                        let ident = path_seg.ident;
+                        let gen_args = path_seg.args.map(|args| args.into_inner());
+                        return Ok((ident, gen_args));
+                    }
+                    let err = self.struct_span_err(
+                        path.span,
+                        "paths with multiple segments cannot be used in associated type constraints",
+                    );
+                    return Err(err);
+                }
+                _ => {
+                    let span = lo.to(self.prev_token.span);
+                    let err = self.struct_span_err(
+                        span,
+                        "only path types can be used in associated type constraints",
+                    );
+                    return Err(err);
                 }
+            },
+            _ => {
+                let span = lo.to(self.prev_token.span);
+                let err = self
+                    .struct_span_err(span, "only types can be used in associated type constraints");
+                return Err(err);
             }
         }
-        Err(gen_arg)
     }
 }
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 8373f6acd7e01..641b29227db98 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -3,13 +3,14 @@ use super::diagnostics::{AttemptLocalParseRecovery, Error};
 use super::expr::LhsExpr;
 use super::pat::{GateOr, RecoverComma};
 use super::path::PathStyle;
-use super::{BlockMode, ForceCollect, Parser, Restrictions, SemiColonMode, TrailingToken};
-use crate::{maybe_collect_tokens, maybe_whole};
+use super::{BlockMode, Parser, Restrictions, SemiColonMode};
+use crate::maybe_whole;
 
 use rustc_ast as ast;
 use rustc_ast::attr::HasAttrs;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, TokenKind};
+use rustc_ast::tokenstream::LazyTokenStream;
 use rustc_ast::util::classify;
 use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle};
 use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID};
@@ -23,22 +24,17 @@ impl<'a> Parser<'a> {
     /// Parses a statement. This stops just before trailing semicolons on everything but items.
     /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
     // Public for rustfmt usage.
-    pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> {
-        Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|mut e| {
+    pub fn parse_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
+        Ok(self.parse_stmt_without_recovery().unwrap_or_else(|mut e| {
             e.emit();
             self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
             None
         }))
     }
 
-    /// If `force_capture` is true, forces collection of tokens regardless of whether
-    /// or not we have attributes
-    fn parse_stmt_without_recovery(
-        &mut self,
-        capture_semi: bool,
-        force_collect: ForceCollect,
-    ) -> PResult<'a, Option<Stmt>> {
+    fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option<Stmt>> {
         let mut attrs = self.parse_outer_attributes()?;
+        let has_attrs = !attrs.is_empty();
         let lo = self.token.span;
 
         maybe_whole!(self, NtStmt, |stmt| {
@@ -50,77 +46,75 @@ impl<'a> Parser<'a> {
             Some(stmt)
         });
 
-        Ok(Some(if self.token.is_keyword(kw::Let) {
-            self.parse_local_mk(lo, attrs.into(), capture_semi, force_collect)?
-        } else if self.is_kw_followed_by_ident(kw::Mut) {
-            self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")?
-        } else if self.is_kw_followed_by_ident(kw::Auto) {
-            self.bump(); // `auto`
-            let msg = "write `let` instead of `auto` to introduce a new variable";
-            self.recover_stmt_local(lo, attrs.into(), msg, "let")?
-        } else if self.is_kw_followed_by_ident(sym::var) {
-            self.bump(); // `var`
-            let msg = "write `let` instead of `var` to introduce a new variable";
-            self.recover_stmt_local(lo, attrs.into(), msg, "let")?
-        } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
-            // We have avoided contextual keywords like `union`, items with `crate` visibility,
-            // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
-            // that starts like a path (1 token), but it fact not a path.
-            // Also, we avoid stealing syntax from `parse_item_`.
-            self.parse_stmt_path_start(lo, attrs, force_collect)?
-        } else if let Some(item) =
-            self.parse_item_common(attrs.clone(), false, true, |_| true, force_collect)?
-        {
-            // FIXME: Bad copy of attrs
-            self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
-        } else if self.eat(&token::Semi) {
-            // Do not attempt to parse an expression if we're done here.
-            self.error_outer_attrs(&attrs);
-            self.mk_stmt(lo, StmtKind::Empty)
-        } else if self.token != token::CloseDelim(token::Brace) {
-            // Remainder are line-expr stmts.
-            let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
-            self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
+        let parse_stmt_inner = |this: &mut Self| {
+            let stmt = if this.eat_keyword(kw::Let) {
+                this.parse_local_mk(lo, attrs.into())?
+            } else if this.is_kw_followed_by_ident(kw::Mut) {
+                this.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")?
+            } else if this.is_kw_followed_by_ident(kw::Auto) {
+                this.bump(); // `auto`
+                let msg = "write `let` instead of `auto` to introduce a new variable";
+                this.recover_stmt_local(lo, attrs.into(), msg, "let")?
+            } else if this.is_kw_followed_by_ident(sym::var) {
+                this.bump(); // `var`
+                let msg = "write `let` instead of `var` to introduce a new variable";
+                this.recover_stmt_local(lo, attrs.into(), msg, "let")?
+            } else if this.check_path()
+                && !this.token.is_qpath_start()
+                && !this.is_path_start_item()
+            {
+                // We have avoided contextual keywords like `union`, items with `crate` visibility,
+                // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
+                // that starts like a path (1 token), but it fact not a path.
+                // Also, we avoid stealing syntax from `parse_item_`.
+                this.parse_stmt_path_start(lo, attrs)?
+            } else if let Some(item) =
+                this.parse_item_common(attrs.clone(), false, true, |_| true)?
+            {
+                // FIXME: Bad copy of attrs
+                this.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
+            } else if this.eat(&token::Semi) {
+                // Do not attempt to parse an expression if we're done here.
+                this.error_outer_attrs(&attrs);
+                this.mk_stmt(lo, StmtKind::Empty)
+            } else if this.token != token::CloseDelim(token::Brace) {
+                // Remainder are line-expr stmts.
+                let e = this.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
+                this.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
+            } else {
+                this.error_outer_attrs(&attrs);
+                return Ok(None);
+            };
+            Ok(Some(stmt))
+        };
+
+        let stmt = if has_attrs {
+            self.collect_tokens(parse_stmt_inner)?
         } else {
-            self.error_outer_attrs(&attrs);
-            return Ok(None);
-        }))
+            parse_stmt_inner(self)?
+        };
+        Ok(stmt)
     }
 
-    fn parse_stmt_path_start(
-        &mut self,
-        lo: Span,
-        attrs: Vec<Attribute>,
-        force_collect: ForceCollect,
-    ) -> PResult<'a, Stmt> {
-        maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Parser<'a>| {
-            let path = this.parse_path(PathStyle::Expr)?;
+    fn parse_stmt_path_start(&mut self, lo: Span, attrs: Vec<Attribute>) -> PResult<'a, Stmt> {
+        let path = self.parse_path(PathStyle::Expr)?;
 
-            if this.eat(&token::Not) {
-                let stmt_mac = this.parse_stmt_mac(lo, attrs.into(), path)?;
-                if this.token == token::Semi {
-                    return Ok((stmt_mac, TrailingToken::Semi));
-                } else {
-                    return Ok((stmt_mac, TrailingToken::None));
-                }
-            }
+        if self.eat(&token::Not) {
+            return self.parse_stmt_mac(lo, attrs.into(), path);
+        }
 
-            let expr = if this.eat(&token::OpenDelim(token::Brace)) {
-                this.parse_struct_expr(path, AttrVec::new(), true)?
-            } else {
-                let hi = this.prev_token.span;
-                this.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
-            };
+        let expr = if self.eat(&token::OpenDelim(token::Brace)) {
+            self.parse_struct_expr(path, AttrVec::new(), true)?
+        } else {
+            let hi = self.prev_token.span;
+            self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
+        };
 
-            let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
-                let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
-                this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
-            })?;
-            Ok((
-                this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Expr(expr)),
-                TrailingToken::None,
-            ))
-        })
+        let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
+            let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
+            this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
+        })?;
+        Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
     }
 
     /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`.
@@ -168,34 +162,15 @@ impl<'a> Parser<'a> {
         msg: &str,
         sugg: &str,
     ) -> PResult<'a, Stmt> {
-        let stmt = self.recover_local_after_let(lo, attrs)?;
+        let stmt = self.parse_local_mk(lo, attrs)?;
         self.struct_span_err(lo, "invalid variable declaration")
             .span_suggestion(lo, msg, sugg.to_string(), Applicability::MachineApplicable)
             .emit();
         Ok(stmt)
     }
 
-    fn parse_local_mk(
-        &mut self,
-        lo: Span,
-        attrs: AttrVec,
-        capture_semi: bool,
-        force_collect: ForceCollect,
-    ) -> PResult<'a, Stmt> {
-        maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Parser<'a>| {
-            this.expect_keyword(kw::Let)?;
-            let local = this.parse_local(attrs.into())?;
-            let trailing = if capture_semi && this.token.kind == token::Semi {
-                TrailingToken::Semi
-            } else {
-                TrailingToken::None
-            };
-            Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)), trailing))
-        })
-    }
-
-    fn recover_local_after_let(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
-        let local = self.parse_local(attrs.into())?;
+    fn parse_local_mk(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
+        let local = self.parse_local(attrs)?;
         Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
     }
 
@@ -317,7 +292,7 @@ impl<'a> Parser<'a> {
         //      bar;
         //
         // which is valid in other languages, but not Rust.
-        match self.parse_stmt_without_recovery(false, ForceCollect::No) {
+        match self.parse_stmt_without_recovery() {
             // If the next token is an open brace (e.g., `if a b {`), the place-
             // inside-a-block suggestion would be more likely wrong than right.
             Ok(Some(_))
@@ -420,11 +395,17 @@ impl<'a> Parser<'a> {
         // Skip looking for a trailing semicolon when we have an interpolated statement.
         maybe_whole!(self, NtStmt, |x| Some(x));
 
-        let mut stmt = match self.parse_stmt_without_recovery(true, ForceCollect::No)? {
+        let mut stmt = match self.parse_stmt_without_recovery()? {
             Some(stmt) => stmt,
             None => return Ok(None),
         };
 
+        let add_semi_token = |tokens: Option<&mut LazyTokenStream>| {
+            if let Some(tokens) = tokens {
+                *tokens = tokens.add_trailing_semi();
+            }
+        };
+
         let mut eat_semi = true;
         match stmt.kind {
             // Expression without semicolon.
@@ -480,12 +461,18 @@ impl<'a> Parser<'a> {
                     }
                 }
                 eat_semi = false;
+                // We just checked that there's a semicolon in the tokenstream,
+                // so capture it
+                add_semi_token(local.tokens.as_mut());
             }
             StmtKind::Empty | StmtKind::Item(_) | StmtKind::Semi(_) => eat_semi = false,
         }
 
         if eat_semi && self.eat(&token::Semi) {
             stmt = stmt.add_trailing_semicolon();
+            // We just checked that we have a semicolon in the tokenstream,
+            // so capture it
+            add_semi_token(stmt.tokens_mut());
         }
         stmt.span = stmt.span.to(self.prev_token.span);
         Ok(Some(stmt))
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 8950f9b33b6da..c887a860303b5 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -199,7 +199,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
             // Skip the following checks if we are not currently in a const context.
             _ if self.const_kind.is_none() => {}
 
-            hir::ExprKind::Loop(_, _, source, _) => {
+            hir::ExprKind::Loop(_, _, source) => {
                 self.const_check_violated(NonConstExpr::Loop(*source), e.span);
             }
 
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 3b1b53553d5e4..80a24c90421e7 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -290,7 +290,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
     }
 
     fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
-        self.in_pat = true;
         match pat.kind {
             PatKind::Struct(ref path, ref fields, _) => {
                 let res = self.typeck_results().qpath_res(path, pat.hir_id);
@@ -303,6 +302,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
             _ => (),
         }
 
+        self.in_pat = true;
         intravisit::walk_pat(self, pat);
         self.in_pat = false;
     }
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index c11dc231d482c..6202cc312fc0e 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -844,7 +844,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
             // Note that labels have been resolved, so we don't need to look
             // at the label ident
-            hir::ExprKind::Loop(ref blk, ..) => self.propagate_through_loop(expr, &blk, succ),
+            hir::ExprKind::Loop(ref blk, _, _) => self.propagate_through_loop(expr, &blk, succ),
 
             hir::ExprKind::If(ref cond, ref then, ref else_opt) => {
                 //
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 4bfac1b72983e..9b4da71e5e961 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -53,7 +53,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
 
     fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
         match e.kind {
-            hir::ExprKind::Loop(ref b, _, source, _) => {
+            hir::ExprKind::Loop(ref b, _, source) => {
                 self.with_context(Loop(source), |v| v.visit_block(&b));
             }
             hir::ExprKind::Closure(_, ref function_decl, b, span, movability) => {
@@ -68,18 +68,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
             hir::ExprKind::Block(ref b, Some(_label)) => {
                 self.with_context(LabeledBlock, |v| v.visit_block(&b));
             }
-            hir::ExprKind::Break(break_label, ref opt_expr) => {
+            hir::ExprKind::Break(label, ref opt_expr) => {
                 if let Some(e) = opt_expr {
                     self.visit_expr(e);
                 }
 
-                if self.require_label_in_labeled_block(e.span, &break_label, "break") {
+                if self.require_label_in_labeled_block(e.span, &label, "break") {
                     // If we emitted an error about an unlabeled break in a labeled
                     // block, we don't need any further checking for this break any more
                     return;
                 }
 
-                let loop_id = match break_label.target_id {
+                let loop_id = match label.target_id {
                     Ok(loop_id) => Some(loop_id),
                     Err(hir::LoopIdError::OutsideLoopScope) => None,
                     Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
@@ -89,89 +89,49 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                     Err(hir::LoopIdError::UnresolvedLabel) => None,
                 };
 
-                if let Some(Node::Block(_)) = loop_id.and_then(|id| self.hir_map.find(id)) {
-                    return;
+                if let Some(loop_id) = loop_id {
+                    if let Node::Block(_) = self.hir_map.find(loop_id).unwrap() {
+                        return;
+                    }
                 }
 
-                if let Some(break_expr) = opt_expr {
-                    let (head, loop_label, loop_kind) = if let Some(loop_id) = loop_id {
-                        match self.hir_map.expect_expr(loop_id).kind {
-                            hir::ExprKind::Loop(_, label, source, sp) => {
-                                (Some(sp), label, Some(source))
-                            }
+                if opt_expr.is_some() {
+                    let loop_kind = if let Some(loop_id) = loop_id {
+                        Some(match self.hir_map.expect_expr(loop_id).kind {
+                            hir::ExprKind::Loop(_, _, source) => source,
                             ref r => {
                                 span_bug!(e.span, "break label resolved to a non-loop: {:?}", r)
                             }
-                        }
+                        })
                     } else {
-                        (None, None, None)
+                        None
                     };
                     match loop_kind {
                         None | Some(hir::LoopSource::Loop) => (),
                         Some(kind) => {
-                            let mut err = struct_span_err!(
+                            struct_span_err!(
                                 self.sess,
                                 e.span,
                                 E0571,
                                 "`break` with value from a `{}` loop",
                                 kind.name()
-                            );
-                            err.span_label(
+                            )
+                            .span_label(
                                 e.span,
-                                "can only break with a value inside `loop` or breakable block",
-                            );
-                            if let Some(head) = head {
-                                err.span_label(
-                                    head,
-                                    &format!(
-                                        "you can't `break` with a value in a `{}` loop",
-                                        kind.name()
-                                    ),
-                                );
-                            }
-                            err.span_suggestion(
+                                "can only break with a value inside \
+                                            `loop` or breakable block",
+                            )
+                            .span_suggestion(
                                 e.span,
                                 &format!(
-                                    "use `break` on its own without a value inside this `{}` loop",
-                                    kind.name(),
-                                ),
-                                format!(
-                                    "break{}",
-                                    break_label
-                                        .label
-                                        .map_or_else(String::new, |l| format!(" {}", l.ident))
+                                    "instead, use `break` on its own \
+                                        without a value inside this `{}` loop",
+                                    kind.name()
                                 ),
+                                "break".to_string(),
                                 Applicability::MaybeIncorrect,
-                            );
-                            if let (Some(label), None) = (loop_label, break_label.label) {
-                                match break_expr.kind {
-                                    hir::ExprKind::Path(hir::QPath::Resolved(
-                                        None,
-                                        hir::Path {
-                                            segments: [segment],
-                                            res: hir::def::Res::Err,
-                                            ..
-                                        },
-                                    )) if label.ident.to_string()
-                                        == format!("'{}", segment.ident) =>
-                                    {
-                                        // This error is redundant, we will have already emitted a
-                                        // suggestion to use the label when `segment` wasn't found
-                                        // (hence the `Res::Err` check).
-                                        err.delay_as_bug();
-                                    }
-                                    _ => {
-                                        err.span_suggestion(
-                                            break_expr.span,
-                                            "alternatively, you might have meant to use the \
-                                             available loop label",
-                                            label.ident.to_string(),
-                                            Applicability::MaybeIncorrect,
-                                        );
-                                    }
-                                }
-                            }
-                            err.emit();
+                            )
+                            .emit();
                         }
                     }
                 }
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index eb24c51c54c35..b237671f8e208 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -307,7 +307,6 @@ impl<'tcx> ReachableContext<'tcx> {
             | Node::Ctor(..)
             | Node::Field(_)
             | Node::Ty(_)
-            | Node::Crate(_)
             | Node::MacroDef(_) => {}
             _ => {
                 bug!(
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index 64356f73f6c65..91421d7f5f22b 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -252,7 +252,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
                 terminating(then.hir_id.local_id);
             }
 
-            hir::ExprKind::Loop(ref body, _, _, _) => {
+            hir::ExprKind::Loop(ref body, _, _) => {
                 terminating(body.hir_id.local_id);
             }
 
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index 1d2bc1a99a596..7bc6ae1d1c6c3 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -15,7 +15,7 @@ pub trait CacheSelector<K, V> {
 }
 
 pub trait QueryStorage: Default {
-    type Value: Debug;
+    type Value;
     type Stored: Clone;
 
     /// Store a value without putting it in the cache.
@@ -75,7 +75,7 @@ impl<K, V> Default for DefaultCache<K, V> {
     }
 }
 
-impl<K: Eq + Hash, V: Clone + Debug> QueryStorage for DefaultCache<K, V> {
+impl<K: Eq + Hash, V: Clone> QueryStorage for DefaultCache<K, V> {
     type Value = V;
     type Stored = V;
 
@@ -89,7 +89,7 @@ impl<K: Eq + Hash, V: Clone + Debug> QueryStorage for DefaultCache<K, V> {
 impl<K, V> QueryCache for DefaultCache<K, V>
 where
     K: Eq + Hash + Clone + Debug,
-    V: Clone + Debug,
+    V: Clone,
 {
     type Key = K;
     type Sharded = FxHashMap<K, (V, DepNodeIndex)>;
@@ -156,7 +156,7 @@ impl<'tcx, K, V> Default for ArenaCache<'tcx, K, V> {
     }
 }
 
-impl<'tcx, K: Eq + Hash, V: Debug + 'tcx> QueryStorage for ArenaCache<'tcx, K, V> {
+impl<'tcx, K: Eq + Hash, V: 'tcx> QueryStorage for ArenaCache<'tcx, K, V> {
     type Value = V;
     type Stored = &'tcx V;
 
@@ -171,7 +171,6 @@ impl<'tcx, K: Eq + Hash, V: Debug + 'tcx> QueryStorage for ArenaCache<'tcx, K, V
 impl<'tcx, K, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V>
 where
     K: Eq + Hash + Clone + Debug,
-    V: Debug,
 {
     type Key = K;
     type Sharded = FxHashMap<K, &'tcx (V, DepNodeIndex)>;
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 36532135f016d..d17af6120c7b8 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -20,7 +20,6 @@ use rustc_errors::{Diagnostic, FatalError};
 use rustc_span::source_map::DUMMY_SP;
 use rustc_span::Span;
 use std::collections::hash_map::Entry;
-use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
 use std::mem;
 use std::num::NonZeroU32;
@@ -479,7 +478,7 @@ where
     result
 }
 
-fn load_from_disk_and_cache_in_memory<CTX, K, V: Debug>(
+fn load_from_disk_and_cache_in_memory<CTX, K, V>(
     tcx: CTX,
     key: K,
     prev_dep_node_index: SerializedDepNodeIndex,
@@ -540,7 +539,7 @@ where
 
 #[inline(never)]
 #[cold]
-fn incremental_verify_ich<CTX, K, V: Debug>(
+fn incremental_verify_ich<CTX, K, V>(
     tcx: CTX,
     result: &V,
     dep_node: &DepNode<CTX::DepKind>,
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index eaeb28388d4f0..fff14747e5729 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2266,12 +2266,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 visit::walk_expr(self, expr);
             }
 
-            ExprKind::Break(None, Some(ref e)) => {
-                // We use this instead of `visit::walk_expr` to keep the parent expr around for
-                // better diagnostics.
-                self.resolve_expr(e, Some(&expr));
-            }
-
             ExprKind::Let(ref pat, ref scrutinee) => {
                 self.visit_expr(scrutinee);
                 self.resolve_pattern_top(pat, PatternSource::Let);
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index bed7a350ea86d..3945afb4724a8 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -545,23 +545,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         if let Some(err_code) = &err.code {
             if err_code == &rustc_errors::error_code!(E0425) {
                 for label_rib in &self.label_ribs {
-                    for (label_ident, node_id) in &label_rib.bindings {
+                    for (label_ident, _) in &label_rib.bindings {
                         if format!("'{}", ident) == label_ident.to_string() {
-                            err.span_label(label_ident.span, "a label with a similar name exists");
-                            if let PathSource::Expr(Some(Expr {
-                                kind: ExprKind::Break(None, Some(_)),
-                                ..
-                            })) = source
-                            {
-                                err.span_suggestion(
-                                    span,
-                                    "use the similarly named label",
-                                    label_ident.name.to_string(),
-                                    Applicability::MaybeIncorrect,
-                                );
-                                // Do not lint against unused label when we suggest them.
-                                self.diagnostic_metadata.unused_labels.remove(node_id);
-                            }
+                            let msg = "a label with a similar name exists";
+                            // FIXME: consider only emitting this suggestion if a label would be valid here
+                            // which is pretty much only the case for `break` expressions.
+                            err.span_suggestion(
+                                span,
+                                &msg,
+                                label_ident.name.to_string(),
+                                Applicability::MaybeIncorrect,
+                            );
                         }
                     }
                 }
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 95ac2a31dd321..64cc113dffe7e 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -1173,7 +1173,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) {
     }
 
     fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> {
-        if let hir::ExprKind::Loop(_, Some(label), ..) = ex.kind { Some(label.ident) } else { None }
+        if let hir::ExprKind::Loop(_, Some(label), _) = ex.kind { Some(label.ident) } else { None }
     }
 
     fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 2b4a1d9e3fa0a..d293899dc0c6f 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1465,14 +1465,16 @@ impl<'a> Resolver<'a> {
 
     /// Entry point to crate resolution.
     pub fn resolve_crate(&mut self, krate: &Crate) {
-        self.session.time("resolve_crate", || {
-            self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
-            self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
-            self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
-            self.session.time("resolve_check_unused", || self.check_unused(krate));
-            self.session.time("resolve_report_errors", || self.report_errors(krate));
-            self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate));
-        });
+        let _prof_timer = self.session.prof.generic_activity("resolve_crate");
+
+        ImportResolver { r: self }.finalize_imports();
+        self.finalize_macro_resolutions();
+
+        self.late_resolve_crate(krate);
+
+        self.check_unused(krate);
+        self.report_errors(krate);
+        self.crate_loader.postprocess(krate);
     }
 
     pub fn traits_in_scope(
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 6e269e9e1264c..49833601c9e91 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -361,7 +361,7 @@ impl Default for TrimmedDefPaths {
 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
 /// dependency tracking for command-line arguments.
-#[derive(Clone, Hash, Debug)]
+#[derive(Clone, Hash)]
 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
 
 impl_stable_hash_via_hash!(OutputTypes);
@@ -552,7 +552,7 @@ impl Input {
     }
 }
 
-#[derive(Clone, Hash, Debug)]
+#[derive(Clone, Hash)]
 pub struct OutputFilenames {
     pub out_directory: PathBuf,
     filestem: String,
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 9f265f37f35f6..1fb5642912f43 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -27,18 +27,14 @@
 use crate::edition::Edition;
 use crate::symbol::{kw, sym, Symbol};
 use crate::SESSION_GLOBALS;
-use crate::{BytePos, CachingSourceMapView, ExpnIdCache, SourceFile, Span, DUMMY_SP};
+use crate::{Span, DUMMY_SP};
 
 use crate::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
-use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::fmt;
-use std::hash::Hash;
-use std::thread::LocalKey;
 use tracing::*;
 
 /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
@@ -84,12 +80,7 @@ pub enum Transparency {
 
 impl ExpnId {
     pub fn fresh(expn_data: Option<ExpnData>) -> Self {
-        let has_data = expn_data.is_some();
-        let expn_id = HygieneData::with(|data| data.fresh_expn(expn_data));
-        if has_data {
-            update_disambiguator(expn_id);
-        }
-        expn_id
+        HygieneData::with(|data| data.fresh_expn(expn_data))
     }
 
     /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
@@ -120,8 +111,7 @@ impl ExpnId {
             assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
             expn_data.orig_id.replace(self.as_u32()).expect_none("orig_id should be None");
             *old_expn_data = Some(expn_data);
-        });
-        update_disambiguator(self)
+        })
     }
 
     pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
@@ -162,12 +152,6 @@ pub struct HygieneData {
     expn_data: Vec<Option<ExpnData>>,
     syntax_context_data: Vec<SyntaxContextData>,
     syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>,
-    /// Maps the `Fingerprint` of an `ExpnData` to the next disambiguator value.
-    /// This is used by `update_disambiguator` to keep track of which `ExpnData`s
-    /// would have collisions without a disambiguator.
-    /// The keys of this map are always computed with `ExpnData.disambiguator`
-    /// set to 0.
-    expn_data_disambiguators: FxHashMap<Fingerprint, u32>,
 }
 
 impl HygieneData {
@@ -191,7 +175,6 @@ impl HygieneData {
                 dollar_crate_name: kw::DollarCrate,
             }],
             syntax_context_map: FxHashMap::default(),
-            expn_data_disambiguators: FxHashMap::default(),
         }
     }
 
@@ -666,8 +649,8 @@ impl Span {
         expn_data: ExpnData,
         transparency: Transparency,
     ) -> Span {
-        let expn_id = ExpnId::fresh(Some(expn_data));
         HygieneData::with(|data| {
+            let expn_id = data.fresh_expn(Some(expn_data));
             self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id, transparency))
         })
     }
@@ -743,23 +726,10 @@ pub struct ExpnData {
     // be considered equivalent.
     #[stable_hasher(ignore)]
     orig_id: Option<u32>,
-
-    /// Used to force two `ExpnData`s to have different `Fingerprint`s.
-    /// Due to macro expansion, it's possible to end up with two `ExpnId`s
-    /// that have identical `ExpnData`s. This violates the constract of `HashStable`
-    /// - the two `ExpnId`s are not equal, but their `Fingerprint`s are equal
-    /// (since the numerical `ExpnId` value is not considered by the `HashStable`
-    /// implementation).
-    ///
-    /// The `disambiguator` field is set by `update_disambiguator` when two distinct
-    /// `ExpnId`s would end up with the same `Fingerprint`. Since `ExpnData` includes
-    /// a `krate` field, this value only needs to be unique within a single crate.
-    disambiguator: u32,
 }
 
-// These would require special handling of `orig_id`.
+// This would require special handling of `orig_id` and `parent`
 impl !PartialEq for ExpnData {}
-impl !Hash for ExpnData {}
 
 impl ExpnData {
     pub fn new(
@@ -785,7 +755,6 @@ impl ExpnData {
             macro_def_id,
             krate: LOCAL_CRATE,
             orig_id: None,
-            disambiguator: 0,
         }
     }
 
@@ -808,7 +777,6 @@ impl ExpnData {
             macro_def_id,
             krate: LOCAL_CRATE,
             orig_id: None,
-            disambiguator: 0,
         }
     }
 
@@ -1308,118 +1276,3 @@ impl<D: Decoder> Decodable<D> for SyntaxContext {
         panic!("cannot decode `SyntaxContext` with `{}`", std::any::type_name::<D>());
     }
 }
-
-/// Updates the `disambiguator` field of the corresponding `ExpnData`
-/// such that the `Fingerprint` of the `ExpnData` does not collide with
-/// any other `ExpnIds`.
-///
-/// This method is called only when an `ExpnData` is first associated
-/// with an `ExpnId` (when the `ExpnId` is initially constructed, or via
-/// `set_expn_data`). It is *not* called for foreign `ExpnId`s deserialized
-/// from another crate's metadata - since `ExpnData` includes a `krate` field,
-/// collisions are only possible between `ExpnId`s within the same crate.
-fn update_disambiguator(expn_id: ExpnId) {
-    /// A `HashStableContext` which hashes the raw id values for `DefId`
-    /// and `CrateNum`, rather than using their computed stable hash.
-    ///
-    /// This allows us to use the `HashStable` implementation on `ExpnId`
-    /// early on in compilation, before we've constructed a `TyCtxt`.
-    /// The `Fingerprint`s created by this context are not 'stable', since
-    /// the raw `CrateNum` and `DefId` values for an item may change between
-    /// sessions due to unrelated changes (e.g. adding/removing an different item).
-    ///
-    /// However, this is fine for our purposes - we only need to detect
-    /// when two `ExpnData`s have the same `Fingerprint`. Since the hashes produced
-    /// by this context still obey the properties of `HashStable`, we have
-    /// that
-    /// `hash_stable(expn1, DummyHashStableContext) == hash_stable(expn2, DummyHashStableContext)`
-    /// iff `hash_stable(expn1, StableHashingContext) == hash_stable(expn2, StableHasingContext)`.
-    ///
-    /// This is sufficient for determining when we need to update the disambiguator.
-    struct DummyHashStableContext<'a> {
-        caching_source_map: CachingSourceMapView<'a>,
-    }
-
-    impl<'a> crate::HashStableContext for DummyHashStableContext<'a> {
-        fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
-            def_id.krate.as_u32().hash_stable(self, hasher);
-            def_id.index.as_u32().hash_stable(self, hasher);
-        }
-
-        fn expn_id_cache() -> &'static LocalKey<ExpnIdCache> {
-            // This cache is only used by `DummyHashStableContext`,
-            // so we won't pollute the cache values of the normal `StableHashingContext`
-            thread_local! {
-                static CACHE: ExpnIdCache = Default::default();
-            }
-
-            &CACHE
-        }
-
-        fn hash_crate_num(&mut self, krate: CrateNum, hasher: &mut StableHasher) {
-            krate.as_u32().hash_stable(self, hasher);
-        }
-        fn hash_spans(&self) -> bool {
-            true
-        }
-        fn byte_pos_to_line_and_col(
-            &mut self,
-            byte: BytePos,
-        ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
-            self.caching_source_map.byte_pos_to_line_and_col(byte)
-        }
-        fn span_data_to_lines_and_cols(
-            &mut self,
-            span: &crate::SpanData,
-        ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
-            self.caching_source_map.span_data_to_lines_and_cols(span)
-        }
-    }
-
-    let source_map = SESSION_GLOBALS
-        .with(|session_globals| session_globals.source_map.borrow().as_ref().unwrap().clone());
-
-    let mut ctx =
-        DummyHashStableContext { caching_source_map: CachingSourceMapView::new(&source_map) };
-
-    let mut hasher = StableHasher::new();
-
-    let expn_data = expn_id.expn_data();
-    // This disambiguator should not have been set yet.
-    assert_eq!(
-        expn_data.disambiguator, 0,
-        "Already set disambiguator for ExpnData: {:?}",
-        expn_data
-    );
-    expn_data.hash_stable(&mut ctx, &mut hasher);
-    let first_hash = hasher.finish();
-
-    let modified = HygieneData::with(|data| {
-        // If this is the first ExpnData with a given hash, then keep our
-        // disambiguator at 0 (the default u32 value)
-        let disambig = data.expn_data_disambiguators.entry(first_hash).or_default();
-        data.expn_data[expn_id.0 as usize].as_mut().unwrap().disambiguator = *disambig;
-        *disambig += 1;
-
-        *disambig != 1
-    });
-
-    if modified {
-        info!("Set disambiguator for {:?} (hash {:?})", expn_id, first_hash);
-        info!("expn_data = {:?}", expn_id.expn_data());
-
-        // Verify that the new disambiguator makes the hash unique
-        #[cfg(debug_assertions)]
-        {
-            hasher = StableHasher::new();
-            expn_id.expn_data().hash_stable(&mut ctx, &mut hasher);
-            let new_hash: Fingerprint = hasher.finish();
-
-            HygieneData::with(|data| {
-                data.expn_data_disambiguators
-                    .get(&new_hash)
-                    .expect_none("Hash collision after disambiguator update!");
-            });
-        };
-    }
-}
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index f3d876a5770a8..50cb15554864f 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -65,7 +65,6 @@ use std::hash::Hash;
 use std::ops::{Add, Range, Sub};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
-use std::thread::LocalKey;
 
 use md5::Md5;
 use sha1::Digest;
@@ -1866,11 +1865,6 @@ fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize {
 /// instead of implementing everything in rustc_middle.
 pub trait HashStableContext {
     fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher);
-    /// Obtains a cache for storing the `Fingerprint` of an `ExpnId`.
-    /// This method allows us to have multiple `HashStableContext` implementations
-    /// that hash things in a different way, without the results of one polluting
-    /// the cache of the other.
-    fn expn_id_cache() -> &'static LocalKey<ExpnIdCache>;
     fn hash_crate_num(&mut self, _: CrateNum, hasher: &mut StableHasher);
     fn hash_spans(&self) -> bool;
     fn byte_pos_to_line_and_col(
@@ -1967,10 +1961,15 @@ impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
     }
 }
 
-pub type ExpnIdCache = RefCell<Vec<Option<Fingerprint>>>;
-
 impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        // Since the same expansion context is usually referenced many
+        // times, we cache a stable hash of it and hash that instead of
+        // recursing every time.
+        thread_local! {
+            static CACHE: RefCell<Vec<Option<Fingerprint>>> = Default::default();
+        }
+
         const TAG_ROOT: u8 = 0;
         const TAG_NOT_ROOT: u8 = 1;
 
@@ -1979,11 +1978,8 @@ impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
             return;
         }
 
-        // Since the same expansion context is usually referenced many
-        // times, we cache a stable hash of it and hash that instead of
-        // recursing every time.
         let index = self.as_u32() as usize;
-        let res = CTX::expn_id_cache().with(|cache| cache.borrow().get(index).copied().flatten());
+        let res = CACHE.with(|cache| cache.borrow().get(index).copied().flatten());
 
         if let Some(res) = res {
             res.hash_stable(ctx, hasher);
@@ -1995,7 +1991,7 @@ impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
             self.expn_data().hash_stable(ctx, &mut sub_hasher);
             let sub_hash: Fingerprint = sub_hasher.finish();
 
-            CTX::expn_id_cache().with(|cache| {
+            CACHE.with(|cache| {
                 let mut cache = cache.borrow_mut();
                 if cache.len() < new_len {
                     cache.resize(new_len, None);
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 2cbd52bf3e9a7..a9e595d11e759 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -27,16 +27,10 @@ mod x86_win64;
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum PassMode {
     /// Ignore the argument.
-    ///
-    /// The argument is either uninhabited or a ZST.
     Ignore,
     /// Pass the argument directly.
-    ///
-    /// The argument has a layout abi of `Scalar` or `Vector`.
     Direct(ArgAttributes),
     /// Pass a pair's elements directly in two arguments.
-    ///
-    /// The argument has a layout abi of `ScalarPair`.
     Pair(ArgAttributes, ArgAttributes),
     /// Pass the argument after casting it, to either
     /// a single uniform or a pair of registers.
@@ -440,49 +434,28 @@ pub struct ArgAbi<'a, Ty> {
 }
 
 impl<'a, Ty> ArgAbi<'a, Ty> {
-    pub fn new(
-        cx: &impl HasDataLayout,
-        layout: TyAndLayout<'a, Ty>,
-        scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, &abi::Scalar, Size) -> ArgAttributes,
-    ) -> Self {
-        let mode = match &layout.abi {
-            Abi::Uninhabited => PassMode::Ignore,
-            Abi::Scalar(scalar) => PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)),
-            Abi::ScalarPair(a, b) => PassMode::Pair(
-                scalar_attrs(&layout, a, Size::ZERO),
-                scalar_attrs(&layout, b, a.value.size(cx).align_to(b.value.align(cx).abi)),
-            ),
-            Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()),
-            Abi::Aggregate { .. } => Self::indirect_pass_mode(&layout),
-        };
-        ArgAbi { layout, pad: None, mode }
+    pub fn new(layout: TyAndLayout<'a, Ty>) -> Self {
+        ArgAbi { layout, pad: None, mode: PassMode::Direct(ArgAttributes::new()) }
     }
 
-    fn indirect_pass_mode(layout: &TyAndLayout<'a, Ty>) -> PassMode {
+    pub fn make_indirect(&mut self) {
+        assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
+
+        // Start with fresh attributes for the pointer.
         let mut attrs = ArgAttributes::new();
 
         // For non-immediate arguments the callee gets its own copy of
         // the value on the stack, so there are no aliases. It's also
         // program-invisible so can't possibly capture
         attrs.set(ArgAttribute::NoAlias).set(ArgAttribute::NoCapture).set(ArgAttribute::NonNull);
-        attrs.pointee_size = layout.size;
+        attrs.pointee_size = self.layout.size;
         // FIXME(eddyb) We should be doing this, but at least on
         // i686-pc-windows-msvc, it results in wrong stack offsets.
-        // attrs.pointee_align = Some(layout.align.abi);
-
-        let extra_attrs = layout.is_unsized().then_some(ArgAttributes::new());
+        // attrs.pointee_align = Some(self.layout.align.abi);
 
-        PassMode::Indirect { attrs, extra_attrs, on_stack: false }
-    }
-
-    pub fn make_indirect(&mut self) {
-        match self.mode {
-            PassMode::Direct(_) | PassMode::Pair(_, _) => {}
-            PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: false } => return,
-            _ => panic!("Tried to make {:?} indirect", self.mode),
-        }
+        let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new());
 
-        self.mode = Self::indirect_pass_mode(&self.layout);
+        self.mode = PassMode::Indirect { attrs, extra_attrs, on_stack: false };
     }
 
     pub fn make_indirect_byval(&mut self) {
@@ -513,6 +486,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
     }
 
     pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
+        assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
         self.mode = PassMode::Cast(target.into());
     }
 
diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs
index cfaf020175b7f..302306ee57990 100644
--- a/compiler/rustc_target/src/spec/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs
@@ -1,5 +1,5 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{StackProbeType, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = opts("ios", Arch::I386);
@@ -10,10 +10,6 @@ pub fn target() -> Target {
             f64:32:64-f80:128-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        options: TargetOptions {
-            max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
-            ..base
-        },
+        options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index 2d3310c7582ef..0ab40340928cc 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::apple_base::opts("macos");
@@ -6,7 +6,7 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
     base.eliminate_frame_pointer = false;
 
     // Clang automatically chooses a more specific target based on
diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs
index 18cd8847abd39..52059b930d134 100644
--- a/compiler/rustc_target/src/spec/i686_linux_android.rs
+++ b/compiler/rustc_target/src/spec/i686_linux_android.rs
@@ -1,4 +1,4 @@
-use crate::spec::{StackProbeType, Target};
+use crate::spec::Target;
 
 // See https://developer.android.com/ndk/guides/abis.html#x86
 // for target ABI requirements.
@@ -11,7 +11,7 @@ pub fn target() -> Target {
     // http://developer.android.com/ndk/guides/abis.html#x86
     base.cpu = "pentiumpro".to_string();
     base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string();
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "i686-linux-android".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
index fc425babb6948..fc1c8607d654c 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
@@ -7,7 +7,7 @@ pub fn target() -> Target {
     let pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
     pre_link_args.push("-m32".to_string());
     pre_link_args.push("-Wl,-znotext".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "i686-unknown-freebsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
index 5fba4e3f14a25..22c8ba5475315 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::haiku_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "i686-unknown-haiku".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
index fe1e6a4299dab..083c115d084b4 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_gnu_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
index 623fd1b9ae801..1673b2a180245 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -6,7 +6,7 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-melf_i386".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind
     // implementation, apparently relies on frame pointers existing... somehow.
diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
index c4d11bfb13ece..c22139b5875d6 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "i686-unknown-netbsdelf".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
index fdaaf6c741e89..87642efdee8f7 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
@@ -6,7 +6,7 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-fuse-ld=lld".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "i686-unknown-openbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
index ec8a2493b4e42..c0825358cabbc 100644
--- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
index 5220156895367..a5fc1649e7ffd 100644
--- a/compiler/rustc_target/src/spec/linux_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs
@@ -1,6 +1,4 @@
-use crate::spec::{
-    LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, RelroLevel, StackProbeType, TargetOptions,
-};
+use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, RelroLevel, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     let mut pre_link_args = LinkArgs::new();
@@ -13,7 +11,7 @@ pub fn opts() -> TargetOptions {
         env: "gnu".to_string(),
         disable_redzone: true,
         panic_strategy: PanicStrategy::Abort,
-        stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
+        stack_probes: true,
         eliminate_frame_pointer: false,
         linker_is_gnu: true,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 90d35efaa25bd..d283c2548864f 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -40,7 +40,6 @@ use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
 use rustc_serialize::json::{Json, ToJson};
 use rustc_span::symbol::{sym, Symbol};
 use std::collections::BTreeMap;
-use std::convert::TryFrom;
 use std::ops::{Deref, DerefMut};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
@@ -480,83 +479,6 @@ macro_rules! supported_targets {
     };
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum StackProbeType {
-    /// Don't emit any stack probes.
-    None,
-    /// It is harmless to use this option even on targets that do not have backend support for
-    /// stack probes as the failure mode is the same as if no stack-probe option was specified in
-    /// the first place.
-    Inline,
-    /// Call `__rust_probestack` whenever stack needs to be probed.
-    Call,
-    /// Use inline option for LLVM versions later than specified in `min_llvm_version_for_inline`
-    /// and call `__rust_probestack` otherwise.
-    InlineOrCall { min_llvm_version_for_inline: (u32, u32, u32) },
-}
-
-impl StackProbeType {
-    fn from_json(json: &Json) -> Result<Self, String> {
-        let object = json.as_object().ok_or_else(|| "expected a JSON object")?;
-        let kind = object
-            .get("kind")
-            .and_then(|o| o.as_string())
-            .ok_or_else(|| "expected `kind` to be a string")?;
-        match kind {
-            "none" => Ok(StackProbeType::None),
-            "inline" => Ok(StackProbeType::Inline),
-            "call" => Ok(StackProbeType::Call),
-            "inline-or-call" => {
-                let min_version = object
-                    .get("min-llvm-version-for-inline")
-                    .and_then(|o| o.as_array())
-                    .ok_or_else(|| "expected `min-llvm-version-for-inline` to be an array")?;
-                let mut iter = min_version.into_iter().map(|v| {
-                    let int = v.as_u64().ok_or_else(
-                        || "expected `min-llvm-version-for-inline` values to be integers",
-                    )?;
-                    u32::try_from(int)
-                        .map_err(|_| "`min-llvm-version-for-inline` values don't convert to u32")
-                });
-                let min_llvm_version_for_inline = (
-                    iter.next().unwrap_or(Ok(11))?,
-                    iter.next().unwrap_or(Ok(0))?,
-                    iter.next().unwrap_or(Ok(0))?,
-                );
-                Ok(StackProbeType::InlineOrCall { min_llvm_version_for_inline })
-            }
-            _ => Err(String::from(
-                "`kind` expected to be one of `inline-or-none`, `call` or `inline-or-call`",
-            )),
-        }
-    }
-}
-
-impl ToJson for StackProbeType {
-    fn to_json(&self) -> Json {
-        Json::Object(match self {
-            StackProbeType::None => {
-                vec![(String::from("kind"), "none".to_json())].into_iter().collect()
-            }
-            StackProbeType::Inline => {
-                vec![(String::from("kind"), "inline".to_json())].into_iter().collect()
-            }
-            StackProbeType::Call => {
-                vec![(String::from("kind"), "call".to_json())].into_iter().collect()
-            }
-            StackProbeType::InlineOrCall { min_llvm_version_for_inline } => vec![
-                (String::from("kind"), "inline-or-call".to_json()),
-                (
-                    String::from("min-llvm-version-for-inline"),
-                    min_llvm_version_for_inline.to_json(),
-                ),
-            ]
-            .into_iter()
-            .collect(),
-        })
-    }
-}
-
 supported_targets! {
     ("x86_64-unknown-linux-gnu", x86_64_unknown_linux_gnu),
     ("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32),
@@ -1004,8 +926,8 @@ pub struct TargetOptions {
     /// Whether or not crt-static is respected by the compiler (or is a no-op).
     pub crt_static_respected: bool,
 
-    /// The implementation of stack probes to use.
-    pub stack_probes: StackProbeType,
+    /// Whether or not stack probes (__rust_probestack) are enabled
+    pub stack_probes: bool,
 
     /// The minimum alignment for global symbols.
     pub min_global_align: Option<u64>,
@@ -1163,7 +1085,7 @@ impl Default for TargetOptions {
             crt_static_allows_dylibs: false,
             crt_static_default: false,
             crt_static_respected: false,
-            stack_probes: StackProbeType::None,
+            stack_probes: false,
             min_global_align: None,
             default_codegen_units: None,
             trap_unreachable: true,
@@ -1439,18 +1361,6 @@ impl Target {
                     Some(Ok(()))
                 })).unwrap_or(Ok(()))
             } );
-            ($key_name:ident, StackProbeType) => ( {
-                let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| match StackProbeType::from_json(o) {
-                    Ok(v) => {
-                        base.$key_name = v;
-                        Some(Ok(()))
-                    },
-                    Err(s) => Some(Err(
-                        format!("`{:?}` is not a valid value for `{}`: {}", o, name, s)
-                    )),
-                }).unwrap_or(Ok(()))
-            } );
             ($key_name:ident, crt_objects_fallback) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
@@ -1606,7 +1516,7 @@ impl Target {
         key!(crt_static_allows_dylibs, bool);
         key!(crt_static_default, bool);
         key!(crt_static_respected, bool);
-        key!(stack_probes, StackProbeType)?;
+        key!(stack_probes, bool);
         key!(min_global_align, Option<u64>);
         key!(default_codegen_units, Option<u64>);
         key!(trap_unreachable, bool);
diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
index b9ff16bd19ff4..322b6f530e9fd 100644
--- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
@@ -9,7 +9,7 @@
 // the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
 // code runs in the same environment, no process separation is supported.
 
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, StackProbeType, TargetOptions};
+use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     let mut base = super::msvc_base::opts();
@@ -43,9 +43,7 @@ pub fn opts() -> TargetOptions {
         exe_suffix: ".efi".to_string(),
         allows_weak_linkage: false,
         panic_strategy: PanicStrategy::Abort,
-        // LLVM does not emit inline assembly because the LLVM target does not get considered as…
-        // "Windows".
-        stack_probes: StackProbeType::Call,
+        stack_probes: true,
         singlethread: true,
         linker: Some("rust-lld".to_string()),
         ..base
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
index 8c40baccda84a..edb33fe6e2b13 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::apple_base::opts("macos");
@@ -10,7 +10,7 @@ pub fn target() -> Target {
         vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()],
     );
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     // Clang automatically chooses a more specific target based on
     // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
index 6feeeac451b27..c9c7eeb723198 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
@@ -1,5 +1,5 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{StackProbeType, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = opts("ios", Arch::X86_64);
@@ -9,10 +9,6 @@ pub fn target() -> Target {
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
         arch: "x86_64".to_string(),
-        options: TargetOptions {
-            max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
-            ..base
-        },
+        options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
index a6e066213e7f9..6b360e5495be7 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
@@ -1,5 +1,5 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{StackProbeType, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = opts("ios", Arch::X86_64_macabi);
@@ -9,10 +9,6 @@ pub fn target() -> Target {
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
         arch: "x86_64".to_string(),
-        options: TargetOptions {
-            max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
-            ..base
-        },
+        options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
index f8c47168da87f..5b2a62a23fd8c 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
@@ -1,5 +1,5 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{StackProbeType, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = opts("tvos", Arch::X86_64);
@@ -8,10 +8,6 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(),
         arch: "x86_64".to_string(),
-        options: TargetOptions {
-            max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
-            ..base
-        },
+        options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
index a39e7f8c34105..6c049c2635c79 100644
--- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
@@ -1,10 +1,10 @@
-use crate::spec::{StackProbeType, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::fuchsia_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-fuchsia".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
index d436242e62b30..27327160178a0 100644
--- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::android_base::opts();
@@ -7,7 +7,7 @@ pub fn target() -> Target {
     base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-linux-android".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
index d84a63562c70a..095c6f15c77ad 100644
--- a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
@@ -12,7 +12,7 @@ pub fn target() -> Target {
     base.has_rpath = false;
     base.position_independent_executables = false;
     base.disable_redzone = true;
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-rumprun-netbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
index 0fe462ec83cbc..6ccf78402e149 100644
--- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::solaris_base::opts();
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-pc-solaris".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
index d86b0d67acd15..30aa2909873a3 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::dragonfly_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-unknown-dragonfly".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
index c7d3b3feed50e..ee904d762421f 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-unknown-freebsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
index 963d4fdb12f2d..ea7e068e516a9 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::haiku_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
     // This option is required to build executables on Haiku x86_64
     base.position_independent_executables = true;
 
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
index 31164f8408dcb..4005aaf58b133 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
@@ -1,11 +1,11 @@
-use crate::spec::{StackProbeType, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::hermit_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.features = "+rdrnd,+rdseed".to_string();
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-unknown-hermit".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
index 9fcfe4e6c14bf..b72d529363afb 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
@@ -1,4 +1,4 @@
-use crate::spec::{StackProbeType, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::hermit_kernel_base::opts();
@@ -7,7 +7,7 @@ pub fn target() -> Target {
     base.features =
         "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
             .to_string();
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-unknown-hermit".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
index 99906764dfc6e..f127dd49bc4b7 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_gnu_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-unknown-linux-gnu".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
index 4b2bce37470cc..0cae57528483f 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_gnu_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
     base.has_elf_tls = false;
     // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
     // breaks code gen. See LLVM bug 36743
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
index fa9fdf5aa0992..3669c10981e19 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
     base.static_position_independent_executables = true;
 
     Target {
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
index 6d19dec00b411..7e91a6ddbe296 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-unknown-netbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
index ac5939bcb3c43..0fe01f09c2e85 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-unknown-openbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
index ddabe95ab8394..cdd445b2614b2 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::redox_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
 
     Target {
         llvm_target: "x86_64-unknown-redox".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
index 1b35e813fcd8f..163af6fd8e175 100644
--- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    base.stack_probes = true;
     base.disable_redzone = true;
 
     Target {
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 77aa441340912..bd1d9cc895fb0 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -218,6 +218,10 @@ fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssociatedItems<'_> {
     ty::AssociatedItems::new(items)
 }
 
+fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span {
+    tcx.hir().span_if_local(def_id).unwrap()
+}
+
 fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
     tcx.hir().get_if_local(def_id).and_then(|node| node.ident()).map(|ident| ident.span)
 }
@@ -491,6 +495,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
         associated_item_def_ids,
         associated_items,
         adt_sized_constraint,
+        def_span,
         def_ident_span,
         param_env,
         param_env_reveal_all_normalized,
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 47361092a5c50..8e339eb26b26c 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -66,7 +66,7 @@ pub(super) fn check_fn<'a, 'tcx>(
     // Create the function context. This is either derived from scratch or,
     // in the case of closures, based on the outer context.
     let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
-    fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
+    *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
 
     let tcx = fcx.tcx;
     let sess = tcx.sess;
@@ -846,13 +846,21 @@ pub(super) fn check_specialization_validity<'tcx>(
         Ok(ancestors) => ancestors,
         Err(_) => return,
     };
-    let mut ancestor_impls = ancestors.skip(1).filter_map(|parent| {
-        if parent.is_from_trait() {
-            None
-        } else {
-            Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
-        }
-    });
+    let mut ancestor_impls = ancestors
+        .skip(1)
+        .filter_map(|parent| {
+            if parent.is_from_trait() {
+                None
+            } else {
+                Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
+            }
+        })
+        .peekable();
+
+    if ancestor_impls.peek().is_none() {
+        // No parent, nothing to specialize.
+        return;
+    }
 
     let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {
         match parent_item {
@@ -894,6 +902,8 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
     impl_trait_ref: ty::TraitRef<'tcx>,
     impl_item_refs: &[hir::ImplItemRef<'_>],
 ) {
+    let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
+
     // If the trait reference itself is erroneous (so the compilation is going
     // to fail), skip checking the items here -- the `impl_item` table in `tcx`
     // isn't populated for such impls.
@@ -921,75 +931,111 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
 
     // Locate trait definition and items
     let trait_def = tcx.trait_def(impl_trait_ref.def_id);
-    let impl_items = impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
-    let associated_items = tcx.associated_items(impl_trait_ref.def_id);
+
+    let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
 
     // Check existing impl methods to see if they are both present in trait
     // and compatible with trait signature
-    for impl_item in impl_items {
+    for impl_item in impl_items() {
+        let namespace = impl_item.kind.namespace();
         let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id));
-
-        let mut items =
-            associated_items.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id);
-
-        let (compatible_kind, ty_trait_item) = if let Some(ty_trait_item) = items.next() {
-            let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
-                (ty::AssocKind::Const, hir::ImplItemKind::Const(..)) => true,
-                (ty::AssocKind::Fn, hir::ImplItemKind::Fn(..)) => true,
-                (ty::AssocKind::Type, hir::ImplItemKind::TyAlias(..)) => true,
-                _ => false,
-            };
-
-            // If we don't have a compatible item, we'll use the first one whose name matches
-            // to report an error.
-            let mut compatible_kind = is_compatible(&ty_trait_item);
-            let mut trait_item = ty_trait_item;
-
-            if !compatible_kind {
-                if let Some(ty_trait_item) = items.find(is_compatible) {
-                    compatible_kind = true;
-                    trait_item = ty_trait_item;
-                }
-            }
-
-            (compatible_kind, trait_item)
-        } else {
-            continue;
-        };
-
-        if compatible_kind {
+        let ty_trait_item = tcx
+            .associated_items(impl_trait_ref.def_id)
+            .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id)
+            .or_else(|| {
+                // Not compatible, but needed for the error message
+                tcx.associated_items(impl_trait_ref.def_id)
+                    .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id)
+                    .next()
+            });
+
+        // Check that impl definition matches trait definition
+        if let Some(ty_trait_item) = ty_trait_item {
             match impl_item.kind {
                 hir::ImplItemKind::Const(..) => {
                     // Find associated const definition.
-                    compare_const_impl(
-                        tcx,
-                        &ty_impl_item,
-                        impl_item.span,
-                        &ty_trait_item,
-                        impl_trait_ref,
-                    );
+                    if ty_trait_item.kind == ty::AssocKind::Const {
+                        compare_const_impl(
+                            tcx,
+                            &ty_impl_item,
+                            impl_item.span,
+                            &ty_trait_item,
+                            impl_trait_ref,
+                        );
+                    } else {
+                        let mut err = struct_span_err!(
+                            tcx.sess,
+                            impl_item.span,
+                            E0323,
+                            "item `{}` is an associated const, \
+                             which doesn't match its trait `{}`",
+                            ty_impl_item.ident,
+                            impl_trait_ref.print_only_trait_path()
+                        );
+                        err.span_label(impl_item.span, "does not match trait");
+                        // We can only get the spans from local trait definition
+                        // Same for E0324 and E0325
+                        if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) {
+                            err.span_label(trait_span, "item in trait");
+                        }
+                        err.emit()
+                    }
                 }
                 hir::ImplItemKind::Fn(..) => {
                     let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
-                    compare_impl_method(
-                        tcx,
-                        &ty_impl_item,
-                        impl_item.span,
-                        &ty_trait_item,
-                        impl_trait_ref,
-                        opt_trait_span,
-                    );
+                    if ty_trait_item.kind == ty::AssocKind::Fn {
+                        compare_impl_method(
+                            tcx,
+                            &ty_impl_item,
+                            impl_item.span,
+                            &ty_trait_item,
+                            impl_trait_ref,
+                            opt_trait_span,
+                        );
+                    } else {
+                        let mut err = struct_span_err!(
+                            tcx.sess,
+                            impl_item.span,
+                            E0324,
+                            "item `{}` is an associated method, \
+                             which doesn't match its trait `{}`",
+                            ty_impl_item.ident,
+                            impl_trait_ref.print_only_trait_path()
+                        );
+                        err.span_label(impl_item.span, "does not match trait");
+                        if let Some(trait_span) = opt_trait_span {
+                            err.span_label(trait_span, "item in trait");
+                        }
+                        err.emit()
+                    }
                 }
                 hir::ImplItemKind::TyAlias(_) => {
                     let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
-                    compare_ty_impl(
-                        tcx,
-                        &ty_impl_item,
-                        impl_item.span,
-                        &ty_trait_item,
-                        impl_trait_ref,
-                        opt_trait_span,
-                    );
+                    if ty_trait_item.kind == ty::AssocKind::Type {
+                        compare_ty_impl(
+                            tcx,
+                            &ty_impl_item,
+                            impl_item.span,
+                            &ty_trait_item,
+                            impl_trait_ref,
+                            opt_trait_span,
+                        );
+                    } else {
+                        let mut err = struct_span_err!(
+                            tcx.sess,
+                            impl_item.span,
+                            E0325,
+                            "item `{}` is an associated type, \
+                             which doesn't match its trait `{}`",
+                            ty_impl_item.ident,
+                            impl_trait_ref.print_only_trait_path()
+                        );
+                        err.span_label(impl_item.span, "does not match trait");
+                        if let Some(trait_span) = opt_trait_span {
+                            err.span_label(trait_span, "item in trait");
+                        }
+                        err.emit()
+                    }
                 }
             }
 
@@ -1000,22 +1046,12 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
                 impl_id.to_def_id(),
                 impl_item,
             );
-        } else {
-            report_mismatch_error(
-                tcx,
-                ty_trait_item.def_id,
-                impl_trait_ref,
-                impl_item,
-                &ty_impl_item,
-            );
         }
     }
 
+    // Check for missing items from trait
+    let mut missing_items = Vec::new();
     if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
-        let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
-
-        // Check for missing items from trait
-        let mut missing_items = Vec::new();
         for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
             let is_implemented = ancestors
                 .leaf_def(tcx, trait_item.ident, trait_item.kind)
@@ -1028,63 +1064,11 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
                 }
             }
         }
-
-        if !missing_items.is_empty() {
-            missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
-        }
     }
-}
-
-#[inline(never)]
-#[cold]
-fn report_mismatch_error<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_item_def_id: DefId,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-    impl_item: &hir::ImplItem<'_>,
-    ty_impl_item: &ty::AssocItem,
-) {
-    let mut err = match impl_item.kind {
-        hir::ImplItemKind::Const(..) => {
-            // Find associated const definition.
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0323,
-                "item `{}` is an associated const, which doesn't match its trait `{}`",
-                ty_impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-
-        hir::ImplItemKind::Fn(..) => {
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0324,
-                "item `{}` is an associated method, which doesn't match its trait `{}`",
-                ty_impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
 
-        hir::ImplItemKind::TyAlias(_) => {
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0325,
-                "item `{}` is an associated type, which doesn't match its trait `{}`",
-                ty_impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-    };
-
-    err.span_label(impl_item.span, "does not match trait");
-    if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
-        err.span_label(trait_span, "item in trait");
+    if !missing_items.is_empty() {
+        missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
     }
-    err.emit();
 }
 
 /// Checks whether a type can be represented in memory. In particular, it
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index b2395b7bb2502..34ad8ec08984e 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -1472,22 +1472,22 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 fn_output = Some(&fn_decl.output); // `impl Trait` return type
             }
         }
-        if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
-            self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
+        if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) {
+            self.add_impl_trait_explanation(&mut err, cause, fcx, expected, *sp, fn_output);
         }
 
-        if let Some(sp) = fcx.ret_coercion_span.get() {
+        if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
             // If the closure has an explicit return type annotation,
             // then a type error may occur at the first return expression we
             // see in the closure (if it conflicts with the declared
             // return type). Skip adding a note in this case, since it
             // would be incorrect.
-            if !err.span.primary_spans().iter().any(|&span| span == sp) {
+            if !err.span.primary_spans().iter().any(|span| span == sp) {
                 let hir = fcx.tcx.hir();
                 let body_owner = hir.body_owned_by(hir.enclosing_body_owner(fcx.body_id));
                 if fcx.tcx.is_closure(hir.body_owner_def_id(body_owner).to_def_id()) {
                     err.span_note(
-                        sp,
+                        *sp,
                         &format!(
                             "return type inferred to be `{}` here",
                             fcx.resolve_vars_if_possible(expected)
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index e37b4ff742bc6..8aa6c6d924a53 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -266,7 +266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
-            ExprKind::Loop(ref body, _, source, _) => {
+            ExprKind::Loop(ref body, _, source) => {
                 self.check_expr_loop(body, source, expected, expr)
             }
             ExprKind::Match(ref discrim, ref arms, match_src) => {
@@ -680,14 +680,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if self.ret_coercion.is_none() {
             self.tcx.sess.emit_err(ReturnStmtOutsideOfFnBody { span: expr.span });
         } else if let Some(ref e) = expr_opt {
-            if self.ret_coercion_span.get().is_none() {
-                self.ret_coercion_span.set(Some(e.span));
+            if self.ret_coercion_span.borrow().is_none() {
+                *self.ret_coercion_span.borrow_mut() = Some(e.span);
             }
             self.check_return_expr(e);
         } else {
             let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
-            if self.ret_coercion_span.get().is_none() {
-                self.ret_coercion_span.set(Some(expr.span));
+            if self.ret_coercion_span.borrow().is_none() {
+                *self.ret_coercion_span.borrow_mut() = Some(expr.span);
             }
             let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
             if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index fb6f9c03352b4..6df9e3ab7dbe8 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -23,6 +23,7 @@ use rustc_span::{self, MultiSpan, Span};
 use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression};
 
 use crate::structured_errors::StructuredDiagnostic;
+use std::mem::replace;
 use std::slice;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -588,7 +589,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         blk: &'tcx hir::Block<'tcx>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        let prev = self.ps.replace(self.ps.get().recurse(blk));
+        let prev = {
+            let mut fcx_ps = self.ps.borrow_mut();
+            let unsafety_state = fcx_ps.recurse(blk);
+            replace(&mut *fcx_ps, unsafety_state)
+        };
 
         // In some cases, blocks have just one exit, but other blocks
         // can be targeted by multiple breaks. This can happen both
@@ -704,7 +709,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         self.write_ty(blk.hir_id, ty);
 
-        self.ps.set(prev);
+        *self.ps.borrow_mut() = prev;
         ty
     }
 
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index e9223f700dcc7..6d09043bd5033 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -66,11 +66,11 @@ pub struct FnCtxt<'a, 'tcx> {
     pub(super) in_tail_expr: bool,
 
     /// First span of a return site that we find. Used in error messages.
-    pub(super) ret_coercion_span: Cell<Option<Span>>,
+    pub(super) ret_coercion_span: RefCell<Option<Span>>,
 
     pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
 
-    pub(super) ps: Cell<UnsafetyState>,
+    pub(super) ps: RefCell<UnsafetyState>,
 
     /// Whether the last checked node generates a divergence (e.g.,
     /// `return` will set this to `Always`). In general, when entering
@@ -127,9 +127,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ret_coercion_impl_trait: None,
             ret_type_span: None,
             in_tail_expr: false,
-            ret_coercion_span: Cell::new(None),
+            ret_coercion_span: RefCell::new(None),
             resume_yield_tys: None,
-            ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
+            ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
             diverges: Cell::new(Diverges::Maybe),
             has_errors: Cell::new(false),
             enclosing_breakables: RefCell::new(EnclosingBreakables {
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index c8c6fa12fae08..52276ed4beeaa 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -184,14 +184,14 @@ impl UnsafetyState {
         UnsafetyState { def, unsafety, unsafe_push_count: 0, from_fn: true }
     }
 
-    pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
+    pub fn recurse(&mut self, blk: &hir::Block<'_>) -> UnsafetyState {
         use hir::BlockCheckMode;
         match self.unsafety {
             // If this unsafe, then if the outer function was already marked as
             // unsafe we shouldn't attribute the unsafe'ness to the block. This
             // way the block can be warned about instead of ignoring this
             // extraneous block (functions are never warned about).
-            hir::Unsafety::Unsafe if self.from_fn => self,
+            hir::Unsafety::Unsafe if self.from_fn => *self,
 
             unsafety => {
                 let (unsafety, def, count) = match blk.rules {
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 24364c6954e49..01519e4c8f7c4 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -289,7 +289,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
             | hir::ExprKind::ConstBlock(..)
             | hir::ExprKind::Err => {}
 
-            hir::ExprKind::Loop(ref blk, ..) => {
+            hir::ExprKind::Loop(ref blk, _, _) => {
                 self.walk_block(blk);
             }
 
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index 339eb5f9afc74..a8fbdfb7c6514 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -207,13 +207,27 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
         }
     }
 
-    #[instrument(skip(self, current))]
+    fn add_constraints_from_trait_ref(
+        &mut self,
+        current: &CurrentItem,
+        trait_ref: ty::TraitRef<'tcx>,
+        variance: VarianceTermPtr<'a>,
+    ) {
+        debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}", trait_ref, variance);
+        self.add_constraints_from_invariant_substs(current, trait_ref.substs, variance);
+    }
+
     fn add_constraints_from_invariant_substs(
         &mut self,
         current: &CurrentItem,
         substs: SubstsRef<'tcx>,
         variance: VarianceTermPtr<'a>,
     ) {
+        debug!(
+            "add_constraints_from_invariant_substs: substs={:?} variance={:?}",
+            substs, variance
+        );
+
         // Trait are always invariant so we can take advantage of that.
         let variance_i = self.invariant(variance);
 
@@ -286,7 +300,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             }
 
             ty::Projection(ref data) => {
-                self.add_constraints_from_invariant_substs(current, data.substs, variance);
+                let tcx = self.tcx();
+                self.add_constraints_from_trait_ref(current, data.trait_ref(tcx), variance);
             }
 
             ty::Opaque(_, substs) => {
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index dacf6f8d83004..0aa52b35ced45 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -178,10 +178,8 @@ impl<T> Box<T> {
     /// ```
     /// let five = Box::new(5);
     /// ```
-    #[inline(always)]
-    #[doc(alias = "alloc")]
-    #[doc(alias = "malloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[inline(always)]
     pub fn new(x: T) -> Self {
         box x
     }
@@ -228,9 +226,8 @@ impl<T> Box<T> {
     /// ```
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
-    #[inline]
-    #[doc(alias = "calloc")]
     #[unstable(feature = "new_uninit", issue = "63291")]
+    #[inline]
     pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> {
         Self::new_zeroed_in(Global)
     }
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 57fad4217b6c6..8ab3f58c1adba 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -238,12 +238,13 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
 /// such restrictions:
 /// - For each type parameter, we can only define a method either generically
 ///   or for one particular type. For example, we cannot define a method like
-///   `into_kv` generically for all `BorrowType`, or once for all types that
-///   carry a lifetime, because we want it to return `&'a` references.
+///   `key_at` generically for all `BorrowType`, because we want it to return
+///   `&'a K` for most choices of `BorrowType`, but plain `K` for `Owned`.
+///   We cannot define `key_at` once for all types that carry a lifetime.
 ///   Therefore, we define it only for the least powerful type `Immut<'a>`.
 /// - We cannot get implicit coercion from say `Mut<'a>` to `Immut<'a>`.
 ///   Therefore, we have to explicitly call `reborrow` on a more powerfull
-///   `NodeRef` in order to reach a method like `into_kv`.
+///   `NodeRef` in order to reach a method like `key_at`.
 ///
 /// All methods on `NodeRef` that return some kind of reference, either:
 /// - Take `self` by value, and return the lifetime carried by `BorrowType`.
@@ -343,6 +344,26 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
     }
 }
 
+impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
+    /// Exposes one of the keys stored in the node.
+    ///
+    /// # Safety
+    /// The node has more than `idx` initialized elements.
+    pub unsafe fn key_at(self, idx: usize) -> &'a K {
+        debug_assert!(idx < self.len());
+        unsafe { self.into_leaf().keys.get_unchecked(idx).assume_init_ref() }
+    }
+
+    /// Exposes one of the values stored in the node.
+    ///
+    /// # Safety
+    /// The node has more than `idx` initialized elements.
+    unsafe fn val_at(self, idx: usize) -> &'a V {
+        debug_assert!(idx < self.len());
+        unsafe { self.into_leaf().vals.get_unchecked(idx).assume_init_ref() }
+    }
+}
+
 impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
     /// Finds the parent of the current node. Returns `Ok(handle)` if the current
     /// node actually has a parent, where `handle` points to the edge of the parent
@@ -400,14 +421,6 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
         // SAFETY: there can be no mutable references into this tree borrowed as `Immut`.
         unsafe { &*ptr }
     }
-
-    /// Borrows a view into the keys stored in the node.
-    pub fn keys(&self) -> &[K] {
-        let leaf = self.into_leaf();
-        unsafe {
-            MaybeUninit::slice_assume_init_ref(leaf.keys.get_unchecked(..usize::from(leaf.len)))
-        }
-    }
 }
 
 impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
@@ -974,11 +987,7 @@ impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marke
 
 impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Immut<'a>, K, V, NodeType>, marker::KV> {
     pub fn into_kv(self) -> (&'a K, &'a V) {
-        debug_assert!(self.idx < self.node.len());
-        let leaf = self.node.into_leaf();
-        let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() };
-        let v = unsafe { leaf.vals.get_unchecked(self.idx).assume_init_ref() };
-        (k, v)
+        (unsafe { self.node.key_at(self.idx) }, unsafe { self.node.val_at(self.idx) })
     }
 }
 
@@ -988,7 +997,6 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>
     }
 
     pub fn into_val_mut(self) -> &'a mut V {
-        debug_assert!(self.idx < self.node.len());
         let leaf = self.node.into_leaf_mut();
         unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }
     }
@@ -1002,7 +1010,6 @@ impl<'a, K, V, NodeType> Handle<NodeRef<marker::ValMut<'a>, K, V, NodeType>, mar
 
 impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
     pub fn kv_mut(&mut self) -> (&mut K, &mut V) {
-        debug_assert!(self.idx < self.node.len());
         // We cannot call separate key and value methods, because calling the second one
         // invalidates the reference returned by the first.
         unsafe {
diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs
index 11433cd845bee..48ce9f2bd89c8 100644
--- a/library/alloc/src/collections/btree/node/tests.rs
+++ b/library/alloc/src/collections/btree/node/tests.rs
@@ -29,7 +29,17 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
             navigate::Position::Leaf(leaf) => {
                 let depth = self.height();
                 let indent = "  ".repeat(depth);
-                result += &format!("\n{}{:?}", indent, leaf.keys());
+                result += &format!("\n{}", indent);
+                if leaf.len() == 0 {
+                    result += "(empty node)";
+                } else {
+                    for idx in 0..leaf.len() {
+                        if idx > 0 {
+                            result += ", ";
+                        }
+                        result += &format!("{:?}", unsafe { leaf.key_at(idx) });
+                    }
+                }
             }
             navigate::Position::Internal(_) => {}
             navigate::Position::InternalKV(kv) => {
diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs
index d8bebed758f1a..f62eae3f4d5a2 100644
--- a/library/alloc/src/collections/btree/search.rs
+++ b/library/alloc/src/collections/btree/search.rs
@@ -71,15 +71,18 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
         Q: Ord,
         K: Borrow<Q>,
     {
-        let node = self.reborrow();
-        let keys = node.keys();
-        for (i, k) in keys.iter().enumerate() {
+        // This function is defined over all borrow types (immutable, mutable, owned).
+        // Using `keys_at()` is fine here even if BorrowType is mutable, as all we return
+        // is an index -- not a reference.
+        let len = self.len();
+        for i in 0..len {
+            let k = unsafe { self.reborrow().key_at(i) };
             match key.cmp(k.borrow()) {
                 Ordering::Greater => {}
                 Ordering::Equal => return IndexResult::KV(i),
                 Ordering::Less => return IndexResult::Edge(i),
             }
         }
-        IndexResult::Edge(keys.len())
+        IndexResult::Edge(len)
     }
 }
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 6f9133e2811bf..5b61e8911a59a 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -2646,13 +2646,9 @@ impl<A: Ord> Ord for VecDeque<A> {
 impl<A: Hash> Hash for VecDeque<A> {
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.len().hash(state);
-        // It's not possible to use Hash::hash_slice on slices
-        // returned by as_slices method as their length can vary
-        // in otherwise identical deques.
-        //
-        // Hasher only guarantees equivalence for the exact same
-        // set of calls to its methods.
-        self.iter().for_each(|elem| elem.hash(state));
+        let (a, b) = self.as_slices();
+        Hash::hash_slice(a, state);
+        Hash::hash_slice(b, state);
     }
 }
 
diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs
index 87e06fa394d38..27dc59ae64411 100644
--- a/library/alloc/src/collections/vec_deque/tests.rs
+++ b/library/alloc/src/collections/vec_deque/tests.rs
@@ -599,43 +599,3 @@ fn issue_53529() {
         assert_eq!(*a, 2);
     }
 }
-
-#[test]
-fn issue_80303() {
-    use core::iter;
-    use core::num::Wrapping;
-
-    // This is a valid, albeit rather bad hash function implementation.
-    struct SimpleHasher(Wrapping<u64>);
-
-    impl Hasher for SimpleHasher {
-        fn finish(&self) -> u64 {
-            self.0.0
-        }
-
-        fn write(&mut self, bytes: &[u8]) {
-            // This particular implementation hashes value 24 in addition to bytes.
-            // Such an implementation is valid as Hasher only guarantees equivalence
-            // for the exact same set of calls to its methods.
-            for &v in iter::once(&24).chain(bytes) {
-                self.0 = Wrapping(31) * self.0 + Wrapping(u64::from(v));
-            }
-        }
-    }
-
-    fn hash_code(value: impl Hash) -> u64 {
-        let mut hasher = SimpleHasher(Wrapping(1));
-        value.hash(&mut hasher);
-        hasher.finish()
-    }
-
-    // This creates two deques for which values returned by as_slices
-    // method differ.
-    let vda: VecDeque<u8> = (0..10).collect();
-    let mut vdb = VecDeque::with_capacity(10);
-    vdb.extend(5..10);
-    (0..5).rev().for_each(|elem| vdb.push_front(elem));
-    assert_ne!(vda.as_slices(), vdb.as_slices());
-    assert_eq!(vda, vdb);
-    assert_eq!(hash_code(vda), hash_code(vdb));
-}
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index d7ae353282e79..8d721ed7487ae 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -189,4 +189,11 @@ pub mod vec;
 #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
 pub mod __export {
     pub use core::format_args;
+
+    /// Force AST node to an expression to improve diagnostics in pattern position.
+    #[rustc_macro_transparency = "semitransparent"]
+    #[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
+    pub macro force_expr($e:expr) {
+        $e
+    }
 }
diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs
index a64a8b32ad77f..3a46763c3f608 100644
--- a/library/alloc/src/macros.rs
+++ b/library/alloc/src/macros.rs
@@ -35,20 +35,18 @@
 ///
 /// [`Vec`]: crate::vec::Vec
 #[cfg(not(test))]
-#[doc(alias = "alloc")]
-#[doc(alias = "malloc")]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow_internal_unstable(box_syntax, liballoc_internals)]
 macro_rules! vec {
     () => (
-        $crate::__rust_force_expr!($crate::vec::Vec::new())
+        $crate::__export::force_expr!($crate::vec::Vec::new())
     );
     ($elem:expr; $n:expr) => (
-        $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))
+        $crate::__export::force_expr!($crate::vec::from_elem($elem, $n))
     );
     ($($x:expr),+ $(,)?) => (
-        $crate::__rust_force_expr!(<[_]>::into_vec(box [$($x),+]))
+        $crate::__export::force_expr!(<[_]>::into_vec(box [$($x),+]))
     );
 }
 
@@ -113,13 +111,3 @@ macro_rules! format {
         res
     }}
 }
-
-/// Force AST node to an expression to improve diagnostics in pattern position.
-#[doc(hidden)]
-#[macro_export]
-#[unstable(feature = "liballoc_internals", issue = "none", reason = "implementation detail")]
-macro_rules! __rust_force_expr {
-    ($e:expr) => {
-        $e
-    };
-}
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 56f4ebe57f8af..36b7efc33a874 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -114,19 +114,6 @@ impl<T> RawVec<T, Global> {
 }
 
 impl<T, A: Allocator> RawVec<T, A> {
-    // Tiny Vecs are dumb. Skip to:
-    // - 8 if the element size is 1, because any heap allocators is likely
-    //   to round up a request of less than 8 bytes to at least 8 bytes.
-    // - 4 if elements are moderate-sized (<= 1 KiB).
-    // - 1 otherwise, to avoid wasting too much space for very short Vecs.
-    const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 {
-        8
-    } else if mem::size_of::<T>() <= 1024 {
-        4
-    } else {
-        1
-    };
-
     /// Like `new`, but parameterized over the choice of allocator for
     /// the returned `RawVec`.
     #[rustc_allow_const_fn_unstable(const_fn)]
@@ -232,7 +219,6 @@ impl<T, A: Allocator> RawVec<T, A> {
     /// Gets a raw pointer to the start of the allocation. Note that this is
     /// `Unique::dangling()` if `capacity == 0` or `T` is zero-sized. In the former case, you must
     /// be careful.
-    #[inline]
     pub fn ptr(&self) -> *mut T {
         self.ptr.as_ptr()
     }
@@ -413,7 +399,22 @@ impl<T, A: Allocator> RawVec<T, A> {
         // This guarantees exponential growth. The doubling cannot overflow
         // because `cap <= isize::MAX` and the type of `cap` is `usize`.
         let cap = cmp::max(self.cap * 2, required_cap);
-        let cap = cmp::max(Self::MIN_NON_ZERO_CAP, cap);
+
+        // Tiny Vecs are dumb. Skip to:
+        // - 8 if the element size is 1, because any heap allocators is likely
+        //   to round up a request of less than 8 bytes to at least 8 bytes.
+        // - 4 if elements are moderate-sized (<= 1 KiB).
+        // - 1 otherwise, to avoid wasting too much space for very short Vecs.
+        // Note that `min_non_zero_cap` is computed statically.
+        let elem_size = mem::size_of::<T>();
+        let min_non_zero_cap = if elem_size == 1 {
+            8
+        } else if elem_size <= 1024 {
+            4
+        } else {
+            1
+        };
+        let cap = cmp::max(min_non_zero_cap, cap);
 
         let new_layout = Layout::array::<T>(cap);
 
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index b1f860d6b64a8..6f2a497598dd7 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -403,8 +403,6 @@ impl String {
     /// s.push('a');
     /// ```
     #[inline]
-    #[doc(alias = "alloc")]
-    #[doc(alias = "malloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(capacity: usize) -> String {
         String { vec: Vec::with_capacity(capacity) }
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index b533ce794207a..0f5feb4ab8dc4 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -433,7 +433,6 @@ impl<T> Vec<T> {
     /// assert!(vec.capacity() >= 11);
     /// ```
     #[inline]
-    #[doc(alias = "malloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(capacity: usize) -> Self {
         Self::with_capacity_in(capacity, Global)
@@ -767,7 +766,6 @@ impl<T, A: Allocator> Vec<T, A> {
     /// vec.reserve(10);
     /// assert!(vec.capacity() >= 11);
     /// ```
-    #[doc(alias = "realloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve(&mut self, additional: usize) {
         self.buf.reserve(self.len, additional);
@@ -793,7 +791,6 @@ impl<T, A: Allocator> Vec<T, A> {
     /// vec.reserve_exact(10);
     /// assert!(vec.capacity() >= 11);
     /// ```
-    #[doc(alias = "realloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve_exact(&mut self, additional: usize) {
         self.buf.reserve_exact(self.len, additional);
@@ -831,7 +828,6 @@ impl<T, A: Allocator> Vec<T, A> {
     /// }
     /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
     /// ```
-    #[doc(alias = "realloc")]
     #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
     pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
         self.buf.try_reserve(self.len, additional)
@@ -873,7 +869,6 @@ impl<T, A: Allocator> Vec<T, A> {
     /// }
     /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?");
     /// ```
-    #[doc(alias = "realloc")]
     #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
     pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
         self.buf.try_reserve_exact(self.len, additional)
@@ -893,7 +888,6 @@ impl<T, A: Allocator> Vec<T, A> {
     /// vec.shrink_to_fit();
     /// assert!(vec.capacity() >= 3);
     /// ```
-    #[doc(alias = "realloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn shrink_to_fit(&mut self) {
         // The capacity is never less than the length, and there's nothing to do when
@@ -926,7 +920,6 @@ impl<T, A: Allocator> Vec<T, A> {
     /// vec.shrink_to(0);
     /// assert!(vec.capacity() >= 3);
     /// ```
-    #[doc(alias = "realloc")]
     #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")]
     pub fn shrink_to(&mut self, min_capacity: usize) {
         self.buf.shrink_to_fit(cmp::max(self.len, min_capacity));
diff --git a/library/alloc/src/vec/spec_from_iter_nested.rs b/library/alloc/src/vec/spec_from_iter_nested.rs
index ec390c62165a5..6abd4ff2a3f0a 100644
--- a/library/alloc/src/vec/spec_from_iter_nested.rs
+++ b/library/alloc/src/vec/spec_from_iter_nested.rs
@@ -5,7 +5,7 @@ use super::{SpecExtend, Vec};
 
 /// Another specialization trait for Vec::from_iter
 /// necessary to manually prioritize overlapping specializations
-/// see [`SpecFromIter`](super::SpecFromIter) for details.
+/// see [`SpecFromIter`] for details.
 pub(super) trait SpecFromIterNested<T, I> {
     fn from_iter(iter: I) -> Self;
 }
diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs
index f2169914ac9da..fb6b4b7837941 100644
--- a/library/core/benches/iter.rs
+++ b/library/core/benches/iter.rs
@@ -276,29 +276,7 @@ bench_sums! {
 bench_sums! {
     bench_cycle_take_sum,
     bench_cycle_take_ref_sum,
-    (0..10000).cycle().take(1000000)
-}
-
-bench_sums! {
-    bench_cycle_skip_take_sum,
-    bench_cycle_skip_take_ref_sum,
-    (0..100000).cycle().skip(1000000).take(1000000)
-}
-
-bench_sums! {
-    bench_cycle_take_skip_sum,
-    bench_cycle_take_skip_ref_sum,
-    (0..100000).cycle().take(1000000).skip(100000)
-}
-
-bench_sums! {
-    bench_skip_cycle_skip_zip_add_sum,
-    bench_skip_cycle_skip_zip_add_ref_sum,
-    (0..100000).skip(100).cycle().skip(100)
-      .zip((0..100000).cycle().skip(10))
-      .map(|(a,b)| a+b)
-      .skip(100000)
-      .take(1000000)
+    (0i64..10000).cycle().take(1000000)
 }
 
 // Checks whether Skip<Zip<A,B>> is as fast as Zip<Skip<A>, Skip<B>>, from
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 139863bbe7f81..041f40f2cbcf5 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -460,6 +460,7 @@ pub trait TryInto<T>: Sized {
 /// assert!(try_successful_smaller_number.is_ok());
 /// ```
 ///
+/// [`i32::MAX`]: crate::i32::MAX
 /// [`try_from`]: TryFrom::try_from
 /// [`!`]: ../../std/primitive.never.html
 #[stable(feature = "try_from", since = "1.34.0")]
diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs
index ce5e9936bbd7f..9753e1b43ba95 100644
--- a/library/core/src/iter/adapters/chain.rs
+++ b/library/core/src/iter/adapters/chain.rs
@@ -1,5 +1,5 @@
 use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
-use crate::ops::Try;
+use crate::{ops::Try, usize};
 
 /// An iterator that links two iterators together, in a chain.
 ///
diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
index d8bbd424cf258..1d01e9b5fb7dc 100644
--- a/library/core/src/iter/adapters/intersperse.rs
+++ b/library/core/src/iter/adapters/intersperse.rs
@@ -151,14 +151,16 @@ where
 {
     let (lo, hi) = iter.size_hint();
     let next_is_elem = !needs_sep;
-    (
-        lo.saturating_sub(next_is_elem as usize).saturating_add(lo),
-        hi.and_then(|hi| hi.saturating_sub(next_is_elem as usize).checked_add(hi)),
-    )
+    let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo);
+    let hi = match hi {
+        Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi),
+        None => None,
+    };
+    (lo, hi)
 }
 
 fn intersperse_fold<I, B, F, G>(
-    mut iter: I,
+    mut iter: Peekable<I>,
     init: B,
     mut f: F,
     mut separator: G,
@@ -171,11 +173,10 @@ where
 {
     let mut accum = init;
 
-    if !needs_sep {
+    // Use `peek()` first to avoid calling `next()` on an empty iterator.
+    if !needs_sep || iter.peek().is_some() {
         if let Some(x) = iter.next() {
             accum = f(accum, x);
-        } else {
-            return accum;
         }
     }
 
diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs
index e55c7a6bf5df1..dd5325660c342 100644
--- a/library/core/src/iter/adapters/skip.rs
+++ b/library/core/src/iter/adapters/skip.rs
@@ -1,4 +1,3 @@
-use crate::intrinsics::unlikely;
 use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
 use crate::ops::{ControlFlow, Try};
 
@@ -32,10 +31,13 @@ where
 
     #[inline]
     fn next(&mut self) -> Option<I::Item> {
-        if unlikely(self.n > 0) {
-            self.iter.nth(crate::mem::take(&mut self.n) - 1);
+        if self.n == 0 {
+            self.iter.next()
+        } else {
+            let old_n = self.n;
+            self.n = 0;
+            self.iter.nth(old_n)
         }
-        self.iter.next()
     }
 
     #[inline]
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index 9e7055a370c9d..4321b2187e108 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -200,7 +200,6 @@ macro_rules! step_identical_methods {
         }
 
         #[inline]
-        #[allow(arithmetic_overflow)]
         fn forward(start: Self, n: usize) -> Self {
             // In debug builds, trigger a panic on overflow.
             // This should optimize completely out in release builds.
@@ -212,7 +211,6 @@ macro_rules! step_identical_methods {
         }
 
         #[inline]
-        #[allow(arithmetic_overflow)]
         fn backward(start: Self, n: usize) -> Self {
             // In debug builds, trigger a panic on overflow.
             // This should optimize completely out in release builds.
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 9f7ced829b0ac..83d339d8f40a5 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -225,6 +225,8 @@ pub trait Iterator {
     /// This function might panic if the iterator has more than [`usize::MAX`]
     /// elements.
     ///
+    /// [`usize::MAX`]: crate::usize::MAX
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -567,10 +569,9 @@ pub trait Iterator {
         Zip::new(self, other.into_iter())
     }
 
-    /// Creates a new iterator which places a copy of `separator` between adjacent
-    /// items of the original iterator.
+    /// Places a copy of `separator` between all elements.
     ///
-    /// In case `separator` does not implement [`Clone`] or needs to be
+    /// In case the separator does not implement [`Clone`] or needs to be
     /// computed every time, use [`intersperse_with`].
     ///
     /// # Examples
@@ -580,19 +581,6 @@ pub trait Iterator {
     /// ```
     /// #![feature(iter_intersperse)]
     ///
-    /// let mut a = [0, 1, 2].iter().intersperse(&100);
-    /// assert_eq!(a.next(), Some(&0));   // The first element from `a`.
-    /// assert_eq!(a.next(), Some(&100)); // The separator.
-    /// assert_eq!(a.next(), Some(&1));   // The next element from `a`.
-    /// assert_eq!(a.next(), Some(&100)); // The separator.
-    /// assert_eq!(a.next(), Some(&2));   // The last element from `a`.
-    /// assert_eq!(a.next(), None);       // The iterator is finished.
-    /// ```
-    ///
-    /// `intersperse` can be very useful to join an iterator's items using a common element:
-    /// ```
-    /// #![feature(iter_intersperse)]
-    ///
     /// let hello = ["Hello", "World", "!"].iter().copied().intersperse(" ").collect::<String>();
     /// assert_eq!(hello, "Hello World !");
     /// ```
@@ -609,16 +597,7 @@ pub trait Iterator {
         Intersperse::new(self, separator)
     }
 
-    /// Creates a new iterator which places an item generated by `separator`
-    /// between adjacent items of the original iterator.
-    ///
-    /// The closure will be called exactly once each time an item is placed
-    /// between two adjacent items from the underlying iterator; specifically,
-    /// the closure is not called if the underlying iterator yields less than
-    /// two items and after the last item is yielded.
-    ///
-    /// If the iterator's item implements [`Clone`], it may be easier to use
-    /// [`intersperse`].
+    /// Places an element generated by `separator` between all elements.
     ///
     /// # Examples
     ///
@@ -627,36 +606,14 @@ pub trait Iterator {
     /// ```
     /// #![feature(iter_intersperse)]
     ///
-    /// #[derive(PartialEq, Debug)]
-    /// struct NotClone(usize);
-    ///
-    /// let v = vec![NotClone(0), NotClone(1), NotClone(2)];
-    /// let mut it = v.into_iter().intersperse_with(|| NotClone(99));
-    ///
-    /// assert_eq!(it.next(), Some(NotClone(0)));  // The first element from `v`.
-    /// assert_eq!(it.next(), Some(NotClone(99))); // The separator.
-    /// assert_eq!(it.next(), Some(NotClone(1)));  // The next element from `v`.
-    /// assert_eq!(it.next(), Some(NotClone(99))); // The separator.
-    /// assert_eq!(it.next(), Some(NotClone(2)));  // The last element from from `v`.
-    /// assert_eq!(it.next(), None);               // The iterator is finished.
-    /// ```
-    ///
-    /// `intersperse_with` can be used in situations where the separator needs
-    /// to be computed:
-    /// ```
-    /// #![feature(iter_intersperse)]
-    ///
     /// let src = ["Hello", "to", "all", "people", "!!"].iter().copied();
     ///
-    /// // The closure mutably borrows its context to generate an item.
     /// let mut happy_emojis = [" ❤️ ", " 😀 "].iter().copied();
     /// let separator = || happy_emojis.next().unwrap_or(" 🦀 ");
     ///
     /// let result = src.intersperse_with(separator).collect::<String>();
     /// assert_eq!(result, "Hello ❤️ to 😀 all 🦀 people 🦀 !!");
     /// ```
-    /// [`Clone`]: crate::clone::Clone
-    /// [`intersperse`]: Iterator::intersperse
     #[inline]
     #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
     fn intersperse_with<G>(self, separator: G) -> IntersperseWith<Self, G>
@@ -914,6 +871,7 @@ pub trait Iterator {
     /// overflow a [`usize`].
     ///
     /// [`usize`]: type@usize
+    /// [`usize::MAX`]: crate::usize::MAX
     /// [`zip`]: Iterator::zip
     ///
     /// # Examples
@@ -2425,6 +2383,7 @@ pub trait Iterator {
     /// non-matching elements.
     ///
     /// [`Some(index)`]: Some
+    /// [`usize::MAX`]: crate::usize::MAX
     ///
     /// # Examples
     ///
diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs
index ed8eea672f80b..0900676146c0d 100644
--- a/library/core/src/iter/traits/marker.rs
+++ b/library/core/src/iter/traits/marker.rs
@@ -33,6 +33,8 @@ impl<I: FusedIterator + ?Sized> FusedIterator for &mut I {}
 ///
 /// This trait must only be implemented when the contract is upheld. Consumers
 /// of this trait must inspect [`Iterator::size_hint()`]’s upper bound.
+///
+/// [`usize::MAX`]: crate::usize::MAX
 #[unstable(feature = "trusted_len", issue = "37572")]
 #[rustc_unsafe_specialization_marker]
 pub unsafe trait TrustedLen: Iterator {}
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 263c6c9cf0f26..df8d9ff371fe4 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -126,7 +126,6 @@
 #![feature(auto_traits)]
 #![feature(or_patterns)]
 #![feature(prelude_import)]
-#![feature(raw_ref_macros)]
 #![feature(repr_simd, platform_intrinsics)]
 #![feature(rustc_attrs)]
 #![feature(simd_ffi)]
diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs
index 91c61f814e1a8..039112e9f3468 100644
--- a/library/core/src/num/dec2flt/mod.rs
+++ b/library/core/src/num/dec2flt/mod.rs
@@ -3,7 +3,7 @@
 //! # Problem statement
 //!
 //! We are given a decimal string such as `12.34e56`. This string consists of integral (`12`),
-//! fractional (`34`), and exponent (`56`) parts. All parts are optional and interpreted as zero
+//! fractional (`45`), and exponent (`56`) parts. All parts are optional and interpreted as zero
 //! when missing.
 //!
 //! We seek the IEEE 754 floating point number that is closest to the exact value of the decimal
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 795f94ec03454..4d876fd8c33e2 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -1,13 +1,12 @@
-//! Constants specific to the `f32` single-precision floating point type.
+//! This module provides constants which are specific to the implementation
+//! of the `f32` floating point data type.
 //!
 //! *[See also the `f32` primitive type](../../std/primitive.f32.html).*
 //!
 //! Mathematically significant numbers are provided in the `consts` sub-module.
 //!
-//! For the constants defined directly in this module
-//! (as distinct from those defined in the `consts` sub-module),
-//! new code should instead use the associated constants
-//! defined directly on the `f32` type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -24,14 +23,12 @@ use crate::num::FpCategory;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let r = std::f32::RADIX;
 ///
 /// // intended way
 /// let r = f32::RADIX;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `RADIX` associated constant on `f32`")]
 pub const RADIX: u32 = f32::RADIX;
 
 /// Number of significant digits in base 2.
@@ -41,17 +38,12 @@ pub const RADIX: u32 = f32::RADIX;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let d = std::f32::MANTISSA_DIGITS;
 ///
 /// // intended way
 /// let d = f32::MANTISSA_DIGITS;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MANTISSA_DIGITS` associated constant on `f32`"
-)]
 pub const MANTISSA_DIGITS: u32 = f32::MANTISSA_DIGITS;
 
 /// Approximate number of significant digits in base 10.
@@ -61,14 +53,12 @@ pub const MANTISSA_DIGITS: u32 = f32::MANTISSA_DIGITS;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let d = std::f32::DIGITS;
 ///
 /// // intended way
 /// let d = f32::DIGITS;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `DIGITS` associated constant on `f32`")]
 pub const DIGITS: u32 = f32::DIGITS;
 
 /// [Machine epsilon] value for `f32`.
@@ -82,17 +72,12 @@ pub const DIGITS: u32 = f32::DIGITS;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let e = std::f32::EPSILON;
 ///
 /// // intended way
 /// let e = f32::EPSILON;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `EPSILON` associated constant on `f32`"
-)]
 pub const EPSILON: f32 = f32::EPSILON;
 
 /// Smallest finite `f32` value.
@@ -102,14 +87,12 @@ pub const EPSILON: f32 = f32::EPSILON;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let min = std::f32::MIN;
 ///
 /// // intended way
 /// let min = f32::MIN;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on `f32`")]
 pub const MIN: f32 = f32::MIN;
 
 /// Smallest positive normal `f32` value.
@@ -119,17 +102,12 @@ pub const MIN: f32 = f32::MIN;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let min = std::f32::MIN_POSITIVE;
 ///
 /// // intended way
 /// let min = f32::MIN_POSITIVE;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_POSITIVE` associated constant on `f32`"
-)]
 pub const MIN_POSITIVE: f32 = f32::MIN_POSITIVE;
 
 /// Largest finite `f32` value.
@@ -139,14 +117,12 @@ pub const MIN_POSITIVE: f32 = f32::MIN_POSITIVE;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let max = std::f32::MAX;
 ///
 /// // intended way
 /// let max = f32::MAX;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on `f32`")]
 pub const MAX: f32 = f32::MAX;
 
 /// One greater than the minimum possible normal power of 2 exponent.
@@ -156,17 +132,12 @@ pub const MAX: f32 = f32::MAX;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let min = std::f32::MIN_EXP;
 ///
 /// // intended way
 /// let min = f32::MIN_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_EXP` associated constant on `f32`"
-)]
 pub const MIN_EXP: i32 = f32::MIN_EXP;
 
 /// Maximum possible power of 2 exponent.
@@ -176,17 +147,12 @@ pub const MIN_EXP: i32 = f32::MIN_EXP;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let max = std::f32::MAX_EXP;
 ///
 /// // intended way
 /// let max = f32::MAX_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MAX_EXP` associated constant on `f32`"
-)]
 pub const MAX_EXP: i32 = f32::MAX_EXP;
 
 /// Minimum possible normal power of 10 exponent.
@@ -196,17 +162,12 @@ pub const MAX_EXP: i32 = f32::MAX_EXP;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let min = std::f32::MIN_10_EXP;
 ///
 /// // intended way
 /// let min = f32::MIN_10_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_10_EXP` associated constant on `f32`"
-)]
 pub const MIN_10_EXP: i32 = f32::MIN_10_EXP;
 
 /// Maximum possible power of 10 exponent.
@@ -216,17 +177,12 @@ pub const MIN_10_EXP: i32 = f32::MIN_10_EXP;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let max = std::f32::MAX_10_EXP;
 ///
 /// // intended way
 /// let max = f32::MAX_10_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MAX_10_EXP` associated constant on `f32`"
-)]
 pub const MAX_10_EXP: i32 = f32::MAX_10_EXP;
 
 /// Not a Number (NaN).
@@ -236,14 +192,12 @@ pub const MAX_10_EXP: i32 = f32::MAX_10_EXP;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let nan = std::f32::NAN;
 ///
 /// // intended way
 /// let nan = f32::NAN;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `NAN` associated constant on `f32`")]
 pub const NAN: f32 = f32::NAN;
 
 /// Infinity (∞).
@@ -253,17 +207,12 @@ pub const NAN: f32 = f32::NAN;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let inf = std::f32::INFINITY;
 ///
 /// // intended way
 /// let inf = f32::INFINITY;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `INFINITY` associated constant on `f32`"
-)]
 pub const INFINITY: f32 = f32::INFINITY;
 
 /// Negative infinity (−∞).
@@ -273,17 +222,12 @@ pub const INFINITY: f32 = f32::INFINITY;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let ninf = std::f32::NEG_INFINITY;
 ///
 /// // intended way
 /// let ninf = f32::NEG_INFINITY;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `NEG_INFINITY` associated constant on `f32`"
-)]
 pub const NEG_INFINITY: f32 = f32::NEG_INFINITY;
 
 /// Basic mathematical constants.
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 7af968f7fe84b..3323b7d6774df 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -1,13 +1,12 @@
-//! Constants specific to the `f64` double-precision floating point type.
+//! This module provides constants which are specific to the implementation
+//! of the `f64` floating point data type.
 //!
 //! *[See also the `f64` primitive type](../../std/primitive.f64.html).*
 //!
 //! Mathematically significant numbers are provided in the `consts` sub-module.
 //!
-//! For the constants defined directly in this module
-//! (as distinct from those defined in the `consts` sub-module),
-//! new code should instead use the associated constants
-//! defined directly on the `f64` type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -24,14 +23,12 @@ use crate::num::FpCategory;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let r = std::f64::RADIX;
 ///
 /// // intended way
 /// let r = f64::RADIX;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `RADIX` associated constant on `f64`")]
 pub const RADIX: u32 = f64::RADIX;
 
 /// Number of significant digits in base 2.
@@ -41,17 +38,12 @@ pub const RADIX: u32 = f64::RADIX;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let d = std::f64::MANTISSA_DIGITS;
 ///
 /// // intended way
 /// let d = f64::MANTISSA_DIGITS;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MANTISSA_DIGITS` associated constant on `f64`"
-)]
 pub const MANTISSA_DIGITS: u32 = f64::MANTISSA_DIGITS;
 
 /// Approximate number of significant digits in base 10.
@@ -61,14 +53,12 @@ pub const MANTISSA_DIGITS: u32 = f64::MANTISSA_DIGITS;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let d = std::f64::DIGITS;
 ///
 /// // intended way
 /// let d = f64::DIGITS;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `DIGITS` associated constant on `f64`")]
 pub const DIGITS: u32 = f64::DIGITS;
 
 /// [Machine epsilon] value for `f64`.
@@ -82,17 +72,12 @@ pub const DIGITS: u32 = f64::DIGITS;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let e = std::f64::EPSILON;
 ///
 /// // intended way
 /// let e = f64::EPSILON;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `EPSILON` associated constant on `f64`"
-)]
 pub const EPSILON: f64 = f64::EPSILON;
 
 /// Smallest finite `f64` value.
@@ -102,14 +87,12 @@ pub const EPSILON: f64 = f64::EPSILON;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let min = std::f64::MIN;
 ///
 /// // intended way
 /// let min = f64::MIN;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on `f64`")]
 pub const MIN: f64 = f64::MIN;
 
 /// Smallest positive normal `f64` value.
@@ -119,17 +102,12 @@ pub const MIN: f64 = f64::MIN;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let min = std::f64::MIN_POSITIVE;
 ///
 /// // intended way
 /// let min = f64::MIN_POSITIVE;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_POSITIVE` associated constant on `f64`"
-)]
 pub const MIN_POSITIVE: f64 = f64::MIN_POSITIVE;
 
 /// Largest finite `f64` value.
@@ -139,14 +117,12 @@ pub const MIN_POSITIVE: f64 = f64::MIN_POSITIVE;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let max = std::f64::MAX;
 ///
 /// // intended way
 /// let max = f64::MAX;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on `f64`")]
 pub const MAX: f64 = f64::MAX;
 
 /// One greater than the minimum possible normal power of 2 exponent.
@@ -156,17 +132,12 @@ pub const MAX: f64 = f64::MAX;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let min = std::f64::MIN_EXP;
 ///
 /// // intended way
 /// let min = f64::MIN_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_EXP` associated constant on `f64`"
-)]
 pub const MIN_EXP: i32 = f64::MIN_EXP;
 
 /// Maximum possible power of 2 exponent.
@@ -176,17 +147,12 @@ pub const MIN_EXP: i32 = f64::MIN_EXP;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let max = std::f64::MAX_EXP;
 ///
 /// // intended way
 /// let max = f64::MAX_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MAX_EXP` associated constant on `f64`"
-)]
 pub const MAX_EXP: i32 = f64::MAX_EXP;
 
 /// Minimum possible normal power of 10 exponent.
@@ -196,17 +162,12 @@ pub const MAX_EXP: i32 = f64::MAX_EXP;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let min = std::f64::MIN_10_EXP;
 ///
 /// // intended way
 /// let min = f64::MIN_10_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_10_EXP` associated constant on `f64`"
-)]
 pub const MIN_10_EXP: i32 = f64::MIN_10_EXP;
 
 /// Maximum possible power of 10 exponent.
@@ -216,17 +177,12 @@ pub const MIN_10_EXP: i32 = f64::MIN_10_EXP;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let max = std::f64::MAX_10_EXP;
 ///
 /// // intended way
 /// let max = f64::MAX_10_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MAX_10_EXP` associated constant on `f64`"
-)]
 pub const MAX_10_EXP: i32 = f64::MAX_10_EXP;
 
 /// Not a Number (NaN).
@@ -236,14 +192,12 @@ pub const MAX_10_EXP: i32 = f64::MAX_10_EXP;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let nan = std::f64::NAN;
 ///
 /// // intended way
 /// let nan = f64::NAN;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `NAN` associated constant on `f64`")]
 pub const NAN: f64 = f64::NAN;
 
 /// Infinity (∞).
@@ -253,17 +207,12 @@ pub const NAN: f64 = f64::NAN;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let inf = std::f64::INFINITY;
 ///
 /// // intended way
 /// let inf = f64::INFINITY;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `INFINITY` associated constant on `f64`"
-)]
 pub const INFINITY: f64 = f64::INFINITY;
 
 /// Negative infinity (−∞).
@@ -273,17 +222,12 @@ pub const INFINITY: f64 = f64::INFINITY;
 ///
 /// ```rust
 /// // deprecated way
-/// # #[allow(deprecated, deprecated_in_future)]
 /// let ninf = std::f64::NEG_INFINITY;
 ///
 /// // intended way
 /// let ninf = f64::NEG_INFINITY;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `NEG_INFINITY` associated constant on `f64`"
-)]
 pub const NEG_INFINITY: f64 = f64::NEG_INFINITY;
 
 /// Basic mathematical constants.
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index f732f11d909e7..162ed7d1b8dfe 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1975,28 +1975,32 @@ macro_rules! int_impl {
             unsafe { mem::transmute(bytes) }
         }
 
-        /// New code should prefer to use
-        #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN).")]
+        /// **This method is soft-deprecated.**
+        ///
+        /// Although using it won’t cause a compilation warning, new code should use
+        #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN)")]
+        /// instead.
         ///
         /// Returns the smallest value that can be represented by this integer type.
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline(always)]
         #[rustc_promotable]
         #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")]
         pub const fn min_value() -> Self {
             Self::MIN
         }
 
-        /// New code should prefer to use
-        #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX).")]
+        /// **This method is soft-deprecated.**
+        ///
+        /// Although using it won’t cause a compilation warning, new code should use
+        #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX)")]
+        /// instead.
         ///
         /// Returns the largest value that can be represented by this integer type.
         #[stable(feature = "rust1", since = "1.0.0")]
         #[inline(always)]
         #[rustc_promotable]
         #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")]
         pub const fn max_value() -> Self {
             Self::MAX
         }
diff --git a/library/core/src/num/shells/i128.rs b/library/core/src/num/shells/i128.rs
index 785e9a4e9cfb7..08cb795946868 100644
--- a/library/core/src/num/shells/i128.rs
+++ b/library/core/src/num/shells/i128.rs
@@ -1,13 +1,10 @@
-//! Constants for the 128-bit signed integer type.
+//! The 128-bit signed integer type.
 //!
 //! *[See also the `i128` primitive type](../../std/primitive.i128.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "i128", since = "1.26.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `i128`"
-)]
 
 int_module! { i128, #[stable(feature = "i128", since="1.26.0")] }
diff --git a/library/core/src/num/shells/i16.rs b/library/core/src/num/shells/i16.rs
index 48ea2e3e964c2..288eaceba59d6 100644
--- a/library/core/src/num/shells/i16.rs
+++ b/library/core/src/num/shells/i16.rs
@@ -1,13 +1,10 @@
-//! Constants for the 16-bit signed integer type.
+//! The 16-bit signed integer type.
 //!
 //! *[See also the `i16` primitive type](../../std/primitive.i16.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `i16`"
-)]
 
 int_module! { i16 }
diff --git a/library/core/src/num/shells/i32.rs b/library/core/src/num/shells/i32.rs
index fce6980f45679..0e1a2ec56ccb2 100644
--- a/library/core/src/num/shells/i32.rs
+++ b/library/core/src/num/shells/i32.rs
@@ -1,13 +1,10 @@
-//! Constants for the 32-bit signed integer type.
+//! The 32-bit signed integer type.
 //!
 //! *[See also the `i32` primitive type](../../std/primitive.i32.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `i32`"
-)]
 
 int_module! { i32 }
diff --git a/library/core/src/num/shells/i64.rs b/library/core/src/num/shells/i64.rs
index 6aa8fcf452bde..27f7092710b34 100644
--- a/library/core/src/num/shells/i64.rs
+++ b/library/core/src/num/shells/i64.rs
@@ -1,13 +1,10 @@
-//! Constants for the 64-bit signed integer type.
+//! The 64-bit signed integer type.
 //!
 //! *[See also the `i64` primitive type](../../std/primitive.i64.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `i64`"
-)]
 
 int_module! { i64 }
diff --git a/library/core/src/num/shells/i8.rs b/library/core/src/num/shells/i8.rs
index b4e0fef61bb28..e84b421e1a444 100644
--- a/library/core/src/num/shells/i8.rs
+++ b/library/core/src/num/shells/i8.rs
@@ -1,13 +1,10 @@
-//! Constants for the 8-bit signed integer type.
+//! The 8-bit signed integer type.
 //!
 //! *[See also the `i8` primitive type](../../std/primitive.i8.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `i8`"
-)]
 
 int_module! { i8 }
diff --git a/library/core/src/num/shells/int_macros.rs b/library/core/src/num/shells/int_macros.rs
index 78513d44b7580..5f8bb648d04ae 100644
--- a/library/core/src/num/shells/int_macros.rs
+++ b/library/core/src/num/shells/int_macros.rs
@@ -20,7 +20,6 @@ macro_rules! int_module {
         /// ```
         ///
         #[$attr]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")]
         pub const MIN: $T = $T::MIN;
 
         #[doc = concat!(
@@ -40,7 +39,6 @@ macro_rules! int_module {
         /// ```
         ///
         #[$attr]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")]
         pub const MAX: $T = $T::MAX;
     )
 }
diff --git a/library/core/src/num/shells/isize.rs b/library/core/src/num/shells/isize.rs
index 5dc128d58ae02..0dcfa4a2bd134 100644
--- a/library/core/src/num/shells/isize.rs
+++ b/library/core/src/num/shells/isize.rs
@@ -1,13 +1,10 @@
-//! Constants for the pointer-sized signed integer type.
+//! The pointer-sized signed integer type.
 //!
 //! *[See also the `isize` primitive type](../../std/primitive.isize.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `isize`"
-)]
 
 int_module! { isize }
diff --git a/library/core/src/num/shells/u128.rs b/library/core/src/num/shells/u128.rs
index 6012584ae86ae..dd45ff141539f 100644
--- a/library/core/src/num/shells/u128.rs
+++ b/library/core/src/num/shells/u128.rs
@@ -1,13 +1,9 @@
-//! Constants for the 128-bit unsigned integer type.
+//! The 128-bit unsigned integer type.
 //!
 //! *[See also the `u128` primitive type](../../std/primitive.u128.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "i128", since = "1.26.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `u128`"
-)]
-
 int_module! { u128, #[stable(feature = "i128", since="1.26.0")] }
diff --git a/library/core/src/num/shells/u16.rs b/library/core/src/num/shells/u16.rs
index 36641196403bc..738071643b639 100644
--- a/library/core/src/num/shells/u16.rs
+++ b/library/core/src/num/shells/u16.rs
@@ -1,13 +1,10 @@
-//! Constants for the 16-bit unsigned integer type.
+//! The 16-bit unsigned integer type.
 //!
 //! *[See also the `u16` primitive type](../../std/primitive.u16.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `u16`"
-)]
 
 int_module! { u16 }
diff --git a/library/core/src/num/shells/u32.rs b/library/core/src/num/shells/u32.rs
index f58f71423dbc3..9800c9099748f 100644
--- a/library/core/src/num/shells/u32.rs
+++ b/library/core/src/num/shells/u32.rs
@@ -1,13 +1,10 @@
-//! Constants for the 32-bit unsigned integer type.
+//! The 32-bit unsigned integer type.
 //!
 //! *[See also the `u32` primitive type](../../std/primitive.u32.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `u32`"
-)]
 
 int_module! { u32 }
diff --git a/library/core/src/num/shells/u64.rs b/library/core/src/num/shells/u64.rs
index 2b221f66da60a..fb686c396f033 100644
--- a/library/core/src/num/shells/u64.rs
+++ b/library/core/src/num/shells/u64.rs
@@ -1,13 +1,10 @@
-//! Constants for the 64-bit unsigned integer type.
+//! The 64-bit unsigned integer type.
 //!
 //! *[See also the `u64` primitive type](../../std/primitive.u64.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `u64`"
-)]
 
 int_module! { u64 }
diff --git a/library/core/src/num/shells/u8.rs b/library/core/src/num/shells/u8.rs
index 83ec60dcbd852..c03cbdda25dbb 100644
--- a/library/core/src/num/shells/u8.rs
+++ b/library/core/src/num/shells/u8.rs
@@ -1,13 +1,10 @@
-//! Constants for the 8-bit unsigned integer type.
+//! The 8-bit unsigned integer type.
 //!
 //! *[See also the `u8` primitive type](../../std/primitive.u8.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `u8`"
-)]
 
 int_module! { u8 }
diff --git a/library/core/src/num/shells/usize.rs b/library/core/src/num/shells/usize.rs
index c38d521f3dae0..a893041615244 100644
--- a/library/core/src/num/shells/usize.rs
+++ b/library/core/src/num/shells/usize.rs
@@ -1,13 +1,10 @@
-//! Constants for the pointer-sized unsigned integer type.
+//! The pointer-sized unsigned integer type.
 //!
 //! *[See also the `usize` primitive type](../../std/primitive.usize.html).*
 //!
-//! New code should use the associated constants directly on the primitive type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
-    since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `usize`"
-)]
 
 int_module! { usize }
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 9fccf3f72ce1a..8f141a3ff9e97 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1805,8 +1805,10 @@ macro_rules! uint_impl {
             unsafe { mem::transmute(bytes) }
         }
 
-        /// New code should prefer to use
-        #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN).")]
+        /// **This method is soft-deprecated.**
+        ///
+        /// Although using it won’t cause compilation warning, new code should use
+        #[doc = concat!("[`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN)")]
         /// instead.
         ///
         /// Returns the smallest value that can be represented by this integer type.
@@ -1814,11 +1816,12 @@ macro_rules! uint_impl {
         #[rustc_promotable]
         #[inline(always)]
         #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")]
         pub const fn min_value() -> Self { Self::MIN }
 
-        /// New code should prefer to use
-        #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX).")]
+        /// **This method is soft-deprecated.**
+        ///
+        /// Although using it won’t cause compilation warning, new code should use
+        #[doc = concat!("[`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX)")]
         /// instead.
         ///
         /// Returns the largest value that can be represented by this integer type.
@@ -1826,7 +1829,6 @@ macro_rules! uint_impl {
         #[rustc_promotable]
         #[inline(always)]
         #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")]
         pub const fn max_value() -> Self { Self::MAX }
     }
 }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index e45fefc7ed765..d849008b88030 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -19,19 +19,12 @@ use crate::slice::{self, SliceIndex};
 /// as a discriminant -- `Option<NonNull<T>>` has the same size as `*mut T`.
 /// However the pointer may still dangle if it isn't dereferenced.
 ///
-/// Unlike `*mut T`, `NonNull<T>` was chosen to be covariant over `T`. This makes it
-/// possible to use `NonNull<T>` when building covariant types, but introduces the
-/// risk of unsoundness if used in a type that shouldn't actually be covariant.
-/// (The opposite choice was made for `*mut T` even though technically the unsoundness
-/// could only be caused by calling unsafe functions.)
-///
-/// Covariance is correct for most safe abstractions, such as `Box`, `Rc`, `Arc`, `Vec`,
-/// and `LinkedList`. This is the case because they provide a public API that follows the
-/// normal shared XOR mutable rules of Rust.
-///
-/// If your type cannot safely be covariant, you must ensure it contains some
-/// additional field to provide invariance. Often this field will be a [`PhantomData`]
-/// type like `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`.
+/// Unlike `*mut T`, `NonNull<T>` is covariant over `T`. If this is incorrect
+/// for your use case, you should include some [`PhantomData`] in your type to
+/// provide invariance, such as `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`.
+/// Usually this won't be necessary; covariance is correct for most safe abstractions,
+/// such as `Box`, `Rc`, `Arc`, `Vec`, and `LinkedList`. This is the case because they
+/// provide a public API that follows the normal shared XOR mutable rules of Rust.
 ///
 /// Notice that `NonNull<T>` has a `From` instance for `&T`. However, this does
 /// not change the fact that mutating through a (pointer derived from a) shared
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index b06b6e93373f3..de8d7fc29dc05 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -542,9 +542,10 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn swap(&mut self, a: usize, b: usize) {
-        // Can't take two mutable loans from one vector, so instead use raw pointers.
-        let pa = ptr::raw_mut!(self[a]);
-        let pb = ptr::raw_mut!(self[b]);
+        // Can't take two mutable loans from one vector, so instead just cast
+        // them to their raw pointers to do the swap.
+        let pa: *mut T = &mut self[a];
+        let pb: *mut T = &mut self[b];
         // SAFETY: `pa` and `pb` have been created from safe mutable references and refer
         // to elements in the slice and therefore are guaranteed to be valid and aligned.
         // Note that accessing the elements behind `a` and `b` is checked and will
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index b1443bc33d2ff..88b4e2a2436e7 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -1067,23 +1067,13 @@ impl fmt::Debug for Duration {
         }
 
         if self.secs > 0 {
-            fmt_decimal(f, self.secs, self.nanos, NANOS_PER_SEC / 10)?;
+            fmt_decimal(f, self.secs, self.nanos, 100_000_000)?;
             f.write_str("s")
-        } else if self.nanos >= NANOS_PER_MILLI {
-            fmt_decimal(
-                f,
-                (self.nanos / NANOS_PER_MILLI) as u64,
-                self.nanos % NANOS_PER_MILLI,
-                NANOS_PER_MILLI / 10,
-            )?;
+        } else if self.nanos >= 1_000_000 {
+            fmt_decimal(f, self.nanos as u64 / 1_000_000, self.nanos % 1_000_000, 100_000)?;
             f.write_str("ms")
-        } else if self.nanos >= NANOS_PER_MICRO {
-            fmt_decimal(
-                f,
-                (self.nanos / NANOS_PER_MICRO) as u64,
-                self.nanos % NANOS_PER_MICRO,
-                NANOS_PER_MICRO / 10,
-            )?;
+        } else if self.nanos >= 1_000 {
+            fmt_decimal(f, self.nanos as u64 / 1_000, self.nanos % 1_000, 100)?;
             f.write_str("µs")
         } else {
             fmt_decimal(f, self.nanos as u64, 0, 1)?;
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
new file mode 100644
index 0000000000000..bc5421bfb5f8f
--- /dev/null
+++ b/library/core/tests/iter.rs
@@ -0,0 +1,3640 @@
+// ignore-tidy-filelength
+
+use core::cell::Cell;
+use core::convert::TryFrom;
+use core::iter::TrustedRandomAccess;
+use core::iter::*;
+
+/// An iterator wrapper that panics whenever `next` or `next_back` is called
+/// after `None` has been returned.
+struct Unfuse<I> {
+    iter: I,
+    exhausted: bool,
+}
+
+fn unfuse<I: IntoIterator>(iter: I) -> Unfuse<I::IntoIter> {
+    Unfuse { iter: iter.into_iter(), exhausted: false }
+}
+
+impl<I> Iterator for Unfuse<I>
+where
+    I: Iterator,
+{
+    type Item = I::Item;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        assert!(!self.exhausted);
+        let next = self.iter.next();
+        self.exhausted = next.is_none();
+        next
+    }
+}
+
+impl<I> DoubleEndedIterator for Unfuse<I>
+where
+    I: DoubleEndedIterator,
+{
+    fn next_back(&mut self) -> Option<Self::Item> {
+        assert!(!self.exhausted);
+        let next = self.iter.next_back();
+        self.exhausted = next.is_none();
+        next
+    }
+}
+
+#[test]
+fn test_lt() {
+    let empty: [isize; 0] = [];
+    let xs = [1, 2, 3];
+    let ys = [1, 2, 0];
+
+    assert!(!xs.iter().lt(ys.iter()));
+    assert!(!xs.iter().le(ys.iter()));
+    assert!(xs.iter().gt(ys.iter()));
+    assert!(xs.iter().ge(ys.iter()));
+
+    assert!(ys.iter().lt(xs.iter()));
+    assert!(ys.iter().le(xs.iter()));
+    assert!(!ys.iter().gt(xs.iter()));
+    assert!(!ys.iter().ge(xs.iter()));
+
+    assert!(empty.iter().lt(xs.iter()));
+    assert!(empty.iter().le(xs.iter()));
+    assert!(!empty.iter().gt(xs.iter()));
+    assert!(!empty.iter().ge(xs.iter()));
+
+    // Sequence with NaN
+    let u = [1.0f64, 2.0];
+    let v = [0.0f64 / 0.0, 3.0];
+
+    assert!(!u.iter().lt(v.iter()));
+    assert!(!u.iter().le(v.iter()));
+    assert!(!u.iter().gt(v.iter()));
+    assert!(!u.iter().ge(v.iter()));
+
+    let a = [0.0f64 / 0.0];
+    let b = [1.0f64];
+    let c = [2.0f64];
+
+    assert!(a.iter().lt(b.iter()) == (a[0] < b[0]));
+    assert!(a.iter().le(b.iter()) == (a[0] <= b[0]));
+    assert!(a.iter().gt(b.iter()) == (a[0] > b[0]));
+    assert!(a.iter().ge(b.iter()) == (a[0] >= b[0]));
+
+    assert!(c.iter().lt(b.iter()) == (c[0] < b[0]));
+    assert!(c.iter().le(b.iter()) == (c[0] <= b[0]));
+    assert!(c.iter().gt(b.iter()) == (c[0] > b[0]));
+    assert!(c.iter().ge(b.iter()) == (c[0] >= b[0]));
+}
+
+#[test]
+fn test_multi_iter() {
+    let xs = [1, 2, 3, 4];
+    let ys = [4, 3, 2, 1];
+    assert!(xs.iter().eq(ys.iter().rev()));
+    assert!(xs.iter().lt(xs.iter().skip(2)));
+}
+
+#[test]
+fn test_cmp_by() {
+    use core::cmp::Ordering;
+
+    let f = |x: i32, y: i32| (x * x).cmp(&y);
+    let xs = || [1, 2, 3, 4].iter().copied();
+    let ys = || [1, 4, 16].iter().copied();
+
+    assert_eq!(xs().cmp_by(ys(), f), Ordering::Less);
+    assert_eq!(ys().cmp_by(xs(), f), Ordering::Greater);
+    assert_eq!(xs().cmp_by(xs().map(|x| x * x), f), Ordering::Equal);
+    assert_eq!(xs().rev().cmp_by(ys().rev(), f), Ordering::Greater);
+    assert_eq!(xs().cmp_by(ys().rev(), f), Ordering::Less);
+    assert_eq!(xs().cmp_by(ys().take(2), f), Ordering::Greater);
+}
+
+#[test]
+fn test_partial_cmp_by() {
+    use core::cmp::Ordering;
+
+    let f = |x: i32, y: i32| (x * x).partial_cmp(&y);
+    let xs = || [1, 2, 3, 4].iter().copied();
+    let ys = || [1, 4, 16].iter().copied();
+
+    assert_eq!(xs().partial_cmp_by(ys(), f), Some(Ordering::Less));
+    assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
+    assert_eq!(xs().partial_cmp_by(xs().map(|x| x * x), f), Some(Ordering::Equal));
+    assert_eq!(xs().rev().partial_cmp_by(ys().rev(), f), Some(Ordering::Greater));
+    assert_eq!(xs().partial_cmp_by(xs().rev(), f), Some(Ordering::Less));
+    assert_eq!(xs().partial_cmp_by(ys().take(2), f), Some(Ordering::Greater));
+
+    let f = |x: f64, y: f64| (x * x).partial_cmp(&y);
+    let xs = || [1.0, 2.0, 3.0, 4.0].iter().copied();
+    let ys = || [1.0, 4.0, f64::NAN, 16.0].iter().copied();
+
+    assert_eq!(xs().partial_cmp_by(ys(), f), None);
+    assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
+}
+
+#[test]
+fn test_eq_by() {
+    let f = |x: i32, y: i32| x * x == y;
+    let xs = || [1, 2, 3, 4].iter().copied();
+    let ys = || [1, 4, 9, 16].iter().copied();
+
+    assert!(xs().eq_by(ys(), f));
+    assert!(!ys().eq_by(xs(), f));
+    assert!(!xs().eq_by(xs(), f));
+    assert!(!ys().eq_by(ys(), f));
+
+    assert!(!xs().take(3).eq_by(ys(), f));
+    assert!(!xs().eq_by(ys().take(3), f));
+    assert!(xs().take(3).eq_by(ys().take(3), f));
+}
+
+#[test]
+fn test_counter_from_iter() {
+    let it = (0..).step_by(5).take(10);
+    let xs: Vec<isize> = FromIterator::from_iter(it);
+    assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
+}
+
+#[test]
+fn test_iterator_chain() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let ys = [30, 40, 50, 60];
+    let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
+    let it = xs.iter().chain(&ys);
+    let mut i = 0;
+    for &x in it {
+        assert_eq!(x, expected[i]);
+        i += 1;
+    }
+    assert_eq!(i, expected.len());
+
+    let ys = (30..).step_by(10).take(4);
+    let it = xs.iter().cloned().chain(ys);
+    let mut i = 0;
+    for x in it {
+        assert_eq!(x, expected[i]);
+        i += 1;
+    }
+    assert_eq!(i, expected.len());
+}
+
+#[test]
+fn test_iterator_chain_advance_by() {
+    fn test_chain(xs: &[i32], ys: &[i32]) {
+        let len = xs.len() + ys.len();
+
+        for i in 0..xs.len() {
+            let mut iter = unfuse(xs).chain(unfuse(ys));
+            iter.advance_by(i).unwrap();
+            assert_eq!(iter.next(), Some(&xs[i]));
+            assert_eq!(iter.advance_by(100), Err(len - i - 1));
+        }
+
+        for i in 0..ys.len() {
+            let mut iter = unfuse(xs).chain(unfuse(ys));
+            iter.advance_by(xs.len() + i).unwrap();
+            assert_eq!(iter.next(), Some(&ys[i]));
+            assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1));
+        }
+
+        let mut iter = xs.iter().chain(ys);
+        iter.advance_by(len).unwrap();
+        assert_eq!(iter.next(), None);
+
+        let mut iter = xs.iter().chain(ys);
+        assert_eq!(iter.advance_by(len + 1), Err(len));
+    }
+
+    test_chain(&[], &[]);
+    test_chain(&[], &[0, 1, 2, 3, 4, 5]);
+    test_chain(&[0, 1, 2, 3, 4, 5], &[]);
+    test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]);
+}
+
+#[test]
+fn test_iterator_chain_advance_back_by() {
+    fn test_chain(xs: &[i32], ys: &[i32]) {
+        let len = xs.len() + ys.len();
+
+        for i in 0..ys.len() {
+            let mut iter = unfuse(xs).chain(unfuse(ys));
+            iter.advance_back_by(i).unwrap();
+            assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
+            assert_eq!(iter.advance_back_by(100), Err(len - i - 1));
+        }
+
+        for i in 0..xs.len() {
+            let mut iter = unfuse(xs).chain(unfuse(ys));
+            iter.advance_back_by(ys.len() + i).unwrap();
+            assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
+            assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1));
+        }
+
+        let mut iter = xs.iter().chain(ys);
+        iter.advance_back_by(len).unwrap();
+        assert_eq!(iter.next_back(), None);
+
+        let mut iter = xs.iter().chain(ys);
+        assert_eq!(iter.advance_back_by(len + 1), Err(len));
+    }
+
+    test_chain(&[], &[]);
+    test_chain(&[], &[0, 1, 2, 3, 4, 5]);
+    test_chain(&[0, 1, 2, 3, 4, 5], &[]);
+    test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]);
+}
+
+#[test]
+fn test_iterator_chain_nth() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let ys = [30, 40, 50, 60];
+    let zs = [];
+    let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
+    for (i, x) in expected.iter().enumerate() {
+        assert_eq!(Some(x), xs.iter().chain(&ys).nth(i));
+    }
+    assert_eq!(zs.iter().chain(&xs).nth(0), Some(&0));
+
+    let mut it = xs.iter().chain(&zs);
+    assert_eq!(it.nth(5), Some(&5));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_iterator_chain_nth_back() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let ys = [30, 40, 50, 60];
+    let zs = [];
+    let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
+    for (i, x) in expected.iter().rev().enumerate() {
+        assert_eq!(Some(x), xs.iter().chain(&ys).nth_back(i));
+    }
+    assert_eq!(zs.iter().chain(&xs).nth_back(0), Some(&5));
+
+    let mut it = xs.iter().chain(&zs);
+    assert_eq!(it.nth_back(5), Some(&0));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_iterator_chain_last() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let ys = [30, 40, 50, 60];
+    let zs = [];
+    assert_eq!(xs.iter().chain(&ys).last(), Some(&60));
+    assert_eq!(zs.iter().chain(&ys).last(), Some(&60));
+    assert_eq!(ys.iter().chain(&zs).last(), Some(&60));
+    assert_eq!(zs.iter().chain(&zs).last(), None);
+}
+
+#[test]
+fn test_iterator_chain_count() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let ys = [30, 40, 50, 60];
+    let zs = [];
+    assert_eq!(xs.iter().chain(&ys).count(), 10);
+    assert_eq!(zs.iter().chain(&ys).count(), 4);
+}
+
+#[test]
+fn test_iterator_chain_find() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let ys = [30, 40, 50, 60];
+    let mut iter = xs.iter().chain(&ys);
+    assert_eq!(iter.find(|&&i| i == 4), Some(&4));
+    assert_eq!(iter.next(), Some(&5));
+    assert_eq!(iter.find(|&&i| i == 40), Some(&40));
+    assert_eq!(iter.next(), Some(&50));
+    assert_eq!(iter.find(|&&i| i == 100), None);
+    assert_eq!(iter.next(), None);
+}
+
+struct Toggle {
+    is_empty: bool,
+}
+
+impl Iterator for Toggle {
+    type Item = ();
+
+    // alternates between `None` and `Some(())`
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.is_empty {
+            self.is_empty = false;
+            None
+        } else {
+            self.is_empty = true;
+            Some(())
+        }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.is_empty { (0, Some(0)) } else { (1, Some(1)) }
+    }
+}
+
+impl DoubleEndedIterator for Toggle {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.next()
+    }
+}
+
+#[test]
+fn test_iterator_chain_size_hint() {
+    // this chains an iterator of length 0 with an iterator of length 1,
+    // so after calling `.next()` once, the iterator is empty and the
+    // state is `ChainState::Back`. `.size_hint()` should now disregard
+    // the size hint of the left iterator
+    let mut iter = Toggle { is_empty: true }.chain(once(()));
+    assert_eq!(iter.next(), Some(()));
+    assert_eq!(iter.size_hint(), (0, Some(0)));
+
+    let mut iter = once(()).chain(Toggle { is_empty: true });
+    assert_eq!(iter.next_back(), Some(()));
+    assert_eq!(iter.size_hint(), (0, Some(0)));
+}
+
+#[test]
+fn test_iterator_chain_unfused() {
+    // Chain shouldn't be fused in its second iterator, depending on direction
+    let mut iter = NonFused::new(empty()).chain(Toggle { is_empty: true });
+    iter.next().unwrap_none();
+    iter.next().unwrap();
+    iter.next().unwrap_none();
+
+    let mut iter = Toggle { is_empty: true }.chain(NonFused::new(empty()));
+    iter.next_back().unwrap_none();
+    iter.next_back().unwrap();
+    iter.next_back().unwrap_none();
+}
+
+#[test]
+fn test_zip_nth() {
+    let xs = [0, 1, 2, 4, 5];
+    let ys = [10, 11, 12];
+
+    let mut it = xs.iter().zip(&ys);
+    assert_eq!(it.nth(0), Some((&0, &10)));
+    assert_eq!(it.nth(1), Some((&2, &12)));
+    assert_eq!(it.nth(0), None);
+
+    let mut it = xs.iter().zip(&ys);
+    assert_eq!(it.nth(3), None);
+
+    let mut it = ys.iter().zip(&xs);
+    assert_eq!(it.nth(3), None);
+}
+
+#[test]
+fn test_zip_nth_side_effects() {
+    let mut a = Vec::new();
+    let mut b = Vec::new();
+    let value = [1, 2, 3, 4, 5, 6]
+        .iter()
+        .cloned()
+        .map(|n| {
+            a.push(n);
+            n * 10
+        })
+        .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
+            b.push(n * 100);
+            n * 1000
+        }))
+        .skip(1)
+        .nth(3);
+    assert_eq!(value, Some((50, 6000)));
+    assert_eq!(a, vec![1, 2, 3, 4, 5]);
+    assert_eq!(b, vec![200, 300, 400, 500, 600]);
+}
+
+#[test]
+fn test_zip_next_back_side_effects() {
+    let mut a = Vec::new();
+    let mut b = Vec::new();
+    let mut iter = [1, 2, 3, 4, 5, 6]
+        .iter()
+        .cloned()
+        .map(|n| {
+            a.push(n);
+            n * 10
+        })
+        .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
+            b.push(n * 100);
+            n * 1000
+        }));
+
+    // The second iterator is one item longer, so `next_back` is called on it
+    // one more time.
+    assert_eq!(iter.next_back(), Some((60, 7000)));
+    assert_eq!(iter.next_back(), Some((50, 6000)));
+    assert_eq!(iter.next_back(), Some((40, 5000)));
+    assert_eq!(iter.next_back(), Some((30, 4000)));
+    assert_eq!(a, vec![6, 5, 4, 3]);
+    assert_eq!(b, vec![800, 700, 600, 500, 400]);
+}
+
+#[test]
+fn test_zip_nth_back_side_effects() {
+    let mut a = Vec::new();
+    let mut b = Vec::new();
+    let value = [1, 2, 3, 4, 5, 6]
+        .iter()
+        .cloned()
+        .map(|n| {
+            a.push(n);
+            n * 10
+        })
+        .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
+            b.push(n * 100);
+            n * 1000
+        }))
+        .nth_back(3);
+    assert_eq!(value, Some((30, 4000)));
+    assert_eq!(a, vec![6, 5, 4, 3]);
+    assert_eq!(b, vec![800, 700, 600, 500, 400]);
+}
+
+#[test]
+fn test_zip_next_back_side_effects_exhausted() {
+    let mut a = Vec::new();
+    let mut b = Vec::new();
+    let mut iter = [1, 2, 3, 4, 5, 6]
+        .iter()
+        .cloned()
+        .map(|n| {
+            a.push(n);
+            n * 10
+        })
+        .zip([2, 3, 4].iter().cloned().map(|n| {
+            b.push(n * 100);
+            n * 1000
+        }));
+
+    iter.next();
+    iter.next();
+    iter.next();
+    iter.next();
+    assert_eq!(iter.next_back(), None);
+    assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
+    assert_eq!(b, vec![200, 300, 400]);
+}
+
+#[derive(Debug)]
+struct CountClone(Cell<i32>);
+
+fn count_clone() -> CountClone {
+    CountClone(Cell::new(0))
+}
+
+impl PartialEq<i32> for CountClone {
+    fn eq(&self, rhs: &i32) -> bool {
+        self.0.get() == *rhs
+    }
+}
+
+impl Clone for CountClone {
+    fn clone(&self) -> Self {
+        let ret = CountClone(self.0.clone());
+        let n = self.0.get();
+        self.0.set(n + 1);
+        ret
+    }
+}
+
+#[test]
+fn test_zip_cloned_sideffectful() {
+    let xs = [count_clone(), count_clone(), count_clone(), count_clone()];
+    let ys = [count_clone(), count_clone()];
+
+    for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
+
+    assert_eq!(&xs, &[1, 1, 1, 0][..]);
+    assert_eq!(&ys, &[1, 1][..]);
+
+    let xs = [count_clone(), count_clone()];
+    let ys = [count_clone(), count_clone(), count_clone(), count_clone()];
+
+    for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
+
+    assert_eq!(&xs, &[1, 1][..]);
+    assert_eq!(&ys, &[1, 1, 0, 0][..]);
+}
+
+#[test]
+fn test_zip_map_sideffectful() {
+    let mut xs = [0; 6];
+    let mut ys = [0; 4];
+
+    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
+
+    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
+    assert_eq!(&ys, &[1, 1, 1, 1]);
+
+    let mut xs = [0; 4];
+    let mut ys = [0; 6];
+
+    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
+
+    assert_eq!(&xs, &[1, 1, 1, 1]);
+    assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]);
+}
+
+#[test]
+fn test_zip_map_rev_sideffectful() {
+    let mut xs = [0; 6];
+    let mut ys = [0; 4];
+
+    {
+        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
+        it.next_back();
+    }
+    assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]);
+    assert_eq!(&ys, &[0, 0, 0, 1]);
+
+    let mut xs = [0; 6];
+    let mut ys = [0; 4];
+
+    {
+        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
+        (&mut it).take(5).count();
+        it.next_back();
+    }
+    assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]);
+    assert_eq!(&ys, &[1, 1, 1, 1]);
+}
+
+#[test]
+fn test_zip_nested_sideffectful() {
+    let mut xs = [0; 6];
+    let ys = [0; 4];
+
+    {
+        // test that it has the side effect nested inside enumerate
+        let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys);
+        it.count();
+    }
+    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
+}
+
+#[test]
+fn test_zip_nth_back_side_effects_exhausted() {
+    let mut a = Vec::new();
+    let mut b = Vec::new();
+    let mut iter = [1, 2, 3, 4, 5, 6]
+        .iter()
+        .cloned()
+        .map(|n| {
+            a.push(n);
+            n * 10
+        })
+        .zip([2, 3, 4].iter().cloned().map(|n| {
+            b.push(n * 100);
+            n * 1000
+        }));
+
+    iter.next();
+    iter.next();
+    iter.next();
+    iter.next();
+    assert_eq!(iter.nth_back(0), None);
+    assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
+    assert_eq!(b, vec![200, 300, 400]);
+}
+
+#[test]
+fn test_zip_trusted_random_access_composition() {
+    let a = [0, 1, 2, 3, 4];
+    let b = a;
+    let c = a;
+
+    let a = a.iter().copied();
+    let b = b.iter().copied();
+    let mut c = c.iter().copied();
+    c.next();
+
+    let mut z1 = a.zip(b);
+    assert_eq!(z1.next().unwrap(), (0, 0));
+
+    let mut z2 = z1.zip(c);
+    fn assert_trusted_random_access<T: TrustedRandomAccess>(_a: &T) {}
+    assert_trusted_random_access(&z2);
+    assert_eq!(z2.next().unwrap(), ((1, 1), 1));
+}
+
+#[test]
+fn test_iterator_step_by() {
+    // Identity
+    let mut it = (0..).step_by(1).take(3);
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.next(), Some(1));
+    assert_eq!(it.next(), Some(2));
+    assert_eq!(it.next(), None);
+
+    let mut it = (0..).step_by(3).take(4);
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.next(), Some(3));
+    assert_eq!(it.next(), Some(6));
+    assert_eq!(it.next(), Some(9));
+    assert_eq!(it.next(), None);
+
+    let mut it = (0..3).step_by(1);
+    assert_eq!(it.next_back(), Some(2));
+    assert_eq!(it.next_back(), Some(1));
+    assert_eq!(it.next_back(), Some(0));
+    assert_eq!(it.next_back(), None);
+
+    let mut it = (0..11).step_by(3);
+    assert_eq!(it.next_back(), Some(9));
+    assert_eq!(it.next_back(), Some(6));
+    assert_eq!(it.next_back(), Some(3));
+    assert_eq!(it.next_back(), Some(0));
+    assert_eq!(it.next_back(), None);
+}
+
+#[test]
+fn test_iterator_step_by_nth() {
+    let mut it = (0..16).step_by(5);
+    assert_eq!(it.nth(0), Some(0));
+    assert_eq!(it.nth(0), Some(5));
+    assert_eq!(it.nth(0), Some(10));
+    assert_eq!(it.nth(0), Some(15));
+    assert_eq!(it.nth(0), None);
+
+    let it = (0..18).step_by(5);
+    assert_eq!(it.clone().nth(0), Some(0));
+    assert_eq!(it.clone().nth(1), Some(5));
+    assert_eq!(it.clone().nth(2), Some(10));
+    assert_eq!(it.clone().nth(3), Some(15));
+    assert_eq!(it.clone().nth(4), None);
+    assert_eq!(it.clone().nth(42), None);
+}
+
+#[test]
+fn test_iterator_step_by_nth_overflow() {
+    #[cfg(target_pointer_width = "8")]
+    type Bigger = u16;
+    #[cfg(target_pointer_width = "16")]
+    type Bigger = u32;
+    #[cfg(target_pointer_width = "32")]
+    type Bigger = u64;
+    #[cfg(target_pointer_width = "64")]
+    type Bigger = u128;
+
+    #[derive(Clone)]
+    struct Test(Bigger);
+    impl Iterator for &mut Test {
+        type Item = i32;
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(21)
+        }
+        fn nth(&mut self, n: usize) -> Option<Self::Item> {
+            self.0 += n as Bigger + 1;
+            Some(42)
+        }
+    }
+
+    let mut it = Test(0);
+    let root = usize::MAX >> (usize::BITS / 2);
+    let n = root + 20;
+    (&mut it).step_by(n).nth(n);
+    assert_eq!(it.0, n as Bigger * n as Bigger);
+
+    // large step
+    let mut it = Test(0);
+    (&mut it).step_by(usize::MAX).nth(5);
+    assert_eq!(it.0, (usize::MAX as Bigger) * 5);
+
+    // n + 1 overflows
+    let mut it = Test(0);
+    (&mut it).step_by(2).nth(usize::MAX);
+    assert_eq!(it.0, (usize::MAX as Bigger) * 2);
+
+    // n + 1 overflows
+    let mut it = Test(0);
+    (&mut it).step_by(1).nth(usize::MAX);
+    assert_eq!(it.0, (usize::MAX as Bigger) * 1);
+}
+
+#[test]
+fn test_iterator_step_by_nth_try_fold() {
+    let mut it = (0..).step_by(10);
+    assert_eq!(it.try_fold(0, i8::checked_add), None);
+    assert_eq!(it.next(), Some(60));
+    assert_eq!(it.try_fold(0, i8::checked_add), None);
+    assert_eq!(it.next(), Some(90));
+
+    let mut it = (100..).step_by(10);
+    assert_eq!(it.try_fold(50, i8::checked_add), None);
+    assert_eq!(it.next(), Some(110));
+
+    let mut it = (100..=100).step_by(10);
+    assert_eq!(it.next(), Some(100));
+    assert_eq!(it.try_fold(0, i8::checked_add), Some(0));
+}
+
+#[test]
+fn test_iterator_step_by_nth_back() {
+    let mut it = (0..16).step_by(5);
+    assert_eq!(it.nth_back(0), Some(15));
+    assert_eq!(it.nth_back(0), Some(10));
+    assert_eq!(it.nth_back(0), Some(5));
+    assert_eq!(it.nth_back(0), Some(0));
+    assert_eq!(it.nth_back(0), None);
+
+    let mut it = (0..16).step_by(5);
+    assert_eq!(it.next(), Some(0)); // to set `first_take` to `false`
+    assert_eq!(it.nth_back(0), Some(15));
+    assert_eq!(it.nth_back(0), Some(10));
+    assert_eq!(it.nth_back(0), Some(5));
+    assert_eq!(it.nth_back(0), None);
+
+    let it = || (0..18).step_by(5);
+    assert_eq!(it().nth_back(0), Some(15));
+    assert_eq!(it().nth_back(1), Some(10));
+    assert_eq!(it().nth_back(2), Some(5));
+    assert_eq!(it().nth_back(3), Some(0));
+    assert_eq!(it().nth_back(4), None);
+    assert_eq!(it().nth_back(42), None);
+}
+
+#[test]
+fn test_iterator_step_by_nth_try_rfold() {
+    let mut it = (0..100).step_by(10);
+    assert_eq!(it.try_rfold(0, i8::checked_add), None);
+    assert_eq!(it.next_back(), Some(70));
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.try_rfold(0, i8::checked_add), None);
+    assert_eq!(it.next_back(), Some(30));
+
+    let mut it = (0..100).step_by(10);
+    assert_eq!(it.try_rfold(50, i8::checked_add), None);
+    assert_eq!(it.next_back(), Some(80));
+
+    let mut it = (100..=100).step_by(10);
+    assert_eq!(it.next_back(), Some(100));
+    assert_eq!(it.try_fold(0, i8::checked_add), Some(0));
+}
+
+#[test]
+#[should_panic]
+fn test_iterator_step_by_zero() {
+    let mut it = (0..).step_by(0);
+    it.next();
+}
+
+#[test]
+fn test_iterator_step_by_size_hint() {
+    struct StubSizeHint(usize, Option<usize>);
+    impl Iterator for StubSizeHint {
+        type Item = ();
+        fn next(&mut self) -> Option<()> {
+            self.0 -= 1;
+            if let Some(ref mut upper) = self.1 {
+                *upper -= 1;
+            }
+            Some(())
+        }
+        fn size_hint(&self) -> (usize, Option<usize>) {
+            (self.0, self.1)
+        }
+    }
+
+    // The two checks in each case are needed because the logic
+    // is different before the first call to `next()`.
+
+    let mut it = StubSizeHint(10, Some(10)).step_by(1);
+    assert_eq!(it.size_hint(), (10, Some(10)));
+    it.next();
+    assert_eq!(it.size_hint(), (9, Some(9)));
+
+    // exact multiple
+    let mut it = StubSizeHint(10, Some(10)).step_by(3);
+    assert_eq!(it.size_hint(), (4, Some(4)));
+    it.next();
+    assert_eq!(it.size_hint(), (3, Some(3)));
+
+    // larger base range, but not enough to get another element
+    let mut it = StubSizeHint(12, Some(12)).step_by(3);
+    assert_eq!(it.size_hint(), (4, Some(4)));
+    it.next();
+    assert_eq!(it.size_hint(), (3, Some(3)));
+
+    // smaller base range, so fewer resulting elements
+    let mut it = StubSizeHint(9, Some(9)).step_by(3);
+    assert_eq!(it.size_hint(), (3, Some(3)));
+    it.next();
+    assert_eq!(it.size_hint(), (2, Some(2)));
+
+    // infinite upper bound
+    let mut it = StubSizeHint(usize::MAX, None).step_by(1);
+    assert_eq!(it.size_hint(), (usize::MAX, None));
+    it.next();
+    assert_eq!(it.size_hint(), (usize::MAX - 1, None));
+
+    // still infinite with larger step
+    let mut it = StubSizeHint(7, None).step_by(3);
+    assert_eq!(it.size_hint(), (3, None));
+    it.next();
+    assert_eq!(it.size_hint(), (2, None));
+
+    // propagates ExactSizeIterator
+    let a = [1, 2, 3, 4, 5];
+    let it = a.iter().step_by(2);
+    assert_eq!(it.len(), 3);
+
+    // Cannot be TrustedLen as a step greater than one makes an iterator
+    // with (usize::MAX, None) no longer meet the safety requirements
+    trait TrustedLenCheck {
+        fn test(self) -> bool;
+    }
+    impl<T: Iterator> TrustedLenCheck for T {
+        default fn test(self) -> bool {
+            false
+        }
+    }
+    impl<T: TrustedLen> TrustedLenCheck for T {
+        fn test(self) -> bool {
+            true
+        }
+    }
+    assert!(TrustedLenCheck::test(a.iter()));
+    assert!(!TrustedLenCheck::test(a.iter().step_by(1)));
+}
+
+#[test]
+fn test_filter_map() {
+    let it = (0..).step_by(1).take(10).filter_map(|x| if x % 2 == 0 { Some(x * x) } else { None });
+    assert_eq!(it.collect::<Vec<usize>>(), [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]);
+}
+
+#[test]
+fn test_filter_map_fold() {
+    let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+    let ys = [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8];
+    let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None });
+    let i = it.fold(0, |i, x| {
+        assert_eq!(x, ys[i]);
+        i + 1
+    });
+    assert_eq!(i, ys.len());
+
+    let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None });
+    let i = it.rfold(ys.len(), |i, x| {
+        assert_eq!(x, ys[i - 1]);
+        i - 1
+    });
+    assert_eq!(i, 0);
+}
+
+#[test]
+fn test_iterator_enumerate() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let it = xs.iter().enumerate();
+    for (i, &x) in it {
+        assert_eq!(i, x);
+    }
+}
+
+#[test]
+fn test_iterator_enumerate_nth() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    for (i, &x) in xs.iter().enumerate() {
+        assert_eq!(i, x);
+    }
+
+    let mut it = xs.iter().enumerate();
+    while let Some((i, &x)) = it.nth(0) {
+        assert_eq!(i, x);
+    }
+
+    let mut it = xs.iter().enumerate();
+    while let Some((i, &x)) = it.nth(1) {
+        assert_eq!(i, x);
+    }
+
+    let (i, &x) = xs.iter().enumerate().nth(3).unwrap();
+    assert_eq!(i, x);
+    assert_eq!(i, 3);
+}
+
+#[test]
+fn test_iterator_enumerate_nth_back() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let mut it = xs.iter().enumerate();
+    while let Some((i, &x)) = it.nth_back(0) {
+        assert_eq!(i, x);
+    }
+
+    let mut it = xs.iter().enumerate();
+    while let Some((i, &x)) = it.nth_back(1) {
+        assert_eq!(i, x);
+    }
+
+    let (i, &x) = xs.iter().enumerate().nth_back(3).unwrap();
+    assert_eq!(i, x);
+    assert_eq!(i, 2);
+}
+
+#[test]
+fn test_iterator_enumerate_count() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    assert_eq!(xs.iter().enumerate().count(), 6);
+}
+
+#[test]
+fn test_iterator_enumerate_fold() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let mut it = xs.iter().enumerate();
+    // steal a couple to get an interesting offset
+    assert_eq!(it.next(), Some((0, &0)));
+    assert_eq!(it.next(), Some((1, &1)));
+    let i = it.fold(2, |i, (j, &x)| {
+        assert_eq!(i, j);
+        assert_eq!(x, xs[j]);
+        i + 1
+    });
+    assert_eq!(i, xs.len());
+
+    let mut it = xs.iter().enumerate();
+    assert_eq!(it.next(), Some((0, &0)));
+    let i = it.rfold(xs.len() - 1, |i, (j, &x)| {
+        assert_eq!(i, j);
+        assert_eq!(x, xs[j]);
+        i - 1
+    });
+    assert_eq!(i, 0);
+}
+
+#[test]
+fn test_iterator_filter_count() {
+    let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+    assert_eq!(xs.iter().filter(|&&x| x % 2 == 0).count(), 5);
+}
+
+#[test]
+fn test_iterator_filter_fold() {
+    let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+    let ys = [0, 2, 4, 6, 8];
+    let it = xs.iter().filter(|&&x| x % 2 == 0);
+    let i = it.fold(0, |i, &x| {
+        assert_eq!(x, ys[i]);
+        i + 1
+    });
+    assert_eq!(i, ys.len());
+
+    let it = xs.iter().filter(|&&x| x % 2 == 0);
+    let i = it.rfold(ys.len(), |i, &x| {
+        assert_eq!(x, ys[i - 1]);
+        i - 1
+    });
+    assert_eq!(i, 0);
+}
+
+#[test]
+fn test_iterator_peekable() {
+    let xs = vec![0, 1, 2, 3, 4, 5];
+
+    let mut it = xs.iter().cloned().peekable();
+    assert_eq!(it.len(), 6);
+    assert_eq!(it.peek().unwrap(), &0);
+    assert_eq!(it.len(), 6);
+    assert_eq!(it.next().unwrap(), 0);
+    assert_eq!(it.len(), 5);
+    assert_eq!(it.next().unwrap(), 1);
+    assert_eq!(it.len(), 4);
+    assert_eq!(it.next().unwrap(), 2);
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.peek().unwrap(), &3);
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.peek().unwrap(), &3);
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.next().unwrap(), 3);
+    assert_eq!(it.len(), 2);
+    assert_eq!(it.next().unwrap(), 4);
+    assert_eq!(it.len(), 1);
+    assert_eq!(it.peek().unwrap(), &5);
+    assert_eq!(it.len(), 1);
+    assert_eq!(it.next().unwrap(), 5);
+    assert_eq!(it.len(), 0);
+    assert!(it.peek().is_none());
+    assert_eq!(it.len(), 0);
+    assert!(it.next().is_none());
+    assert_eq!(it.len(), 0);
+
+    let mut it = xs.iter().cloned().peekable();
+    assert_eq!(it.len(), 6);
+    assert_eq!(it.peek().unwrap(), &0);
+    assert_eq!(it.len(), 6);
+    assert_eq!(it.next_back().unwrap(), 5);
+    assert_eq!(it.len(), 5);
+    assert_eq!(it.next_back().unwrap(), 4);
+    assert_eq!(it.len(), 4);
+    assert_eq!(it.next_back().unwrap(), 3);
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.peek().unwrap(), &0);
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.peek().unwrap(), &0);
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.next_back().unwrap(), 2);
+    assert_eq!(it.len(), 2);
+    assert_eq!(it.next_back().unwrap(), 1);
+    assert_eq!(it.len(), 1);
+    assert_eq!(it.peek().unwrap(), &0);
+    assert_eq!(it.len(), 1);
+    assert_eq!(it.next_back().unwrap(), 0);
+    assert_eq!(it.len(), 0);
+    assert!(it.peek().is_none());
+    assert_eq!(it.len(), 0);
+    assert!(it.next_back().is_none());
+    assert_eq!(it.len(), 0);
+}
+
+#[test]
+fn test_iterator_peekable_count() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let ys = [10];
+    let zs: [i32; 0] = [];
+
+    assert_eq!(xs.iter().peekable().count(), 6);
+
+    let mut it = xs.iter().peekable();
+    assert_eq!(it.peek(), Some(&&0));
+    assert_eq!(it.count(), 6);
+
+    assert_eq!(ys.iter().peekable().count(), 1);
+
+    let mut it = ys.iter().peekable();
+    assert_eq!(it.peek(), Some(&&10));
+    assert_eq!(it.count(), 1);
+
+    assert_eq!(zs.iter().peekable().count(), 0);
+
+    let mut it = zs.iter().peekable();
+    assert_eq!(it.peek(), None);
+}
+
+#[test]
+fn test_iterator_peekable_nth() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let mut it = xs.iter().peekable();
+
+    assert_eq!(it.peek(), Some(&&0));
+    assert_eq!(it.nth(0), Some(&0));
+    assert_eq!(it.peek(), Some(&&1));
+    assert_eq!(it.nth(1), Some(&2));
+    assert_eq!(it.peek(), Some(&&3));
+    assert_eq!(it.nth(2), Some(&5));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_iterator_peekable_last() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let ys = [0];
+
+    let mut it = xs.iter().peekable();
+    assert_eq!(it.peek(), Some(&&0));
+    assert_eq!(it.last(), Some(&5));
+
+    let mut it = ys.iter().peekable();
+    assert_eq!(it.peek(), Some(&&0));
+    assert_eq!(it.last(), Some(&0));
+
+    let mut it = ys.iter().peekable();
+    assert_eq!(it.next(), Some(&0));
+    assert_eq!(it.peek(), None);
+    assert_eq!(it.last(), None);
+}
+
+#[test]
+fn test_iterator_peekable_fold() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let mut it = xs.iter().peekable();
+    assert_eq!(it.peek(), Some(&&0));
+    let i = it.fold(0, |i, &x| {
+        assert_eq!(x, xs[i]);
+        i + 1
+    });
+    assert_eq!(i, xs.len());
+}
+
+#[test]
+fn test_iterator_peekable_rfold() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let mut it = xs.iter().peekable();
+    assert_eq!(it.peek(), Some(&&0));
+    let i = it.rfold(0, |i, &x| {
+        assert_eq!(x, xs[xs.len() - 1 - i]);
+        i + 1
+    });
+    assert_eq!(i, xs.len());
+}
+
+#[test]
+fn test_iterator_peekable_next_if_eq() {
+    // first, try on references
+    let xs = vec!["Heart", "of", "Gold"];
+    let mut it = xs.into_iter().peekable();
+    // try before `peek()`
+    assert_eq!(it.next_if_eq(&"trillian"), None);
+    assert_eq!(it.next_if_eq(&"Heart"), Some("Heart"));
+    // try after peek()
+    assert_eq!(it.peek(), Some(&"of"));
+    assert_eq!(it.next_if_eq(&"of"), Some("of"));
+    assert_eq!(it.next_if_eq(&"zaphod"), None);
+    // make sure `next()` still behaves
+    assert_eq!(it.next(), Some("Gold"));
+
+    // make sure comparison works for owned values
+    let xs = vec![String::from("Ludicrous"), "speed".into()];
+    let mut it = xs.into_iter().peekable();
+    // make sure basic functionality works
+    assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into()));
+    assert_eq!(it.next_if_eq("speed"), Some("speed".into()));
+    assert_eq!(it.next_if_eq(""), None);
+}
+
+#[test]
+fn test_iterator_peekable_mut() {
+    let mut it = vec![1, 2, 3].into_iter().peekable();
+    if let Some(p) = it.peek_mut() {
+        if *p == 1 {
+            *p = 5;
+        }
+    }
+    assert_eq!(it.collect::<Vec<_>>(), vec![5, 2, 3]);
+}
+
+/// This is an iterator that follows the Iterator contract,
+/// but it is not fused. After having returned None once, it will start
+/// producing elements if .next() is called again.
+pub struct CycleIter<'a, T> {
+    index: usize,
+    data: &'a [T],
+}
+
+pub fn cycle<T>(data: &[T]) -> CycleIter<'_, T> {
+    CycleIter { index: 0, data }
+}
+
+impl<'a, T> Iterator for CycleIter<'a, T> {
+    type Item = &'a T;
+    fn next(&mut self) -> Option<Self::Item> {
+        let elt = self.data.get(self.index);
+        self.index += 1;
+        self.index %= 1 + self.data.len();
+        elt
+    }
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_1() {
+    // Check that the loop using .peek() terminates
+    let data = [1, 2, 3];
+    let mut iter = cycle(&data).peekable();
+
+    let mut n = 0;
+    while let Some(_) = iter.next() {
+        let is_the_last = iter.peek().is_none();
+        assert_eq!(is_the_last, n == data.len() - 1);
+        n += 1;
+        if n > data.len() {
+            break;
+        }
+    }
+    assert_eq!(n, data.len());
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_2() {
+    let data = [0];
+    let mut iter = cycle(&data).peekable();
+    iter.next();
+    assert_eq!(iter.peek(), None);
+    assert_eq!(iter.last(), None);
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_3() {
+    let data = [0];
+    let mut iter = cycle(&data).peekable();
+    iter.peek();
+    assert_eq!(iter.nth(0), Some(&0));
+
+    let mut iter = cycle(&data).peekable();
+    iter.next();
+    assert_eq!(iter.peek(), None);
+    assert_eq!(iter.nth(0), None);
+}
+
+#[test]
+fn test_iterator_take_while() {
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
+    let ys = [0, 1, 2, 3, 5, 13];
+    let it = xs.iter().take_while(|&x| *x < 15);
+    let mut i = 0;
+    for x in it {
+        assert_eq!(*x, ys[i]);
+        i += 1;
+    }
+    assert_eq!(i, ys.len());
+}
+
+#[test]
+fn test_iterator_skip_while() {
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
+    let ys = [15, 16, 17, 19];
+    let it = xs.iter().skip_while(|&x| *x < 15);
+    let mut i = 0;
+    for x in it {
+        assert_eq!(*x, ys[i]);
+        i += 1;
+    }
+    assert_eq!(i, ys.len());
+}
+
+#[test]
+fn test_iterator_skip_while_fold() {
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
+    let ys = [15, 16, 17, 19];
+    let it = xs.iter().skip_while(|&x| *x < 15);
+    let i = it.fold(0, |i, &x| {
+        assert_eq!(x, ys[i]);
+        i + 1
+    });
+    assert_eq!(i, ys.len());
+
+    let mut it = xs.iter().skip_while(|&x| *x < 15);
+    assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
+    let i = it.fold(1, |i, &x| {
+        assert_eq!(x, ys[i]);
+        i + 1
+    });
+    assert_eq!(i, ys.len());
+}
+
+#[test]
+fn test_iterator_skip() {
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+    let ys = [13, 15, 16, 17, 19, 20, 30];
+    let mut it = xs.iter().skip(5);
+    let mut i = 0;
+    while let Some(&x) = it.next() {
+        assert_eq!(x, ys[i]);
+        i += 1;
+        assert_eq!(it.len(), xs.len() - 5 - i);
+    }
+    assert_eq!(i, ys.len());
+    assert_eq!(it.len(), 0);
+}
+
+#[test]
+fn test_iterator_skip_doubleended() {
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+    let mut it = xs.iter().rev().skip(5);
+    assert_eq!(it.next(), Some(&15));
+    assert_eq!(it.by_ref().rev().next(), Some(&0));
+    assert_eq!(it.next(), Some(&13));
+    assert_eq!(it.by_ref().rev().next(), Some(&1));
+    assert_eq!(it.next(), Some(&5));
+    assert_eq!(it.by_ref().rev().next(), Some(&2));
+    assert_eq!(it.next(), Some(&3));
+    assert_eq!(it.next(), None);
+    let mut it = xs.iter().rev().skip(5).rev();
+    assert_eq!(it.next(), Some(&0));
+    assert_eq!(it.rev().next(), Some(&15));
+    let mut it_base = xs.iter();
+    {
+        let mut it = it_base.by_ref().skip(5).rev();
+        assert_eq!(it.next(), Some(&30));
+        assert_eq!(it.next(), Some(&20));
+        assert_eq!(it.next(), Some(&19));
+        assert_eq!(it.next(), Some(&17));
+        assert_eq!(it.next(), Some(&16));
+        assert_eq!(it.next(), Some(&15));
+        assert_eq!(it.next(), Some(&13));
+        assert_eq!(it.next(), None);
+    }
+    // make sure the skipped parts have not been consumed
+    assert_eq!(it_base.next(), Some(&0));
+    assert_eq!(it_base.next(), Some(&1));
+    assert_eq!(it_base.next(), Some(&2));
+    assert_eq!(it_base.next(), Some(&3));
+    assert_eq!(it_base.next(), Some(&5));
+    assert_eq!(it_base.next(), None);
+    let it = xs.iter().skip(5).rev();
+    assert_eq!(it.last(), Some(&13));
+}
+
+#[test]
+fn test_iterator_skip_nth() {
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+
+    let mut it = xs.iter().skip(0);
+    assert_eq!(it.nth(0), Some(&0));
+    assert_eq!(it.nth(1), Some(&2));
+
+    let mut it = xs.iter().skip(5);
+    assert_eq!(it.nth(0), Some(&13));
+    assert_eq!(it.nth(1), Some(&16));
+
+    let mut it = xs.iter().skip(12);
+    assert_eq!(it.nth(0), None);
+}
+
+#[test]
+fn test_iterator_skip_count() {
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+
+    assert_eq!(xs.iter().skip(0).count(), 12);
+    assert_eq!(xs.iter().skip(1).count(), 11);
+    assert_eq!(xs.iter().skip(11).count(), 1);
+    assert_eq!(xs.iter().skip(12).count(), 0);
+    assert_eq!(xs.iter().skip(13).count(), 0);
+}
+
+#[test]
+fn test_iterator_skip_last() {
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+
+    assert_eq!(xs.iter().skip(0).last(), Some(&30));
+    assert_eq!(xs.iter().skip(1).last(), Some(&30));
+    assert_eq!(xs.iter().skip(11).last(), Some(&30));
+    assert_eq!(xs.iter().skip(12).last(), None);
+    assert_eq!(xs.iter().skip(13).last(), None);
+
+    let mut it = xs.iter().skip(5);
+    assert_eq!(it.next(), Some(&13));
+    assert_eq!(it.last(), Some(&30));
+}
+
+#[test]
+fn test_iterator_skip_fold() {
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+    let ys = [13, 15, 16, 17, 19, 20, 30];
+
+    let it = xs.iter().skip(5);
+    let i = it.fold(0, |i, &x| {
+        assert_eq!(x, ys[i]);
+        i + 1
+    });
+    assert_eq!(i, ys.len());
+
+    let mut it = xs.iter().skip(5);
+    assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
+    let i = it.fold(1, |i, &x| {
+        assert_eq!(x, ys[i]);
+        i + 1
+    });
+    assert_eq!(i, ys.len());
+
+    let it = xs.iter().skip(5);
+    let i = it.rfold(ys.len(), |i, &x| {
+        let i = i - 1;
+        assert_eq!(x, ys[i]);
+        i
+    });
+    assert_eq!(i, 0);
+
+    let mut it = xs.iter().skip(5);
+    assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
+    let i = it.rfold(ys.len(), |i, &x| {
+        let i = i - 1;
+        assert_eq!(x, ys[i]);
+        i
+    });
+    assert_eq!(i, 1);
+}
+
+#[test]
+fn test_iterator_take() {
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
+    let ys = [0, 1, 2, 3, 5];
+
+    let mut it = xs.iter().take(ys.len());
+    let mut i = 0;
+    assert_eq!(it.len(), ys.len());
+    while let Some(&x) = it.next() {
+        assert_eq!(x, ys[i]);
+        i += 1;
+        assert_eq!(it.len(), ys.len() - i);
+    }
+    assert_eq!(i, ys.len());
+    assert_eq!(it.len(), 0);
+
+    let mut it = xs.iter().take(ys.len());
+    let mut i = 0;
+    assert_eq!(it.len(), ys.len());
+    while let Some(&x) = it.next_back() {
+        i += 1;
+        assert_eq!(x, ys[ys.len() - i]);
+        assert_eq!(it.len(), ys.len() - i);
+    }
+    assert_eq!(i, ys.len());
+    assert_eq!(it.len(), 0);
+}
+
+#[test]
+fn test_iterator_take_nth() {
+    let xs = [0, 1, 2, 4, 5];
+    let mut it = xs.iter();
+    {
+        let mut take = it.by_ref().take(3);
+        let mut i = 0;
+        while let Some(&x) = take.nth(0) {
+            assert_eq!(x, i);
+            i += 1;
+        }
+    }
+    assert_eq!(it.nth(1), Some(&5));
+    assert_eq!(it.nth(0), None);
+
+    let xs = [0, 1, 2, 3, 4];
+    let mut it = xs.iter().take(7);
+    let mut i = 1;
+    while let Some(&x) = it.nth(1) {
+        assert_eq!(x, i);
+        i += 2;
+    }
+}
+
+#[test]
+fn test_iterator_take_nth_back() {
+    let xs = [0, 1, 2, 4, 5];
+    let mut it = xs.iter();
+    {
+        let mut take = it.by_ref().take(3);
+        let mut i = 0;
+        while let Some(&x) = take.nth_back(0) {
+            i += 1;
+            assert_eq!(x, 3 - i);
+        }
+    }
+    assert_eq!(it.nth_back(0), None);
+
+    let xs = [0, 1, 2, 3, 4];
+    let mut it = xs.iter().take(7);
+    assert_eq!(it.nth_back(1), Some(&3));
+    assert_eq!(it.nth_back(1), Some(&1));
+    assert_eq!(it.nth_back(1), None);
+}
+
+#[test]
+fn test_iterator_take_short() {
+    let xs = [0, 1, 2, 3];
+
+    let mut it = xs.iter().take(5);
+    let mut i = 0;
+    assert_eq!(it.len(), xs.len());
+    while let Some(&x) = it.next() {
+        assert_eq!(x, xs[i]);
+        i += 1;
+        assert_eq!(it.len(), xs.len() - i);
+    }
+    assert_eq!(i, xs.len());
+    assert_eq!(it.len(), 0);
+
+    let mut it = xs.iter().take(5);
+    let mut i = 0;
+    assert_eq!(it.len(), xs.len());
+    while let Some(&x) = it.next_back() {
+        i += 1;
+        assert_eq!(x, xs[xs.len() - i]);
+        assert_eq!(it.len(), xs.len() - i);
+    }
+    assert_eq!(i, xs.len());
+    assert_eq!(it.len(), 0);
+}
+
+#[test]
+fn test_iterator_scan() {
+    // test the type inference
+    fn add(old: &mut isize, new: &usize) -> Option<f64> {
+        *old += *new as isize;
+        Some(*old as f64)
+    }
+    let xs = [0, 1, 2, 3, 4];
+    let ys = [0f64, 1.0, 3.0, 6.0, 10.0];
+
+    let it = xs.iter().scan(0, add);
+    let mut i = 0;
+    for x in it {
+        assert_eq!(x, ys[i]);
+        i += 1;
+    }
+    assert_eq!(i, ys.len());
+}
+
+#[test]
+fn test_iterator_flat_map() {
+    let xs = [0, 3, 6];
+    let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+    let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3));
+    let mut i = 0;
+    for x in it {
+        assert_eq!(x, ys[i]);
+        i += 1;
+    }
+    assert_eq!(i, ys.len());
+}
+
+/// Tests `FlatMap::fold` with items already picked off the front and back,
+/// to make sure all parts of the `FlatMap` are folded correctly.
+#[test]
+fn test_iterator_flat_map_fold() {
+    let xs = [0, 3, 6];
+    let ys = [1, 2, 3, 4, 5, 6, 7];
+    let mut it = xs.iter().flat_map(|&x| x..x + 3);
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.next_back(), Some(8));
+    let i = it.fold(0, |i, x| {
+        assert_eq!(x, ys[i]);
+        i + 1
+    });
+    assert_eq!(i, ys.len());
+
+    let mut it = xs.iter().flat_map(|&x| x..x + 3);
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.next_back(), Some(8));
+    let i = it.rfold(ys.len(), |i, x| {
+        assert_eq!(x, ys[i - 1]);
+        i - 1
+    });
+    assert_eq!(i, 0);
+}
+
+#[test]
+fn test_iterator_flatten() {
+    let xs = [0, 3, 6];
+    let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+    let it = xs.iter().map(|&x| (x..).step_by(1).take(3)).flatten();
+    let mut i = 0;
+    for x in it {
+        assert_eq!(x, ys[i]);
+        i += 1;
+    }
+    assert_eq!(i, ys.len());
+}
+
+/// Tests `Flatten::fold` with items already picked off the front and back,
+/// to make sure all parts of the `Flatten` are folded correctly.
+#[test]
+fn test_iterator_flatten_fold() {
+    let xs = [0, 3, 6];
+    let ys = [1, 2, 3, 4, 5, 6, 7];
+    let mut it = xs.iter().map(|&x| x..x + 3).flatten();
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.next_back(), Some(8));
+    let i = it.fold(0, |i, x| {
+        assert_eq!(x, ys[i]);
+        i + 1
+    });
+    assert_eq!(i, ys.len());
+
+    let mut it = xs.iter().map(|&x| x..x + 3).flatten();
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.next_back(), Some(8));
+    let i = it.rfold(ys.len(), |i, x| {
+        assert_eq!(x, ys[i - 1]);
+        i - 1
+    });
+    assert_eq!(i, 0);
+}
+
+#[test]
+fn test_inspect() {
+    let xs = [1, 2, 3, 4];
+    let mut n = 0;
+
+    let ys = xs.iter().cloned().inspect(|_| n += 1).collect::<Vec<usize>>();
+
+    assert_eq!(n, xs.len());
+    assert_eq!(&xs[..], &ys[..]);
+}
+
+#[test]
+fn test_inspect_fold() {
+    let xs = [1, 2, 3, 4];
+    let mut n = 0;
+    {
+        let it = xs.iter().inspect(|_| n += 1);
+        let i = it.fold(0, |i, &x| {
+            assert_eq!(x, xs[i]);
+            i + 1
+        });
+        assert_eq!(i, xs.len());
+    }
+    assert_eq!(n, xs.len());
+
+    let mut n = 0;
+    {
+        let it = xs.iter().inspect(|_| n += 1);
+        let i = it.rfold(xs.len(), |i, &x| {
+            assert_eq!(x, xs[i - 1]);
+            i - 1
+        });
+        assert_eq!(i, 0);
+    }
+    assert_eq!(n, xs.len());
+}
+
+#[test]
+fn test_cycle() {
+    let cycle_len = 3;
+    let it = (0..).step_by(1).take(cycle_len).cycle();
+    assert_eq!(it.size_hint(), (usize::MAX, None));
+    for (i, x) in it.take(100).enumerate() {
+        assert_eq!(i % cycle_len, x);
+    }
+
+    let mut it = (0..).step_by(1).take(0).cycle();
+    assert_eq!(it.size_hint(), (0, Some(0)));
+    assert_eq!(it.next(), None);
+
+    assert_eq!(empty::<i32>().cycle().fold(0, |acc, x| acc + x), 0);
+
+    assert_eq!(once(1).cycle().skip(1).take(4).fold(0, |acc, x| acc + x), 4);
+
+    assert_eq!((0..10).cycle().take(5).sum::<i32>(), 10);
+    assert_eq!((0..10).cycle().take(15).sum::<i32>(), 55);
+    assert_eq!((0..10).cycle().take(25).sum::<i32>(), 100);
+
+    let mut iter = (0..10).cycle();
+    iter.nth(14);
+    assert_eq!(iter.take(8).sum::<i32>(), 38);
+
+    let mut iter = (0..10).cycle();
+    iter.nth(9);
+    assert_eq!(iter.take(3).sum::<i32>(), 3);
+}
+
+#[test]
+fn test_iterator_nth() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+    for i in 0..v.len() {
+        assert_eq!(v.iter().nth(i).unwrap(), &v[i]);
+    }
+    assert_eq!(v.iter().nth(v.len()), None);
+}
+
+#[test]
+fn test_iterator_nth_back() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+    for i in 0..v.len() {
+        assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - 1 - i]);
+    }
+    assert_eq!(v.iter().nth_back(v.len()), None);
+}
+
+#[test]
+fn test_iterator_rev_nth_back() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+    for i in 0..v.len() {
+        assert_eq!(v.iter().rev().nth_back(i).unwrap(), &v[i]);
+    }
+    assert_eq!(v.iter().rev().nth_back(v.len()), None);
+}
+
+#[test]
+fn test_iterator_rev_nth() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+    for i in 0..v.len() {
+        assert_eq!(v.iter().rev().nth(i).unwrap(), &v[v.len() - 1 - i]);
+    }
+    assert_eq!(v.iter().rev().nth(v.len()), None);
+}
+
+#[test]
+fn test_iterator_advance_by() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+
+    for i in 0..v.len() {
+        let mut iter = v.iter();
+        assert_eq!(iter.advance_by(i), Ok(()));
+        assert_eq!(iter.next().unwrap(), &v[i]);
+        assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
+    }
+
+    assert_eq!(v.iter().advance_by(v.len()), Ok(()));
+    assert_eq!(v.iter().advance_by(100), Err(v.len()));
+}
+
+#[test]
+fn test_iterator_advance_back_by() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+
+    for i in 0..v.len() {
+        let mut iter = v.iter();
+        assert_eq!(iter.advance_back_by(i), Ok(()));
+        assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]);
+        assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
+    }
+
+    assert_eq!(v.iter().advance_back_by(v.len()), Ok(()));
+    assert_eq!(v.iter().advance_back_by(100), Err(v.len()));
+}
+
+#[test]
+fn test_iterator_rev_advance_by() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+
+    for i in 0..v.len() {
+        let mut iter = v.iter().rev();
+        assert_eq!(iter.advance_by(i), Ok(()));
+        assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]);
+        assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
+    }
+
+    assert_eq!(v.iter().rev().advance_by(v.len()), Ok(()));
+    assert_eq!(v.iter().rev().advance_by(100), Err(v.len()));
+}
+
+#[test]
+fn test_iterator_rev_advance_back_by() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+
+    for i in 0..v.len() {
+        let mut iter = v.iter().rev();
+        assert_eq!(iter.advance_back_by(i), Ok(()));
+        assert_eq!(iter.next_back().unwrap(), &v[i]);
+        assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
+    }
+
+    assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(()));
+    assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len()));
+}
+
+#[test]
+fn test_iterator_last() {
+    let v: &[_] = &[0, 1, 2, 3, 4];
+    assert_eq!(v.iter().last().unwrap(), &4);
+    assert_eq!(v[..1].iter().last().unwrap(), &0);
+}
+
+#[test]
+fn test_iterator_len() {
+    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    assert_eq!(v[..4].iter().count(), 4);
+    assert_eq!(v[..10].iter().count(), 10);
+    assert_eq!(v[..0].iter().count(), 0);
+}
+
+#[test]
+fn test_iterator_sum() {
+    let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    assert_eq!(v[..4].iter().cloned().sum::<i32>(), 6);
+    assert_eq!(v.iter().cloned().sum::<i32>(), 55);
+    assert_eq!(v[..0].iter().cloned().sum::<i32>(), 0);
+}
+
+#[test]
+fn test_iterator_sum_result() {
+    let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
+    assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Ok(10));
+    let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
+    assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Err(()));
+
+    #[derive(PartialEq, Debug)]
+    struct S(Result<i32, ()>);
+
+    impl Sum<Result<i32, ()>> for S {
+        fn sum<I: Iterator<Item = Result<i32, ()>>>(mut iter: I) -> Self {
+            // takes the sum by repeatedly calling `next` on `iter`,
+            // thus testing that repeated calls to `ResultShunt::try_fold`
+            // produce the expected results
+            Self(iter.by_ref().sum())
+        }
+    }
+
+    let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
+    assert_eq!(v.iter().cloned().sum::<S>(), S(Ok(10)));
+    let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
+    assert_eq!(v.iter().cloned().sum::<S>(), S(Err(())));
+}
+
+#[test]
+fn test_iterator_sum_option() {
+    let v: &[Option<i32>] = &[Some(1), Some(2), Some(3), Some(4)];
+    assert_eq!(v.iter().cloned().sum::<Option<i32>>(), Some(10));
+    let v: &[Option<i32>] = &[Some(1), None, Some(3), Some(4)];
+    assert_eq!(v.iter().cloned().sum::<Option<i32>>(), None);
+}
+
+#[test]
+fn test_iterator_product() {
+    let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    assert_eq!(v[..4].iter().cloned().product::<i32>(), 0);
+    assert_eq!(v[1..5].iter().cloned().product::<i32>(), 24);
+    assert_eq!(v[..0].iter().cloned().product::<i32>(), 1);
+}
+
+#[test]
+fn test_iterator_product_result() {
+    let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
+    assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Ok(24));
+    let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
+    assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Err(()));
+}
+
+/// A wrapper struct that implements `Eq` and `Ord` based on the wrapped
+/// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min`
+/// return the correct element if some of them are equal.
+#[derive(Debug)]
+struct Mod3(i32);
+
+impl PartialEq for Mod3 {
+    fn eq(&self, other: &Self) -> bool {
+        self.0 % 3 == other.0 % 3
+    }
+}
+
+impl Eq for Mod3 {}
+
+impl PartialOrd for Mod3 {
+    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for Mod3 {
+    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+        (self.0 % 3).cmp(&(other.0 % 3))
+    }
+}
+
+#[test]
+fn test_iterator_product_option() {
+    let v: &[Option<i32>] = &[Some(1), Some(2), Some(3), Some(4)];
+    assert_eq!(v.iter().cloned().product::<Option<i32>>(), Some(24));
+    let v: &[Option<i32>] = &[Some(1), None, Some(3), Some(4)];
+    assert_eq!(v.iter().cloned().product::<Option<i32>>(), None);
+}
+
+#[test]
+fn test_iterator_max() {
+    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    assert_eq!(v[..4].iter().cloned().max(), Some(3));
+    assert_eq!(v.iter().cloned().max(), Some(10));
+    assert_eq!(v[..0].iter().cloned().max(), None);
+    assert_eq!(v.iter().cloned().map(Mod3).max().map(|x| x.0), Some(8));
+}
+
+#[test]
+fn test_iterator_min() {
+    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    assert_eq!(v[..4].iter().cloned().min(), Some(0));
+    assert_eq!(v.iter().cloned().min(), Some(0));
+    assert_eq!(v[..0].iter().cloned().min(), None);
+    assert_eq!(v.iter().cloned().map(Mod3).min().map(|x| x.0), Some(0));
+}
+
+#[test]
+fn test_iterator_size_hint() {
+    let c = (0..).step_by(1);
+    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+    let v2 = &[10, 11, 12];
+    let vi = v.iter();
+
+    assert_eq!((0..).size_hint(), (usize::MAX, None));
+    assert_eq!(c.size_hint(), (usize::MAX, None));
+    assert_eq!(vi.clone().size_hint(), (10, Some(10)));
+
+    assert_eq!(c.clone().take(5).size_hint(), (5, Some(5)));
+    assert_eq!(c.clone().skip(5).size_hint().1, None);
+    assert_eq!(c.clone().take_while(|_| false).size_hint(), (0, None));
+    assert_eq!(c.clone().map_while(|_| None::<()>).size_hint(), (0, None));
+    assert_eq!(c.clone().skip_while(|_| false).size_hint(), (0, None));
+    assert_eq!(c.clone().enumerate().size_hint(), (usize::MAX, None));
+    assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), (usize::MAX, None));
+    assert_eq!(c.clone().zip(vi.clone()).size_hint(), (10, Some(10)));
+    assert_eq!(c.clone().scan(0, |_, _| Some(0)).size_hint(), (0, None));
+    assert_eq!(c.clone().filter(|_| false).size_hint(), (0, None));
+    assert_eq!(c.clone().map(|_| 0).size_hint(), (usize::MAX, None));
+    assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None));
+
+    assert_eq!(vi.clone().take(5).size_hint(), (5, Some(5)));
+    assert_eq!(vi.clone().take(12).size_hint(), (10, Some(10)));
+    assert_eq!(vi.clone().skip(3).size_hint(), (7, Some(7)));
+    assert_eq!(vi.clone().skip(12).size_hint(), (0, Some(0)));
+    assert_eq!(vi.clone().take_while(|_| false).size_hint(), (0, Some(10)));
+    assert_eq!(vi.clone().map_while(|_| None::<()>).size_hint(), (0, Some(10)));
+    assert_eq!(vi.clone().skip_while(|_| false).size_hint(), (0, Some(10)));
+    assert_eq!(vi.clone().enumerate().size_hint(), (10, Some(10)));
+    assert_eq!(vi.clone().chain(v2).size_hint(), (13, Some(13)));
+    assert_eq!(vi.clone().zip(v2).size_hint(), (3, Some(3)));
+    assert_eq!(vi.clone().scan(0, |_, _| Some(0)).size_hint(), (0, Some(10)));
+    assert_eq!(vi.clone().filter(|_| false).size_hint(), (0, Some(10)));
+    assert_eq!(vi.clone().map(|&i| i + 1).size_hint(), (10, Some(10)));
+    assert_eq!(vi.filter_map(|_| Some(0)).size_hint(), (0, Some(10)));
+}
+
+#[test]
+fn test_collect() {
+    let a = vec![1, 2, 3, 4, 5];
+    let b: Vec<isize> = a.iter().cloned().collect();
+    assert!(a == b);
+}
+
+#[test]
+fn test_all() {
+    let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]);
+    assert!(v.iter().all(|&x| x < 10));
+    assert!(!v.iter().all(|&x| x % 2 == 0));
+    assert!(!v.iter().all(|&x| x > 100));
+    assert!(v[..0].iter().all(|_| panic!()));
+}
+
+#[test]
+fn test_any() {
+    let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]);
+    assert!(v.iter().any(|&x| x < 10));
+    assert!(v.iter().any(|&x| x % 2 == 0));
+    assert!(!v.iter().any(|&x| x > 100));
+    assert!(!v[..0].iter().any(|_| panic!()));
+}
+
+#[test]
+fn test_find() {
+    let v: &[isize] = &[1, 3, 9, 27, 103, 14, 11];
+    assert_eq!(*v.iter().find(|&&x| x & 1 == 0).unwrap(), 14);
+    assert_eq!(*v.iter().find(|&&x| x % 3 == 0).unwrap(), 3);
+    assert!(v.iter().find(|&&x| x % 12 == 0).is_none());
+}
+
+#[test]
+fn test_find_map() {
+    let xs: &[isize] = &[];
+    assert_eq!(xs.iter().find_map(half_if_even), None);
+    let xs: &[isize] = &[3, 5];
+    assert_eq!(xs.iter().find_map(half_if_even), None);
+    let xs: &[isize] = &[4, 5];
+    assert_eq!(xs.iter().find_map(half_if_even), Some(2));
+    let xs: &[isize] = &[3, 6];
+    assert_eq!(xs.iter().find_map(half_if_even), Some(3));
+
+    let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7];
+    let mut iter = xs.iter();
+    assert_eq!(iter.find_map(half_if_even), Some(1));
+    assert_eq!(iter.find_map(half_if_even), Some(2));
+    assert_eq!(iter.find_map(half_if_even), Some(3));
+    assert_eq!(iter.next(), Some(&7));
+
+    fn half_if_even(x: &isize) -> Option<isize> {
+        if x % 2 == 0 { Some(x / 2) } else { None }
+    }
+}
+
+#[test]
+fn test_try_find() {
+    let xs: &[isize] = &[];
+    assert_eq!(xs.iter().try_find(testfn), Ok(None));
+    let xs: &[isize] = &[1, 2, 3, 4];
+    assert_eq!(xs.iter().try_find(testfn), Ok(Some(&2)));
+    let xs: &[isize] = &[1, 3, 4];
+    assert_eq!(xs.iter().try_find(testfn), Err(()));
+
+    let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7];
+    let mut iter = xs.iter();
+    assert_eq!(iter.try_find(testfn), Ok(Some(&2)));
+    assert_eq!(iter.try_find(testfn), Err(()));
+    assert_eq!(iter.next(), Some(&5));
+
+    fn testfn(x: &&isize) -> Result<bool, ()> {
+        if **x == 2 {
+            return Ok(true);
+        }
+        if **x == 4 {
+            return Err(());
+        }
+        Ok(false)
+    }
+}
+
+#[test]
+fn test_try_find_api_usability() -> Result<(), Box<dyn std::error::Error>> {
+    let a = ["1", "2"];
+
+    let is_my_num = |s: &str, search: i32| -> Result<bool, std::num::ParseIntError> {
+        Ok(s.parse::<i32>()? == search)
+    };
+
+    let val = a.iter().try_find(|&&s| is_my_num(s, 2))?;
+    assert_eq!(val, Some(&"2"));
+
+    Ok(())
+}
+
+#[test]
+fn test_position() {
+    let v = &[1, 3, 9, 27, 103, 14, 11];
+    assert_eq!(v.iter().position(|x| *x & 1 == 0).unwrap(), 5);
+    assert_eq!(v.iter().position(|x| *x % 3 == 0).unwrap(), 1);
+    assert!(v.iter().position(|x| *x % 12 == 0).is_none());
+}
+
+#[test]
+fn test_count() {
+    let xs = &[1, 2, 2, 1, 5, 9, 0, 2];
+    assert_eq!(xs.iter().filter(|x| **x == 2).count(), 3);
+    assert_eq!(xs.iter().filter(|x| **x == 5).count(), 1);
+    assert_eq!(xs.iter().filter(|x| **x == 95).count(), 0);
+}
+
+#[test]
+fn test_max_by_key() {
+    let xs: &[isize] = &[-3, 0, 1, 5, -10];
+    assert_eq!(*xs.iter().max_by_key(|x| x.abs()).unwrap(), -10);
+}
+
+#[test]
+fn test_max_by() {
+    let xs: &[isize] = &[-3, 0, 1, 5, -10];
+    assert_eq!(*xs.iter().max_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), -10);
+}
+
+#[test]
+fn test_min_by_key() {
+    let xs: &[isize] = &[-3, 0, 1, 5, -10];
+    assert_eq!(*xs.iter().min_by_key(|x| x.abs()).unwrap(), 0);
+}
+
+#[test]
+fn test_min_by() {
+    let xs: &[isize] = &[-3, 0, 1, 5, -10];
+    assert_eq!(*xs.iter().min_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), 0);
+}
+
+#[test]
+fn test_by_ref() {
+    let mut xs = 0..10;
+    // sum the first five values
+    let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b);
+    assert_eq!(partial_sum, 10);
+    assert_eq!(xs.next(), Some(5));
+}
+
+#[test]
+fn test_rev() {
+    let xs = [2, 4, 6, 8, 10, 12, 14, 16];
+    let mut it = xs.iter();
+    it.next();
+    it.next();
+    assert!(it.rev().cloned().collect::<Vec<isize>>() == vec![16, 14, 12, 10, 8, 6]);
+}
+
+#[test]
+fn test_copied() {
+    let xs = [2, 4, 6, 8];
+
+    let mut it = xs.iter().copied();
+    assert_eq!(it.len(), 4);
+    assert_eq!(it.next(), Some(2));
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.next(), Some(4));
+    assert_eq!(it.len(), 2);
+    assert_eq!(it.next_back(), Some(8));
+    assert_eq!(it.len(), 1);
+    assert_eq!(it.next_back(), Some(6));
+    assert_eq!(it.len(), 0);
+    assert_eq!(it.next_back(), None);
+}
+
+#[test]
+fn test_cloned() {
+    let xs = [2, 4, 6, 8];
+
+    let mut it = xs.iter().cloned();
+    assert_eq!(it.len(), 4);
+    assert_eq!(it.next(), Some(2));
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.next(), Some(4));
+    assert_eq!(it.len(), 2);
+    assert_eq!(it.next_back(), Some(8));
+    assert_eq!(it.len(), 1);
+    assert_eq!(it.next_back(), Some(6));
+    assert_eq!(it.len(), 0);
+    assert_eq!(it.next_back(), None);
+}
+
+#[test]
+fn test_cloned_side_effects() {
+    let mut count = 0;
+    {
+        let iter = [1, 2, 3]
+            .iter()
+            .map(|x| {
+                count += 1;
+                x
+            })
+            .cloned()
+            .zip(&[1]);
+        for _ in iter {}
+    }
+    assert_eq!(count, 2);
+}
+
+#[test]
+fn test_double_ended_map() {
+    let xs = [1, 2, 3, 4, 5, 6];
+    let mut it = xs.iter().map(|&x| x * -1);
+    assert_eq!(it.next(), Some(-1));
+    assert_eq!(it.next(), Some(-2));
+    assert_eq!(it.next_back(), Some(-6));
+    assert_eq!(it.next_back(), Some(-5));
+    assert_eq!(it.next(), Some(-3));
+    assert_eq!(it.next_back(), Some(-4));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_double_ended_enumerate() {
+    let xs = [1, 2, 3, 4, 5, 6];
+    let mut it = xs.iter().cloned().enumerate();
+    assert_eq!(it.next(), Some((0, 1)));
+    assert_eq!(it.next(), Some((1, 2)));
+    assert_eq!(it.next_back(), Some((5, 6)));
+    assert_eq!(it.next_back(), Some((4, 5)));
+    assert_eq!(it.next_back(), Some((3, 4)));
+    assert_eq!(it.next_back(), Some((2, 3)));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_double_ended_zip() {
+    let xs = [1, 2, 3, 4, 5, 6];
+    let ys = [1, 2, 3, 7];
+    let a = xs.iter().cloned();
+    let b = ys.iter().cloned();
+    let mut it = a.zip(b);
+    assert_eq!(it.next(), Some((1, 1)));
+    assert_eq!(it.next(), Some((2, 2)));
+    assert_eq!(it.next_back(), Some((4, 7)));
+    assert_eq!(it.next_back(), Some((3, 3)));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_double_ended_filter() {
+    let xs = [1, 2, 3, 4, 5, 6];
+    let mut it = xs.iter().filter(|&x| *x & 1 == 0);
+    assert_eq!(it.next_back().unwrap(), &6);
+    assert_eq!(it.next_back().unwrap(), &4);
+    assert_eq!(it.next().unwrap(), &2);
+    assert_eq!(it.next_back(), None);
+}
+
+#[test]
+fn test_double_ended_filter_map() {
+    let xs = [1, 2, 3, 4, 5, 6];
+    let mut it = xs.iter().filter_map(|&x| if x & 1 == 0 { Some(x * 2) } else { None });
+    assert_eq!(it.next_back().unwrap(), 12);
+    assert_eq!(it.next_back().unwrap(), 8);
+    assert_eq!(it.next().unwrap(), 4);
+    assert_eq!(it.next_back(), None);
+}
+
+#[test]
+fn test_double_ended_chain() {
+    let xs = [1, 2, 3, 4, 5];
+    let ys = [7, 9, 11];
+    let mut it = xs.iter().chain(&ys).rev();
+    assert_eq!(it.next().unwrap(), &11);
+    assert_eq!(it.next().unwrap(), &9);
+    assert_eq!(it.next_back().unwrap(), &1);
+    assert_eq!(it.next_back().unwrap(), &2);
+    assert_eq!(it.next_back().unwrap(), &3);
+    assert_eq!(it.next_back().unwrap(), &4);
+    assert_eq!(it.next_back().unwrap(), &5);
+    assert_eq!(it.next_back().unwrap(), &7);
+    assert_eq!(it.next_back(), None);
+
+    // test that .chain() is well behaved with an unfused iterator
+    struct CrazyIterator(bool);
+    impl CrazyIterator {
+        fn new() -> CrazyIterator {
+            CrazyIterator(false)
+        }
+    }
+    impl Iterator for CrazyIterator {
+        type Item = i32;
+        fn next(&mut self) -> Option<i32> {
+            if self.0 {
+                Some(99)
+            } else {
+                self.0 = true;
+                None
+            }
+        }
+    }
+
+    impl DoubleEndedIterator for CrazyIterator {
+        fn next_back(&mut self) -> Option<i32> {
+            self.next()
+        }
+    }
+
+    assert_eq!(CrazyIterator::new().chain(0..10).rev().last(), Some(0));
+    assert!((0..10).chain(CrazyIterator::new()).rev().any(|i| i == 0));
+}
+
+#[test]
+fn test_rposition() {
+    fn f(xy: &(isize, char)) -> bool {
+        let (_x, y) = *xy;
+        y == 'b'
+    }
+    fn g(xy: &(isize, char)) -> bool {
+        let (_x, y) = *xy;
+        y == 'd'
+    }
+    let v = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')];
+
+    assert_eq!(v.iter().rposition(f), Some(3));
+    assert!(v.iter().rposition(g).is_none());
+}
+
+#[test]
+fn test_rev_rposition() {
+    let v = [0, 0, 1, 1];
+    assert_eq!(v.iter().rev().rposition(|&x| x == 1), Some(1));
+}
+
+#[test]
+#[should_panic]
+fn test_rposition_panic() {
+    let v: [(Box<_>, Box<_>); 4] = [(box 0, box 0), (box 0, box 0), (box 0, box 0), (box 0, box 0)];
+    let mut i = 0;
+    v.iter().rposition(|_elt| {
+        if i == 2 {
+            panic!()
+        }
+        i += 1;
+        false
+    });
+}
+
+#[test]
+fn test_double_ended_flat_map() {
+    let u = [0, 1];
+    let v = [5, 6, 7, 8];
+    let mut it = u.iter().flat_map(|x| &v[*x..v.len()]);
+    assert_eq!(it.next_back().unwrap(), &8);
+    assert_eq!(it.next().unwrap(), &5);
+    assert_eq!(it.next_back().unwrap(), &7);
+    assert_eq!(it.next_back().unwrap(), &6);
+    assert_eq!(it.next_back().unwrap(), &8);
+    assert_eq!(it.next().unwrap(), &6);
+    assert_eq!(it.next_back().unwrap(), &7);
+    assert_eq!(it.next_back(), None);
+    assert_eq!(it.next(), None);
+    assert_eq!(it.next_back(), None);
+}
+
+#[test]
+fn test_double_ended_flatten() {
+    let u = [0, 1];
+    let v = [5, 6, 7, 8];
+    let mut it = u.iter().map(|x| &v[*x..v.len()]).flatten();
+    assert_eq!(it.next_back().unwrap(), &8);
+    assert_eq!(it.next().unwrap(), &5);
+    assert_eq!(it.next_back().unwrap(), &7);
+    assert_eq!(it.next_back().unwrap(), &6);
+    assert_eq!(it.next_back().unwrap(), &8);
+    assert_eq!(it.next().unwrap(), &6);
+    assert_eq!(it.next_back().unwrap(), &7);
+    assert_eq!(it.next_back(), None);
+    assert_eq!(it.next(), None);
+    assert_eq!(it.next_back(), None);
+}
+
+#[test]
+fn test_double_ended_range() {
+    assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);
+    for _ in (10..0).rev() {
+        panic!("unreachable");
+    }
+
+    assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);
+    for _ in (10..0).rev() {
+        panic!("unreachable");
+    }
+}
+
+#[test]
+fn test_range() {
+    assert_eq!((0..5).collect::<Vec<_>>(), [0, 1, 2, 3, 4]);
+    assert_eq!((-10..-1).collect::<Vec<_>>(), [-10, -9, -8, -7, -6, -5, -4, -3, -2]);
+    assert_eq!((0..5).rev().collect::<Vec<_>>(), [4, 3, 2, 1, 0]);
+    assert_eq!((200..-5).count(), 0);
+    assert_eq!((200..-5).rev().count(), 0);
+    assert_eq!((200..200).count(), 0);
+    assert_eq!((200..200).rev().count(), 0);
+
+    assert_eq!((0..100).size_hint(), (100, Some(100)));
+    // this test is only meaningful when sizeof usize < sizeof u64
+    assert_eq!((usize::MAX - 1..usize::MAX).size_hint(), (1, Some(1)));
+    assert_eq!((-10..-1).size_hint(), (9, Some(9)));
+    assert_eq!((-1..-10).size_hint(), (0, Some(0)));
+
+    assert_eq!((-70..58).size_hint(), (128, Some(128)));
+    assert_eq!((-128..127).size_hint(), (255, Some(255)));
+    assert_eq!(
+        (-2..isize::MAX).size_hint(),
+        (isize::MAX as usize + 2, Some(isize::MAX as usize + 2))
+    );
+}
+
+#[test]
+fn test_char_range() {
+    use std::char;
+    // Miri is too slow
+    let from = if cfg!(miri) { char::from_u32(0xD800 - 10).unwrap() } else { '\0' };
+    let to = if cfg!(miri) { char::from_u32(0xDFFF + 10).unwrap() } else { char::MAX };
+    assert!((from..=to).eq((from as u32..=to as u32).filter_map(char::from_u32)));
+    assert!((from..=to).rev().eq((from as u32..=to as u32).filter_map(char::from_u32).rev()));
+
+    assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2);
+    assert_eq!(('\u{D7FF}'..='\u{E000}').size_hint(), (2, Some(2)));
+    assert_eq!(('\u{D7FF}'..'\u{E000}').count(), 1);
+    assert_eq!(('\u{D7FF}'..'\u{E000}').size_hint(), (1, Some(1)));
+}
+
+#[test]
+fn test_range_exhaustion() {
+    let mut r = 10..10;
+    assert!(r.is_empty());
+    assert_eq!(r.next(), None);
+    assert_eq!(r.next_back(), None);
+    assert_eq!(r, 10..10);
+
+    let mut r = 10..12;
+    assert_eq!(r.next(), Some(10));
+    assert_eq!(r.next(), Some(11));
+    assert!(r.is_empty());
+    assert_eq!(r, 12..12);
+    assert_eq!(r.next(), None);
+
+    let mut r = 10..12;
+    assert_eq!(r.next_back(), Some(11));
+    assert_eq!(r.next_back(), Some(10));
+    assert!(r.is_empty());
+    assert_eq!(r, 10..10);
+    assert_eq!(r.next_back(), None);
+
+    let mut r = 100..10;
+    assert!(r.is_empty());
+    assert_eq!(r.next(), None);
+    assert_eq!(r.next_back(), None);
+    assert_eq!(r, 100..10);
+}
+
+#[test]
+fn test_range_inclusive_exhaustion() {
+    let mut r = 10..=10;
+    assert_eq!(r.next(), Some(10));
+    assert!(r.is_empty());
+    assert_eq!(r.next(), None);
+    assert_eq!(r.next(), None);
+
+    assert_eq!(*r.start(), 10);
+    assert_eq!(*r.end(), 10);
+    assert_ne!(r, 10..=10);
+
+    let mut r = 10..=10;
+    assert_eq!(r.next_back(), Some(10));
+    assert!(r.is_empty());
+    assert_eq!(r.next_back(), None);
+
+    assert_eq!(*r.start(), 10);
+    assert_eq!(*r.end(), 10);
+    assert_ne!(r, 10..=10);
+
+    let mut r = 10..=12;
+    assert_eq!(r.next(), Some(10));
+    assert_eq!(r.next(), Some(11));
+    assert_eq!(r.next(), Some(12));
+    assert!(r.is_empty());
+    assert_eq!(r.next(), None);
+
+    let mut r = 10..=12;
+    assert_eq!(r.next_back(), Some(12));
+    assert_eq!(r.next_back(), Some(11));
+    assert_eq!(r.next_back(), Some(10));
+    assert!(r.is_empty());
+    assert_eq!(r.next_back(), None);
+
+    let mut r = 10..=12;
+    assert_eq!(r.nth(2), Some(12));
+    assert!(r.is_empty());
+    assert_eq!(r.next(), None);
+
+    let mut r = 10..=12;
+    assert_eq!(r.nth(5), None);
+    assert!(r.is_empty());
+    assert_eq!(r.next(), None);
+
+    let mut r = 100..=10;
+    assert_eq!(r.next(), None);
+    assert!(r.is_empty());
+    assert_eq!(r.next(), None);
+    assert_eq!(r.next(), None);
+    assert_eq!(r, 100..=10);
+
+    let mut r = 100..=10;
+    assert_eq!(r.next_back(), None);
+    assert!(r.is_empty());
+    assert_eq!(r.next_back(), None);
+    assert_eq!(r.next_back(), None);
+    assert_eq!(r, 100..=10);
+}
+
+#[test]
+fn test_range_nth() {
+    assert_eq!((10..15).nth(0), Some(10));
+    assert_eq!((10..15).nth(1), Some(11));
+    assert_eq!((10..15).nth(4), Some(14));
+    assert_eq!((10..15).nth(5), None);
+
+    let mut r = 10..20;
+    assert_eq!(r.nth(2), Some(12));
+    assert_eq!(r, 13..20);
+    assert_eq!(r.nth(2), Some(15));
+    assert_eq!(r, 16..20);
+    assert_eq!(r.nth(10), None);
+    assert_eq!(r, 20..20);
+}
+
+#[test]
+fn test_range_nth_back() {
+    assert_eq!((10..15).nth_back(0), Some(14));
+    assert_eq!((10..15).nth_back(1), Some(13));
+    assert_eq!((10..15).nth_back(4), Some(10));
+    assert_eq!((10..15).nth_back(5), None);
+    assert_eq!((-120..80_i8).nth_back(199), Some(-120));
+
+    let mut r = 10..20;
+    assert_eq!(r.nth_back(2), Some(17));
+    assert_eq!(r, 10..17);
+    assert_eq!(r.nth_back(2), Some(14));
+    assert_eq!(r, 10..14);
+    assert_eq!(r.nth_back(10), None);
+    assert_eq!(r, 10..10);
+}
+
+#[test]
+fn test_range_from_nth() {
+    assert_eq!((10..).nth(0), Some(10));
+    assert_eq!((10..).nth(1), Some(11));
+    assert_eq!((10..).nth(4), Some(14));
+
+    let mut r = 10..;
+    assert_eq!(r.nth(2), Some(12));
+    assert_eq!(r, 13..);
+    assert_eq!(r.nth(2), Some(15));
+    assert_eq!(r, 16..);
+    assert_eq!(r.nth(10), Some(26));
+    assert_eq!(r, 27..);
+
+    assert_eq!((0..).size_hint(), (usize::MAX, None));
+}
+
+fn is_trusted_len<I: TrustedLen>(_: I) {}
+
+#[test]
+fn test_range_from_take() {
+    let mut it = (0..).take(3);
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.next(), Some(1));
+    assert_eq!(it.next(), Some(2));
+    assert_eq!(it.next(), None);
+    is_trusted_len((0..).take(3));
+    assert_eq!((0..).take(3).size_hint(), (3, Some(3)));
+    assert_eq!((0..).take(0).size_hint(), (0, Some(0)));
+    assert_eq!((0..).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
+}
+
+#[test]
+fn test_range_from_take_collect() {
+    let v: Vec<_> = (0..).take(3).collect();
+    assert_eq!(v, vec![0, 1, 2]);
+}
+
+#[test]
+fn test_range_inclusive_nth() {
+    assert_eq!((10..=15).nth(0), Some(10));
+    assert_eq!((10..=15).nth(1), Some(11));
+    assert_eq!((10..=15).nth(5), Some(15));
+    assert_eq!((10..=15).nth(6), None);
+
+    let mut exhausted_via_next = 10_u8..=20;
+    while exhausted_via_next.next().is_some() {}
+
+    let mut r = 10_u8..=20;
+    assert_eq!(r.nth(2), Some(12));
+    assert_eq!(r, 13..=20);
+    assert_eq!(r.nth(2), Some(15));
+    assert_eq!(r, 16..=20);
+    assert_eq!(r.is_empty(), false);
+    assert_eq!(ExactSizeIterator::is_empty(&r), false);
+    assert_eq!(r.nth(10), None);
+    assert_eq!(r.is_empty(), true);
+    assert_eq!(r, exhausted_via_next);
+    assert_eq!(ExactSizeIterator::is_empty(&r), true);
+}
+
+#[test]
+fn test_range_inclusive_nth_back() {
+    assert_eq!((10..=15).nth_back(0), Some(15));
+    assert_eq!((10..=15).nth_back(1), Some(14));
+    assert_eq!((10..=15).nth_back(5), Some(10));
+    assert_eq!((10..=15).nth_back(6), None);
+    assert_eq!((-120..=80_i8).nth_back(200), Some(-120));
+
+    let mut exhausted_via_next_back = 10_u8..=20;
+    while exhausted_via_next_back.next_back().is_some() {}
+
+    let mut r = 10_u8..=20;
+    assert_eq!(r.nth_back(2), Some(18));
+    assert_eq!(r, 10..=17);
+    assert_eq!(r.nth_back(2), Some(15));
+    assert_eq!(r, 10..=14);
+    assert_eq!(r.is_empty(), false);
+    assert_eq!(ExactSizeIterator::is_empty(&r), false);
+    assert_eq!(r.nth_back(10), None);
+    assert_eq!(r.is_empty(), true);
+    assert_eq!(r, exhausted_via_next_back);
+    assert_eq!(ExactSizeIterator::is_empty(&r), true);
+}
+
+#[test]
+fn test_range_len() {
+    assert_eq!((0..10_u8).len(), 10);
+    assert_eq!((9..10_u8).len(), 1);
+    assert_eq!((10..10_u8).len(), 0);
+    assert_eq!((11..10_u8).len(), 0);
+    assert_eq!((100..10_u8).len(), 0);
+}
+
+#[test]
+fn test_range_inclusive_len() {
+    assert_eq!((0..=10_u8).len(), 11);
+    assert_eq!((9..=10_u8).len(), 2);
+    assert_eq!((10..=10_u8).len(), 1);
+    assert_eq!((11..=10_u8).len(), 0);
+    assert_eq!((100..=10_u8).len(), 0);
+}
+
+#[test]
+fn test_range_step() {
+    #![allow(deprecated)]
+
+    assert_eq!((0..20).step_by(5).collect::<Vec<isize>>(), [0, 5, 10, 15]);
+    assert_eq!((1..21).rev().step_by(5).collect::<Vec<isize>>(), [20, 15, 10, 5]);
+    assert_eq!((1..21).rev().step_by(6).collect::<Vec<isize>>(), [20, 14, 8, 2]);
+    assert_eq!((200..255).step_by(50).collect::<Vec<u8>>(), [200, 250]);
+    assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []);
+    assert_eq!((200..200).step_by(1).collect::<Vec<isize>>(), []);
+
+    assert_eq!((0..20).step_by(1).size_hint(), (20, Some(20)));
+    assert_eq!((0..20).step_by(21).size_hint(), (1, Some(1)));
+    assert_eq!((0..20).step_by(5).size_hint(), (4, Some(4)));
+    assert_eq!((1..21).rev().step_by(5).size_hint(), (4, Some(4)));
+    assert_eq!((1..21).rev().step_by(6).size_hint(), (4, Some(4)));
+    assert_eq!((20..-5).step_by(1).size_hint(), (0, Some(0)));
+    assert_eq!((20..20).step_by(1).size_hint(), (0, Some(0)));
+    assert_eq!((i8::MIN..i8::MAX).step_by(-(i8::MIN as i32) as usize).size_hint(), (2, Some(2)));
+    assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX as usize).size_hint(), (3, Some(3)));
+    assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX)));
+}
+
+#[test]
+fn test_step_by_skip() {
+    assert_eq!((0..640).step_by(128).skip(1).collect::<Vec<_>>(), [128, 256, 384, 512]);
+    assert_eq!((0..=50).step_by(10).nth(3), Some(30));
+    assert_eq!((200..=255u8).step_by(10).nth(3), Some(230));
+}
+
+#[test]
+fn test_range_inclusive_step() {
+    assert_eq!((0..=50).step_by(10).collect::<Vec<_>>(), [0, 10, 20, 30, 40, 50]);
+    assert_eq!((0..=5).step_by(1).collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5]);
+    assert_eq!((200..=255u8).step_by(10).collect::<Vec<_>>(), [200, 210, 220, 230, 240, 250]);
+    assert_eq!((250..=255u8).step_by(1).collect::<Vec<_>>(), [250, 251, 252, 253, 254, 255]);
+}
+
+#[test]
+fn test_range_last_max() {
+    assert_eq!((0..20).last(), Some(19));
+    assert_eq!((-20..0).last(), Some(-1));
+    assert_eq!((5..5).last(), None);
+
+    assert_eq!((0..20).max(), Some(19));
+    assert_eq!((-20..0).max(), Some(-1));
+    assert_eq!((5..5).max(), None);
+}
+
+#[test]
+fn test_range_inclusive_last_max() {
+    assert_eq!((0..=20).last(), Some(20));
+    assert_eq!((-20..=0).last(), Some(0));
+    assert_eq!((5..=5).last(), Some(5));
+    let mut r = 10..=10;
+    r.next();
+    assert_eq!(r.last(), None);
+
+    assert_eq!((0..=20).max(), Some(20));
+    assert_eq!((-20..=0).max(), Some(0));
+    assert_eq!((5..=5).max(), Some(5));
+    let mut r = 10..=10;
+    r.next();
+    assert_eq!(r.max(), None);
+}
+
+#[test]
+fn test_range_min() {
+    assert_eq!((0..20).min(), Some(0));
+    assert_eq!((-20..0).min(), Some(-20));
+    assert_eq!((5..5).min(), None);
+}
+
+#[test]
+fn test_range_inclusive_min() {
+    assert_eq!((0..=20).min(), Some(0));
+    assert_eq!((-20..=0).min(), Some(-20));
+    assert_eq!((5..=5).min(), Some(5));
+    let mut r = 10..=10;
+    r.next();
+    assert_eq!(r.min(), None);
+}
+
+#[test]
+fn test_range_inclusive_folds() {
+    assert_eq!((1..=10).sum::<i32>(), 55);
+    assert_eq!((1..=10).rev().sum::<i32>(), 55);
+
+    let mut it = 44..=50;
+    assert_eq!(it.try_fold(0, i8::checked_add), None);
+    assert_eq!(it, 47..=50);
+    assert_eq!(it.try_fold(0, i8::checked_add), None);
+    assert_eq!(it, 50..=50);
+    assert_eq!(it.try_fold(0, i8::checked_add), Some(50));
+    assert!(it.is_empty());
+    assert_eq!(it.try_fold(0, i8::checked_add), Some(0));
+    assert!(it.is_empty());
+
+    let mut it = 40..=47;
+    assert_eq!(it.try_rfold(0, i8::checked_add), None);
+    assert_eq!(it, 40..=44);
+    assert_eq!(it.try_rfold(0, i8::checked_add), None);
+    assert_eq!(it, 40..=41);
+    assert_eq!(it.try_rfold(0, i8::checked_add), Some(81));
+    assert!(it.is_empty());
+    assert_eq!(it.try_rfold(0, i8::checked_add), Some(0));
+    assert!(it.is_empty());
+
+    let mut it = 10..=20;
+    assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(165));
+    assert!(it.is_empty());
+    assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(0));
+    assert!(it.is_empty());
+
+    let mut it = 10..=20;
+    assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(165));
+    assert!(it.is_empty());
+    assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(0));
+    assert!(it.is_empty());
+}
+
+#[test]
+fn test_range_size_hint() {
+    assert_eq!((0..0usize).size_hint(), (0, Some(0)));
+    assert_eq!((0..100usize).size_hint(), (100, Some(100)));
+    assert_eq!((0..usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
+
+    let umax = u128::try_from(usize::MAX).unwrap();
+    assert_eq!((0..0u128).size_hint(), (0, Some(0)));
+    assert_eq!((0..100u128).size_hint(), (100, Some(100)));
+    assert_eq!((0..umax).size_hint(), (usize::MAX, Some(usize::MAX)));
+    assert_eq!((0..umax + 1).size_hint(), (usize::MAX, None));
+
+    assert_eq!((0..0isize).size_hint(), (0, Some(0)));
+    assert_eq!((-100..100isize).size_hint(), (200, Some(200)));
+    assert_eq!((isize::MIN..isize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
+
+    let imin = i128::try_from(isize::MIN).unwrap();
+    let imax = i128::try_from(isize::MAX).unwrap();
+    assert_eq!((0..0i128).size_hint(), (0, Some(0)));
+    assert_eq!((-100..100i128).size_hint(), (200, Some(200)));
+    assert_eq!((imin..imax).size_hint(), (usize::MAX, Some(usize::MAX)));
+    assert_eq!((imin..imax + 1).size_hint(), (usize::MAX, None));
+}
+
+#[test]
+fn test_range_inclusive_size_hint() {
+    assert_eq!((1..=0usize).size_hint(), (0, Some(0)));
+    assert_eq!((0..=0usize).size_hint(), (1, Some(1)));
+    assert_eq!((0..=100usize).size_hint(), (101, Some(101)));
+    assert_eq!((0..=usize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
+    assert_eq!((0..=usize::MAX).size_hint(), (usize::MAX, None));
+
+    let umax = u128::try_from(usize::MAX).unwrap();
+    assert_eq!((1..=0u128).size_hint(), (0, Some(0)));
+    assert_eq!((0..=0u128).size_hint(), (1, Some(1)));
+    assert_eq!((0..=100u128).size_hint(), (101, Some(101)));
+    assert_eq!((0..=umax - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
+    assert_eq!((0..=umax).size_hint(), (usize::MAX, None));
+    assert_eq!((0..=umax + 1).size_hint(), (usize::MAX, None));
+
+    assert_eq!((0..=-1isize).size_hint(), (0, Some(0)));
+    assert_eq!((0..=0isize).size_hint(), (1, Some(1)));
+    assert_eq!((-100..=100isize).size_hint(), (201, Some(201)));
+    assert_eq!((isize::MIN..=isize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
+    assert_eq!((isize::MIN..=isize::MAX).size_hint(), (usize::MAX, None));
+
+    let imin = i128::try_from(isize::MIN).unwrap();
+    let imax = i128::try_from(isize::MAX).unwrap();
+    assert_eq!((0..=-1i128).size_hint(), (0, Some(0)));
+    assert_eq!((0..=0i128).size_hint(), (1, Some(1)));
+    assert_eq!((-100..=100i128).size_hint(), (201, Some(201)));
+    assert_eq!((imin..=imax - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
+    assert_eq!((imin..=imax).size_hint(), (usize::MAX, None));
+    assert_eq!((imin..=imax + 1).size_hint(), (usize::MAX, None));
+}
+
+#[test]
+fn test_repeat() {
+    let mut it = repeat(42);
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(repeat(42).size_hint(), (usize::MAX, None));
+}
+
+#[test]
+fn test_repeat_take() {
+    let mut it = repeat(42).take(3);
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), None);
+    is_trusted_len(repeat(42).take(3));
+    assert_eq!(repeat(42).take(3).size_hint(), (3, Some(3)));
+    assert_eq!(repeat(42).take(0).size_hint(), (0, Some(0)));
+    assert_eq!(repeat(42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
+}
+
+#[test]
+fn test_repeat_take_collect() {
+    let v: Vec<_> = repeat(42).take(3).collect();
+    assert_eq!(v, vec![42, 42, 42]);
+}
+
+#[test]
+fn test_repeat_with() {
+    #[derive(PartialEq, Debug)]
+    struct NotClone(usize);
+    let mut it = repeat_with(|| NotClone(42));
+    assert_eq!(it.next(), Some(NotClone(42)));
+    assert_eq!(it.next(), Some(NotClone(42)));
+    assert_eq!(it.next(), Some(NotClone(42)));
+    assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None));
+}
+
+#[test]
+fn test_repeat_with_take() {
+    let mut it = repeat_with(|| 42).take(3);
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), None);
+    is_trusted_len(repeat_with(|| 42).take(3));
+    assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3)));
+    assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0)));
+    assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
+}
+
+#[test]
+fn test_repeat_with_take_collect() {
+    let mut curr = 1;
+    let v: Vec<_> = repeat_with(|| {
+        let tmp = curr;
+        curr *= 2;
+        tmp
+    })
+    .take(5)
+    .collect();
+    assert_eq!(v, vec![1, 2, 4, 8, 16]);
+}
+
+#[test]
+fn test_successors() {
+    let mut powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10));
+    assert_eq!(powers_of_10.by_ref().collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]);
+    assert_eq!(powers_of_10.next(), None);
+
+    let mut empty = successors(None::<u32>, |_| unimplemented!());
+    assert_eq!(empty.next(), None);
+    assert_eq!(empty.next(), None);
+}
+
+#[test]
+fn test_fuse() {
+    let mut it = 0..3;
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.next(), Some(0));
+    assert_eq!(it.len(), 2);
+    assert_eq!(it.next(), Some(1));
+    assert_eq!(it.len(), 1);
+    assert_eq!(it.next(), Some(2));
+    assert_eq!(it.len(), 0);
+    assert_eq!(it.next(), None);
+    assert_eq!(it.len(), 0);
+    assert_eq!(it.next(), None);
+    assert_eq!(it.len(), 0);
+    assert_eq!(it.next(), None);
+    assert_eq!(it.len(), 0);
+}
+
+#[test]
+fn test_fuse_nth() {
+    let xs = [0, 1, 2];
+    let mut it = xs.iter();
+
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.nth(2), Some(&2));
+    assert_eq!(it.len(), 0);
+    assert_eq!(it.nth(2), None);
+    assert_eq!(it.len(), 0);
+}
+
+#[test]
+fn test_fuse_last() {
+    let xs = [0, 1, 2];
+    let it = xs.iter();
+
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.last(), Some(&2));
+}
+
+#[test]
+fn test_fuse_count() {
+    let xs = [0, 1, 2];
+    let it = xs.iter();
+
+    assert_eq!(it.len(), 3);
+    assert_eq!(it.count(), 3);
+    // Can't check len now because count consumes.
+}
+
+#[test]
+fn test_fuse_fold() {
+    let xs = [0, 1, 2];
+    let it = xs.iter(); // `FusedIterator`
+    let i = it.fuse().fold(0, |i, &x| {
+        assert_eq!(x, xs[i]);
+        i + 1
+    });
+    assert_eq!(i, xs.len());
+
+    let it = xs.iter(); // `FusedIterator`
+    let i = it.fuse().rfold(xs.len(), |i, &x| {
+        assert_eq!(x, xs[i - 1]);
+        i - 1
+    });
+    assert_eq!(i, 0);
+
+    let it = xs.iter().scan((), |_, &x| Some(x)); // `!FusedIterator`
+    let i = it.fuse().fold(0, |i, x| {
+        assert_eq!(x, xs[i]);
+        i + 1
+    });
+    assert_eq!(i, xs.len());
+}
+
+#[test]
+fn test_once() {
+    let mut it = once(42);
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_once_with() {
+    let count = Cell::new(0);
+    let mut it = once_with(|| {
+        count.set(count.get() + 1);
+        42
+    });
+
+    assert_eq!(count.get(), 0);
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(count.get(), 1);
+    assert_eq!(it.next(), None);
+    assert_eq!(count.get(), 1);
+    assert_eq!(it.next(), None);
+    assert_eq!(count.get(), 1);
+}
+
+#[test]
+fn test_empty() {
+    let mut it = empty::<i32>();
+    assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_chain_fold() {
+    let xs = [1, 2, 3];
+    let ys = [1, 2, 0];
+
+    let mut iter = xs.iter().chain(&ys);
+    iter.next();
+    let mut result = Vec::new();
+    iter.fold((), |(), &elt| result.push(elt));
+    assert_eq!(&[2, 3, 1, 2, 0], &result[..]);
+}
+
+#[test]
+fn test_steps_between() {
+    assert_eq!(Step::steps_between(&20_u8, &200_u8), Some(180_usize));
+    assert_eq!(Step::steps_between(&-20_i8, &80_i8), Some(100_usize));
+    assert_eq!(Step::steps_between(&-120_i8, &80_i8), Some(200_usize));
+    assert_eq!(Step::steps_between(&20_u32, &4_000_100_u32), Some(4_000_080_usize));
+    assert_eq!(Step::steps_between(&-20_i32, &80_i32), Some(100_usize));
+    assert_eq!(Step::steps_between(&-2_000_030_i32, &2_000_050_i32), Some(4_000_080_usize));
+
+    // Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms
+
+    assert_eq!(Step::steps_between(&20_u128, &200_u128), Some(180_usize));
+    assert_eq!(Step::steps_between(&-20_i128, &80_i128), Some(100_usize));
+    if cfg!(target_pointer_width = "64") {
+        assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), Some(usize::MAX));
+    }
+    assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), None);
+    assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), None);
+    assert_eq!(
+        Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,),
+        None,
+    );
+}
+
+#[test]
+fn test_step_forward() {
+    assert_eq!(Step::forward_checked(55_u8, 200_usize), Some(255_u8));
+    assert_eq!(Step::forward_checked(252_u8, 200_usize), None);
+    assert_eq!(Step::forward_checked(0_u8, 256_usize), None);
+    assert_eq!(Step::forward_checked(-110_i8, 200_usize), Some(90_i8));
+    assert_eq!(Step::forward_checked(-110_i8, 248_usize), None);
+    assert_eq!(Step::forward_checked(-126_i8, 256_usize), None);
+
+    assert_eq!(Step::forward_checked(35_u16, 100_usize), Some(135_u16));
+    assert_eq!(Step::forward_checked(35_u16, 65500_usize), Some(u16::MAX));
+    assert_eq!(Step::forward_checked(36_u16, 65500_usize), None);
+    assert_eq!(Step::forward_checked(-110_i16, 200_usize), Some(90_i16));
+    assert_eq!(Step::forward_checked(-20_030_i16, 50_050_usize), Some(30_020_i16));
+    assert_eq!(Step::forward_checked(-10_i16, 40_000_usize), None);
+    assert_eq!(Step::forward_checked(-10_i16, 70_000_usize), None);
+
+    assert_eq!(Step::forward_checked(10_u128, 70_000_usize), Some(70_010_u128));
+    assert_eq!(Step::forward_checked(10_i128, 70_030_usize), Some(70_040_i128));
+    assert_eq!(
+        Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0xff_usize),
+        Some(u128::MAX),
+    );
+    assert_eq!(
+        Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0x100_usize),
+        None
+    );
+    assert_eq!(
+        Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0xff_usize),
+        Some(i128::MAX),
+    );
+    assert_eq!(
+        Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize),
+        None
+    );
+}
+
+#[test]
+fn test_step_backward() {
+    assert_eq!(Step::backward_checked(255_u8, 200_usize), Some(55_u8));
+    assert_eq!(Step::backward_checked(100_u8, 200_usize), None);
+    assert_eq!(Step::backward_checked(255_u8, 256_usize), None);
+    assert_eq!(Step::backward_checked(90_i8, 200_usize), Some(-110_i8));
+    assert_eq!(Step::backward_checked(110_i8, 248_usize), None);
+    assert_eq!(Step::backward_checked(127_i8, 256_usize), None);
+
+    assert_eq!(Step::backward_checked(135_u16, 100_usize), Some(35_u16));
+    assert_eq!(Step::backward_checked(u16::MAX, 65500_usize), Some(35_u16));
+    assert_eq!(Step::backward_checked(10_u16, 11_usize), None);
+    assert_eq!(Step::backward_checked(90_i16, 200_usize), Some(-110_i16));
+    assert_eq!(Step::backward_checked(30_020_i16, 50_050_usize), Some(-20_030_i16));
+    assert_eq!(Step::backward_checked(-10_i16, 40_000_usize), None);
+    assert_eq!(Step::backward_checked(-10_i16, 70_000_usize), None);
+
+    assert_eq!(Step::backward_checked(70_010_u128, 70_000_usize), Some(10_u128));
+    assert_eq!(Step::backward_checked(70_020_i128, 70_030_usize), Some(-10_i128));
+    assert_eq!(Step::backward_checked(10_u128, 7_usize), Some(3_u128));
+    assert_eq!(Step::backward_checked(10_u128, 11_usize), None);
+    assert_eq!(
+        Step::backward_checked(-0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize),
+        Some(i128::MIN)
+    );
+}
+
+#[test]
+fn test_rev_try_folds() {
+    let f = &|acc, x| i32::checked_add(2 * acc, x);
+    assert_eq!((1..10).rev().try_fold(7, f), (1..10).try_rfold(7, f));
+    assert_eq!((1..10).rev().try_rfold(7, f), (1..10).try_fold(7, f));
+
+    let a = [10, 20, 30, 40, 100, 60, 70, 80, 90];
+    let mut iter = a.iter().rev();
+    assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None);
+    assert_eq!(iter.next(), Some(&70));
+    let mut iter = a.iter().rev();
+    assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None);
+    assert_eq!(iter.next_back(), Some(&60));
+}
+
+#[test]
+fn test_cloned_try_folds() {
+    let a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
+    let f = &|acc, x| i32::checked_add(2 * acc, x);
+    let f_ref = &|acc, &x| i32::checked_add(2 * acc, x);
+    assert_eq!(a.iter().cloned().try_fold(7, f), a.iter().try_fold(7, f_ref));
+    assert_eq!(a.iter().cloned().try_rfold(7, f), a.iter().try_rfold(7, f_ref));
+
+    let a = [10, 20, 30, 40, 100, 60, 70, 80, 90];
+    let mut iter = a.iter().cloned();
+    assert_eq!(iter.try_fold(0_i8, |acc, x| acc.checked_add(x)), None);
+    assert_eq!(iter.next(), Some(60));
+    let mut iter = a.iter().cloned();
+    assert_eq!(iter.try_rfold(0_i8, |acc, x| acc.checked_add(x)), None);
+    assert_eq!(iter.next_back(), Some(70));
+}
+
+#[test]
+fn test_chain_try_folds() {
+    let c = || (0..10).chain(10..20);
+
+    let f = &|acc, x| i32::checked_add(2 * acc, x);
+    assert_eq!(c().try_fold(7, f), (0..20).try_fold(7, f));
+    assert_eq!(c().try_rfold(7, f), (0..20).rev().try_fold(7, f));
+
+    let mut iter = c();
+    assert_eq!(iter.position(|x| x == 5), Some(5));
+    assert_eq!(iter.next(), Some(6), "stopped in front, state Both");
+    assert_eq!(iter.position(|x| x == 13), Some(6));
+    assert_eq!(iter.next(), Some(14), "stopped in back, state Back");
+    assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((15..20).sum()));
+
+    let mut iter = c().rev(); // use rev to access try_rfold
+    assert_eq!(iter.position(|x| x == 15), Some(4));
+    assert_eq!(iter.next(), Some(14), "stopped in back, state Both");
+    assert_eq!(iter.position(|x| x == 5), Some(8));
+    assert_eq!(iter.next(), Some(4), "stopped in front, state Front");
+    assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((0..4).sum()));
+
+    let mut iter = c();
+    iter.by_ref().rev().nth(14); // skip the last 15, ending in state Front
+    assert_eq!(iter.try_fold(7, f), (0..5).try_fold(7, f));
+
+    let mut iter = c();
+    iter.nth(14); // skip the first 15, ending in state Back
+    assert_eq!(iter.try_rfold(7, f), (15..20).try_rfold(7, f));
+}
+
+#[test]
+fn test_map_try_folds() {
+    let f = &|acc, x| i32::checked_add(2 * acc, x);
+    assert_eq!((0..10).map(|x| x + 3).try_fold(7, f), (3..13).try_fold(7, f));
+    assert_eq!((0..10).map(|x| x + 3).try_rfold(7, f), (3..13).try_rfold(7, f));
+
+    let mut iter = (0..40).map(|x| x + 10);
+    assert_eq!(iter.try_fold(0, i8::checked_add), None);
+    assert_eq!(iter.next(), Some(20));
+    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+    assert_eq!(iter.next_back(), Some(46));
+}
+
+#[test]
+fn test_filter_try_folds() {
+    fn p(&x: &i32) -> bool {
+        0 <= x && x < 10
+    }
+    let f = &|acc, x| i32::checked_add(2 * acc, x);
+    assert_eq!((-10..20).filter(p).try_fold(7, f), (0..10).try_fold(7, f));
+    assert_eq!((-10..20).filter(p).try_rfold(7, f), (0..10).try_rfold(7, f));
+
+    let mut iter = (0..40).filter(|&x| x % 2 == 1);
+    assert_eq!(iter.try_fold(0, i8::checked_add), None);
+    assert_eq!(iter.next(), Some(25));
+    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+    assert_eq!(iter.next_back(), Some(31));
+}
+
+#[test]
+fn test_filter_map_try_folds() {
+    let mp = &|x| if 0 <= x && x < 10 { Some(x * 2) } else { None };
+    let f = &|acc, x| i32::checked_add(2 * acc, x);
+    assert_eq!((-9..20).filter_map(mp).try_fold(7, f), (0..10).map(|x| 2 * x).try_fold(7, f));
+    assert_eq!((-9..20).filter_map(mp).try_rfold(7, f), (0..10).map(|x| 2 * x).try_rfold(7, f));
+
+    let mut iter = (0..40).filter_map(|x| if x % 2 == 1 { None } else { Some(x * 2 + 10) });
+    assert_eq!(iter.try_fold(0, i8::checked_add), None);
+    assert_eq!(iter.next(), Some(38));
+    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+    assert_eq!(iter.next_back(), Some(78));
+}
+
+#[test]
+fn test_enumerate_try_folds() {
+    let f = &|acc, (i, x)| usize::checked_add(2 * acc, x / (i + 1) + i);
+    assert_eq!((9..18).enumerate().try_fold(7, f), (0..9).map(|i| (i, i + 9)).try_fold(7, f));
+    assert_eq!((9..18).enumerate().try_rfold(7, f), (0..9).map(|i| (i, i + 9)).try_rfold(7, f));
+
+    let mut iter = (100..200).enumerate();
+    let f = &|acc, (i, x)| u8::checked_add(acc, u8::checked_div(x, i as u8 + 1)?);
+    assert_eq!(iter.try_fold(0, f), None);
+    assert_eq!(iter.next(), Some((7, 107)));
+    assert_eq!(iter.try_rfold(0, f), None);
+    assert_eq!(iter.next_back(), Some((11, 111)));
+}
+
+#[test]
+fn test_peek_try_folds() {
+    let f = &|acc, x| i32::checked_add(2 * acc, x);
+
+    assert_eq!((1..20).peekable().try_fold(7, f), (1..20).try_fold(7, f));
+    assert_eq!((1..20).peekable().try_rfold(7, f), (1..20).try_rfold(7, f));
+
+    let mut iter = (1..20).peekable();
+    assert_eq!(iter.peek(), Some(&1));
+    assert_eq!(iter.try_fold(7, f), (1..20).try_fold(7, f));
+
+    let mut iter = (1..20).peekable();
+    assert_eq!(iter.peek(), Some(&1));
+    assert_eq!(iter.try_rfold(7, f), (1..20).try_rfold(7, f));
+
+    let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable();
+    assert_eq!(iter.peek(), Some(&100));
+    assert_eq!(iter.try_fold(0, i8::checked_add), None);
+    assert_eq!(iter.peek(), Some(&40));
+
+    let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable();
+    assert_eq!(iter.peek(), Some(&100));
+    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+    assert_eq!(iter.peek(), Some(&100));
+    assert_eq!(iter.next_back(), Some(50));
+
+    let mut iter = (2..5).peekable();
+    assert_eq!(iter.peek(), Some(&2));
+    assert_eq!(iter.try_for_each(Err), Err(2));
+    assert_eq!(iter.peek(), Some(&3));
+    assert_eq!(iter.try_for_each(Err), Err(3));
+    assert_eq!(iter.peek(), Some(&4));
+    assert_eq!(iter.try_for_each(Err), Err(4));
+    assert_eq!(iter.peek(), None);
+    assert_eq!(iter.try_for_each(Err), Ok(()));
+
+    let mut iter = (2..5).peekable();
+    assert_eq!(iter.peek(), Some(&2));
+    assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(4));
+    assert_eq!(iter.peek(), Some(&2));
+    assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(3));
+    assert_eq!(iter.peek(), Some(&2));
+    assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(2));
+    assert_eq!(iter.peek(), None);
+    assert_eq!(iter.try_rfold((), |(), x| Err(x)), Ok(()));
+}
+
+#[test]
+fn test_skip_while_try_fold() {
+    let f = &|acc, x| i32::checked_add(2 * acc, x);
+    fn p(&x: &i32) -> bool {
+        (x % 10) <= 5
+    }
+    assert_eq!((1..20).skip_while(p).try_fold(7, f), (6..20).try_fold(7, f));
+    let mut iter = (1..20).skip_while(p);
+    assert_eq!(iter.nth(5), Some(11));
+    assert_eq!(iter.try_fold(7, f), (12..20).try_fold(7, f));
+
+    let mut iter = (0..50).skip_while(|&x| (x % 20) < 15);
+    assert_eq!(iter.try_fold(0, i8::checked_add), None);
+    assert_eq!(iter.next(), Some(23));
+}
+
+#[test]
+fn test_take_while_folds() {
+    let f = &|acc, x| i32::checked_add(2 * acc, x);
+    assert_eq!((1..20).take_while(|&x| x != 10).try_fold(7, f), (1..10).try_fold(7, f));
+    let mut iter = (1..20).take_while(|&x| x != 10);
+    assert_eq!(iter.try_fold(0, |x, y| Some(x + y)), Some((1..10).sum()));
+    assert_eq!(iter.next(), None, "flag should be set");
+    let iter = (1..20).take_while(|&x| x != 10);
+    assert_eq!(iter.fold(0, |x, y| x + y), (1..10).sum());
+
+    let mut iter = (10..50).take_while(|&x| x != 40);
+    assert_eq!(iter.try_fold(0, i8::checked_add), None);
+    assert_eq!(iter.next(), Some(20));
+}
+
+#[test]
+fn test_skip_try_folds() {
+    let f = &|acc, x| i32::checked_add(2 * acc, x);
+    assert_eq!((1..20).skip(9).try_fold(7, f), (10..20).try_fold(7, f));
+    assert_eq!((1..20).skip(9).try_rfold(7, f), (10..20).try_rfold(7, f));
+
+    let mut iter = (0..30).skip(10);
+    assert_eq!(iter.try_fold(0, i8::checked_add), None);
+    assert_eq!(iter.next(), Some(20));
+    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+    assert_eq!(iter.next_back(), Some(24));
+}
+
+#[test]
+fn test_skip_nth_back() {
+    let xs = [0, 1, 2, 3, 4, 5];
+    let mut it = xs.iter().skip(2);
+    assert_eq!(it.nth_back(0), Some(&5));
+    assert_eq!(it.nth_back(1), Some(&3));
+    assert_eq!(it.nth_back(0), Some(&2));
+    assert_eq!(it.nth_back(0), None);
+
+    let ys = [2, 3, 4, 5];
+    let mut ity = ys.iter();
+    let mut it = xs.iter().skip(2);
+    assert_eq!(it.nth_back(1), ity.nth_back(1));
+    assert_eq!(it.clone().nth(0), ity.clone().nth(0));
+    assert_eq!(it.nth_back(0), ity.nth_back(0));
+    assert_eq!(it.clone().nth(0), ity.clone().nth(0));
+    assert_eq!(it.nth_back(0), ity.nth_back(0));
+    assert_eq!(it.clone().nth(0), ity.clone().nth(0));
+    assert_eq!(it.nth_back(0), ity.nth_back(0));
+    assert_eq!(it.clone().nth(0), ity.clone().nth(0));
+
+    let mut it = xs.iter().skip(2);
+    assert_eq!(it.nth_back(4), None);
+    assert_eq!(it.nth_back(0), None);
+
+    let mut it = xs.iter();
+    it.by_ref().skip(2).nth_back(3);
+    assert_eq!(it.next_back(), Some(&1));
+
+    let mut it = xs.iter();
+    it.by_ref().skip(2).nth_back(10);
+    assert_eq!(it.next_back(), Some(&1));
+}
+
+#[test]
+fn test_take_try_folds() {
+    let f = &|acc, x| i32::checked_add(2 * acc, x);
+    assert_eq!((10..30).take(10).try_fold(7, f), (10..20).try_fold(7, f));
+    assert_eq!((10..30).take(10).try_rfold(7, f), (10..20).try_rfold(7, f));
+
+    let mut iter = (10..30).take(20);
+    assert_eq!(iter.try_fold(0, i8::checked_add), None);
+    assert_eq!(iter.next(), Some(20));
+    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+    assert_eq!(iter.next_back(), Some(24));
+
+    let mut iter = (2..20).take(3);
+    assert_eq!(iter.try_for_each(Err), Err(2));
+    assert_eq!(iter.try_for_each(Err), Err(3));
+    assert_eq!(iter.try_for_each(Err), Err(4));
+    assert_eq!(iter.try_for_each(Err), Ok(()));
+
+    let mut iter = (2..20).take(3).rev();
+    assert_eq!(iter.try_for_each(Err), Err(4));
+    assert_eq!(iter.try_for_each(Err), Err(3));
+    assert_eq!(iter.try_for_each(Err), Err(2));
+    assert_eq!(iter.try_for_each(Err), Ok(()));
+}
+
+#[test]
+fn test_flat_map_try_folds() {
+    let f = &|acc, x| i32::checked_add(acc * 2 / 3, x);
+    let mr = &|x| (5 * x)..(5 * x + 5);
+    assert_eq!((0..10).flat_map(mr).try_fold(7, f), (0..50).try_fold(7, f));
+    assert_eq!((0..10).flat_map(mr).try_rfold(7, f), (0..50).try_rfold(7, f));
+    let mut iter = (0..10).flat_map(mr);
+    iter.next();
+    iter.next_back(); // have front and back iters in progress
+    assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f));
+
+    let mut iter = (0..10).flat_map(|x| (4 * x)..(4 * x + 4));
+    assert_eq!(iter.try_fold(0, i8::checked_add), None);
+    assert_eq!(iter.next(), Some(17));
+    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+    assert_eq!(iter.next_back(), Some(35));
+}
+
+#[test]
+fn test_flatten_try_folds() {
+    let f = &|acc, x| i32::checked_add(acc * 2 / 3, x);
+    let mr = &|x| (5 * x)..(5 * x + 5);
+    assert_eq!((0..10).map(mr).flatten().try_fold(7, f), (0..50).try_fold(7, f));
+    assert_eq!((0..10).map(mr).flatten().try_rfold(7, f), (0..50).try_rfold(7, f));
+    let mut iter = (0..10).map(mr).flatten();
+    iter.next();
+    iter.next_back(); // have front and back iters in progress
+    assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f));
+
+    let mut iter = (0..10).map(|x| (4 * x)..(4 * x + 4)).flatten();
+    assert_eq!(iter.try_fold(0, i8::checked_add), None);
+    assert_eq!(iter.next(), Some(17));
+    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+    assert_eq!(iter.next_back(), Some(35));
+}
+
+#[test]
+fn test_functor_laws() {
+    // identity:
+    fn identity<T>(x: T) -> T {
+        x
+    }
+    assert_eq!((0..10).map(identity).sum::<usize>(), (0..10).sum());
+
+    // composition:
+    fn f(x: usize) -> usize {
+        x + 3
+    }
+    fn g(x: usize) -> usize {
+        x * 2
+    }
+    fn h(x: usize) -> usize {
+        g(f(x))
+    }
+    assert_eq!((0..10).map(f).map(g).sum::<usize>(), (0..10).map(h).sum());
+}
+
+#[test]
+fn test_monad_laws_left_identity() {
+    fn f(x: usize) -> impl Iterator<Item = usize> {
+        (0..10).map(move |y| x * y)
+    }
+    assert_eq!(once(42).flat_map(f.clone()).sum::<usize>(), f(42).sum());
+}
+
+#[test]
+fn test_monad_laws_right_identity() {
+    assert_eq!((0..10).flat_map(|x| once(x)).sum::<usize>(), (0..10).sum());
+}
+
+#[test]
+fn test_monad_laws_associativity() {
+    fn f(x: usize) -> impl Iterator<Item = usize> {
+        0..x
+    }
+    fn g(x: usize) -> impl Iterator<Item = usize> {
+        (0..x).rev()
+    }
+    assert_eq!(
+        (0..10).flat_map(f).flat_map(g).sum::<usize>(),
+        (0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>()
+    );
+}
+
+#[test]
+fn test_is_sorted() {
+    assert!([1, 2, 2, 9].iter().is_sorted());
+    assert!(![1, 3, 2].iter().is_sorted());
+    assert!([0].iter().is_sorted());
+    assert!(std::iter::empty::<i32>().is_sorted());
+    assert!(![0.0, 1.0, f32::NAN].iter().is_sorted());
+    assert!([-2, -1, 0, 3].iter().is_sorted());
+    assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
+    assert!(!["c", "bb", "aaa"].iter().is_sorted());
+    assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len()));
+}
+
+#[test]
+fn test_partition() {
+    fn check(xs: &mut [i32], ref p: impl Fn(&i32) -> bool, expected: usize) {
+        let i = xs.iter_mut().partition_in_place(p);
+        assert_eq!(expected, i);
+        assert!(xs[..i].iter().all(p));
+        assert!(!xs[i..].iter().any(p));
+        assert!(xs.iter().is_partitioned(p));
+        if i == 0 || i == xs.len() {
+            assert!(xs.iter().rev().is_partitioned(p));
+        } else {
+            assert!(!xs.iter().rev().is_partitioned(p));
+        }
+    }
+
+    check(&mut [], |_| true, 0);
+    check(&mut [], |_| false, 0);
+
+    check(&mut [0], |_| true, 1);
+    check(&mut [0], |_| false, 0);
+
+    check(&mut [-1, 1], |&x| x > 0, 1);
+    check(&mut [-1, 1], |&x| x < 0, 1);
+
+    let ref mut xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+    check(xs, |_| true, 10);
+    check(xs, |_| false, 0);
+    check(xs, |&x| x % 2 == 0, 5); // evens
+    check(xs, |&x| x % 2 == 1, 5); // odds
+    check(xs, |&x| x % 3 == 0, 4); // multiple of 3
+    check(xs, |&x| x % 4 == 0, 3); // multiple of 4
+    check(xs, |&x| x % 5 == 0, 2); // multiple of 5
+    check(xs, |&x| x < 3, 3); // small
+    check(xs, |&x| x > 6, 3); // large
+}
+
+/// An iterator that panics whenever `next` or next_back` is called
+/// after `None` has already been returned. This does not violate
+/// `Iterator`'s contract. Used to test that iterator adaptors don't
+/// poll their inner iterators after exhausting them.
+struct NonFused<I> {
+    iter: I,
+    done: bool,
+}
+
+impl<I> NonFused<I> {
+    fn new(iter: I) -> Self {
+        Self { iter, done: false }
+    }
+}
+
+impl<I> Iterator for NonFused<I>
+where
+    I: Iterator,
+{
+    type Item = I::Item;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        assert!(!self.done, "this iterator has already returned None");
+        self.iter.next().or_else(|| {
+            self.done = true;
+            None
+        })
+    }
+}
+
+impl<I> DoubleEndedIterator for NonFused<I>
+where
+    I: DoubleEndedIterator,
+{
+    fn next_back(&mut self) -> Option<Self::Item> {
+        assert!(!self.done, "this iterator has already returned None");
+        self.iter.next_back().or_else(|| {
+            self.done = true;
+            None
+        })
+    }
+}
+
+#[test]
+fn test_peekable_non_fused() {
+    let mut iter = NonFused::new(empty::<i32>()).peekable();
+
+    assert_eq!(iter.peek(), None);
+    assert_eq!(iter.next_back(), None);
+}
+
+#[test]
+fn test_flatten_non_fused_outer() {
+    let mut iter = NonFused::new(once(0..2)).flatten();
+
+    assert_eq!(iter.next_back(), Some(1));
+    assert_eq!(iter.next(), Some(0));
+    assert_eq!(iter.next(), None);
+}
+
+#[test]
+fn test_flatten_non_fused_inner() {
+    let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new);
+
+    assert_eq!(iter.next_back(), Some(2));
+    assert_eq!(iter.next(), Some(0));
+    assert_eq!(iter.next(), Some(1));
+    assert_eq!(iter.next(), None);
+}
+
+#[test]
+pub fn extend_for_unit() {
+    let mut x = 0;
+    {
+        let iter = (0..5).map(|_| {
+            x += 1;
+        });
+        ().extend(iter);
+    }
+    assert_eq!(x, 5);
+}
+
+#[test]
+fn test_intersperse() {
+    let v = std::iter::empty().intersperse(0u32).collect::<Vec<_>>();
+    assert_eq!(v, vec![]);
+
+    let v = std::iter::once(1).intersperse(0).collect::<Vec<_>>();
+    assert_eq!(v, vec![1]);
+
+    let xs = ["a", "", "b", "c"];
+    let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect();
+    let text: String = v.concat();
+    assert_eq!(text, "a, , b, c".to_string());
+
+    let ys = [0, 1, 2, 3];
+    let mut it = ys[..0].iter().map(|x| *x).intersperse(1);
+    assert!(it.next() == None);
+}
+
+#[test]
+fn test_intersperse_size_hint() {
+    let iter = std::iter::empty::<i32>().intersperse(0);
+    assert_eq!(iter.size_hint(), (0, Some(0)));
+
+    let xs = ["a", "", "b", "c"];
+    let mut iter = xs.iter().map(|x| x.clone()).intersperse(", ");
+    assert_eq!(iter.size_hint(), (7, Some(7)));
+
+    assert_eq!(iter.next(), Some("a"));
+    assert_eq!(iter.size_hint(), (6, Some(6)));
+    assert_eq!(iter.next(), Some(", "));
+    assert_eq!(iter.size_hint(), (5, Some(5)));
+
+    assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0)));
+}
+
+#[test]
+fn test_fold_specialization_intersperse() {
+    let mut iter = (1..2).intersperse(0);
+    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+
+    let mut iter = (1..3).intersperse(0);
+    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+
+    let mut iter = (1..4).intersperse(0);
+    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+}
+
+#[test]
+fn test_try_fold_specialization_intersperse_ok() {
+    let mut iter = (1..2).intersperse(0);
+    iter.clone().try_for_each(|x| {
+        assert_eq!(Some(x), iter.next());
+        Some(())
+    });
+
+    let mut iter = (1..3).intersperse(0);
+    iter.clone().try_for_each(|x| {
+        assert_eq!(Some(x), iter.next());
+        Some(())
+    });
+
+    let mut iter = (1..4).intersperse(0);
+    iter.clone().try_for_each(|x| {
+        assert_eq!(Some(x), iter.next());
+        Some(())
+    });
+}
+
+#[test]
+fn test_try_fold_specialization_intersperse_err() {
+    let orig_iter = ["a", "b"].iter().copied().intersperse("-");
+
+    // Abort after the first item.
+    let mut iter = orig_iter.clone();
+    iter.try_for_each(|_| None::<()>);
+    assert_eq!(iter.next(), Some("-"));
+    assert_eq!(iter.next(), Some("b"));
+    assert_eq!(iter.next(), None);
+
+    // Abort after the second item.
+    let mut iter = orig_iter.clone();
+    iter.try_for_each(|item| if item == "-" { None } else { Some(()) });
+    assert_eq!(iter.next(), Some("b"));
+    assert_eq!(iter.next(), None);
+
+    // Abort after the third item.
+    let mut iter = orig_iter.clone();
+    iter.try_for_each(|item| if item == "b" { None } else { Some(()) });
+    assert_eq!(iter.next(), None);
+}
+
+#[test]
+fn test_intersperse_with() {
+    #[derive(PartialEq, Debug)]
+    struct NotClone {
+        u: u32,
+    }
+    let r = vec![NotClone { u: 0 }, NotClone { u: 1 }]
+        .into_iter()
+        .intersperse_with(|| NotClone { u: 2 })
+        .collect::<Vec<_>>();
+    assert_eq!(r, vec![NotClone { u: 0 }, NotClone { u: 2 }, NotClone { u: 1 }]);
+
+    let mut ctr = 100;
+    let separator = || {
+        ctr *= 2;
+        ctr
+    };
+    let r = (0..3).intersperse_with(separator).collect::<Vec<_>>();
+    assert_eq!(r, vec![0, 200, 1, 400, 2]);
+}
diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs
deleted file mode 100644
index ca5ae12ae263f..0000000000000
--- a/library/core/tests/iter/adapters/chain.rs
+++ /dev/null
@@ -1,272 +0,0 @@
-use super::*;
-use core::iter::*;
-
-#[test]
-fn test_iterator_chain() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let ys = [30, 40, 50, 60];
-    let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
-    let it = xs.iter().chain(&ys);
-    let mut i = 0;
-    for &x in it {
-        assert_eq!(x, expected[i]);
-        i += 1;
-    }
-    assert_eq!(i, expected.len());
-
-    let ys = (30..).step_by(10).take(4);
-    let it = xs.iter().cloned().chain(ys);
-    let mut i = 0;
-    for x in it {
-        assert_eq!(x, expected[i]);
-        i += 1;
-    }
-    assert_eq!(i, expected.len());
-}
-
-#[test]
-fn test_iterator_chain_advance_by() {
-    fn test_chain(xs: &[i32], ys: &[i32]) {
-        let len = xs.len() + ys.len();
-
-        for i in 0..xs.len() {
-            let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
-            iter.advance_by(i).unwrap();
-            assert_eq!(iter.next(), Some(&xs[i]));
-            assert_eq!(iter.advance_by(100), Err(len - i - 1));
-        }
-
-        for i in 0..ys.len() {
-            let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
-            iter.advance_by(xs.len() + i).unwrap();
-            assert_eq!(iter.next(), Some(&ys[i]));
-            assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1));
-        }
-
-        let mut iter = xs.iter().chain(ys);
-        iter.advance_by(len).unwrap();
-        assert_eq!(iter.next(), None);
-
-        let mut iter = xs.iter().chain(ys);
-        assert_eq!(iter.advance_by(len + 1), Err(len));
-    }
-
-    test_chain(&[], &[]);
-    test_chain(&[], &[0, 1, 2, 3, 4, 5]);
-    test_chain(&[0, 1, 2, 3, 4, 5], &[]);
-    test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]);
-}
-
-#[test]
-fn test_iterator_chain_advance_back_by() {
-    fn test_chain(xs: &[i32], ys: &[i32]) {
-        let len = xs.len() + ys.len();
-
-        for i in 0..ys.len() {
-            let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
-            iter.advance_back_by(i).unwrap();
-            assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
-            assert_eq!(iter.advance_back_by(100), Err(len - i - 1));
-        }
-
-        for i in 0..xs.len() {
-            let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
-            iter.advance_back_by(ys.len() + i).unwrap();
-            assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
-            assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1));
-        }
-
-        let mut iter = xs.iter().chain(ys);
-        iter.advance_back_by(len).unwrap();
-        assert_eq!(iter.next_back(), None);
-
-        let mut iter = xs.iter().chain(ys);
-        assert_eq!(iter.advance_back_by(len + 1), Err(len));
-    }
-
-    test_chain(&[], &[]);
-    test_chain(&[], &[0, 1, 2, 3, 4, 5]);
-    test_chain(&[0, 1, 2, 3, 4, 5], &[]);
-    test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]);
-}
-
-#[test]
-fn test_iterator_chain_nth() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let ys = [30, 40, 50, 60];
-    let zs = [];
-    let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
-    for (i, x) in expected.iter().enumerate() {
-        assert_eq!(Some(x), xs.iter().chain(&ys).nth(i));
-    }
-    assert_eq!(zs.iter().chain(&xs).nth(0), Some(&0));
-
-    let mut it = xs.iter().chain(&zs);
-    assert_eq!(it.nth(5), Some(&5));
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_iterator_chain_nth_back() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let ys = [30, 40, 50, 60];
-    let zs = [];
-    let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
-    for (i, x) in expected.iter().rev().enumerate() {
-        assert_eq!(Some(x), xs.iter().chain(&ys).nth_back(i));
-    }
-    assert_eq!(zs.iter().chain(&xs).nth_back(0), Some(&5));
-
-    let mut it = xs.iter().chain(&zs);
-    assert_eq!(it.nth_back(5), Some(&0));
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_iterator_chain_last() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let ys = [30, 40, 50, 60];
-    let zs = [];
-    assert_eq!(xs.iter().chain(&ys).last(), Some(&60));
-    assert_eq!(zs.iter().chain(&ys).last(), Some(&60));
-    assert_eq!(ys.iter().chain(&zs).last(), Some(&60));
-    assert_eq!(zs.iter().chain(&zs).last(), None);
-}
-
-#[test]
-fn test_iterator_chain_count() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let ys = [30, 40, 50, 60];
-    let zs = [];
-    assert_eq!(xs.iter().chain(&ys).count(), 10);
-    assert_eq!(zs.iter().chain(&ys).count(), 4);
-}
-
-#[test]
-fn test_iterator_chain_find() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let ys = [30, 40, 50, 60];
-    let mut iter = xs.iter().chain(&ys);
-    assert_eq!(iter.find(|&&i| i == 4), Some(&4));
-    assert_eq!(iter.next(), Some(&5));
-    assert_eq!(iter.find(|&&i| i == 40), Some(&40));
-    assert_eq!(iter.next(), Some(&50));
-    assert_eq!(iter.find(|&&i| i == 100), None);
-    assert_eq!(iter.next(), None);
-}
-
-#[test]
-fn test_iterator_chain_size_hint() {
-    // this chains an iterator of length 0 with an iterator of length 1,
-    // so after calling `.next()` once, the iterator is empty and the
-    // state is `ChainState::Back`. `.size_hint()` should now disregard
-    // the size hint of the left iterator
-    let mut iter = Toggle { is_empty: true }.chain(once(()));
-    assert_eq!(iter.next(), Some(()));
-    assert_eq!(iter.size_hint(), (0, Some(0)));
-
-    let mut iter = once(()).chain(Toggle { is_empty: true });
-    assert_eq!(iter.next_back(), Some(()));
-    assert_eq!(iter.size_hint(), (0, Some(0)));
-}
-
-#[test]
-fn test_iterator_chain_unfused() {
-    // Chain shouldn't be fused in its second iterator, depending on direction
-    let mut iter = NonFused::new(empty()).chain(Toggle { is_empty: true });
-    iter.next().unwrap_none();
-    iter.next().unwrap();
-    iter.next().unwrap_none();
-
-    let mut iter = Toggle { is_empty: true }.chain(NonFused::new(empty()));
-    iter.next_back().unwrap_none();
-    iter.next_back().unwrap();
-    iter.next_back().unwrap_none();
-}
-
-#[test]
-fn test_chain_fold() {
-    let xs = [1, 2, 3];
-    let ys = [1, 2, 0];
-
-    let mut iter = xs.iter().chain(&ys);
-    iter.next();
-    let mut result = Vec::new();
-    iter.fold((), |(), &elt| result.push(elt));
-    assert_eq!(&[2, 3, 1, 2, 0], &result[..]);
-}
-
-#[test]
-fn test_chain_try_folds() {
-    let c = || (0..10).chain(10..20);
-
-    let f = &|acc, x| i32::checked_add(2 * acc, x);
-    assert_eq!(c().try_fold(7, f), (0..20).try_fold(7, f));
-    assert_eq!(c().try_rfold(7, f), (0..20).rev().try_fold(7, f));
-
-    let mut iter = c();
-    assert_eq!(iter.position(|x| x == 5), Some(5));
-    assert_eq!(iter.next(), Some(6), "stopped in front, state Both");
-    assert_eq!(iter.position(|x| x == 13), Some(6));
-    assert_eq!(iter.next(), Some(14), "stopped in back, state Back");
-    assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((15..20).sum()));
-
-    let mut iter = c().rev(); // use rev to access try_rfold
-    assert_eq!(iter.position(|x| x == 15), Some(4));
-    assert_eq!(iter.next(), Some(14), "stopped in back, state Both");
-    assert_eq!(iter.position(|x| x == 5), Some(8));
-    assert_eq!(iter.next(), Some(4), "stopped in front, state Front");
-    assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((0..4).sum()));
-
-    let mut iter = c();
-    iter.by_ref().rev().nth(14); // skip the last 15, ending in state Front
-    assert_eq!(iter.try_fold(7, f), (0..5).try_fold(7, f));
-
-    let mut iter = c();
-    iter.nth(14); // skip the first 15, ending in state Back
-    assert_eq!(iter.try_rfold(7, f), (15..20).try_rfold(7, f));
-}
-
-#[test]
-fn test_double_ended_chain() {
-    let xs = [1, 2, 3, 4, 5];
-    let ys = [7, 9, 11];
-    let mut it = xs.iter().chain(&ys).rev();
-    assert_eq!(it.next().unwrap(), &11);
-    assert_eq!(it.next().unwrap(), &9);
-    assert_eq!(it.next_back().unwrap(), &1);
-    assert_eq!(it.next_back().unwrap(), &2);
-    assert_eq!(it.next_back().unwrap(), &3);
-    assert_eq!(it.next_back().unwrap(), &4);
-    assert_eq!(it.next_back().unwrap(), &5);
-    assert_eq!(it.next_back().unwrap(), &7);
-    assert_eq!(it.next_back(), None);
-
-    // test that .chain() is well behaved with an unfused iterator
-    struct CrazyIterator(bool);
-    impl CrazyIterator {
-        fn new() -> CrazyIterator {
-            CrazyIterator(false)
-        }
-    }
-    impl Iterator for CrazyIterator {
-        type Item = i32;
-        fn next(&mut self) -> Option<i32> {
-            if self.0 {
-                Some(99)
-            } else {
-                self.0 = true;
-                None
-            }
-        }
-    }
-
-    impl DoubleEndedIterator for CrazyIterator {
-        fn next_back(&mut self) -> Option<i32> {
-            self.next()
-        }
-    }
-
-    assert_eq!(CrazyIterator::new().chain(0..10).rev().last(), Some(0));
-    assert!((0..10).chain(CrazyIterator::new()).rev().any(|i| i == 0));
-}
diff --git a/library/core/tests/iter/adapters/cloned.rs b/library/core/tests/iter/adapters/cloned.rs
deleted file mode 100644
index 78babb7feab18..0000000000000
--- a/library/core/tests/iter/adapters/cloned.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_cloned() {
-    let xs = [2, 4, 6, 8];
-
-    let mut it = xs.iter().cloned();
-    assert_eq!(it.len(), 4);
-    assert_eq!(it.next(), Some(2));
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.next(), Some(4));
-    assert_eq!(it.len(), 2);
-    assert_eq!(it.next_back(), Some(8));
-    assert_eq!(it.len(), 1);
-    assert_eq!(it.next_back(), Some(6));
-    assert_eq!(it.len(), 0);
-    assert_eq!(it.next_back(), None);
-}
-
-#[test]
-fn test_cloned_side_effects() {
-    let mut count = 0;
-    {
-        let iter = [1, 2, 3]
-            .iter()
-            .map(|x| {
-                count += 1;
-                x
-            })
-            .cloned()
-            .zip(&[1]);
-        for _ in iter {}
-    }
-    assert_eq!(count, 2);
-}
-
-#[test]
-fn test_cloned_try_folds() {
-    let a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
-    let f = &|acc, x| i32::checked_add(2 * acc, x);
-    let f_ref = &|acc, &x| i32::checked_add(2 * acc, x);
-    assert_eq!(a.iter().cloned().try_fold(7, f), a.iter().try_fold(7, f_ref));
-    assert_eq!(a.iter().cloned().try_rfold(7, f), a.iter().try_rfold(7, f_ref));
-
-    let a = [10, 20, 30, 40, 100, 60, 70, 80, 90];
-    let mut iter = a.iter().cloned();
-    assert_eq!(iter.try_fold(0_i8, |acc, x| acc.checked_add(x)), None);
-    assert_eq!(iter.next(), Some(60));
-    let mut iter = a.iter().cloned();
-    assert_eq!(iter.try_rfold(0_i8, |acc, x| acc.checked_add(x)), None);
-    assert_eq!(iter.next_back(), Some(70));
-}
diff --git a/library/core/tests/iter/adapters/copied.rs b/library/core/tests/iter/adapters/copied.rs
deleted file mode 100644
index b12f2035dc133..0000000000000
--- a/library/core/tests/iter/adapters/copied.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_copied() {
-    let xs = [2, 4, 6, 8];
-
-    let mut it = xs.iter().copied();
-    assert_eq!(it.len(), 4);
-    assert_eq!(it.next(), Some(2));
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.next(), Some(4));
-    assert_eq!(it.len(), 2);
-    assert_eq!(it.next_back(), Some(8));
-    assert_eq!(it.len(), 1);
-    assert_eq!(it.next_back(), Some(6));
-    assert_eq!(it.len(), 0);
-    assert_eq!(it.next_back(), None);
-}
diff --git a/library/core/tests/iter/adapters/cycle.rs b/library/core/tests/iter/adapters/cycle.rs
deleted file mode 100644
index 8831c09b48b3f..0000000000000
--- a/library/core/tests/iter/adapters/cycle.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_cycle() {
-    let cycle_len = 3;
-    let it = (0..).step_by(1).take(cycle_len).cycle();
-    assert_eq!(it.size_hint(), (usize::MAX, None));
-    for (i, x) in it.take(100).enumerate() {
-        assert_eq!(i % cycle_len, x);
-    }
-
-    let mut it = (0..).step_by(1).take(0).cycle();
-    assert_eq!(it.size_hint(), (0, Some(0)));
-    assert_eq!(it.next(), None);
-
-    assert_eq!(empty::<i32>().cycle().fold(0, |acc, x| acc + x), 0);
-
-    assert_eq!(once(1).cycle().skip(1).take(4).fold(0, |acc, x| acc + x), 4);
-
-    assert_eq!((0..10).cycle().take(5).sum::<i32>(), 10);
-    assert_eq!((0..10).cycle().take(15).sum::<i32>(), 55);
-    assert_eq!((0..10).cycle().take(25).sum::<i32>(), 100);
-
-    let mut iter = (0..10).cycle();
-    iter.nth(14);
-    assert_eq!(iter.take(8).sum::<i32>(), 38);
-
-    let mut iter = (0..10).cycle();
-    iter.nth(9);
-    assert_eq!(iter.take(3).sum::<i32>(), 3);
-}
diff --git a/library/core/tests/iter/adapters/enumerate.rs b/library/core/tests/iter/adapters/enumerate.rs
deleted file mode 100644
index 0e60338784797..0000000000000
--- a/library/core/tests/iter/adapters/enumerate.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_iterator_enumerate() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let it = xs.iter().enumerate();
-    for (i, &x) in it {
-        assert_eq!(i, x);
-    }
-}
-
-#[test]
-fn test_iterator_enumerate_nth() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    for (i, &x) in xs.iter().enumerate() {
-        assert_eq!(i, x);
-    }
-
-    let mut it = xs.iter().enumerate();
-    while let Some((i, &x)) = it.nth(0) {
-        assert_eq!(i, x);
-    }
-
-    let mut it = xs.iter().enumerate();
-    while let Some((i, &x)) = it.nth(1) {
-        assert_eq!(i, x);
-    }
-
-    let (i, &x) = xs.iter().enumerate().nth(3).unwrap();
-    assert_eq!(i, x);
-    assert_eq!(i, 3);
-}
-
-#[test]
-fn test_iterator_enumerate_nth_back() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let mut it = xs.iter().enumerate();
-    while let Some((i, &x)) = it.nth_back(0) {
-        assert_eq!(i, x);
-    }
-
-    let mut it = xs.iter().enumerate();
-    while let Some((i, &x)) = it.nth_back(1) {
-        assert_eq!(i, x);
-    }
-
-    let (i, &x) = xs.iter().enumerate().nth_back(3).unwrap();
-    assert_eq!(i, x);
-    assert_eq!(i, 2);
-}
-
-#[test]
-fn test_iterator_enumerate_count() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    assert_eq!(xs.iter().enumerate().count(), 6);
-}
-
-#[test]
-fn test_iterator_enumerate_fold() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let mut it = xs.iter().enumerate();
-    // steal a couple to get an interesting offset
-    assert_eq!(it.next(), Some((0, &0)));
-    assert_eq!(it.next(), Some((1, &1)));
-    let i = it.fold(2, |i, (j, &x)| {
-        assert_eq!(i, j);
-        assert_eq!(x, xs[j]);
-        i + 1
-    });
-    assert_eq!(i, xs.len());
-
-    let mut it = xs.iter().enumerate();
-    assert_eq!(it.next(), Some((0, &0)));
-    let i = it.rfold(xs.len() - 1, |i, (j, &x)| {
-        assert_eq!(i, j);
-        assert_eq!(x, xs[j]);
-        i - 1
-    });
-    assert_eq!(i, 0);
-}
-
-#[test]
-fn test_enumerate_try_folds() {
-    let f = &|acc, (i, x)| usize::checked_add(2 * acc, x / (i + 1) + i);
-    assert_eq!((9..18).enumerate().try_fold(7, f), (0..9).map(|i| (i, i + 9)).try_fold(7, f));
-    assert_eq!((9..18).enumerate().try_rfold(7, f), (0..9).map(|i| (i, i + 9)).try_rfold(7, f));
-
-    let mut iter = (100..200).enumerate();
-    let f = &|acc, (i, x)| u8::checked_add(acc, u8::checked_div(x, i as u8 + 1)?);
-    assert_eq!(iter.try_fold(0, f), None);
-    assert_eq!(iter.next(), Some((7, 107)));
-    assert_eq!(iter.try_rfold(0, f), None);
-    assert_eq!(iter.next_back(), Some((11, 111)));
-}
-
-#[test]
-fn test_double_ended_enumerate() {
-    let xs = [1, 2, 3, 4, 5, 6];
-    let mut it = xs.iter().cloned().enumerate();
-    assert_eq!(it.next(), Some((0, 1)));
-    assert_eq!(it.next(), Some((1, 2)));
-    assert_eq!(it.next_back(), Some((5, 6)));
-    assert_eq!(it.next_back(), Some((4, 5)));
-    assert_eq!(it.next_back(), Some((3, 4)));
-    assert_eq!(it.next_back(), Some((2, 3)));
-    assert_eq!(it.next(), None);
-}
diff --git a/library/core/tests/iter/adapters/filter.rs b/library/core/tests/iter/adapters/filter.rs
deleted file mode 100644
index a2050d89d8564..0000000000000
--- a/library/core/tests/iter/adapters/filter.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_iterator_filter_count() {
-    let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
-    assert_eq!(xs.iter().filter(|&&x| x % 2 == 0).count(), 5);
-}
-
-#[test]
-fn test_iterator_filter_fold() {
-    let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
-    let ys = [0, 2, 4, 6, 8];
-    let it = xs.iter().filter(|&&x| x % 2 == 0);
-    let i = it.fold(0, |i, &x| {
-        assert_eq!(x, ys[i]);
-        i + 1
-    });
-    assert_eq!(i, ys.len());
-
-    let it = xs.iter().filter(|&&x| x % 2 == 0);
-    let i = it.rfold(ys.len(), |i, &x| {
-        assert_eq!(x, ys[i - 1]);
-        i - 1
-    });
-    assert_eq!(i, 0);
-}
-
-#[test]
-fn test_filter_try_folds() {
-    fn p(&x: &i32) -> bool {
-        0 <= x && x < 10
-    }
-    let f = &|acc, x| i32::checked_add(2 * acc, x);
-    assert_eq!((-10..20).filter(p).try_fold(7, f), (0..10).try_fold(7, f));
-    assert_eq!((-10..20).filter(p).try_rfold(7, f), (0..10).try_rfold(7, f));
-
-    let mut iter = (0..40).filter(|&x| x % 2 == 1);
-    assert_eq!(iter.try_fold(0, i8::checked_add), None);
-    assert_eq!(iter.next(), Some(25));
-    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
-    assert_eq!(iter.next_back(), Some(31));
-}
-
-#[test]
-fn test_double_ended_filter() {
-    let xs = [1, 2, 3, 4, 5, 6];
-    let mut it = xs.iter().filter(|&x| *x & 1 == 0);
-    assert_eq!(it.next_back().unwrap(), &6);
-    assert_eq!(it.next_back().unwrap(), &4);
-    assert_eq!(it.next().unwrap(), &2);
-    assert_eq!(it.next_back(), None);
-}
diff --git a/library/core/tests/iter/adapters/filter_map.rs b/library/core/tests/iter/adapters/filter_map.rs
deleted file mode 100644
index 46738eda63f3d..0000000000000
--- a/library/core/tests/iter/adapters/filter_map.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_filter_map() {
-    let it = (0..).step_by(1).take(10).filter_map(|x| if x % 2 == 0 { Some(x * x) } else { None });
-    assert_eq!(it.collect::<Vec<usize>>(), [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]);
-}
-
-#[test]
-fn test_filter_map_fold() {
-    let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
-    let ys = [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8];
-    let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None });
-    let i = it.fold(0, |i, x| {
-        assert_eq!(x, ys[i]);
-        i + 1
-    });
-    assert_eq!(i, ys.len());
-
-    let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None });
-    let i = it.rfold(ys.len(), |i, x| {
-        assert_eq!(x, ys[i - 1]);
-        i - 1
-    });
-    assert_eq!(i, 0);
-}
-
-#[test]
-fn test_filter_map_try_folds() {
-    let mp = &|x| if 0 <= x && x < 10 { Some(x * 2) } else { None };
-    let f = &|acc, x| i32::checked_add(2 * acc, x);
-    assert_eq!((-9..20).filter_map(mp).try_fold(7, f), (0..10).map(|x| 2 * x).try_fold(7, f));
-    assert_eq!((-9..20).filter_map(mp).try_rfold(7, f), (0..10).map(|x| 2 * x).try_rfold(7, f));
-
-    let mut iter = (0..40).filter_map(|x| if x % 2 == 1 { None } else { Some(x * 2 + 10) });
-    assert_eq!(iter.try_fold(0, i8::checked_add), None);
-    assert_eq!(iter.next(), Some(38));
-    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
-    assert_eq!(iter.next_back(), Some(78));
-}
-
-#[test]
-fn test_double_ended_filter_map() {
-    let xs = [1, 2, 3, 4, 5, 6];
-    let mut it = xs.iter().filter_map(|&x| if x & 1 == 0 { Some(x * 2) } else { None });
-    assert_eq!(it.next_back().unwrap(), 12);
-    assert_eq!(it.next_back().unwrap(), 8);
-    assert_eq!(it.next().unwrap(), 4);
-    assert_eq!(it.next_back(), None);
-}
diff --git a/library/core/tests/iter/adapters/flat_map.rs b/library/core/tests/iter/adapters/flat_map.rs
deleted file mode 100644
index ee945e69801b8..0000000000000
--- a/library/core/tests/iter/adapters/flat_map.rs
+++ /dev/null
@@ -1,74 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_iterator_flat_map() {
-    let xs = [0, 3, 6];
-    let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
-    let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3));
-    let mut i = 0;
-    for x in it {
-        assert_eq!(x, ys[i]);
-        i += 1;
-    }
-    assert_eq!(i, ys.len());
-}
-
-/// Tests `FlatMap::fold` with items already picked off the front and back,
-/// to make sure all parts of the `FlatMap` are folded correctly.
-#[test]
-fn test_iterator_flat_map_fold() {
-    let xs = [0, 3, 6];
-    let ys = [1, 2, 3, 4, 5, 6, 7];
-    let mut it = xs.iter().flat_map(|&x| x..x + 3);
-    assert_eq!(it.next(), Some(0));
-    assert_eq!(it.next_back(), Some(8));
-    let i = it.fold(0, |i, x| {
-        assert_eq!(x, ys[i]);
-        i + 1
-    });
-    assert_eq!(i, ys.len());
-
-    let mut it = xs.iter().flat_map(|&x| x..x + 3);
-    assert_eq!(it.next(), Some(0));
-    assert_eq!(it.next_back(), Some(8));
-    let i = it.rfold(ys.len(), |i, x| {
-        assert_eq!(x, ys[i - 1]);
-        i - 1
-    });
-    assert_eq!(i, 0);
-}
-
-#[test]
-fn test_flat_map_try_folds() {
-    let f = &|acc, x| i32::checked_add(acc * 2 / 3, x);
-    let mr = &|x| (5 * x)..(5 * x + 5);
-    assert_eq!((0..10).flat_map(mr).try_fold(7, f), (0..50).try_fold(7, f));
-    assert_eq!((0..10).flat_map(mr).try_rfold(7, f), (0..50).try_rfold(7, f));
-    let mut iter = (0..10).flat_map(mr);
-    iter.next();
-    iter.next_back(); // have front and back iters in progress
-    assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f));
-
-    let mut iter = (0..10).flat_map(|x| (4 * x)..(4 * x + 4));
-    assert_eq!(iter.try_fold(0, i8::checked_add), None);
-    assert_eq!(iter.next(), Some(17));
-    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
-    assert_eq!(iter.next_back(), Some(35));
-}
-
-#[test]
-fn test_double_ended_flat_map() {
-    let u = [0, 1];
-    let v = [5, 6, 7, 8];
-    let mut it = u.iter().flat_map(|x| &v[*x..v.len()]);
-    assert_eq!(it.next_back().unwrap(), &8);
-    assert_eq!(it.next().unwrap(), &5);
-    assert_eq!(it.next_back().unwrap(), &7);
-    assert_eq!(it.next_back().unwrap(), &6);
-    assert_eq!(it.next_back().unwrap(), &8);
-    assert_eq!(it.next().unwrap(), &6);
-    assert_eq!(it.next_back().unwrap(), &7);
-    assert_eq!(it.next_back(), None);
-    assert_eq!(it.next(), None);
-    assert_eq!(it.next_back(), None);
-}
diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs
deleted file mode 100644
index bd2c6fd9252df..0000000000000
--- a/library/core/tests/iter/adapters/flatten.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-use super::*;
-use core::iter::*;
-
-#[test]
-fn test_iterator_flatten() {
-    let xs = [0, 3, 6];
-    let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
-    let it = xs.iter().map(|&x| (x..).step_by(1).take(3)).flatten();
-    let mut i = 0;
-    for x in it {
-        assert_eq!(x, ys[i]);
-        i += 1;
-    }
-    assert_eq!(i, ys.len());
-}
-
-/// Tests `Flatten::fold` with items already picked off the front and back,
-/// to make sure all parts of the `Flatten` are folded correctly.
-#[test]
-fn test_iterator_flatten_fold() {
-    let xs = [0, 3, 6];
-    let ys = [1, 2, 3, 4, 5, 6, 7];
-    let mut it = xs.iter().map(|&x| x..x + 3).flatten();
-    assert_eq!(it.next(), Some(0));
-    assert_eq!(it.next_back(), Some(8));
-    let i = it.fold(0, |i, x| {
-        assert_eq!(x, ys[i]);
-        i + 1
-    });
-    assert_eq!(i, ys.len());
-
-    let mut it = xs.iter().map(|&x| x..x + 3).flatten();
-    assert_eq!(it.next(), Some(0));
-    assert_eq!(it.next_back(), Some(8));
-    let i = it.rfold(ys.len(), |i, x| {
-        assert_eq!(x, ys[i - 1]);
-        i - 1
-    });
-    assert_eq!(i, 0);
-}
-
-#[test]
-fn test_flatten_try_folds() {
-    let f = &|acc, x| i32::checked_add(acc * 2 / 3, x);
-    let mr = &|x| (5 * x)..(5 * x + 5);
-    assert_eq!((0..10).map(mr).flatten().try_fold(7, f), (0..50).try_fold(7, f));
-    assert_eq!((0..10).map(mr).flatten().try_rfold(7, f), (0..50).try_rfold(7, f));
-    let mut iter = (0..10).map(mr).flatten();
-    iter.next();
-    iter.next_back(); // have front and back iters in progress
-    assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f));
-
-    let mut iter = (0..10).map(|x| (4 * x)..(4 * x + 4)).flatten();
-    assert_eq!(iter.try_fold(0, i8::checked_add), None);
-    assert_eq!(iter.next(), Some(17));
-    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
-    assert_eq!(iter.next_back(), Some(35));
-}
-
-#[test]
-fn test_flatten_non_fused_outer() {
-    let mut iter = NonFused::new(once(0..2)).flatten();
-
-    assert_eq!(iter.next_back(), Some(1));
-    assert_eq!(iter.next(), Some(0));
-    assert_eq!(iter.next(), None);
-}
-
-#[test]
-fn test_flatten_non_fused_inner() {
-    let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new);
-
-    assert_eq!(iter.next_back(), Some(2));
-    assert_eq!(iter.next(), Some(0));
-    assert_eq!(iter.next(), Some(1));
-    assert_eq!(iter.next(), None);
-}
-
-#[test]
-fn test_double_ended_flatten() {
-    let u = [0, 1];
-    let v = [5, 6, 7, 8];
-    let mut it = u.iter().map(|x| &v[*x..v.len()]).flatten();
-    assert_eq!(it.next_back().unwrap(), &8);
-    assert_eq!(it.next().unwrap(), &5);
-    assert_eq!(it.next_back().unwrap(), &7);
-    assert_eq!(it.next_back().unwrap(), &6);
-    assert_eq!(it.next_back().unwrap(), &8);
-    assert_eq!(it.next().unwrap(), &6);
-    assert_eq!(it.next_back().unwrap(), &7);
-    assert_eq!(it.next_back(), None);
-    assert_eq!(it.next(), None);
-    assert_eq!(it.next_back(), None);
-}
diff --git a/library/core/tests/iter/adapters/fuse.rs b/library/core/tests/iter/adapters/fuse.rs
deleted file mode 100644
index f41b379b3ac7f..0000000000000
--- a/library/core/tests/iter/adapters/fuse.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_fuse_nth() {
-    let xs = [0, 1, 2];
-    let mut it = xs.iter();
-
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.nth(2), Some(&2));
-    assert_eq!(it.len(), 0);
-    assert_eq!(it.nth(2), None);
-    assert_eq!(it.len(), 0);
-}
-
-#[test]
-fn test_fuse_last() {
-    let xs = [0, 1, 2];
-    let it = xs.iter();
-
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.last(), Some(&2));
-}
-
-#[test]
-fn test_fuse_count() {
-    let xs = [0, 1, 2];
-    let it = xs.iter();
-
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.count(), 3);
-    // Can't check len now because count consumes.
-}
-
-#[test]
-fn test_fuse_fold() {
-    let xs = [0, 1, 2];
-    let it = xs.iter(); // `FusedIterator`
-    let i = it.fuse().fold(0, |i, &x| {
-        assert_eq!(x, xs[i]);
-        i + 1
-    });
-    assert_eq!(i, xs.len());
-
-    let it = xs.iter(); // `FusedIterator`
-    let i = it.fuse().rfold(xs.len(), |i, &x| {
-        assert_eq!(x, xs[i - 1]);
-        i - 1
-    });
-    assert_eq!(i, 0);
-
-    let it = xs.iter().scan((), |_, &x| Some(x)); // `!FusedIterator`
-    let i = it.fuse().fold(0, |i, x| {
-        assert_eq!(x, xs[i]);
-        i + 1
-    });
-    assert_eq!(i, xs.len());
-}
-
-#[test]
-fn test_fuse() {
-    let mut it = 0..3;
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.next(), Some(0));
-    assert_eq!(it.len(), 2);
-    assert_eq!(it.next(), Some(1));
-    assert_eq!(it.len(), 1);
-    assert_eq!(it.next(), Some(2));
-    assert_eq!(it.len(), 0);
-    assert_eq!(it.next(), None);
-    assert_eq!(it.len(), 0);
-    assert_eq!(it.next(), None);
-    assert_eq!(it.len(), 0);
-    assert_eq!(it.next(), None);
-    assert_eq!(it.len(), 0);
-}
diff --git a/library/core/tests/iter/adapters/inspect.rs b/library/core/tests/iter/adapters/inspect.rs
deleted file mode 100644
index 939e3a28a7204..0000000000000
--- a/library/core/tests/iter/adapters/inspect.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_inspect() {
-    let xs = [1, 2, 3, 4];
-    let mut n = 0;
-
-    let ys = xs.iter().cloned().inspect(|_| n += 1).collect::<Vec<usize>>();
-
-    assert_eq!(n, xs.len());
-    assert_eq!(&xs[..], &ys[..]);
-}
-
-#[test]
-fn test_inspect_fold() {
-    let xs = [1, 2, 3, 4];
-    let mut n = 0;
-    {
-        let it = xs.iter().inspect(|_| n += 1);
-        let i = it.fold(0, |i, &x| {
-            assert_eq!(x, xs[i]);
-            i + 1
-        });
-        assert_eq!(i, xs.len());
-    }
-    assert_eq!(n, xs.len());
-
-    let mut n = 0;
-    {
-        let it = xs.iter().inspect(|_| n += 1);
-        let i = it.rfold(xs.len(), |i, &x| {
-            assert_eq!(x, xs[i - 1]);
-            i - 1
-        });
-        assert_eq!(i, 0);
-    }
-    assert_eq!(n, xs.len());
-}
diff --git a/library/core/tests/iter/adapters/intersperse.rs b/library/core/tests/iter/adapters/intersperse.rs
deleted file mode 100644
index 9dbe232e4eec8..0000000000000
--- a/library/core/tests/iter/adapters/intersperse.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_intersperse() {
-    let v = std::iter::empty().intersperse(0u32).collect::<Vec<_>>();
-    assert_eq!(v, vec![]);
-
-    let v = std::iter::once(1).intersperse(0).collect::<Vec<_>>();
-    assert_eq!(v, vec![1]);
-
-    let xs = ["a", "", "b", "c"];
-    let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect();
-    let text: String = v.concat();
-    assert_eq!(text, "a, , b, c".to_string());
-
-    let ys = [0, 1, 2, 3];
-    let mut it = ys[..0].iter().map(|x| *x).intersperse(1);
-    assert!(it.next() == None);
-}
-
-#[test]
-fn test_intersperse_size_hint() {
-    let iter = std::iter::empty::<i32>().intersperse(0);
-    assert_eq!(iter.size_hint(), (0, Some(0)));
-
-    let xs = ["a", "", "b", "c"];
-    let mut iter = xs.iter().map(|x| x.clone()).intersperse(", ");
-    assert_eq!(iter.size_hint(), (7, Some(7)));
-
-    assert_eq!(iter.next(), Some("a"));
-    assert_eq!(iter.size_hint(), (6, Some(6)));
-    assert_eq!(iter.next(), Some(", "));
-    assert_eq!(iter.size_hint(), (5, Some(5)));
-
-    assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0)));
-}
-
-#[test]
-fn test_fold_specialization_intersperse() {
-    let mut iter = (1..2).intersperse(0);
-    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
-
-    let mut iter = (1..3).intersperse(0);
-    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
-
-    let mut iter = (1..4).intersperse(0);
-    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
-}
-
-#[test]
-fn test_try_fold_specialization_intersperse_ok() {
-    let mut iter = (1..2).intersperse(0);
-    iter.clone().try_for_each(|x| {
-        assert_eq!(Some(x), iter.next());
-        Some(())
-    });
-
-    let mut iter = (1..3).intersperse(0);
-    iter.clone().try_for_each(|x| {
-        assert_eq!(Some(x), iter.next());
-        Some(())
-    });
-
-    let mut iter = (1..4).intersperse(0);
-    iter.clone().try_for_each(|x| {
-        assert_eq!(Some(x), iter.next());
-        Some(())
-    });
-}
-
-#[test]
-fn test_intersperse_with() {
-    #[derive(PartialEq, Debug)]
-    struct NotClone {
-        u: u32,
-    }
-    let r = vec![NotClone { u: 0 }, NotClone { u: 1 }]
-        .into_iter()
-        .intersperse_with(|| NotClone { u: 2 })
-        .collect::<Vec<_>>();
-    assert_eq!(r, vec![NotClone { u: 0 }, NotClone { u: 2 }, NotClone { u: 1 }]);
-
-    let mut ctr = 100;
-    let separator = || {
-        ctr *= 2;
-        ctr
-    };
-    let r = (0..3).intersperse_with(separator).collect::<Vec<_>>();
-    assert_eq!(r, vec![0, 200, 1, 400, 2]);
-}
-
-#[test]
-fn test_intersperse_fold() {
-    let v = (1..4).intersperse(9).fold(Vec::new(), |mut acc, x| {
-        acc.push(x);
-        acc
-    });
-    assert_eq!(v.as_slice(), [1, 9, 2, 9, 3]);
-
-    let mut iter = (1..4).intersperse(9);
-    assert_eq!(iter.next(), Some(1));
-    let v = iter.fold(Vec::new(), |mut acc, x| {
-        acc.push(x);
-        acc
-    });
-    assert_eq!(v.as_slice(), [9, 2, 9, 3]);
-
-    struct NoneAtStart(i32); // Produces: None, Some(2), Some(3), None, ...
-    impl Iterator for NoneAtStart {
-        type Item = i32;
-        fn next(&mut self) -> Option<i32> {
-            self.0 += 1;
-            Some(self.0).filter(|i| i % 3 != 1)
-        }
-    }
-
-    let v = NoneAtStart(0).intersperse(1000).fold(0, |a, b| a + b);
-    assert_eq!(v, 0);
-}
-
-#[test]
-fn test_intersperse_collect_string() {
-    let contents = vec![1, 2, 3];
-
-    let contents_string = contents
-        .into_iter()
-        .map(|id| id.to_string())
-        .intersperse(", ".to_owned())
-        .collect::<String>();
-    assert_eq!(contents_string, "1, 2, 3");
-}
-
-#[test]
-fn test_try_fold_specialization_intersperse_err() {
-    let orig_iter = ["a", "b"].iter().copied().intersperse("-");
-
-    // Abort after the first item.
-    let mut iter = orig_iter.clone();
-    iter.try_for_each(|_| None::<()>);
-    assert_eq!(iter.next(), Some("-"));
-    assert_eq!(iter.next(), Some("b"));
-    assert_eq!(iter.next(), None);
-
-    // Abort after the second item.
-    let mut iter = orig_iter.clone();
-    iter.try_for_each(|item| if item == "-" { None } else { Some(()) });
-    assert_eq!(iter.next(), Some("b"));
-    assert_eq!(iter.next(), None);
-
-    // Abort after the third item.
-    let mut iter = orig_iter.clone();
-    iter.try_for_each(|item| if item == "b" { None } else { Some(()) });
-    assert_eq!(iter.next(), None);
-}
diff --git a/library/core/tests/iter/adapters/map.rs b/library/core/tests/iter/adapters/map.rs
deleted file mode 100644
index 77ce3819b322e..0000000000000
--- a/library/core/tests/iter/adapters/map.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_map_try_folds() {
-    let f = &|acc, x| i32::checked_add(2 * acc, x);
-    assert_eq!((0..10).map(|x| x + 3).try_fold(7, f), (3..13).try_fold(7, f));
-    assert_eq!((0..10).map(|x| x + 3).try_rfold(7, f), (3..13).try_rfold(7, f));
-
-    let mut iter = (0..40).map(|x| x + 10);
-    assert_eq!(iter.try_fold(0, i8::checked_add), None);
-    assert_eq!(iter.next(), Some(20));
-    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
-    assert_eq!(iter.next_back(), Some(46));
-}
-
-#[test]
-fn test_double_ended_map() {
-    let xs = [1, 2, 3, 4, 5, 6];
-    let mut it = xs.iter().map(|&x| x * -1);
-    assert_eq!(it.next(), Some(-1));
-    assert_eq!(it.next(), Some(-2));
-    assert_eq!(it.next_back(), Some(-6));
-    assert_eq!(it.next_back(), Some(-5));
-    assert_eq!(it.next(), Some(-3));
-    assert_eq!(it.next_back(), Some(-4));
-    assert_eq!(it.next(), None);
-}
diff --git a/library/core/tests/iter/adapters/mod.rs b/library/core/tests/iter/adapters/mod.rs
deleted file mode 100644
index 96a53be1eaa50..0000000000000
--- a/library/core/tests/iter/adapters/mod.rs
+++ /dev/null
@@ -1,185 +0,0 @@
-mod chain;
-mod cloned;
-mod copied;
-mod cycle;
-mod enumerate;
-mod filter;
-mod filter_map;
-mod flat_map;
-mod flatten;
-mod fuse;
-mod inspect;
-mod intersperse;
-mod map;
-mod peekable;
-mod scan;
-mod skip;
-mod skip_while;
-mod step_by;
-mod take;
-mod take_while;
-mod zip;
-
-use core::cell::Cell;
-
-/// An iterator that panics whenever `next` or next_back` is called
-/// after `None` has already been returned. This does not violate
-/// `Iterator`'s contract. Used to test that iterator adaptors don't
-/// poll their inner iterators after exhausting them.
-pub struct NonFused<I> {
-    iter: I,
-    done: bool,
-}
-
-impl<I> NonFused<I> {
-    pub fn new(iter: I) -> Self {
-        Self { iter, done: false }
-    }
-}
-
-impl<I> Iterator for NonFused<I>
-where
-    I: Iterator,
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        assert!(!self.done, "this iterator has already returned None");
-        self.iter.next().or_else(|| {
-            self.done = true;
-            None
-        })
-    }
-}
-
-impl<I> DoubleEndedIterator for NonFused<I>
-where
-    I: DoubleEndedIterator,
-{
-    fn next_back(&mut self) -> Option<Self::Item> {
-        assert!(!self.done, "this iterator has already returned None");
-        self.iter.next_back().or_else(|| {
-            self.done = true;
-            None
-        })
-    }
-}
-
-/// An iterator wrapper that panics whenever `next` or `next_back` is called
-/// after `None` has been returned.
-pub struct Unfuse<I> {
-    iter: I,
-    exhausted: bool,
-}
-
-impl<I> Unfuse<I> {
-    pub fn new<T>(iter: T) -> Self
-    where
-        T: IntoIterator<IntoIter = I>,
-    {
-        Self { iter: iter.into_iter(), exhausted: false }
-    }
-}
-
-impl<I> Iterator for Unfuse<I>
-where
-    I: Iterator,
-{
-    type Item = I::Item;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        assert!(!self.exhausted);
-        let next = self.iter.next();
-        self.exhausted = next.is_none();
-        next
-    }
-}
-
-impl<I> DoubleEndedIterator for Unfuse<I>
-where
-    I: DoubleEndedIterator,
-{
-    fn next_back(&mut self) -> Option<Self::Item> {
-        assert!(!self.exhausted);
-        let next = self.iter.next_back();
-        self.exhausted = next.is_none();
-        next
-    }
-}
-
-pub struct Toggle {
-    is_empty: bool,
-}
-
-impl Iterator for Toggle {
-    type Item = ();
-
-    // alternates between `None` and `Some(())`
-    fn next(&mut self) -> Option<Self::Item> {
-        if self.is_empty {
-            self.is_empty = false;
-            None
-        } else {
-            self.is_empty = true;
-            Some(())
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.is_empty { (0, Some(0)) } else { (1, Some(1)) }
-    }
-}
-
-impl DoubleEndedIterator for Toggle {
-    fn next_back(&mut self) -> Option<Self::Item> {
-        self.next()
-    }
-}
-
-/// This is an iterator that follows the Iterator contract,
-/// but it is not fused. After having returned None once, it will start
-/// producing elements if .next() is called again.
-pub struct CycleIter<'a, T> {
-    index: usize,
-    data: &'a [T],
-}
-
-impl<'a, T> CycleIter<'a, T> {
-    pub fn new(data: &'a [T]) -> Self {
-        Self { index: 0, data }
-    }
-}
-
-impl<'a, T> Iterator for CycleIter<'a, T> {
-    type Item = &'a T;
-    fn next(&mut self) -> Option<Self::Item> {
-        let elt = self.data.get(self.index);
-        self.index += 1;
-        self.index %= 1 + self.data.len();
-        elt
-    }
-}
-
-#[derive(Debug)]
-struct CountClone(Cell<i32>);
-
-impl CountClone {
-    pub fn new() -> Self {
-        Self(Cell::new(0))
-    }
-}
-
-impl PartialEq<i32> for CountClone {
-    fn eq(&self, rhs: &i32) -> bool {
-        self.0.get() == *rhs
-    }
-}
-
-impl Clone for CountClone {
-    fn clone(&self) -> Self {
-        let ret = CountClone(self.0.clone());
-        let n = self.0.get();
-        self.0.set(n + 1);
-        ret
-    }
-}
diff --git a/library/core/tests/iter/adapters/peekable.rs b/library/core/tests/iter/adapters/peekable.rs
deleted file mode 100644
index 390414d4aa213..0000000000000
--- a/library/core/tests/iter/adapters/peekable.rs
+++ /dev/null
@@ -1,272 +0,0 @@
-use super::*;
-use core::iter::*;
-
-#[test]
-fn test_iterator_peekable() {
-    let xs = vec![0, 1, 2, 3, 4, 5];
-
-    let mut it = xs.iter().cloned().peekable();
-    assert_eq!(it.len(), 6);
-    assert_eq!(it.peek().unwrap(), &0);
-    assert_eq!(it.len(), 6);
-    assert_eq!(it.next().unwrap(), 0);
-    assert_eq!(it.len(), 5);
-    assert_eq!(it.next().unwrap(), 1);
-    assert_eq!(it.len(), 4);
-    assert_eq!(it.next().unwrap(), 2);
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.peek().unwrap(), &3);
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.peek().unwrap(), &3);
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.next().unwrap(), 3);
-    assert_eq!(it.len(), 2);
-    assert_eq!(it.next().unwrap(), 4);
-    assert_eq!(it.len(), 1);
-    assert_eq!(it.peek().unwrap(), &5);
-    assert_eq!(it.len(), 1);
-    assert_eq!(it.next().unwrap(), 5);
-    assert_eq!(it.len(), 0);
-    assert!(it.peek().is_none());
-    assert_eq!(it.len(), 0);
-    assert!(it.next().is_none());
-    assert_eq!(it.len(), 0);
-
-    let mut it = xs.iter().cloned().peekable();
-    assert_eq!(it.len(), 6);
-    assert_eq!(it.peek().unwrap(), &0);
-    assert_eq!(it.len(), 6);
-    assert_eq!(it.next_back().unwrap(), 5);
-    assert_eq!(it.len(), 5);
-    assert_eq!(it.next_back().unwrap(), 4);
-    assert_eq!(it.len(), 4);
-    assert_eq!(it.next_back().unwrap(), 3);
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.peek().unwrap(), &0);
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.peek().unwrap(), &0);
-    assert_eq!(it.len(), 3);
-    assert_eq!(it.next_back().unwrap(), 2);
-    assert_eq!(it.len(), 2);
-    assert_eq!(it.next_back().unwrap(), 1);
-    assert_eq!(it.len(), 1);
-    assert_eq!(it.peek().unwrap(), &0);
-    assert_eq!(it.len(), 1);
-    assert_eq!(it.next_back().unwrap(), 0);
-    assert_eq!(it.len(), 0);
-    assert!(it.peek().is_none());
-    assert_eq!(it.len(), 0);
-    assert!(it.next_back().is_none());
-    assert_eq!(it.len(), 0);
-}
-
-#[test]
-fn test_iterator_peekable_count() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let ys = [10];
-    let zs: [i32; 0] = [];
-
-    assert_eq!(xs.iter().peekable().count(), 6);
-
-    let mut it = xs.iter().peekable();
-    assert_eq!(it.peek(), Some(&&0));
-    assert_eq!(it.count(), 6);
-
-    assert_eq!(ys.iter().peekable().count(), 1);
-
-    let mut it = ys.iter().peekable();
-    assert_eq!(it.peek(), Some(&&10));
-    assert_eq!(it.count(), 1);
-
-    assert_eq!(zs.iter().peekable().count(), 0);
-
-    let mut it = zs.iter().peekable();
-    assert_eq!(it.peek(), None);
-}
-
-#[test]
-fn test_iterator_peekable_nth() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let mut it = xs.iter().peekable();
-
-    assert_eq!(it.peek(), Some(&&0));
-    assert_eq!(it.nth(0), Some(&0));
-    assert_eq!(it.peek(), Some(&&1));
-    assert_eq!(it.nth(1), Some(&2));
-    assert_eq!(it.peek(), Some(&&3));
-    assert_eq!(it.nth(2), Some(&5));
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_iterator_peekable_last() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let ys = [0];
-
-    let mut it = xs.iter().peekable();
-    assert_eq!(it.peek(), Some(&&0));
-    assert_eq!(it.last(), Some(&5));
-
-    let mut it = ys.iter().peekable();
-    assert_eq!(it.peek(), Some(&&0));
-    assert_eq!(it.last(), Some(&0));
-
-    let mut it = ys.iter().peekable();
-    assert_eq!(it.next(), Some(&0));
-    assert_eq!(it.peek(), None);
-    assert_eq!(it.last(), None);
-}
-
-#[test]
-fn test_iterator_peekable_fold() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let mut it = xs.iter().peekable();
-    assert_eq!(it.peek(), Some(&&0));
-    let i = it.fold(0, |i, &x| {
-        assert_eq!(x, xs[i]);
-        i + 1
-    });
-    assert_eq!(i, xs.len());
-}
-
-#[test]
-fn test_iterator_peekable_rfold() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let mut it = xs.iter().peekable();
-    assert_eq!(it.peek(), Some(&&0));
-    let i = it.rfold(0, |i, &x| {
-        assert_eq!(x, xs[xs.len() - 1 - i]);
-        i + 1
-    });
-    assert_eq!(i, xs.len());
-}
-
-#[test]
-fn test_iterator_peekable_next_if_eq() {
-    // first, try on references
-    let xs = vec!["Heart", "of", "Gold"];
-    let mut it = xs.into_iter().peekable();
-    // try before `peek()`
-    assert_eq!(it.next_if_eq(&"trillian"), None);
-    assert_eq!(it.next_if_eq(&"Heart"), Some("Heart"));
-    // try after peek()
-    assert_eq!(it.peek(), Some(&"of"));
-    assert_eq!(it.next_if_eq(&"of"), Some("of"));
-    assert_eq!(it.next_if_eq(&"zaphod"), None);
-    // make sure `next()` still behaves
-    assert_eq!(it.next(), Some("Gold"));
-
-    // make sure comparison works for owned values
-    let xs = vec![String::from("Ludicrous"), "speed".into()];
-    let mut it = xs.into_iter().peekable();
-    // make sure basic functionality works
-    assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into()));
-    assert_eq!(it.next_if_eq("speed"), Some("speed".into()));
-    assert_eq!(it.next_if_eq(""), None);
-}
-
-#[test]
-fn test_iterator_peekable_mut() {
-    let mut it = vec![1, 2, 3].into_iter().peekable();
-    if let Some(p) = it.peek_mut() {
-        if *p == 1 {
-            *p = 5;
-        }
-    }
-    assert_eq!(it.collect::<Vec<_>>(), vec![5, 2, 3]);
-}
-
-#[test]
-fn test_iterator_peekable_remember_peek_none_1() {
-    // Check that the loop using .peek() terminates
-    let data = [1, 2, 3];
-    let mut iter = CycleIter::new(&data).peekable();
-
-    let mut n = 0;
-    while let Some(_) = iter.next() {
-        let is_the_last = iter.peek().is_none();
-        assert_eq!(is_the_last, n == data.len() - 1);
-        n += 1;
-        if n > data.len() {
-            break;
-        }
-    }
-    assert_eq!(n, data.len());
-}
-
-#[test]
-fn test_iterator_peekable_remember_peek_none_2() {
-    let data = [0];
-    let mut iter = CycleIter::new(&data).peekable();
-    iter.next();
-    assert_eq!(iter.peek(), None);
-    assert_eq!(iter.last(), None);
-}
-
-#[test]
-fn test_iterator_peekable_remember_peek_none_3() {
-    let data = [0];
-    let mut iter = CycleIter::new(&data).peekable();
-    iter.peek();
-    assert_eq!(iter.nth(0), Some(&0));
-
-    let mut iter = CycleIter::new(&data).peekable();
-    iter.next();
-    assert_eq!(iter.peek(), None);
-    assert_eq!(iter.nth(0), None);
-}
-
-#[test]
-fn test_peek_try_folds() {
-    let f = &|acc, x| i32::checked_add(2 * acc, x);
-
-    assert_eq!((1..20).peekable().try_fold(7, f), (1..20).try_fold(7, f));
-    assert_eq!((1..20).peekable().try_rfold(7, f), (1..20).try_rfold(7, f));
-
-    let mut iter = (1..20).peekable();
-    assert_eq!(iter.peek(), Some(&1));
-    assert_eq!(iter.try_fold(7, f), (1..20).try_fold(7, f));
-
-    let mut iter = (1..20).peekable();
-    assert_eq!(iter.peek(), Some(&1));
-    assert_eq!(iter.try_rfold(7, f), (1..20).try_rfold(7, f));
-
-    let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable();
-    assert_eq!(iter.peek(), Some(&100));
-    assert_eq!(iter.try_fold(0, i8::checked_add), None);
-    assert_eq!(iter.peek(), Some(&40));
-
-    let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable();
-    assert_eq!(iter.peek(), Some(&100));
-    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
-    assert_eq!(iter.peek(), Some(&100));
-    assert_eq!(iter.next_back(), Some(50));
-
-    let mut iter = (2..5).peekable();
-    assert_eq!(iter.peek(), Some(&2));
-    assert_eq!(iter.try_for_each(Err), Err(2));
-    assert_eq!(iter.peek(), Some(&3));
-    assert_eq!(iter.try_for_each(Err), Err(3));
-    assert_eq!(iter.peek(), Some(&4));
-    assert_eq!(iter.try_for_each(Err), Err(4));
-    assert_eq!(iter.peek(), None);
-    assert_eq!(iter.try_for_each(Err), Ok(()));
-
-    let mut iter = (2..5).peekable();
-    assert_eq!(iter.peek(), Some(&2));
-    assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(4));
-    assert_eq!(iter.peek(), Some(&2));
-    assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(3));
-    assert_eq!(iter.peek(), Some(&2));
-    assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(2));
-    assert_eq!(iter.peek(), None);
-    assert_eq!(iter.try_rfold((), |(), x| Err(x)), Ok(()));
-}
-
-#[test]
-fn test_peekable_non_fused() {
-    let mut iter = NonFused::new(empty::<i32>()).peekable();
-
-    assert_eq!(iter.peek(), None);
-    assert_eq!(iter.next_back(), None);
-}
diff --git a/library/core/tests/iter/adapters/scan.rs b/library/core/tests/iter/adapters/scan.rs
deleted file mode 100644
index 1d28ca6b7fdc5..0000000000000
--- a/library/core/tests/iter/adapters/scan.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_iterator_scan() {
-    // test the type inference
-    fn add(old: &mut isize, new: &usize) -> Option<f64> {
-        *old += *new as isize;
-        Some(*old as f64)
-    }
-    let xs = [0, 1, 2, 3, 4];
-    let ys = [0f64, 1.0, 3.0, 6.0, 10.0];
-
-    let it = xs.iter().scan(0, add);
-    let mut i = 0;
-    for x in it {
-        assert_eq!(x, ys[i]);
-        i += 1;
-    }
-    assert_eq!(i, ys.len());
-}
diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs
deleted file mode 100644
index cf60057a1644a..0000000000000
--- a/library/core/tests/iter/adapters/skip.rs
+++ /dev/null
@@ -1,181 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_iterator_skip() {
-    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
-    let ys = [13, 15, 16, 17, 19, 20, 30];
-    let mut it = xs.iter().skip(5);
-    let mut i = 0;
-    while let Some(&x) = it.next() {
-        assert_eq!(x, ys[i]);
-        i += 1;
-        assert_eq!(it.len(), xs.len() - 5 - i);
-    }
-    assert_eq!(i, ys.len());
-    assert_eq!(it.len(), 0);
-}
-
-#[test]
-fn test_iterator_skip_doubleended() {
-    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
-    let mut it = xs.iter().rev().skip(5);
-    assert_eq!(it.next(), Some(&15));
-    assert_eq!(it.by_ref().rev().next(), Some(&0));
-    assert_eq!(it.next(), Some(&13));
-    assert_eq!(it.by_ref().rev().next(), Some(&1));
-    assert_eq!(it.next(), Some(&5));
-    assert_eq!(it.by_ref().rev().next(), Some(&2));
-    assert_eq!(it.next(), Some(&3));
-    assert_eq!(it.next(), None);
-    let mut it = xs.iter().rev().skip(5).rev();
-    assert_eq!(it.next(), Some(&0));
-    assert_eq!(it.rev().next(), Some(&15));
-    let mut it_base = xs.iter();
-    {
-        let mut it = it_base.by_ref().skip(5).rev();
-        assert_eq!(it.next(), Some(&30));
-        assert_eq!(it.next(), Some(&20));
-        assert_eq!(it.next(), Some(&19));
-        assert_eq!(it.next(), Some(&17));
-        assert_eq!(it.next(), Some(&16));
-        assert_eq!(it.next(), Some(&15));
-        assert_eq!(it.next(), Some(&13));
-        assert_eq!(it.next(), None);
-    }
-    // make sure the skipped parts have not been consumed
-    assert_eq!(it_base.next(), Some(&0));
-    assert_eq!(it_base.next(), Some(&1));
-    assert_eq!(it_base.next(), Some(&2));
-    assert_eq!(it_base.next(), Some(&3));
-    assert_eq!(it_base.next(), Some(&5));
-    assert_eq!(it_base.next(), None);
-    let it = xs.iter().skip(5).rev();
-    assert_eq!(it.last(), Some(&13));
-}
-
-#[test]
-fn test_iterator_skip_nth() {
-    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
-
-    let mut it = xs.iter().skip(0);
-    assert_eq!(it.nth(0), Some(&0));
-    assert_eq!(it.nth(1), Some(&2));
-
-    let mut it = xs.iter().skip(5);
-    assert_eq!(it.nth(0), Some(&13));
-    assert_eq!(it.nth(1), Some(&16));
-
-    let mut it = xs.iter().skip(12);
-    assert_eq!(it.nth(0), None);
-}
-
-#[test]
-fn test_iterator_skip_count() {
-    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
-
-    assert_eq!(xs.iter().skip(0).count(), 12);
-    assert_eq!(xs.iter().skip(1).count(), 11);
-    assert_eq!(xs.iter().skip(11).count(), 1);
-    assert_eq!(xs.iter().skip(12).count(), 0);
-    assert_eq!(xs.iter().skip(13).count(), 0);
-}
-
-#[test]
-fn test_iterator_skip_last() {
-    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
-
-    assert_eq!(xs.iter().skip(0).last(), Some(&30));
-    assert_eq!(xs.iter().skip(1).last(), Some(&30));
-    assert_eq!(xs.iter().skip(11).last(), Some(&30));
-    assert_eq!(xs.iter().skip(12).last(), None);
-    assert_eq!(xs.iter().skip(13).last(), None);
-
-    let mut it = xs.iter().skip(5);
-    assert_eq!(it.next(), Some(&13));
-    assert_eq!(it.last(), Some(&30));
-}
-
-#[test]
-fn test_iterator_skip_fold() {
-    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
-    let ys = [13, 15, 16, 17, 19, 20, 30];
-
-    let it = xs.iter().skip(5);
-    let i = it.fold(0, |i, &x| {
-        assert_eq!(x, ys[i]);
-        i + 1
-    });
-    assert_eq!(i, ys.len());
-
-    let mut it = xs.iter().skip(5);
-    assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
-    let i = it.fold(1, |i, &x| {
-        assert_eq!(x, ys[i]);
-        i + 1
-    });
-    assert_eq!(i, ys.len());
-
-    let it = xs.iter().skip(5);
-    let i = it.rfold(ys.len(), |i, &x| {
-        let i = i - 1;
-        assert_eq!(x, ys[i]);
-        i
-    });
-    assert_eq!(i, 0);
-
-    let mut it = xs.iter().skip(5);
-    assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
-    let i = it.rfold(ys.len(), |i, &x| {
-        let i = i - 1;
-        assert_eq!(x, ys[i]);
-        i
-    });
-    assert_eq!(i, 1);
-}
-
-#[test]
-fn test_skip_try_folds() {
-    let f = &|acc, x| i32::checked_add(2 * acc, x);
-    assert_eq!((1..20).skip(9).try_fold(7, f), (10..20).try_fold(7, f));
-    assert_eq!((1..20).skip(9).try_rfold(7, f), (10..20).try_rfold(7, f));
-
-    let mut iter = (0..30).skip(10);
-    assert_eq!(iter.try_fold(0, i8::checked_add), None);
-    assert_eq!(iter.next(), Some(20));
-    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
-    assert_eq!(iter.next_back(), Some(24));
-}
-
-#[test]
-fn test_skip_nth_back() {
-    let xs = [0, 1, 2, 3, 4, 5];
-    let mut it = xs.iter().skip(2);
-    assert_eq!(it.nth_back(0), Some(&5));
-    assert_eq!(it.nth_back(1), Some(&3));
-    assert_eq!(it.nth_back(0), Some(&2));
-    assert_eq!(it.nth_back(0), None);
-
-    let ys = [2, 3, 4, 5];
-    let mut ity = ys.iter();
-    let mut it = xs.iter().skip(2);
-    assert_eq!(it.nth_back(1), ity.nth_back(1));
-    assert_eq!(it.clone().nth(0), ity.clone().nth(0));
-    assert_eq!(it.nth_back(0), ity.nth_back(0));
-    assert_eq!(it.clone().nth(0), ity.clone().nth(0));
-    assert_eq!(it.nth_back(0), ity.nth_back(0));
-    assert_eq!(it.clone().nth(0), ity.clone().nth(0));
-    assert_eq!(it.nth_back(0), ity.nth_back(0));
-    assert_eq!(it.clone().nth(0), ity.clone().nth(0));
-
-    let mut it = xs.iter().skip(2);
-    assert_eq!(it.nth_back(4), None);
-    assert_eq!(it.nth_back(0), None);
-
-    let mut it = xs.iter();
-    it.by_ref().skip(2).nth_back(3);
-    assert_eq!(it.next_back(), Some(&1));
-
-    let mut it = xs.iter();
-    it.by_ref().skip(2).nth_back(10);
-    assert_eq!(it.next_back(), Some(&1));
-}
diff --git a/library/core/tests/iter/adapters/skip_while.rs b/library/core/tests/iter/adapters/skip_while.rs
deleted file mode 100644
index 929d4f6e64fd0..0000000000000
--- a/library/core/tests/iter/adapters/skip_while.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_iterator_skip_while() {
-    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
-    let ys = [15, 16, 17, 19];
-    let it = xs.iter().skip_while(|&x| *x < 15);
-    let mut i = 0;
-    for x in it {
-        assert_eq!(*x, ys[i]);
-        i += 1;
-    }
-    assert_eq!(i, ys.len());
-}
-
-#[test]
-fn test_iterator_skip_while_fold() {
-    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
-    let ys = [15, 16, 17, 19];
-    let it = xs.iter().skip_while(|&x| *x < 15);
-    let i = it.fold(0, |i, &x| {
-        assert_eq!(x, ys[i]);
-        i + 1
-    });
-    assert_eq!(i, ys.len());
-
-    let mut it = xs.iter().skip_while(|&x| *x < 15);
-    assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
-    let i = it.fold(1, |i, &x| {
-        assert_eq!(x, ys[i]);
-        i + 1
-    });
-    assert_eq!(i, ys.len());
-}
-
-#[test]
-fn test_skip_while_try_fold() {
-    let f = &|acc, x| i32::checked_add(2 * acc, x);
-    fn p(&x: &i32) -> bool {
-        (x % 10) <= 5
-    }
-    assert_eq!((1..20).skip_while(p).try_fold(7, f), (6..20).try_fold(7, f));
-    let mut iter = (1..20).skip_while(p);
-    assert_eq!(iter.nth(5), Some(11));
-    assert_eq!(iter.try_fold(7, f), (12..20).try_fold(7, f));
-
-    let mut iter = (0..50).skip_while(|&x| (x % 20) < 15);
-    assert_eq!(iter.try_fold(0, i8::checked_add), None);
-    assert_eq!(iter.next(), Some(23));
-}
diff --git a/library/core/tests/iter/adapters/step_by.rs b/library/core/tests/iter/adapters/step_by.rs
deleted file mode 100644
index 6502c7fb79588..0000000000000
--- a/library/core/tests/iter/adapters/step_by.rs
+++ /dev/null
@@ -1,248 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_iterator_step_by() {
-    // Identity
-    let mut it = (0..).step_by(1).take(3);
-    assert_eq!(it.next(), Some(0));
-    assert_eq!(it.next(), Some(1));
-    assert_eq!(it.next(), Some(2));
-    assert_eq!(it.next(), None);
-
-    let mut it = (0..).step_by(3).take(4);
-    assert_eq!(it.next(), Some(0));
-    assert_eq!(it.next(), Some(3));
-    assert_eq!(it.next(), Some(6));
-    assert_eq!(it.next(), Some(9));
-    assert_eq!(it.next(), None);
-
-    let mut it = (0..3).step_by(1);
-    assert_eq!(it.next_back(), Some(2));
-    assert_eq!(it.next_back(), Some(1));
-    assert_eq!(it.next_back(), Some(0));
-    assert_eq!(it.next_back(), None);
-
-    let mut it = (0..11).step_by(3);
-    assert_eq!(it.next_back(), Some(9));
-    assert_eq!(it.next_back(), Some(6));
-    assert_eq!(it.next_back(), Some(3));
-    assert_eq!(it.next_back(), Some(0));
-    assert_eq!(it.next_back(), None);
-}
-
-#[test]
-fn test_iterator_step_by_nth() {
-    let mut it = (0..16).step_by(5);
-    assert_eq!(it.nth(0), Some(0));
-    assert_eq!(it.nth(0), Some(5));
-    assert_eq!(it.nth(0), Some(10));
-    assert_eq!(it.nth(0), Some(15));
-    assert_eq!(it.nth(0), None);
-
-    let it = (0..18).step_by(5);
-    assert_eq!(it.clone().nth(0), Some(0));
-    assert_eq!(it.clone().nth(1), Some(5));
-    assert_eq!(it.clone().nth(2), Some(10));
-    assert_eq!(it.clone().nth(3), Some(15));
-    assert_eq!(it.clone().nth(4), None);
-    assert_eq!(it.clone().nth(42), None);
-}
-
-#[test]
-fn test_iterator_step_by_nth_overflow() {
-    #[cfg(target_pointer_width = "8")]
-    type Bigger = u16;
-    #[cfg(target_pointer_width = "16")]
-    type Bigger = u32;
-    #[cfg(target_pointer_width = "32")]
-    type Bigger = u64;
-    #[cfg(target_pointer_width = "64")]
-    type Bigger = u128;
-
-    #[derive(Clone)]
-    struct Test(Bigger);
-    impl Iterator for &mut Test {
-        type Item = i32;
-        fn next(&mut self) -> Option<Self::Item> {
-            Some(21)
-        }
-        fn nth(&mut self, n: usize) -> Option<Self::Item> {
-            self.0 += n as Bigger + 1;
-            Some(42)
-        }
-    }
-
-    let mut it = Test(0);
-    let root = usize::MAX >> (usize::BITS / 2);
-    let n = root + 20;
-    (&mut it).step_by(n).nth(n);
-    assert_eq!(it.0, n as Bigger * n as Bigger);
-
-    // large step
-    let mut it = Test(0);
-    (&mut it).step_by(usize::MAX).nth(5);
-    assert_eq!(it.0, (usize::MAX as Bigger) * 5);
-
-    // n + 1 overflows
-    let mut it = Test(0);
-    (&mut it).step_by(2).nth(usize::MAX);
-    assert_eq!(it.0, (usize::MAX as Bigger) * 2);
-
-    // n + 1 overflows
-    let mut it = Test(0);
-    (&mut it).step_by(1).nth(usize::MAX);
-    assert_eq!(it.0, (usize::MAX as Bigger) * 1);
-}
-
-#[test]
-fn test_iterator_step_by_nth_try_fold() {
-    let mut it = (0..).step_by(10);
-    assert_eq!(it.try_fold(0, i8::checked_add), None);
-    assert_eq!(it.next(), Some(60));
-    assert_eq!(it.try_fold(0, i8::checked_add), None);
-    assert_eq!(it.next(), Some(90));
-
-    let mut it = (100..).step_by(10);
-    assert_eq!(it.try_fold(50, i8::checked_add), None);
-    assert_eq!(it.next(), Some(110));
-
-    let mut it = (100..=100).step_by(10);
-    assert_eq!(it.next(), Some(100));
-    assert_eq!(it.try_fold(0, i8::checked_add), Some(0));
-}
-
-#[test]
-fn test_iterator_step_by_nth_back() {
-    let mut it = (0..16).step_by(5);
-    assert_eq!(it.nth_back(0), Some(15));
-    assert_eq!(it.nth_back(0), Some(10));
-    assert_eq!(it.nth_back(0), Some(5));
-    assert_eq!(it.nth_back(0), Some(0));
-    assert_eq!(it.nth_back(0), None);
-
-    let mut it = (0..16).step_by(5);
-    assert_eq!(it.next(), Some(0)); // to set `first_take` to `false`
-    assert_eq!(it.nth_back(0), Some(15));
-    assert_eq!(it.nth_back(0), Some(10));
-    assert_eq!(it.nth_back(0), Some(5));
-    assert_eq!(it.nth_back(0), None);
-
-    let it = || (0..18).step_by(5);
-    assert_eq!(it().nth_back(0), Some(15));
-    assert_eq!(it().nth_back(1), Some(10));
-    assert_eq!(it().nth_back(2), Some(5));
-    assert_eq!(it().nth_back(3), Some(0));
-    assert_eq!(it().nth_back(4), None);
-    assert_eq!(it().nth_back(42), None);
-}
-
-#[test]
-fn test_iterator_step_by_nth_try_rfold() {
-    let mut it = (0..100).step_by(10);
-    assert_eq!(it.try_rfold(0, i8::checked_add), None);
-    assert_eq!(it.next_back(), Some(70));
-    assert_eq!(it.next(), Some(0));
-    assert_eq!(it.try_rfold(0, i8::checked_add), None);
-    assert_eq!(it.next_back(), Some(30));
-
-    let mut it = (0..100).step_by(10);
-    assert_eq!(it.try_rfold(50, i8::checked_add), None);
-    assert_eq!(it.next_back(), Some(80));
-
-    let mut it = (100..=100).step_by(10);
-    assert_eq!(it.next_back(), Some(100));
-    assert_eq!(it.try_fold(0, i8::checked_add), Some(0));
-}
-
-#[test]
-#[should_panic]
-fn test_iterator_step_by_zero() {
-    let mut it = (0..).step_by(0);
-    it.next();
-}
-
-#[test]
-fn test_iterator_step_by_size_hint() {
-    struct StubSizeHint(usize, Option<usize>);
-    impl Iterator for StubSizeHint {
-        type Item = ();
-        fn next(&mut self) -> Option<()> {
-            self.0 -= 1;
-            if let Some(ref mut upper) = self.1 {
-                *upper -= 1;
-            }
-            Some(())
-        }
-        fn size_hint(&self) -> (usize, Option<usize>) {
-            (self.0, self.1)
-        }
-    }
-
-    // The two checks in each case are needed because the logic
-    // is different before the first call to `next()`.
-
-    let mut it = StubSizeHint(10, Some(10)).step_by(1);
-    assert_eq!(it.size_hint(), (10, Some(10)));
-    it.next();
-    assert_eq!(it.size_hint(), (9, Some(9)));
-
-    // exact multiple
-    let mut it = StubSizeHint(10, Some(10)).step_by(3);
-    assert_eq!(it.size_hint(), (4, Some(4)));
-    it.next();
-    assert_eq!(it.size_hint(), (3, Some(3)));
-
-    // larger base range, but not enough to get another element
-    let mut it = StubSizeHint(12, Some(12)).step_by(3);
-    assert_eq!(it.size_hint(), (4, Some(4)));
-    it.next();
-    assert_eq!(it.size_hint(), (3, Some(3)));
-
-    // smaller base range, so fewer resulting elements
-    let mut it = StubSizeHint(9, Some(9)).step_by(3);
-    assert_eq!(it.size_hint(), (3, Some(3)));
-    it.next();
-    assert_eq!(it.size_hint(), (2, Some(2)));
-
-    // infinite upper bound
-    let mut it = StubSizeHint(usize::MAX, None).step_by(1);
-    assert_eq!(it.size_hint(), (usize::MAX, None));
-    it.next();
-    assert_eq!(it.size_hint(), (usize::MAX - 1, None));
-
-    // still infinite with larger step
-    let mut it = StubSizeHint(7, None).step_by(3);
-    assert_eq!(it.size_hint(), (3, None));
-    it.next();
-    assert_eq!(it.size_hint(), (2, None));
-
-    // propagates ExactSizeIterator
-    let a = [1, 2, 3, 4, 5];
-    let it = a.iter().step_by(2);
-    assert_eq!(it.len(), 3);
-
-    // Cannot be TrustedLen as a step greater than one makes an iterator
-    // with (usize::MAX, None) no longer meet the safety requirements
-    trait TrustedLenCheck {
-        fn test(self) -> bool;
-    }
-    impl<T: Iterator> TrustedLenCheck for T {
-        default fn test(self) -> bool {
-            false
-        }
-    }
-    impl<T: TrustedLen> TrustedLenCheck for T {
-        fn test(self) -> bool {
-            true
-        }
-    }
-    assert!(TrustedLenCheck::test(a.iter()));
-    assert!(!TrustedLenCheck::test(a.iter().step_by(1)));
-}
-
-#[test]
-fn test_step_by_skip() {
-    assert_eq!((0..640).step_by(128).skip(1).collect::<Vec<_>>(), [128, 256, 384, 512]);
-    assert_eq!((0..=50).step_by(10).nth(3), Some(30));
-    assert_eq!((200..=255u8).step_by(10).nth(3), Some(230));
-}
diff --git a/library/core/tests/iter/adapters/take.rs b/library/core/tests/iter/adapters/take.rs
deleted file mode 100644
index 89f9cb1e2ed1b..0000000000000
--- a/library/core/tests/iter/adapters/take.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_iterator_take() {
-    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
-    let ys = [0, 1, 2, 3, 5];
-
-    let mut it = xs.iter().take(ys.len());
-    let mut i = 0;
-    assert_eq!(it.len(), ys.len());
-    while let Some(&x) = it.next() {
-        assert_eq!(x, ys[i]);
-        i += 1;
-        assert_eq!(it.len(), ys.len() - i);
-    }
-    assert_eq!(i, ys.len());
-    assert_eq!(it.len(), 0);
-
-    let mut it = xs.iter().take(ys.len());
-    let mut i = 0;
-    assert_eq!(it.len(), ys.len());
-    while let Some(&x) = it.next_back() {
-        i += 1;
-        assert_eq!(x, ys[ys.len() - i]);
-        assert_eq!(it.len(), ys.len() - i);
-    }
-    assert_eq!(i, ys.len());
-    assert_eq!(it.len(), 0);
-}
-
-#[test]
-fn test_iterator_take_nth() {
-    let xs = [0, 1, 2, 4, 5];
-    let mut it = xs.iter();
-    {
-        let mut take = it.by_ref().take(3);
-        let mut i = 0;
-        while let Some(&x) = take.nth(0) {
-            assert_eq!(x, i);
-            i += 1;
-        }
-    }
-    assert_eq!(it.nth(1), Some(&5));
-    assert_eq!(it.nth(0), None);
-
-    let xs = [0, 1, 2, 3, 4];
-    let mut it = xs.iter().take(7);
-    let mut i = 1;
-    while let Some(&x) = it.nth(1) {
-        assert_eq!(x, i);
-        i += 2;
-    }
-}
-
-#[test]
-fn test_iterator_take_nth_back() {
-    let xs = [0, 1, 2, 4, 5];
-    let mut it = xs.iter();
-    {
-        let mut take = it.by_ref().take(3);
-        let mut i = 0;
-        while let Some(&x) = take.nth_back(0) {
-            i += 1;
-            assert_eq!(x, 3 - i);
-        }
-    }
-    assert_eq!(it.nth_back(0), None);
-
-    let xs = [0, 1, 2, 3, 4];
-    let mut it = xs.iter().take(7);
-    assert_eq!(it.nth_back(1), Some(&3));
-    assert_eq!(it.nth_back(1), Some(&1));
-    assert_eq!(it.nth_back(1), None);
-}
-
-#[test]
-fn test_iterator_take_short() {
-    let xs = [0, 1, 2, 3];
-
-    let mut it = xs.iter().take(5);
-    let mut i = 0;
-    assert_eq!(it.len(), xs.len());
-    while let Some(&x) = it.next() {
-        assert_eq!(x, xs[i]);
-        i += 1;
-        assert_eq!(it.len(), xs.len() - i);
-    }
-    assert_eq!(i, xs.len());
-    assert_eq!(it.len(), 0);
-
-    let mut it = xs.iter().take(5);
-    let mut i = 0;
-    assert_eq!(it.len(), xs.len());
-    while let Some(&x) = it.next_back() {
-        i += 1;
-        assert_eq!(x, xs[xs.len() - i]);
-        assert_eq!(it.len(), xs.len() - i);
-    }
-    assert_eq!(i, xs.len());
-    assert_eq!(it.len(), 0);
-}
-
-#[test]
-fn test_take_try_folds() {
-    let f = &|acc, x| i32::checked_add(2 * acc, x);
-    assert_eq!((10..30).take(10).try_fold(7, f), (10..20).try_fold(7, f));
-    assert_eq!((10..30).take(10).try_rfold(7, f), (10..20).try_rfold(7, f));
-
-    let mut iter = (10..30).take(20);
-    assert_eq!(iter.try_fold(0, i8::checked_add), None);
-    assert_eq!(iter.next(), Some(20));
-    assert_eq!(iter.try_rfold(0, i8::checked_add), None);
-    assert_eq!(iter.next_back(), Some(24));
-
-    let mut iter = (2..20).take(3);
-    assert_eq!(iter.try_for_each(Err), Err(2));
-    assert_eq!(iter.try_for_each(Err), Err(3));
-    assert_eq!(iter.try_for_each(Err), Err(4));
-    assert_eq!(iter.try_for_each(Err), Ok(()));
-
-    let mut iter = (2..20).take(3).rev();
-    assert_eq!(iter.try_for_each(Err), Err(4));
-    assert_eq!(iter.try_for_each(Err), Err(3));
-    assert_eq!(iter.try_for_each(Err), Err(2));
-    assert_eq!(iter.try_for_each(Err), Ok(()));
-}
diff --git a/library/core/tests/iter/adapters/take_while.rs b/library/core/tests/iter/adapters/take_while.rs
deleted file mode 100644
index 6f1ebab29b31c..0000000000000
--- a/library/core/tests/iter/adapters/take_while.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_iterator_take_while() {
-    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
-    let ys = [0, 1, 2, 3, 5, 13];
-    let it = xs.iter().take_while(|&x| *x < 15);
-    let mut i = 0;
-    for x in it {
-        assert_eq!(*x, ys[i]);
-        i += 1;
-    }
-    assert_eq!(i, ys.len());
-}
-
-#[test]
-fn test_take_while_folds() {
-    let f = &|acc, x| i32::checked_add(2 * acc, x);
-    assert_eq!((1..20).take_while(|&x| x != 10).try_fold(7, f), (1..10).try_fold(7, f));
-    let mut iter = (1..20).take_while(|&x| x != 10);
-    assert_eq!(iter.try_fold(0, |x, y| Some(x + y)), Some((1..10).sum()));
-    assert_eq!(iter.next(), None, "flag should be set");
-    let iter = (1..20).take_while(|&x| x != 10);
-    assert_eq!(iter.fold(0, |x, y| x + y), (1..10).sum());
-
-    let mut iter = (10..50).take_while(|&x| x != 40);
-    assert_eq!(iter.try_fold(0, i8::checked_add), None);
-    assert_eq!(iter.next(), Some(20));
-}
diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs
deleted file mode 100644
index 1fce0951e365e..0000000000000
--- a/library/core/tests/iter/adapters/zip.rs
+++ /dev/null
@@ -1,247 +0,0 @@
-use super::*;
-use core::iter::*;
-
-#[test]
-fn test_zip_nth() {
-    let xs = [0, 1, 2, 4, 5];
-    let ys = [10, 11, 12];
-
-    let mut it = xs.iter().zip(&ys);
-    assert_eq!(it.nth(0), Some((&0, &10)));
-    assert_eq!(it.nth(1), Some((&2, &12)));
-    assert_eq!(it.nth(0), None);
-
-    let mut it = xs.iter().zip(&ys);
-    assert_eq!(it.nth(3), None);
-
-    let mut it = ys.iter().zip(&xs);
-    assert_eq!(it.nth(3), None);
-}
-
-#[test]
-fn test_zip_nth_side_effects() {
-    let mut a = Vec::new();
-    let mut b = Vec::new();
-    let value = [1, 2, 3, 4, 5, 6]
-        .iter()
-        .cloned()
-        .map(|n| {
-            a.push(n);
-            n * 10
-        })
-        .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
-            b.push(n * 100);
-            n * 1000
-        }))
-        .skip(1)
-        .nth(3);
-    assert_eq!(value, Some((50, 6000)));
-    assert_eq!(a, vec![1, 2, 3, 4, 5]);
-    assert_eq!(b, vec![200, 300, 400, 500, 600]);
-}
-
-#[test]
-fn test_zip_next_back_side_effects() {
-    let mut a = Vec::new();
-    let mut b = Vec::new();
-    let mut iter = [1, 2, 3, 4, 5, 6]
-        .iter()
-        .cloned()
-        .map(|n| {
-            a.push(n);
-            n * 10
-        })
-        .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
-            b.push(n * 100);
-            n * 1000
-        }));
-
-    // The second iterator is one item longer, so `next_back` is called on it
-    // one more time.
-    assert_eq!(iter.next_back(), Some((60, 7000)));
-    assert_eq!(iter.next_back(), Some((50, 6000)));
-    assert_eq!(iter.next_back(), Some((40, 5000)));
-    assert_eq!(iter.next_back(), Some((30, 4000)));
-    assert_eq!(a, vec![6, 5, 4, 3]);
-    assert_eq!(b, vec![800, 700, 600, 500, 400]);
-}
-
-#[test]
-fn test_zip_nth_back_side_effects() {
-    let mut a = Vec::new();
-    let mut b = Vec::new();
-    let value = [1, 2, 3, 4, 5, 6]
-        .iter()
-        .cloned()
-        .map(|n| {
-            a.push(n);
-            n * 10
-        })
-        .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
-            b.push(n * 100);
-            n * 1000
-        }))
-        .nth_back(3);
-    assert_eq!(value, Some((30, 4000)));
-    assert_eq!(a, vec![6, 5, 4, 3]);
-    assert_eq!(b, vec![800, 700, 600, 500, 400]);
-}
-
-#[test]
-fn test_zip_next_back_side_effects_exhausted() {
-    let mut a = Vec::new();
-    let mut b = Vec::new();
-    let mut iter = [1, 2, 3, 4, 5, 6]
-        .iter()
-        .cloned()
-        .map(|n| {
-            a.push(n);
-            n * 10
-        })
-        .zip([2, 3, 4].iter().cloned().map(|n| {
-            b.push(n * 100);
-            n * 1000
-        }));
-
-    iter.next();
-    iter.next();
-    iter.next();
-    iter.next();
-    assert_eq!(iter.next_back(), None);
-    assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
-    assert_eq!(b, vec![200, 300, 400]);
-}
-
-#[test]
-fn test_zip_cloned_sideffectful() {
-    let xs = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()];
-    let ys = [CountClone::new(), CountClone::new()];
-
-    for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
-
-    assert_eq!(&xs, &[1, 1, 1, 0][..]);
-    assert_eq!(&ys, &[1, 1][..]);
-
-    let xs = [CountClone::new(), CountClone::new()];
-    let ys = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()];
-
-    for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
-
-    assert_eq!(&xs, &[1, 1][..]);
-    assert_eq!(&ys, &[1, 1, 0, 0][..]);
-}
-
-#[test]
-fn test_zip_map_sideffectful() {
-    let mut xs = [0; 6];
-    let mut ys = [0; 4];
-
-    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
-
-    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
-    assert_eq!(&ys, &[1, 1, 1, 1]);
-
-    let mut xs = [0; 4];
-    let mut ys = [0; 6];
-
-    for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
-
-    assert_eq!(&xs, &[1, 1, 1, 1]);
-    assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]);
-}
-
-#[test]
-fn test_zip_map_rev_sideffectful() {
-    let mut xs = [0; 6];
-    let mut ys = [0; 4];
-
-    {
-        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
-        it.next_back();
-    }
-    assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]);
-    assert_eq!(&ys, &[0, 0, 0, 1]);
-
-    let mut xs = [0; 6];
-    let mut ys = [0; 4];
-
-    {
-        let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
-        (&mut it).take(5).count();
-        it.next_back();
-    }
-    assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]);
-    assert_eq!(&ys, &[1, 1, 1, 1]);
-}
-
-#[test]
-fn test_zip_nested_sideffectful() {
-    let mut xs = [0; 6];
-    let ys = [0; 4];
-
-    {
-        // test that it has the side effect nested inside enumerate
-        let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys);
-        it.count();
-    }
-    assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
-}
-
-#[test]
-fn test_zip_nth_back_side_effects_exhausted() {
-    let mut a = Vec::new();
-    let mut b = Vec::new();
-    let mut iter = [1, 2, 3, 4, 5, 6]
-        .iter()
-        .cloned()
-        .map(|n| {
-            a.push(n);
-            n * 10
-        })
-        .zip([2, 3, 4].iter().cloned().map(|n| {
-            b.push(n * 100);
-            n * 1000
-        }));
-
-    iter.next();
-    iter.next();
-    iter.next();
-    iter.next();
-    assert_eq!(iter.nth_back(0), None);
-    assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
-    assert_eq!(b, vec![200, 300, 400]);
-}
-
-#[test]
-fn test_zip_trusted_random_access_composition() {
-    let a = [0, 1, 2, 3, 4];
-    let b = a;
-    let c = a;
-
-    let a = a.iter().copied();
-    let b = b.iter().copied();
-    let mut c = c.iter().copied();
-    c.next();
-
-    let mut z1 = a.zip(b);
-    assert_eq!(z1.next().unwrap(), (0, 0));
-
-    let mut z2 = z1.zip(c);
-    fn assert_trusted_random_access<T: TrustedRandomAccess>(_a: &T) {}
-    assert_trusted_random_access(&z2);
-    assert_eq!(z2.next().unwrap(), ((1, 1), 1));
-}
-
-#[test]
-fn test_double_ended_zip() {
-    let xs = [1, 2, 3, 4, 5, 6];
-    let ys = [1, 2, 3, 7];
-    let a = xs.iter().cloned();
-    let b = ys.iter().cloned();
-    let mut it = a.zip(b);
-    assert_eq!(it.next(), Some((1, 1)));
-    assert_eq!(it.next(), Some((2, 2)));
-    assert_eq!(it.next_back(), Some((4, 7)));
-    assert_eq!(it.next_back(), Some((3, 3)));
-    assert_eq!(it.next(), None);
-}
diff --git a/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs
deleted file mode 100644
index 770b6f7601fa2..0000000000000
--- a/library/core/tests/iter/mod.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-//! Note
-//! ----
-//! You're probably viewing this file because you're adding a test (or you might
-//! just be browsing, in that case, hey there!).
-//!
-//! The iter test suite is split into two big modules, and some miscellaneous
-//! smaller modules. The two big modules are `adapters` and `traits`.
-//!
-//! `adapters` are for methods on `Iterator` that adapt the data inside the
-//! iterator, whether it be by emitting another iterator or returning an item
-//! from inside the iterator after executing a closure on each item.
-//!
-//! `traits` are for trait's that extend an `Iterator` (and the `Iterator`
-//! trait itself, mostly containing miscellaneous methods). For the most part,
-//! if a test in `traits` uses a specific adapter, then it should be moved to
-//! that adapter's test file in `adapters`.
-
-mod adapters;
-mod range;
-mod sources;
-mod traits;
-
-use core::cell::Cell;
-use core::convert::TryFrom;
-use core::iter::*;
-
-pub fn is_trusted_len<I: TrustedLen>(_: I) {}
-
-#[test]
-fn test_multi_iter() {
-    let xs = [1, 2, 3, 4];
-    let ys = [4, 3, 2, 1];
-    assert!(xs.iter().eq(ys.iter().rev()));
-    assert!(xs.iter().lt(xs.iter().skip(2)));
-}
-
-#[test]
-fn test_counter_from_iter() {
-    let it = (0..).step_by(5).take(10);
-    let xs: Vec<isize> = FromIterator::from_iter(it);
-    assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
-}
-
-#[test]
-fn test_functor_laws() {
-    // identity:
-    fn identity<T>(x: T) -> T {
-        x
-    }
-    assert_eq!((0..10).map(identity).sum::<usize>(), (0..10).sum());
-
-    // composition:
-    fn f(x: usize) -> usize {
-        x + 3
-    }
-    fn g(x: usize) -> usize {
-        x * 2
-    }
-    fn h(x: usize) -> usize {
-        g(f(x))
-    }
-    assert_eq!((0..10).map(f).map(g).sum::<usize>(), (0..10).map(h).sum());
-}
-
-#[test]
-fn test_monad_laws_left_identity() {
-    fn f(x: usize) -> impl Iterator<Item = usize> {
-        (0..10).map(move |y| x * y)
-    }
-    assert_eq!(once(42).flat_map(f.clone()).sum::<usize>(), f(42).sum());
-}
-
-#[test]
-fn test_monad_laws_right_identity() {
-    assert_eq!((0..10).flat_map(|x| once(x)).sum::<usize>(), (0..10).sum());
-}
-
-#[test]
-fn test_monad_laws_associativity() {
-    fn f(x: usize) -> impl Iterator<Item = usize> {
-        0..x
-    }
-    fn g(x: usize) -> impl Iterator<Item = usize> {
-        (0..x).rev()
-    }
-    assert_eq!(
-        (0..10).flat_map(f).flat_map(g).sum::<usize>(),
-        (0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>()
-    );
-}
-
-#[test]
-pub fn extend_for_unit() {
-    let mut x = 0;
-    {
-        let iter = (0..5).map(|_| {
-            x += 1;
-        });
-        ().extend(iter);
-    }
-    assert_eq!(x, 5);
-}
diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs
deleted file mode 100644
index 44adc3c58d249..0000000000000
--- a/library/core/tests/iter/range.rs
+++ /dev/null
@@ -1,446 +0,0 @@
-use super::*;
-
-#[test]
-fn test_range() {
-    assert_eq!((0..5).collect::<Vec<_>>(), [0, 1, 2, 3, 4]);
-    assert_eq!((-10..-1).collect::<Vec<_>>(), [-10, -9, -8, -7, -6, -5, -4, -3, -2]);
-    assert_eq!((0..5).rev().collect::<Vec<_>>(), [4, 3, 2, 1, 0]);
-    assert_eq!((200..-5).count(), 0);
-    assert_eq!((200..-5).rev().count(), 0);
-    assert_eq!((200..200).count(), 0);
-    assert_eq!((200..200).rev().count(), 0);
-
-    assert_eq!((0..100).size_hint(), (100, Some(100)));
-    // this test is only meaningful when sizeof usize < sizeof u64
-    assert_eq!((usize::MAX - 1..usize::MAX).size_hint(), (1, Some(1)));
-    assert_eq!((-10..-1).size_hint(), (9, Some(9)));
-    assert_eq!((-1..-10).size_hint(), (0, Some(0)));
-
-    assert_eq!((-70..58).size_hint(), (128, Some(128)));
-    assert_eq!((-128..127).size_hint(), (255, Some(255)));
-    assert_eq!(
-        (-2..isize::MAX).size_hint(),
-        (isize::MAX as usize + 2, Some(isize::MAX as usize + 2))
-    );
-}
-
-#[test]
-fn test_char_range() {
-    use std::char;
-    // Miri is too slow
-    let from = if cfg!(miri) { char::from_u32(0xD800 - 10).unwrap() } else { '\0' };
-    let to = if cfg!(miri) { char::from_u32(0xDFFF + 10).unwrap() } else { char::MAX };
-    assert!((from..=to).eq((from as u32..=to as u32).filter_map(char::from_u32)));
-    assert!((from..=to).rev().eq((from as u32..=to as u32).filter_map(char::from_u32).rev()));
-
-    assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2);
-    assert_eq!(('\u{D7FF}'..='\u{E000}').size_hint(), (2, Some(2)));
-    assert_eq!(('\u{D7FF}'..'\u{E000}').count(), 1);
-    assert_eq!(('\u{D7FF}'..'\u{E000}').size_hint(), (1, Some(1)));
-}
-
-#[test]
-fn test_range_exhaustion() {
-    let mut r = 10..10;
-    assert!(r.is_empty());
-    assert_eq!(r.next(), None);
-    assert_eq!(r.next_back(), None);
-    assert_eq!(r, 10..10);
-
-    let mut r = 10..12;
-    assert_eq!(r.next(), Some(10));
-    assert_eq!(r.next(), Some(11));
-    assert!(r.is_empty());
-    assert_eq!(r, 12..12);
-    assert_eq!(r.next(), None);
-
-    let mut r = 10..12;
-    assert_eq!(r.next_back(), Some(11));
-    assert_eq!(r.next_back(), Some(10));
-    assert!(r.is_empty());
-    assert_eq!(r, 10..10);
-    assert_eq!(r.next_back(), None);
-
-    let mut r = 100..10;
-    assert!(r.is_empty());
-    assert_eq!(r.next(), None);
-    assert_eq!(r.next_back(), None);
-    assert_eq!(r, 100..10);
-}
-
-#[test]
-fn test_range_inclusive_exhaustion() {
-    let mut r = 10..=10;
-    assert_eq!(r.next(), Some(10));
-    assert!(r.is_empty());
-    assert_eq!(r.next(), None);
-    assert_eq!(r.next(), None);
-
-    assert_eq!(*r.start(), 10);
-    assert_eq!(*r.end(), 10);
-    assert_ne!(r, 10..=10);
-
-    let mut r = 10..=10;
-    assert_eq!(r.next_back(), Some(10));
-    assert!(r.is_empty());
-    assert_eq!(r.next_back(), None);
-
-    assert_eq!(*r.start(), 10);
-    assert_eq!(*r.end(), 10);
-    assert_ne!(r, 10..=10);
-
-    let mut r = 10..=12;
-    assert_eq!(r.next(), Some(10));
-    assert_eq!(r.next(), Some(11));
-    assert_eq!(r.next(), Some(12));
-    assert!(r.is_empty());
-    assert_eq!(r.next(), None);
-
-    let mut r = 10..=12;
-    assert_eq!(r.next_back(), Some(12));
-    assert_eq!(r.next_back(), Some(11));
-    assert_eq!(r.next_back(), Some(10));
-    assert!(r.is_empty());
-    assert_eq!(r.next_back(), None);
-
-    let mut r = 10..=12;
-    assert_eq!(r.nth(2), Some(12));
-    assert!(r.is_empty());
-    assert_eq!(r.next(), None);
-
-    let mut r = 10..=12;
-    assert_eq!(r.nth(5), None);
-    assert!(r.is_empty());
-    assert_eq!(r.next(), None);
-
-    let mut r = 100..=10;
-    assert_eq!(r.next(), None);
-    assert!(r.is_empty());
-    assert_eq!(r.next(), None);
-    assert_eq!(r.next(), None);
-    assert_eq!(r, 100..=10);
-
-    let mut r = 100..=10;
-    assert_eq!(r.next_back(), None);
-    assert!(r.is_empty());
-    assert_eq!(r.next_back(), None);
-    assert_eq!(r.next_back(), None);
-    assert_eq!(r, 100..=10);
-}
-
-#[test]
-fn test_range_nth() {
-    assert_eq!((10..15).nth(0), Some(10));
-    assert_eq!((10..15).nth(1), Some(11));
-    assert_eq!((10..15).nth(4), Some(14));
-    assert_eq!((10..15).nth(5), None);
-
-    let mut r = 10..20;
-    assert_eq!(r.nth(2), Some(12));
-    assert_eq!(r, 13..20);
-    assert_eq!(r.nth(2), Some(15));
-    assert_eq!(r, 16..20);
-    assert_eq!(r.nth(10), None);
-    assert_eq!(r, 20..20);
-}
-
-#[test]
-fn test_range_nth_back() {
-    assert_eq!((10..15).nth_back(0), Some(14));
-    assert_eq!((10..15).nth_back(1), Some(13));
-    assert_eq!((10..15).nth_back(4), Some(10));
-    assert_eq!((10..15).nth_back(5), None);
-    assert_eq!((-120..80_i8).nth_back(199), Some(-120));
-
-    let mut r = 10..20;
-    assert_eq!(r.nth_back(2), Some(17));
-    assert_eq!(r, 10..17);
-    assert_eq!(r.nth_back(2), Some(14));
-    assert_eq!(r, 10..14);
-    assert_eq!(r.nth_back(10), None);
-    assert_eq!(r, 10..10);
-}
-
-#[test]
-fn test_range_from_nth() {
-    assert_eq!((10..).nth(0), Some(10));
-    assert_eq!((10..).nth(1), Some(11));
-    assert_eq!((10..).nth(4), Some(14));
-
-    let mut r = 10..;
-    assert_eq!(r.nth(2), Some(12));
-    assert_eq!(r, 13..);
-    assert_eq!(r.nth(2), Some(15));
-    assert_eq!(r, 16..);
-    assert_eq!(r.nth(10), Some(26));
-    assert_eq!(r, 27..);
-
-    assert_eq!((0..).size_hint(), (usize::MAX, None));
-}
-
-#[test]
-fn test_range_from_take() {
-    let mut it = (0..).take(3);
-    assert_eq!(it.next(), Some(0));
-    assert_eq!(it.next(), Some(1));
-    assert_eq!(it.next(), Some(2));
-    assert_eq!(it.next(), None);
-    is_trusted_len((0..).take(3));
-    assert_eq!((0..).take(3).size_hint(), (3, Some(3)));
-    assert_eq!((0..).take(0).size_hint(), (0, Some(0)));
-    assert_eq!((0..).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
-}
-
-#[test]
-fn test_range_from_take_collect() {
-    let v: Vec<_> = (0..).take(3).collect();
-    assert_eq!(v, vec![0, 1, 2]);
-}
-
-#[test]
-fn test_range_inclusive_nth() {
-    assert_eq!((10..=15).nth(0), Some(10));
-    assert_eq!((10..=15).nth(1), Some(11));
-    assert_eq!((10..=15).nth(5), Some(15));
-    assert_eq!((10..=15).nth(6), None);
-
-    let mut exhausted_via_next = 10_u8..=20;
-    while exhausted_via_next.next().is_some() {}
-
-    let mut r = 10_u8..=20;
-    assert_eq!(r.nth(2), Some(12));
-    assert_eq!(r, 13..=20);
-    assert_eq!(r.nth(2), Some(15));
-    assert_eq!(r, 16..=20);
-    assert_eq!(r.is_empty(), false);
-    assert_eq!(ExactSizeIterator::is_empty(&r), false);
-    assert_eq!(r.nth(10), None);
-    assert_eq!(r.is_empty(), true);
-    assert_eq!(r, exhausted_via_next);
-    assert_eq!(ExactSizeIterator::is_empty(&r), true);
-}
-
-#[test]
-fn test_range_inclusive_nth_back() {
-    assert_eq!((10..=15).nth_back(0), Some(15));
-    assert_eq!((10..=15).nth_back(1), Some(14));
-    assert_eq!((10..=15).nth_back(5), Some(10));
-    assert_eq!((10..=15).nth_back(6), None);
-    assert_eq!((-120..=80_i8).nth_back(200), Some(-120));
-
-    let mut exhausted_via_next_back = 10_u8..=20;
-    while exhausted_via_next_back.next_back().is_some() {}
-
-    let mut r = 10_u8..=20;
-    assert_eq!(r.nth_back(2), Some(18));
-    assert_eq!(r, 10..=17);
-    assert_eq!(r.nth_back(2), Some(15));
-    assert_eq!(r, 10..=14);
-    assert_eq!(r.is_empty(), false);
-    assert_eq!(ExactSizeIterator::is_empty(&r), false);
-    assert_eq!(r.nth_back(10), None);
-    assert_eq!(r.is_empty(), true);
-    assert_eq!(r, exhausted_via_next_back);
-    assert_eq!(ExactSizeIterator::is_empty(&r), true);
-}
-
-#[test]
-fn test_range_len() {
-    assert_eq!((0..10_u8).len(), 10);
-    assert_eq!((9..10_u8).len(), 1);
-    assert_eq!((10..10_u8).len(), 0);
-    assert_eq!((11..10_u8).len(), 0);
-    assert_eq!((100..10_u8).len(), 0);
-}
-
-#[test]
-fn test_range_inclusive_len() {
-    assert_eq!((0..=10_u8).len(), 11);
-    assert_eq!((9..=10_u8).len(), 2);
-    assert_eq!((10..=10_u8).len(), 1);
-    assert_eq!((11..=10_u8).len(), 0);
-    assert_eq!((100..=10_u8).len(), 0);
-}
-
-#[test]
-fn test_range_step() {
-    #![allow(deprecated)]
-
-    assert_eq!((0..20).step_by(5).collect::<Vec<isize>>(), [0, 5, 10, 15]);
-    assert_eq!((1..21).rev().step_by(5).collect::<Vec<isize>>(), [20, 15, 10, 5]);
-    assert_eq!((1..21).rev().step_by(6).collect::<Vec<isize>>(), [20, 14, 8, 2]);
-    assert_eq!((200..255).step_by(50).collect::<Vec<u8>>(), [200, 250]);
-    assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []);
-    assert_eq!((200..200).step_by(1).collect::<Vec<isize>>(), []);
-
-    assert_eq!((0..20).step_by(1).size_hint(), (20, Some(20)));
-    assert_eq!((0..20).step_by(21).size_hint(), (1, Some(1)));
-    assert_eq!((0..20).step_by(5).size_hint(), (4, Some(4)));
-    assert_eq!((1..21).rev().step_by(5).size_hint(), (4, Some(4)));
-    assert_eq!((1..21).rev().step_by(6).size_hint(), (4, Some(4)));
-    assert_eq!((20..-5).step_by(1).size_hint(), (0, Some(0)));
-    assert_eq!((20..20).step_by(1).size_hint(), (0, Some(0)));
-    assert_eq!((i8::MIN..i8::MAX).step_by(-(i8::MIN as i32) as usize).size_hint(), (2, Some(2)));
-    assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX as usize).size_hint(), (3, Some(3)));
-    assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX)));
-}
-
-#[test]
-fn test_range_inclusive_step() {
-    assert_eq!((0..=50).step_by(10).collect::<Vec<_>>(), [0, 10, 20, 30, 40, 50]);
-    assert_eq!((0..=5).step_by(1).collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5]);
-    assert_eq!((200..=255u8).step_by(10).collect::<Vec<_>>(), [200, 210, 220, 230, 240, 250]);
-    assert_eq!((250..=255u8).step_by(1).collect::<Vec<_>>(), [250, 251, 252, 253, 254, 255]);
-}
-
-#[test]
-fn test_range_last_max() {
-    assert_eq!((0..20).last(), Some(19));
-    assert_eq!((-20..0).last(), Some(-1));
-    assert_eq!((5..5).last(), None);
-
-    assert_eq!((0..20).max(), Some(19));
-    assert_eq!((-20..0).max(), Some(-1));
-    assert_eq!((5..5).max(), None);
-}
-
-#[test]
-fn test_range_inclusive_last_max() {
-    assert_eq!((0..=20).last(), Some(20));
-    assert_eq!((-20..=0).last(), Some(0));
-    assert_eq!((5..=5).last(), Some(5));
-    let mut r = 10..=10;
-    r.next();
-    assert_eq!(r.last(), None);
-
-    assert_eq!((0..=20).max(), Some(20));
-    assert_eq!((-20..=0).max(), Some(0));
-    assert_eq!((5..=5).max(), Some(5));
-    let mut r = 10..=10;
-    r.next();
-    assert_eq!(r.max(), None);
-}
-
-#[test]
-fn test_range_min() {
-    assert_eq!((0..20).min(), Some(0));
-    assert_eq!((-20..0).min(), Some(-20));
-    assert_eq!((5..5).min(), None);
-}
-
-#[test]
-fn test_range_inclusive_min() {
-    assert_eq!((0..=20).min(), Some(0));
-    assert_eq!((-20..=0).min(), Some(-20));
-    assert_eq!((5..=5).min(), Some(5));
-    let mut r = 10..=10;
-    r.next();
-    assert_eq!(r.min(), None);
-}
-
-#[test]
-fn test_range_inclusive_folds() {
-    assert_eq!((1..=10).sum::<i32>(), 55);
-    assert_eq!((1..=10).rev().sum::<i32>(), 55);
-
-    let mut it = 44..=50;
-    assert_eq!(it.try_fold(0, i8::checked_add), None);
-    assert_eq!(it, 47..=50);
-    assert_eq!(it.try_fold(0, i8::checked_add), None);
-    assert_eq!(it, 50..=50);
-    assert_eq!(it.try_fold(0, i8::checked_add), Some(50));
-    assert!(it.is_empty());
-    assert_eq!(it.try_fold(0, i8::checked_add), Some(0));
-    assert!(it.is_empty());
-
-    let mut it = 40..=47;
-    assert_eq!(it.try_rfold(0, i8::checked_add), None);
-    assert_eq!(it, 40..=44);
-    assert_eq!(it.try_rfold(0, i8::checked_add), None);
-    assert_eq!(it, 40..=41);
-    assert_eq!(it.try_rfold(0, i8::checked_add), Some(81));
-    assert!(it.is_empty());
-    assert_eq!(it.try_rfold(0, i8::checked_add), Some(0));
-    assert!(it.is_empty());
-
-    let mut it = 10..=20;
-    assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(165));
-    assert!(it.is_empty());
-    assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(0));
-    assert!(it.is_empty());
-
-    let mut it = 10..=20;
-    assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(165));
-    assert!(it.is_empty());
-    assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(0));
-    assert!(it.is_empty());
-}
-
-#[test]
-fn test_range_size_hint() {
-    assert_eq!((0..0usize).size_hint(), (0, Some(0)));
-    assert_eq!((0..100usize).size_hint(), (100, Some(100)));
-    assert_eq!((0..usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
-
-    let umax = u128::try_from(usize::MAX).unwrap();
-    assert_eq!((0..0u128).size_hint(), (0, Some(0)));
-    assert_eq!((0..100u128).size_hint(), (100, Some(100)));
-    assert_eq!((0..umax).size_hint(), (usize::MAX, Some(usize::MAX)));
-    assert_eq!((0..umax + 1).size_hint(), (usize::MAX, None));
-
-    assert_eq!((0..0isize).size_hint(), (0, Some(0)));
-    assert_eq!((-100..100isize).size_hint(), (200, Some(200)));
-    assert_eq!((isize::MIN..isize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
-
-    let imin = i128::try_from(isize::MIN).unwrap();
-    let imax = i128::try_from(isize::MAX).unwrap();
-    assert_eq!((0..0i128).size_hint(), (0, Some(0)));
-    assert_eq!((-100..100i128).size_hint(), (200, Some(200)));
-    assert_eq!((imin..imax).size_hint(), (usize::MAX, Some(usize::MAX)));
-    assert_eq!((imin..imax + 1).size_hint(), (usize::MAX, None));
-}
-
-#[test]
-fn test_range_inclusive_size_hint() {
-    assert_eq!((1..=0usize).size_hint(), (0, Some(0)));
-    assert_eq!((0..=0usize).size_hint(), (1, Some(1)));
-    assert_eq!((0..=100usize).size_hint(), (101, Some(101)));
-    assert_eq!((0..=usize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
-    assert_eq!((0..=usize::MAX).size_hint(), (usize::MAX, None));
-
-    let umax = u128::try_from(usize::MAX).unwrap();
-    assert_eq!((1..=0u128).size_hint(), (0, Some(0)));
-    assert_eq!((0..=0u128).size_hint(), (1, Some(1)));
-    assert_eq!((0..=100u128).size_hint(), (101, Some(101)));
-    assert_eq!((0..=umax - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
-    assert_eq!((0..=umax).size_hint(), (usize::MAX, None));
-    assert_eq!((0..=umax + 1).size_hint(), (usize::MAX, None));
-
-    assert_eq!((0..=-1isize).size_hint(), (0, Some(0)));
-    assert_eq!((0..=0isize).size_hint(), (1, Some(1)));
-    assert_eq!((-100..=100isize).size_hint(), (201, Some(201)));
-    assert_eq!((isize::MIN..=isize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
-    assert_eq!((isize::MIN..=isize::MAX).size_hint(), (usize::MAX, None));
-
-    let imin = i128::try_from(isize::MIN).unwrap();
-    let imax = i128::try_from(isize::MAX).unwrap();
-    assert_eq!((0..=-1i128).size_hint(), (0, Some(0)));
-    assert_eq!((0..=0i128).size_hint(), (1, Some(1)));
-    assert_eq!((-100..=100i128).size_hint(), (201, Some(201)));
-    assert_eq!((imin..=imax - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
-    assert_eq!((imin..=imax).size_hint(), (usize::MAX, None));
-    assert_eq!((imin..=imax + 1).size_hint(), (usize::MAX, None));
-}
-
-#[test]
-fn test_double_ended_range() {
-    assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);
-    for _ in (10..0).rev() {
-        panic!("unreachable");
-    }
-
-    assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);
-    for _ in (10..0).rev() {
-        panic!("unreachable");
-    }
-}
diff --git a/library/core/tests/iter/sources.rs b/library/core/tests/iter/sources.rs
deleted file mode 100644
index d0114ade6e463..0000000000000
--- a/library/core/tests/iter/sources.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-use super::*;
-use core::iter::*;
-
-#[test]
-fn test_repeat() {
-    let mut it = repeat(42);
-    assert_eq!(it.next(), Some(42));
-    assert_eq!(it.next(), Some(42));
-    assert_eq!(it.next(), Some(42));
-    assert_eq!(repeat(42).size_hint(), (usize::MAX, None));
-}
-
-#[test]
-fn test_repeat_take() {
-    let mut it = repeat(42).take(3);
-    assert_eq!(it.next(), Some(42));
-    assert_eq!(it.next(), Some(42));
-    assert_eq!(it.next(), Some(42));
-    assert_eq!(it.next(), None);
-    is_trusted_len(repeat(42).take(3));
-    assert_eq!(repeat(42).take(3).size_hint(), (3, Some(3)));
-    assert_eq!(repeat(42).take(0).size_hint(), (0, Some(0)));
-    assert_eq!(repeat(42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
-}
-
-#[test]
-fn test_repeat_take_collect() {
-    let v: Vec<_> = repeat(42).take(3).collect();
-    assert_eq!(v, vec![42, 42, 42]);
-}
-
-#[test]
-fn test_repeat_with() {
-    #[derive(PartialEq, Debug)]
-    struct NotClone(usize);
-    let mut it = repeat_with(|| NotClone(42));
-    assert_eq!(it.next(), Some(NotClone(42)));
-    assert_eq!(it.next(), Some(NotClone(42)));
-    assert_eq!(it.next(), Some(NotClone(42)));
-    assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None));
-}
-
-#[test]
-fn test_repeat_with_take() {
-    let mut it = repeat_with(|| 42).take(3);
-    assert_eq!(it.next(), Some(42));
-    assert_eq!(it.next(), Some(42));
-    assert_eq!(it.next(), Some(42));
-    assert_eq!(it.next(), None);
-    is_trusted_len(repeat_with(|| 42).take(3));
-    assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3)));
-    assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0)));
-    assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
-}
-
-#[test]
-fn test_repeat_with_take_collect() {
-    let mut curr = 1;
-    let v: Vec<_> = repeat_with(|| {
-        let tmp = curr;
-        curr *= 2;
-        tmp
-    })
-    .take(5)
-    .collect();
-    assert_eq!(v, vec![1, 2, 4, 8, 16]);
-}
-
-#[test]
-fn test_successors() {
-    let mut powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10));
-    assert_eq!(powers_of_10.by_ref().collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]);
-    assert_eq!(powers_of_10.next(), None);
-
-    let mut empty = successors(None::<u32>, |_| unimplemented!());
-    assert_eq!(empty.next(), None);
-    assert_eq!(empty.next(), None);
-}
-
-#[test]
-fn test_once() {
-    let mut it = once(42);
-    assert_eq!(it.next(), Some(42));
-    assert_eq!(it.next(), None);
-}
-
-#[test]
-fn test_once_with() {
-    let count = Cell::new(0);
-    let mut it = once_with(|| {
-        count.set(count.get() + 1);
-        42
-    });
-
-    assert_eq!(count.get(), 0);
-    assert_eq!(it.next(), Some(42));
-    assert_eq!(count.get(), 1);
-    assert_eq!(it.next(), None);
-    assert_eq!(count.get(), 1);
-    assert_eq!(it.next(), None);
-    assert_eq!(count.get(), 1);
-}
-
-#[test]
-fn test_empty() {
-    let mut it = empty::<i32>();
-    assert_eq!(it.next(), None);
-}
diff --git a/library/core/tests/iter/traits/accum.rs b/library/core/tests/iter/traits/accum.rs
deleted file mode 100644
index f3eeb31fe5803..0000000000000
--- a/library/core/tests/iter/traits/accum.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_iterator_sum() {
-    let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    assert_eq!(v[..4].iter().cloned().sum::<i32>(), 6);
-    assert_eq!(v.iter().cloned().sum::<i32>(), 55);
-    assert_eq!(v[..0].iter().cloned().sum::<i32>(), 0);
-}
-
-#[test]
-fn test_iterator_sum_result() {
-    let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
-    assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Ok(10));
-    let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
-    assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Err(()));
-
-    #[derive(PartialEq, Debug)]
-    struct S(Result<i32, ()>);
-
-    impl Sum<Result<i32, ()>> for S {
-        fn sum<I: Iterator<Item = Result<i32, ()>>>(mut iter: I) -> Self {
-            // takes the sum by repeatedly calling `next` on `iter`,
-            // thus testing that repeated calls to `ResultShunt::try_fold`
-            // produce the expected results
-            Self(iter.by_ref().sum())
-        }
-    }
-
-    let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
-    assert_eq!(v.iter().cloned().sum::<S>(), S(Ok(10)));
-    let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
-    assert_eq!(v.iter().cloned().sum::<S>(), S(Err(())));
-}
-
-#[test]
-fn test_iterator_sum_option() {
-    let v: &[Option<i32>] = &[Some(1), Some(2), Some(3), Some(4)];
-    assert_eq!(v.iter().cloned().sum::<Option<i32>>(), Some(10));
-    let v: &[Option<i32>] = &[Some(1), None, Some(3), Some(4)];
-    assert_eq!(v.iter().cloned().sum::<Option<i32>>(), None);
-}
-
-#[test]
-fn test_iterator_product() {
-    let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    assert_eq!(v[..4].iter().cloned().product::<i32>(), 0);
-    assert_eq!(v[1..5].iter().cloned().product::<i32>(), 24);
-    assert_eq!(v[..0].iter().cloned().product::<i32>(), 1);
-}
-
-#[test]
-fn test_iterator_product_result() {
-    let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
-    assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Ok(24));
-    let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
-    assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Err(()));
-}
-
-#[test]
-fn test_iterator_product_option() {
-    let v: &[Option<i32>] = &[Some(1), Some(2), Some(3), Some(4)];
-    assert_eq!(v.iter().cloned().product::<Option<i32>>(), Some(24));
-    let v: &[Option<i32>] = &[Some(1), None, Some(3), Some(4)];
-    assert_eq!(v.iter().cloned().product::<Option<i32>>(), None);
-}
diff --git a/library/core/tests/iter/traits/double_ended.rs b/library/core/tests/iter/traits/double_ended.rs
deleted file mode 100644
index 947d19d3dfed0..0000000000000
--- a/library/core/tests/iter/traits/double_ended.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-//! Note
-//! ----
-//! You're probably viewing this file because you're adding a test (or you might
-//! just be browsing, in that case, hey there!).
-//!
-//! If you've made a test that happens to use one of DoubleEnded's methods, but
-//! it tests another adapter or trait, you should *add it to the adapter or
-//! trait's test file*.
-//!
-//! Some examples would be `adapters::cloned::test_cloned_try_folds` or
-//! `adapters::flat_map::test_double_ended_flat_map`, which use `try_fold` and
-//! `next_back`, but test their own adapter.
-
-#[test]
-fn test_iterator_rev_nth_back() {
-    let v: &[_] = &[0, 1, 2, 3, 4];
-    for i in 0..v.len() {
-        assert_eq!(v.iter().rev().nth_back(i).unwrap(), &v[i]);
-    }
-    assert_eq!(v.iter().rev().nth_back(v.len()), None);
-}
-
-#[test]
-fn test_iterator_rev_nth() {
-    let v: &[_] = &[0, 1, 2, 3, 4];
-    for i in 0..v.len() {
-        assert_eq!(v.iter().rev().nth(i).unwrap(), &v[v.len() - 1 - i]);
-    }
-    assert_eq!(v.iter().rev().nth(v.len()), None);
-}
-
-#[test]
-fn test_rev() {
-    let xs = [2, 4, 6, 8, 10, 12, 14, 16];
-    let mut it = xs.iter();
-    it.next();
-    it.next();
-    assert!(it.rev().cloned().collect::<Vec<isize>>() == vec![16, 14, 12, 10, 8, 6]);
-}
-
-#[test]
-fn test_rev_try_folds() {
-    let f = &|acc, x| i32::checked_add(2 * acc, x);
-    assert_eq!((1..10).rev().try_fold(7, f), (1..10).try_rfold(7, f));
-    assert_eq!((1..10).rev().try_rfold(7, f), (1..10).try_fold(7, f));
-
-    let a = [10, 20, 30, 40, 100, 60, 70, 80, 90];
-    let mut iter = a.iter().rev();
-    assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None);
-    assert_eq!(iter.next(), Some(&70));
-    let mut iter = a.iter().rev();
-    assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None);
-    assert_eq!(iter.next_back(), Some(&60));
-}
-
-#[test]
-fn test_rposition() {
-    fn f(xy: &(isize, char)) -> bool {
-        let (_x, y) = *xy;
-        y == 'b'
-    }
-    fn g(xy: &(isize, char)) -> bool {
-        let (_x, y) = *xy;
-        y == 'd'
-    }
-    let v = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')];
-
-    assert_eq!(v.iter().rposition(f), Some(3));
-    assert!(v.iter().rposition(g).is_none());
-}
-
-#[test]
-fn test_rev_rposition() {
-    let v = [0, 0, 1, 1];
-    assert_eq!(v.iter().rev().rposition(|&x| x == 1), Some(1));
-}
-
-#[test]
-#[should_panic]
-fn test_rposition_panic() {
-    let v: [(Box<_>, Box<_>); 4] = [(box 0, box 0), (box 0, box 0), (box 0, box 0), (box 0, box 0)];
-    let mut i = 0;
-    v.iter().rposition(|_elt| {
-        if i == 2 {
-            panic!()
-        }
-        i += 1;
-        false
-    });
-}
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
deleted file mode 100644
index 422e389e38017..0000000000000
--- a/library/core/tests/iter/traits/iterator.rs
+++ /dev/null
@@ -1,470 +0,0 @@
-/// A wrapper struct that implements `Eq` and `Ord` based on the wrapped
-/// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min`
-/// return the correct element if some of them are equal.
-#[derive(Debug)]
-struct Mod3(i32);
-
-impl PartialEq for Mod3 {
-    fn eq(&self, other: &Self) -> bool {
-        self.0 % 3 == other.0 % 3
-    }
-}
-
-impl Eq for Mod3 {}
-
-impl PartialOrd for Mod3 {
-    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for Mod3 {
-    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
-        (self.0 % 3).cmp(&(other.0 % 3))
-    }
-}
-
-#[test]
-fn test_lt() {
-    let empty: [isize; 0] = [];
-    let xs = [1, 2, 3];
-    let ys = [1, 2, 0];
-
-    assert!(!xs.iter().lt(ys.iter()));
-    assert!(!xs.iter().le(ys.iter()));
-    assert!(xs.iter().gt(ys.iter()));
-    assert!(xs.iter().ge(ys.iter()));
-
-    assert!(ys.iter().lt(xs.iter()));
-    assert!(ys.iter().le(xs.iter()));
-    assert!(!ys.iter().gt(xs.iter()));
-    assert!(!ys.iter().ge(xs.iter()));
-
-    assert!(empty.iter().lt(xs.iter()));
-    assert!(empty.iter().le(xs.iter()));
-    assert!(!empty.iter().gt(xs.iter()));
-    assert!(!empty.iter().ge(xs.iter()));
-
-    // Sequence with NaN
-    let u = [1.0f64, 2.0];
-    let v = [0.0f64 / 0.0, 3.0];
-
-    assert!(!u.iter().lt(v.iter()));
-    assert!(!u.iter().le(v.iter()));
-    assert!(!u.iter().gt(v.iter()));
-    assert!(!u.iter().ge(v.iter()));
-
-    let a = [0.0f64 / 0.0];
-    let b = [1.0f64];
-    let c = [2.0f64];
-
-    assert!(a.iter().lt(b.iter()) == (a[0] < b[0]));
-    assert!(a.iter().le(b.iter()) == (a[0] <= b[0]));
-    assert!(a.iter().gt(b.iter()) == (a[0] > b[0]));
-    assert!(a.iter().ge(b.iter()) == (a[0] >= b[0]));
-
-    assert!(c.iter().lt(b.iter()) == (c[0] < b[0]));
-    assert!(c.iter().le(b.iter()) == (c[0] <= b[0]));
-    assert!(c.iter().gt(b.iter()) == (c[0] > b[0]));
-    assert!(c.iter().ge(b.iter()) == (c[0] >= b[0]));
-}
-
-#[test]
-fn test_cmp_by() {
-    use core::cmp::Ordering;
-
-    let f = |x: i32, y: i32| (x * x).cmp(&y);
-    let xs = || [1, 2, 3, 4].iter().copied();
-    let ys = || [1, 4, 16].iter().copied();
-
-    assert_eq!(xs().cmp_by(ys(), f), Ordering::Less);
-    assert_eq!(ys().cmp_by(xs(), f), Ordering::Greater);
-    assert_eq!(xs().cmp_by(xs().map(|x| x * x), f), Ordering::Equal);
-    assert_eq!(xs().rev().cmp_by(ys().rev(), f), Ordering::Greater);
-    assert_eq!(xs().cmp_by(ys().rev(), f), Ordering::Less);
-    assert_eq!(xs().cmp_by(ys().take(2), f), Ordering::Greater);
-}
-
-#[test]
-fn test_partial_cmp_by() {
-    use core::cmp::Ordering;
-
-    let f = |x: i32, y: i32| (x * x).partial_cmp(&y);
-    let xs = || [1, 2, 3, 4].iter().copied();
-    let ys = || [1, 4, 16].iter().copied();
-
-    assert_eq!(xs().partial_cmp_by(ys(), f), Some(Ordering::Less));
-    assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
-    assert_eq!(xs().partial_cmp_by(xs().map(|x| x * x), f), Some(Ordering::Equal));
-    assert_eq!(xs().rev().partial_cmp_by(ys().rev(), f), Some(Ordering::Greater));
-    assert_eq!(xs().partial_cmp_by(xs().rev(), f), Some(Ordering::Less));
-    assert_eq!(xs().partial_cmp_by(ys().take(2), f), Some(Ordering::Greater));
-
-    let f = |x: f64, y: f64| (x * x).partial_cmp(&y);
-    let xs = || [1.0, 2.0, 3.0, 4.0].iter().copied();
-    let ys = || [1.0, 4.0, f64::NAN, 16.0].iter().copied();
-
-    assert_eq!(xs().partial_cmp_by(ys(), f), None);
-    assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
-}
-
-#[test]
-fn test_eq_by() {
-    let f = |x: i32, y: i32| x * x == y;
-    let xs = || [1, 2, 3, 4].iter().copied();
-    let ys = || [1, 4, 9, 16].iter().copied();
-
-    assert!(xs().eq_by(ys(), f));
-    assert!(!ys().eq_by(xs(), f));
-    assert!(!xs().eq_by(xs(), f));
-    assert!(!ys().eq_by(ys(), f));
-
-    assert!(!xs().take(3).eq_by(ys(), f));
-    assert!(!xs().eq_by(ys().take(3), f));
-    assert!(xs().take(3).eq_by(ys().take(3), f));
-}
-
-#[test]
-fn test_iterator_nth() {
-    let v: &[_] = &[0, 1, 2, 3, 4];
-    for i in 0..v.len() {
-        assert_eq!(v.iter().nth(i).unwrap(), &v[i]);
-    }
-    assert_eq!(v.iter().nth(v.len()), None);
-}
-
-#[test]
-fn test_iterator_nth_back() {
-    let v: &[_] = &[0, 1, 2, 3, 4];
-    for i in 0..v.len() {
-        assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - 1 - i]);
-    }
-    assert_eq!(v.iter().nth_back(v.len()), None);
-}
-
-#[test]
-fn test_iterator_advance_by() {
-    let v: &[_] = &[0, 1, 2, 3, 4];
-
-    for i in 0..v.len() {
-        let mut iter = v.iter();
-        assert_eq!(iter.advance_by(i), Ok(()));
-        assert_eq!(iter.next().unwrap(), &v[i]);
-        assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
-    }
-
-    assert_eq!(v.iter().advance_by(v.len()), Ok(()));
-    assert_eq!(v.iter().advance_by(100), Err(v.len()));
-}
-
-#[test]
-fn test_iterator_advance_back_by() {
-    let v: &[_] = &[0, 1, 2, 3, 4];
-
-    for i in 0..v.len() {
-        let mut iter = v.iter();
-        assert_eq!(iter.advance_back_by(i), Ok(()));
-        assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]);
-        assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
-    }
-
-    assert_eq!(v.iter().advance_back_by(v.len()), Ok(()));
-    assert_eq!(v.iter().advance_back_by(100), Err(v.len()));
-}
-
-#[test]
-fn test_iterator_rev_advance_back_by() {
-    let v: &[_] = &[0, 1, 2, 3, 4];
-
-    for i in 0..v.len() {
-        let mut iter = v.iter().rev();
-        assert_eq!(iter.advance_back_by(i), Ok(()));
-        assert_eq!(iter.next_back().unwrap(), &v[i]);
-        assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
-    }
-
-    assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(()));
-    assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len()));
-}
-
-#[test]
-fn test_iterator_last() {
-    let v: &[_] = &[0, 1, 2, 3, 4];
-    assert_eq!(v.iter().last().unwrap(), &4);
-    assert_eq!(v[..1].iter().last().unwrap(), &0);
-}
-
-#[test]
-fn test_iterator_max() {
-    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    assert_eq!(v[..4].iter().cloned().max(), Some(3));
-    assert_eq!(v.iter().cloned().max(), Some(10));
-    assert_eq!(v[..0].iter().cloned().max(), None);
-    assert_eq!(v.iter().cloned().map(Mod3).max().map(|x| x.0), Some(8));
-}
-
-#[test]
-fn test_iterator_min() {
-    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    assert_eq!(v[..4].iter().cloned().min(), Some(0));
-    assert_eq!(v.iter().cloned().min(), Some(0));
-    assert_eq!(v[..0].iter().cloned().min(), None);
-    assert_eq!(v.iter().cloned().map(Mod3).min().map(|x| x.0), Some(0));
-}
-
-#[test]
-fn test_iterator_size_hint() {
-    let c = (0..).step_by(1);
-    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
-    let v2 = &[10, 11, 12];
-    let vi = v.iter();
-
-    assert_eq!((0..).size_hint(), (usize::MAX, None));
-    assert_eq!(c.size_hint(), (usize::MAX, None));
-    assert_eq!(vi.clone().size_hint(), (10, Some(10)));
-
-    assert_eq!(c.clone().take(5).size_hint(), (5, Some(5)));
-    assert_eq!(c.clone().skip(5).size_hint().1, None);
-    assert_eq!(c.clone().take_while(|_| false).size_hint(), (0, None));
-    assert_eq!(c.clone().map_while(|_| None::<()>).size_hint(), (0, None));
-    assert_eq!(c.clone().skip_while(|_| false).size_hint(), (0, None));
-    assert_eq!(c.clone().enumerate().size_hint(), (usize::MAX, None));
-    assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), (usize::MAX, None));
-    assert_eq!(c.clone().zip(vi.clone()).size_hint(), (10, Some(10)));
-    assert_eq!(c.clone().scan(0, |_, _| Some(0)).size_hint(), (0, None));
-    assert_eq!(c.clone().filter(|_| false).size_hint(), (0, None));
-    assert_eq!(c.clone().map(|_| 0).size_hint(), (usize::MAX, None));
-    assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None));
-
-    assert_eq!(vi.clone().take(5).size_hint(), (5, Some(5)));
-    assert_eq!(vi.clone().take(12).size_hint(), (10, Some(10)));
-    assert_eq!(vi.clone().skip(3).size_hint(), (7, Some(7)));
-    assert_eq!(vi.clone().skip(12).size_hint(), (0, Some(0)));
-    assert_eq!(vi.clone().take_while(|_| false).size_hint(), (0, Some(10)));
-    assert_eq!(vi.clone().map_while(|_| None::<()>).size_hint(), (0, Some(10)));
-    assert_eq!(vi.clone().skip_while(|_| false).size_hint(), (0, Some(10)));
-    assert_eq!(vi.clone().enumerate().size_hint(), (10, Some(10)));
-    assert_eq!(vi.clone().chain(v2).size_hint(), (13, Some(13)));
-    assert_eq!(vi.clone().zip(v2).size_hint(), (3, Some(3)));
-    assert_eq!(vi.clone().scan(0, |_, _| Some(0)).size_hint(), (0, Some(10)));
-    assert_eq!(vi.clone().filter(|_| false).size_hint(), (0, Some(10)));
-    assert_eq!(vi.clone().map(|&i| i + 1).size_hint(), (10, Some(10)));
-    assert_eq!(vi.filter_map(|_| Some(0)).size_hint(), (0, Some(10)));
-}
-
-#[test]
-fn test_all() {
-    let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]);
-    assert!(v.iter().all(|&x| x < 10));
-    assert!(!v.iter().all(|&x| x % 2 == 0));
-    assert!(!v.iter().all(|&x| x > 100));
-    assert!(v[..0].iter().all(|_| panic!()));
-}
-
-#[test]
-fn test_any() {
-    let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]);
-    assert!(v.iter().any(|&x| x < 10));
-    assert!(v.iter().any(|&x| x % 2 == 0));
-    assert!(!v.iter().any(|&x| x > 100));
-    assert!(!v[..0].iter().any(|_| panic!()));
-}
-
-#[test]
-fn test_find() {
-    let v: &[isize] = &[1, 3, 9, 27, 103, 14, 11];
-    assert_eq!(*v.iter().find(|&&x| x & 1 == 0).unwrap(), 14);
-    assert_eq!(*v.iter().find(|&&x| x % 3 == 0).unwrap(), 3);
-    assert!(v.iter().find(|&&x| x % 12 == 0).is_none());
-}
-
-#[test]
-fn test_try_find() {
-    let xs: &[isize] = &[];
-    assert_eq!(xs.iter().try_find(testfn), Ok(None));
-    let xs: &[isize] = &[1, 2, 3, 4];
-    assert_eq!(xs.iter().try_find(testfn), Ok(Some(&2)));
-    let xs: &[isize] = &[1, 3, 4];
-    assert_eq!(xs.iter().try_find(testfn), Err(()));
-
-    let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7];
-    let mut iter = xs.iter();
-    assert_eq!(iter.try_find(testfn), Ok(Some(&2)));
-    assert_eq!(iter.try_find(testfn), Err(()));
-    assert_eq!(iter.next(), Some(&5));
-
-    fn testfn(x: &&isize) -> Result<bool, ()> {
-        if **x == 2 {
-            return Ok(true);
-        }
-        if **x == 4 {
-            return Err(());
-        }
-        Ok(false)
-    }
-}
-
-#[test]
-fn test_try_find_api_usability() -> Result<(), Box<dyn std::error::Error>> {
-    let a = ["1", "2"];
-
-    let is_my_num = |s: &str, search: i32| -> Result<bool, std::num::ParseIntError> {
-        Ok(s.parse::<i32>()? == search)
-    };
-
-    let val = a.iter().try_find(|&&s| is_my_num(s, 2))?;
-    assert_eq!(val, Some(&"2"));
-
-    Ok(())
-}
-
-#[test]
-fn test_position() {
-    let v = &[1, 3, 9, 27, 103, 14, 11];
-    assert_eq!(v.iter().position(|x| *x & 1 == 0).unwrap(), 5);
-    assert_eq!(v.iter().position(|x| *x % 3 == 0).unwrap(), 1);
-    assert!(v.iter().position(|x| *x % 12 == 0).is_none());
-}
-
-#[test]
-fn test_count() {
-    let xs = &[1, 2, 2, 1, 5, 9, 0, 2];
-    assert_eq!(xs.iter().filter(|x| **x == 2).count(), 3);
-    assert_eq!(xs.iter().filter(|x| **x == 5).count(), 1);
-    assert_eq!(xs.iter().filter(|x| **x == 95).count(), 0);
-}
-
-#[test]
-fn test_max_by_key() {
-    let xs: &[isize] = &[-3, 0, 1, 5, -10];
-    assert_eq!(*xs.iter().max_by_key(|x| x.abs()).unwrap(), -10);
-}
-
-#[test]
-fn test_max_by() {
-    let xs: &[isize] = &[-3, 0, 1, 5, -10];
-    assert_eq!(*xs.iter().max_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), -10);
-}
-
-#[test]
-fn test_min_by_key() {
-    let xs: &[isize] = &[-3, 0, 1, 5, -10];
-    assert_eq!(*xs.iter().min_by_key(|x| x.abs()).unwrap(), 0);
-}
-
-#[test]
-fn test_min_by() {
-    let xs: &[isize] = &[-3, 0, 1, 5, -10];
-    assert_eq!(*xs.iter().min_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), 0);
-}
-
-#[test]
-fn test_by_ref() {
-    let mut xs = 0..10;
-    // sum the first five values
-    let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b);
-    assert_eq!(partial_sum, 10);
-    assert_eq!(xs.next(), Some(5));
-}
-
-#[test]
-fn test_is_sorted() {
-    assert!([1, 2, 2, 9].iter().is_sorted());
-    assert!(![1, 3, 2].iter().is_sorted());
-    assert!([0].iter().is_sorted());
-    assert!(std::iter::empty::<i32>().is_sorted());
-    assert!(![0.0, 1.0, f32::NAN].iter().is_sorted());
-    assert!([-2, -1, 0, 3].iter().is_sorted());
-    assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
-    assert!(!["c", "bb", "aaa"].iter().is_sorted());
-    assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len()));
-}
-
-#[test]
-fn test_partition() {
-    fn check(xs: &mut [i32], ref p: impl Fn(&i32) -> bool, expected: usize) {
-        let i = xs.iter_mut().partition_in_place(p);
-        assert_eq!(expected, i);
-        assert!(xs[..i].iter().all(p));
-        assert!(!xs[i..].iter().any(p));
-        assert!(xs.iter().is_partitioned(p));
-        if i == 0 || i == xs.len() {
-            assert!(xs.iter().rev().is_partitioned(p));
-        } else {
-            assert!(!xs.iter().rev().is_partitioned(p));
-        }
-    }
-
-    check(&mut [], |_| true, 0);
-    check(&mut [], |_| false, 0);
-
-    check(&mut [0], |_| true, 1);
-    check(&mut [0], |_| false, 0);
-
-    check(&mut [-1, 1], |&x| x > 0, 1);
-    check(&mut [-1, 1], |&x| x < 0, 1);
-
-    let ref mut xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
-    check(xs, |_| true, 10);
-    check(xs, |_| false, 0);
-    check(xs, |&x| x % 2 == 0, 5); // evens
-    check(xs, |&x| x % 2 == 1, 5); // odds
-    check(xs, |&x| x % 3 == 0, 4); // multiple of 3
-    check(xs, |&x| x % 4 == 0, 3); // multiple of 4
-    check(xs, |&x| x % 5 == 0, 2); // multiple of 5
-    check(xs, |&x| x < 3, 3); // small
-    check(xs, |&x| x > 6, 3); // large
-}
-
-#[test]
-fn test_iterator_rev_advance_by() {
-    let v: &[_] = &[0, 1, 2, 3, 4];
-
-    for i in 0..v.len() {
-        let mut iter = v.iter().rev();
-        assert_eq!(iter.advance_by(i), Ok(()));
-        assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]);
-        assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
-    }
-
-    assert_eq!(v.iter().rev().advance_by(v.len()), Ok(()));
-    assert_eq!(v.iter().rev().advance_by(100), Err(v.len()));
-}
-
-#[test]
-fn test_find_map() {
-    let xs: &[isize] = &[];
-    assert_eq!(xs.iter().find_map(half_if_even), None);
-    let xs: &[isize] = &[3, 5];
-    assert_eq!(xs.iter().find_map(half_if_even), None);
-    let xs: &[isize] = &[4, 5];
-    assert_eq!(xs.iter().find_map(half_if_even), Some(2));
-    let xs: &[isize] = &[3, 6];
-    assert_eq!(xs.iter().find_map(half_if_even), Some(3));
-
-    let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7];
-    let mut iter = xs.iter();
-    assert_eq!(iter.find_map(half_if_even), Some(1));
-    assert_eq!(iter.find_map(half_if_even), Some(2));
-    assert_eq!(iter.find_map(half_if_even), Some(3));
-    assert_eq!(iter.next(), Some(&7));
-
-    fn half_if_even(x: &isize) -> Option<isize> {
-        if x % 2 == 0 { Some(x / 2) } else { None }
-    }
-}
-
-#[test]
-fn test_iterator_len() {
-    let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    assert_eq!(v[..4].iter().count(), 4);
-    assert_eq!(v[..10].iter().count(), 10);
-    assert_eq!(v[..0].iter().count(), 0);
-}
-
-#[test]
-fn test_collect() {
-    let a = vec![1, 2, 3, 4, 5];
-    let b: Vec<isize> = a.iter().cloned().collect();
-    assert!(a == b);
-}
diff --git a/library/core/tests/iter/traits/mod.rs b/library/core/tests/iter/traits/mod.rs
deleted file mode 100644
index 80619f53f25f9..0000000000000
--- a/library/core/tests/iter/traits/mod.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-mod accum;
-mod double_ended;
-mod iterator;
-mod step;
diff --git a/library/core/tests/iter/traits/step.rs b/library/core/tests/iter/traits/step.rs
deleted file mode 100644
index 3d82a40cd2941..0000000000000
--- a/library/core/tests/iter/traits/step.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-use core::iter::*;
-
-#[test]
-fn test_steps_between() {
-    assert_eq!(Step::steps_between(&20_u8, &200_u8), Some(180_usize));
-    assert_eq!(Step::steps_between(&-20_i8, &80_i8), Some(100_usize));
-    assert_eq!(Step::steps_between(&-120_i8, &80_i8), Some(200_usize));
-    assert_eq!(Step::steps_between(&20_u32, &4_000_100_u32), Some(4_000_080_usize));
-    assert_eq!(Step::steps_between(&-20_i32, &80_i32), Some(100_usize));
-    assert_eq!(Step::steps_between(&-2_000_030_i32, &2_000_050_i32), Some(4_000_080_usize));
-
-    // Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms
-
-    assert_eq!(Step::steps_between(&20_u128, &200_u128), Some(180_usize));
-    assert_eq!(Step::steps_between(&-20_i128, &80_i128), Some(100_usize));
-    if cfg!(target_pointer_width = "64") {
-        assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), Some(usize::MAX));
-    }
-    assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), None);
-    assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), None);
-    assert_eq!(
-        Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,),
-        None,
-    );
-}
-
-#[test]
-fn test_step_forward() {
-    assert_eq!(Step::forward_checked(55_u8, 200_usize), Some(255_u8));
-    assert_eq!(Step::forward_checked(252_u8, 200_usize), None);
-    assert_eq!(Step::forward_checked(0_u8, 256_usize), None);
-    assert_eq!(Step::forward_checked(-110_i8, 200_usize), Some(90_i8));
-    assert_eq!(Step::forward_checked(-110_i8, 248_usize), None);
-    assert_eq!(Step::forward_checked(-126_i8, 256_usize), None);
-
-    assert_eq!(Step::forward_checked(35_u16, 100_usize), Some(135_u16));
-    assert_eq!(Step::forward_checked(35_u16, 65500_usize), Some(u16::MAX));
-    assert_eq!(Step::forward_checked(36_u16, 65500_usize), None);
-    assert_eq!(Step::forward_checked(-110_i16, 200_usize), Some(90_i16));
-    assert_eq!(Step::forward_checked(-20_030_i16, 50_050_usize), Some(30_020_i16));
-    assert_eq!(Step::forward_checked(-10_i16, 40_000_usize), None);
-    assert_eq!(Step::forward_checked(-10_i16, 70_000_usize), None);
-
-    assert_eq!(Step::forward_checked(10_u128, 70_000_usize), Some(70_010_u128));
-    assert_eq!(Step::forward_checked(10_i128, 70_030_usize), Some(70_040_i128));
-    assert_eq!(
-        Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0xff_usize),
-        Some(u128::MAX),
-    );
-    assert_eq!(
-        Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0x100_usize),
-        None
-    );
-    assert_eq!(
-        Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0xff_usize),
-        Some(i128::MAX),
-    );
-    assert_eq!(
-        Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize),
-        None
-    );
-}
-
-#[test]
-fn test_step_backward() {
-    assert_eq!(Step::backward_checked(255_u8, 200_usize), Some(55_u8));
-    assert_eq!(Step::backward_checked(100_u8, 200_usize), None);
-    assert_eq!(Step::backward_checked(255_u8, 256_usize), None);
-    assert_eq!(Step::backward_checked(90_i8, 200_usize), Some(-110_i8));
-    assert_eq!(Step::backward_checked(110_i8, 248_usize), None);
-    assert_eq!(Step::backward_checked(127_i8, 256_usize), None);
-
-    assert_eq!(Step::backward_checked(135_u16, 100_usize), Some(35_u16));
-    assert_eq!(Step::backward_checked(u16::MAX, 65500_usize), Some(35_u16));
-    assert_eq!(Step::backward_checked(10_u16, 11_usize), None);
-    assert_eq!(Step::backward_checked(90_i16, 200_usize), Some(-110_i16));
-    assert_eq!(Step::backward_checked(30_020_i16, 50_050_usize), Some(-20_030_i16));
-    assert_eq!(Step::backward_checked(-10_i16, 40_000_usize), None);
-    assert_eq!(Step::backward_checked(-10_i16, 70_000_usize), None);
-
-    assert_eq!(Step::backward_checked(70_010_u128, 70_000_usize), Some(10_u128));
-    assert_eq!(Step::backward_checked(70_020_i128, 70_030_usize), Some(-10_i128));
-    assert_eq!(Step::backward_checked(10_u128, 7_usize), Some(3_u128));
-    assert_eq!(Step::backward_checked(10_u128, 11_usize), None);
-    assert_eq!(
-        Step::backward_checked(-0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize),
-        Some(i128::MIN)
-    );
-}
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 9763a2da34151..b0fceb9b2f669 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -561,13 +561,6 @@ pub fn home_dir() -> Option<PathBuf> {
 
 /// Returns the path of a temporary directory.
 ///
-/// The temporary directory may be shared among users, or between processes
-/// with different privileges; thus, the creation of any files or directories
-/// in the temporary directory must use a secure method to create a uniquely
-/// named file. Creating a file or directory with a fixed or predictable name
-/// may result in "insecure temporary file" security vulnerabilities. Consider
-/// using a crate that securely creates temporary files or directories.
-///
 /// # Unix
 ///
 /// Returns the value of the `TMPDIR` environment variable if it is
@@ -587,10 +580,14 @@ pub fn home_dir() -> Option<PathBuf> {
 ///
 /// ```no_run
 /// use std::env;
+/// use std::fs::File;
 ///
-/// fn main() {
+/// fn main() -> std::io::Result<()> {
 ///     let mut dir = env::temp_dir();
-///     println!("Temporary directory: {}", dir.display());
+///     dir.push("foo.txt");
+///
+///     let f = File::create(dir)?;
+///     Ok(())
 /// }
 /// ```
 #[stable(feature = "env", since = "1.0.0")]
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 605d953f5da71..ca83c409822fc 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -486,27 +486,6 @@ impl<T: Error> Error for Box<T> {
     }
 }
 
-#[stable(feature = "error_by_ref", since = "1.51.0")]
-impl<'a, T: Error + ?Sized> Error for &'a T {
-    #[allow(deprecated, deprecated_in_future)]
-    fn description(&self) -> &str {
-        Error::description(&**self)
-    }
-
-    #[allow(deprecated)]
-    fn cause(&self) -> Option<&dyn Error> {
-        Error::cause(&**self)
-    }
-
-    fn source(&self) -> Option<&(dyn Error + 'static)> {
-        Error::source(&**self)
-    }
-
-    fn backtrace(&self) -> Option<&Backtrace> {
-        Error::backtrace(&**self)
-    }
-}
-
 #[stable(feature = "fmt_error", since = "1.11.0")]
 impl Error for fmt::Error {
     #[allow(deprecated)]
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index f51b2c2462166..c30458c0545d0 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -1,13 +1,12 @@
-//! Constants specific to the `f32` single-precision floating point type.
+//! This module provides constants which are specific to the implementation
+//! of the `f32` floating point data type.
 //!
 //! *[See also the `f32` primitive type](primitive@f32).*
 //!
 //! Mathematically significant numbers are provided in the `consts` sub-module.
 //!
-//! For the constants defined directly in this module
-//! (as distinct from those defined in the `consts` sub-module),
-//! new code should instead use the associated constants
-//! defined directly on the `f32` type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![allow(missing_docs)]
@@ -21,11 +20,15 @@ use crate::intrinsics;
 use crate::sys::cmath;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
-pub use core::f32::{
-    consts, DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP,
-    MIN_EXP, MIN_POSITIVE, NAN, NEG_INFINITY, RADIX,
-};
+pub use core::f32::consts;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f32::{DIGITS, EPSILON, MANTISSA_DIGITS, RADIX};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f32::{INFINITY, MAX_10_EXP, NAN, NEG_INFINITY};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f32::{MAX, MIN, MIN_POSITIVE};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f32::{MAX_EXP, MIN_10_EXP, MIN_EXP};
 
 #[cfg(not(test))]
 #[lang = "f32_runtime"]
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 8c41e4486865c..f4cc53979d1a6 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -1,13 +1,12 @@
-//! Constants specific to the `f64` double-precision floating point type.
+//! This module provides constants which are specific to the implementation
+//! of the `f64` floating point data type.
 //!
 //! *[See also the `f64` primitive type](primitive@f64).*
 //!
 //! Mathematically significant numbers are provided in the `consts` sub-module.
 //!
-//! For the constants defined directly in this module
-//! (as distinct from those defined in the `consts` sub-module),
-//! new code should instead use the associated constants
-//! defined directly on the `f64` type.
+//! Although using these constants won’t cause compilation warnings,
+//! new code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
 #![allow(missing_docs)]
@@ -21,11 +20,15 @@ use crate::intrinsics;
 use crate::sys::cmath;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
-pub use core::f64::{
-    consts, DIGITS, EPSILON, INFINITY, MANTISSA_DIGITS, MAX, MAX_10_EXP, MAX_EXP, MIN, MIN_10_EXP,
-    MIN_EXP, MIN_POSITIVE, NAN, NEG_INFINITY, RADIX,
-};
+pub use core::f64::consts;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f64::{DIGITS, EPSILON, MANTISSA_DIGITS, RADIX};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f64::{INFINITY, MAX_10_EXP, NAN, NEG_INFINITY};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f64::{MAX, MIN, MIN_POSITIVE};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::f64::{MAX_EXP, MIN_10_EXP, MIN_EXP};
 
 #[cfg(not(test))]
 #[lang = "f64_runtime"]
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 32f0f8a52f820..2eef4d58507c0 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -111,7 +111,6 @@ impl OsString {
     /// let os_string = OsString::new();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn new() -> OsString {
         OsString { inner: Buf::from_string(String::new()) }
     }
@@ -128,7 +127,6 @@ impl OsString {
     /// assert_eq!(os_string.as_os_str(), os_str);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn as_os_str(&self) -> &OsStr {
         self
     }
@@ -147,7 +145,6 @@ impl OsString {
     /// assert_eq!(string, Ok(String::from("foo")));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn into_string(self) -> Result<String, OsString> {
         self.inner.into_string().map_err(|buf| OsString { inner: buf })
     }
@@ -166,7 +163,6 @@ impl OsString {
     /// assert_eq!(&os_string, "foobar");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn push<T: AsRef<OsStr>>(&mut self, s: T) {
         self.inner.push_slice(&s.as_ref().inner)
     }
@@ -193,7 +189,6 @@ impl OsString {
     /// assert_eq!(capacity, os_string.capacity());
     /// ```
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
-    #[inline]
     pub fn with_capacity(capacity: usize) -> OsString {
         OsString { inner: Buf::with_capacity(capacity) }
     }
@@ -212,7 +207,6 @@ impl OsString {
     /// assert_eq!(&os_string, "");
     /// ```
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
-    #[inline]
     pub fn clear(&mut self) {
         self.inner.clear()
     }
@@ -230,7 +224,6 @@ impl OsString {
     /// assert!(os_string.capacity() >= 10);
     /// ```
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
-    #[inline]
     pub fn capacity(&self) -> usize {
         self.inner.capacity()
     }
@@ -250,7 +243,6 @@ impl OsString {
     /// assert!(s.capacity() >= 10);
     /// ```
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
-    #[inline]
     pub fn reserve(&mut self, additional: usize) {
         self.inner.reserve(additional)
     }
@@ -273,7 +265,6 @@ impl OsString {
     /// assert!(s.capacity() >= 10);
     /// ```
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
-    #[inline]
     pub fn reserve_exact(&mut self, additional: usize) {
         self.inner.reserve_exact(additional)
     }
@@ -294,7 +285,6 @@ impl OsString {
     /// assert_eq!(3, s.capacity());
     /// ```
     #[stable(feature = "osstring_shrink_to_fit", since = "1.19.0")]
-    #[inline]
     pub fn shrink_to_fit(&mut self) {
         self.inner.shrink_to_fit()
     }
@@ -352,7 +342,6 @@ impl From<String> for OsString {
     /// Converts a [`String`] into a [`OsString`].
     ///
     /// The conversion copies the data, and includes an allocation on the heap.
-    #[inline]
     fn from(s: String) -> OsString {
         OsString { inner: Buf::from_string(s) }
     }
@@ -419,7 +408,6 @@ impl fmt::Debug for OsString {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl PartialEq for OsString {
-    #[inline]
     fn eq(&self, other: &OsString) -> bool {
         &**self == &**other
     }
@@ -427,7 +415,6 @@ impl PartialEq for OsString {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl PartialEq<str> for OsString {
-    #[inline]
     fn eq(&self, other: &str) -> bool {
         &**self == other
     }
@@ -435,7 +422,6 @@ impl PartialEq<str> for OsString {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl PartialEq<OsString> for str {
-    #[inline]
     fn eq(&self, other: &OsString) -> bool {
         &**other == self
     }
@@ -443,7 +429,6 @@ impl PartialEq<OsString> for str {
 
 #[stable(feature = "os_str_str_ref_eq", since = "1.29.0")]
 impl PartialEq<&str> for OsString {
-    #[inline]
     fn eq(&self, other: &&str) -> bool {
         **self == **other
     }
@@ -451,7 +436,6 @@ impl PartialEq<&str> for OsString {
 
 #[stable(feature = "os_str_str_ref_eq", since = "1.29.0")]
 impl<'a> PartialEq<OsString> for &'a str {
-    #[inline]
     fn eq(&self, other: &OsString) -> bool {
         **other == **self
     }
@@ -555,7 +539,6 @@ impl OsStr {
     /// assert_eq!(os_str.to_str(), Some("foo"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn to_str(&self) -> Option<&str> {
         self.inner.to_str()
     }
@@ -606,7 +589,6 @@ impl OsStr {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn to_string_lossy(&self) -> Cow<'_, str> {
         self.inner.to_string_lossy()
     }
@@ -623,7 +605,6 @@ impl OsStr {
     /// assert_eq!(os_string, OsString::from("foo"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn to_os_string(&self) -> OsString {
         OsString { inner: self.inner.to_owned() }
     }
@@ -674,7 +655,6 @@ impl OsStr {
     /// ```
     #[doc(alias = "length")]
     #[stable(feature = "osstring_simple_functions", since = "1.9.0")]
-    #[inline]
     pub fn len(&self) -> usize {
         self.inner.inner.len()
     }
@@ -716,7 +696,6 @@ impl OsStr {
     /// assert_eq!("grÜße, jÜrgen ❤", s);
     /// ```
     #[unstable(feature = "osstring_ascii", issue = "70516")]
-    #[inline]
     pub fn make_ascii_lowercase(&mut self) {
         self.inner.make_ascii_lowercase()
     }
@@ -742,7 +721,6 @@ impl OsStr {
     /// assert_eq!("GRüßE, JüRGEN ❤", s);
     /// ```
     #[unstable(feature = "osstring_ascii", issue = "70516")]
-    #[inline]
     pub fn make_ascii_uppercase(&mut self) {
         self.inner.make_ascii_uppercase()
     }
@@ -806,7 +784,6 @@ impl OsStr {
     /// assert!(!non_ascii.is_ascii());
     /// ```
     #[unstable(feature = "osstring_ascii", issue = "70516")]
-    #[inline]
     pub fn is_ascii(&self) -> bool {
         self.inner.is_ascii()
     }
@@ -834,7 +811,6 @@ impl OsStr {
 
 #[stable(feature = "box_from_os_str", since = "1.17.0")]
 impl From<&OsStr> for Box<OsStr> {
-    #[inline]
     fn from(s: &OsStr) -> Box<OsStr> {
         let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr;
         unsafe { Box::from_raw(rw) }
@@ -856,7 +832,6 @@ impl From<Cow<'_, OsStr>> for Box<OsStr> {
 impl From<Box<OsStr>> for OsString {
     /// Converts a [`Box`]`<`[`OsStr`]`>` into a `OsString` without copying or
     /// allocating.
-    #[inline]
     fn from(boxed: Box<OsStr>) -> OsString {
         boxed.into_os_string()
     }
@@ -865,7 +840,6 @@ impl From<Box<OsStr>> for OsString {
 #[stable(feature = "box_from_os_string", since = "1.20.0")]
 impl From<OsString> for Box<OsStr> {
     /// Converts a [`OsString`] into a [`Box`]`<OsStr>` without copying or allocating.
-    #[inline]
     fn from(s: OsString) -> Box<OsStr> {
         s.into_boxed_os_str()
     }
@@ -951,7 +925,6 @@ impl<'a> From<Cow<'a, OsStr>> for OsString {
 
 #[stable(feature = "box_default_extra", since = "1.17.0")]
 impl Default for Box<OsStr> {
-    #[inline]
     fn default() -> Box<OsStr> {
         let rw = Box::into_raw(Slice::empty_box()) as *mut OsStr;
         unsafe { Box::from_raw(rw) }
@@ -1102,7 +1075,6 @@ impl OsStr {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Borrow<OsStr> for OsString {
-    #[inline]
     fn borrow(&self) -> &OsStr {
         &self[..]
     }
@@ -1111,11 +1083,9 @@ impl Borrow<OsStr> for OsString {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ToOwned for OsStr {
     type Owned = OsString;
-    #[inline]
     fn to_owned(&self) -> OsString {
         self.to_os_string()
     }
-    #[inline]
     fn clone_into(&self, target: &mut OsString) {
         self.inner.clone_into(&mut target.inner)
     }
@@ -1123,7 +1093,6 @@ impl ToOwned for OsStr {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<OsStr> for OsStr {
-    #[inline]
     fn as_ref(&self) -> &OsStr {
         self
     }
@@ -1154,14 +1123,12 @@ impl AsRef<OsStr> for String {
 }
 
 impl FromInner<Buf> for OsString {
-    #[inline]
     fn from_inner(buf: Buf) -> OsString {
         OsString { inner: buf }
     }
 }
 
 impl IntoInner<Buf> for OsString {
-    #[inline]
     fn into_inner(self) -> Buf {
         self.inner
     }
@@ -1178,7 +1145,6 @@ impl AsInner<Slice> for OsStr {
 impl FromStr for OsString {
     type Err = core::convert::Infallible;
 
-    #[inline]
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         Ok(OsString::from(s))
     }
diff --git a/library/std/src/future.rs b/library/std/src/future.rs
new file mode 100644
index 0000000000000..9d9c36e9afb0f
--- /dev/null
+++ b/library/std/src/future.rs
@@ -0,0 +1,17 @@
+//! Asynchronous values.
+
+#[doc(inline)]
+#[stable(feature = "futures_api", since = "1.36.0")]
+pub use core::future::Future;
+
+#[doc(inline)]
+#[unstable(feature = "gen_future", issue = "50547")]
+pub use core::future::{from_generator, get_context, ResumeTy};
+
+#[doc(inline)]
+#[stable(feature = "future_readiness_fns", since = "1.48.0")]
+pub use core::future::{pending, ready, Pending, Ready};
+
+#[doc(inline)]
+#[unstable(feature = "into_future", issue = "67644")]
+pub use core::future::IntoFuture;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 92c8b7c177477..15ef5d1619ba3 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -406,31 +406,23 @@ pub use core::cmp;
 pub use core::convert;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::default;
-#[stable(feature = "futures_api", since = "1.36.0")]
-pub use core::future;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::hash;
 #[stable(feature = "core_hint", since = "1.27.0")]
 pub use core::hint;
 #[stable(feature = "i128", since = "1.26.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::i128;
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::i16;
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::i32;
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::i64;
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::i8;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::intrinsics;
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::isize;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::iter;
@@ -451,22 +443,16 @@ pub use core::raw;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::result;
 #[stable(feature = "i128", since = "1.26.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::u128;
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::u16;
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::u32;
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::u64;
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::u8;
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated, deprecated_in_future)]
 pub use core::usize;
 
 pub mod f32;
@@ -507,6 +493,9 @@ pub mod task {
     pub use alloc::task::*;
 }
 
+#[stable(feature = "futures_api", since = "1.36.0")]
+pub mod future;
+
 // Platform-abstraction modules
 #[macro_use]
 mod sys_common;
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index e466f3151524c..5a70aa070e870 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -282,10 +282,6 @@ macro_rules! eprintln {
 #[macro_export]
 #[stable(feature = "dbg_macro", since = "1.32.0")]
 macro_rules! dbg {
-    // NOTE: We cannot use `concat!` to make a static string as a format argument
-    // of `eprintln!` because `file!` could contain a `{` or
-    // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!`
-    // will be malformed.
     () => {
         $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!());
     };
diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs
index 84449e4876718..d33b772633d29 100644
--- a/library/std/src/net/ip.rs
+++ b/library/std/src/net/ip.rs
@@ -1610,11 +1610,11 @@ impl fmt::Display for Ipv6Addr {
                 /// Write a colon-separated part of the address
                 #[inline]
                 fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result {
-                    if let Some((first, tail)) = chunk.split_first() {
-                        write!(f, "{:x}", first)?;
-                        for segment in tail {
+                    if let Some(first) = chunk.first() {
+                        fmt::LowerHex::fmt(first, f)?;
+                        for segment in &chunk[1..] {
                             f.write_char(':')?;
-                            write!(f, "{:x}", segment)?;
+                            fmt::LowerHex::fmt(segment, f)?;
                         }
                     }
                     Ok(())
diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs
index ef0d4edc43473..44fb3adf07023 100644
--- a/library/std/src/net/ip/tests.rs
+++ b/library/std/src/net/ip/tests.rs
@@ -166,9 +166,6 @@ fn ipv6_addr_to_string() {
 
     // two runs of zeros, equal length
     assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
-
-    // don't prefix `0x` to each segment in `dbg!`.
-    assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8)));
 }
 
 #[test]
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 0f568da459bef..d18b94b6c1aef 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -31,9 +31,9 @@ pub use core::panic::{Location, PanicInfo};
 /// accessed later using [`PanicInfo::payload`].
 ///
 /// See the [`panic!`] macro for more information about panicking.
-#[stable(feature = "panic_any", since = "1.51.0")]
+#[unstable(feature = "panic_any", issue = "78500")]
 #[inline]
-pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
+pub fn panic_any<M: Any + Send>(msg: M) -> ! {
     crate::panicking::begin_panic(msg);
 }
 
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 1889e54933867..243761e389784 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -401,14 +401,12 @@ impl<'a> PrefixComponent<'a> {
     /// See [`Prefix`]'s documentation for more information on the different
     /// kinds of prefixes.
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn kind(&self) -> Prefix<'a> {
         self.parsed
     }
 
     /// Returns the raw [`OsStr`] slice for this prefix.
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn as_os_str(&self) -> &'a OsStr {
         self.raw
     }
@@ -416,7 +414,6 @@ impl<'a> PrefixComponent<'a> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> cmp::PartialEq for PrefixComponent<'a> {
-    #[inline]
     fn eq(&self, other: &PrefixComponent<'a>) -> bool {
         cmp::PartialEq::eq(&self.parsed, &other.parsed)
     }
@@ -424,7 +421,6 @@ impl<'a> cmp::PartialEq for PrefixComponent<'a> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> cmp::PartialOrd for PrefixComponent<'a> {
-    #[inline]
     fn partial_cmp(&self, other: &PrefixComponent<'a>) -> Option<cmp::Ordering> {
         cmp::PartialOrd::partial_cmp(&self.parsed, &other.parsed)
     }
@@ -432,7 +428,6 @@ impl<'a> cmp::PartialOrd for PrefixComponent<'a> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl cmp::Ord for PrefixComponent<'_> {
-    #[inline]
     fn cmp(&self, other: &Self) -> cmp::Ordering {
         cmp::Ord::cmp(&self.parsed, &other.parsed)
     }
@@ -527,7 +522,6 @@ impl<'a> Component<'a> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<OsStr> for Component<'_> {
-    #[inline]
     fn as_ref(&self) -> &OsStr {
         self.as_os_str()
     }
@@ -535,7 +529,6 @@ impl AsRef<OsStr> for Component<'_> {
 
 #[stable(feature = "path_component_asref", since = "1.25.0")]
 impl AsRef<Path> for Component<'_> {
-    #[inline]
     fn as_ref(&self) -> &Path {
         self.as_os_str().as_ref()
     }
@@ -757,7 +750,6 @@ impl<'a> Components<'a> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<Path> for Components<'_> {
-    #[inline]
     fn as_ref(&self) -> &Path {
         self.as_path()
     }
@@ -765,7 +757,6 @@ impl AsRef<Path> for Components<'_> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<OsStr> for Components<'_> {
-    #[inline]
     fn as_ref(&self) -> &OsStr {
         self.as_path().as_os_str()
     }
@@ -801,7 +792,6 @@ impl<'a> Iter<'a> {
     /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn as_path(&self) -> &'a Path {
         self.inner.as_path()
     }
@@ -809,7 +799,6 @@ impl<'a> Iter<'a> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<Path> for Iter<'_> {
-    #[inline]
     fn as_ref(&self) -> &Path {
         self.as_path()
     }
@@ -817,7 +806,6 @@ impl AsRef<Path> for Iter<'_> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<OsStr> for Iter<'_> {
-    #[inline]
     fn as_ref(&self) -> &OsStr {
         self.as_path().as_os_str()
     }
@@ -827,7 +815,6 @@ impl AsRef<OsStr> for Iter<'_> {
 impl<'a> Iterator for Iter<'a> {
     type Item = &'a OsStr;
 
-    #[inline]
     fn next(&mut self) -> Option<&'a OsStr> {
         self.inner.next().map(Component::as_os_str)
     }
@@ -835,7 +822,6 @@ impl<'a> Iterator for Iter<'a> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> DoubleEndedIterator for Iter<'a> {
-    #[inline]
     fn next_back(&mut self) -> Option<&'a OsStr> {
         self.inner.next_back().map(Component::as_os_str)
     }
@@ -949,7 +935,6 @@ impl FusedIterator for Components<'_> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> cmp::PartialEq for Components<'a> {
-    #[inline]
     fn eq(&self, other: &Components<'a>) -> bool {
         Iterator::eq(self.clone(), other.clone())
     }
@@ -960,7 +945,6 @@ impl cmp::Eq for Components<'_> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> cmp::PartialOrd for Components<'a> {
-    #[inline]
     fn partial_cmp(&self, other: &Components<'a>) -> Option<cmp::Ordering> {
         Iterator::partial_cmp(self.clone(), other.clone())
     }
@@ -968,7 +952,6 @@ impl<'a> cmp::PartialOrd for Components<'a> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl cmp::Ord for Components<'_> {
-    #[inline]
     fn cmp(&self, other: &Self) -> cmp::Ordering {
         Iterator::cmp(self.clone(), other.clone())
     }
@@ -1002,7 +985,6 @@ pub struct Ancestors<'a> {
 impl<'a> Iterator for Ancestors<'a> {
     type Item = &'a Path;
 
-    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         let next = self.next;
         self.next = next.and_then(Path::parent);
@@ -1078,7 +1060,6 @@ pub struct PathBuf {
 }
 
 impl PathBuf {
-    #[inline]
     fn as_mut_vec(&mut self) -> &mut Vec<u8> {
         unsafe { &mut *(self as *mut PathBuf as *mut Vec<u8>) }
     }
@@ -1093,7 +1074,6 @@ impl PathBuf {
     /// let path = PathBuf::new();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn new() -> PathBuf {
         PathBuf { inner: OsString::new() }
     }
@@ -1117,7 +1097,6 @@ impl PathBuf {
     ///
     /// [`with_capacity`]: OsString::with_capacity
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
-    #[inline]
     pub fn with_capacity(capacity: usize) -> PathBuf {
         PathBuf { inner: OsString::with_capacity(capacity) }
     }
@@ -1133,7 +1112,6 @@ impl PathBuf {
     /// assert_eq!(Path::new("/test"), p.as_path());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn as_path(&self) -> &Path {
         self
     }
@@ -1337,14 +1315,12 @@ impl PathBuf {
     /// let os_str = p.into_os_string();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn into_os_string(self) -> OsString {
         self.inner
     }
 
     /// Converts this `PathBuf` into a [boxed](Box) [`Path`].
     #[stable(feature = "into_boxed_path", since = "1.20.0")]
-    #[inline]
     pub fn into_boxed_path(self) -> Box<Path> {
         let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path;
         unsafe { Box::from_raw(rw) }
@@ -1354,7 +1330,6 @@ impl PathBuf {
     ///
     /// [`capacity`]: OsString::capacity
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
-    #[inline]
     pub fn capacity(&self) -> usize {
         self.inner.capacity()
     }
@@ -1363,7 +1338,6 @@ impl PathBuf {
     ///
     /// [`clear`]: OsString::clear
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
-    #[inline]
     pub fn clear(&mut self) {
         self.inner.clear()
     }
@@ -1372,7 +1346,6 @@ impl PathBuf {
     ///
     /// [`reserve`]: OsString::reserve
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
-    #[inline]
     pub fn reserve(&mut self, additional: usize) {
         self.inner.reserve(additional)
     }
@@ -1381,7 +1354,6 @@ impl PathBuf {
     ///
     /// [`reserve_exact`]: OsString::reserve_exact
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
-    #[inline]
     pub fn reserve_exact(&mut self, additional: usize) {
         self.inner.reserve_exact(additional)
     }
@@ -1390,7 +1362,6 @@ impl PathBuf {
     ///
     /// [`shrink_to_fit`]: OsString::shrink_to_fit
     #[stable(feature = "path_buf_capacity", since = "1.44.0")]
-    #[inline]
     pub fn shrink_to_fit(&mut self) {
         self.inner.shrink_to_fit()
     }
@@ -1399,7 +1370,6 @@ impl PathBuf {
     ///
     /// [`shrink_to`]: OsString::shrink_to
     #[unstable(feature = "shrink_to", issue = "56431")]
-    #[inline]
     pub fn shrink_to(&mut self, min_capacity: usize) {
         self.inner.shrink_to(min_capacity)
     }
@@ -1430,7 +1400,6 @@ impl From<Box<Path>> for PathBuf {
     /// Converts a `Box<Path>` into a `PathBuf`
     ///
     /// This conversion does not allocate or copy memory.
-    #[inline]
     fn from(boxed: Box<Path>) -> PathBuf {
         boxed.into_path_buf()
     }
@@ -1442,7 +1411,6 @@ impl From<PathBuf> for Box<Path> {
     ///
     /// This conversion currently should not allocate memory,
     /// but this behavior is not guaranteed on all platforms or in all future versions.
-    #[inline]
     fn from(p: PathBuf) -> Box<Path> {
         p.into_boxed_path()
     }
@@ -1458,7 +1426,6 @@ impl Clone for Box<Path> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
-    #[inline]
     fn from(s: &T) -> PathBuf {
         PathBuf::from(s.as_ref().to_os_string())
     }
@@ -1480,7 +1447,6 @@ impl From<PathBuf> for OsString {
     /// Converts a `PathBuf` into a `OsString`
     ///
     /// This conversion does not allocate or copy memory.
-    #[inline]
     fn from(path_buf: PathBuf) -> OsString {
         path_buf.inner
     }
@@ -1491,7 +1457,6 @@ impl From<String> for PathBuf {
     /// Converts a `String` into a `PathBuf`
     ///
     /// This conversion does not allocate or copy memory.
-    #[inline]
     fn from(s: String) -> PathBuf {
         PathBuf::from(OsString::from(s))
     }
@@ -1501,7 +1466,6 @@ impl From<String> for PathBuf {
 impl FromStr for PathBuf {
     type Err = core::convert::Infallible;
 
-    #[inline]
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         Ok(PathBuf::from(s))
     }
@@ -1546,7 +1510,6 @@ impl ops::Deref for PathBuf {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Borrow<Path> for PathBuf {
-    #[inline]
     fn borrow(&self) -> &Path {
         self.deref()
     }
@@ -1554,7 +1517,6 @@ impl Borrow<Path> for PathBuf {
 
 #[stable(feature = "default_for_pathbuf", since = "1.17.0")]
 impl Default for PathBuf {
-    #[inline]
     fn default() -> Self {
         PathBuf::new()
     }
@@ -1635,11 +1597,9 @@ impl From<&Path> for Rc<Path> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ToOwned for Path {
     type Owned = PathBuf;
-    #[inline]
     fn to_owned(&self) -> PathBuf {
         self.to_path_buf()
     }
-    #[inline]
     fn clone_into(&self, target: &mut PathBuf) {
         self.inner.clone_into(&mut target.inner);
     }
@@ -1647,7 +1607,6 @@ impl ToOwned for Path {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl cmp::PartialEq for PathBuf {
-    #[inline]
     fn eq(&self, other: &PathBuf) -> bool {
         self.components() == other.components()
     }
@@ -1665,7 +1624,6 @@ impl cmp::Eq for PathBuf {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl cmp::PartialOrd for PathBuf {
-    #[inline]
     fn partial_cmp(&self, other: &PathBuf) -> Option<cmp::Ordering> {
         self.components().partial_cmp(other.components())
     }
@@ -1673,7 +1631,6 @@ impl cmp::PartialOrd for PathBuf {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl cmp::Ord for PathBuf {
-    #[inline]
     fn cmp(&self, other: &PathBuf) -> cmp::Ordering {
         self.components().cmp(other.components())
     }
@@ -1681,7 +1638,6 @@ impl cmp::Ord for PathBuf {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<OsStr> for PathBuf {
-    #[inline]
     fn as_ref(&self) -> &OsStr {
         &self.inner[..]
     }
@@ -1789,7 +1745,6 @@ impl Path {
     /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn as_os_str(&self) -> &OsStr {
         &self.inner
     }
@@ -1811,7 +1766,6 @@ impl Path {
     /// assert_eq!(path.to_str(), Some("foo.txt"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn to_str(&self) -> Option<&str> {
         self.inner.to_str()
     }
@@ -1837,7 +1791,6 @@ impl Path {
     /// Had `path` contained invalid unicode, the `to_string_lossy` call might
     /// have returned `"fo�.txt"`.
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn to_string_lossy(&self) -> Cow<'_, str> {
         self.inner.to_string_lossy()
     }
@@ -1901,7 +1854,6 @@ impl Path {
     ///
     /// [`is_absolute`]: Path::is_absolute
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn is_relative(&self) -> bool {
         !self.is_absolute()
     }
@@ -1927,7 +1879,6 @@ impl Path {
     /// assert!(Path::new("/etc/passwd").has_root());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn has_root(&self) -> bool {
         self.components().has_root()
     }
@@ -1990,7 +1941,6 @@ impl Path {
     ///
     /// [`parent`]: Path::parent
     #[stable(feature = "path_ancestors", since = "1.28.0")]
-    #[inline]
     pub fn ancestors(&self) -> Ancestors<'_> {
         Ancestors { next: Some(&self) }
     }
@@ -2315,7 +2265,6 @@ impl Path {
     /// assert_eq!(it.next(), None)
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn iter(&self) -> Iter<'_> {
         Iter { inner: self.components() }
     }
@@ -2335,7 +2284,6 @@ impl Path {
     /// println!("{}", path.display());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
     pub fn display(&self) -> Display<'_> {
         Display { path: self }
     }
@@ -2357,7 +2305,6 @@ impl Path {
     /// println!("{:?}", metadata.file_type());
     /// ```
     #[stable(feature = "path_ext", since = "1.5.0")]
-    #[inline]
     pub fn metadata(&self) -> io::Result<fs::Metadata> {
         fs::metadata(self)
     }
@@ -2376,7 +2323,6 @@ impl Path {
     /// println!("{:?}", metadata.file_type());
     /// ```
     #[stable(feature = "path_ext", since = "1.5.0")]
-    #[inline]
     pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
         fs::symlink_metadata(self)
     }
@@ -2395,7 +2341,6 @@ impl Path {
     /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
     /// ```
     #[stable(feature = "path_ext", since = "1.5.0")]
-    #[inline]
     pub fn canonicalize(&self) -> io::Result<PathBuf> {
         fs::canonicalize(self)
     }
@@ -2413,7 +2358,6 @@ impl Path {
     /// let path_link = path.read_link().expect("read_link call failed");
     /// ```
     #[stable(feature = "path_ext", since = "1.5.0")]
-    #[inline]
     pub fn read_link(&self) -> io::Result<PathBuf> {
         fs::read_link(self)
     }
@@ -2438,7 +2382,6 @@ impl Path {
     /// }
     /// ```
     #[stable(feature = "path_ext", since = "1.5.0")]
-    #[inline]
     pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
         fs::read_dir(self)
     }
@@ -2463,7 +2406,6 @@ impl Path {
     /// This is a convenience function that coerces errors to false. If you want to
     /// check errors, call [`fs::metadata`].
     #[stable(feature = "path_ext", since = "1.5.0")]
-    #[inline]
     pub fn exists(&self) -> bool {
         fs::metadata(self).is_ok()
     }
@@ -2538,7 +2480,6 @@ impl Path {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<OsStr> for Path {
-    #[inline]
     fn as_ref(&self) -> &OsStr {
         &self.inner
     }
@@ -2590,7 +2531,6 @@ impl fmt::Display for Display<'_> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl cmp::PartialEq for Path {
-    #[inline]
     fn eq(&self, other: &Path) -> bool {
         self.components().eq(other.components())
     }
@@ -2610,7 +2550,6 @@ impl cmp::Eq for Path {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl cmp::PartialOrd for Path {
-    #[inline]
     fn partial_cmp(&self, other: &Path) -> Option<cmp::Ordering> {
         self.components().partial_cmp(other.components())
     }
@@ -2618,7 +2557,6 @@ impl cmp::PartialOrd for Path {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl cmp::Ord for Path {
-    #[inline]
     fn cmp(&self, other: &Path) -> cmp::Ordering {
         self.components().cmp(other.components())
     }
@@ -2626,7 +2564,6 @@ impl cmp::Ord for Path {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<Path> for Path {
-    #[inline]
     fn as_ref(&self) -> &Path {
         self
     }
@@ -2634,7 +2571,6 @@ impl AsRef<Path> for Path {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<Path> for OsStr {
-    #[inline]
     fn as_ref(&self) -> &Path {
         Path::new(self)
     }
@@ -2642,7 +2578,6 @@ impl AsRef<Path> for OsStr {
 
 #[stable(feature = "cow_os_str_as_ref_path", since = "1.8.0")]
 impl AsRef<Path> for Cow<'_, OsStr> {
-    #[inline]
     fn as_ref(&self) -> &Path {
         Path::new(self)
     }
@@ -2650,7 +2585,6 @@ impl AsRef<Path> for Cow<'_, OsStr> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<Path> for OsString {
-    #[inline]
     fn as_ref(&self) -> &Path {
         Path::new(self)
     }
@@ -2666,7 +2600,6 @@ impl AsRef<Path> for str {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<Path> for String {
-    #[inline]
     fn as_ref(&self) -> &Path {
         Path::new(self)
     }
@@ -2684,7 +2617,6 @@ impl AsRef<Path> for PathBuf {
 impl<'a> IntoIterator for &'a PathBuf {
     type Item = &'a OsStr;
     type IntoIter = Iter<'a>;
-    #[inline]
     fn into_iter(self) -> Iter<'a> {
         self.iter()
     }
@@ -2694,7 +2626,6 @@ impl<'a> IntoIterator for &'a PathBuf {
 impl<'a> IntoIterator for &'a Path {
     type Item = &'a OsStr;
     type IntoIter = Iter<'a>;
-    #[inline]
     fn into_iter(self) -> Iter<'a> {
         self.iter()
     }
diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs
index 724b5dcca6a36..f4c67b225e6e1 100644
--- a/library/std/src/sys/unix/ext/process.rs
+++ b/library/std/src/sys/unix/ext/process.rs
@@ -39,15 +39,6 @@ pub trait CommandExt {
         #[cfg(target_os = "vxworks")] id: u16,
     ) -> &mut process::Command;
 
-    /// Sets the supplementary group IDs for the calling process. Translates to
-    /// a `setgroups` call in the child process.
-    #[unstable(feature = "setgroups", issue = "38527", reason = "")]
-    fn groups(
-        &mut self,
-        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
-        #[cfg(target_os = "vxworks")] groups: &[u16],
-    ) -> &mut process::Command;
-
     /// Schedules a closure to be run just before the `exec` function is
     /// invoked.
     ///
@@ -158,15 +149,6 @@ impl CommandExt for process::Command {
         self
     }
 
-    fn groups(
-        &mut self,
-        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
-        #[cfg(target_os = "vxworks")] groups: &[u16],
-    ) -> &mut process::Command {
-        self.as_inner_mut().groups(groups);
-        self
-    }
-
     unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
     where
         F: FnMut() -> io::Result<()> + Send + Sync + 'static,
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index a96d4aa6a4555..372e5e6a5b367 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -87,7 +87,6 @@ pub struct Command {
     gid: Option<gid_t>,
     saw_nul: bool,
     closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
-    groups: Option<Box<[gid_t]>>,
     stdin: Option<Stdio>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
@@ -149,7 +148,6 @@ impl Command {
             gid: None,
             saw_nul,
             closures: Vec::new(),
-            groups: None,
             stdin: None,
             stdout: None,
             stderr: None,
@@ -185,9 +183,6 @@ impl Command {
     pub fn gid(&mut self, id: gid_t) {
         self.gid = Some(id);
     }
-    pub fn groups(&mut self, groups: &[gid_t]) {
-        self.groups = Some(Box::from(groups));
-    }
 
     pub fn saw_nul(&self) -> bool {
         self.saw_nul
@@ -231,10 +226,6 @@ impl Command {
     pub fn get_gid(&self) -> Option<gid_t> {
         self.gid
     }
-    #[allow(dead_code)]
-    pub fn get_groups(&self) -> Option<&[gid_t]> {
-        self.groups.as_deref()
-    }
 
     pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
         &mut self.closures
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 2746f87468dca..ddcb404c60ebc 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -183,26 +183,20 @@ impl Command {
 
         #[cfg(not(target_os = "l4re"))]
         {
-            if let Some(_g) = self.get_groups() {
-                //FIXME: Redox kernel does not support setgroups yet
-                #[cfg(not(target_os = "redox"))]
-                cvt(libc::setgroups(_g.len().try_into().unwrap(), _g.as_ptr()))?;
-            }
             if let Some(u) = self.get_gid() {
                 cvt(libc::setgid(u as gid_t))?;
             }
             if let Some(u) = self.get_uid() {
                 // When dropping privileges from root, the `setgroups` call
-                // will remove any extraneous groups. We only drop groups
-                // if the current uid is 0 and we weren't given an explicit
-                // set of groups. If we don't call this, then even though our
-                // uid has dropped, we may still have groups that enable us to
-                // do super-user things.
+                // will remove any extraneous groups. If we don't call this,
+                // then even though our uid has dropped, we may still have
+                // groups that enable us to do super-user things. This will
+                // fail if we aren't root, so don't bother checking the
+                // return value, this is just done as an optimistic
+                // privilege dropping function.
                 //FIXME: Redox kernel does not support setgroups yet
                 #[cfg(not(target_os = "redox"))]
-                if libc::getuid() == 0 && self.get_groups().is_none() {
-                    cvt(libc::setgroups(0, ptr::null()))?;
-                }
+                let _ = libc::setgroups(0, ptr::null());
                 cvt(libc::setuid(u as uid_t))?;
             }
         }
@@ -293,7 +287,6 @@ impl Command {
             || self.get_uid().is_some()
             || (self.env_saw_path() && !self.program_is_path())
             || !self.get_closures().is_empty()
-            || self.get_groups().is_some()
         {
             return Ok(None);
         }
diff --git a/library/std/src/sys/unix/process/zircon.rs b/library/std/src/sys/unix/process/zircon.rs
index 58427bb8b69d9..69ec275c2b318 100644
--- a/library/std/src/sys/unix/process/zircon.rs
+++ b/library/std/src/sys/unix/process/zircon.rs
@@ -1,6 +1,7 @@
 #![allow(non_camel_case_types, unused)]
 
 use crate::convert::TryInto;
+use crate::i64;
 use crate::io;
 use crate::mem::MaybeUninit;
 use crate::os::raw::c_char;
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index f43a19d91b657..2b1bc92dc84ae 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -1020,60 +1020,6 @@ extern "system" {
     pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
     pub fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
     pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinka
-    pub fn CreateSymbolicLinkW(
-        lpSymlinkFileName: LPCWSTR,
-        lpTargetFileName: LPCWSTR,
-        dwFlags: DWORD,
-    ) -> BOOLEAN;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
-    pub fn GetFinalPathNameByHandleW(
-        hFile: HANDLE,
-        lpszFilePath: LPCWSTR,
-        cchFilePath: DWORD,
-        dwFlags: DWORD,
-    ) -> DWORD;
-
-    // >= Vista / Server 2003
-    // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadstackguarantee
-    #[cfg(not(target_vendor = "uwp"))]
-    pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle
-    pub fn SetFileInformationByHandle(
-        hFile: HANDLE,
-        FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
-        lpFileInformation: LPVOID,
-        dwBufferSize: DWORD,
-    ) -> BOOL;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepconditionvariablesrw
-    pub fn SleepConditionVariableSRW(
-        ConditionVariable: PCONDITION_VARIABLE,
-        SRWLock: PSRWLOCK,
-        dwMilliseconds: DWORD,
-        Flags: ULONG,
-    ) -> BOOL;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakeconditionvariable
-    pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE);
-    pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE);
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockexclusive
-    pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK);
-    pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK);
-    pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK);
-    pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK);
-    pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN;
-    pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN;
 }
 
 // Functions that aren't available on every version of Windows that we support,
@@ -1081,26 +1027,70 @@ extern "system" {
 compat_fn! {
     "kernel32":
 
-    // >= Win10 1607
-    // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
+    pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR,
+                               _lpTargetFileName: LPCWSTR,
+                               _dwFlags: DWORD) -> BOOLEAN {
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
+    }
+    pub fn GetFinalPathNameByHandleW(_hFile: HANDLE,
+                                     _lpszFilePath: LPCWSTR,
+                                     _cchFilePath: DWORD,
+                                     _dwFlags: DWORD) -> DWORD {
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
+    }
+    #[cfg(not(target_vendor = "uwp"))]
+    pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL {
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
+    }
     pub fn SetThreadDescription(hThread: HANDLE,
                                 lpThreadDescription: LPCWSTR) -> HRESULT {
         SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
     }
-
-    // >= Win8 / Server 2012
-    // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime
+    pub fn SetFileInformationByHandle(_hFile: HANDLE,
+                    _FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
+                    _lpFileInformation: LPVOID,
+                    _dwBufferSize: DWORD) -> BOOL {
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
+    }
     pub fn GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime: LPFILETIME)
                                           -> () {
         GetSystemTimeAsFileTime(lpSystemTimeAsFileTime)
     }
+    pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE,
+                                     SRWLock: PSRWLOCK,
+                                     dwMilliseconds: DWORD,
+                                     Flags: ULONG) -> BOOL {
+        panic!("condition variables not available")
+    }
+    pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE)
+                                 -> () {
+        panic!("condition variables not available")
+    }
+    pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE)
+                                    -> () {
+        panic!("condition variables not available")
+    }
+    pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> () {
+        panic!("rwlocks not available")
+    }
+    pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK) -> () {
+        panic!("rwlocks not available")
+    }
+    pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK) -> () {
+        panic!("rwlocks not available")
+    }
+    pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK) -> () {
+        panic!("rwlocks not available")
+    }
+    pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN {
+        panic!("rwlocks not available")
+    }
+    pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN {
+        panic!("rwlocks not available")
+    }
 }
-
 compat_fn! {
     "api-ms-win-core-synch-l1-2-0":
-
-    // >= Windows 8 / Server 2012
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress
     pub fn WaitOnAddress(
         Address: LPVOID,
         CompareAddress: LPVOID,
diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs
index 72a0993d94ddf..d4cc56d4cb3ef 100644
--- a/library/std/src/sys/windows/mutex.rs
+++ b/library/std/src/sys/windows/mutex.rs
@@ -13,13 +13,20 @@
 //!
 //! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy
 //!    is that there are no guarantees of fairness.
-
-use crate::cell::UnsafeCell;
-use crate::mem::MaybeUninit;
+//!
+//! The downside of this approach, however, is that SRWLock is not available on
+//! Windows XP, so we continue to have a fallback implementation where
+//! CriticalSection is used and we keep track of who's holding the mutex to
+//! detect recursive locks.
+
+use crate::cell::{Cell, UnsafeCell};
+use crate::mem::{self, MaybeUninit};
+use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sys::c;
 
 pub struct Mutex {
-    srwlock: UnsafeCell<c::SRWLOCK>,
+    // This is either directly an SRWLOCK (if supported), or a Box<Inner> otherwise.
+    lock: AtomicUsize,
 }
 
 // Windows SRW Locks are movable (while not borrowed).
@@ -30,37 +37,104 @@ pub type MovableMutex = Mutex;
 unsafe impl Send for Mutex {}
 unsafe impl Sync for Mutex {}
 
+struct Inner {
+    remutex: ReentrantMutex,
+    held: Cell<bool>,
+}
+
+#[derive(Clone, Copy)]
+enum Kind {
+    SRWLock,
+    CriticalSection,
+}
+
 #[inline]
 pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK {
-    m.srwlock.get()
+    debug_assert!(mem::size_of::<c::SRWLOCK>() <= mem::size_of_val(&m.lock));
+    &m.lock as *const _ as *mut _
 }
 
 impl Mutex {
     pub const fn new() -> Mutex {
-        Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) }
+        Mutex {
+            // This works because SRWLOCK_INIT is 0 (wrapped in a struct), so we are also properly
+            // initializing an SRWLOCK here.
+            lock: AtomicUsize::new(0),
+        }
     }
     #[inline]
     pub unsafe fn init(&mut self) {}
-
-    #[inline]
     pub unsafe fn lock(&self) {
-        c::AcquireSRWLockExclusive(raw(self));
+        match kind() {
+            Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)),
+            Kind::CriticalSection => {
+                let inner = &*self.inner();
+                inner.remutex.lock();
+                if inner.held.replace(true) {
+                    // It was already locked, so we got a recursive lock which we do not want.
+                    inner.remutex.unlock();
+                    panic!("cannot recursively lock a mutex");
+                }
+            }
+        }
     }
-
-    #[inline]
     pub unsafe fn try_lock(&self) -> bool {
-        c::TryAcquireSRWLockExclusive(raw(self)) != 0
+        match kind() {
+            Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0,
+            Kind::CriticalSection => {
+                let inner = &*self.inner();
+                if !inner.remutex.try_lock() {
+                    false
+                } else if inner.held.replace(true) {
+                    // It was already locked, so we got a recursive lock which we do not want.
+                    inner.remutex.unlock();
+                    false
+                } else {
+                    true
+                }
+            }
+        }
     }
-
-    #[inline]
     pub unsafe fn unlock(&self) {
-        c::ReleaseSRWLockExclusive(raw(self));
+        match kind() {
+            Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)),
+            Kind::CriticalSection => {
+                let inner = &*(self.lock.load(Ordering::SeqCst) as *const Inner);
+                inner.held.set(false);
+                inner.remutex.unlock();
+            }
+        }
     }
-
-    #[inline]
     pub unsafe fn destroy(&self) {
-        // SRWLock does not need to be destroyed.
+        match kind() {
+            Kind::SRWLock => {}
+            Kind::CriticalSection => match self.lock.load(Ordering::SeqCst) {
+                0 => {}
+                n => Box::from_raw(n as *mut Inner).remutex.destroy(),
+            },
+        }
     }
+
+    unsafe fn inner(&self) -> *const Inner {
+        match self.lock.load(Ordering::SeqCst) {
+            0 => {}
+            n => return n as *const _,
+        }
+        let inner = box Inner { remutex: ReentrantMutex::uninitialized(), held: Cell::new(false) };
+        inner.remutex.init();
+        let inner = Box::into_raw(inner);
+        match self.lock.compare_exchange(0, inner as usize, Ordering::SeqCst, Ordering::SeqCst) {
+            Ok(_) => inner,
+            Err(n) => {
+                Box::from_raw(inner).remutex.destroy();
+                n as *const _
+            }
+        }
+    }
+}
+
+fn kind() -> Kind {
+    if c::AcquireSRWLockExclusive::is_available() { Kind::SRWLock } else { Kind::CriticalSection }
 }
 
 pub struct ReentrantMutex {
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 3ff79eaea49ab..656d9669e81d2 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -25,7 +25,6 @@
 #![feature(nll)]
 #![feature(available_concurrency)]
 #![feature(internal_output_capture)]
-#![feature(option_unwrap_none)]
 #![feature(panic_unwind)]
 #![feature(staged_api)]
 #![feature(termination_trait_lib)]
@@ -62,7 +61,6 @@ pub mod test {
 }
 
 use std::{
-    collections::VecDeque,
     env, io,
     io::prelude::Write,
     panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo},
@@ -210,19 +208,9 @@ where
     use std::collections::{self, HashMap};
     use std::hash::BuildHasherDefault;
     use std::sync::mpsc::RecvTimeoutError;
-
-    struct RunningTest {
-        join_handle: Option<thread::JoinHandle<()>>,
-    }
-
     // Use a deterministic hasher
     type TestMap =
-        HashMap<TestDesc, RunningTest, BuildHasherDefault<collections::hash_map::DefaultHasher>>;
-
-    struct TimeoutEntry {
-        desc: TestDesc,
-        timeout: Instant,
-    }
+        HashMap<TestDesc, Instant, BuildHasherDefault<collections::hash_map::DefaultHasher>>;
 
     let tests_len = tests.len();
 
@@ -267,30 +255,23 @@ where
     };
 
     let mut running_tests: TestMap = HashMap::default();
-    let mut timeout_queue: VecDeque<TimeoutEntry> = VecDeque::new();
 
-    fn get_timed_out_tests(
-        running_tests: &TestMap,
-        timeout_queue: &mut VecDeque<TimeoutEntry>,
-    ) -> Vec<TestDesc> {
+    fn get_timed_out_tests(running_tests: &mut TestMap) -> Vec<TestDesc> {
         let now = Instant::now();
-        let mut timed_out = Vec::new();
-        while let Some(timeout_entry) = timeout_queue.front() {
-            if now < timeout_entry.timeout {
-                break;
-            }
-            let timeout_entry = timeout_queue.pop_front().unwrap();
-            if running_tests.contains_key(&timeout_entry.desc) {
-                timed_out.push(timeout_entry.desc);
-            }
+        let timed_out = running_tests
+            .iter()
+            .filter_map(|(desc, timeout)| if &now >= timeout { Some(desc.clone()) } else { None })
+            .collect();
+        for test in &timed_out {
+            running_tests.remove(test);
         }
         timed_out
     }
 
-    fn calc_timeout(timeout_queue: &VecDeque<TimeoutEntry>) -> Option<Duration> {
-        timeout_queue.front().map(|&TimeoutEntry { timeout: next_timeout, .. }| {
+    fn calc_timeout(running_tests: &TestMap) -> Option<Duration> {
+        running_tests.values().min().map(|next_timeout| {
             let now = Instant::now();
-            if next_timeout >= now { next_timeout - now } else { Duration::new(0, 0) }
+            if *next_timeout >= now { *next_timeout - now } else { Duration::new(0, 0) }
         })
     }
 
@@ -299,8 +280,7 @@ where
             let test = remaining.pop().unwrap();
             let event = TestEvent::TeWait(test.desc.clone());
             notify_about_test_event(event)?;
-            run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::No)
-                .unwrap_none();
+            run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::No);
             let completed_test = rx.recv().unwrap();
 
             let event = TestEvent::TeResult(completed_test);
@@ -311,28 +291,19 @@ where
             while pending < concurrency && !remaining.is_empty() {
                 let test = remaining.pop().unwrap();
                 let timeout = time::get_default_test_timeout();
-                let desc = test.desc.clone();
+                running_tests.insert(test.desc.clone(), timeout);
 
-                let event = TestEvent::TeWait(desc.clone());
+                let event = TestEvent::TeWait(test.desc.clone());
                 notify_about_test_event(event)?; //here no pad
-                let join_handle = run_test(
-                    opts,
-                    !opts.run_tests,
-                    test,
-                    run_strategy,
-                    tx.clone(),
-                    Concurrent::Yes,
-                );
-                running_tests.insert(desc.clone(), RunningTest { join_handle });
-                timeout_queue.push_back(TimeoutEntry { desc, timeout });
+                run_test(opts, !opts.run_tests, test, run_strategy, tx.clone(), Concurrent::Yes);
                 pending += 1;
             }
 
             let mut res;
             loop {
-                if let Some(timeout) = calc_timeout(&timeout_queue) {
+                if let Some(timeout) = calc_timeout(&running_tests) {
                     res = rx.recv_timeout(timeout);
-                    for test in get_timed_out_tests(&running_tests, &mut timeout_queue) {
+                    for test in get_timed_out_tests(&mut running_tests) {
                         let event = TestEvent::TeTimeout(test);
                         notify_about_test_event(event)?;
                     }
@@ -352,16 +323,8 @@ where
                 }
             }
 
-            let mut completed_test = res.unwrap();
-            let running_test = running_tests.remove(&completed_test.desc).unwrap();
-            if let Some(join_handle) = running_test.join_handle {
-                if let Err(_) = join_handle.join() {
-                    if let TrOk = completed_test.result {
-                        completed_test.result =
-                            TrFailedMsg("panicked after reporting success".to_string());
-                    }
-                }
-            }
+            let completed_test = res.unwrap();
+            running_tests.remove(&completed_test.desc);
 
             let event = TestEvent::TeResult(completed_test);
             notify_about_test_event(event)?;
@@ -452,7 +415,7 @@ pub fn run_test(
     strategy: RunStrategy,
     monitor_ch: Sender<CompletedTest>,
     concurrency: Concurrent,
-) -> Option<thread::JoinHandle<()>> {
+) {
     let TestDescAndFn { desc, testfn } = test;
 
     // Emscripten can catch panics but other wasm targets cannot
@@ -463,7 +426,7 @@ pub fn run_test(
     if force_ignore || desc.ignore || ignore_because_no_process_support {
         let message = CompletedTest::new(desc, TrIgnored, None, Vec::new());
         monitor_ch.send(message).unwrap();
-        return None;
+        return;
     }
 
     struct TestRunOpts {
@@ -478,7 +441,7 @@ pub fn run_test(
         monitor_ch: Sender<CompletedTest>,
         testfn: Box<dyn FnOnce() + Send>,
         opts: TestRunOpts,
-    ) -> Option<thread::JoinHandle<()>> {
+    ) {
         let concurrency = opts.concurrency;
         let name = desc.name.clone();
 
@@ -506,10 +469,9 @@ pub fn run_test(
         let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32");
         if concurrency == Concurrent::Yes && supports_threads {
             let cfg = thread::Builder::new().name(name.as_slice().to_owned());
-            Some(cfg.spawn(runtest).unwrap())
+            cfg.spawn(runtest).unwrap();
         } else {
             runtest();
-            None
         }
     }
 
@@ -522,12 +484,10 @@ pub fn run_test(
             crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| {
                 bencher.run(harness)
             });
-            None
         }
         StaticBenchFn(benchfn) => {
             // Benchmarks aren't expected to panic, so we run them all in-process.
             crate::bench::benchmark(desc, monitor_ch, opts.nocapture, benchfn);
-            None
         }
         DynTestFn(f) => {
             match strategy {
@@ -539,7 +499,7 @@ pub fn run_test(
                 monitor_ch,
                 Box::new(move || __rust_begin_short_backtrace(f)),
                 test_run_opts,
-            )
+            );
         }
         StaticTestFn(f) => run_test_inner(
             desc,
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 6626fead774d6..c19bb536ce83c 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -320,13 +320,6 @@ macro_rules! tool_check_step {
                     cargo.arg("--all-targets");
                 }
 
-                // Enable internal lints for clippy and rustdoc
-                // NOTE: this intentionally doesn't enable lints for any other tools,
-                // see https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
-                if $path == "src/tools/rustdoc" || $path == "src/tools/clippy" {
-                    cargo.rustflag("-Zunstable-options");
-                }
-
                 builder.info(&format!(
                     "Checking stage{} {} artifacts ({} -> {})",
                     builder.top_stage,
diff --git a/src/ci/pgo.sh b/src/ci/pgo.sh
index a5f47ca78ff59..13b8ca91f890f 100755
--- a/src/ci/pgo.sh
+++ b/src/ci/pgo.sh
@@ -24,20 +24,6 @@ pgo_perf_benchmark ctfe-stress-4
 
 cp -pri ../src/tools/cargo /tmp/cargo
 
-# The Cargo repository does not have a Cargo.lock in it, as it relies on the
-# lockfile already present in the rust-lang/rust monorepo. This decision breaks
-# down when Cargo is built outside the monorepo though (like in this case),
-# resulting in a build without any dependency locking.
-#
-# To ensure Cargo is built with locked dependencies even during PGO profiling
-# the following command copies the monorepo's lockfile into the Cargo temporary
-# directory. Cargo will *not* keep that lockfile intact, as it will remove all
-# the dependencies Cargo itself doesn't rely on. Still, it will prevent
-# building Cargo with arbitrary dependency versions.
-#
-# See #81378 for the bug that prompted adding this.
-cp -p ../Cargo.lock /tmp/cargo
-
 # Build cargo (with some flags)
 function pgo_cargo {
     RUSTC=./build/$PGO_HOST/stage2/bin/rustc \
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 1f9e7f8ae5cd4..916684baf855d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -5,7 +5,7 @@ use std::iter::once;
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_hir::Mutability;
 use rustc_metadata::creader::LoadedMacro;
@@ -17,6 +17,7 @@ use rustc_span::Span;
 
 use crate::clean::{self, Attributes, GetDefId, ToSource, TypeKind};
 use crate::core::DocContext;
+use crate::doctree;
 
 use super::Clean;
 
@@ -245,7 +246,11 @@ fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct {
     let variant = cx.tcx.adt_def(did).non_enum_variant();
 
     clean::Struct {
-        struct_type: variant.ctor_kind,
+        struct_type: match variant.ctor_kind {
+            CtorKind::Fictive => doctree::Plain,
+            CtorKind::Fn => doctree::Tuple,
+            CtorKind::Const => doctree::Unit,
+        },
         generics: (cx.tcx.generics_of(did), predicates).clean(cx),
         fields: variant.fields.clean(cx),
         fields_stripped: false,
@@ -257,6 +262,7 @@ fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union {
     let variant = cx.tcx.adt_def(did).non_enum_variant();
 
     clean::Union {
+        struct_type: doctree::Plain,
         generics: (cx.tcx.generics_of(did), predicates).clean(cx),
         fields: variant.fields.clean(cx),
         fields_stripped: false,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a116ed686d90e..3ddb2adbf0aa7 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1096,10 +1096,7 @@ impl Clean<Item> for hir::TraitItem<'_> {
                     AssocTypeItem(bounds.clean(cx), default.clean(cx))
                 }
             };
-            let what_rustc_thinks =
-                Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
-            // Trait items always inherit the trait's visibility -- we don't want to show `pub`.
-            Item { visibility: Inherited, ..what_rustc_thinks }
+            Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx)
         })
     }
 }
@@ -1134,21 +1131,7 @@ impl Clean<Item> for hir::ImplItem<'_> {
                     )
                 }
             };
-
-            let what_rustc_thinks =
-                Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
-            let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(self.hir_id));
-            if let hir::ItemKind::Impl(impl_) = &parent_item.kind {
-                if impl_.of_trait.is_some() {
-                    // Trait impl items always inherit the impl's visibility --
-                    // we don't want to show `pub`.
-                    Item { visibility: Inherited, ..what_rustc_thinks }
-                } else {
-                    what_rustc_thinks
-                }
-            } else {
-                panic!("found impl item with non-impl parent {:?}", parent_item);
-            }
+            Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx)
         })
     }
 }
@@ -1844,7 +1827,7 @@ impl Clean<Visibility> for ty::Visibility {
 impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
         VariantStruct {
-            struct_type: CtorKind::from_hir(self),
+            struct_type: doctree::struct_type_from_def(self),
             fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
             fields_stripped: false,
         }
@@ -1859,7 +1842,7 @@ impl Clean<Item> for ty::VariantDef {
                 self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect(),
             ),
             CtorKind::Fictive => Variant::Struct(VariantStruct {
-                struct_type: CtorKind::Fictive,
+                struct_type: doctree::Plain,
                 fields_stripped: false,
                 fields: self
                     .fields
@@ -2013,12 +1996,13 @@ impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
                     bounds: bounds.clean(cx),
                 }),
                 ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
+                    struct_type: doctree::struct_type_from_def(&variant_data),
                     generics: generics.clean(cx),
                     fields: variant_data.fields().clean(cx),
                     fields_stripped: false,
                 }),
                 ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
-                    struct_type: CtorKind::from_hir(variant_data),
+                    struct_type: doctree::struct_type_from_def(&variant_data),
                     generics: generics.clean(cx),
                     fields: variant_data.fields().clean(cx),
                     fields_stripped: false,
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index c767b9dd85bf9..666b11b5f806d 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -16,7 +16,7 @@ use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_feature::UnstableFeatures;
 use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, Res};
+use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::Mutability;
@@ -37,6 +37,7 @@ use crate::clean::inline;
 use crate::clean::types::Type::{QPath, ResolvedPath};
 use crate::clean::Clean;
 use crate::core::DocContext;
+use crate::doctree;
 use crate::formats::cache::cache;
 use crate::formats::item_type::ItemType;
 use crate::html::render::cache::ExternalLocation;
@@ -1684,7 +1685,7 @@ impl Visibility {
 
 #[derive(Clone, Debug)]
 crate struct Struct {
-    crate struct_type: CtorKind,
+    crate struct_type: doctree::StructType,
     crate generics: Generics,
     crate fields: Vec<Item>,
     crate fields_stripped: bool,
@@ -1692,6 +1693,7 @@ crate struct Struct {
 
 #[derive(Clone, Debug)]
 crate struct Union {
+    crate struct_type: doctree::StructType,
     crate generics: Generics,
     crate fields: Vec<Item>,
     crate fields_stripped: bool,
@@ -1702,7 +1704,7 @@ crate struct Union {
 /// only as a variant in an enum.
 #[derive(Clone, Debug)]
 crate struct VariantStruct {
-    crate struct_type: CtorKind,
+    crate struct_type: doctree::StructType,
     crate fields: Vec<Item>,
     crate fields_stripped: bool,
 }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index fee1bf4c3a6a7..e43ea965c0423 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -1,4 +1,4 @@
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, HashMap};
 use std::convert::TryFrom;
 use std::ffi::OsStr;
 use std::fmt;
@@ -103,8 +103,6 @@ crate struct Options {
     crate should_test: bool,
     /// List of arguments to pass to the test harness, if running tests.
     crate test_args: Vec<String>,
-    /// The working directory in which to run tests.
-    crate test_run_directory: Option<PathBuf>,
     /// Optional path to persist the doctest executables to, defaults to a
     /// temporary directory if not set.
     crate persist_doctests: Option<PathBuf>,
@@ -177,7 +175,6 @@ impl fmt::Debug for Options {
             .field("lint_cap", &self.lint_cap)
             .field("should_test", &self.should_test)
             .field("test_args", &self.test_args)
-            .field("test_run_directory", &self.test_run_directory)
             .field("persist_doctests", &self.persist_doctests)
             .field("default_passes", &self.default_passes)
             .field("manual_passes", &self.manual_passes)
@@ -222,7 +219,7 @@ crate struct RenderOptions {
     crate extern_html_root_urls: BTreeMap<String, String>,
     /// A map of the default settings (values are as for DOM storage API). Keys should lack the
     /// `rustdoc-` prefix.
-    crate default_settings: FxHashMap<String, String>,
+    crate default_settings: HashMap<String, String>,
     /// If present, suffix added to CSS/JavaScript files when referencing them in generated pages.
     crate resource_suffix: String,
     /// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by
@@ -575,7 +572,6 @@ impl Options {
         let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some();
         let static_root_path = matches.opt_str("static-root-path");
         let generate_search_filter = !matches.opt_present("disable-per-crate-search");
-        let test_run_directory = matches.opt_str("test-run-directory").map(PathBuf::from);
         let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from);
         let test_builder = matches.opt_str("test-builder").map(PathBuf::from);
         let codegen_options_strs = matches.opt_strs("C");
@@ -617,7 +613,6 @@ impl Options {
             display_warnings,
             show_coverage,
             crate_version,
-            test_run_directory,
             persist_doctests,
             runtool,
             runtool_args,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 30ff124dac60f..3de97f2dd2e59 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1,5 +1,4 @@
 use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{ColorConfig, ErrorReported};
 use rustc_hir as hir;
@@ -17,6 +16,7 @@ use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP};
 use rustc_target::spec::TargetTriple;
 use tempfile::Builder as TempFileBuilder;
 
+use std::collections::HashMap;
 use std::env;
 use std::io::{self, Write};
 use std::panic;
@@ -365,9 +365,6 @@ fn run_test(
     } else {
         cmd = Command::new(output_file);
     }
-    if let Some(run_directory) = options.test_run_directory {
-        cmd.current_dir(run_directory);
-    }
 
     match cmd.output() {
         Err(e) => return Err(TestFailure::ExecutionError(e)),
@@ -426,7 +423,6 @@ crate fn make_test(
             use rustc_errors::emitter::{Emitter, EmitterWriter};
             use rustc_errors::Handler;
             use rustc_parse::maybe_new_parser_from_source_str;
-            use rustc_parse::parser::ForceCollect;
             use rustc_session::parse::ParseSess;
             use rustc_span::source_map::FilePathMapping;
 
@@ -463,7 +459,7 @@ crate fn make_test(
             };
 
             loop {
-                match parser.parse_item(ForceCollect::No) {
+                match parser.parse_item() {
                     Ok(Some(item)) => {
                         if !found_main {
                             if let ast::ItemKind::Fn(..) = item.kind {
@@ -707,7 +703,7 @@ crate struct Collector {
     position: Span,
     source_map: Option<Lrc<SourceMap>>,
     filename: Option<PathBuf>,
-    visited_tests: FxHashMap<(String, usize), usize>,
+    visited_tests: HashMap<(String, usize), usize>,
 }
 
 impl Collector {
@@ -731,7 +727,7 @@ impl Collector {
             position: DUMMY_SP,
             source_map,
             filename,
-            visited_tests: FxHashMap::default(),
+            visited_tests: HashMap::new(),
         }
     }
 
@@ -1013,7 +1009,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
                 self.codes,
                 self.collector.enable_per_target_ignores,
                 Some(&crate::html::markdown::ExtraInfo::new(
-                    self.tcx,
+                    &self.tcx,
                     hir_id,
                     span_of_attrs(&attrs).unwrap_or(sp),
                 )),
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 645b2bb193ec2..f90623c03118b 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -1,5 +1,7 @@
 //! This module is used to store stuff from Rust's AST in a more convenient
 //! manner (and with prettier names) before cleaning.
+crate use self::StructType::*;
+
 use rustc_span::{self, Span, Symbol};
 
 use rustc_hir as hir;
@@ -32,3 +34,21 @@ impl Module<'hir> {
         }
     }
 }
+
+#[derive(Debug, Clone, Copy)]
+crate enum StructType {
+    /// A braced struct
+    Plain,
+    /// A tuple struct
+    Tuple,
+    /// A unit struct
+    Unit,
+}
+
+crate fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType {
+    match *vdata {
+        hir::VariantData::Struct(..) => Plain,
+        hir::VariantData::Tuple(..) => Tuple,
+        hir::VariantData::Unit(..) => Unit,
+    }
+}
diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs
index 6941fa064ec03..e84a9853d9b7c 100644
--- a/src/librustdoc/formats/renderer.rs
+++ b/src/librustdoc/formats/renderer.rs
@@ -1,6 +1,6 @@
 use std::sync::Arc;
 
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty;
 use rustc_span::edition::Edition;
 
 use crate::clean;
@@ -12,9 +12,6 @@ use crate::formats::cache::{Cache, CACHE_KEY};
 /// backend renderer has hooks for initialization, documenting an item, entering and exiting a
 /// module, and cleanup/finalizing output.
 crate trait FormatRenderer<'tcx>: Clone {
-    /// Gives a description of the renderer. Used for performance profiling.
-    fn descr() -> &'static str;
-
     /// Sets up any state required for the renderer. When this is called the cache has already been
     /// populated.
     fn init(
@@ -23,7 +20,7 @@ crate trait FormatRenderer<'tcx>: Clone {
         render_info: RenderInfo,
         edition: Edition,
         cache: &mut Cache,
-        tcx: TyCtxt<'tcx>,
+        tcx: ty::TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error>;
 
     /// Renders a single non-module item. This means no recursive sub-item rendering is required.
@@ -41,14 +38,10 @@ crate trait FormatRenderer<'tcx>: Clone {
     fn mod_item_out(&mut self, item_name: &str) -> Result<(), Error>;
 
     /// Post processing hook for cleanup and dumping output to files.
-    ///
-    /// A handler is available if the renderer wants to report errors.
-    fn after_krate(
-        &mut self,
-        krate: &clean::Crate,
-        cache: &Cache,
-        diag: &rustc_errors::Handler,
-    ) -> Result<(), Error>;
+    fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error>;
+
+    /// Called after everything else to write out errors.
+    fn after_run(&mut self, diag: &rustc_errors::Handler) -> Result<(), Error>;
 }
 
 /// Main method for rendering a crate.
@@ -58,22 +51,18 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
     render_info: RenderInfo,
     diag: &rustc_errors::Handler,
     edition: Edition,
-    tcx: TyCtxt<'tcx>,
+    tcx: ty::TyCtxt<'tcx>,
 ) -> Result<(), Error> {
-    let (krate, mut cache) = tcx.sess.time("create_format_cache", || {
-        Cache::from_krate(
-            render_info.clone(),
-            options.document_private,
-            &options.extern_html_root_urls,
-            &options.output,
-            krate,
-        )
-    });
-    let prof = &tcx.sess.prof;
-
-    let (mut format_renderer, mut krate) = prof
-        .extra_verbose_generic_activity("create_renderer", T::descr())
-        .run(|| T::init(krate, options, render_info, edition, &mut cache, tcx))?;
+    let (krate, mut cache) = Cache::from_krate(
+        render_info.clone(),
+        options.document_private,
+        &options.extern_html_root_urls,
+        &options.output,
+        krate,
+    );
+
+    let (mut format_renderer, mut krate) =
+        T::init(krate, options, render_info, edition, &mut cache, tcx)?;
 
     let cache = Arc::new(cache);
     // Freeze the cache now that the index has been built. Put an Arc into TLS for future
@@ -90,7 +79,6 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
     // Render the crate documentation
     let mut work = vec![(format_renderer.clone(), item)];
 
-    let unknown = rustc_span::Symbol::intern("<unknown item>");
     while let Some((mut cx, item)) = work.pop() {
         if item.is_mod() {
             // modules are special because they add a namespace. We also need to
@@ -99,7 +87,6 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
             if name.is_empty() {
                 panic!("Unexpected module with empty name");
             }
-            let _timer = prof.generic_activity_with_arg("render_mod_item", name.as_str());
 
             cx.mod_item_in(&item, &name, &cache)?;
             let module = match *item.kind {
@@ -113,10 +100,10 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
 
             cx.mod_item_out(&name)?;
         } else if item.name.is_some() {
-            prof.generic_activity_with_arg("render_item", &*item.name.unwrap_or(unknown).as_str())
-                .run(|| cx.item(item, &cache))?;
+            cx.item(item, &cache)?;
         }
     }
-    prof.extra_verbose_generic_activity("renderer_after_krate", T::descr())
-        .run(|| format_renderer.after_krate(&krate, &cache, diag))
+
+    format_renderer.after_krate(&krate, &cache)?;
+    format_renderer.after_run(diag)
 }
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index c6ff4b57a6e59..4458eea95f3e1 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -1,7 +1,6 @@
+use std::collections::HashMap;
 use std::path::PathBuf;
 
-use rustc_data_structures::fx::FxHashMap;
-
 use crate::externalfiles::ExternalHtml;
 use crate::html::escape::Escape;
 use crate::html::format::{Buffer, Print};
@@ -12,7 +11,7 @@ crate struct Layout {
     crate logo: String,
     crate favicon: String,
     crate external_html: ExternalHtml,
-    crate default_settings: FxHashMap<String, String>,
+    crate default_settings: HashMap<String, String>,
     crate krate: String,
     /// The given user css file which allow to customize the generated
     /// documentation theme.
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 7c8b76be374a8..cfa6cd96595d6 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -620,7 +620,7 @@ crate fn find_testable_code<T: doctest::Tester>(
     tests: &mut T,
     error_codes: ErrorCodes,
     enable_per_target_ignores: bool,
-    extra_info: Option<&ExtraInfo<'_>>,
+    extra_info: Option<&ExtraInfo<'_, '_>>,
 ) {
     let mut parser = Parser::new(doc).into_offset_iter();
     let mut prev_offset = 0;
@@ -681,19 +681,19 @@ crate fn find_testable_code<T: doctest::Tester>(
     }
 }
 
-crate struct ExtraInfo<'tcx> {
+crate struct ExtraInfo<'a, 'b> {
     hir_id: Option<HirId>,
     item_did: Option<DefId>,
     sp: Span,
-    tcx: TyCtxt<'tcx>,
+    tcx: &'a TyCtxt<'b>,
 }
 
-impl<'tcx> ExtraInfo<'tcx> {
-    crate fn new(tcx: TyCtxt<'tcx>, hir_id: HirId, sp: Span) -> ExtraInfo<'tcx> {
+impl<'a, 'b> ExtraInfo<'a, 'b> {
+    crate fn new(tcx: &'a TyCtxt<'b>, hir_id: HirId, sp: Span) -> ExtraInfo<'a, 'b> {
         ExtraInfo { hir_id: Some(hir_id), item_did: None, sp, tcx }
     }
 
-    crate fn new_did(tcx: TyCtxt<'tcx>, did: DefId, sp: Span) -> ExtraInfo<'tcx> {
+    crate fn new_did(tcx: &'a TyCtxt<'b>, did: DefId, sp: Span) -> ExtraInfo<'a, 'b> {
         ExtraInfo { hir_id: None, item_did: Some(did), sp, tcx }
     }
 
@@ -775,7 +775,7 @@ impl LangString {
         string: &str,
         allow_error_code_check: ErrorCodes,
         enable_per_target_ignores: bool,
-        extra: Option<&ExtraInfo<'_>>,
+        extra: Option<&ExtraInfo<'_, '_>>,
     ) -> LangString {
         let allow_error_code_check = allow_error_code_check.as_bool();
         let mut seen_rust_tags = false;
@@ -1208,7 +1208,7 @@ crate struct RustCodeBlock {
 
 /// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or
 /// untagged (and assumed to be rust).
-crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<RustCodeBlock> {
+crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_, '_>) -> Vec<RustCodeBlock> {
     let mut code_blocks = vec![];
 
     if md.is_empty() {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index ef45c98e40629..03e091297e5b6 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -52,10 +52,10 @@ use rustc_attr::{Deprecation, StabilityLevel};
 use rustc_data_structures::flock;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
-use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::Mutability;
 use rustc_middle::middle::stability;
+use rustc_middle::ty;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -68,6 +68,7 @@ use serde::{Serialize, Serializer};
 use crate::clean::{self, AttributesExt, GetDefId, RenderedLink, SelfTy, TypeKind};
 use crate::config::{RenderInfo, RenderOptions};
 use crate::docfs::{DocFS, PathError};
+use crate::doctree;
 use crate::error::Error;
 use crate::formats::cache::{cache, Cache};
 use crate::formats::item_type::ItemType;
@@ -383,17 +384,13 @@ crate fn initial_ids() -> Vec<String> {
 
 /// Generates the documentation for `crate` into the directory `dst`
 impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
-    fn descr() -> &'static str {
-        "html"
-    }
-
     fn init(
         mut krate: clean::Crate,
         options: RenderOptions,
         _render_info: RenderInfo,
         edition: Edition,
         cache: &mut Cache,
-        tcx: TyCtxt<'tcx>,
+        tcx: ty::TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error> {
         // need to save a copy of the options for rendering the index page
         let md_opts = options.clone();
@@ -526,12 +523,17 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         Ok((cx, krate))
     }
 
-    fn after_krate(
-        &mut self,
-        krate: &clean::Crate,
-        cache: &Cache,
-        diag: &rustc_errors::Handler,
-    ) -> Result<(), Error> {
+    fn after_run(&mut self, diag: &rustc_errors::Handler) -> Result<(), Error> {
+        Arc::get_mut(&mut self.shared).unwrap().fs.close();
+        let nb_errors = self.errors.iter().map(|err| diag.struct_err(&err).emit()).count();
+        if nb_errors > 0 {
+            Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), ""))
+        } else {
+            Ok(())
+        }
+    }
+
+    fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error> {
         let final_file = self.dst.join(&*krate.name.as_str()).join("all.html");
         let settings_file = self.dst.join("settings.html");
         let crate_name = krate.name;
@@ -594,15 +596,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             &style_files,
         );
         self.shared.fs.write(&settings_file, v.as_bytes())?;
-
-        // Flush pending errors.
-        Arc::get_mut(&mut self.shared).unwrap().fs.close();
-        let nb_errors = self.errors.iter().map(|err| diag.struct_err(&err).emit()).count();
-        if nb_errors > 0 {
-            Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), ""))
-        } else {
-            Ok(())
-        }
+        Ok(())
     }
 
     fn mod_item_in(
@@ -2474,7 +2468,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
 fn render_implementor(
     cx: &Context<'_>,
     implementor: &Impl,
-    trait_: &clean::Item,
+    parent: &clean::Item,
     w: &mut Buffer,
     implementor_dups: &FxHashMap<Symbol, (DefId, bool)>,
     aliases: &[String],
@@ -2494,11 +2488,11 @@ fn render_implementor(
         w,
         cx,
         implementor,
-        trait_,
+        parent,
         AssocItemLink::Anchor(None),
         RenderMode::Normal,
-        trait_.stable_since(cx.tcx()).as_deref(),
-        trait_.const_stable_since(cx.tcx()).as_deref(),
+        implementor.impl_item.stable_since(cx.tcx()).as_deref(),
+        implementor.impl_item.const_stable_since(cx.tcx()).as_deref(),
         false,
         Some(use_absolute),
         false,
@@ -2937,25 +2931,34 @@ fn render_stability_since_raw(
     containing_ver: Option<&str>,
     containing_const_ver: Option<&str>,
 ) {
-    let ver = ver.filter(|inner| !inner.is_empty());
-    let const_ver = const_ver.filter(|inner| !inner.is_empty());
+    let ver = ver.and_then(|inner| if !inner.is_empty() { Some(inner) } else { None });
 
-    match (ver, const_ver) {
-        (Some(v), Some(cv)) if const_ver != containing_const_ver => {
-            write!(
-                w,
-                "<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>",
-                v, cv
-            );
-        }
-        (Some(v), _) if ver != containing_ver => {
-            write!(
-                w,
-                "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
-                v
-            );
+    let const_ver = const_ver.and_then(|inner| if !inner.is_empty() { Some(inner) } else { None });
+
+    if let Some(v) = ver {
+        if let Some(cv) = const_ver {
+            if const_ver != containing_const_ver {
+                write!(
+                    w,
+                    "<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>",
+                    v, cv
+                );
+            } else if ver != containing_ver {
+                write!(
+                    w,
+                    "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
+                    v
+                );
+            }
+        } else {
+            if ver != containing_ver {
+                write!(
+                    w,
+                    "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
+                    v
+                );
+            }
         }
-        _ => {}
     }
 }
 
@@ -3098,7 +3101,7 @@ fn item_struct(
             _ => None,
         })
         .peekable();
-    if let CtorKind::Fictive = s.struct_type {
+    if let doctree::Plain = s.struct_type {
         if fields.peek().is_some() {
             write!(
                 w,
@@ -3348,7 +3351,7 @@ fn render_struct(
     w: &mut Buffer,
     it: &clean::Item,
     g: Option<&clean::Generics>,
-    ty: CtorKind,
+    ty: doctree::StructType,
     fields: &[clean::Item],
     tab: &str,
     structhead: bool,
@@ -3365,7 +3368,7 @@ fn render_struct(
         write!(w, "{}", g.print())
     }
     match ty {
-        CtorKind::Fictive => {
+        doctree::Plain => {
             if let Some(g) = g {
                 write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })
             }
@@ -3397,7 +3400,7 @@ fn render_struct(
             }
             write!(w, "}}");
         }
-        CtorKind::Fn => {
+        doctree::Tuple => {
             write!(w, "(");
             for (i, field) in fields.iter().enumerate() {
                 if i > 0 {
@@ -3422,7 +3425,7 @@ fn render_struct(
             }
             write!(w, ";");
         }
-        CtorKind::Const => {
+        doctree::Unit => {
             // Needed for PhantomData.
             if let Some(g) = g {
                 write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })
@@ -4457,7 +4460,7 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea
     let fields = get_struct_fields_name(&s.fields);
 
     if !fields.is_empty() {
-        if let CtorKind::Fictive = s.struct_type {
+        if let doctree::Plain = s.struct_type {
             sidebar.push_str(&format!(
                 "<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\
                  <div class=\"sidebar-links\">{}</div>",
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index bfd2141d9a174..7d05cb016b67c 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -5,11 +5,11 @@
 use std::convert::From;
 
 use rustc_ast::ast;
-use rustc_hir::def::CtorKind;
 use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_span::Pos;
 
 use crate::clean;
+use crate::doctree;
 use crate::formats::item_type::ItemType;
 use crate::json::types::*;
 use crate::json::JsonRenderer;
@@ -27,7 +27,7 @@ impl JsonRenderer<'_> {
                 name: name.map(|sym| sym.to_string()),
                 source: self.convert_span(source),
                 visibility: self.convert_visibility(visibility),
-                docs: attrs.collapsed_doc_value(),
+                docs: attrs.collapsed_doc_value().unwrap_or_default(),
                 links: attrs
                     .links
                     .into_iter()
@@ -210,9 +210,9 @@ impl From<clean::Struct> for Struct {
 
 impl From<clean::Union> for Struct {
     fn from(struct_: clean::Union) -> Self {
-        let clean::Union { generics, fields, fields_stripped } = struct_;
+        let clean::Union { struct_type, generics, fields, fields_stripped } = struct_;
         Struct {
-            struct_type: StructType::Union,
+            struct_type: struct_type.into(),
             generics: generics.into(),
             fields_stripped,
             fields: ids(fields),
@@ -221,12 +221,13 @@ impl From<clean::Union> for Struct {
     }
 }
 
-impl From<CtorKind> for StructType {
-    fn from(struct_type: CtorKind) -> Self {
+impl From<doctree::StructType> for StructType {
+    fn from(struct_type: doctree::StructType) -> Self {
+        use doctree::StructType::*;
         match struct_type {
-            CtorKind::Fictive => StructType::Plain,
-            CtorKind::Fn => StructType::Tuple,
-            CtorKind::Const => StructType::Unit,
+            Plain => StructType::Plain,
+            Tuple => StructType::Tuple,
+            Unit => StructType::Unit,
         }
     }
 }
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 512c9124727ef..df7ab9b7361a0 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -13,7 +13,7 @@ use std::path::PathBuf;
 use std::rc::Rc;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
 
@@ -26,7 +26,7 @@ use crate::html::render::cache::ExternalLocation;
 
 #[derive(Clone)]
 crate struct JsonRenderer<'tcx> {
-    tcx: TyCtxt<'tcx>,
+    tcx: ty::TyCtxt<'tcx>,
     /// A mapping of IDs that contains all local items for this crate which gets output as a top
     /// level field of the JSON blob.
     index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>,
@@ -125,17 +125,13 @@ impl JsonRenderer<'_> {
 }
 
 impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
-    fn descr() -> &'static str {
-        "json"
-    }
-
     fn init(
         krate: clean::Crate,
         options: RenderOptions,
         _render_info: RenderInfo,
         _edition: Edition,
         _cache: &mut Cache,
-        tcx: TyCtxt<'tcx>,
+        tcx: ty::TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error> {
         debug!("Initializing json renderer");
         Ok((
@@ -203,12 +199,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         Ok(())
     }
 
-    fn after_krate(
-        &mut self,
-        krate: &clean::Crate,
-        cache: &Cache,
-        _diag: &rustc_errors::Handler,
-    ) -> Result<(), Error> {
+    fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error> {
         debug!("Done with crate");
         let mut index = (*self.index).clone().into_inner();
         index.extend(self.get_trait_items(cache));
@@ -245,7 +236,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
                     )
                 })
                 .collect(),
-            format_version: 2,
+            format_version: 1,
         };
         let mut p = self.out_path.clone();
         p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
@@ -254,4 +245,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         serde_json::ser::to_writer(&file, &output).unwrap();
         Ok(())
     }
+
+    fn after_run(&mut self, _diag: &rustc_errors::Handler) -> Result<(), Error> {
+        Ok(())
+    }
 }
diff --git a/src/librustdoc/json/types.rs b/src/librustdoc/json/types.rs
index 66cf12954dd0b..9335fe9be1a4b 100644
--- a/src/librustdoc/json/types.rs
+++ b/src/librustdoc/json/types.rs
@@ -68,9 +68,8 @@ pub struct Item {
     /// By default all documented items are public, but you can tell rustdoc to output private items
     /// so this field is needed to differentiate.
     pub visibility: Visibility,
-    /// The full markdown docstring of this item. Absent if there is no documentation at all,
-    /// Some("") if there is some documentation but it is empty (EG `#[doc = ""]`).
-    pub docs: Option<String>,
+    /// The full markdown docstring of this item.
+    pub docs: String,
     /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs
     pub links: FxHashMap<String, Id>,
     /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`)
@@ -270,7 +269,6 @@ pub enum StructType {
     Plain,
     Tuple,
     Unit,
-    Union,
 }
 
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index c61cbf78f771a..719aca612f50d 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -18,7 +18,6 @@
 #![feature(str_split_once)]
 #![feature(iter_intersperse)]
 #![recursion_limit = "256"]
-#![deny(rustc::internal)]
 
 #[macro_use]
 extern crate lazy_static;
@@ -66,7 +65,7 @@ use std::process;
 use rustc_driver::abort_on_err;
 use rustc_errors::ErrorReported;
 use rustc_interface::interface;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty;
 use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup};
 use rustc_session::getopts;
 use rustc_session::{early_error, early_warn};
@@ -168,14 +167,6 @@ fn opts() -> Vec<RustcOptGroup> {
         stable("test-args", |o| {
             o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")
         }),
-        unstable("test-run-directory", |o| {
-            o.optopt(
-                "",
-                "test-run-directory",
-                "The working directory in which to run tests",
-                "PATH",
-            )
-        }),
         stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")),
         stable("markdown-css", |o| {
             o.optmulti(
@@ -480,7 +471,7 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
     render_info: config::RenderInfo,
     diag: &rustc_errors::Handler,
     edition: rustc_span::edition::Edition,
-    tcx: TyCtxt<'tcx>,
+    tcx: ty::TyCtxt<'tcx>,
 ) -> MainResult {
     match formats::run_format::<T>(krate, renderopts, render_info, &diag, edition, tcx) {
         Ok(_) => Ok(()),
@@ -548,7 +539,7 @@ fn main_options(options: config::Options) -> MainResult {
                 sess.fatal("Compilation failed, aborting rustdoc");
             }
 
-            let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).peek_mut();
+            let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take();
 
             global_ctxt.enter(|tcx| {
                 let (mut krate, render_info, render_opts) = sess.time("run_global_ctxt", || {
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index 9516130034b59..554392c213e24 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -108,7 +108,7 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         if let Some(dox) = &item.attrs.collapsed_doc_value() {
             let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());
-            let extra = crate::html::markdown::ExtraInfo::new_did(self.cx.tcx, item.def_id, sp);
+            let extra = crate::html::markdown::ExtraInfo::new_did(&self.cx.tcx, item.def_id, sp);
             for code_block in markdown::rust_code_blocks(&dox, &extra) {
                 self.check_rust_syntax(&item, &dox, code_block);
             }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 002d8938f694d..2694450a520c9 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -13,7 +13,6 @@ use rustc_hir::def::{
     PerNS,
 };
 use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_middle::ty::TyCtxt;
 use rustc_middle::{bug, ty};
 use rustc_resolve::ParentScope;
 use rustc_session::lint::{
@@ -86,7 +85,7 @@ impl Res {
         }
     }
 
-    fn name(self, tcx: TyCtxt<'_>) -> String {
+    fn name(self, tcx: ty::TyCtxt<'_>) -> String {
         match self {
             Res::Def(_, id) => tcx.item_name(id).to_string(),
             Res::Primitive(prim) => prim.as_str().to_string(),
@@ -866,11 +865,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
 
         // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
         let self_name = self_id.and_then(|self_id| {
+            use ty::TyKind;
             if matches!(self.cx.tcx.def_kind(self_id), DefKind::Impl) {
                 // using `ty.to_string()` (or any variant) has issues with raw idents
                 let ty = self.cx.tcx.type_of(self_id);
                 let name = match ty.kind() {
-                    ty::Adt(def, _) => Some(self.cx.tcx.item_name(def.did).to_string()),
+                    TyKind::Adt(def, _) => Some(self.cx.tcx.item_name(def.did).to_string()),
                     other if other.is_primitive() => Some(ty.to_string()),
                     _ => None,
                 };
diff --git a/src/test/mir-opt/inline/cycle.f.Inline.diff b/src/test/mir-opt/inline/cycle.f.Inline.diff
deleted file mode 100644
index 54dd545dfb9a6..0000000000000
--- a/src/test/mir-opt/inline/cycle.f.Inline.diff
+++ /dev/null
@@ -1,42 +0,0 @@
-- // MIR for `f` before Inline
-+ // MIR for `f` after Inline
-  
-  fn f(_1: impl Fn()) -> () {
-      debug g => _1;                       // in scope 0 at $DIR/cycle.rs:5:6: 5:7
-      let mut _0: ();                      // return place in scope 0 at $DIR/cycle.rs:5:20: 5:20
-      let _2: ();                          // in scope 0 at $DIR/cycle.rs:6:5: 6:8
-      let mut _3: &impl Fn();              // in scope 0 at $DIR/cycle.rs:6:5: 6:6
-      let mut _4: ();                      // in scope 0 at $DIR/cycle.rs:6:5: 6:8
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/cycle.rs:6:5: 6:8
-          StorageLive(_3);                 // scope 0 at $DIR/cycle.rs:6:5: 6:6
-          _3 = &_1;                        // scope 0 at $DIR/cycle.rs:6:5: 6:6
-          StorageLive(_4);                 // scope 0 at $DIR/cycle.rs:6:5: 6:8
-          _2 = <impl Fn() as Fn<()>>::call(move _3, move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/cycle.rs:6:5: 6:8
-                                           // mir::Constant
-                                           // + span: $DIR/cycle.rs:6:5: 6:6
-                                           // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as std::ops::FnOnce<()>>::Output {<impl Fn() as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
-      }
-  
-      bb1: {
-          StorageDead(_4);                 // scope 0 at $DIR/cycle.rs:6:7: 6:8
-          StorageDead(_3);                 // scope 0 at $DIR/cycle.rs:6:7: 6:8
-          StorageDead(_2);                 // scope 0 at $DIR/cycle.rs:6:8: 6:9
-          _0 = const ();                   // scope 0 at $DIR/cycle.rs:5:20: 7:2
-          drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/cycle.rs:7:1: 7:2
-      }
-  
-      bb2: {
-          return;                          // scope 0 at $DIR/cycle.rs:7:2: 7:2
-      }
-  
-      bb3 (cleanup): {
-          drop(_1) -> bb4;                 // scope 0 at $DIR/cycle.rs:7:1: 7:2
-      }
-  
-      bb4 (cleanup): {
-          resume;                          // scope 0 at $DIR/cycle.rs:5:1: 7:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/inline/cycle.g.Inline.diff b/src/test/mir-opt/inline/cycle.g.Inline.diff
deleted file mode 100644
index 46f5e5e20655b..0000000000000
--- a/src/test/mir-opt/inline/cycle.g.Inline.diff
+++ /dev/null
@@ -1,25 +0,0 @@
-- // MIR for `g` before Inline
-+ // MIR for `g` after Inline
-  
-  fn g() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/cycle.rs:11:8: 11:8
-      let _1: ();                          // in scope 0 at $DIR/cycle.rs:12:5: 12:12
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/cycle.rs:12:5: 12:12
-          _1 = f::<fn() {main}>(main) -> bb1; // scope 0 at $DIR/cycle.rs:12:5: 12:12
-                                           // mir::Constant
-                                           // + span: $DIR/cycle.rs:12:5: 12:6
-                                           // + literal: Const { ty: fn(fn() {main}) {f::<fn() {main}>}, val: Value(Scalar(<ZST>)) }
-                                           // mir::Constant
-                                           // + span: $DIR/cycle.rs:12:7: 12:11
-                                           // + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) }
-      }
-  
-      bb1: {
-          StorageDead(_1);                 // scope 0 at $DIR/cycle.rs:12:12: 12:13
-          _0 = const ();                   // scope 0 at $DIR/cycle.rs:11:8: 13:2
-          return;                          // scope 0 at $DIR/cycle.rs:13:2: 13:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/inline/cycle.main.Inline.diff b/src/test/mir-opt/inline/cycle.main.Inline.diff
deleted file mode 100644
index c8d1448d949d4..0000000000000
--- a/src/test/mir-opt/inline/cycle.main.Inline.diff
+++ /dev/null
@@ -1,25 +0,0 @@
-- // MIR for `main` before Inline
-+ // MIR for `main` after Inline
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/cycle.rs:16:11: 16:11
-      let _1: ();                          // in scope 0 at $DIR/cycle.rs:17:5: 17:9
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/cycle.rs:17:5: 17:9
-          _1 = f::<fn() {g}>(g) -> bb1;    // scope 0 at $DIR/cycle.rs:17:5: 17:9
-                                           // mir::Constant
-                                           // + span: $DIR/cycle.rs:17:5: 17:6
-                                           // + literal: Const { ty: fn(fn() {g}) {f::<fn() {g}>}, val: Value(Scalar(<ZST>)) }
-                                           // mir::Constant
-                                           // + span: $DIR/cycle.rs:17:7: 17:8
-                                           // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) }
-      }
-  
-      bb1: {
-          StorageDead(_1);                 // scope 0 at $DIR/cycle.rs:17:9: 17:10
-          _0 = const ();                   // scope 0 at $DIR/cycle.rs:16:11: 18:2
-          return;                          // scope 0 at $DIR/cycle.rs:18:2: 18:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/inline/cycle.rs b/src/test/mir-opt/inline/cycle.rs
deleted file mode 100644
index 9e8950d8a3d61..0000000000000
--- a/src/test/mir-opt/inline/cycle.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// ignore-wasm32-bare compiled with panic=abort by default
-
-// EMIT_MIR cycle.f.Inline.diff
-#[inline(always)]
-fn f(g: impl Fn()) {
-    g();
-}
-
-// EMIT_MIR cycle.g.Inline.diff
-#[inline(always)]
-fn g() {
-    f(main);
-}
-
-// EMIT_MIR cycle.main.Inline.diff
-fn main() {
-    f(g);
-}
diff --git a/src/test/mir-opt/inline/inline-cycle-generic.rs b/src/test/mir-opt/inline/inline-cycle-generic.rs
deleted file mode 100644
index 24b4f37939ad1..0000000000000
--- a/src/test/mir-opt/inline/inline-cycle-generic.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Check that inliner handles various forms of recursion and doesn't fall into
-// an infinite inlining cycle. The particular outcome of inlining is not
-// crucial otherwise.
-//
-// Regression test for issue #78573.
-
-// EMIT_MIR inline_cycle_generic.main.Inline.diff
-fn main() {
-    <C as Call>::call();
-}
-
-pub trait Call {
-    fn call();
-}
-
-pub struct A;
-pub struct B<T>(T);
-pub struct C;
-
-impl Call for A {
-    #[inline]
-    fn call() {
-        <B<C> as Call>::call()
-    }
-}
-
-
-impl<T: Call> Call for B<T> {
-    #[inline]
-    fn call() {
-        <T as Call>::call()
-    }
-}
-
-impl Call for C {
-    #[inline]
-    fn call() {
-        <B<A> as Call>::call()
-    }
-}
diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
index 4bda9ae383c22..db504b416fe1d 100644
--- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
@@ -40,7 +40,7 @@ fn foo(_1: T, _2: &i32) -> i32 {
         _9 = move (_5.1: &i32);          // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         StorageLive(_10);                // scope 2 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         _10 = _8;                        // scope 2 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
-        _0 = (*_10);                     // scope 3 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
+        _0 = (*_8);                      // scope 3 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         StorageDead(_10);                // scope 2 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         StorageDead(_9);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         StorageDead(_8);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
diff --git a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
deleted file mode 100644
index 9709f27377920..0000000000000
--- a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
+++ /dev/null
@@ -1,29 +0,0 @@
-- // MIR for `main` before Inline
-+ // MIR for `main` after Inline
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/inline-cycle-generic.rs:8:11: 8:11
-      let _1: ();                          // in scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24
-+     scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle-generic.rs:9:5: 9:24
-+         scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline-cycle-generic.rs:9:5: 9:24
-+         }
-+     }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24
--         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24
-+         _1 = <A as Call>::call() -> bb1; // scope 2 at $DIR/inline-cycle-generic.rs:9:5: 9:24
-                                           // mir::Constant
--                                          // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22
--                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) }
-+                                          // + span: $DIR/inline-cycle-generic.rs:9:5: 9:24
-+                                          // + literal: Const { ty: fn() {<A as Call>::call}, val: Value(Scalar(<ZST>)) }
-      }
-  
-      bb1: {
-          StorageDead(_1);                 // scope 0 at $DIR/inline-cycle-generic.rs:9:24: 9:25
-          _0 = const ();                   // scope 0 at $DIR/inline-cycle-generic.rs:8:11: 10:2
-          return;                          // scope 0 at $DIR/inline-cycle-generic.rs:10:2: 10:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/inst_combine_deref.rs b/src/test/mir-opt/inst_combine_deref.rs
new file mode 100644
index 0000000000000..78361c336607c
--- /dev/null
+++ b/src/test/mir-opt/inst_combine_deref.rs
@@ -0,0 +1,69 @@
+// compile-flags: -O -Zunsound-mir-opts
+// EMIT_MIR inst_combine_deref.simple_opt.InstCombine.diff
+fn simple_opt() -> u64 {
+    let x = 5;
+    let y = &x;
+    let z = *y;
+    z
+}
+
+// EMIT_MIR inst_combine_deref.deep_opt.InstCombine.diff
+fn deep_opt() -> (u64, u64, u64) {
+    let x1 = 1;
+    let x2 = 2;
+    let x3 = 3;
+    let y1 = &x1;
+    let y2 = &x2;
+    let y3 = &x3;
+    let z1 = *y1;
+    let z2 = *y2;
+    let z3 = *y3;
+    (z1, z2, z3)
+}
+
+struct S {
+    a: u64,
+    b: u64,
+}
+
+// EMIT_MIR inst_combine_deref.opt_struct.InstCombine.diff
+fn opt_struct(s: S) -> u64 {
+    let a = &s.a;
+    let b = &s.b;
+    let x = *a;
+    *b + x
+}
+
+// EMIT_MIR inst_combine_deref.dont_opt.InstCombine.diff
+// do not optimize a sequence looking like this:
+// _1 = &_2;
+// _1 = _3;
+// _4 = *_1;
+// as the _1 = _3 assignment makes it not legal to replace the last statement with _4 = _2
+fn dont_opt() -> u64 {
+    let y = 5;
+    let _ref = &y;
+    let x = 5;
+    let mut _1 = &x;
+    _1 = _ref;
+    let _4 = *_1;
+    0
+}
+
+// EMIT_MIR inst_combine_deref.do_not_miscompile.InstCombine.diff
+fn do_not_miscompile() {
+    let x = 42;
+    let a = 99;
+    let mut y = &x;
+    let z = &mut y;
+    *z = &a;
+    assert!(*y == 99);
+}
+
+fn main() {
+    simple_opt();
+    deep_opt();
+    opt_struct(S { a: 0, b: 1 });
+    dont_opt();
+    do_not_miscompile();
+}
diff --git a/src/test/rustdoc-ui/run-directory.correct.stdout b/src/test/rustdoc-ui/run-directory.correct.stdout
deleted file mode 100644
index e9b2754794a78..0000000000000
--- a/src/test/rustdoc-ui/run-directory.correct.stdout
+++ /dev/null
@@ -1,6 +0,0 @@
-
-running 1 test
-test $DIR/run-directory.rs - foo (line 10) ... ok
-
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
-
diff --git a/src/test/rustdoc-ui/run-directory.incorrect.stdout b/src/test/rustdoc-ui/run-directory.incorrect.stdout
deleted file mode 100644
index 97a5dbc5c0cd1..0000000000000
--- a/src/test/rustdoc-ui/run-directory.incorrect.stdout
+++ /dev/null
@@ -1,6 +0,0 @@
-
-running 1 test
-test $DIR/run-directory.rs - foo (line 19) ... ok
-
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
-
diff --git a/src/test/rustdoc-ui/run-directory.rs b/src/test/rustdoc-ui/run-directory.rs
deleted file mode 100644
index 78431c0e80b59..0000000000000
--- a/src/test/rustdoc-ui/run-directory.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// this test asserts that the cwd of doctest invocations is set correctly.
-
-// revisions: correct incorrect
-// check-pass
-// [correct]compile-flags:--test --test-run-directory={{src-base}}
-// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage
-// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
-// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
-
-/// ```
-/// assert_eq!(
-///     std::fs::read_to_string("run-directory.rs").unwrap(),
-///     include_str!("run-directory.rs"),
-/// );
-/// ```
-#[cfg(correct)]
-pub fn foo() {}
-
-/// ```
-/// assert!(std::fs::read_to_string("run-directory.rs").is_err());
-/// ```
-#[cfg(incorrect)]
-pub fn foo() {}
diff --git a/src/test/rustdoc/implementor-stable-version.rs b/src/test/rustdoc/implementor-stable-version.rs
deleted file mode 100644
index 0a065d8095bf2..0000000000000
--- a/src/test/rustdoc/implementor-stable-version.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-#![crate_name = "foo"]
-
-#![feature(staged_api)]
-
-#[stable(feature = "bar", since = "OLD 1.0")]
-pub trait Bar {}
-
-#[stable(feature = "baz", since = "OLD 1.0")]
-pub trait Baz {}
-
-pub struct Foo;
-
-// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' 'NEW 2.0'
-#[stable(feature = "foobar", since = "NEW 2.0")]
-impl Bar for Foo {}
-
-// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' 'OLD 1.0'
-#[stable(feature = "foobaz", since = "OLD 1.0")]
-impl Baz for Foo {}
diff --git a/src/test/rustdoc/reexport-check.rs b/src/test/rustdoc/reexport-check.rs
index 9a22903a94cc8..841702987ef7c 100644
--- a/src/test/rustdoc/reexport-check.rs
+++ b/src/test/rustdoc/reexport-check.rs
@@ -4,7 +4,7 @@
 extern crate reexport_check;
 
 // @!has 'foo/index.html' '//code' 'pub use self::i32;'
-// @has 'foo/index.html' '//tr[@class="deprecated module-item"]' 'i32'
+// @has 'foo/index.html' '//tr[@class="module-item"]' 'i32'
 // @has 'foo/i32/index.html'
 #[allow(deprecated, deprecated_in_future)]
 pub use std::i32;
diff --git a/src/test/rustdoc/visibility.rs b/src/test/rustdoc/visibility.rs
index beb638406c4be..59427693c5a5d 100644
--- a/src/test/rustdoc/visibility.rs
+++ b/src/test/rustdoc/visibility.rs
@@ -42,35 +42,3 @@ mod a {
         struct FooBPriv;
     }
 }
-
-// @has 'foo/trait.PubTrait.html' '//pre' 'pub trait PubTrait'
-//
-// @has 'foo/trait.PubTrait.html' '//pre' 'type Type;'
-// @!has 'foo/trait.PubTrait.html' '//pre' 'pub type Type;'
-//
-// @has 'foo/trait.PubTrait.html' '//pre' 'const CONST: usize;'
-// @!has 'foo/trait.PubTrait.html' '//pre' 'pub const CONST: usize;'
-//
-// @has 'foo/trait.PubTrait.html' '//pre' 'fn function();'
-// @!has 'foo/trait.PubTrait.html' '//pre' 'pub fn function();'
-
-pub trait PubTrait {
-    type Type;
-    const CONST: usize;
-    fn function();
-}
-
-// @has 'foo/struct.FooPublic.html' '//code' 'type Type'
-// @!has 'foo/struct.FooPublic.html' '//code' 'pub type Type'
-//
-// @has 'foo/struct.FooPublic.html' '//code' 'const CONST: usize'
-// @!has 'foo/struct.FooPublic.html' '//code' 'pub const CONST: usize'
-//
-// @has 'foo/struct.FooPublic.html' '//code' 'fn function()'
-// @!has 'foo/struct.FooPublic.html' '//code' 'pub fn function()'
-
-impl PubTrait for FooPublic {
-    type Type = usize;
-    const CONST: usize = 0;
-    fn function() {}
-}
diff --git a/src/test/ui-fulldeps/lint-tool-test.stderr b/src/test/ui-fulldeps/lint-tool-test.stderr
index 2260477a91d39..5e1cb4fb843fd 100644
--- a/src/test/ui-fulldeps/lint-tool-test.stderr
+++ b/src/test/ui-fulldeps/lint-tool-test.stderr
@@ -1,4 +1,4 @@
-warning: lint name `test_lint` is deprecated and may not have an effect in the future.
+warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
   --> $DIR/lint-tool-test.rs:9:23
    |
 LL | #![cfg_attr(foo, warn(test_lint))]
@@ -6,13 +6,13 @@ LL | #![cfg_attr(foo, warn(test_lint))]
    |
    = note: `#[warn(renamed_and_removed_lints)]` on by default
 
-warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
+warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
   --> $DIR/lint-tool-test.rs:13:9
    |
 LL | #![deny(clippy_group)]
    |         ^^^^^^^^^^^^ help: change it to: `clippy::group`
 
-warning: lint name `test_group` is deprecated and may not have an effect in the future.
+warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
   --> $DIR/lint-tool-test.rs:29:9
    |
 LL | #[allow(test_group)]
@@ -26,19 +26,19 @@ LL | #[deny(this_lint_does_not_exist)]
    |
    = note: `#[warn(unknown_lints)]` on by default
 
-warning: lint name `test_lint` is deprecated and may not have an effect in the future.
+warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
   --> $DIR/lint-tool-test.rs:9:23
    |
 LL | #![cfg_attr(foo, warn(test_lint))]
    |                       ^^^^^^^^^ help: change it to: `clippy::test_lint`
 
-warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
+warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
   --> $DIR/lint-tool-test.rs:13:9
    |
 LL | #![deny(clippy_group)]
    |         ^^^^^^^^^^^^ help: change it to: `clippy::group`
 
-warning: lint name `test_group` is deprecated and may not have an effect in the future.
+warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
   --> $DIR/lint-tool-test.rs:29:9
    |
 LL | #[allow(test_group)]
@@ -52,13 +52,13 @@ LL | #![plugin(lint_tool_test)]
    |
    = note: `#[warn(deprecated)]` on by default
 
-warning: lint name `test_lint` is deprecated and may not have an effect in the future.
+warning: lint name `test_lint` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
   --> $DIR/lint-tool-test.rs:9:23
    |
 LL | #![cfg_attr(foo, warn(test_lint))]
    |                       ^^^^^^^^^ help: change it to: `clippy::test_lint`
 
-warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
+warning: lint name `clippy_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
   --> $DIR/lint-tool-test.rs:13:9
    |
 LL | #![deny(clippy_group)]
@@ -90,7 +90,7 @@ LL | #![deny(clippy_group)]
    |         ^^^^^^^^^^^^
    = note: `#[deny(clippy::test_group)]` implied by `#[deny(clippy::group)]`
 
-warning: lint name `test_group` is deprecated and may not have an effect in the future.
+warning: lint name `test_group` is deprecated and may not have an effect in the future. Also `cfg_attr(cargo-clippy)` won't be necessary anymore
   --> $DIR/lint-tool-test.rs:29:9
    |
 LL | #[allow(test_group)]
diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout
index 02342af8dc53e..9c29a5f2337cd 100644
--- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout
+++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":null}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout
index 235f39c567b8e..cccd51985dc83 100644
--- a/src/test/ui/ast-json/ast-json-output.stdout
+++ b/src/test/ui/ast-json/ast-json-output.stdout
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":null}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
diff --git a/src/test/ui/attributes/key-value-non-ascii.rs b/src/test/ui/attributes/key-value-non-ascii.rs
deleted file mode 100644
index 91c917e7db56f..0000000000000
--- a/src/test/ui/attributes/key-value-non-ascii.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![feature(rustc_attrs)]
-
-#[rustc_dummy = b"ffi.rs"] //~ ERROR byte constant must be ASCII
-fn main() {}
diff --git a/src/test/ui/attributes/key-value-non-ascii.stderr b/src/test/ui/attributes/key-value-non-ascii.stderr
deleted file mode 100644
index 3e082139f895b..0000000000000
--- a/src/test/ui/attributes/key-value-non-ascii.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte
-  --> $DIR/key-value-non-ascii.rs:3:19
-   |
-LL | #[rustc_dummy = b"ffi.rs"]
-   |                   ^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/check-static-immutable-mut-slices.rs b/src/test/ui/check-static-immutable-mut-slices.rs
index 8f9680778aa03..3be02f6a0f674 100644
--- a/src/test/ui/check-static-immutable-mut-slices.rs
+++ b/src/test/ui/check-static-immutable-mut-slices.rs
@@ -1,6 +1,6 @@
 // Checks that immutable static items can't have mutable slices
 
 static TEST: &'static mut [isize] = &mut [];
-//~^ ERROR mutable references are not allowed
+//~^ ERROR mutable references are not allowed in statics
 
 pub fn main() { }
diff --git a/src/test/ui/check-static-immutable-mut-slices.stderr b/src/test/ui/check-static-immutable-mut-slices.stderr
index a32a94c1315ab..9ffbb483d139d 100644
--- a/src/test/ui/check-static-immutable-mut-slices.stderr
+++ b/src/test/ui/check-static-immutable-mut-slices.stderr
@@ -1,8 +1,8 @@
-error[E0764]: mutable references are not allowed in the final value of statics
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/check-static-immutable-mut-slices.rs:3:37
    |
 LL | static TEST: &'static mut [isize] = &mut [];
-   |                                     ^^^^^^^
+   |                                     ^^^^^^^ `&mut` is only allowed in `const fn`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/closures/local-type-mix.rs b/src/test/ui/closures/local-type-mix.rs
deleted file mode 100644
index 006e6f490f06b..0000000000000
--- a/src/test/ui/closures/local-type-mix.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Check that using the parameter name in its type does not ICE.
-// edition:2018
-
-#![feature(async_closure)]
-
-fn main() {
-    let _ = |x: x| x; //~ ERROR expected type
-    let _ = |x: bool| -> x { x }; //~ ERROR expected type
-    let _ = async move |x: x| x; //~ ERROR expected type
-    let _ = async move |x: bool| -> x { x }; //~ ERROR expected type
-}
-
-fn foo(x: x) {} //~ ERROR expected type
-fn foo_ret(x: bool) -> x {} //~ ERROR expected type
-
-async fn async_foo(x: x) {} //~ ERROR expected type
-async fn async_foo_ret(x: bool) -> x {} //~ ERROR expected type
diff --git a/src/test/ui/closures/local-type-mix.stderr b/src/test/ui/closures/local-type-mix.stderr
deleted file mode 100644
index 68c320a065d57..0000000000000
--- a/src/test/ui/closures/local-type-mix.stderr
+++ /dev/null
@@ -1,51 +0,0 @@
-error[E0573]: expected type, found local variable `x`
-  --> $DIR/local-type-mix.rs:7:17
-   |
-LL |     let _ = |x: x| x;
-   |                 ^ not a type
-
-error[E0573]: expected type, found local variable `x`
-  --> $DIR/local-type-mix.rs:8:26
-   |
-LL |     let _ = |x: bool| -> x { x };
-   |                          ^ not a type
-
-error[E0573]: expected type, found local variable `x`
-  --> $DIR/local-type-mix.rs:9:28
-   |
-LL |     let _ = async move |x: x| x;
-   |                            ^ not a type
-
-error[E0573]: expected type, found local variable `x`
-  --> $DIR/local-type-mix.rs:10:37
-   |
-LL |     let _ = async move |x: bool| -> x { x };
-   |                                     ^ not a type
-
-error[E0573]: expected type, found local variable `x`
-  --> $DIR/local-type-mix.rs:13:11
-   |
-LL | fn foo(x: x) {}
-   |           ^ not a type
-
-error[E0573]: expected type, found local variable `x`
-  --> $DIR/local-type-mix.rs:14:24
-   |
-LL | fn foo_ret(x: bool) -> x {}
-   |                        ^ not a type
-
-error[E0573]: expected type, found local variable `x`
-  --> $DIR/local-type-mix.rs:16:23
-   |
-LL | async fn async_foo(x: x) {}
-   |                       ^ not a type
-
-error[E0573]: expected type, found local variable `x`
-  --> $DIR/local-type-mix.rs:17:36
-   |
-LL | async fn async_foo_ret(x: bool) -> x {}
-   |                                    ^ not a type
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0573`.
diff --git a/src/test/ui/command/command-setgroups.rs b/src/test/ui/command/command-setgroups.rs
deleted file mode 100644
index 28f2bfdd3a776..0000000000000
--- a/src/test/ui/command/command-setgroups.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-// run-pass
-// ignore-windows - this is a unix-specific test
-// ignore-cloudabi
-// ignore-emscripten
-// ignore-sgx
-
-#![feature(rustc_private)]
-#![feature(setgroups)]
-
-extern crate libc;
-use std::process::Command;
-use std::os::unix::process::CommandExt;
-
-fn main() {
-    #[cfg(unix)]
-    run()
-}
-
-#[cfg(unix)]
-fn run() {
-    let max_ngroups = unsafe { libc::sysconf(libc::_SC_NGROUPS_MAX) };
-    let max_ngroups = max_ngroups as u32 + 1;
-    let vec: Vec<u32> = (0..max_ngroups).collect();
-    let p = Command::new("/bin/id").groups(&vec[..]).spawn();
-    assert!(p.is_err());
-}
diff --git a/src/test/ui/const_prop/inline_spans_lint_attribute.rs b/src/test/ui/const_prop/inline_spans_lint_attribute.rs
deleted file mode 100644
index 656ff02dc67ef..0000000000000
--- a/src/test/ui/const_prop/inline_spans_lint_attribute.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Must be build-pass, because check-pass will not run const prop and thus not emit the lint anyway.
-// build-pass
-// compile-flags: -Zmir-opt-level=2
-
-#![deny(warnings)]
-
-fn main() {
-    #[allow(arithmetic_overflow)]
-    let _ = add(u8::MAX, 1);
-}
-
-#[inline(always)]
-fn add(x: u8, y: u8) -> u8 {
-    x + y
-}
diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs
index 9b3f735b1f849..f36ebf38db4fe 100644
--- a/src/test/ui/consts/array-literal-index-oob.rs
+++ b/src/test/ui/consts/array-literal-index-oob.rs
@@ -6,4 +6,6 @@
 fn main() {
     &{ [1, 2, 3][4] };
     //~^ WARN operation will panic
+    //~| WARN reaching this expression at runtime will panic or abort
+    //~| WARN erroneous constant used [const_err]
 }
diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr
index f96b8d48b3e7c..5916ea6d323e6 100644
--- a/src/test/ui/consts/array-literal-index-oob.stderr
+++ b/src/test/ui/consts/array-literal-index-oob.stderr
@@ -10,5 +10,25 @@ note: the lint level is defined here
 LL | #![warn(const_err, unconditional_panic)]
    |                    ^^^^^^^^^^^^^^^^^^^
 
-warning: 1 warning emitted
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/array-literal-index-oob.rs:7:8
+   |
+LL |     &{ [1, 2, 3][4] };
+   |     ---^^^^^^^^^^^^--
+   |        |
+   |        indexing out of bounds: the len is 3 but the index is 4
+   |
+note: the lint level is defined here
+  --> $DIR/array-literal-index-oob.rs:4:9
+   |
+LL | #![warn(const_err, unconditional_panic)]
+   |         ^^^^^^^^^
+
+warning: erroneous constant used
+  --> $DIR/array-literal-index-oob.rs:7:5
+   |
+LL |     &{ [1, 2, 3][4] };
+   |     ^^^^^^^^^^^^^^^^^ referenced constant has errors
+
+warning: 3 warnings emitted
 
diff --git a/src/test/ui/consts/const-address-of-mut.stderr b/src/test/ui/consts/const-address-of-mut.stderr
index 60cdcc7df7449..ec2dac5a7d16f 100644
--- a/src/test/ui/consts/const-address-of-mut.stderr
+++ b/src/test/ui/consts/const-address-of-mut.stderr
@@ -1,29 +1,20 @@
-error[E0658]: raw mutable references are not allowed in constants
+error[E0764]: raw mutable references are not allowed in constants
   --> $DIR/const-address-of-mut.rs:3:32
    |
 LL | const A: () = { let mut x = 2; &raw mut x; };
-   |                                ^^^^^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                ^^^^^^^^^^ `&raw mut` is only allowed in `const fn`
 
-error[E0658]: raw mutable references are not allowed in statics
+error[E0764]: raw mutable references are not allowed in statics
   --> $DIR/const-address-of-mut.rs:5:33
    |
 LL | static B: () = { let mut x = 2; &raw mut x; };
-   |                                 ^^^^^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                 ^^^^^^^^^^ `&raw mut` is only allowed in `const fn`
 
-error[E0658]: raw mutable references are not allowed in statics
+error[E0764]: raw mutable references are not allowed in statics
   --> $DIR/const-address-of-mut.rs:7:37
    |
 LL | static mut C: () = { let mut x = 2; &raw mut x; };
-   |                                     ^^^^^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                     ^^^^^^^^^^ `&raw mut` is only allowed in `const fn`
 
 error[E0658]: raw mutable references are not allowed in constant functions
   --> $DIR/const-address-of-mut.rs:11:13
@@ -36,4 +27,5 @@ LL |     let y = &raw mut x;
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0658, E0764.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.rs b/src/test/ui/consts/const-eval/const-eval-query-stack.rs
index 39803c8f257e0..8a6f7de1c9fbd 100644
--- a/src/test/ui/consts/const-eval/const-eval-query-stack.rs
+++ b/src/test/ui/consts/const-eval/const-eval-query-stack.rs
@@ -1,5 +1,4 @@
-//~ERROR constructed but no error reported
-// compile-flags: -Ztreat-err-as-bug=2
+// compile-flags: -Ztreat-err-as-bug
 // build-fail
 // failure-status: 101
 // rustc-env:RUST_BACKTRACE=1
@@ -16,11 +15,8 @@
 
 #![allow(unconditional_panic)]
 
-#[warn(const_err)]
-const X: i32 = 1 / 0; //~WARN any use of this value will cause an error
-
 fn main() {
-    let x: &'static i32 = &X;
-    //~^ ERROR evaluation of constant expression failed
+    let x: &'static i32 = &(1 / 0);
+    //~^ ERROR reaching this expression at runtime will panic or abort [const_err]
     println!("x={}", x);
 }
diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
index 0016d301e598c..8c57fd37e88f6 100644
--- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
+++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr
@@ -1,26 +1,18 @@
-warning: any use of this value will cause an error
-  --> $DIR/const-eval-query-stack.rs:20:16
+error: reaching this expression at runtime will panic or abort
+  --> $DIR/const-eval-query-stack.rs:19:28
    |
-LL | const X: i32 = 1 / 0;
-   | ---------------^^^^^-
-   |                |
-   |                attempt to divide `1_i32` by zero
-   |
-note: the lint level is defined here
-  --> $DIR/const-eval-query-stack.rs:19:8
+LL |     let x: &'static i32 = &(1 / 0);
+   |                           -^^^^^^^
+   |                            |
+   |                            dividing by zero
    |
-LL | #[warn(const_err)]
-   |        ^^^^^^^^^
+   = note: `#[deny(const_err)]` on by default
 
-error[E0080]: evaluation of constant expression failed
-  --> $DIR/const-eval-query-stack.rs:23:27
-   |
-LL |     let x: &'static i32 = &X;
-   |                           ^-
-   |                            |
-   |                            referenced constant has errors
 query stack during panic:
-#0 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]`
-#1 [optimized_mir] optimizing MIR for `main`
-#2 [collect_and_partition_mono_items] collect_and_partition_mono_items
+#0 [eval_to_allocation_raw] const-evaluating + checking `main::promoted[1]`
+#1 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]`
+#2 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]`
+#3 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]`
+#4 [optimized_mir] optimizing MIR for `main`
+#5 [collect_and_partition_mono_items] collect_and_partition_mono_items
 end of query stack
diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr
index ec229d7f53a0f..771d368d78391 100644
--- a/src/test/ui/consts/const-eval/issue-65394.stderr
+++ b/src/test/ui/consts/const-eval/issue-65394.stderr
@@ -1,11 +1,8 @@
-error[E0658]: mutable references are not allowed in constants
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/issue-65394.rs:8:13
    |
 LL |     let r = &mut x;
-   |             ^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |             ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/issue-65394.rs:7:9
@@ -18,5 +15,5 @@ LL | };
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0493, E0658.
+Some errors have detailed explanations: E0493, E0764.
 For more information about an error, try `rustc --explain E0493`.
diff --git a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr
index 1cd1be5309b90..ce83d8e9bb0c9 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr
@@ -1,21 +1,38 @@
-warning: any use of this value will cause an error
-  --> $DIR/promoted_errors.rs:13:5
-   |
-LL |       0 - 1
-   |       ^^^^^
-   |       |
-   |       attempt to compute `0_u32 - 1_u32`, which would overflow
-   |       inside `overflow` at $DIR/promoted_errors.rs:13:5
-   |       inside `X` at $DIR/promoted_errors.rs:31:29
-...
-LL | / const X: () = {
-LL | |     let _x: &'static u32 = &overflow();
-LL | |
-LL | |     let _x: &'static i32 = &div_by_zero1();
-...  |
-LL | |     let _x: &'static i32 = &oob();
-LL | | };
-   | |__-
+warning: this arithmetic operation will overflow
+  --> $DIR/promoted_errors.rs:12:20
+   |
+LL |     println!("{}", 0u32 - 1);
+   |                    ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:9:20
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |                    ^^^^^^^^^^^^^^^^^^^
+
+warning: this arithmetic operation will overflow
+  --> $DIR/promoted_errors.rs:14:14
+   |
+LL |     let _x = 0u32 - 1;
+   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:16:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ attempt to divide `1_i32` by zero
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:9:41
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |                                         ^^^^^^^^^^^^^^^^^^^
+
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/promoted_errors.rs:16:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ dividing by zero
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:9
@@ -23,18 +40,41 @@ note: the lint level is defined here
 LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
    |         ^^^^^^^^^
 
-warning: any use of this value will cause an error
-  --> $DIR/promoted_errors.rs:31:28
+warning: erroneous constant used
+  --> $DIR/promoted_errors.rs:16:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ referenced constant has errors
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:20:14
+   |
+LL |     let _x = 1 / (1 - 1);
+   |              ^^^^^^^^^^^ attempt to divide `1_i32` by zero
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:22:20
+   |
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
+
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/promoted_errors.rs:22:20
+   |
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ dividing by zero
+
+warning: erroneous constant used
+  --> $DIR/promoted_errors.rs:22:20
+   |
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:26:14
    |
-LL | / const X: () = {
-LL | |     let _x: &'static u32 = &overflow();
-   | |                            ^^^^^^^^^^^ referenced constant has errors
-LL | |
-LL | |     let _x: &'static i32 = &div_by_zero1();
-...  |
-LL | |     let _x: &'static i32 = &oob();
-LL | | };
-   | |__-
+LL |     let _x = 1 / (false as u32);
+   |              ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
 
-warning: 2 warnings emitted
+warning: 10 warnings emitted
 
diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr
index ca62e21b61385..2c66b175cfc2b 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr
@@ -1,21 +1,32 @@
-warning: any use of this value will cause an error
-  --> $DIR/promoted_errors.rs:17:5
-   |
-LL |       1 / 0
-   |       ^^^^^
-   |       |
-   |       attempt to divide `1_i32` by zero
-   |       inside `div_by_zero1` at $DIR/promoted_errors.rs:17:5
-   |       inside `X` at $DIR/promoted_errors.rs:33:29
-...
-LL | / const X: () = {
-LL | |     let _x: &'static u32 = &overflow();
-LL | |
-LL | |     let _x: &'static i32 = &div_by_zero1();
-...  |
-LL | |     let _x: &'static i32 = &oob();
-LL | | };
-   | |__-
+warning: this arithmetic operation will overflow
+  --> $DIR/promoted_errors.rs:14:14
+   |
+LL |     let _x = 0u32 - 1;
+   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:9:20
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |                    ^^^^^^^^^^^^^^^^^^^
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:16:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ attempt to divide `1_i32` by zero
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:9:41
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |                                         ^^^^^^^^^^^^^^^^^^^
+
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/promoted_errors.rs:16:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ dividing by zero
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:9
@@ -23,18 +34,41 @@ note: the lint level is defined here
 LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
    |         ^^^^^^^^^
 
-warning: any use of this value will cause an error
-  --> $DIR/promoted_errors.rs:33:28
+warning: erroneous constant used
+  --> $DIR/promoted_errors.rs:16:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ referenced constant has errors
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:20:14
+   |
+LL |     let _x = 1 / (1 - 1);
+   |              ^^^^^^^^^^^ attempt to divide `1_i32` by zero
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:22:20
+   |
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
+
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/promoted_errors.rs:22:20
+   |
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ dividing by zero
+
+warning: erroneous constant used
+  --> $DIR/promoted_errors.rs:22:20
+   |
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:26:14
    |
-LL | / const X: () = {
-LL | |     let _x: &'static u32 = &overflow();
-LL | |
-LL | |     let _x: &'static i32 = &div_by_zero1();
-   | |                            ^^^^^^^^^^^^^^^ referenced constant has errors
-...  |
-LL | |     let _x: &'static i32 = &oob();
-LL | | };
-   | |__-
+LL |     let _x = 1 / (false as u32);
+   |              ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
 
-warning: 2 warnings emitted
+warning: 9 warnings emitted
 
diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr
index 1cd1be5309b90..ce83d8e9bb0c9 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr
@@ -1,21 +1,38 @@
-warning: any use of this value will cause an error
-  --> $DIR/promoted_errors.rs:13:5
-   |
-LL |       0 - 1
-   |       ^^^^^
-   |       |
-   |       attempt to compute `0_u32 - 1_u32`, which would overflow
-   |       inside `overflow` at $DIR/promoted_errors.rs:13:5
-   |       inside `X` at $DIR/promoted_errors.rs:31:29
-...
-LL | / const X: () = {
-LL | |     let _x: &'static u32 = &overflow();
-LL | |
-LL | |     let _x: &'static i32 = &div_by_zero1();
-...  |
-LL | |     let _x: &'static i32 = &oob();
-LL | | };
-   | |__-
+warning: this arithmetic operation will overflow
+  --> $DIR/promoted_errors.rs:12:20
+   |
+LL |     println!("{}", 0u32 - 1);
+   |                    ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:9:20
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |                    ^^^^^^^^^^^^^^^^^^^
+
+warning: this arithmetic operation will overflow
+  --> $DIR/promoted_errors.rs:14:14
+   |
+LL |     let _x = 0u32 - 1;
+   |              ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:16:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ attempt to divide `1_i32` by zero
+   |
+note: the lint level is defined here
+  --> $DIR/promoted_errors.rs:9:41
+   |
+LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
+   |                                         ^^^^^^^^^^^^^^^^^^^
+
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/promoted_errors.rs:16:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ dividing by zero
    |
 note: the lint level is defined here
   --> $DIR/promoted_errors.rs:9:9
@@ -23,18 +40,41 @@ note: the lint level is defined here
 LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)]
    |         ^^^^^^^^^
 
-warning: any use of this value will cause an error
-  --> $DIR/promoted_errors.rs:31:28
+warning: erroneous constant used
+  --> $DIR/promoted_errors.rs:16:20
+   |
+LL |     println!("{}", 1 / (1 - 1));
+   |                    ^^^^^^^^^^^ referenced constant has errors
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:20:14
+   |
+LL |     let _x = 1 / (1 - 1);
+   |              ^^^^^^^^^^^ attempt to divide `1_i32` by zero
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:22:20
+   |
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
+
+warning: reaching this expression at runtime will panic or abort
+  --> $DIR/promoted_errors.rs:22:20
+   |
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ dividing by zero
+
+warning: erroneous constant used
+  --> $DIR/promoted_errors.rs:22:20
+   |
+LL |     println!("{}", 1 / (false as u32));
+   |                    ^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
+warning: this operation will panic at runtime
+  --> $DIR/promoted_errors.rs:26:14
    |
-LL | / const X: () = {
-LL | |     let _x: &'static u32 = &overflow();
-   | |                            ^^^^^^^^^^^ referenced constant has errors
-LL | |
-LL | |     let _x: &'static i32 = &div_by_zero1();
-...  |
-LL | |     let _x: &'static i32 = &oob();
-LL | | };
-   | |__-
+LL |     let _x = 1 / (false as u32);
+   |              ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero
 
-warning: 2 warnings emitted
+warning: 10 warnings emitted
 
diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs
index a2136c8d09be4..142ce75eebc80 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors.rs
@@ -8,34 +8,21 @@
 
 #![warn(const_err, arithmetic_overflow, unconditional_panic)]
 
-// The only way to have promoteds that fail is in `const fn` called from `const`/`static`.
-const fn overflow() -> u32 {
-    0 - 1
-    //[opt_with_overflow_checks,noopt]~^ WARN any use of this value will cause an error
-}
-const fn div_by_zero1() -> i32 {
-    1 / 0
-    //[opt]~^ WARN any use of this value will cause an error
-}
-const fn div_by_zero2() -> i32 {
-    1 / (1-1)
-}
-const fn div_by_zero3() -> i32 {
-    1 / (false as i32)
-}
-const fn oob() -> i32 {
-    [1,2,3][4]
-}
-
-const X: () = {
-    let _x: &'static u32 = &overflow();
-    //[opt_with_overflow_checks,noopt]~^ WARN any use of this value will cause an error
-    let _x: &'static i32 = &div_by_zero1();
-    //[opt]~^ WARN any use of this value will cause an error
-    let _x: &'static i32 = &div_by_zero2();
-    let _x: &'static i32 = &div_by_zero3();
-    let _x: &'static i32 = &oob();
-};
-
 fn main() {
+    println!("{}", 0u32 - 1);
+    //[opt_with_overflow_checks,noopt]~^ WARN [arithmetic_overflow]
+    let _x = 0u32 - 1;
+    //~^ WARN [arithmetic_overflow]
+    println!("{}", 1 / (1 - 1));
+    //~^ WARN [unconditional_panic]
+    //~| WARN panic or abort [const_err]
+    //~| WARN erroneous constant used [const_err]
+    let _x = 1 / (1 - 1);
+    //~^ WARN [unconditional_panic]
+    println!("{}", 1 / (false as u32));
+    //~^ WARN [unconditional_panic]
+    //~| WARN panic or abort [const_err]
+    //~| WARN erroneous constant used [const_err]
+    let _x = 1 / (false as u32);
+    //~^ WARN [unconditional_panic]
 }
diff --git a/src/test/ui/consts/const-multi-ref.stderr b/src/test/ui/consts/const-multi-ref.stderr
index dd5cadfe2951e..c0a320d46cbf9 100644
--- a/src/test/ui/consts/const-multi-ref.stderr
+++ b/src/test/ui/consts/const-multi-ref.stderr
@@ -1,11 +1,8 @@
-error[E0658]: mutable references are not allowed in constants
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/const-multi-ref.rs:6:13
    |
 LL |     let p = &mut a;
-   |             ^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |             ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
   --> $DIR/const-multi-ref.rs:16:13
@@ -18,4 +15,5 @@ LL |     let p = &a;
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0658, E0764.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
index 24df647f05b7e..5819daa817af0 100644
--- a/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
+++ b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
@@ -1,4 +1,3 @@
-// check-pass
 #![feature(const_mut_refs)]
 #![feature(const_fn)]
 #![feature(raw_ref_op)]
@@ -23,7 +22,9 @@ const fn baz(foo: &mut Foo)-> *mut usize {
 
 const _: () = {
     foo().bar();
+    //~^ ERROR mutable references are not allowed in constants
     baz(&mut foo());
+    //~^ ERROR mutable references are not allowed in constants
 };
 
 fn main() {}
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr b/src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr
new file mode 100644
index 0000000000000..2214ce6ee1c87
--- /dev/null
+++ b/src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr
@@ -0,0 +1,15 @@
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/const_mut_address_of.rs:24:5
+   |
+LL |     foo().bar();
+   |     ^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/const_mut_address_of.rs:26:9
+   |
+LL |     baz(&mut foo());
+   |         ^^^^^^^^^^ `&mut` is only allowed in `const fn`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0764`.
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
index 544458dfcd8bb..9099d5a1b8ea6 100644
--- a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
+++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs
@@ -1,4 +1,3 @@
-// check-pass
 #![feature(const_mut_refs)]
 
 struct Foo {
@@ -30,6 +29,9 @@ const fn bazz(foo: &mut Foo) -> usize {
 
 fn main() {
     let _: [(); foo().bar()] = [(); 1];
+    //~^ ERROR mutable references are not allowed in constants
     let _: [(); baz(&mut foo())] = [(); 2];
+    //~^ ERROR mutable references are not allowed in constants
     let _: [(); bazz(&mut foo())] = [(); 3];
+    //~^ ERROR mutable references are not allowed in constants
 }
diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.stderr b/src/test/ui/consts/const-mut-refs/const_mut_refs.stderr
new file mode 100644
index 0000000000000..4ca7b128b7c4b
--- /dev/null
+++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.stderr
@@ -0,0 +1,21 @@
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/const_mut_refs.rs:31:17
+   |
+LL |     let _: [(); foo().bar()] = [(); 1];
+   |                 ^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/const_mut_refs.rs:33:21
+   |
+LL |     let _: [(); baz(&mut foo())] = [(); 2];
+   |                     ^^^^^^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/const_mut_refs.rs:35:22
+   |
+LL |     let _: [(); bazz(&mut foo())] = [(); 3];
+   |                      ^^^^^^^^^^ `&mut` is only allowed in `const fn`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0764`.
diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs
deleted file mode 100644
index 166ba20f124e6..0000000000000
--- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-#![feature(const_mut_refs)]
-#![feature(const_fn)]
-#![feature(raw_ref_op)]
-#![feature(const_raw_ptr_deref)]
-
-const NULL: *mut i32 = std::ptr::null_mut();
-const A: *const i32 = &4;
-
-// It could be made sound to allow it to compile,
-// but we do not want to allow this to compile,
-// as that would be an enormous footgun in oli-obk's opinion.
-const B: *mut i32 = &mut 4; //~ ERROR mutable references are not allowed
-
-// Ok, no actual mutable allocation exists
-const B2: Option<&mut i32> = None;
-
-// Not ok, can't prove that no mutable allocation ends up in final value
-const B3: Option<&mut i32> = Some(&mut 42); //~ ERROR temporary value dropped while borrowed
-
-const fn helper(x: &mut i32) -> Option<&mut i32> { Some(x) }
-const B4: Option<&mut i32> = helper(&mut 42); //~ ERROR temporary value dropped while borrowed
-
-// Ok, because no references to mutable data exist here, since the `{}` moves
-// its value and then takes a reference to that.
-const C: *const i32 = &{
-    let mut x = 42;
-    x += 3;
-    x
-};
-
-use std::cell::UnsafeCell;
-struct NotAMutex<T>(UnsafeCell<T>);
-
-unsafe impl<T> Sync for NotAMutex<T> {}
-
-const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
-//~^ ERROR temporary value dropped while borrowed
-
-static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
-//~^ ERROR temporary value dropped while borrowed
-
-static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
-//~^ ERROR temporary value dropped while borrowed
-
-// `BAR` works, because `&42` promotes immediately instead of relying on
-// the enclosing scope rule.
-const BAR: NotAMutex<&i32> = NotAMutex(UnsafeCell::new(&42));
-
-fn main() {
-    println!("{}", unsafe { *A });
-    unsafe { *B = 4 } // Bad news
-
-    unsafe {
-        **FOO.0.get() = 99;
-        assert_eq!(**FOO.0.get(), 99);
-    }
-}
diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr
deleted file mode 100644
index cbae74cce6f6b..0000000000000
--- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr
+++ /dev/null
@@ -1,60 +0,0 @@
-error[E0764]: mutable references are not allowed in the final value of constants
-  --> $DIR/mut_ref_in_final.rs:12:21
-   |
-LL | const B: *mut i32 = &mut 4;
-   |                     ^^^^^^
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:18:40
-   |
-LL | const B3: Option<&mut i32> = Some(&mut 42);
-   |                              ----------^^-
-   |                              |         | |
-   |                              |         | temporary value is freed at the end of this statement
-   |                              |         creates a temporary which is freed while still in use
-   |                              using this value as a constant requires that borrow lasts for `'static`
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:21:42
-   |
-LL | const B4: Option<&mut i32> = helper(&mut 42);
-   |                              ------------^^-
-   |                              |           | |
-   |                              |           | temporary value is freed at the end of this statement
-   |                              |           creates a temporary which is freed while still in use
-   |                              using this value as a constant requires that borrow lasts for `'static`
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:36:65
-   |
-LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
-   |                                  -------------------------------^^--
-   |                                  |                              |  |
-   |                                  |                              |  temporary value is freed at the end of this statement
-   |                                  |                              creates a temporary which is freed while still in use
-   |                                  using this value as a constant requires that borrow lasts for `'static`
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:39:67
-   |
-LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
-   |                                    -------------------------------^^--
-   |                                    |                              |  |
-   |                                    |                              |  temporary value is freed at the end of this statement
-   |                                    |                              creates a temporary which is freed while still in use
-   |                                    using this value as a static requires that borrow lasts for `'static`
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:42:71
-   |
-LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
-   |                                        -------------------------------^^--
-   |                                        |                              |  |
-   |                                        |                              |  temporary value is freed at the end of this statement
-   |                                        |                              creates a temporary which is freed while still in use
-   |                                        using this value as a static requires that borrow lasts for `'static`
-
-error: aborting due to 6 previous errors
-
-Some errors have detailed explanations: E0716, E0764.
-For more information about an error, try `rustc --explain E0716`.
diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs
deleted file mode 100644
index 1e856ec0a0acc..0000000000000
--- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-#![feature(const_mut_refs)]
-#![feature(const_fn)]
-#![feature(raw_ref_op)]
-#![feature(const_raw_ptr_deref)]
-
-// This file checks that our dynamic checks catch things that the static checks miss.
-// We do not have static checks for these, because we do not look into function bodies.
-// We treat all functions as not returning a mutable reference, because there is no way to
-// do that without causing the borrow checker to complain (see the B4/helper test in
-// mut_ref_in_final.rs).
-
-const fn helper() -> Option<&'static mut i32> { unsafe {
-    // Undefined behaviour (integer as pointer), who doesn't love tests like this.
-    // This code never gets executed, because the static checks fail before that.
-    Some(&mut *(42 as *mut i32)) //~ ERROR any use of this value will cause an error
-} }
-// The error is an evaluation error and not a validation error, so the error is reported
-// directly at the site where it occurs.
-const A: Option<&mut i32> = helper();
-
-const fn helper2() -> Option<&'static mut i32> { unsafe {
-    // Undefined behaviour (dangling pointer), who doesn't love tests like this.
-    // This code never gets executed, because the static checks fail before that.
-    Some(&mut *(&mut 42 as *mut i32))
-} }
-const B: Option<&mut i32> = helper2(); //~ ERROR encountered dangling pointer in final constant
-
-fn main() {}
diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
deleted file mode 100644
index 0bbf84b71bb68..0000000000000
--- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error: any use of this value will cause an error
-  --> $DIR/mut_ref_in_final_dynamic_check.rs:15:10
-   |
-LL |     Some(&mut *(42 as *mut i32))
-   |          ^^^^^^^^^^^^^^^^^^^^^^
-   |          |
-   |          unable to turn bytes into a pointer
-   |          inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:15:10
-   |          inside `A` at $DIR/mut_ref_in_final_dynamic_check.rs:19:29
-...
-LL | const A: Option<&mut i32> = helper();
-   | -------------------------------------
-   |
-   = note: `#[deny(const_err)]` on by default
-
-error: encountered dangling pointer in final constant
-  --> $DIR/mut_ref_in_final_dynamic_check.rs:26:1
-   |
-LL | const B: Option<&mut i32> = helper2();
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr
index 3eac61c0ce670..dc86e178a42c3 100644
--- a/src/test/ui/consts/const_let_assign3.stderr
+++ b/src/test/ui/consts/const_let_assign3.stderr
@@ -7,24 +7,19 @@ LL |     const fn foo(&mut self, x: u32) {
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: mutable references are not allowed in constants
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/const_let_assign3.rs:16:5
    |
 LL |     s.foo(3);
-   |     ^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |     ^ `&mut` is only allowed in `const fn`
 
-error[E0658]: mutable references are not allowed in constants
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/const_let_assign3.rs:22:13
    |
 LL |     let y = &mut x;
-   |             ^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |             ^^^^^^ `&mut` is only allowed in `const fn`
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0658, E0764.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/issue-17718-const-bad-values.rs b/src/test/ui/consts/issue-17718-const-bad-values.rs
index 62bbb3b569c37..49023f18ddbfb 100644
--- a/src/test/ui/consts/issue-17718-const-bad-values.rs
+++ b/src/test/ui/consts/issue-17718-const-bad-values.rs
@@ -1,9 +1,10 @@
 const C1: &'static mut [usize] = &mut [];
-//~^ ERROR: mutable references are not allowed
+//~^ ERROR: mutable references are not allowed in constants
 
 static mut S: usize = 3;
 const C2: &'static mut usize = unsafe { &mut S };
 //~^ ERROR: constants cannot refer to statics
 //~| ERROR: constants cannot refer to statics
+//~| ERROR: mutable references are not allowed in constants
 
 fn main() {}
diff --git a/src/test/ui/consts/issue-17718-const-bad-values.stderr b/src/test/ui/consts/issue-17718-const-bad-values.stderr
index ce60aaa0797f8..7c50978d4ebb8 100644
--- a/src/test/ui/consts/issue-17718-const-bad-values.stderr
+++ b/src/test/ui/consts/issue-17718-const-bad-values.stderr
@@ -1,8 +1,8 @@
-error[E0764]: mutable references are not allowed in the final value of constants
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/issue-17718-const-bad-values.rs:1:34
    |
 LL | const C1: &'static mut [usize] = &mut [];
-   |                                  ^^^^^^^
+   |                                  ^^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0013]: constants cannot refer to statics
   --> $DIR/issue-17718-const-bad-values.rs:5:46
@@ -20,7 +20,13 @@ LL | const C2: &'static mut usize = unsafe { &mut S };
    |
    = help: consider extracting the value of the `static` to a `const`, and referring to that
 
-error: aborting due to 3 previous errors
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/issue-17718-const-bad-values.rs:5:41
+   |
+LL | const C2: &'static mut usize = unsafe { &mut S };
+   |                                         ^^^^^^ `&mut` is only allowed in `const fn`
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0013, E0764.
 For more information about an error, try `rustc --explain E0013`.
diff --git a/src/test/ui/consts/projection_qualif.mut_refs.stderr b/src/test/ui/consts/projection_qualif.mut_refs.stderr
new file mode 100644
index 0000000000000..fad8f011f75f5
--- /dev/null
+++ b/src/test/ui/consts/projection_qualif.mut_refs.stderr
@@ -0,0 +1,19 @@
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/projection_qualif.rs:10:27
+   |
+LL |         let b: *mut u32 = &mut a;
+   |                           ^^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0658]: dereferencing raw pointers in constants is unstable
+  --> $DIR/projection_qualif.rs:11:18
+   |
+LL |         unsafe { *b = 5; }
+   |                  ^^^^^^
+   |
+   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
+   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0658, E0764.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/write_to_mut_ref_dest.rs b/src/test/ui/consts/projection_qualif.rs
similarity index 72%
rename from src/test/ui/consts/write_to_mut_ref_dest.rs
rename to src/test/ui/consts/projection_qualif.rs
index d35df330bb8c3..5e2584a6e951a 100644
--- a/src/test/ui/consts/write_to_mut_ref_dest.rs
+++ b/src/test/ui/consts/projection_qualif.rs
@@ -7,7 +7,7 @@ use std::cell::Cell;
 const FOO: &u32 = {
     let mut a = 42;
     {
-        let b: *mut u32 = &mut a; //[stock]~ ERROR mutable references are not allowed in constants
+        let b: *mut u32 = &mut a; //~ ERROR mutable references are not allowed in constants
         unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
     }
     &{a}
diff --git a/src/test/ui/consts/projection_qualif.stock.stderr b/src/test/ui/consts/projection_qualif.stock.stderr
new file mode 100644
index 0000000000000..fad8f011f75f5
--- /dev/null
+++ b/src/test/ui/consts/projection_qualif.stock.stderr
@@ -0,0 +1,19 @@
+error[E0764]: mutable references are not allowed in constants
+  --> $DIR/projection_qualif.rs:10:27
+   |
+LL |         let b: *mut u32 = &mut a;
+   |                           ^^^^^^ `&mut` is only allowed in `const fn`
+
+error[E0658]: dereferencing raw pointers in constants is unstable
+  --> $DIR/projection_qualif.rs:11:18
+   |
+LL |         unsafe { *b = 5; }
+   |                  ^^^^^^
+   |
+   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
+   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0658, E0764.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs
index 0d0c78b0fc260..1e4d8586b872c 100644
--- a/src/test/ui/consts/promote-not.rs
+++ b/src/test/ui/consts/promote-not.rs
@@ -44,11 +44,4 @@ fn main() {
     // We must not promote things with interior mutability. Not even if we "project it away".
     let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed
     let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed
-
-    // No promotion of fallible operations.
-    let _val: &'static _ = &(1/0); //~ ERROR temporary value dropped while borrowed
-    let _val: &'static _ = &(1/(1-1)); //~ ERROR temporary value dropped while borrowed
-    let _val: &'static _ = &(1%0); //~ ERROR temporary value dropped while borrowed
-    let _val: &'static _ = &(1%(1-1)); //~ ERROR temporary value dropped while borrowed
-    let _val: &'static _ = &([1,2,3][4]+1); //~ ERROR temporary value dropped while borrowed
 }
diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr
index 108d0da7a674a..6e76d9ee6c165 100644
--- a/src/test/ui/consts/promote-not.stderr
+++ b/src/test/ui/consts/promote-not.stderr
@@ -65,7 +65,7 @@ LL |     let _val: &'static _ = &(Cell::new(1), 2).0;
    |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
-...
+LL |     let _val: &'static _ = &(Cell::new(1), 2).1;
 LL | }
    | - temporary value is freed at the end of this statement
 
@@ -76,64 +76,9 @@ LL |     let _val: &'static _ = &(Cell::new(1), 2).1;
    |               ----------    ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
    |               |
    |               type annotation requires that borrow lasts for `'static`
-...
-LL | }
-   | - temporary value is freed at the end of this statement
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:49:29
-   |
-LL |     let _val: &'static _ = &(1/0);
-   |               ----------    ^^^^^ creates a temporary which is freed while still in use
-   |               |
-   |               type annotation requires that borrow lasts for `'static`
-...
-LL | }
-   | - temporary value is freed at the end of this statement
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:50:29
-   |
-LL |     let _val: &'static _ = &(1/(1-1));
-   |               ----------    ^^^^^^^^^ creates a temporary which is freed while still in use
-   |               |
-   |               type annotation requires that borrow lasts for `'static`
-...
-LL | }
-   | - temporary value is freed at the end of this statement
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:51:29
-   |
-LL |     let _val: &'static _ = &(1%0);
-   |               ----------    ^^^^^ creates a temporary which is freed while still in use
-   |               |
-   |               type annotation requires that borrow lasts for `'static`
-...
-LL | }
-   | - temporary value is freed at the end of this statement
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:52:29
-   |
-LL |     let _val: &'static _ = &(1%(1-1));
-   |               ----------    ^^^^^^^^^ creates a temporary which is freed while still in use
-   |               |
-   |               type annotation requires that borrow lasts for `'static`
-LL |     let _val: &'static _ = &([1,2,3][4]+1);
-LL | }
-   | - temporary value is freed at the end of this statement
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promote-not.rs:53:29
-   |
-LL |     let _val: &'static _ = &([1,2,3][4]+1);
-   |               ----------    ^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
-   |               |
-   |               type annotation requires that borrow lasts for `'static`
 LL | }
    | - temporary value is freed at the end of this statement
 
-error: aborting due to 13 previous errors
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0716`.
diff --git a/src/test/ui/consts/promoted_div_by_zero.rs b/src/test/ui/consts/promoted_div_by_zero.rs
new file mode 100644
index 0000000000000..b4503f691ffd9
--- /dev/null
+++ b/src/test/ui/consts/promoted_div_by_zero.rs
@@ -0,0 +1,9 @@
+#![allow(unconditional_panic, const_err)]
+
+// run-fail
+// error-pattern: attempt to divide by zero
+// ignore-emscripten no processes
+
+fn main() {
+    let x = &(1 / (1 - 1));
+}
diff --git a/src/test/ui/consts/promotion.rs b/src/test/ui/consts/promotion.rs
index 580c6d62f10af..b6e7127a9b779 100644
--- a/src/test/ui/consts/promotion.rs
+++ b/src/test/ui/consts/promotion.rs
@@ -1,43 +1,28 @@
-// revisions: noopt opt opt_with_overflow_checks
-//[noopt]compile-flags: -C opt-level=0
-//[opt]compile-flags: -O
-//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O
+// check-pass
 
-// build-pass
-#[allow(arithmetic_overflow)]
+// compile-flags: -O
 
-const fn assert_static<T>(_: &'static T) {}
+fn foo(_: &'static [&'static str]) {}
+fn bar(_: &'static [&'static str; 3]) {}
+const fn baz_i32(_: &'static i32) {}
+const fn baz_u32(_: &'static u32) {}
 
 const fn fail() -> i32 { 1/0 }
 const C: i32 = {
     // Promoted that fails to evaluate in dead code -- this must work
     // (for backwards compatibility reasons).
     if false {
-        assert_static(&fail());
+        baz_i32(&fail());
     }
     42
 };
 
 fn main() {
-    assert_static(&["a", "b", "c"]);
-    assert_static(&["d", "e", "f"]);
+    foo(&["a", "b", "c"]);
+    bar(&["d", "e", "f"]);
     assert_eq!(C, 42);
 
     // make sure that these do not cause trouble despite overflowing
-    assert_static(&(0-1));
-    assert_static(&-i32::MIN);
-
-    // div-by-non-0 is okay
-    assert_static(&(1/1));
-    assert_static(&(1%1));
-
-    // in-bounds array access is okay
-    assert_static(&([1,2,3][0] + 1));
-    assert_static(&[[1,2][1]]);
-
-    // Top-level projections are not part of the promoted, so no error here.
-    if false {
-        #[allow(unconditional_panic)]
-        assert_static(&[1,2,3][4]);
-    }
+    baz_u32(&(0-1));
+    baz_i32(&-i32::MIN);
 }
diff --git a/src/test/ui/consts/read_from_static_mut_ref.rs b/src/test/ui/consts/read_from_static_mut_ref.rs
new file mode 100644
index 0000000000000..5faa983ab09f7
--- /dev/null
+++ b/src/test/ui/consts/read_from_static_mut_ref.rs
@@ -0,0 +1,9 @@
+// We are keeping this test in case we decide to allow mutable references in statics again
+#![feature(const_mut_refs)]
+#![allow(const_err)]
+
+static OH_NO: &mut i32 = &mut 42;
+//~^ ERROR mutable references are not allowed in statics
+fn main() {
+    assert_eq!(*OH_NO, 42);
+}
diff --git a/src/test/ui/consts/read_from_static_mut_ref.stderr b/src/test/ui/consts/read_from_static_mut_ref.stderr
new file mode 100644
index 0000000000000..c936ac0b7d585
--- /dev/null
+++ b/src/test/ui/consts/read_from_static_mut_ref.stderr
@@ -0,0 +1,9 @@
+error[E0764]: mutable references are not allowed in statics
+  --> $DIR/read_from_static_mut_ref.rs:5:26
+   |
+LL | static OH_NO: &mut i32 = &mut 42;
+   |                          ^^^^^^^ `&mut` is only allowed in `const fn`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0764`.
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr
index 8db75dd63cf2a..36c280ca5c607 100644
--- a/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr
+++ b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr
@@ -1,9 +1,9 @@
-error[E0080]: could not evaluate static initializer
-  --> $DIR/static_mut_containing_mut_ref2.rs:7:45
+error[E0764]: mutable references are not allowed in statics
+  --> $DIR/static_mut_containing_mut_ref2.rs:7:46
    |
 LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0764`.
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs
index 61368546083db..2821d1a015435 100644
--- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs
+++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs
@@ -5,7 +5,6 @@
 static mut STDERR_BUFFER_SPACE: u8 = 0;
 
 pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
-//[mut_refs]~^ ERROR could not evaluate static initializer
-//[stock]~^^ ERROR mutable references are not allowed in statics
+//~^ ERROR  mutable references are not allowed in statics
 
 fn main() {}
diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr
index 5cdcea2323109..36c280ca5c607 100644
--- a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr
+++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr
@@ -1,12 +1,9 @@
-error[E0658]: mutable references are not allowed in statics
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/static_mut_containing_mut_ref2.rs:7:46
    |
 LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0764`.
diff --git a/src/test/ui/consts/write_to_mut_ref_dest.mut_refs.stderr b/src/test/ui/consts/write_to_mut_ref_dest.mut_refs.stderr
deleted file mode 100644
index 3ee50907461ca..0000000000000
--- a/src/test/ui/consts/write_to_mut_ref_dest.mut_refs.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: dereferencing raw pointers in constants is unstable
-  --> $DIR/write_to_mut_ref_dest.rs:11:18
-   |
-LL |         unsafe { *b = 5; }
-   |                  ^^^^^^
-   |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` 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/consts/write_to_mut_ref_dest.stock.stderr b/src/test/ui/consts/write_to_mut_ref_dest.stock.stderr
deleted file mode 100644
index 2b6d1d3267b61..0000000000000
--- a/src/test/ui/consts/write_to_mut_ref_dest.stock.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: mutable references are not allowed in constants
-  --> $DIR/write_to_mut_ref_dest.rs:10:27
-   |
-LL |         let b: *mut u32 = &mut a;
-   |                           ^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
-error[E0658]: dereferencing raw pointers in constants is unstable
-  --> $DIR/write_to_mut_ref_dest.rs:11:18
-   |
-LL |         unsafe { *b = 5; }
-   |                  ^^^^^^
-   |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/write_to_static_via_mut_ref.rs b/src/test/ui/consts/write_to_static_via_mut_ref.rs
deleted file mode 100644
index 665c305e9617f..0000000000000
--- a/src/test/ui/consts/write_to_static_via_mut_ref.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(const_mut_refs)]
-#![allow(const_err)]
-
-static OH_NO: &mut i32 = &mut 42; //~ ERROR mutable references are not allowed
-fn main() {
-    assert_eq!(*OH_NO, 42);
-    *OH_NO = 43; //~ ERROR cannot assign to `*OH_NO`, as `OH_NO` is an immutable static
-}
diff --git a/src/test/ui/consts/write_to_static_via_mut_ref.stderr b/src/test/ui/consts/write_to_static_via_mut_ref.stderr
deleted file mode 100644
index d19e998d61736..0000000000000
--- a/src/test/ui/consts/write_to_static_via_mut_ref.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0764]: mutable references are not allowed in the final value of statics
-  --> $DIR/write_to_static_via_mut_ref.rs:4:26
-   |
-LL | static OH_NO: &mut i32 = &mut 42;
-   |                          ^^^^^^^
-
-error[E0594]: cannot assign to `*OH_NO`, as `OH_NO` is an immutable static item
-  --> $DIR/write_to_static_via_mut_ref.rs:7:5
-   |
-LL |     *OH_NO = 43;
-   |     ^^^^^^^^^^^ cannot assign
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0594, E0764.
-For more information about an error, try `rustc --explain E0594`.
diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs
index c211ad1a2f8f6..262f7bc72c739 100644
--- a/src/test/ui/error-codes/E0017.rs
+++ b/src/test/ui/error-codes/E0017.rs
@@ -2,13 +2,12 @@ static X: i32 = 1;
 const C: i32 = 2;
 static mut M: i32 = 3;
 
-const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed
+const CR: &'static mut i32 = &mut C; //~ ERROR E0764
                                      //~| WARN taking a mutable
-static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658
+static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0764
                                               //~| ERROR cannot borrow
-                                              //~| ERROR mutable references are not allowed
 
-static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764
                                               //~| WARN taking a mutable
-static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR mutable references are not
+static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0764
 fn main() {}
diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr
index 7d959b6d148ed..ea591587e6daa 100644
--- a/src/test/ui/error-codes/E0017.stderr
+++ b/src/test/ui/error-codes/E0017.stderr
@@ -13,26 +13,17 @@ note: `const` item defined here
 LL | const C: i32 = 2;
    | ^^^^^^^^^^^^^^^^^
 
-error[E0764]: mutable references are not allowed in the final value of constants
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/E0017.rs:5:30
    |
 LL | const CR: &'static mut i32 = &mut C;
-   |                              ^^^^^^
+   |                              ^^^^^^ `&mut` is only allowed in `const fn`
 
-error[E0658]: mutation through a reference is not allowed in statics
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/E0017.rs:7:39
    |
 LL | static STATIC_REF: &'static mut i32 = &mut X;
-   |                                       ^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
-error[E0764]: mutable references are not allowed in the final value of statics
-  --> $DIR/E0017.rs:7:39
-   |
-LL | static STATIC_REF: &'static mut i32 = &mut X;
-   |                                       ^^^^^^
+   |                                       ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0596]: cannot borrow immutable static item `X` as mutable
   --> $DIR/E0017.rs:7:39
@@ -41,7 +32,7 @@ LL | static STATIC_REF: &'static mut i32 = &mut X;
    |                                       ^^^^^^ cannot borrow as mutable
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/E0017.rs:11:38
+  --> $DIR/E0017.rs:10:38
    |
 LL | static CONST_REF: &'static mut i32 = &mut C;
    |                                      ^^^^^^
@@ -54,19 +45,19 @@ note: `const` item defined here
 LL | const C: i32 = 2;
    | ^^^^^^^^^^^^^^^^^
 
-error[E0764]: mutable references are not allowed in the final value of statics
-  --> $DIR/E0017.rs:11:38
+error[E0764]: mutable references are not allowed in statics
+  --> $DIR/E0017.rs:10:38
    |
 LL | static CONST_REF: &'static mut i32 = &mut C;
-   |                                      ^^^^^^
+   |                                      ^^^^^^ `&mut` is only allowed in `const fn`
 
-error[E0764]: mutable references are not allowed in the final value of statics
-  --> $DIR/E0017.rs:13:52
+error[E0764]: mutable references are not allowed in statics
+  --> $DIR/E0017.rs:12:52
    |
 LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M };
-   |                                                    ^^^^^^
+   |                                                    ^^^^^^ `&mut` is only allowed in `const fn`
 
-error: aborting due to 6 previous errors; 2 warnings emitted
+error: aborting due to 5 previous errors; 2 warnings emitted
 
-Some errors have detailed explanations: E0596, E0658, E0764.
+Some errors have detailed explanations: E0596, E0764.
 For more information about an error, try `rustc --explain E0596`.
diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs
index 6049d95f0d277..bb0c4979b9ac9 100644
--- a/src/test/ui/error-codes/E0388.rs
+++ b/src/test/ui/error-codes/E0388.rs
@@ -1,13 +1,12 @@
 static X: i32 = 1;
 const C: i32 = 2;
 
-const CR: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed
+const CR: &'static mut i32 = &mut C; //~ ERROR E0764
                                      //~| WARN taking a mutable
 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR cannot borrow
-                                              //~| ERROR E0658
-                                              //~| ERROR mutable references are not allowed
+                                              //~| ERROR E0764
 
-static CONST_REF: &'static mut i32 = &mut C; //~ ERROR mutable references are not allowed
+static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764
                                              //~| WARN taking a mutable
 
 fn main() {}
diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr
index 4886a156d2ea5..73e0b139cd056 100644
--- a/src/test/ui/error-codes/E0388.stderr
+++ b/src/test/ui/error-codes/E0388.stderr
@@ -13,26 +13,17 @@ note: `const` item defined here
 LL | const C: i32 = 2;
    | ^^^^^^^^^^^^^^^^^
 
-error[E0764]: mutable references are not allowed in the final value of constants
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/E0388.rs:4:30
    |
 LL | const CR: &'static mut i32 = &mut C;
-   |                              ^^^^^^
+   |                              ^^^^^^ `&mut` is only allowed in `const fn`
 
-error[E0658]: mutation through a reference is not allowed in statics
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/E0388.rs:6:39
    |
 LL | static STATIC_REF: &'static mut i32 = &mut X;
-   |                                       ^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
-error[E0764]: mutable references are not allowed in the final value of statics
-  --> $DIR/E0388.rs:6:39
-   |
-LL | static STATIC_REF: &'static mut i32 = &mut X;
-   |                                       ^^^^^^
+   |                                       ^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0596]: cannot borrow immutable static item `X` as mutable
   --> $DIR/E0388.rs:6:39
@@ -41,7 +32,7 @@ LL | static STATIC_REF: &'static mut i32 = &mut X;
    |                                       ^^^^^^ cannot borrow as mutable
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/E0388.rs:10:38
+  --> $DIR/E0388.rs:9:38
    |
 LL | static CONST_REF: &'static mut i32 = &mut C;
    |                                      ^^^^^^
@@ -54,13 +45,13 @@ note: `const` item defined here
 LL | const C: i32 = 2;
    | ^^^^^^^^^^^^^^^^^
 
-error[E0764]: mutable references are not allowed in the final value of statics
-  --> $DIR/E0388.rs:10:38
+error[E0764]: mutable references are not allowed in statics
+  --> $DIR/E0388.rs:9:38
    |
 LL | static CONST_REF: &'static mut i32 = &mut C;
-   |                                      ^^^^^^
+   |                                      ^^^^^^ `&mut` is only allowed in `const fn`
 
-error: aborting due to 5 previous errors; 2 warnings emitted
+error: aborting due to 4 previous errors; 2 warnings emitted
 
-Some errors have detailed explanations: E0596, E0658, E0764.
+Some errors have detailed explanations: E0596, E0764.
 For more information about an error, try `rustc --explain E0596`.
diff --git a/src/test/ui/extern/extern-compare-with-return-type.rs b/src/test/ui/extern/extern-compare-with-return-type.rs
index 42693d3a061c8..1ddfc77a4c43a 100644
--- a/src/test/ui/extern/extern-compare-with-return-type.rs
+++ b/src/test/ui/extern/extern-compare-with-return-type.rs
@@ -1,5 +1,4 @@
 // run-pass
-
 // Tests that we can compare various kinds of extern fn signatures.
 #![allow(non_camel_case_types)]
 
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.rs b/src/test/ui/feature-gates/feature-gate-cfg-version.rs
index e35784a68d101..c29ef99945e71 100644
--- a/src/test/ui/feature-gates/feature-gate-cfg-version.rs
+++ b/src/test/ui/feature-gates/feature-gate-cfg-version.rs
@@ -1,9 +1,3 @@
-#[cfg(version(42))] //~ ERROR: expected a version literal
-//~^ ERROR `cfg(version)` is experimental and subject to change
-fn foo() {}
-#[cfg(version(1.20))] //~ ERROR: expected a version literal
-//~^ ERROR `cfg(version)` is experimental and subject to change
-fn foo() -> bool { true }
 #[cfg(version("1.44"))]
 //~^ ERROR `cfg(version)` is experimental and subject to change
 fn foo() -> bool { true }
@@ -17,32 +11,30 @@ fn bar() -> bool  { false }
 #[cfg(version(false))] //~ ERROR: expected a version literal
 //~^ ERROR `cfg(version)` is experimental and subject to change
 fn bar() -> bool  { false }
-#[cfg(version("foo"))] //~ WARNING: unknown version literal format
+#[cfg(version("foo"))] //~ ERROR: invalid version literal
 //~^ ERROR `cfg(version)` is experimental and subject to change
 fn bar() -> bool  { false }
-#[cfg(version("999"))] //~ WARNING: unknown version literal format
+#[cfg(version("999"))]
 //~^ ERROR `cfg(version)` is experimental and subject to change
 fn bar() -> bool  { false }
-#[cfg(version("-1"))] //~ WARNING: unknown version literal format
+#[cfg(version("-1"))] //~ ERROR: invalid version literal
 //~^ ERROR `cfg(version)` is experimental and subject to change
 fn bar() -> bool  { false }
-#[cfg(version("65536"))] //~ WARNING: unknown version literal format
+#[cfg(version("65536"))] //~ ERROR: invalid version literal
 //~^ ERROR `cfg(version)` is experimental and subject to change
 fn bar() -> bool  { false }
-#[cfg(version("0"))] //~ WARNING: unknown version literal format
-//~^ ERROR `cfg(version)` is experimental and subject to change
-fn bar() -> bool { true }
-#[cfg(version("1.0"))]
+#[cfg(version("0"))]
 //~^ ERROR `cfg(version)` is experimental and subject to change
 fn bar() -> bool { true }
-#[cfg(version("1.65536.2"))] //~ WARNING: unknown version literal format
-//~^ ERROR `cfg(version)` is experimental and subject to change
-fn bar() -> bool  { false }
-#[cfg(version("1.20.0-stable"))] //~ WARNING: unknown version literal format
+
+#[cfg(version("1.65536.2"))]
 //~^ ERROR `cfg(version)` is experimental and subject to change
-fn bar() {}
+fn version_check_bug() {}
 
 fn main() {
+    // This should fail but due to a bug in version_check `1.65536.2` is interpreted as `1.2`.
+    // See https://github.com/SergioBenitez/version_check/issues/11
+    version_check_bug();
     assert!(foo());
     assert!(bar());
     assert!(cfg!(version("1.42"))); //~ ERROR `cfg(version)` is experimental and subject to change
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-version.stderr b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr
index ae899d409ecf9..bdf160b5a0270 100644
--- a/src/test/ui/feature-gates/feature-gate-cfg-version.stderr
+++ b/src/test/ui/feature-gates/feature-gate-cfg-version.stderr
@@ -1,36 +1,6 @@
 error[E0658]: `cfg(version)` is experimental and subject to change
   --> $DIR/feature-gate-cfg-version.rs:1:7
    |
-LL | #[cfg(version(42))]
-   |       ^^^^^^^^^^^
-   |
-   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
-   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
-
-error: expected a version literal
-  --> $DIR/feature-gate-cfg-version.rs:1:15
-   |
-LL | #[cfg(version(42))]
-   |               ^^
-
-error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:4:7
-   |
-LL | #[cfg(version(1.20))]
-   |       ^^^^^^^^^^^^^
-   |
-   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
-   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
-
-error: expected a version literal
-  --> $DIR/feature-gate-cfg-version.rs:4:15
-   |
-LL | #[cfg(version(1.20))]
-   |               ^^^^
-
-error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:7:7
-   |
 LL | #[cfg(version("1.44"))]
    |       ^^^^^^^^^^^^^^^
    |
@@ -38,7 +8,7 @@ LL | #[cfg(version("1.44"))]
    = help: add `#![feature(cfg_version)]` to the crate attributes to enable
 
 error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:10:11
+  --> $DIR/feature-gate-cfg-version.rs:4:11
    |
 LL | #[cfg(not(version("1.44")))]
    |           ^^^^^^^^^^^^^^^
@@ -47,7 +17,7 @@ LL | #[cfg(not(version("1.44")))]
    = help: add `#![feature(cfg_version)]` to the crate attributes to enable
 
 error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:14:7
+  --> $DIR/feature-gate-cfg-version.rs:8:7
    |
 LL | #[cfg(version("1.43", "1.44", "1.45"))]
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -56,13 +26,13 @@ LL | #[cfg(version("1.43", "1.44", "1.45"))]
    = help: add `#![feature(cfg_version)]` to the crate attributes to enable
 
 error: expected single version literal
-  --> $DIR/feature-gate-cfg-version.rs:14:7
+  --> $DIR/feature-gate-cfg-version.rs:8:7
    |
 LL | #[cfg(version("1.43", "1.44", "1.45"))]
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:17:7
+  --> $DIR/feature-gate-cfg-version.rs:11:7
    |
 LL | #[cfg(version(false))]
    |       ^^^^^^^^^^^^^^
@@ -71,13 +41,13 @@ LL | #[cfg(version(false))]
    = help: add `#![feature(cfg_version)]` to the crate attributes to enable
 
 error: expected a version literal
-  --> $DIR/feature-gate-cfg-version.rs:17:15
+  --> $DIR/feature-gate-cfg-version.rs:11:15
    |
 LL | #[cfg(version(false))]
    |               ^^^^^
 
 error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:20:7
+  --> $DIR/feature-gate-cfg-version.rs:14:7
    |
 LL | #[cfg(version("foo"))]
    |       ^^^^^^^^^^^^^^
@@ -85,14 +55,14 @@ LL | #[cfg(version("foo"))]
    = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
    = help: add `#![feature(cfg_version)]` to the crate attributes to enable
 
-warning: unknown version literal format, assuming it refers to a future version
-  --> $DIR/feature-gate-cfg-version.rs:20:15
+error: invalid version literal
+  --> $DIR/feature-gate-cfg-version.rs:14:15
    |
 LL | #[cfg(version("foo"))]
    |               ^^^^^
 
 error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:23:7
+  --> $DIR/feature-gate-cfg-version.rs:17:7
    |
 LL | #[cfg(version("999"))]
    |       ^^^^^^^^^^^^^^
@@ -100,14 +70,8 @@ LL | #[cfg(version("999"))]
    = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
    = help: add `#![feature(cfg_version)]` to the crate attributes to enable
 
-warning: unknown version literal format, assuming it refers to a future version
-  --> $DIR/feature-gate-cfg-version.rs:23:15
-   |
-LL | #[cfg(version("999"))]
-   |               ^^^^^
-
 error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:26:7
+  --> $DIR/feature-gate-cfg-version.rs:20:7
    |
 LL | #[cfg(version("-1"))]
    |       ^^^^^^^^^^^^^
@@ -115,14 +79,14 @@ LL | #[cfg(version("-1"))]
    = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
    = help: add `#![feature(cfg_version)]` to the crate attributes to enable
 
-warning: unknown version literal format, assuming it refers to a future version
-  --> $DIR/feature-gate-cfg-version.rs:26:15
+error: invalid version literal
+  --> $DIR/feature-gate-cfg-version.rs:20:15
    |
 LL | #[cfg(version("-1"))]
    |               ^^^^
 
 error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:29:7
+  --> $DIR/feature-gate-cfg-version.rs:23:7
    |
 LL | #[cfg(version("65536"))]
    |       ^^^^^^^^^^^^^^^^
@@ -130,14 +94,14 @@ LL | #[cfg(version("65536"))]
    = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
    = help: add `#![feature(cfg_version)]` to the crate attributes to enable
 
-warning: unknown version literal format, assuming it refers to a future version
-  --> $DIR/feature-gate-cfg-version.rs:29:15
+error: invalid version literal
+  --> $DIR/feature-gate-cfg-version.rs:23:15
    |
 LL | #[cfg(version("65536"))]
    |               ^^^^^^^
 
 error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:32:7
+  --> $DIR/feature-gate-cfg-version.rs:26:7
    |
 LL | #[cfg(version("0"))]
    |       ^^^^^^^^^^^^
@@ -145,23 +109,8 @@ LL | #[cfg(version("0"))]
    = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
    = help: add `#![feature(cfg_version)]` to the crate attributes to enable
 
-warning: unknown version literal format, assuming it refers to a future version
-  --> $DIR/feature-gate-cfg-version.rs:32:15
-   |
-LL | #[cfg(version("0"))]
-   |               ^^^
-
-error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:35:7
-   |
-LL | #[cfg(version("1.0"))]
-   |       ^^^^^^^^^^^^^^
-   |
-   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
-   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
-
 error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:38:7
+  --> $DIR/feature-gate-cfg-version.rs:30:7
    |
 LL | #[cfg(version("1.65536.2"))]
    |       ^^^^^^^^^^^^^^^^^^^^
@@ -169,29 +118,8 @@ LL | #[cfg(version("1.65536.2"))]
    = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
    = help: add `#![feature(cfg_version)]` to the crate attributes to enable
 
-warning: unknown version literal format, assuming it refers to a future version
-  --> $DIR/feature-gate-cfg-version.rs:38:15
-   |
-LL | #[cfg(version("1.65536.2"))]
-   |               ^^^^^^^^^^^
-
-error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:41:7
-   |
-LL | #[cfg(version("1.20.0-stable"))]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
-   = help: add `#![feature(cfg_version)]` to the crate attributes to enable
-
-warning: unknown version literal format, assuming it refers to a future version
-  --> $DIR/feature-gate-cfg-version.rs:41:15
-   |
-LL | #[cfg(version("1.20.0-stable"))]
-   |               ^^^^^^^^^^^^^^^
-
 error[E0658]: `cfg(version)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-version.rs:48:18
+  --> $DIR/feature-gate-cfg-version.rs:40:18
    |
 LL |     assert!(cfg!(version("1.42")));
    |                  ^^^^^^^^^^^^^^^
@@ -199,6 +127,6 @@ LL |     assert!(cfg!(version("1.42")));
    = note: see issue #64796 <https://github.com/rust-lang/rust/issues/64796> for more information
    = help: add `#![feature(cfg_version)]` to the crate attributes to enable
 
-error: aborting due to 19 previous errors; 7 warnings emitted
+error: aborting due to 16 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr
index 8abc4ccc9a5fa..051253cadc652 100644
--- a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr
+++ b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr
@@ -2,9 +2,7 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
   --> $DIR/trait-path-expected-token.rs:8:33
    |
 LL | fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {}
-   |                               - ^ expected one of 7 possible tokens
-   |                               |
-   |                               maybe try to close unmatched angle bracket
+   |                                 ^ expected one of 7 possible tokens
 
 warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/trait-path-expected-token.rs:1:12
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs
index 5e50c6b35c960..de61cfa1cf718 100644
--- a/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs
+++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs
@@ -17,7 +17,7 @@ mod error2 {
   }
 
   fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
-    //~^ ERROR: expected one of
+    //~^ ERROR: only types can be used in associated type constraints
 }
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr
index 27e1a750b2131..a9ba8adcaba3f 100644
--- a/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr
+++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr
@@ -6,13 +6,11 @@ LL |   fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {}
    |                              |
    |                              while parsing a const generic argument starting here
 
-error: expected one of `,`, `:`, or `>`, found `=`
-  --> $DIR/trait-path-expressions.rs:19:36
+error: only types can be used in associated type constraints
+  --> $DIR/trait-path-expressions.rs:19:30
    |
 LL |   fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
-   |                                  - ^ expected one of `,`, `:`, or `>`
-   |                                  |
-   |                                  maybe try to close unmatched angle bracket
+   |                              ^^^^^
 
 warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/trait-path-expressions.rs:1:12
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr
index f6038566e5b5e..8a5e2c29c3665 100644
--- a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr
+++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr
@@ -28,9 +28,7 @@ error: expected one of `>`, a const expression, lifetime, or type, found `=`
   --> $DIR/trait-path-missing-gen_arg.rs:17:30
    |
 LL |   fn f1<'a>(arg : Box<dyn X< = 32 >>) {}
-   |                            - ^ expected one of `>`, a const expression, lifetime, or type
-   |                            |
-   |                            maybe try to close unmatched angle bracket
+   |                              ^ expected one of `>`, a const expression, lifetime, or type
 
 warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/trait-path-missing-gen_arg.rs:1:12
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.rs b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs
index eba30e1438f04..0bf48b1f41810 100644
--- a/src/test/ui/generic-associated-types/parse/trait-path-segments.rs
+++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs
@@ -7,7 +7,7 @@ const _: () = {
     }
 
     fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
-        //~^ ERROR: expected one of
+        //~^ ERROR: paths with multiple segments cannot be used in associated type constraints
   };
 
 const _: () = {
@@ -18,7 +18,7 @@ const _: () = {
     trait Z {}
 
     impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
-        //~^ ERROR: expected one of
+        //~^ ERROR: qualified paths cannot be used in associated type constraints
 };
 
 const _: () = {
@@ -29,7 +29,7 @@ const _: () = {
     trait Z {}
 
     impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
-        //~^ ERROR: expected one of
+        //~^ ERROR: paths with multiple segments cannot be used in associated type constraints
 };
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr
index c82953aaed7dd..4e2b84d018239 100644
--- a/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr
+++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr
@@ -1,26 +1,22 @@
-error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, or `>`, found `=`
-  --> $DIR/trait-path-segments.rs:9:36
+error: paths with multiple segments cannot be used in associated type constraints
+  --> $DIR/trait-path-segments.rs:9:31
    |
 LL |     fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
-   |                                  - ^ expected one of 8 possible tokens
-   |                                  |
-   |                                  maybe try to close unmatched angle bracket
+   |                               ^^^^
 
-error: expected one of `,`, `::`, `:`, or `>`, found `=`
-  --> $DIR/trait-path-segments.rs:20:35
+error: qualified paths cannot be used in associated type constraints
+  --> $DIR/trait-path-segments.rs:20:16
    |
 LL |     impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
-   |                                 - ^ expected one of `,`, `::`, `:`, or `>`
-   |                                 |
-   |                                 maybe try to close unmatched angle bracket
+   |                ^^^^^^^^^-^^^^^^^^
+   |                         |
+   |                         not allowed in associated type constraints
 
-error: expected one of `!`, `+`, `,`, `::`, `:`, or `>`, found `=`
-  --> $DIR/trait-path-segments.rs:31:25
+error: paths with multiple segments cannot be used in associated type constraints
+  --> $DIR/trait-path-segments.rs:31:16
    |
 LL |     impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
-   |                       - ^ expected one of `!`, `+`, `,`, `::`, `:`, or `>`
-   |                       |
-   |                       maybe try to close unmatched angle bracket
+   |                ^^^^^^^^
 
 warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/trait-path-segments.rs:1:12
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.rs b/src/test/ui/generic-associated-types/parse/trait-path-types.rs
index 522b3edc638ea..6cdb501ec65fb 100644
--- a/src/test/ui/generic-associated-types/parse/trait-path-types.rs
+++ b/src/test/ui/generic-associated-types/parse/trait-path-types.rs
@@ -7,17 +7,17 @@ trait X {
 
 const _: () = {
   fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {}
-      //~^ ERROR: expected one of
+      //~^ ERROR: only path types can be used in associated type constraints
 };
 
 const _: () = {
   fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {}
-      //~^ ERROR: expected one of
+      //~^ ERROR: only path types can be used in associated type constraints
 };
 
 const _: () = {
   fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {}
-      //~^ ERROR: expected one of
+      //~^ ERROR: only types can be used in associated type constraints
 };
 
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.stderr b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr
index ac791c224810e..f5be084613b4c 100644
--- a/src/test/ui/generic-associated-types/parse/trait-path-types.stderr
+++ b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr
@@ -1,26 +1,20 @@
-error: expected one of `,`, `:`, or `>`, found `=`
-  --> $DIR/trait-path-types.rs:9:37
+error: only path types can be used in associated type constraints
+  --> $DIR/trait-path-types.rs:9:29
    |
 LL |   fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {}
-   |                                   - ^ expected one of `,`, `:`, or `>`
-   |                                   |
-   |                                   maybe try to close unmatched angle bracket
+   |                             ^^^^^^^
 
-error: expected one of `,`, `:`, or `>`, found `=`
-  --> $DIR/trait-path-types.rs:14:37
+error: only path types can be used in associated type constraints
+  --> $DIR/trait-path-types.rs:14:29
    |
 LL |   fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {}
-   |                                   - ^ expected one of `,`, `:`, or `>`
-   |                                   |
-   |                                   maybe try to close unmatched angle bracket
+   |                             ^^^^^^^
 
-error: expected one of `,`, `:`, or `>`, found `=`
-  --> $DIR/trait-path-types.rs:19:33
+error: only types can be used in associated type constraints
+  --> $DIR/trait-path-types.rs:19:30
    |
 LL |   fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {}
-   |                              -- ^ expected one of `,`, `:`, or `>`
-   |                              |
-   |                              maybe try to close unmatched angle bracket
+   |                              ^^
 
 warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
   --> $DIR/trait-path-types.rs:1:12
diff --git a/src/test/ui/generic-associated-types/variance_constraints.rs b/src/test/ui/generic-associated-types/variance_constraints.rs
deleted file mode 100644
index 36db80706b499..0000000000000
--- a/src/test/ui/generic-associated-types/variance_constraints.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// check-pass
-// issue #69184
-#![feature(generic_associated_types)]
-#![allow(incomplete_features)]
-
-trait A {
-    type B<'a>;
-
-    fn make_b<'a>(&'a self) -> Self::B<'a>;
-}
-
-struct S {}
-impl A for S {
-    type B<'a> = &'a S;
-    fn make_b<'a>(&'a self) -> &'a Self {
-        self
-    }
-}
-
-enum E<'a> {
-    S(<S as A>::B<'a>),
-}
-
-fn main() {}
diff --git a/src/test/ui/hygiene/no_implicit_prelude-2021.rs b/src/test/ui/hygiene/no_implicit_prelude-2021.rs
deleted file mode 100644
index 0fe9ae56c6564..0000000000000
--- a/src/test/ui/hygiene/no_implicit_prelude-2021.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// check-pass
-// edition:2021
-
-#![no_implicit_prelude]
-
-fn main() {
-    assert!(true, "hoi");
-    assert!(false, "hoi {}", 123);
-}
diff --git a/src/test/ui/issues/issue-1962.fixed b/src/test/ui/issues/issue-1962.fixed
index 897fd172b29f3..b810a90ef37f9 100644
--- a/src/test/ui/issues/issue-1962.fixed
+++ b/src/test/ui/issues/issue-1962.fixed
@@ -3,8 +3,8 @@
 
 fn main() {
     let mut i = 0;
-    'a: loop { //~ ERROR denote infinite loops with `loop
+    loop { //~ ERROR denote infinite loops with `loop
         i += 1;
-        if i == 5 { break 'a; }
+        if i == 5 { break; }
     }
 }
diff --git a/src/test/ui/issues/issue-1962.rs b/src/test/ui/issues/issue-1962.rs
index 71e874100874f..00d2bbd28506e 100644
--- a/src/test/ui/issues/issue-1962.rs
+++ b/src/test/ui/issues/issue-1962.rs
@@ -3,8 +3,8 @@
 
 fn main() {
     let mut i = 0;
-    'a: while true { //~ ERROR denote infinite loops with `loop
+    while true { //~ ERROR denote infinite loops with `loop
         i += 1;
-        if i == 5 { break 'a; }
+        if i == 5 { break; }
     }
 }
diff --git a/src/test/ui/issues/issue-1962.stderr b/src/test/ui/issues/issue-1962.stderr
index 4c32a4cf3dd59..17142912696a7 100644
--- a/src/test/ui/issues/issue-1962.stderr
+++ b/src/test/ui/issues/issue-1962.stderr
@@ -1,8 +1,8 @@
 error: denote infinite loops with `loop { ... }`
   --> $DIR/issue-1962.rs:6:5
    |
-LL |     'a: while true {
-   |     ^^^^^^^^^^^^^^ help: use `loop`
+LL |     while true {
+   |     ^^^^^^^^^^ help: use `loop`
    |
    = note: requested on the command line with `-D while-true`
 
diff --git a/src/test/ui/issues/issue-27042.stderr b/src/test/ui/issues/issue-27042.stderr
index 59ef28481d0e6..7dee1a6a5f044 100644
--- a/src/test/ui/issues/issue-27042.stderr
+++ b/src/test/ui/issues/issue-27042.stderr
@@ -4,7 +4,7 @@ warning: denote infinite loops with `loop { ... }`
 LL | /         'b:
 LL | |
 LL | |         while true { break }; // but here we cite the whole loop
-   | |__________________^ help: use `loop`
+   | |____________________________^ help: use `loop`
    |
    = note: `#[warn(while_true)]` on by default
 
diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs
index 51486bc40de0c..b45c00f694321 100644
--- a/src/test/ui/issues/issue-34334.rs
+++ b/src/test/ui/issues/issue-34334.rs
@@ -1,8 +1,6 @@
 fn main () {
     let sr: Vec<(u32, _, _) = vec![];
-    //~^ ERROR expected one of
-
+    //~^ ERROR only path types can be used in associated type constraints
     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
     //~^ ERROR a value of type `Vec<(u32, _, _)>` cannot be built
-
 }
diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr
index acb44ce2c3545..a9b9bf06d7f42 100644
--- a/src/test/ui/issues/issue-34334.stderr
+++ b/src/test/ui/issues/issue-34334.stderr
@@ -1,14 +1,13 @@
-error: expected one of `,`, `:`, or `>`, found `=`
-  --> $DIR/issue-34334.rs:2:29
+error: only path types can be used in associated type constraints
+  --> $DIR/issue-34334.rs:2:17
    |
 LL |     let sr: Vec<(u32, _, _) = vec![];
-   |         --                - ^ expected one of `,`, `:`, or `>`
-   |         |                 |
-   |         |                 maybe try to close unmatched angle bracket
+   |         --      ^^^^^^^^^^^
+   |         |
    |         while parsing the type for `sr`
 
 error[E0277]: a value of type `Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()`
-  --> $DIR/issue-34334.rs:5:87
+  --> $DIR/issue-34334.rs:4:87
    |
 LL |     let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
    |                                                                                       ^^^^^^^ value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator<Item=()>`
diff --git a/src/test/ui/issues/issue-46604.rs b/src/test/ui/issues/issue-46604.rs
index 6ec6e7bdcb81e..273187a5a13be 100644
--- a/src/test/ui/issues/issue-46604.rs
+++ b/src/test/ui/issues/issue-46604.rs
@@ -1,4 +1,4 @@
-static buf: &mut [u8] = &mut [1u8,2,3,4,5,7];   //~ ERROR mutable references are not allowed
+static buf: &mut [u8] = &mut [1u8,2,3,4,5,7];   //~ ERROR E0764
 fn write<T: AsRef<[u8]>>(buffer: T) { }
 
 fn main() {
diff --git a/src/test/ui/issues/issue-46604.stderr b/src/test/ui/issues/issue-46604.stderr
index 7faa2d79ba483..5421721dec2e3 100644
--- a/src/test/ui/issues/issue-46604.stderr
+++ b/src/test/ui/issues/issue-46604.stderr
@@ -1,8 +1,8 @@
-error[E0764]: mutable references are not allowed in the final value of statics
+error[E0764]: mutable references are not allowed in statics
   --> $DIR/issue-46604.rs:1:25
    |
 LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7];
-   |                         ^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item
   --> $DIR/issue-46604.rs:6:5
diff --git a/src/test/ui/label/label_misspelled.rs b/src/test/ui/label/label_misspelled.rs
index e3180b06ecb2b..ebfd5642c9fa8 100644
--- a/src/test/ui/label/label_misspelled.rs
+++ b/src/test/ui/label/label_misspelled.rs
@@ -1,62 +1,18 @@
-#![warn(unused_labels)]
-
 fn main() {
-    'while_loop: while true { //~ WARN denote infinite loops with
-        //~^ WARN unused label
-        while_loop;
-        //~^ ERROR cannot find value `while_loop` in this scope
-    };
-    'while_let: while let Some(_) = Some(()) {
-        //~^ WARN unused label
-        while_let;
-        //~^ ERROR cannot find value `while_let` in this scope
-    }
-    'for_loop: for _ in 0..3 {
-        //~^ WARN unused label
-        for_loop;
-        //~^ ERROR cannot find value `for_loop` in this scope
-    };
     'LOOP: loop {
-        //~^ WARN unused label
         LOOP;
         //~^ ERROR cannot find value `LOOP` in this scope
     };
-}
-
-fn foo() {
-    'LOOP: loop {
-        break LOOP;
-        //~^ ERROR cannot find value `LOOP` in this scope
-    };
     'while_loop: while true { //~ WARN denote infinite loops with
-        break while_loop;
+        while_loop;
         //~^ ERROR cannot find value `while_loop` in this scope
     };
     'while_let: while let Some(_) = Some(()) {
-        break while_let;
+        while_let;
         //~^ ERROR cannot find value `while_let` in this scope
     }
     'for_loop: for _ in 0..3 {
-        break for_loop;
+        for_loop;
         //~^ ERROR cannot find value `for_loop` in this scope
     };
 }
-
-fn bar() {
-    let foo = ();
-    'while_loop: while true { //~ WARN denote infinite loops with
-        //~^ WARN unused label
-        break foo;
-        //~^ ERROR `break` with value from a `while` loop
-    };
-    'while_let: while let Some(_) = Some(()) {
-        //~^ WARN unused label
-        break foo;
-        //~^ ERROR `break` with value from a `while` loop
-    }
-    'for_loop: for _ in 0..3 {
-        //~^ WARN unused label
-        break foo;
-        //~^ ERROR `break` with value from a `for` loop
-    };
-}
diff --git a/src/test/ui/label/label_misspelled.stderr b/src/test/ui/label/label_misspelled.stderr
index b09695787a443..1368ca4126cdd 100644
--- a/src/test/ui/label/label_misspelled.stderr
+++ b/src/test/ui/label/label_misspelled.stderr
@@ -1,206 +1,47 @@
-error[E0425]: cannot find value `while_loop` in this scope
-  --> $DIR/label_misspelled.rs:6:9
-   |
-LL |     'while_loop: while true {
-   |     ----------- a label with a similar name exists
-LL |
-LL |         while_loop;
-   |         ^^^^^^^^^^ not found in this scope
-
-error[E0425]: cannot find value `while_let` in this scope
-  --> $DIR/label_misspelled.rs:11:9
-   |
-LL |     'while_let: while let Some(_) = Some(()) {
-   |     ---------- a label with a similar name exists
-LL |
-LL |         while_let;
-   |         ^^^^^^^^^ not found in this scope
-
-error[E0425]: cannot find value `for_loop` in this scope
-  --> $DIR/label_misspelled.rs:16:9
-   |
-LL |     'for_loop: for _ in 0..3 {
-   |     --------- a label with a similar name exists
-LL |
-LL |         for_loop;
-   |         ^^^^^^^^ not found in this scope
-
 error[E0425]: cannot find value `LOOP` in this scope
-  --> $DIR/label_misspelled.rs:21:9
+  --> $DIR/label_misspelled.rs:3:9
    |
-LL |     'LOOP: loop {
-   |     ----- a label with a similar name exists
-LL |
 LL |         LOOP;
-   |         ^^^^ not found in this scope
-
-error[E0425]: cannot find value `LOOP` in this scope
-  --> $DIR/label_misspelled.rs:28:15
-   |
-LL |     'LOOP: loop {
-   |     ----- a label with a similar name exists
-LL |         break LOOP;
-   |               ^^^^
-   |               |
-   |               not found in this scope
-   |               help: use the similarly named label: `'LOOP`
+   |         ^^^^
+   |         |
+   |         not found in this scope
+   |         help: a label with a similar name exists: `'LOOP`
 
 error[E0425]: cannot find value `while_loop` in this scope
-  --> $DIR/label_misspelled.rs:32:15
+  --> $DIR/label_misspelled.rs:7:9
    |
-LL |     'while_loop: while true {
-   |     ----------- a label with a similar name exists
-LL |         break while_loop;
-   |               ^^^^^^^^^^
-   |               |
-   |               not found in this scope
-   |               help: use the similarly named label: `'while_loop`
+LL |         while_loop;
+   |         ^^^^^^^^^^
+   |         |
+   |         not found in this scope
+   |         help: a label with a similar name exists: `'while_loop`
 
 error[E0425]: cannot find value `while_let` in this scope
-  --> $DIR/label_misspelled.rs:36:15
+  --> $DIR/label_misspelled.rs:11:9
    |
-LL |     'while_let: while let Some(_) = Some(()) {
-   |     ---------- a label with a similar name exists
-LL |         break while_let;
-   |               ^^^^^^^^^
-   |               |
-   |               not found in this scope
-   |               help: use the similarly named label: `'while_let`
+LL |         while_let;
+   |         ^^^^^^^^^
+   |         |
+   |         not found in this scope
+   |         help: a label with a similar name exists: `'while_let`
 
 error[E0425]: cannot find value `for_loop` in this scope
-  --> $DIR/label_misspelled.rs:40:15
-   |
-LL |     'for_loop: for _ in 0..3 {
-   |     --------- a label with a similar name exists
-LL |         break for_loop;
-   |               ^^^^^^^^
-   |               |
-   |               not found in this scope
-   |               help: use the similarly named label: `'for_loop`
-
-warning: unused label
-  --> $DIR/label_misspelled.rs:4:5
-   |
-LL |     'while_loop: while true {
-   |     ^^^^^^^^^^^
+  --> $DIR/label_misspelled.rs:15:9
    |
-note: the lint level is defined here
-  --> $DIR/label_misspelled.rs:1:9
-   |
-LL | #![warn(unused_labels)]
-   |         ^^^^^^^^^^^^^
+LL |         for_loop;
+   |         ^^^^^^^^
+   |         |
+   |         not found in this scope
+   |         help: a label with a similar name exists: `'for_loop`
 
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/label_misspelled.rs:4:5
+  --> $DIR/label_misspelled.rs:6:5
    |
 LL |     'while_loop: while true {
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
    |
    = note: `#[warn(while_true)]` on by default
 
-warning: unused label
-  --> $DIR/label_misspelled.rs:9:5
-   |
-LL |     'while_let: while let Some(_) = Some(()) {
-   |     ^^^^^^^^^^
-
-warning: unused label
-  --> $DIR/label_misspelled.rs:14:5
-   |
-LL |     'for_loop: for _ in 0..3 {
-   |     ^^^^^^^^^
-
-warning: unused label
-  --> $DIR/label_misspelled.rs:19:5
-   |
-LL |     'LOOP: loop {
-   |     ^^^^^
-
-warning: denote infinite loops with `loop { ... }`
-  --> $DIR/label_misspelled.rs:31:5
-   |
-LL |     'while_loop: while true {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
-
-warning: unused label
-  --> $DIR/label_misspelled.rs:47:5
-   |
-LL |     'while_loop: while true {
-   |     ^^^^^^^^^^^
-
-warning: denote infinite loops with `loop { ... }`
-  --> $DIR/label_misspelled.rs:47:5
-   |
-LL |     'while_loop: while true {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
-
-warning: unused label
-  --> $DIR/label_misspelled.rs:52:5
-   |
-LL |     'while_let: while let Some(_) = Some(()) {
-   |     ^^^^^^^^^^
-
-warning: unused label
-  --> $DIR/label_misspelled.rs:57:5
-   |
-LL |     'for_loop: for _ in 0..3 {
-   |     ^^^^^^^^^
-
-error[E0571]: `break` with value from a `while` loop
-  --> $DIR/label_misspelled.rs:49:9
-   |
-LL |     'while_loop: while true {
-   |     ----------------------- you can't `break` with a value in a `while` loop
-LL |
-LL |         break foo;
-   |         ^^^^^^^^^ can only break with a value inside `loop` or breakable block
-   |
-help: use `break` on its own without a value inside this `while` loop
-   |
-LL |         break;
-   |         ^^^^^
-help: alternatively, you might have meant to use the available loop label
-   |
-LL |         break 'while_loop;
-   |               ^^^^^^^^^^^
-
-error[E0571]: `break` with value from a `while` loop
-  --> $DIR/label_misspelled.rs:54:9
-   |
-LL |     'while_let: while let Some(_) = Some(()) {
-   |     ---------------------------------------- you can't `break` with a value in a `while` loop
-LL |
-LL |         break foo;
-   |         ^^^^^^^^^ can only break with a value inside `loop` or breakable block
-   |
-help: use `break` on its own without a value inside this `while` loop
-   |
-LL |         break;
-   |         ^^^^^
-help: alternatively, you might have meant to use the available loop label
-   |
-LL |         break 'while_let;
-   |               ^^^^^^^^^^
-
-error[E0571]: `break` with value from a `for` loop
-  --> $DIR/label_misspelled.rs:59:9
-   |
-LL |     'for_loop: for _ in 0..3 {
-   |     ------------------------ you can't `break` with a value in a `for` loop
-LL |
-LL |         break foo;
-   |         ^^^^^^^^^ can only break with a value inside `loop` or breakable block
-   |
-help: use `break` on its own without a value inside this `for` loop
-   |
-LL |         break;
-   |         ^^^^^
-help: alternatively, you might have meant to use the available loop label
-   |
-LL |         break 'for_loop;
-   |               ^^^^^^^^^
-
-error: aborting due to 11 previous errors; 10 warnings emitted
+error: aborting due to 4 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0425, E0571.
-For more information about an error, try `rustc --explain E0425`.
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/label/label_misspelled_2.rs b/src/test/ui/label/label_misspelled_2.rs
deleted file mode 100644
index 55bbe6b30a593..0000000000000
--- a/src/test/ui/label/label_misspelled_2.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-#![warn(unused_labels)]
-
-fn main() {
-    'a: for _ in 0..1 {
-        break 'a;
-    }
-    'b: for _ in 0..1 {
-        break b; //~ ERROR cannot find value `b` in this scope
-    }
-    c: for _ in 0..1 { //~ ERROR malformed loop label
-        break 'c;
-    }
-    d: for _ in 0..1 { //~ ERROR malformed loop label
-        break d; //~ ERROR cannot find value `d` in this scope
-    }
-}
diff --git a/src/test/ui/label/label_misspelled_2.stderr b/src/test/ui/label/label_misspelled_2.stderr
deleted file mode 100644
index 960646d9894d1..0000000000000
--- a/src/test/ui/label/label_misspelled_2.stderr
+++ /dev/null
@@ -1,37 +0,0 @@
-error: malformed loop label
-  --> $DIR/label_misspelled_2.rs:10:5
-   |
-LL |     c: for _ in 0..1 {
-   |     ^ help: use the correct loop label format: `'c`
-
-error: malformed loop label
-  --> $DIR/label_misspelled_2.rs:13:5
-   |
-LL |     d: for _ in 0..1 {
-   |     ^ help: use the correct loop label format: `'d`
-
-error[E0425]: cannot find value `b` in this scope
-  --> $DIR/label_misspelled_2.rs:8:15
-   |
-LL |     'b: for _ in 0..1 {
-   |     -- a label with a similar name exists
-LL |         break b;
-   |               ^
-   |               |
-   |               not found in this scope
-   |               help: use the similarly named label: `'b`
-
-error[E0425]: cannot find value `d` in this scope
-  --> $DIR/label_misspelled_2.rs:14:15
-   |
-LL |     d: for _ in 0..1 {
-   |     - a label with a similar name exists
-LL |         break d;
-   |               ^
-   |               |
-   |               not found in this scope
-   |               help: use the similarly named label: `'d`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/lint/dead-code/const-and-self.rs b/src/test/ui/lint/dead-code/const-and-self.rs
index 0bcdd6edf0d66..1a7b3f43cda14 100644
--- a/src/test/ui/lint/dead-code/const-and-self.rs
+++ b/src/test/ui/lint/dead-code/const-and-self.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![warn(dead_code)]
+#![deny(dead_code)]
 
 const TLC: usize = 4;
 
@@ -28,27 +28,8 @@ impl Foo<Y> for X {
     }
 }
 
-enum E {
-    A,
-    B, //~ WARN variant is never constructed: `B`
-    C, //~ WARN variant is never constructed: `C`
-}
-
-type F = E;
-
-impl E {
-    fn check(&self) -> bool {
-        match self {
-            Self::A => true,
-            Self::B => false,
-            F::C => false,
-        }
-    }
-}
-
 fn main() {
     let s = [0,1,2,3];
     s.doit();
     X::foo();
-    E::A.check();
 }
diff --git a/src/test/ui/lint/dead-code/const-and-self.stderr b/src/test/ui/lint/dead-code/const-and-self.stderr
deleted file mode 100644
index c0e406189e8ab..0000000000000
--- a/src/test/ui/lint/dead-code/const-and-self.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-warning: variant is never constructed: `B`
-  --> $DIR/const-and-self.rs:33:5
-   |
-LL |     B,
-   |     ^
-   |
-note: the lint level is defined here
-  --> $DIR/const-and-self.rs:3:9
-   |
-LL | #![warn(dead_code)]
-   |         ^^^^^^^^^
-
-warning: variant is never constructed: `C`
-  --> $DIR/const-and-self.rs:34:5
-   |
-LL |     C,
-   |     ^
-
-warning: 2 warnings emitted
-
diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr
index 540e076c7e4c6..3973af540c81f 100644
--- a/src/test/ui/lint/lint-const-item-mutation.stderr
+++ b/src/test/ui/lint/lint-const-item-mutation.stderr
@@ -109,8 +109,14 @@ LL |     VEC.push(0);
 note: mutable reference created due to call to this method
   --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
    |
-LL |     pub fn push(&mut self, value: T) {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     pub fn push(&mut self, value: T) {
+LL | |         // This will panic or abort if we would allocate > isize::MAX bytes
+LL | |         // or if the length increment would overflow for zero-sized types.
+LL | |         if self.len == self.buf.capacity() {
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
 note: `const` item defined here
   --> $DIR/lint-const-item-mutation.rs:31:1
    |
diff --git a/src/test/ui/lint/lint-removed-cmdline.stderr b/src/test/ui/lint/lint-removed-cmdline.stderr
index fc2ba92479cc6..1c45c38774e5a 100644
--- a/src/test/ui/lint/lint-removed-cmdline.stderr
+++ b/src/test/ui/lint/lint-removed-cmdline.stderr
@@ -1,16 +1,16 @@
-warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok`
    |
    = note: requested on the command line with `-D raw_pointer_derive`
 
-warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok`
    |
    = note: requested on the command line with `-D raw_pointer_derive`
 
-warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok`
    |
    = note: requested on the command line with `-D raw_pointer_derive`
 
-warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok`
    |
    = note: requested on the command line with `-D raw_pointer_derive`
 
diff --git a/src/test/ui/lint/lint-removed.stderr b/src/test/ui/lint/lint-removed.stderr
index dc0515b84820b..44480d84203bd 100644
--- a/src/test/ui/lint/lint-removed.stderr
+++ b/src/test/ui/lint/lint-removed.stderr
@@ -1,4 +1,4 @@
-warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok`
   --> $DIR/lint-removed.rs:6:8
    |
 LL | #[deny(raw_pointer_derive)]
diff --git a/src/test/ui/lint/lint-unexported-no-mangle.stderr b/src/test/ui/lint/lint-unexported-no-mangle.stderr
index 66d64e8937a2b..48d9b38a99b65 100644
--- a/src/test/ui/lint/lint-unexported-no-mangle.stderr
+++ b/src/test/ui/lint/lint-unexported-no-mangle.stderr
@@ -1,32 +1,32 @@
-warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported
+warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, `#[no_mangle]` functions always exported`
    |
    = note: requested on the command line with `-F private_no_mangle_fns`
 
-warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported
+warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, `#[no_mangle]` statics always exported`
    |
    = note: requested on the command line with `-F private_no_mangle_statics`
 
-warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported
+warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, `#[no_mangle]` functions always exported`
    |
    = note: requested on the command line with `-F private_no_mangle_fns`
 
-warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported
+warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, `#[no_mangle]` statics always exported`
    |
    = note: requested on the command line with `-F private_no_mangle_statics`
 
-warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported
+warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, `#[no_mangle]` functions always exported`
    |
    = note: requested on the command line with `-F private_no_mangle_fns`
 
-warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported
+warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, `#[no_mangle]` statics always exported`
    |
    = note: requested on the command line with `-F private_no_mangle_statics`
 
-warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported
+warning: lint `private_no_mangle_fns` has been removed: `no longer a warning, `#[no_mangle]` functions always exported`
    |
    = note: requested on the command line with `-F private_no_mangle_fns`
 
-warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported
+warning: lint `private_no_mangle_statics` has been removed: `no longer a warning, `#[no_mangle]` statics always exported`
    |
    = note: requested on the command line with `-F private_no_mangle_statics`
 
diff --git a/src/test/ui/loops/loop-break-value-no-repeat.stderr b/src/test/ui/loops/loop-break-value-no-repeat.stderr
index 1c0d39a6e5ad7..ff93e9220e986 100644
--- a/src/test/ui/loops/loop-break-value-no-repeat.stderr
+++ b/src/test/ui/loops/loop-break-value-no-repeat.stderr
@@ -1,12 +1,10 @@
 error[E0571]: `break` with value from a `for` loop
   --> $DIR/loop-break-value-no-repeat.rs:12:9
    |
-LL |     for _ in &[1,2,3] {
-   |     ----------------- you can't `break` with a value in a `for` loop
 LL |         break 22
    |         ^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: use `break` on its own without a value inside this `for` loop
+help: instead, use `break` on its own without a value inside this `for` loop
    |
 LL |         break
    |         ^^^^^
diff --git a/src/test/ui/loops/loop-break-value.rs b/src/test/ui/loops/loop-break-value.rs
index 51c9a36a03956..8a080cfdf494a 100644
--- a/src/test/ui/loops/loop-break-value.rs
+++ b/src/test/ui/loops/loop-break-value.rs
@@ -94,5 +94,6 @@ fn main() {
     'LOOP: for _ in 0 .. 9 {
         break LOOP;
         //~^ ERROR cannot find value `LOOP` in this scope
+        //~| ERROR `break` with value from a `for` loop
     }
 }
diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr
index adb099f9b1769..0237435c8b46a 100644
--- a/src/test/ui/loops/loop-break-value.stderr
+++ b/src/test/ui/loops/loop-break-value.stderr
@@ -1,13 +1,11 @@
 error[E0425]: cannot find value `LOOP` in this scope
   --> $DIR/loop-break-value.rs:95:15
    |
-LL |     'LOOP: for _ in 0 .. 9 {
-   |     ----- a label with a similar name exists
 LL |         break LOOP;
    |               ^^^^
    |               |
    |               not found in this scope
-   |               help: use the similarly named label: `'LOOP`
+   |               help: a label with a similar name exists: `'LOOP`
 
 warning: denote infinite loops with `loop { ... }`
   --> $DIR/loop-break-value.rs:26:5
@@ -20,44 +18,32 @@ LL |     'while_loop: while true {
 error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:28:9
    |
-LL |     'while_loop: while true {
-   |     ----------------------- you can't `break` with a value in a `while` loop
-LL |         break;
 LL |         break ();
    |         ^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: use `break` on its own without a value inside this `while` loop
+help: instead, use `break` on its own without a value inside this `while` loop
    |
 LL |         break;
    |         ^^^^^
-help: alternatively, you might have meant to use the available loop label
-   |
-LL |         break 'while_loop;
-   |               ^^^^^^^^^^^
 
 error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:30:13
    |
-LL |     'while_loop: while true {
-   |     ----------------------- you can't `break` with a value in a `while` loop
-...
 LL |             break 'while_loop 123;
    |             ^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: use `break` on its own without a value inside this `while` loop
+help: instead, use `break` on its own without a value inside this `while` loop
    |
-LL |             break 'while_loop;
-   |             ^^^^^^^^^^^^^^^^^
+LL |             break;
+   |             ^^^^^
 
 error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:38:12
    |
-LL |     while let Some(_) = Some(()) {
-   |     ---------------------------- you can't `break` with a value in a `while` loop
 LL |         if break () {
    |            ^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: use `break` on its own without a value inside this `while` loop
+help: instead, use `break` on its own without a value inside this `while` loop
    |
 LL |         if break {
    |            ^^^^^
@@ -65,12 +51,10 @@ LL |         if break {
 error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:43:9
    |
-LL |     while let Some(_) = Some(()) {
-   |     ---------------------------- you can't `break` with a value in a `while` loop
 LL |         break None;
    |         ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: use `break` on its own without a value inside this `while` loop
+help: instead, use `break` on its own without a value inside this `while` loop
    |
 LL |         break;
    |         ^^^^^
@@ -78,26 +62,21 @@ LL |         break;
 error[E0571]: `break` with value from a `while` loop
   --> $DIR/loop-break-value.rs:49:13
    |
-LL |     'while_let_loop: while let Some(_) = Some(()) {
-   |     --------------------------------------------- you can't `break` with a value in a `while` loop
-LL |         loop {
 LL |             break 'while_let_loop "nope";
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: use `break` on its own without a value inside this `while` loop
+help: instead, use `break` on its own without a value inside this `while` loop
    |
-LL |             break 'while_let_loop;
-   |             ^^^^^^^^^^^^^^^^^^^^^
+LL |             break;
+   |             ^^^^^
 
 error[E0571]: `break` with value from a `for` loop
   --> $DIR/loop-break-value.rs:56:9
    |
-LL |     for _ in &[1,2,3] {
-   |     ----------------- you can't `break` with a value in a `for` loop
 LL |         break ();
    |         ^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: use `break` on its own without a value inside this `for` loop
+help: instead, use `break` on its own without a value inside this `for` loop
    |
 LL |         break;
    |         ^^^^^
@@ -105,13 +84,10 @@ LL |         break;
 error[E0571]: `break` with value from a `for` loop
   --> $DIR/loop-break-value.rs:57:9
    |
-LL |     for _ in &[1,2,3] {
-   |     ----------------- you can't `break` with a value in a `for` loop
-LL |         break ();
 LL |         break [()];
    |         ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: use `break` on its own without a value inside this `for` loop
+help: instead, use `break` on its own without a value inside this `for` loop
    |
 LL |         break;
    |         ^^^^^
@@ -119,16 +95,24 @@ LL |         break;
 error[E0571]: `break` with value from a `for` loop
   --> $DIR/loop-break-value.rs:64:13
    |
-LL |     'for_loop: for _ in &[1,2,3] {
-   |     ---------------------------- you can't `break` with a value in a `for` loop
-...
 LL |             break 'for_loop Some(17);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-help: use `break` on its own without a value inside this `for` loop
+help: instead, use `break` on its own without a value inside this `for` loop
+   |
+LL |             break;
+   |             ^^^^^
+
+error[E0571]: `break` with value from a `for` loop
+  --> $DIR/loop-break-value.rs:95:9
+   |
+LL |         break LOOP;
+   |         ^^^^^^^^^^ can only break with a value inside `loop` or breakable block
    |
-LL |             break 'for_loop;
-   |             ^^^^^^^^^^^^^^^
+help: instead, use `break` on its own without a value inside this `for` loop
+   |
+LL |         break;
+   |         ^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/loop-break-value.rs:4:31
@@ -187,7 +171,7 @@ LL |         break;
    |         expected integer, found `()`
    |         help: give it a value of the expected type: `break value`
 
-error: aborting due to 17 previous errors; 1 warning emitted
+error: aborting due to 18 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0308, E0425, E0571.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/mir/issue-80742.rs b/src/test/ui/mir/issue-80742.rs
deleted file mode 100644
index c06d182fd567d..0000000000000
--- a/src/test/ui/mir/issue-80742.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-// check-fail
-
-// This test used to cause an ICE in rustc_mir::interpret::step::eval_rvalue_into_place
-
-#![allow(incomplete_features)]
-#![feature(const_evaluatable_checked)]
-#![feature(const_generics)]
-
-use std::fmt::Debug;
-use std::marker::PhantomData;
-use std::mem::size_of;
-
-struct Inline<T>
-where
-    [u8; size_of::<T>() + 1]: ,
-{
-    _phantom: PhantomData<T>,
-    buf: [u8; size_of::<T>() + 1],
-}
-
-impl<T> Inline<T>
-where
-    [u8; size_of::<T>() + 1]: ,
-{
-    pub fn new(val: T) -> Inline<T> {
-        todo!()
-    }
-}
-
-fn main() {
-    let dst = Inline::<dyn Debug>::new(0); //~ ERROR
-    //~^ ERROR
-}
diff --git a/src/test/ui/mir/issue-80742.stderr b/src/test/ui/mir/issue-80742.stderr
deleted file mode 100644
index 26f9c786ba13b..0000000000000
--- a/src/test/ui/mir/issue-80742.stderr
+++ /dev/null
@@ -1,70 +0,0 @@
-error[E0080]: evaluation of constant value failed
-  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
-   |
-LL |     intrinsics::size_of::<T>()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |     |
-   |     size_of called on unsized type `dyn Debug`
-   |     inside `std::mem::size_of::<dyn Debug>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
-   | 
-  ::: $DIR/issue-80742.rs:23:10
-   |
-LL |     [u8; size_of::<T>() + 1]: ,
-   |          -------------- inside `Inline::<dyn Debug>::{constant#0}` at $DIR/issue-80742.rs:23:10
-
-error[E0599]: no function or associated item named `new` found for struct `Inline<dyn Debug>` in the current scope
-  --> $DIR/issue-80742.rs:31:36
-   |
-LL | / struct Inline<T>
-LL | | where
-LL | |     [u8; size_of::<T>() + 1]: ,
-LL | | {
-LL | |     _phantom: PhantomData<T>,
-LL | |     buf: [u8; size_of::<T>() + 1],
-LL | | }
-   | |_- function or associated item `new` not found for this
-...
-LL |       let dst = Inline::<dyn Debug>::new(0);
-   |                                      ^^^ function or associated item not found in `Inline<dyn Debug>`
-   | 
-  ::: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
-   |
-LL |   pub trait Debug {
-   |   --------------- doesn't satisfy `dyn Debug: Sized`
-   |
-   = note: the method `new` exists but the following trait bounds were not satisfied:
-           `dyn Debug: Sized`
-
-error[E0080]: evaluation of constant value failed
-  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
-   |
-LL |     intrinsics::size_of::<T>()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |     |
-   |     size_of called on unsized type `dyn Debug`
-   |     inside `std::mem::size_of::<dyn Debug>` at $SRC_DIR/core/src/mem/mod.rs:LL:COL
-   | 
-  ::: $DIR/issue-80742.rs:15:10
-   |
-LL |     [u8; size_of::<T>() + 1]: ,
-   |          -------------- inside `Inline::<dyn Debug>::{constant#0}` at $DIR/issue-80742.rs:15:10
-
-error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time
-  --> $DIR/issue-80742.rs:31:15
-   |
-LL | struct Inline<T>
-   |               - required by this bound in `Inline`
-...
-LL |     let dst = Inline::<dyn Debug>::new(0);
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `dyn Debug`
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL | struct Inline<T: ?Sized>
-   |                ^^^^^^^^
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0080, E0277, E0599.
-For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/never_type/issue-52443.stderr b/src/test/ui/never_type/issue-52443.stderr
index 1683841e9d781..051896cb89c8f 100644
--- a/src/test/ui/never_type/issue-52443.stderr
+++ b/src/test/ui/never_type/issue-52443.stderr
@@ -39,14 +39,11 @@ error[E0015]: calls in constants are limited to constant functions, tuple struct
 LL |     [(); { for _ in 0usize.. {}; 0}];
    |                     ^^^^^^^^
 
-error[E0658]: mutable references are not allowed in constants
+error[E0764]: mutable references are not allowed in constants
   --> $DIR/issue-52443.rs:9:21
    |
 LL |     [(); { for _ in 0usize.. {}; 0}];
-   |                     ^^^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   |                     ^^^^^^^^ `&mut` is only allowed in `const fn`
 
 error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
   --> $DIR/issue-52443.rs:9:21
@@ -56,5 +53,5 @@ LL |     [(); { for _ in 0usize.. {}; 0}];
 
 error: aborting due to 6 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0015, E0308, E0658, E0744.
+Some errors have detailed explanations: E0015, E0308, E0744, E0764.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.rs b/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.rs
deleted file mode 100644
index da95c1bfa2709..0000000000000
--- a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-struct Foo<T1, T2> {
-  _a : T1,
-  _b : T2,
-}
-
-fn test1<T>(arg : T) {
-  let v : Vec<(u32,_) = vec![];
-    //~^ ERROR: expected one of
-    //~| ERROR: type annotations needed
-}
-
-fn test2<T1, T2>(arg1 : T1, arg2 : T2) {
-  let foo : Foo::<T1, T2 = Foo {_a : arg1, _b : arg2};
-    //~^ ERROR: expected one of
-}
-
-fn test3<'a>(arg : &'a u32) {
-  let v : Vec<'a = vec![];
-    //~^ ERROR: expected one of
-    //~| ERROR: type annotations needed for `Vec<T>`
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr b/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
deleted file mode 100644
index ae53334f5e02a..0000000000000
--- a/src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
+++ /dev/null
@@ -1,49 +0,0 @@
-error: expected one of `,`, `:`, or `>`, found `=`
-  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:23
-   |
-LL |   let v : Vec<(u32,_) = vec![];
-   |       -             - ^ expected one of `,`, `:`, or `>`
-   |       |             |
-   |       |             maybe try to close unmatched angle bracket
-   |       while parsing the type for `v`
-
-error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `{`
-  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:13:32
-   |
-LL |   let foo : Foo::<T1, T2 = Foo {_a : arg1, _b : arg2};
-   |       ---                      ^ expected one of 7 possible tokens
-   |       |
-   |       while parsing the type for `foo`
-
-error: expected one of `,`, `:`, or `>`, found `=`
-  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:18
-   |
-LL |   let v : Vec<'a = vec![];
-   |       -       -- ^ expected one of `,`, `:`, or `>`
-   |       |       |
-   |       |       maybe try to close unmatched angle bracket
-   |       while parsing the type for `v`
-
-error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:25
-   |
-LL |   let v : Vec<(u32,_) = vec![];
-   |       -                 ^^^^^^ cannot infer type for type parameter `T`
-   |       |
-   |       consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0282]: type annotations needed for `Vec<T>`
-  --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:20
-   |
-LL |   let v : Vec<'a = vec![];
-   |       -            ^^^^^^ cannot infer type for type parameter `T`
-   |       |
-   |       consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/parser/nested-missing-closing-angle-bracket.rs b/src/test/ui/parser/nested-missing-closing-angle-bracket.rs
deleted file mode 100644
index 84ffdd176aea0..0000000000000
--- a/src/test/ui/parser/nested-missing-closing-angle-bracket.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-  let v : Vec::<Vec<(u32,_,_)> = vec![vec![]];
-    //~^ ERROR: expected one of
-}
diff --git a/src/test/ui/parser/nested-missing-closing-angle-bracket.stderr b/src/test/ui/parser/nested-missing-closing-angle-bracket.stderr
deleted file mode 100644
index b85bc02568c77..0000000000000
--- a/src/test/ui/parser/nested-missing-closing-angle-bracket.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: expected one of `,` or `>`, found `;`
-  --> $DIR/nested-missing-closing-angle-bracket.rs:2:46
-   |
-LL |   let v : Vec::<Vec<(u32,_,_)> = vec![vec![]];
-   |       - while parsing the type for `v`       ^ expected one of `,` or `>`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/proc-macro/issue-81007-item-attrs.rs b/src/test/ui/proc-macro/issue-81007-item-attrs.rs
deleted file mode 100644
index ea27d54ee4148..0000000000000
--- a/src/test/ui/proc-macro/issue-81007-item-attrs.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// check-pass
-// edition:2018
-// compile-flags: -Z span-debug
-// aux-build:test-macros.rs
-
-#![feature(rustc_attrs)]
-
-#![no_std] // Don't load unnecessary hygiene information from std
-extern crate std;
-
-#[macro_use] extern crate test_macros;
-
-macro_rules! capture_item {
-    ($item:item) => {
-        #[print_attr]
-        $item
-    }
-}
-
-capture_item! {
-    /// A doc comment
-    struct Foo {}
-}
-
-capture_item! {
-    #[rustc_dummy]
-    /// Another comment comment
-    struct Bar {}
-}
-
-fn main() {}
diff --git a/src/test/ui/proc-macro/issue-81007-item-attrs.stdout b/src/test/ui/proc-macro/issue-81007-item-attrs.stdout
deleted file mode 100644
index 6f880a1202170..0000000000000
--- a/src/test/ui/proc-macro/issue-81007-item-attrs.stdout
+++ /dev/null
@@ -1,99 +0,0 @@
-PRINT-ATTR INPUT (DISPLAY): #[doc = r" A doc comment"] struct Foo { }
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Punct {
-        ch: '#',
-        spacing: Alone,
-        span: $DIR/issue-81007-item-attrs.rs:21:5: 21:22 (#0),
-    },
-    Group {
-        delimiter: Bracket,
-        stream: TokenStream [
-            Ident {
-                ident: "doc",
-                span: $DIR/issue-81007-item-attrs.rs:21:5: 21:22 (#0),
-            },
-            Punct {
-                ch: '=',
-                spacing: Alone,
-                span: $DIR/issue-81007-item-attrs.rs:21:5: 21:22 (#0),
-            },
-            Literal {
-                kind: StrRaw(0),
-                symbol: " A doc comment",
-                suffix: None,
-                span: $DIR/issue-81007-item-attrs.rs:21:5: 21:22 (#0),
-            },
-        ],
-        span: $DIR/issue-81007-item-attrs.rs:21:5: 21:22 (#0),
-    },
-    Ident {
-        ident: "struct",
-        span: $DIR/issue-81007-item-attrs.rs:22:5: 22:11 (#0),
-    },
-    Ident {
-        ident: "Foo",
-        span: $DIR/issue-81007-item-attrs.rs:22:12: 22:15 (#0),
-    },
-    Group {
-        delimiter: Brace,
-        stream: TokenStream [],
-        span: $DIR/issue-81007-item-attrs.rs:22:16: 22:18 (#0),
-    },
-]
-PRINT-ATTR INPUT (DISPLAY): #[rustc_dummy] #[doc = r" Another comment comment"] struct Bar { }
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Punct {
-        ch: '#',
-        spacing: Alone,
-        span: $DIR/issue-81007-item-attrs.rs:26:5: 26:6 (#0),
-    },
-    Group {
-        delimiter: Bracket,
-        stream: TokenStream [
-            Ident {
-                ident: "rustc_dummy",
-                span: $DIR/issue-81007-item-attrs.rs:26:7: 26:18 (#0),
-            },
-        ],
-        span: $DIR/issue-81007-item-attrs.rs:26:6: 26:19 (#0),
-    },
-    Punct {
-        ch: '#',
-        spacing: Alone,
-        span: $DIR/issue-81007-item-attrs.rs:27:5: 27:32 (#0),
-    },
-    Group {
-        delimiter: Bracket,
-        stream: TokenStream [
-            Ident {
-                ident: "doc",
-                span: $DIR/issue-81007-item-attrs.rs:27:5: 27:32 (#0),
-            },
-            Punct {
-                ch: '=',
-                spacing: Alone,
-                span: $DIR/issue-81007-item-attrs.rs:27:5: 27:32 (#0),
-            },
-            Literal {
-                kind: StrRaw(0),
-                symbol: " Another comment comment",
-                suffix: None,
-                span: $DIR/issue-81007-item-attrs.rs:27:5: 27:32 (#0),
-            },
-        ],
-        span: $DIR/issue-81007-item-attrs.rs:27:5: 27:32 (#0),
-    },
-    Ident {
-        ident: "struct",
-        span: $DIR/issue-81007-item-attrs.rs:28:5: 28:11 (#0),
-    },
-    Ident {
-        ident: "Bar",
-        span: $DIR/issue-81007-item-attrs.rs:28:12: 28:15 (#0),
-    },
-    Group {
-        delimiter: Brace,
-        stream: TokenStream [],
-        span: $DIR/issue-81007-item-attrs.rs:28:16: 28:18 (#0),
-    },
-]
diff --git a/src/test/ui/unsafe/ranged_ints2_const.rs b/src/test/ui/unsafe/ranged_ints2_const.rs
index b7178c2b52bfb..65e0d79308ca3 100644
--- a/src/test/ui/unsafe/ranged_ints2_const.rs
+++ b/src/test/ui/unsafe/ranged_ints2_const.rs
@@ -18,9 +18,3 @@ const fn bar() -> NonZero<u32> {
     let y = unsafe { &mut x.0 }; //~ ERROR mutable references
     unsafe { NonZero(1) }
 }
-
-const fn boo() -> NonZero<u32> {
-    let mut x = unsafe { NonZero(1) };
-    unsafe { let y = &mut x.0; } //~ ERROR mutable references
-    unsafe { NonZero(1) }
-}
diff --git a/src/test/ui/unsafe/ranged_ints2_const.stderr b/src/test/ui/unsafe/ranged_ints2_const.stderr
index a0dc950e76dd1..5ce4296458e6d 100644
--- a/src/test/ui/unsafe/ranged_ints2_const.stderr
+++ b/src/test/ui/unsafe/ranged_ints2_const.stderr
@@ -16,15 +16,6 @@ LL |     let y = unsafe { &mut x.0 };
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/ranged_ints2_const.rs:24:22
-   |
-LL |     unsafe { let y = &mut x.0; }
-   |                      ^^^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
-
 error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
   --> $DIR/ranged_ints2_const.rs:11:13
    |
@@ -33,7 +24,7 @@ LL |     let y = &mut x.0;
    |
    = note: mutating layout constrained fields cannot statically be checked for valid values
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0133, E0658.
 For more information about an error, try `rustc --explain E0133`.
diff --git a/src/tools/cargo b/src/tools/cargo
index 783bc43c660bf..a73e5b7d567c3 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 783bc43c660bf39c1e562c8c429b32078ad3099b
+Subproject commit a73e5b7d567c3036b296fc6b33ed52c5edcd882e
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 3a754f4991782..f518da55cd76f 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -12,7 +12,6 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_parse::maybe_new_parser_from_source_str;
-use rustc_parse::parser::ForceCollect;
 use rustc_session::parse::ParseSess;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::edition::Edition;
@@ -484,7 +483,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
 
                 let mut relevant_main_found = false;
                 loop {
-                    match parser.parse_item(ForceCollect::No) {
+                    match parser.parse_item() {
                         Ok(Some(item)) => match &item.kind {
                             // Tests with one of these items are ignored
                             ItemKind::Static(..)
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index bbcea387de2cb..1c5ab2874b048 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -533,7 +533,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
         }
 
         // check for never_loop
-        if let ExprKind::Loop(ref block, _, _, _) = expr.kind {
+        if let ExprKind::Loop(ref block, _, _) = expr.kind {
             match never_loop_block(block, expr.hir_id) {
                 NeverLoopResult::AlwaysBreak => span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
                 NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
@@ -543,7 +543,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
         // check for `loop { if let {} else break }` that could be `while let`
         // (also matches an explicit "match" instead of "if let")
         // (even if the "match" or "if let" is used for declaration)
-        if let ExprKind::Loop(ref block, _, LoopSource::Loop, _) = expr.kind {
+        if let ExprKind::Loop(ref block, _, LoopSource::Loop) = expr.kind {
             // also check for empty `loop {}` statements, skipping those in #[panic_handler]
             if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) {
                 let msg = "empty `loop {}` wastes CPU cycles";
@@ -738,7 +738,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
         | ExprKind::Assign(ref e1, ref e2, _)
         | ExprKind::AssignOp(_, ref e1, ref e2)
         | ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
-        ExprKind::Loop(ref b, _, _, _) => {
+        ExprKind::Loop(ref b, _, _) => {
             // Break can come from the inner loop so remove them.
             absorb_break(&never_loop_block(b, main_loop_id))
         },
@@ -1314,7 +1314,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         match &expr.kind {
             // Non-determinism may occur ... don't give a lint
-            ExprKind::Loop(..) | ExprKind::Match(..) => self.should_lint = false,
+            ExprKind::Loop(_, _, _) | ExprKind::Match(_, _, _) => self.should_lint = false,
             ExprKind::Block(block, _) => self.visit_block(block),
             _ => {},
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index 603071a5f4ac4..a971d041ca661 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -221,7 +221,7 @@ where
 {
     if let ast::ExprKind::While(_, loop_block, label)
     | ast::ExprKind::ForLoop(_, _, loop_block, label)
-    | ast::ExprKind::Loop(loop_block, label, ..) = &expr.kind
+    | ast::ExprKind::Loop(loop_block, label) = &expr.kind
     {
         func(loop_block, label.as_ref());
     }
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index d5b1767e945b9..24da056770c9d 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -325,7 +325,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut
         | ExprKind::Field(ref e, _)
         | ExprKind::AddrOf(_, _, ref e)
         | ExprKind::Box(ref e) => check_expr(cx, e, bindings),
-        ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, ..) => check_block(cx, block, bindings),
+        ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, _, _) => check_block(cx, block, bindings),
         // ExprKind::Call
         // ExprKind::MethodCall
         ExprKind::Array(v) | ExprKind::Tup(v) => {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index ca60d335262b3..43afa65de3e55 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -317,7 +317,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 self.current = cast_pat;
                 self.visit_expr(expr);
             },
-            ExprKind::Loop(ref body, _, desugaring, _) => {
+            ExprKind::Loop(ref body, _, desugaring) => {
                 let body_pat = self.next("body");
                 let des = loop_desugaring_name(desugaring);
                 let label_pat = self.next("label");
diff --git a/src/tools/clippy/clippy_lints/src/utils/higher.rs b/src/tools/clippy/clippy_lints/src/utils/higher.rs
index 42ab9a1e7d247..9b3585865da32 100644
--- a/src/tools/clippy/clippy_lints/src/utils/higher.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/higher.rs
@@ -142,7 +142,7 @@ pub fn for_loop<'tcx>(
         if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
         if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind;
         if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none();
-        if let hir::ExprKind::Loop(ref block, ..) = arms[0].body.kind;
+        if let hir::ExprKind::Loop(ref block, _, _) = arms[0].body.kind;
         if block.expr.is_none();
         if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
         if let hir::StmtKind::Local(ref local) = let_stmt.kind;
@@ -158,7 +158,7 @@ pub fn for_loop<'tcx>(
 /// `while cond { body }` becomes `(cond, body)`.
 pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>)> {
     if_chain! {
-        if let hir::ExprKind::Loop(block, _, hir::LoopSource::While, _) = &expr.kind;
+        if let hir::ExprKind::Loop(block, _, hir::LoopSource::While) = &expr.kind;
         if let hir::Block { expr: Some(expr), .. } = &**block;
         if let hir::ExprKind::Match(cond, arms, hir::MatchSource::WhileDesugar) = &expr.kind;
         if let hir::ExprKind::DropTemps(cond) = &cond.kind;
diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
index 6066383f2ef42..10120a8805db2 100644
--- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
@@ -123,7 +123,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
                 self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
             },
             (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
-            (&ExprKind::Loop(ref lb, ref ll, ref lls, _), &ExprKind::Loop(ref rb, ref rl, ref rls, _)) => {
+            (&ExprKind::Loop(ref lb, ref ll, ref lls), &ExprKind::Loop(ref rb, ref rl, ref rls)) => {
                 lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
             },
             (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
@@ -560,7 +560,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             ExprKind::Lit(ref l) => {
                 l.node.hash(&mut self.s);
             },
-            ExprKind::Loop(ref b, ref i, ..) => {
+            ExprKind::Loop(ref b, ref i, _) => {
                 self.hash_block(b);
                 if let Some(i) = *i {
                     self.hash_name(i.ident.name);
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
index f361db6b147da..3429317498ed6 100644
--- a/src/tools/clippy/tests/ui/deprecated.stderr
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -1,4 +1,4 @@
-error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
+error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
   --> $DIR/deprecated.rs:1:8
    |
 LL | #[warn(clippy::unstable_as_slice)]
@@ -6,73 +6,73 @@ LL | #[warn(clippy::unstable_as_slice)]
    |
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
-error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
+error: lint `clippy::unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7`
   --> $DIR/deprecated.rs:2:8
    |
 LL | #[warn(clippy::unstable_as_mut_slice)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
+error: lint `clippy::misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr`
   --> $DIR/deprecated.rs:3:8
    |
 LL | #[warn(clippy::misaligned_transmute)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
+error: lint `clippy::unused_collect` has been removed: ``collect` has been marked as #[must_use] in rustc and that covers all cases of this lint`
   --> $DIR/deprecated.rs:4:8
    |
 LL | #[warn(clippy::unused_collect)]
    |        ^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::invalid_ref` has been removed: superseded by rustc lint `invalid_value`
+error: lint `clippy::invalid_ref` has been removed: `superseded by rustc lint `invalid_value``
   --> $DIR/deprecated.rs:5:8
    |
 LL | #[warn(clippy::invalid_ref)]
    |        ^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::into_iter_on_array` has been removed: this lint has been uplifted to rustc and is now called `array_into_iter`
+error: lint `clippy::into_iter_on_array` has been removed: `this lint has been uplifted to rustc and is now called `array_into_iter``
   --> $DIR/deprecated.rs:6:8
    |
 LL | #[warn(clippy::into_iter_on_array)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unused_label` has been removed: this lint has been uplifted to rustc and is now called `unused_labels`
+error: lint `clippy::unused_label` has been removed: `this lint has been uplifted to rustc and is now called `unused_labels``
   --> $DIR/deprecated.rs:7:8
    |
 LL | #[warn(clippy::unused_label)]
    |        ^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
+error: lint `clippy::regex_macro` has been removed: `the regex! macro has been removed from the regex crate in 2018`
   --> $DIR/deprecated.rs:8:8
    |
 LL | #[warn(clippy::regex_macro)]
    |        ^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::drop_bounds` has been removed: this lint has been uplifted to rustc and is now called `drop_bounds`
+error: lint `clippy::drop_bounds` has been removed: `this lint has been uplifted to rustc and is now called `drop_bounds``
   --> $DIR/deprecated.rs:9:8
    |
 LL | #[warn(clippy::drop_bounds)]
    |        ^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::temporary_cstring_as_ptr` has been removed: this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`
+error: lint `clippy::temporary_cstring_as_ptr` has been removed: `this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr``
   --> $DIR/deprecated.rs:10:8
    |
 LL | #[warn(clippy::temporary_cstring_as_ptr)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::panic_params` has been removed: this lint has been uplifted to rustc and is now called `panic_fmt`
+error: lint `clippy::panic_params` has been removed: `this lint has been uplifted to rustc and is now called `panic_fmt``
   --> $DIR/deprecated.rs:11:8
    |
 LL | #[warn(clippy::panic_params)]
    |        ^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unknown_clippy_lints` has been removed: this lint has been integrated into the `unknown_lints` rustc lint
+error: lint `clippy::unknown_clippy_lints` has been removed: `this lint has been integrated into the `unknown_lints` rustc lint`
   --> $DIR/deprecated.rs:12:8
    |
 LL | #[warn(clippy::unknown_clippy_lints)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
+error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
   --> $DIR/deprecated.rs:1:8
    |
 LL | #[warn(clippy::unstable_as_slice)]
diff --git a/src/tools/clippy/tests/ui/deprecated_old.stderr b/src/tools/clippy/tests/ui/deprecated_old.stderr
index b8550078c4600..2fe1facf0c72d 100644
--- a/src/tools/clippy/tests/ui/deprecated_old.stderr
+++ b/src/tools/clippy/tests/ui/deprecated_old.stderr
@@ -1,4 +1,4 @@
-error: lint `unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
+error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
   --> $DIR/deprecated_old.rs:1:8
    |
 LL | #[warn(unstable_as_slice)]
@@ -6,19 +6,19 @@ LL | #[warn(unstable_as_slice)]
    |
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
-error: lint `unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
+error: lint `unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7`
   --> $DIR/deprecated_old.rs:2:8
    |
 LL | #[warn(unstable_as_mut_slice)]
    |        ^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
+error: lint `misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr`
   --> $DIR/deprecated_old.rs:3:8
    |
 LL | #[warn(misaligned_transmute)]
    |        ^^^^^^^^^^^^^^^^^^^^
 
-error: lint `unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
+error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
   --> $DIR/deprecated_old.rs:1:8
    |
 LL | #[warn(unstable_as_slice)]
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index 6ec292aba6495..29131f686a9dc 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -149,22 +149,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
             }
         }
 
-        let args = cap.name("args").map_or(Some(vec![]), |m| shlex::split(m.as_str()));
-
-        let args = match args {
-            Some(args) => args,
-            None => {
-                print_err(
-                    &format!(
-                        "Invalid arguments to shlex::split: `{}`",
-                        cap.name("args").unwrap().as_str()
-                    ),
-                    lineno,
-                );
-                errors = true;
-                continue;
-            }
-        };
+        let args = cap.name("args").map_or(vec![], |m| shlex::split(m.as_str()).unwrap());
 
         if !cmd.validate(&args, commands.len(), lineno) {
             errors = true;
diff --git a/src/tools/miri b/src/tools/miri
index de0800e83b4e1..1cf1a2e40a686 160000
--- a/src/tools/miri
+++ b/src/tools/miri
@@ -1 +1 @@
-Subproject commit de0800e83b4e15cf3c6aa8f15f8328e86a95d955
+Subproject commit 1cf1a2e40a6867948db84f806085a875fbefce3c