about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore70
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs97
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs30
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs168
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0404.md26
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_mir/src/transform/coverage/mod.rs3
-rw-r--r--compiler/rustc_mir/src/transform/coverage/spans.rs9
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs9
-rw-r--r--compiler/rustc_session/src/config.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/alloc/src/task.rs6
-rw-r--r--library/alloc/src/vec/mod.rs3
-rw-r--r--library/core/src/convert/num.rs16
-rw-r--r--library/core/src/iter/adapters/take.rs23
-rw-r--r--library/core/src/iter/traits/iterator.rs31
-rw-r--r--library/std/src/sync/condvar.rs3
-rw-r--r--library/std/src/sync/mod.rs5
-rw-r--r--library/std/src/sync/mutex.rs2
-rw-r--r--library/std/src/sync/poison.rs (renamed from library/std/src/sys_common/poison.rs)16
-rw-r--r--library/std/src/sync/rwlock.rs2
-rw-r--r--library/std/src/sys_common/mod.rs1
-rw-r--r--src/bootstrap/install.rs7
-rw-r--r--src/doc/rustc/src/platform-support.md4
-rw-r--r--src/librustdoc/clean/mod.rs117
-rw-r--r--src/librustdoc/clean/types.rs139
-rw-r--r--src/librustdoc/clean/utils.rs12
-rw-r--r--src/librustdoc/formats/cache.rs11
-rw-r--r--src/librustdoc/formats/renderer.rs35
-rw-r--r--src/librustdoc/html/render/cache.rs3
-rw-r--r--src/librustdoc/html/render/context.rs29
-rw-r--r--src/librustdoc/html/render/mod.rs23
-rw-r--r--src/librustdoc/html/render/print_item.rs2
-rw-r--r--src/librustdoc/html/render/write_shared.rs2
-rw-r--r--src/librustdoc/html/sources.rs2
-rw-r--r--src/librustdoc/html/static/main.js43
-rw-r--r--src/librustdoc/html/static/rustdoc.css13
-rw-r--r--src/librustdoc/html/static/search.js9
-rw-r--r--src/librustdoc/json/mod.rs14
-rw-r--r--src/librustdoc/lib.rs28
-rw-r--r--src/test/codegen/wasm_casts_nontrapping.rs162
-rw-r--r--src/test/codegen/wasm_casts_trapping.rs23
-rw-r--r--src/test/rustdoc-gui/lib.rs8
-rw-r--r--src/test/rustdoc/const-generics/add-impl.rs2
-rw-r--r--src/test/rustdoc/duplicate_impls/issue-33054.rs4
-rw-r--r--src/test/rustdoc/issue-21474.rs2
-rw-r--r--src/test/rustdoc/issue-29503.rs2
-rw-r--r--src/test/rustdoc/issue-45584.rs4
-rw-r--r--src/test/rustdoc/issue-50159.rs4
-rw-r--r--src/test/rustdoc/issue-51236.rs2
-rw-r--r--src/test/rustdoc/issue-53812.rs10
-rw-r--r--src/test/rustdoc/issue-54705.rs4
-rw-r--r--src/test/rustdoc/issue-55321.rs8
-rw-r--r--src/test/rustdoc/issue-56822.rs2
-rw-r--r--src/test/rustdoc/issue-60726.rs4
-rw-r--r--src/test/rustdoc/item-hide-threshold.rs3
-rw-r--r--src/test/rustdoc/synthetic_auto/basic.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/complex.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/lifetimes.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/manual.rs8
-rw-r--r--src/test/rustdoc/synthetic_auto/negative.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/nested.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/no-redundancy.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/project.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/self-referential.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/static-region.rs2
-rw-r--r--src/test/ui/associated-type-bounds/issue-81193.rs15
-rw-r--r--src/test/ui/associated-type-bounds/issue-83017.rs39
-rw-r--r--src/test/ui/associated-type-bounds/issue-83017.stderr27
-rw-r--r--src/test/ui/codemap_tests/two_files.stderr5
-rw-r--r--src/test/ui/resolve/issue-3907.stderr5
-rw-r--r--src/test/ui/resolve/issue-5035.stderr14
-rw-r--r--src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr5
-rw-r--r--src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.fixed13
-rw-r--r--src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.rs13
-rw-r--r--src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.stderr14
m---------src/tools/rust-analyzer35
78 files changed, 695 insertions, 791 deletions
diff --git a/.gitignore b/.gitignore
index 3f77e6884b9..0cd6b9f648d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,53 +5,71 @@
 # created during manual debugging and many people like to clean up instead of
 # having git ignore such leftovers. You can use `.git/info/exclude` to
 # configure your local ignore list.
-# FIXME: This needs cleanup.
-*~
+
+## File system
+.DS_Store
+desktop.ini
+
+## Editor
 *.swp
 *.swo
-.#*
-.DS_Store
+Session.vim
 .cproject
-.hg/
-.hgignore
 .idea
 *.iml
-__pycache__/
-*.py[cod]
-*$py.class
+.vscode
 .project
+.favorites.json
 .settings/
+
+## Tool
 .valgrindrc
-.vscode
-.favorites.json
-/Makefile
-/build/
+.cargo
+# Included because it is part of the test case
+!/src/test/run-make/thumb-none-qemu/example/.cargo
+
+## Configuration
 /config.toml
-/dist/
+/Makefile
+config.mk
+config.stamp
+no_llvm_build
+
+## Build
 /dl/
 /doc/
 /inst/
 /llvm/
 /mingw-build/
-/src/tools/x/target
-# Created by default with `src/ci/docker/run.sh`:
-/obj/
+/build/
+/dist/
 /unicode-downloads
 /target
-# Generated by compiletest for incremental:
+/src/tools/x/target
+# Generated by compiletest for incremental
 /tmp/
+# Created by default with `src/ci/docker/run.sh`
+/obj/
+
+## Temporary files
+*~
+\#*
+\#*\#
+.#*
+
+## Tags
 tags
 tags.*
 TAGS
 TAGS.*
-\#*
-\#*\#
-config.mk
-config.stamp
-Session.vim
-.cargo
-!/src/test/run-make/thumb-none-qemu/example/.cargo
-no_llvm_build
+
+## Python
+__pycache__/
+*.py[cod]
+*$py.class
+
+## Node
 **node_modules
 **package-lock.json
+
 # Before adding new lines, see the comment at the top.
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index f823792fabe..053cda1e7cc 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -2,6 +2,7 @@ use crate::common::Funclet;
 use crate::context::CodegenCx;
 use crate::llvm::{self, BasicBlock, False};
 use crate::llvm::{AtomicOrdering, AtomicRmwBinOp, SynchronizationScope};
+use crate::llvm_util;
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
@@ -16,7 +17,7 @@ use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::{sym, Span};
+use rustc_span::Span;
 use rustc_target::abi::{self, Align, Size};
 use rustc_target::spec::{HasTargetSpec, Target};
 use std::borrow::Cow;
@@ -669,81 +670,47 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
-        // WebAssembly has saturating floating point to integer casts if the
-        // `nontrapping-fptoint` target feature is activated. We'll use those if
-        // they are available.
-        if self.sess().target.arch == "wasm32"
-            && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
-        {
+        if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
             let src_ty = self.cx.val_ty(val);
             let float_width = self.cx.float_width(src_ty);
             let int_width = self.cx.int_width(dest_ty);
-            let name = match (int_width, float_width) {
-                (32, 32) => Some("llvm.wasm.trunc.saturate.unsigned.i32.f32"),
-                (32, 64) => Some("llvm.wasm.trunc.saturate.unsigned.i32.f64"),
-                (64, 32) => Some("llvm.wasm.trunc.saturate.unsigned.i64.f32"),
-                (64, 64) => Some("llvm.wasm.trunc.saturate.unsigned.i64.f64"),
-                _ => None,
-            };
-            if let Some(name) = name {
-                let intrinsic = self.get_intrinsic(name);
-                return Some(self.call(intrinsic, &[val], None));
-            }
+            let name = format!("llvm.fptoui.sat.i{}.f{}", int_width, float_width);
+            let intrinsic = self.get_intrinsic(&name);
+            return Some(self.call(intrinsic, &[val], None));
         }
+
         None
     }
 
     fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
-        // WebAssembly has saturating floating point to integer casts if the
-        // `nontrapping-fptoint` target feature is activated. We'll use those if
-        // they are available.
-        if self.sess().target.arch == "wasm32"
-            && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
-        {
+        if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
             let src_ty = self.cx.val_ty(val);
             let float_width = self.cx.float_width(src_ty);
             let int_width = self.cx.int_width(dest_ty);
-            let name = match (int_width, float_width) {
-                (32, 32) => Some("llvm.wasm.trunc.saturate.signed.i32.f32"),
-                (32, 64) => Some("llvm.wasm.trunc.saturate.signed.i32.f64"),
-                (64, 32) => Some("llvm.wasm.trunc.saturate.signed.i64.f32"),
-                (64, 64) => Some("llvm.wasm.trunc.saturate.signed.i64.f64"),
-                _ => None,
-            };
-            if let Some(name) = name {
-                let intrinsic = self.get_intrinsic(name);
-                return Some(self.call(intrinsic, &[val], None));
-            }
+            let name = format!("llvm.fptosi.sat.i{}.f{}", int_width, float_width);
+            let intrinsic = self.get_intrinsic(&name);
+            return Some(self.call(intrinsic, &[val], None));
         }
-        None
-    }
 
-    fn fptosui_may_trap(&self, val: &'ll Value, dest_ty: &'ll Type) -> bool {
-        // Most of the time we'll be generating the `fptosi` or `fptoui`
-        // instruction for floating-point-to-integer conversions. These
-        // instructions by definition in LLVM do not trap. For the WebAssembly
-        // target, however, we'll lower in some cases to intrinsic calls instead
-        // which may trap. If we detect that this is a situation where we'll be
-        // using the intrinsics then we report that the call map trap, which
-        // callers might need to handle.
-        if !self.wasm_and_missing_nontrapping_fptoint() {
-            return false;
-        }
-        let src_ty = self.cx.val_ty(val);
-        let float_width = self.cx.float_width(src_ty);
-        let int_width = self.cx.int_width(dest_ty);
-        matches!((int_width, float_width), (32, 32) | (32, 64) | (64, 32) | (64, 64))
+        None
     }
 
     fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
-        // When we can, use the native wasm intrinsics which have tighter
-        // codegen. Note that this has a semantic difference in that the
-        // intrinsic can trap whereas `fptoui` never traps. That difference,
-        // however, is handled by `fptosui_may_trap` above.
+        // On WebAssembly the `fptoui` and `fptosi` instructions currently have
+        // poor codegen. The reason for this is that the corresponding wasm
+        // instructions, `i32.trunc_f32_s` for example, will trap when the float
+        // is out-of-bounds, infinity, or nan. This means that LLVM
+        // automatically inserts control flow around `fptoui` and `fptosi`
+        // because the LLVM instruction `fptoui` is defined as producing a
+        // poison value, not having UB on out-of-bounds values.
         //
-        // Note that we skip the wasm intrinsics for vector types where `fptoui`
-        // must be used instead.
-        if self.wasm_and_missing_nontrapping_fptoint() {
+        // This method, however, is only used with non-saturating casts that
+        // have UB on out-of-bounds values. This means that it's ok if we use
+        // the raw wasm instruction since out-of-bounds values can do whatever
+        // we like. To ensure that LLVM picks the right instruction we choose
+        // the raw wasm intrinsic functions which avoid LLVM inserting all the
+        // other control flow automatically.
+        if self.sess().target.arch == "wasm32" {
             let src_ty = self.cx.val_ty(val);
             if self.cx.type_kind(src_ty) != TypeKind::Vector {
                 let float_width = self.cx.float_width(src_ty);
@@ -765,7 +732,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn fptosi(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
-        if self.wasm_and_missing_nontrapping_fptoint() {
+        // see `fptoui` above for why wasm is different here
+        if self.sess().target.arch == "wasm32" {
             let src_ty = self.cx.val_ty(val);
             if self.cx.type_kind(src_ty) != TypeKind::Vector {
                 let float_width = self.cx.float_width(src_ty);
@@ -1420,8 +1388,11 @@ impl Builder<'a, 'll, 'tcx> {
         }
     }
 
-    fn wasm_and_missing_nontrapping_fptoint(&self) -> bool {
-        self.sess().target.arch == "wasm32"
-            && !self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
+    fn fptoint_sat_broken_in_llvm(&self) -> bool {
+        match self.tcx.sess.target.arch.as_str() {
+            // FIXME - https://bugs.llvm.org/show_bug.cgi?id=50083
+            "riscv64" => llvm_util::get_version() < (13, 0, 0),
+            _ => false,
+        }
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 773c0c16328..f5c54b11c08 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -503,14 +503,6 @@ impl CodegenCx<'b, 'tcx> {
         let t_f32 = self.type_f32();
         let t_f64 = self.type_f64();
 
-        ifn!("llvm.wasm.trunc.saturate.unsigned.i32.f32", fn(t_f32) -> t_i32);
-        ifn!("llvm.wasm.trunc.saturate.unsigned.i32.f64", fn(t_f64) -> t_i32);
-        ifn!("llvm.wasm.trunc.saturate.unsigned.i64.f32", fn(t_f32) -> t_i64);
-        ifn!("llvm.wasm.trunc.saturate.unsigned.i64.f64", fn(t_f64) -> t_i64);
-        ifn!("llvm.wasm.trunc.saturate.signed.i32.f32", fn(t_f32) -> t_i32);
-        ifn!("llvm.wasm.trunc.saturate.signed.i32.f64", fn(t_f64) -> t_i32);
-        ifn!("llvm.wasm.trunc.saturate.signed.i64.f32", fn(t_f32) -> t_i64);
-        ifn!("llvm.wasm.trunc.saturate.signed.i64.f64", fn(t_f64) -> t_i64);
         ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32);
         ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32);
         ifn!("llvm.wasm.trunc.unsigned.i64.f32", fn(t_f32) -> t_i64);
@@ -520,6 +512,28 @@ impl CodegenCx<'b, 'tcx> {
         ifn!("llvm.wasm.trunc.signed.i64.f32", fn(t_f32) -> t_i64);
         ifn!("llvm.wasm.trunc.signed.i64.f64", fn(t_f64) -> t_i64);
 
+        ifn!("llvm.fptosi.sat.i8.f32", fn(t_f32) -> t_i8);
+        ifn!("llvm.fptosi.sat.i16.f32", fn(t_f32) -> t_i16);
+        ifn!("llvm.fptosi.sat.i32.f32", fn(t_f32) -> t_i32);
+        ifn!("llvm.fptosi.sat.i64.f32", fn(t_f32) -> t_i64);
+        ifn!("llvm.fptosi.sat.i128.f32", fn(t_f32) -> t_i128);
+        ifn!("llvm.fptosi.sat.i8.f64", fn(t_f64) -> t_i8);
+        ifn!("llvm.fptosi.sat.i16.f64", fn(t_f64) -> t_i16);
+        ifn!("llvm.fptosi.sat.i32.f64", fn(t_f64) -> t_i32);
+        ifn!("llvm.fptosi.sat.i64.f64", fn(t_f64) -> t_i64);
+        ifn!("llvm.fptosi.sat.i128.f64", fn(t_f64) -> t_i128);
+
+        ifn!("llvm.fptoui.sat.i8.f32", fn(t_f32) -> t_i8);
+        ifn!("llvm.fptoui.sat.i16.f32", fn(t_f32) -> t_i16);
+        ifn!("llvm.fptoui.sat.i32.f32", fn(t_f32) -> t_i32);
+        ifn!("llvm.fptoui.sat.i64.f32", fn(t_f32) -> t_i64);
+        ifn!("llvm.fptoui.sat.i128.f32", fn(t_f32) -> t_i128);
+        ifn!("llvm.fptoui.sat.i8.f64", fn(t_f64) -> t_i8);
+        ifn!("llvm.fptoui.sat.i16.f64", fn(t_f64) -> t_i16);
+        ifn!("llvm.fptoui.sat.i32.f64", fn(t_f64) -> t_i32);
+        ifn!("llvm.fptoui.sat.i64.f64", fn(t_f64) -> t_i64);
+        ifn!("llvm.fptoui.sat.i128.f64", fn(t_f64) -> t_i128);
+
         ifn!("llvm.trap", fn() -> void);
         ifn!("llvm.debugtrap", fn() -> void);
         ifn!("llvm.frameaddress", fn(t_i32) -> i8p);
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 629cb64d43e..9917c23f121 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -11,7 +11,7 @@ use rustc_apfloat::{ieee, Float, Round, Status};
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir;
 use rustc_middle::ty::cast::{CastTy, IntTy};
-use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
+use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
 use rustc_span::source_map::{Span, DUMMY_SP};
 use rustc_span::symbol::sym;
@@ -385,10 +385,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 bx.inttoptr(usize_llval, ll_t_out)
                             }
                             (CastTy::Float, CastTy::Int(IntTy::I)) => {
-                                cast_float_to_int(&mut bx, true, llval, ll_t_in, ll_t_out, cast)
+                                cast_float_to_int(&mut bx, true, llval, ll_t_in, ll_t_out)
                             }
                             (CastTy::Float, CastTy::Int(_)) => {
-                                cast_float_to_int(&mut bx, false, llval, ll_t_in, ll_t_out, cast)
+                                cast_float_to_int(&mut bx, false, llval, ll_t_in, ll_t_out)
                             }
                             _ => bug!("unsupported cast: {:?} to {:?}", operand.layout.ty, cast.ty),
                         };
@@ -790,7 +790,6 @@ fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     x: Bx::Value,
     float_ty: Bx::Type,
     int_ty: Bx::Type,
-    int_layout: TyAndLayout<'tcx>,
 ) -> Bx::Value {
     if let Some(false) = bx.cx().sess().opts.debugging_opts.saturating_float_casts {
         return if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) };
@@ -891,134 +890,39 @@ fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     let int_min = bx.cx().const_uint_big(int_ty, int_min(signed, int_width) as u128);
     let zero = bx.cx().const_uint(int_ty, 0);
 
-    // The codegen here differs quite a bit depending on whether our builder's
-    // `fptosi` and `fptoui` instructions may trap for out-of-bounds values. If
-    // they don't trap then we can start doing everything inline with a
-    // `select` instruction because it's ok to execute `fptosi` and `fptoui`
-    // even if we don't use the results.
-    if !bx.fptosui_may_trap(x, int_ty) {
-        // Step 1 ...
-        let fptosui_result = if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) };
-        let less_or_nan = bx.fcmp(RealPredicate::RealULT, x, f_min);
-        let greater = bx.fcmp(RealPredicate::RealOGT, x, f_max);
-
-        // Step 2: We use two comparisons and two selects, with %s1 being the
-        // result:
-        //     %less_or_nan = fcmp ult %x, %f_min
-        //     %greater = fcmp olt %x, %f_max
-        //     %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
-        //     %s1 = select %greater, int_ty::MAX, %s0
-        // Note that %less_or_nan uses an *unordered* comparison. This
-        // comparison is true if the operands are not comparable (i.e., if x is
-        // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
-        // x is NaN.
-        //
-        // Performance note: Unordered comparison can be lowered to a "flipped"
-        // comparison and a negation, and the negation can be merged into the
-        // select. Therefore, it not necessarily any more expensive than a
-        // ordered ("normal") comparison. Whether these optimizations will be
-        // performed is ultimately up to the backend, but at least x86 does
-        // perform them.
-        let s0 = bx.select(less_or_nan, int_min, fptosui_result);
-        let s1 = bx.select(greater, int_max, s0);
-
-        // Step 3: NaN replacement.
-        // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN.
-        // Therefore we only need to execute this step for signed integer types.
-        if signed {
-            // LLVM has no isNaN predicate, so we use (x == x) instead
-            let cmp = bx.fcmp(RealPredicate::RealOEQ, x, x);
-            bx.select(cmp, s1, zero)
-        } else {
-            s1
-        }
+    // Step 1 ...
+    let fptosui_result = if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) };
+    let less_or_nan = bx.fcmp(RealPredicate::RealULT, x, f_min);
+    let greater = bx.fcmp(RealPredicate::RealOGT, x, f_max);
+
+    // Step 2: We use two comparisons and two selects, with %s1 being the
+    // result:
+    //     %less_or_nan = fcmp ult %x, %f_min
+    //     %greater = fcmp olt %x, %f_max
+    //     %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
+    //     %s1 = select %greater, int_ty::MAX, %s0
+    // Note that %less_or_nan uses an *unordered* comparison. This
+    // comparison is true if the operands are not comparable (i.e., if x is
+    // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
+    // x is NaN.
+    //
+    // Performance note: Unordered comparison can be lowered to a "flipped"
+    // comparison and a negation, and the negation can be merged into the
+    // select. Therefore, it not necessarily any more expensive than a
+    // ordered ("normal") comparison. Whether these optimizations will be
+    // performed is ultimately up to the backend, but at least x86 does
+    // perform them.
+    let s0 = bx.select(less_or_nan, int_min, fptosui_result);
+    let s1 = bx.select(greater, int_max, s0);
+
+    // Step 3: NaN replacement.
+    // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN.
+    // Therefore we only need to execute this step for signed integer types.
+    if signed {
+        // LLVM has no isNaN predicate, so we use (x == x) instead
+        let cmp = bx.fcmp(RealPredicate::RealOEQ, x, x);
+        bx.select(cmp, s1, zero)
     } else {
-        // In this case we cannot execute `fptosi` or `fptoui` and then later
-        // discard the result. The builder is telling us that these instructions
-        // will trap on out-of-bounds values, so we need to use basic blocks and
-        // control flow to avoid executing the `fptosi` and `fptoui`
-        // instructions.
-        //
-        // The general idea of what we're constructing here is, for f64 -> i32:
-        //
-        //      ;; block so far... %0 is the argument
-        //      %result = alloca i32, align 4
-        //      %inbound_lower = fcmp oge double %0, 0xC1E0000000000000
-        //      %inbound_upper = fcmp ole double %0, 0x41DFFFFFFFC00000
-        //      ;; match (inbound_lower, inbound_upper) {
-        //      ;;     (true, true) => %0 can be converted without trapping
-        //      ;;     (false, false) => %0 is a NaN
-        //      ;;     (true, false) => %0 is too large
-        //      ;;     (false, true) => %0 is too small
-        //      ;; }
-        //      ;;
-        //      ;; The (true, true) check, go to %convert if so.
-        //      %inbounds = and i1 %inbound_lower, %inbound_upper
-        //      br i1 %inbounds, label %convert, label %specialcase
-        //
-        //  convert:
-        //      %cvt = call i32 @llvm.wasm.trunc.signed.i32.f64(double %0)
-        //      store i32 %cvt, i32* %result, align 4
-        //      br label %done
-        //
-        //  specialcase:
-        //      ;; Handle the cases where the number is NaN, too large or too small
-        //
-        //      ;; Either (true, false) or (false, true)
-        //      %is_not_nan = or i1 %inbound_lower, %inbound_upper
-        //      ;; Figure out which saturated value we are interested in if not `NaN`
-        //      %saturated = select i1 %inbound_lower, i32 2147483647, i32 -2147483648
-        //      ;; Figure out between saturated and NaN representations
-        //      %result_nan = select i1 %is_not_nan, i32 %saturated, i32 0
-        //      store i32 %result_nan, i32* %result, align 4
-        //      br label %done
-        //
-        //  done:
-        //      %r = load i32, i32* %result, align 4
-        //      ;; ...
-        let done = bx.build_sibling_block("float_cast_done");
-        let mut convert = bx.build_sibling_block("float_cast_convert");
-        let mut specialcase = bx.build_sibling_block("float_cast_specialcase");
-
-        let result = PlaceRef::alloca(bx, int_layout);
-        result.storage_live(bx);
-
-        // Use control flow to figure out whether we can execute `fptosi` in a
-        // basic block, or whether we go to a different basic block to implement
-        // the saturating logic.
-        let inbound_lower = bx.fcmp(RealPredicate::RealOGE, x, f_min);
-        let inbound_upper = bx.fcmp(RealPredicate::RealOLE, x, f_max);
-        let inbounds = bx.and(inbound_lower, inbound_upper);
-        bx.cond_br(inbounds, convert.llbb(), specialcase.llbb());
-
-        // Translation of the `convert` basic block
-        let cvt = if signed { convert.fptosi(x, int_ty) } else { convert.fptoui(x, int_ty) };
-        convert.store(cvt, result.llval, result.align);
-        convert.br(done.llbb());
-
-        // Translation of the `specialcase` basic block. Note that like above
-        // we try to be a bit clever here for unsigned conversions. In those
-        // cases the `int_min` is zero so we don't need two select instructions,
-        // just one to choose whether we need `int_max` or not. If
-        // `inbound_lower` is true then we're guaranteed to not be `NaN` and
-        // since we're greater than zero we must be saturating to `int_max`. If
-        // `inbound_lower` is false then we're either NaN or less than zero, so
-        // we saturate to zero.
-        let result_nan = if signed {
-            let is_not_nan = specialcase.or(inbound_lower, inbound_upper);
-            let saturated = specialcase.select(inbound_lower, int_max, int_min);
-            specialcase.select(is_not_nan, saturated, zero)
-        } else {
-            specialcase.select(inbound_lower, int_max, int_min)
-        };
-        specialcase.store(result_nan, result.llval, result.align);
-        specialcase.br(done.llbb());
-
-        // Translation of the `done` basic block, positioning ourselves to
-        // continue from that point as well.
-        *bx = done;
-        let ret = bx.load(result.llval, result.align);
-        result.storage_dead(bx);
-        ret
+        s1
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index d5bd2780388..1bc05f30e5c 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -171,7 +171,6 @@ pub trait BuilderMethods<'a, 'tcx>:
     fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
     fn fptoui_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Option<Self::Value>;
     fn fptosi_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Option<Self::Value>;
-    fn fptosui_may_trap(&self, val: Self::Value, dest_ty: Self::Type) -> bool;
     fn fptoui(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
     fn fptosi(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
     fn uitofp(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
diff --git a/compiler/rustc_error_codes/src/error_codes/E0404.md b/compiler/rustc_error_codes/src/error_codes/E0404.md
index 1360cc99afc..d6fa51e618c 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0404.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0404.md
@@ -8,14 +8,15 @@ struct Foo;
 struct Bar;
 
 impl Foo for Bar {} // error: `Foo` is not a trait
+fn baz<T: Foo>(t: T) {} // error: `Foo` is not a trait
 ```
 
 Another erroneous code example:
 
 ```compile_fail,E0404
-struct Foo;
+type Foo = Iterator<Item=String>;
 
-fn bar<T: Foo>(t: T) {} // error: `Foo` is not a trait
+fn bar<T: Foo>(t: T) {} // error: `Foo` is a type alias
 ```
 
 Please verify that the trait's name was not misspelled or that the right
@@ -30,14 +31,27 @@ struct Bar;
 impl Foo for Bar { // ok!
     // functions implementation
 }
+
+fn baz<T: Foo>(t: T) {} // ok!
 ```
 
-or:
+Alternatively, you could introduce a new trait with your desired restrictions
+as a super trait:
 
 ```
-trait Foo {
-    // some functions
-}
+# trait Foo {}
+# struct Bar;
+# impl Foo for Bar {}
+trait Qux: Foo {} // Anything that implements Qux also needs to implement Foo
+fn baz<T: Qux>(t: T) {} // also ok!
+```
+
+Finally, if you are on nightly and want to use a trait alias
+instead of a type alias, you should use `#![feature(trait_alias)]`:
+
+```
+#![feature(trait_alias)]
+trait Foo = Iterator<Item=String>;
 
 fn bar<T: Foo>(t: T) {} // ok!
 ```
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 1051fb8cea2..685429863fa 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2201,7 +2201,7 @@ impl PrimTy {
 
     /// Like [`PrimTy::name`], but returns a &str instead of a symbol.
     ///
-    /// Used by rustdoc.
+    /// Used by clippy.
     pub fn name_str(self) -> &'static str {
         match self {
             PrimTy::Int(i) => i.name_str(),
diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs
index 93133e9b7f0..60757178bec 100644
--- a/compiler/rustc_mir/src/transform/coverage/mod.rs
+++ b/compiler/rustc_mir/src/transform/coverage/mod.rs
@@ -111,7 +111,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         let body_span = hir_body.value.span;
         let source_file = source_map.lookup_source_file(body_span.lo());
         let fn_sig_span = match some_fn_sig.filter(|fn_sig| {
-            Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.hi()))
+            fn_sig.span.ctxt() == body_span.ctxt()
+                && Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.hi()))
         }) {
             Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()),
             None => body_span.shrink_to_lo(),
diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs
index 067e1001def..249f5e835cd 100644
--- a/compiler/rustc_mir/src/transform/coverage/spans.rs
+++ b/compiler/rustc_mir/src/transform/coverage/spans.rs
@@ -240,13 +240,13 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
     /// to be).
     pub(super) fn generate_coverage_spans(
         mir_body: &'a mir::Body<'tcx>,
-        fn_sig_span: Span,
+        fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span`
         body_span: Span,
         basic_coverage_blocks: &'a CoverageGraph,
     ) -> Vec<CoverageSpan> {
         let mut coverage_spans = CoverageSpans {
             mir_body,
-            fn_sig_span: fn_sig_source_span(fn_sig_span, body_span),
+            fn_sig_span,
             body_span,
             basic_coverage_blocks,
             sorted_spans_iter: None,
@@ -732,11 +732,6 @@ pub(super) fn filtered_terminator_span(
 }
 
 #[inline]
-fn fn_sig_source_span(fn_sig_span: Span, body_span: Span) -> Span {
-    original_sp(fn_sig_span, body_span).with_ctxt(body_span.ctxt())
-}
-
-#[inline]
 fn function_source_span(span: Span, body_span: Span) -> Span {
     let span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
     if body_span.contains(span) { span } else { body_span }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 6fae6921fc9..e33c374f562 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -930,7 +930,14 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                     let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \
                                `type` alias";
                     if let Some(span) = self.def_span(def_id) {
-                        err.span_help(span, msg);
+                        if let Ok(snip) = self.r.session.source_map().span_to_snippet(span) {
+                            // The span contains a type alias so we should be able to
+                            // replace `type` with `trait`.
+                            let snip = snip.replacen("type", "trait", 1);
+                            err.span_suggestion(span, msg, snip, Applicability::MaybeIncorrect);
+                        } else {
+                            err.span_help(span, msg);
+                        }
                     } else {
                         err.help(msg);
                     }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index b683626bbd6..52a6e4ff924 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -797,7 +797,7 @@ pub const fn default_lib_output() -> CrateType {
     CrateType::Rlib
 }
 
-pub fn default_configuration(sess: &Session) -> CrateConfig {
+fn default_configuration(sess: &Session) -> CrateConfig {
     let end = &sess.target.endian;
     let arch = &sess.target.arch;
     let wordsz = sess.target.pointer_width.to_string();
@@ -892,7 +892,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo
     user_cfg
 }
 
-pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
+pub(super) fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
     let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
     let target = target_result.unwrap_or_else(|e| {
         early_error(
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 52270f0e627..1d1471fdeca 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -796,7 +796,6 @@ symbols! {
         non_modrs_mods,
         none_error,
         nontemporal_store,
-        nontrapping_dash_fptoint: "nontrapping-fptoint",
         noop_method_borrow,
         noop_method_clone,
         noop_method_deref,
diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs
index 58a9ae77244..528ee4ff154 100644
--- a/library/alloc/src/task.rs
+++ b/library/alloc/src/task.rs
@@ -87,6 +87,9 @@ pub trait Wake {
 
 #[stable(feature = "wake_trait", since = "1.51.0")]
 impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
+    /// Use a `Wake`-able type as a `Waker`.
+    ///
+    /// No heap allocations or atomic operations are used for this conversion.
     fn from(waker: Arc<W>) -> Waker {
         // SAFETY: This is safe because raw_waker safely constructs
         // a RawWaker from Arc<W>.
@@ -96,6 +99,9 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
 
 #[stable(feature = "wake_trait", since = "1.51.0")]
 impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
+    /// Use a `Wake`-able type as a `RawWaker`.
+    ///
+    /// No heap allocations or atomic operations are used for this conversion.
     fn from(waker: Arc<W>) -> RawWaker {
         raw_waker(waker)
     }
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 1b78356fde5..e459442dfcf 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2810,8 +2810,7 @@ impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
     /// assert_eq!(Vec::from(b), vec![1, 2, 3]);
     /// ```
     fn from(s: Box<[T], A>) -> Self {
-        let len = s.len();
-        Self { buf: RawVec::from_box(s), len }
+        s.into_vec()
     }
 }
 
diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs
index 5b113610a5d..a522b7da3bd 100644
--- a/library/core/src/convert/num.rs
+++ b/library/core/src/convert/num.rs
@@ -45,8 +45,10 @@ impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
 macro_rules! impl_from {
     ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
         #[$attr]
-        #[doc = $doc]
         impl From<$Small> for $Large {
+            // Rustdocs on the impl block show a "[+] show undocumented items" toggle.
+            // Rustdocs on functions do not.
+            #[doc = $doc]
             #[inline]
             fn from(small: $Small) -> Self {
                 small as Self
@@ -383,8 +385,10 @@ use crate::num::NonZeroUsize;
 macro_rules! nzint_impl_from {
     ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => {
         #[$attr]
-        #[doc = $doc]
         impl From<$Small> for $Large {
+            // Rustdocs on the impl block show a "[+] show undocumented items" toggle.
+            // Rustdocs on functions do not.
+            #[doc = $doc]
             #[inline]
             fn from(small: $Small) -> Self {
                 // SAFETY: input type guarantees the value is non-zero
@@ -450,10 +454,12 @@ nzint_impl_from! { NonZeroU64, NonZeroI128, #[stable(feature = "nz_int_conv", si
 macro_rules! nzint_impl_try_from_int {
     ($Int: ty, $NonZeroInt: ty, #[$attr:meta], $doc: expr) => {
         #[$attr]
-        #[doc = $doc]
         impl TryFrom<$Int> for $NonZeroInt {
             type Error = TryFromIntError;
 
+            // Rustdocs on the impl block show a "[+] show undocumented items" toggle.
+            // Rustdocs on functions do not.
+            #[doc = $doc]
             #[inline]
             fn try_from(value: $Int) -> Result<Self, Self::Error> {
                 Self::new(value).ok_or(TryFromIntError(()))
@@ -489,10 +495,12 @@ nzint_impl_try_from_int! { isize, NonZeroIsize, #[stable(feature = "nzint_try_fr
 macro_rules! nzint_impl_try_from_nzint {
     ($From:ty => $To:ty, $doc: expr) => {
         #[stable(feature = "nzint_try_from_nzint_conv", since = "1.49.0")]
-        #[doc = $doc]
         impl TryFrom<$From> for $To {
             type Error = TryFromIntError;
 
+            // Rustdocs on the impl block show a "[+] show undocumented items" toggle.
+            // Rustdocs on functions do not.
+            #[doc = $doc]
             #[inline]
             fn try_from(value: $From) -> Result<Self, Self::Error> {
                 TryFrom::try_from(value.get()).map(|v| {
diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs
index 9efc7a480ae..54a47f1323e 100644
--- a/library/core/src/iter/adapters/take.rs
+++ b/library/core/src/iter/adapters/take.rs
@@ -1,5 +1,8 @@
 use crate::cmp;
-use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
+use crate::iter::{
+    adapters::zip::try_get_unchecked, adapters::SourceIter, FusedIterator, InPlaceIterable,
+    TrustedLen, TrustedRandomAccess,
+};
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator that only iterates over the first `n` iterations of `iter`.
@@ -111,6 +114,15 @@ where
 
         self.try_fold(init, ok(fold)).unwrap()
     }
+
+    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <I as Iterator>::Item
+    where
+        Self: TrustedRandomAccess,
+    {
+        // SAFETY: the caller must uphold the contract for
+        // `Iterator::__iterator_get_unchecked`.
+        unsafe { try_get_unchecked(&mut self.iter, idx) }
+    }
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
@@ -207,3 +219,12 @@ impl<I> FusedIterator for Take<I> where I: FusedIterator {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<I: TrustedLen> TrustedLen for Take<I> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<I> TrustedRandomAccess for Take<I>
+where
+    I: TrustedRandomAccess,
+{
+    const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
+}
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index c0cab86cf62..7977d599ae7 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -1651,31 +1651,16 @@ pub trait Iterator {
     /// Basic usage:
     ///
     /// ```
-    /// let a = [1, 2, 3];
-    ///
-    /// let iter = a.iter();
-    ///
-    /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i);
-    ///
-    /// assert_eq!(sum, 6);
-    ///
-    /// // if we try to use iter again, it won't work. The following line
-    /// // gives "error: use of moved value: `iter`
-    /// // assert_eq!(iter.next(), None);
+    /// let mut words = vec!["hello", "world", "of", "Rust"].into_iter();
     ///
-    /// // let's try that again
-    /// let a = [1, 2, 3];
-    ///
-    /// let mut iter = a.iter();
-    ///
-    /// // instead, we add in a .by_ref()
-    /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i);
+    /// // Take the first two words.
+    /// let hello_world: Vec<_> = words.by_ref().take(2).collect();
+    /// assert_eq!(hello_world, vec!["hello", "world"]);
     ///
-    /// assert_eq!(sum, 3);
-    ///
-    /// // now this is just fine:
-    /// assert_eq!(iter.next(), Some(&3));
-    /// assert_eq!(iter.next(), None);
+    /// // Collect the rest of the words.
+    /// // We can only do this because we used `by_ref` earlier.
+    /// let of_rust: Vec<_> = words.collect();
+    /// assert_eq!(of_rust, vec!["of", "Rust"]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn by_ref(&mut self) -> &mut Self
diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs
index 60be63c9543..2f0b32c90d0 100644
--- a/library/std/src/sync/condvar.rs
+++ b/library/std/src/sync/condvar.rs
@@ -2,9 +2,8 @@
 mod tests;
 
 use crate::fmt;
-use crate::sync::{mutex, MutexGuard, PoisonError};
+use crate::sync::{mutex, poison, LockResult, MutexGuard, PoisonError};
 use crate::sys_common::condvar as sys;
-use crate::sys_common::poison::{self, LockResult};
 use crate::time::{Duration, Instant};
 
 /// A type indicating whether a timed wait on a condition variable returned
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index b6699910b07..ee35598bab5 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -166,9 +166,9 @@ pub use self::mutex::{Mutex, MutexGuard};
 #[allow(deprecated)]
 pub use self::once::{Once, OnceState, ONCE_INIT};
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
+pub use self::poison::{LockResult, PoisonError, TryLockError, TryLockResult};
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys_common::poison::{LockResult, PoisonError, TryLockError, TryLockResult};
+pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
 
 pub mod mpsc;
 
@@ -176,4 +176,5 @@ mod barrier;
 mod condvar;
 mod mutex;
 mod once;
+mod poison;
 mod rwlock;
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index 98c34282e0c..2615bea6592 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -6,8 +6,8 @@ use crate::fmt;
 use crate::mem;
 use crate::ops::{Deref, DerefMut};
 use crate::ptr;
+use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
 use crate::sys_common::mutex as sys;
-use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
 
 /// A mutual exclusion primitive useful for protecting shared data
 ///
diff --git a/library/std/src/sys_common/poison.rs b/library/std/src/sync/poison.rs
index 1f71187f1b4..05e1833c3e5 100644
--- a/library/std/src/sys_common/poison.rs
+++ b/library/std/src/sync/poison.rs
@@ -3,9 +3,6 @@ use crate::fmt;
 use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::thread;
 
-#[allow(unused_imports)] // for intra-doc links
-use crate::sync::{Mutex, RwLock};
-
 pub struct Flag {
     failed: AtomicBool,
 }
@@ -80,6 +77,8 @@ pub struct Guard {
 ///     }
 /// };
 /// ```
+/// [`Mutex`]: crate::sync::Mutex
+/// [`RwLock`]: crate::sync::RwLock
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct PoisonError<T> {
     guard: T,
@@ -89,9 +88,11 @@ pub struct PoisonError<T> {
 /// can occur while trying to acquire a lock, from the [`try_lock`] method on a
 /// [`Mutex`] or the [`try_read`] and [`try_write`] methods on an [`RwLock`].
 ///
-/// [`try_lock`]: Mutex::try_lock
-/// [`try_read`]: RwLock::try_read
-/// [`try_write`]: RwLock::try_write
+/// [`try_lock`]: crate::sync::Mutex::try_lock
+/// [`try_read`]: crate::sync::RwLock::try_read
+/// [`try_write`]: crate::sync::RwLock::try_write
+/// [`Mutex`]: crate::sync::Mutex
+/// [`RwLock`]: crate::sync::RwLock
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum TryLockError<T> {
     /// The lock could not be acquired because another thread failed while holding
@@ -149,7 +150,8 @@ impl<T> Error for PoisonError<T> {
 impl<T> PoisonError<T> {
     /// Creates a `PoisonError`.
     ///
-    /// This is generally created by methods like [`Mutex::lock`] or [`RwLock::read`].
+    /// This is generally created by methods like [`Mutex::lock`](crate::sync::Mutex::lock)
+    /// or [`RwLock::read`](crate::sync::RwLock::read).
     #[stable(feature = "sync_poison", since = "1.2.0")]
     pub fn new(guard: T) -> PoisonError<T> {
         PoisonError { guard }
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index 351804ec979..b01bcec1361 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -6,7 +6,7 @@ use crate::fmt;
 use crate::mem;
 use crate::ops::{Deref, DerefMut};
 use crate::ptr;
-use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
+use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
 use crate::sys_common::rwlock as sys;
 
 /// A reader-writer lock
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 23a3a0e907d..4979bc0b5af 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -59,7 +59,6 @@ pub mod mutex;
 // when generating documentation.
 #[cfg(any(doc, not(windows)))]
 pub mod os_str_bytes;
-pub mod poison;
 pub mod process;
 pub mod remutex;
 pub mod rwlock;
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 68e7dc80067..13ee909afd5 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -17,6 +17,11 @@ use crate::Compiler;
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::config::{Config, TargetSelection};
 
+#[cfg(target_os = "illumos")]
+const SHELL: &str = "bash";
+#[cfg(not(target_os = "illumos"))]
+const SHELL: &str = "sh";
+
 fn install_sh(
     builder: &Builder<'_>,
     package: &str,
@@ -37,7 +42,7 @@ fn install_sh(
     let empty_dir = builder.out.join("tmp/empty_dir");
     t!(fs::create_dir_all(&empty_dir));
 
-    let mut cmd = Command::new("sh");
+    let mut cmd = Command::new(SHELL);
     cmd.current_dir(&empty_dir)
         .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh")))
         .arg(format!("--prefix={}", prepare_dir(prefix)))
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index f352746d3fb..25b56b96ed2 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -179,7 +179,7 @@ target | std | host | notes
 `i386-apple-ios` | ✓ |  | 32-bit x86 iOS
 `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
 `i686-pc-windows-msvc` | ✓ |  | 32-bit Windows XP support
-`i686-unknown-uefi` | ? |  | 32-bit UEFI
+`i686-unknown-uefi` | * |  | 32-bit UEFI
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
 `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
 `i686-unknown-openbsd` | ✓ | ✓ | 32-bit OpenBSD
@@ -228,7 +228,7 @@ target | std | host | notes
 `x86_64-unknown-none-hermitkernel` | ? |  | HermitCore kernel
 `x86_64-unknown-l4re-uclibc` | ? |  |
 `x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD
-`x86_64-unknown-uefi` | ? |  |
+`x86_64-unknown-uefi` | * |  | 64-bit UEFI
 `x86_64-uwp-windows-gnu` | ✓ |  |
 `x86_64-uwp-windows-msvc` | ✓ |  |
 `x86_64-wrs-vxworks` | ? |  |
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7d33cf21013..72046645e3a 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -84,123 +84,8 @@ impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
 
 impl Clean<ExternalCrate> for CrateNum {
     fn clean(&self, cx: &mut DocContext<'_>) -> ExternalCrate {
-        let tcx = cx.tcx;
         let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
-        let krate_span = tcx.def_span(root);
-        let krate_src = cx.sess().source_map().span_to_filename(krate_span);
-
-        // Collect all inner modules which are tagged as implementations of
-        // primitives.
-        //
-        // Note that this loop only searches the top-level items of the crate,
-        // and this is intentional. If we were to search the entire crate for an
-        // item tagged with `#[doc(primitive)]` then we would also have to
-        // search the entirety of external modules for items tagged
-        // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
-        // all that metadata unconditionally).
-        //
-        // In order to keep the metadata load under control, the
-        // `#[doc(primitive)]` feature is explicitly designed to only allow the
-        // primitive tags to show up as the top level items in a crate.
-        //
-        // Also note that this does not attempt to deal with modules tagged
-        // duplicately for the same primitive. This is handled later on when
-        // rendering by delegating everything to a hash map.
-        let mut as_primitive = |res: Res| {
-            if let Res::Def(DefKind::Mod, def_id) = res {
-                let attrs = cx.tcx.get_attrs(def_id).clean(cx);
-                let mut prim = None;
-                for attr in attrs.lists(sym::doc) {
-                    if let Some(v) = attr.value_str() {
-                        if attr.has_name(sym::primitive) {
-                            prim = PrimitiveType::from_symbol(v);
-                            if prim.is_some() {
-                                break;
-                            }
-                            // FIXME: should warn on unknown primitives?
-                        }
-                    }
-                }
-                return prim.map(|p| (def_id, p));
-            }
-            None
-        };
-        let primitives = if root.is_local() {
-            tcx.hir()
-                .krate()
-                .item
-                .item_ids
-                .iter()
-                .filter_map(|&id| {
-                    let item = tcx.hir().item(id);
-                    match item.kind {
-                        hir::ItemKind::Mod(_) => {
-                            as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
-                        }
-                        hir::ItemKind::Use(ref path, hir::UseKind::Single)
-                            if item.vis.node.is_pub() =>
-                        {
-                            as_primitive(path.res).map(|(_, prim)| {
-                                // Pretend the primitive is local.
-                                (id.def_id.to_def_id(), prim)
-                            })
-                        }
-                        _ => None,
-                    }
-                })
-                .collect()
-        } else {
-            tcx.item_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
-        };
-
-        let mut as_keyword = |res: Res| {
-            if let Res::Def(DefKind::Mod, def_id) = res {
-                let attrs = tcx.get_attrs(def_id).clean(cx);
-                let mut keyword = None;
-                for attr in attrs.lists(sym::doc) {
-                    if attr.has_name(sym::keyword) {
-                        if let Some(v) = attr.value_str() {
-                            keyword = Some(v);
-                            break;
-                        }
-                    }
-                }
-                return keyword.map(|p| (def_id, p));
-            }
-            None
-        };
-        let keywords = if root.is_local() {
-            tcx.hir()
-                .krate()
-                .item
-                .item_ids
-                .iter()
-                .filter_map(|&id| {
-                    let item = tcx.hir().item(id);
-                    match item.kind {
-                        hir::ItemKind::Mod(_) => {
-                            as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
-                        }
-                        hir::ItemKind::Use(ref path, hir::UseKind::Single)
-                            if item.vis.node.is_pub() =>
-                        {
-                            as_keyword(path.res).map(|(_, prim)| (id.def_id.to_def_id(), prim))
-                        }
-                        _ => None,
-                    }
-                })
-                .collect()
-        } else {
-            tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
-        };
-
-        ExternalCrate {
-            name: tcx.crate_name(*self),
-            src: krate_src,
-            attrs: tcx.get_attrs(root).clean(cx),
-            primitives,
-            keywords,
-        }
+        ExternalCrate { crate_num: *self, attrs: cx.tcx.get_attrs(root).clean(cx) }
     }
 }
 
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 675de640c70..1acde8401b2 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -17,8 +17,8 @@ use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex};
+use rustc_hir::def::{CtorKind, DefKind, Res};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{BodyId, Mutability};
 use rustc_index::vec::IndexVec;
@@ -72,11 +72,138 @@ crate struct TraitWithExtraInfo {
 
 #[derive(Clone, Debug)]
 crate struct ExternalCrate {
-    crate name: Symbol,
-    crate src: FileName,
+    crate crate_num: CrateNum,
     crate attrs: Attributes,
-    crate primitives: ThinVec<(DefId, PrimitiveType)>,
-    crate keywords: ThinVec<(DefId, Symbol)>,
+}
+
+impl ExternalCrate {
+    #[inline]
+    fn def_id(&self) -> DefId {
+        DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }
+    }
+
+    crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
+        let krate_span = tcx.def_span(self.def_id());
+        tcx.sess.source_map().span_to_filename(krate_span)
+    }
+
+    crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
+        tcx.crate_name(self.crate_num)
+    }
+
+    crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
+        let root = self.def_id();
+
+        let as_keyword = |res: Res| {
+            if let Res::Def(DefKind::Mod, def_id) = res {
+                let attrs = tcx.get_attrs(def_id);
+                let mut keyword = None;
+                for attr in attrs.lists(sym::doc) {
+                    if attr.has_name(sym::keyword) {
+                        if let Some(v) = attr.value_str() {
+                            keyword = Some(v);
+                            break;
+                        }
+                    }
+                }
+                return keyword.map(|p| (def_id, p));
+            }
+            None
+        };
+        if root.is_local() {
+            tcx.hir()
+                .krate()
+                .item
+                .item_ids
+                .iter()
+                .filter_map(|&id| {
+                    let item = tcx.hir().item(id);
+                    match item.kind {
+                        hir::ItemKind::Mod(_) => {
+                            as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
+                        }
+                        hir::ItemKind::Use(ref path, hir::UseKind::Single)
+                            if item.vis.node.is_pub() =>
+                        {
+                            as_keyword(path.res).map(|(_, prim)| (id.def_id.to_def_id(), prim))
+                        }
+                        _ => None,
+                    }
+                })
+                .collect()
+        } else {
+            tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
+        }
+    }
+
+    crate fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> {
+        let root = self.def_id();
+
+        // Collect all inner modules which are tagged as implementations of
+        // primitives.
+        //
+        // Note that this loop only searches the top-level items of the crate,
+        // and this is intentional. If we were to search the entire crate for an
+        // item tagged with `#[doc(primitive)]` then we would also have to
+        // search the entirety of external modules for items tagged
+        // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
+        // all that metadata unconditionally).
+        //
+        // In order to keep the metadata load under control, the
+        // `#[doc(primitive)]` feature is explicitly designed to only allow the
+        // primitive tags to show up as the top level items in a crate.
+        //
+        // Also note that this does not attempt to deal with modules tagged
+        // duplicately for the same primitive. This is handled later on when
+        // rendering by delegating everything to a hash map.
+        let as_primitive = |res: Res| {
+            if let Res::Def(DefKind::Mod, def_id) = res {
+                let attrs = tcx.get_attrs(def_id);
+                let mut prim = None;
+                for attr in attrs.lists(sym::doc) {
+                    if let Some(v) = attr.value_str() {
+                        if attr.has_name(sym::primitive) {
+                            prim = PrimitiveType::from_symbol(v);
+                            if prim.is_some() {
+                                break;
+                            }
+                            // FIXME: should warn on unknown primitives?
+                        }
+                    }
+                }
+                return prim.map(|p| (def_id, p));
+            }
+            None
+        };
+
+        if root.is_local() {
+            tcx.hir()
+                .krate()
+                .item
+                .item_ids
+                .iter()
+                .filter_map(|&id| {
+                    let item = tcx.hir().item(id);
+                    match item.kind {
+                        hir::ItemKind::Mod(_) => {
+                            as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
+                        }
+                        hir::ItemKind::Use(ref path, hir::UseKind::Single)
+                            if item.vis.node.is_pub() =>
+                        {
+                            as_primitive(path.res).map(|(_, prim)| {
+                                // Pretend the primitive is local.
+                                (id.def_id.to_def_id(), prim)
+                            })
+                        }
+                        _ => None,
+                    }
+                })
+                .collect()
+        } else {
+            tcx.item_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
+        }
+    }
 }
 
 /// Anything with a source location and set of attributes and, optionally, a
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index c2a971d6375..55a0cb42a20 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -1,9 +1,9 @@
 use crate::clean::auto_trait::AutoTraitFinder;
 use crate::clean::blanket_impl::BlanketImplFinder;
 use crate::clean::{
-    inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item,
-    ItemKind, Lifetime, MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type,
-    TypeBinding, TypeKind,
+    inline, Clean, Crate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime,
+    MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding,
+    TypeKind,
 };
 use crate::core::DocContext;
 
@@ -54,7 +54,11 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate {
         _ => unreachable!(),
     }
 
-    let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
+    let local_crate = LOCAL_CRATE.clean(cx);
+    let src = local_crate.src(cx.tcx);
+    let name = local_crate.name(cx.tcx);
+    let primitives = local_crate.primitives(cx.tcx);
+    let keywords = local_crate.keywords(cx.tcx);
     {
         let m = match *module.kind {
             ItemKind::ModuleItem(ref mut m) => m,
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index b2b895cc672..9a61f963a3e 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -155,19 +155,20 @@ impl Cache {
         // Cache where all our extern crates are located
         // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code
         for &(n, ref e) in &krate.externs {
-            let src_root = match e.src {
+            let src_root = match e.src(tcx) {
                 FileName::Real(ref p) => match p.local_path().parent() {
                     Some(p) => p.to_path_buf(),
                     None => PathBuf::new(),
                 },
                 _ => PathBuf::new(),
             };
-            let extern_url = extern_html_root_urls.get(&*e.name.as_str()).map(|u| &**u);
+            let name = e.name(tcx);
+            let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u);
             self.extern_locations
-                .insert(n, (e.name, src_root, extern_location(e, extern_url, &dst)));
+                .insert(n, (name, src_root, extern_location(e, extern_url, &dst, tcx)));
 
             let did = DefId { krate: n, index: CRATE_DEF_INDEX };
-            self.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
+            self.external_paths.insert(did, (vec![name.to_string()], ItemType::Module));
         }
 
         // Cache where all known primitives have their documentation located.
@@ -175,7 +176,7 @@ impl Cache {
         // Favor linking to as local extern as possible, so iterate all crates in
         // reverse topological order.
         for &(_, ref e) in krate.externs.iter().rev() {
-            for &(def_id, prim) in &e.primitives {
+            for &(def_id, prim) in &e.primitives(tcx) {
                 self.primitive_locations.insert(prim, def_id);
             }
         }
diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs
index ae97cd64fb5..b8ef3384c59 100644
--- a/src/librustdoc/formats/renderer.rs
+++ b/src/librustdoc/formats/renderer.rs
@@ -1,5 +1,5 @@
 use rustc_middle::ty::TyCtxt;
-use rustc_span::{edition::Edition, Symbol};
+use rustc_span::Symbol;
 
 use crate::clean;
 use crate::config::RenderOptions;
@@ -23,7 +23,6 @@ crate trait FormatRenderer<'tcx>: Sized {
     fn init(
         krate: clean::Crate,
         options: RenderOptions,
-        edition: Edition,
         cache: Cache,
         tcx: TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error>;
@@ -35,19 +34,15 @@ crate trait FormatRenderer<'tcx>: Sized {
     fn item(&mut self, item: clean::Item) -> Result<(), Error>;
 
     /// Renders a module (should not handle recursing into children).
-    fn mod_item_in(&mut self, item: &clean::Item, item_name: &str) -> Result<(), Error>;
+    fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error>;
 
     /// Runs after recursively rendering all sub-items of a module.
-    fn mod_item_out(&mut self, item_name: &str) -> Result<(), Error>;
+    fn mod_item_out(&mut self) -> Result<(), Error> {
+        Ok(())
+    }
 
     /// 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,
-        crate_name: Symbol,
-        diag: &rustc_errors::Handler,
-    ) -> Result<(), Error>;
+    fn after_krate(&mut self) -> Result<(), Error>;
 
     fn cache(&self) -> &Cache;
 }
@@ -57,8 +52,6 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
     krate: clean::Crate,
     options: RenderOptions,
     cache: Cache,
-    diag: &rustc_errors::Handler,
-    edition: Edition,
     tcx: TyCtxt<'tcx>,
 ) -> Result<(), Error> {
     let prof = &tcx.sess.prof;
@@ -66,14 +59,13 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
     let emit_crate = options.should_emit_crate();
     let (mut format_renderer, krate) = prof
         .extra_verbose_generic_activity("create_renderer", T::descr())
-        .run(|| T::init(krate, options, edition, cache, tcx))?;
+        .run(|| T::init(krate, options, cache, tcx))?;
 
     if !emit_crate {
         return Ok(());
     }
 
     // Render the crate documentation
-    let crate_name = krate.name;
     let mut work = vec![(format_renderer.make_child_renderer(), krate.module)];
 
     let unknown = Symbol::intern("<unknown item>");
@@ -81,13 +73,10 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
         if item.is_mod() && T::RUN_ON_MODULE {
             // modules are special because they add a namespace. We also need to
             // recurse into the items of the module as well.
-            let name = item.name.as_ref().unwrap().to_string();
-            if name.is_empty() {
-                panic!("Unexpected module with empty name");
-            }
-            let _timer = prof.generic_activity_with_arg("render_mod_item", name.as_str());
+            let _timer =
+                prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string());
 
-            cx.mod_item_in(&item, &name)?;
+            cx.mod_item_in(&item)?;
             let module = match *item.kind {
                 clean::StrippedItem(box clean::ModuleItem(m)) | clean::ModuleItem(m) => m,
                 _ => unreachable!(),
@@ -97,7 +86,7 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
                 work.push((cx.make_child_renderer(), it));
             }
 
-            cx.mod_item_out(&name)?;
+            cx.mod_item_out()?;
         // FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special
         // cases. Use an explicit match instead.
         } else if item.name.is_some() && !item.is_extern_crate() {
@@ -106,5 +95,5 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>(
         }
     }
     prof.extra_verbose_generic_activity("renderer_after_krate", T::descr())
-        .run(|| format_renderer.after_krate(crate_name, diag))
+        .run(|| format_renderer.after_krate())
 }
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 2265905dcba..b8544a0f439 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -31,10 +31,11 @@ crate fn extern_location(
     e: &clean::ExternalCrate,
     extern_url: Option<&str>,
     dst: &Path,
+    tcx: TyCtxt<'_>,
 ) -> ExternalLocation {
     use ExternalLocation::*;
     // See if there's documentation generated into the local directory
-    let local_location = dst.join(&*e.name.as_str());
+    let local_location = dst.join(&*e.name(tcx).as_str());
     if local_location.is_dir() {
         return Local;
     }
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 0aa7aa763c2..9cffcef9749 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::FileName;
-use rustc_span::{symbol::sym, Symbol};
+use rustc_span::symbol::sym;
 
 use super::cache::{build_index, ExternalLocation};
 use super::print_item::{full_path, item_path, print_item};
@@ -111,8 +111,6 @@ crate struct SharedContext<'tcx> {
     crate static_root_path: Option<String>,
     /// The fs handle we are working with.
     crate fs: DocFS,
-    /// The default edition used to parse doctests.
-    crate edition: Edition,
     pub(super) codes: ErrorCodes,
     pub(super) playground: Option<markdown::Playground>,
     all: RefCell<AllTypes>,
@@ -141,6 +139,10 @@ impl SharedContext<'_> {
     crate fn maybe_collapsed_doc_value<'a>(&self, item: &'a clean::Item) -> Option<String> {
         if self.collapsed { item.collapsed_doc_value() } else { item.doc_value() }
     }
+
+    crate fn edition(&self) -> Edition {
+        self.tcx.sess.edition()
+    }
 }
 
 impl<'tcx> Context<'tcx> {
@@ -346,7 +348,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
     fn init(
         mut krate: clean::Crate,
         options: RenderOptions,
-        edition: Edition,
         mut cache: Cache,
         tcx: TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error> {
@@ -435,7 +436,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             resource_suffix,
             static_root_path,
             fs: DocFS::new(sender),
-            edition,
             codes: ErrorCodes::from(unstable_features.is_nightly_build()),
             playground,
             all: RefCell::new(AllTypes::new()),
@@ -494,11 +494,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         }
     }
 
-    fn after_krate(
-        &mut self,
-        crate_name: Symbol,
-        diag: &rustc_errors::Handler,
-    ) -> Result<(), Error> {
+    fn after_krate(&mut self) -> Result<(), Error> {
+        let crate_name = self.tcx().crate_name(LOCAL_CRATE);
         let final_file = self.dst.join(&*crate_name.as_str()).join("all.html");
         let settings_file = self.dst.join("settings.html");
 
@@ -572,7 +569,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
 
         // Flush pending errors.
         Rc::get_mut(&mut self.shared).unwrap().fs.close();
-        let nb_errors = self.shared.errors.iter().map(|err| diag.struct_err(&err).emit()).count();
+        let nb_errors =
+            self.shared.errors.iter().map(|err| self.tcx().sess.struct_err(&err).emit()).count();
         if nb_errors > 0 {
             Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), ""))
         } else {
@@ -580,7 +578,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         }
     }
 
-    fn mod_item_in(&mut self, item: &clean::Item, item_name: &str) -> Result<(), Error> {
+    fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error> {
         // Stripped modules survive the rustdoc passes (i.e., `strip-private`)
         // if they contain impls for public types. These modules can also
         // contain items such as publicly re-exported structures.
@@ -592,8 +590,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             self.render_redirect_pages = item.is_stripped();
         }
         let scx = &self.shared;
-        self.dst.push(item_name);
-        self.current.push(item_name.to_owned());
+        let item_name = item.name.as_ref().unwrap().to_string();
+        self.dst.push(&item_name);
+        self.current.push(item_name);
 
         info!("Recursing into {}", self.dst.display());
 
@@ -619,7 +618,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         Ok(())
     }
 
-    fn mod_item_out(&mut self, _item_name: &str) -> Result<(), Error> {
+    fn mod_item_out(&mut self) -> Result<(), Error> {
         info!("Recursed; leaving {}", self.dst.display());
 
         // Go back to where we were at
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index d773f37ad90..f6d6b34f8be 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -530,7 +530,7 @@ fn render_markdown(
             &links,
             &mut ids,
             cx.shared.codes,
-            cx.shared.edition,
+            cx.shared.edition(),
             &cx.shared.playground
         )
         .into_string()
@@ -660,7 +660,7 @@ fn short_item_info(
                 &note,
                 &mut ids,
                 error_codes,
-                cx.shared.edition,
+                cx.shared.edition(),
                 &cx.shared.playground,
             );
             message.push_str(&format!(": {}", html.into_string()));
@@ -702,7 +702,7 @@ fn short_item_info(
                     &unstable_reason.as_str(),
                     &mut ids,
                     error_codes,
-                    cx.shared.edition,
+                    cx.shared.edition(),
                     &cx.shared.playground,
                 )
                 .into_string()
@@ -1284,6 +1284,7 @@ fn render_impl(
     let cache = cx.cache();
     let traits = &cache.traits;
     let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
+    let mut close_tags = String::new();
 
     if render_mode == RenderMode::Normal {
         let id = cx.derive_id(match i.inner_impl().trait_ {
@@ -1302,7 +1303,12 @@ fn render_impl(
             format!(" aliases=\"{}\"", aliases.join(","))
         };
         if let Some(use_absolute) = use_absolute {
-            write!(w, "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", id, aliases);
+            write!(
+                w,
+                "<details class=\"rustdoc-toggle implementors-toggle\"><summary><h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">",
+                id, aliases
+            );
+            close_tags.insert_str(0, "</details>");
             write!(w, "{}", i.inner_impl().print(use_absolute, cx));
             if show_def_docs {
                 for it in &i.inner_impl().items {
@@ -1325,11 +1331,12 @@ fn render_impl(
         } else {
             write!(
                 w,
-                "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
+                "<details class=\"rustdoc-toggle implementors-toggle\"><summary><h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
                 id,
                 aliases,
                 i.inner_impl().print(false, cx)
             );
+            close_tags.insert_str(0, "</details>");
         }
         write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
         render_stability_since_raw(
@@ -1341,6 +1348,7 @@ fn render_impl(
         );
         write_srclink(cx, &i.impl_item, w);
         w.write_str("</h3>");
+        w.write_str("</summary>");
 
         if trait_.is_some() {
             if let Some(portability) = portability(&i.impl_item, Some(parent)) {
@@ -1358,7 +1366,7 @@ fn render_impl(
                     &i.impl_item.links(cx),
                     &mut ids,
                     cx.shared.codes,
-                    cx.shared.edition,
+                    cx.shared.edition(),
                     &cx.shared.playground
                 )
                 .into_string()
@@ -1542,6 +1550,7 @@ fn render_impl(
     }
 
     w.write_str("<div class=\"impl-items\">");
+    close_tags.insert_str(0, "</div>");
     for trait_item in &i.inner_impl().items {
         doc_impl_item(
             w,
@@ -1612,7 +1621,7 @@ fn render_impl(
             );
         }
     }
-    w.write_str("</div>");
+    w.write_str(&close_tags);
 }
 
 fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index a303ca956d8..9d7d8a7cb8a 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -963,6 +963,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
 
             use crate::clean::Variant;
             if let clean::VariantItem(Variant::Struct(ref s)) = *variant.kind {
+                toggle_open(w, "fields");
                 let variant_id = cx.derive_id(format!(
                     "{}.{}.fields",
                     ItemType::Variant,
@@ -996,6 +997,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                     }
                 }
                 w.write_str("</div></div>");
+                toggle_close(w);
             }
             render_stability_since(w, variant, it, cx.tcx());
         }
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 78bcd40af75..8e10c696df0 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -425,7 +425,7 @@ pub(super) fn write_shared(
             md_opts.output = cx.dst.clone();
             md_opts.external_html = (*cx.shared).layout.external_html.clone();
 
-            crate::markdown::render(&index_page, md_opts, cx.shared.edition)
+            crate::markdown::render(&index_page, md_opts, cx.shared.edition())
                 .map_err(|e| Error::new(e, &index_page))?;
         } else {
             let dst = cx.dst.join("index.html");
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 001c8b09044..5a2a165191a 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -129,7 +129,7 @@ impl SourceCollector<'_, 'tcx> {
             &self.scx.layout,
             &page,
             "",
-            |buf: &mut _| print_src(buf, contents, self.scx.edition),
+            |buf: &mut _| print_src(buf, contents, self.scx.edition()),
             &self.scx.style_files,
         );
         self.scx.fs.write(&cur, v.as_bytes())?;
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index be8d0a5996f..2e3e148eaf6 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -455,6 +455,15 @@ function hideThemeButtonState() {
         handleHashes(ev);
     }
 
+    function openParentDetails(elem) {
+        while (elem) {
+            if (elem.tagName === "DETAILS") {
+                elem.open = true;
+            }
+            elem = elem.parentNode;
+        }
+    }
+
     function expandSection(id) {
         var elem = document.getElementById(id);
         if (elem && isHidden(elem)) {
@@ -469,6 +478,8 @@ function hideThemeButtonState() {
                     // The element is not visible, we need to make it appear!
                     collapseDocs(collapses[0], "show");
                 }
+                // Open all ancestor <details> to make this element visible.
+                openParentDetails(h3.parentNode);
             }
         }
     }
@@ -1009,7 +1020,7 @@ function hideThemeButtonState() {
             if (hasClass(relatedDoc, "item-info")) {
                 relatedDoc = relatedDoc.nextElementSibling;
             }
-            if (hasClass(relatedDoc, "docblock") || hasClass(relatedDoc, "sub-variant")) {
+            if (hasClass(relatedDoc, "docblock")) {
                 if (mode === "toggle") {
                     if (hasClass(relatedDoc, "hidden-by-usual-hider")) {
                         action = "show";
@@ -1196,31 +1207,18 @@ function hideThemeButtonState() {
             if (!next) {
                 return;
             }
-            if (hasClass(e, "impl") &&
-                (next.getElementsByClassName("method").length > 0 ||
-                 next.getElementsByClassName("associatedconstant").length > 0)) {
-                var newToggle = toggle.cloneNode(true);
-                insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
-                // In case the option "auto-collapse implementors" is not set to false, we collapse
-                // all implementors.
-                if (hideImplementors === true && e.parentNode.id === "implementors-list") {
-                    collapseDocs(newToggle, "hide");
-                }
-            }
         };
 
         onEachLazy(document.getElementsByClassName("method"), func);
         onEachLazy(document.getElementsByClassName("associatedconstant"), func);
-        onEachLazy(document.getElementsByClassName("impl"), funcImpl);
         var impl_call = function() {};
-        // Large items are hidden by default in the HTML. If the setting overrides that, show 'em.
-        if (!hideLargeItemContents) {
-            onEachLazy(document.getElementsByTagName("details"), function (e) {
-                if (hasClass(e, "type-contents-toggle")) {
-                    e.open = true;
-                }
-            });
-        }
+        onEachLazy(document.getElementsByTagName("details"), function (e) {
+            var showLargeItem = !hideLargeItemContents && hasClass(e, "type-contents-toggle");
+            var showImplementor = !hideImplementors && hasClass(e, "implementors-toggle");
+            if (showLargeItem || showImplementor) {
+                e.open = true;
+            }
+        });
         if (hideMethodDocs === true) {
             impl_call = function(e, newToggle) {
                 if (e.id.match(/^impl(?:-\d+)?$/) === null) {
@@ -1318,8 +1316,6 @@ function hideThemeButtonState() {
                 if (hasClass(e, "type-decl")) {
                     // We do something special for these
                     return;
-                } else if (hasClass(e, "sub-variant")) {
-                    otherMessage = "&nbsp;Show&nbsp;fields";
                 } else if (hasClass(e, "non-exhaustive")) {
                     otherMessage = "&nbsp;This&nbsp;";
                     if (hasClass(e, "non-exhaustive-struct")) {
@@ -1351,7 +1347,6 @@ function hideThemeButtonState() {
         }
 
         onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper);
-        onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper);
 
         autoCollapse(getSettingValue("collapse") === "true");
 
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 213ca9ec9e3..a024fa49b0e 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -1046,10 +1046,11 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
 }
 
 .sub-variant, .sub-variant > h3 {
-	margin-top: 1px !important;
+	margin-top: 0px !important;
+	padding-top: 1px;
 }
 
-#main > .sub-variant > h3 {
+#main > details > .sub-variant > h3 {
 	font-size: 15px;
 	margin-left: 25px;
 	margin-bottom: 5px;
@@ -1572,6 +1573,10 @@ h4 > .notable-traits {
 		left: -10px;
 	}
 
+	.item-list > details.rustdoc-toggle > summary:not(.hideme)::before {
+		left: -10px;
+	}
+
 	#all-types {
 		margin: 10px;
 	}
@@ -1786,6 +1791,7 @@ details.rustdoc-toggle > summary::before {
 	font-weight: 300;
 	font-size: 0.8em;
 	letter-spacing: 1px;
+	cursor: pointer;
 }
 
 details.rustdoc-toggle > summary.hideme::before {
@@ -1793,7 +1799,8 @@ details.rustdoc-toggle > summary.hideme::before {
 }
 
 details.rustdoc-toggle > summary:not(.hideme)::before {
-	float: left;
+	position: absolute;
+	left: -23px;
 }
 
 /* When a "hideme" summary is open and the "Expand description" or "Show
diff --git a/src/librustdoc/html/static/search.js b/src/librustdoc/html/static/search.js
index eb232a96081..9fab435de49 100644
--- a/src/librustdoc/html/static/search.js
+++ b/src/librustdoc/html/static/search.js
@@ -935,6 +935,9 @@ window.initSearch = function(rawSearchIndex) {
                 });
                 current += 1;
             });
+            var SHIFT = 16;
+            var CTRL = 17;
+            var ALT = 18;
 
             var currentTab = searchState.currentTab;
             if (e.which === 38) { // up
@@ -967,10 +970,10 @@ window.initSearch = function(rawSearchIndex) {
                 e.preventDefault();
             } else if (e.which === 13) { // return
                 if (actives[currentTab].length) {
-                    document.location.href =
-                        actives[currentTab][0].getElementsByTagName("a")[0].href;
+                    var elem = actives[currentTab][0].getElementsByTagName("a")[0];
+                    document.location.href = elem.href;
                 }
-            } else if (e.which === 16) { // shift
+            } else if ([SHIFT, CTRL, ALT].indexOf(e.which) !== -1) {
                 // Does nothing, it's just to avoid losing "focus" on the highlighted element.
             } else if (actives[currentTab].length > 0) {
                 removeClass(actives[currentTab][0], "highlighted");
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index db3a0c5ceb1..b048e7f919f 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -14,7 +14,6 @@ use std::rc::Rc;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
-use rustc_span::{edition::Edition, Symbol};
 
 use rustdoc_json_types as types;
 
@@ -134,7 +133,6 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
     fn init(
         krate: clean::Crate,
         options: RenderOptions,
-        _edition: Edition,
         cache: Cache,
         tcx: TyCtxt<'tcx>,
     ) -> Result<(Self, clean::Crate), Error> {
@@ -183,7 +181,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         Ok(())
     }
 
-    fn mod_item_in(&mut self, item: &clean::Item, _module_name: &str) -> Result<(), Error> {
+    fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error> {
         use clean::types::ItemKind::*;
         if let ModuleItem(m) = &*item.kind {
             for item in &m.items {
@@ -200,15 +198,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         Ok(())
     }
 
-    fn mod_item_out(&mut self, _item_name: &str) -> Result<(), Error> {
-        Ok(())
-    }
-
-    fn after_krate(
-        &mut self,
-        _crate_name: Symbol,
-        _diag: &rustc_errors::Handler,
-    ) -> Result<(), Error> {
+    fn after_krate(&mut self) -> Result<(), Error> {
         debug!("Done with crate");
         let mut index = (*self.index).clone().into_inner();
         index.extend(self.get_trait_items());
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 2a51d78f64a..26aaf0db6f6 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -656,14 +656,13 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
     krate: clean::Crate,
     renderopts: config::RenderOptions,
     cache: formats::cache::Cache,
-    diag: &rustc_errors::Handler,
-    edition: rustc_span::edition::Edition,
     tcx: TyCtxt<'tcx>,
 ) -> MainResult {
-    match formats::run_format::<T>(krate, renderopts, cache, &diag, edition, tcx) {
+    match formats::run_format::<T>(krate, renderopts, cache, tcx) {
         Ok(_) => Ok(()),
         Err(e) => {
-            let mut msg = diag.struct_err(&format!("couldn't generate documentation: {}", e.error));
+            let mut msg =
+                tcx.sess.struct_err(&format!("couldn't generate documentation: {}", e.error));
             let file = e.file.display().to_string();
             if file.is_empty() {
                 msg.emit()
@@ -692,7 +691,6 @@ fn main_options(options: config::Options) -> MainResult {
 
     // need to move these items separately because we lose them by the time the closure is called,
     // but we can't create the Handler ahead of time because it's not Send
-    let diag_opts = (options.error_format, options.edition, options.debugging_opts.clone());
     let show_coverage = options.show_coverage;
     let run_check = options.run_check;
 
@@ -758,28 +756,12 @@ fn main_options(options: config::Options) -> MainResult {
                 }
 
                 info!("going to format");
-                let (error_format, edition, debugging_options) = diag_opts;
-                let diag = core::new_handler(error_format, None, &debugging_options);
                 match output_format {
                     config::OutputFormat::Html => sess.time("render_html", || {
-                        run_renderer::<html::render::Context<'_>>(
-                            krate,
-                            render_opts,
-                            cache,
-                            &diag,
-                            edition,
-                            tcx,
-                        )
+                        run_renderer::<html::render::Context<'_>>(krate, render_opts, cache, tcx)
                     }),
                     config::OutputFormat::Json => sess.time("render_json", || {
-                        run_renderer::<json::JsonRenderer<'_>>(
-                            krate,
-                            render_opts,
-                            cache,
-                            &diag,
-                            edition,
-                            tcx,
-                        )
+                        run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx)
                     }),
                 }
             })
diff --git a/src/test/codegen/wasm_casts_nontrapping.rs b/src/test/codegen/wasm_casts_nontrapping.rs
deleted file mode 100644
index bd6073d8c20..00000000000
--- a/src/test/codegen/wasm_casts_nontrapping.rs
+++ /dev/null
@@ -1,162 +0,0 @@
-// only-wasm32
-// compile-flags: -C target-feature=+nontrapping-fptoint
-#![crate_type = "lib"]
-
-// CHECK-LABEL: @cast_f64_i64
-#[no_mangle]
-pub fn cast_f64_i64(a: f64) -> i64 {
-    // CHECK: tail call i64 @llvm.wasm.trunc.saturate.signed.i64.f64(double {{.*}})
-    // CHECK-NEXT: ret i64 {{.*}}
-    a as _
-}
-
-// CHECK-LABEL: @cast_f64_i32
-#[no_mangle]
-pub fn cast_f64_i32(a: f64) -> i32 {
-    // CHECK: tail call i32 @llvm.wasm.trunc.saturate.signed.i32.f64(double {{.*}})
-    // CHECK-NEXT: ret i32 {{.*}}
-    a as _
-}
-
-// CHECK-LABEL: @cast_f32_i64
-#[no_mangle]
-pub fn cast_f32_i64(a: f32) -> i64 {
-    // CHECK: tail call i64 @llvm.wasm.trunc.saturate.signed.i64.f32(float {{.*}})
-    // CHECK-NEXT: ret i64 {{.*}}
-    a as _
-}
-
-// CHECK-LABEL: @cast_f32_i32
-#[no_mangle]
-pub fn cast_f32_i32(a: f32) -> i32 {
-    // CHECK: tail call i32 @llvm.wasm.trunc.saturate.signed.i32.f32(float {{.*}})
-    // CHECK-NEXT: ret i32 {{.*}}
-    a as _
-}
-
-
-// CHECK-LABEL: @cast_f64_u64
-#[no_mangle]
-pub fn cast_f64_u64(a: f64) -> u64 {
-    // CHECK: tail call i64 @llvm.wasm.trunc.saturate.unsigned.i64.f64(double {{.*}})
-    // CHECK-NEXT: ret i64 {{.*}}
-    a as _
-}
-
-// CHECK-LABEL: @cast_f64_u32
-#[no_mangle]
-pub fn cast_f64_u32(a: f64) -> u32 {
-    // CHECK: tail call i32 @llvm.wasm.trunc.saturate.unsigned.i32.f64(double {{.*}})
-    // CHECK-NEXT: ret i32 {{.*}}
-    a as _
-}
-
-// CHECK-LABEL: @cast_f32_u64
-#[no_mangle]
-pub fn cast_f32_u64(a: f32) -> u64 {
-    // CHECK: tail call i64 @llvm.wasm.trunc.saturate.unsigned.i64.f32(float {{.*}})
-    // CHECK-NEXT: ret i64 {{.*}}
-    a as _
-}
-
-// CHECK-LABEL: @cast_f32_u32
-#[no_mangle]
-pub fn cast_f32_u32(a: f32) -> u32 {
-    // CHECK: tail call i32 @llvm.wasm.trunc.saturate.unsigned.i32.f32(float {{.*}})
-    // CHECK-NEXT: ret i32 {{.*}}
-    a as _
-}
-
-// CHECK-LABEL: @cast_f32_u8
-#[no_mangle]
-pub fn cast_f32_u8(a: f32) -> u8 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptoui float {{.*}} to i8
-    // CHECK-NEXT: select i1 {{.*}}, i8 {{.*}}, i8 {{.*}}
-    // CHECK-NEXT: ret i8 {{.*}}
-    a as _
-}
-
-
-
-// CHECK-LABEL: @cast_unchecked_f64_i64
-#[no_mangle]
-pub unsafe fn cast_unchecked_f64_i64(a: f64) -> i64 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptosi double {{.*}} to i64
-    // CHECK-NEXT: ret i64 {{.*}}
-    a.to_int_unchecked()
-}
-
-// CHECK-LABEL: @cast_unchecked_f64_i32
-#[no_mangle]
-pub unsafe fn cast_unchecked_f64_i32(a: f64) -> i32 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptosi double {{.*}} to i32
-    // CHECK-NEXT: ret i32 {{.*}}
-    a.to_int_unchecked()
-}
-
-// CHECK-LABEL: @cast_unchecked_f32_i64
-#[no_mangle]
-pub unsafe fn cast_unchecked_f32_i64(a: f32) -> i64 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptosi float {{.*}} to i64
-    // CHECK-NEXT: ret i64 {{.*}}
-    a.to_int_unchecked()
-}
-
-// CHECK-LABEL: @cast_unchecked_f32_i32
-#[no_mangle]
-pub unsafe fn cast_unchecked_f32_i32(a: f32) -> i32 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptosi float {{.*}} to i32
-    // CHECK-NEXT: ret i32 {{.*}}
-    a.to_int_unchecked()
-}
-
-
-// CHECK-LABEL: @cast_unchecked_f64_u64
-#[no_mangle]
-pub unsafe fn cast_unchecked_f64_u64(a: f64) -> u64 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptoui double {{.*}} to i64
-    // CHECK-NEXT: ret i64 {{.*}}
-    a.to_int_unchecked()
-}
-
-// CHECK-LABEL: @cast_unchecked_f64_u32
-#[no_mangle]
-pub unsafe fn cast_unchecked_f64_u32(a: f64) -> u32 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptoui double {{.*}} to i32
-    // CHECK-NEXT: ret i32 {{.*}}
-    a.to_int_unchecked()
-}
-
-// CHECK-LABEL: @cast_unchecked_f32_u64
-#[no_mangle]
-pub unsafe fn cast_unchecked_f32_u64(a: f32) -> u64 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptoui float {{.*}} to i64
-    // CHECK-NEXT: ret i64 {{.*}}
-    a.to_int_unchecked()
-}
-
-// CHECK-LABEL: @cast_unchecked_f32_u32
-#[no_mangle]
-pub unsafe fn cast_unchecked_f32_u32(a: f32) -> u32 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptoui float {{.*}} to i32
-    // CHECK-NEXT: ret i32 {{.*}}
-    a.to_int_unchecked()
-}
-
-// CHECK-LABEL: @cast_unchecked_f32_u8
-#[no_mangle]
-pub unsafe fn cast_unchecked_f32_u8(a: f32) -> u8 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptoui float {{.*}} to i8
-    // CHECK-NEXT: ret i8 {{.*}}
-    a.to_int_unchecked()
-}
diff --git a/src/test/codegen/wasm_casts_trapping.rs b/src/test/codegen/wasm_casts_trapping.rs
index ed51faa7be1..baf130a8791 100644
--- a/src/test/codegen/wasm_casts_trapping.rs
+++ b/src/test/codegen/wasm_casts_trapping.rs
@@ -1,5 +1,6 @@
 // only-wasm32
 // compile-flags: -C target-feature=-nontrapping-fptoint
+// min-llvm-version: 12.0
 #![crate_type = "lib"]
 
 // CHECK-LABEL: @cast_f64_i64
@@ -7,7 +8,7 @@
 pub fn cast_f64_i64(a: f64) -> i64 {
     // CHECK-NOT: fptosi double {{.*}} to i64
     // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}}
-    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i64.f64{{.*}}
     a as _
 }
 
@@ -16,7 +17,7 @@ pub fn cast_f64_i64(a: f64) -> i64 {
 pub fn cast_f64_i32(a: f64) -> i32 {
     // CHECK-NOT: fptosi double {{.*}} to i32
     // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}}
-    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i32.f64{{.*}}
     a as _
 }
 
@@ -25,7 +26,7 @@ pub fn cast_f64_i32(a: f64) -> i32 {
 pub fn cast_f32_i64(a: f32) -> i64 {
     // CHECK-NOT: fptosi float {{.*}} to i64
     // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}}
-    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i64.f32{{.*}}
     a as _
 }
 
@@ -34,7 +35,7 @@ pub fn cast_f32_i64(a: f32) -> i64 {
 pub fn cast_f32_i32(a: f32) -> i32 {
     // CHECK-NOT: fptosi float {{.*}} to i32
     // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}}
-    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptosi.sat.i32.f32{{.*}}
     a as _
 }
 
@@ -43,7 +44,7 @@ pub fn cast_f32_i32(a: f32) -> i32 {
 pub fn cast_f64_u64(a: f64) -> u64 {
     // CHECK-NOT: fptoui double {{.*}} to i64
     // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}}
-    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i64.f64{{.*}}
     a as _
 }
 
@@ -52,7 +53,7 @@ pub fn cast_f64_u64(a: f64) -> u64 {
 pub fn cast_f64_u32(a: f64) -> u32 {
     // CHECK-NOT: fptoui double {{.*}} to i32
     // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}}
-    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i32.f64{{.*}}
     a as _
 }
 
@@ -61,7 +62,7 @@ pub fn cast_f64_u32(a: f64) -> u32 {
 pub fn cast_f32_u64(a: f32) -> u64 {
     // CHECK-NOT: fptoui float {{.*}} to i64
     // CHECK-NOT: select i1 {{.*}}, i64 {{.*}}, i64 {{.*}}
-    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i64.f32{{.*}}
     a as _
 }
 
@@ -70,16 +71,16 @@ pub fn cast_f32_u64(a: f32) -> u64 {
 pub fn cast_f32_u32(a: f32) -> u32 {
     // CHECK-NOT: fptoui float {{.*}} to i32
     // CHECK-NOT: select i1 {{.*}}, i32 {{.*}}, i32 {{.*}}
-    // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i32.f32{{.*}}
     a as _
 }
 
 // CHECK-LABEL: @cast_f32_u8
 #[no_mangle]
 pub fn cast_f32_u8(a: f32) -> u8 {
-    // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
-    // CHECK: fptoui float {{.*}} to i8
-    // CHECK-NEXT: select i1 {{.*}}, i8 {{.*}}, i8 {{.*}}
+    // CHECK-NOT: fptoui float {{.*}} to i8
+    // CHECK-NOT: select i1 {{.*}}, i8 {{.*}}, i8 {{.*}}
+    // CHECK: {{.*}} call {{.*}} @llvm.fptoui.sat.i8.f32{{.*}}
     a as _
 }
 
diff --git a/src/test/rustdoc-gui/lib.rs b/src/test/rustdoc-gui/lib.rs
index c1e161e1235..eeba3e3f907 100644
--- a/src/test/rustdoc-gui/lib.rs
+++ b/src/test/rustdoc-gui/lib.rs
@@ -29,7 +29,9 @@ pub struct Foo;
 
 impl Foo {
     #[must_use]
-    pub fn must_use(&self) -> bool { true }
+    pub fn must_use(&self) -> bool {
+        true
+    }
 }
 
 /// Just a normal enum.
@@ -85,3 +87,7 @@ pub trait AnotherOne {
 /// let x = 12;
 /// ```
 pub fn check_list_code_block() {}
+
+pub enum AnEnum {
+    WithVariants { and: usize, sub: usize, variants: usize },
+}
diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs
index db4be82e6bf..77432ba1539 100644
--- a/src/test/rustdoc/const-generics/add-impl.rs
+++ b/src/test/rustdoc/const-generics/add-impl.rs
@@ -8,7 +8,7 @@ pub struct Simd<T, const WIDTH: usize> {
     inner: T,
 }
 
-// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]/h3/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
 impl Add for Simd<u8, 16> {
     type Output = Self;
 
diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs
index 112d632971a..1e644bb9739 100644
--- a/src/test/rustdoc/duplicate_impls/issue-33054.rs
+++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs
@@ -1,8 +1,8 @@
 // @has issue_33054/impls/struct.Foo.html
 // @has - '//code' 'impl Foo'
 // @has - '//code' 'impl Bar for Foo'
-// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1
-// @count - '//*[@id="main"]/*[@class="impl"]' 1
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @count - '//*[@id="main"]/details/summary/*[@class="impl"]' 1
 // @has issue_33054/impls/bar/trait.Bar.html
 // @has - '//code' 'impl Bar for Foo'
 // @count - '//*[@class="struct"]' 1
diff --git a/src/test/rustdoc/issue-21474.rs b/src/test/rustdoc/issue-21474.rs
index 896fc1a78f1..5de26abace6 100644
--- a/src/test/rustdoc/issue-21474.rs
+++ b/src/test/rustdoc/issue-21474.rs
@@ -7,5 +7,5 @@ mod inner {
 pub trait Blah { }
 
 // @count issue_21474/struct.What.html \
-//        '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1
+//        '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
 pub struct What;
diff --git a/src/test/rustdoc/issue-29503.rs b/src/test/rustdoc/issue-29503.rs
index 19bab394dcf..2b25da77d7e 100644
--- a/src/test/rustdoc/issue-29503.rs
+++ b/src/test/rustdoc/issue-29503.rs
@@ -5,7 +5,7 @@ pub trait MyTrait {
     fn my_string(&self) -> String;
 }
 
-// @has - "//div[@id='implementors-list']/h3[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug"
+// @has - "//div[@id='implementors-list']//h3[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug"
 impl<T> MyTrait for T where T: fmt::Debug {
     fn my_string(&self) -> String {
         format!("{:?}", self)
diff --git a/src/test/rustdoc/issue-45584.rs b/src/test/rustdoc/issue-45584.rs
index 0225c0c5c2f..8a5f0413826 100644
--- a/src/test/rustdoc/issue-45584.rs
+++ b/src/test/rustdoc/issue-45584.rs
@@ -4,12 +4,12 @@ pub trait Bar<T, U> {}
 
 // @has 'foo/struct.Foo1.html'
 pub struct Foo1;
-// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
 // @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
 impl Bar<Foo1, &'static Foo1> for Foo1 {}
 
 // @has 'foo/struct.Foo2.html'
 pub struct Foo2;
-// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
 // @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8"
 impl Bar<&'static Foo2, Foo2> for u8 {}
diff --git a/src/test/rustdoc/issue-50159.rs b/src/test/rustdoc/issue-50159.rs
index 74502be622a..0820512e521 100644
--- a/src/test/rustdoc/issue-50159.rs
+++ b/src/test/rustdoc/issue-50159.rs
@@ -13,8 +13,8 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> {
 // @has issue_50159/struct.Switch.html
 // @has - '//code' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send'
 // @has - '//code' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync'
-// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 5
+// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
 pub struct Switch<B: Signal> {
     pub inner: <B as Signal2>::Item2,
 }
diff --git a/src/test/rustdoc/issue-51236.rs b/src/test/rustdoc/issue-51236.rs
index d9accf9c599..d018c948162 100644
--- a/src/test/rustdoc/issue-51236.rs
+++ b/src/test/rustdoc/issue-51236.rs
@@ -7,7 +7,7 @@ pub mod traits {
 }
 
 // @has issue_51236/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
 // Owned<T> where <T as Owned<'static>>::Reader: Send"
 pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
     marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
diff --git a/src/test/rustdoc/issue-53812.rs b/src/test/rustdoc/issue-53812.rs
index 3ebf154077f..daebe059f8e 100644
--- a/src/test/rustdoc/issue-53812.rs
+++ b/src/test/rustdoc/issue-53812.rs
@@ -12,9 +12,9 @@ macro_rules! array_impls {
     }
 }
 
-// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]//h3[1]' 'MyStruct<[T; 0]>'
-// @has - '//*[@id="implementors-list"]//h3[2]' 'MyStruct<[T; 1]>'
-// @has - '//*[@id="implementors-list"]//h3[3]' 'MyStruct<[T; 2]>'
-// @has - '//*[@id="implementors-list"]//h3[4]' 'MyStruct<[T; 3]>'
-// @has - '//*[@id="implementors-list"]//h3[5]' 'MyStruct<[T; 10]>'
+// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/details[1]/summary/h3' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/details[2]/summary/h3' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/details[3]/summary/h3' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/details[4]/summary/h3' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/details[5]/summary/h3' 'MyStruct<[T; 10]>'
 array_impls! { 10 3 2 1 0 }
diff --git a/src/test/rustdoc/issue-54705.rs b/src/test/rustdoc/issue-54705.rs
index 263b1eb0bd6..47da94a4ccf 100644
--- a/src/test/rustdoc/issue-54705.rs
+++ b/src/test/rustdoc/issue-54705.rs
@@ -3,10 +3,10 @@ pub trait ScopeHandle<'scope> {}
 
 
 // @has issue_54705/struct.ScopeFutureContents.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'scope, S> \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \
 // Send for ScopeFutureContents<'scope, S> where S: Sync"
 //
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'scope, S> \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \
 // Sync for ScopeFutureContents<'scope, S> where S: Sync"
 pub struct ScopeFutureContents<'scope, S>
     where S: ScopeHandle<'scope>,
diff --git a/src/test/rustdoc/issue-55321.rs b/src/test/rustdoc/issue-55321.rs
index d312a511459..d1877f39ba7 100644
--- a/src/test/rustdoc/issue-55321.rs
+++ b/src/test/rustdoc/issue-55321.rs
@@ -1,16 +1,16 @@
 #![feature(negative_impls)]
 
 // @has issue_55321/struct.A.html
-// @has - '//*[@id="trait-implementations-list"]/*[@class="impl"]//code' "impl !Send for A"
-// @has - '//*[@id="trait-implementations-list"]/*[@class="impl"]//code' "impl !Sync for A"
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Send for A"
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Sync for A"
 pub struct A();
 
 impl !Send for A {}
 impl !Sync for A {}
 
 // @has issue_55321/struct.B.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Send for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
 // B<T>"
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Sync for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \
 // B<T>"
 pub struct B<T: ?Sized>(A, Box<T>);
diff --git a/src/test/rustdoc/issue-56822.rs b/src/test/rustdoc/issue-56822.rs
index 5b67817fa4c..b932a3d3474 100644
--- a/src/test/rustdoc/issue-56822.rs
+++ b/src/test/rustdoc/issue-56822.rs
@@ -17,7 +17,7 @@ impl<'a, T> MyTrait for Inner<'a, T> {
 }
 
 // @has issue_56822/struct.Parser.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'a> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a> Send for \
 // Parser<'a>"
 pub struct Parser<'a> {
     field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
diff --git a/src/test/rustdoc/issue-60726.rs b/src/test/rustdoc/issue-60726.rs
index 6acc8627738..79b8b70c545 100644
--- a/src/test/rustdoc/issue-60726.rs
+++ b/src/test/rustdoc/issue-60726.rs
@@ -26,9 +26,9 @@ where
 {}
 
 // @has issue_60726/struct.IntoIter.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Send for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
 // IntoIter<T>"
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Sync for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \
 // IntoIter<T>"
 pub struct IntoIter<T>{
     hello:DynTrait<FooInterface<T>>,
diff --git a/src/test/rustdoc/item-hide-threshold.rs b/src/test/rustdoc/item-hide-threshold.rs
index 616eef95662..8986f72636a 100644
--- a/src/test/rustdoc/item-hide-threshold.rs
+++ b/src/test/rustdoc/item-hide-threshold.rs
@@ -62,7 +62,8 @@ pub struct PrivStruct {
 }
 
 // @has 'item_hide_threshold/enum.Enum.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
 pub enum Enum {
     A, B, C,
     D {
diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs
index 38de5316b6c..0dd3a3f7a86 100644
--- a/src/test/rustdoc/synthetic_auto/basic.rs
+++ b/src/test/rustdoc/synthetic_auto/basic.rs
@@ -1,8 +1,8 @@
 // @has basic/struct.Foo.html
 // @has - '//code' 'impl<T> Send for Foo<T> where T: Send'
 // @has - '//code' 'impl<T> Sync for Foo<T> where T: Sync'
-// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 5
+// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
 pub struct Foo<T> {
     field: T,
 }
diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs
index 80a717718c2..d951a20e2de 100644
--- a/src/test/rustdoc/synthetic_auto/complex.rs
+++ b/src/test/rustdoc/synthetic_auto/complex.rs
@@ -20,7 +20,7 @@ mod foo {
 }
 
 // @has complex/struct.NotOuter.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'a, T, K: \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a, T, K: \
 // ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
 // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
 
diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs
index 6d0a68f9b07..05c88f10822 100644
--- a/src/test/rustdoc/synthetic_auto/lifetimes.rs
+++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs
@@ -9,10 +9,10 @@ where
 {}
 
 // @has lifetimes/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Send \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \
 // for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Sync \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \
 // for Foo<'c, K> where K: Sync"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs
index d20b4744af1..88ddd57349a 100644
--- a/src/test/rustdoc/synthetic_auto/manual.rs
+++ b/src/test/rustdoc/synthetic_auto/manual.rs
@@ -1,12 +1,12 @@
 // @has manual/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' 'impl<T> Sync for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Sync for \
 // Foo<T> where T: Sync'
 //
-// @has - '//*[@id="trait-implementations-list"]/*[@class="impl"]//code' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' \
 // 'impl<T> Send for Foo<T>'
 //
-// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1
-// @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 4
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4
 pub struct Foo<T> {
     field: T,
 }
diff --git a/src/test/rustdoc/synthetic_auto/negative.rs b/src/test/rustdoc/synthetic_auto/negative.rs
index 30713849da2..53801542c95 100644
--- a/src/test/rustdoc/synthetic_auto/negative.rs
+++ b/src/test/rustdoc/synthetic_auto/negative.rs
@@ -3,10 +3,10 @@ pub struct Inner<T: Copy> {
 }
 
 // @has negative/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> !Send for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
 // Outer<T>"
 //
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> \
 // !Sync for Outer<T>"
 pub struct Outer<T: Copy> {
     inner_field: Inner<T>,
diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs
index e710ce1c2ed..d4d93a87ffc 100644
--- a/src/test/rustdoc/synthetic_auto/nested.rs
+++ b/src/test/rustdoc/synthetic_auto/nested.rs
@@ -9,10 +9,10 @@ where
 }
 
 // @has nested/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' 'impl<T> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Send for \
 // Foo<T> where T: Copy'
 //
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' \
 // 'impl<T> Sync for Foo<T> where T: Sync'
 pub struct Foo<T> {
     inner_field: Inner<T>,
diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
index cf173111ec1..3a23dc2cf95 100644
--- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs
+++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
@@ -9,7 +9,7 @@ where
 }
 
 // @has no_redundancy/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
 // Outer<T> where T: Copy + Send"
 pub struct Outer<T> {
     inner_field: Inner<T>,
diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs
index 5346521f8d2..060491e3cf1 100644
--- a/src/test/rustdoc/synthetic_auto/project.rs
+++ b/src/test/rustdoc/synthetic_auto/project.rs
@@ -23,10 +23,10 @@ where
 }
 
 // @has project/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Send \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \
 // for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<'c, K> Sync \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \
 // for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, 'c: 'static,"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs
index 905aa20918b..ecdbdf41b20 100644
--- a/src/test/rustdoc/synthetic_auto/self-referential.rs
+++ b/src/test/rustdoc/synthetic_auto/self-referential.rs
@@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> {
 
 
 // @has self_referential/struct.WriteAndThen.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<P1> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<P1> Send for \
 // WriteAndThen<P1>  where  <P1 as Pattern>::Value: Send"
 pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
     where P1: Pattern;
diff --git a/src/test/rustdoc/synthetic_auto/static-region.rs b/src/test/rustdoc/synthetic_auto/static-region.rs
index 59493744b62..a10e694c1b2 100644
--- a/src/test/rustdoc/synthetic_auto/static-region.rs
+++ b/src/test/rustdoc/synthetic_auto/static-region.rs
@@ -3,7 +3,7 @@ pub trait OwnedTrait<'a> {
 }
 
 // @has static_region/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' "impl<T> Send for \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
 // Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
 pub struct Owned<T> where T: OwnedTrait<'static> {
     marker: <T as OwnedTrait<'static>>::Reader,
diff --git a/src/test/ui/associated-type-bounds/issue-81193.rs b/src/test/ui/associated-type-bounds/issue-81193.rs
new file mode 100644
index 00000000000..d2aa54ab951
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-81193.rs
@@ -0,0 +1,15 @@
+// check-pass
+
+#![feature(associated_type_bounds)]
+
+trait A<'a, 'b> {}
+
+trait B<'a, 'b, 'c> {}
+
+fn err<'u, 'a, F>()
+where
+    for<'b> F: Iterator<Item: for<'c> B<'a, 'b, 'c> + for<'c> A<'a, 'c>>,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/issue-83017.rs b/src/test/ui/associated-type-bounds/issue-83017.rs
new file mode 100644
index 00000000000..8f0a9ea3566
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-83017.rs
@@ -0,0 +1,39 @@
+#![feature(associated_type_bounds)]
+
+trait TraitA<'a> {
+    type AsA;
+}
+
+trait TraitB<'a, 'b> {
+    type AsB;
+}
+
+trait TraitC<'a, 'b, 'c> {}
+
+struct X;
+
+impl<'a, 'b, 'c> TraitC<'a, 'b, 'c> for X {}
+
+struct Y;
+
+impl<'a, 'b> TraitB<'a, 'b> for Y {
+    type AsB = X;
+}
+
+struct Z;
+
+impl<'a> TraitA<'a> for Z {
+    type AsA = Y;
+}
+
+fn foo<T>()
+where
+    for<'a> T: TraitA<'a, AsA: for<'b> TraitB<'a, 'b, AsB: for<'c> TraitC<'a, 'b, 'c>>>,
+{
+}
+
+fn main() {
+    foo::<Z>();
+    //~^ ERROR: the trait bound `for<'a, 'b> <Z as TraitA<'a>>::AsA: TraitB<'a, 'b>` is not satisfied
+    //~| ERROR: the trait bound `for<'a, 'b, 'c> <<Z as TraitA<'a>>::AsA as TraitB<'a, 'b>>::AsB: TraitC<'a, 'b, 'c>` is not satisfied
+}
diff --git a/src/test/ui/associated-type-bounds/issue-83017.stderr b/src/test/ui/associated-type-bounds/issue-83017.stderr
new file mode 100644
index 00000000000..4eb71fd0287
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-83017.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the trait bound `for<'a, 'b> <Z as TraitA<'a>>::AsA: TraitB<'a, 'b>` is not satisfied
+  --> $DIR/issue-83017.rs:36:5
+   |
+LL | fn foo<T>()
+   |    --- required by a bound in this
+LL | where
+LL |     for<'a> T: TraitA<'a, AsA: for<'b> TraitB<'a, 'b, AsB: for<'c> TraitC<'a, 'b, 'c>>>,
+   |                                ------------------------------------------------------- required by this bound in `foo`
+...
+LL |     foo::<Z>();
+   |     ^^^^^^^^ the trait `for<'a, 'b> TraitB<'a, 'b>` is not implemented for `<Z as TraitA<'a>>::AsA`
+
+error[E0277]: the trait bound `for<'a, 'b, 'c> <<Z as TraitA<'a>>::AsA as TraitB<'a, 'b>>::AsB: TraitC<'a, 'b, 'c>` is not satisfied
+  --> $DIR/issue-83017.rs:36:5
+   |
+LL | fn foo<T>()
+   |    --- required by a bound in this
+LL | where
+LL |     for<'a> T: TraitA<'a, AsA: for<'b> TraitB<'a, 'b, AsB: for<'c> TraitC<'a, 'b, 'c>>>,
+   |                                                            -------------------------- required by this bound in `foo`
+...
+LL |     foo::<Z>();
+   |     ^^^^^^^^ the trait `for<'a, 'b, 'c> TraitC<'a, 'b, 'c>` is not implemented for `<<Z as TraitA<'a>>::AsA as TraitB<'a, 'b>>::AsB`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr
index de2ffc2e5dc..aff51ee9e2f 100644
--- a/src/test/ui/codemap_tests/two_files.stderr
+++ b/src/test/ui/codemap_tests/two_files.stderr
@@ -5,10 +5,9 @@ LL | impl Bar for Baz { }
    |      ^^^ type aliases cannot be used as traits
    |
 help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
-  --> $DIR/two_files_data.rs:5:1
    |
-LL | type Bar = dyn Foo;
-   | ^^^^^^^^^^^^^^^^^^^
+LL | trait Bar = dyn Foo;
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/issue-3907.stderr b/src/test/ui/resolve/issue-3907.stderr
index 4d0b0af58a3..6fc61cae843 100644
--- a/src/test/ui/resolve/issue-3907.stderr
+++ b/src/test/ui/resolve/issue-3907.stderr
@@ -5,10 +5,9 @@ LL | impl Foo for S {
    |      ^^^ type aliases cannot be used as traits
    |
 help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
-  --> $DIR/issue-3907.rs:5:1
    |
-LL | type Foo = dyn issue_3907::Foo;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait Foo = dyn issue_3907::Foo;
+   |
 help: consider importing this trait instead
    |
 LL | use issue_3907::Foo;
diff --git a/src/test/ui/resolve/issue-5035.stderr b/src/test/ui/resolve/issue-5035.stderr
index 41dff2fe542..a8aa50b7c3a 100644
--- a/src/test/ui/resolve/issue-5035.stderr
+++ b/src/test/ui/resolve/issue-5035.stderr
@@ -11,16 +11,16 @@ LL | trait I {}
    | ------- similarly named trait `I` defined here
 LL | type K = dyn I;
 LL | impl K for isize {}
-   |      ^
-   |      |
-   |      type aliases cannot be used as traits
-   |      help: a trait with a similar name exists: `I`
+   |      ^ type aliases cannot be used as traits
    |
 help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
-  --> $DIR/issue-5035.rs:2:1
    |
-LL | type K = dyn I;
-   | ^^^^^^^^^^^^^^^
+LL | trait K = dyn I;
+   |
+help: a trait with a similar name exists
+   |
+LL | impl I for isize {}
+   |      ^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr
index 2974d08eb23..8addc0303fb 100644
--- a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr
+++ b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr
@@ -11,10 +11,9 @@ LL | fn g<F:Typedef(isize) -> isize>(x: F) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^ type aliases cannot be used as traits
    |
 help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
-  --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:4:1
    |
-LL | type Typedef = isize;
-   | ^^^^^^^^^^^^^^^^^^^^^
+LL | trait Typedef = isize;
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.fixed b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.fixed
new file mode 100644
index 00000000000..8a94abaeb07
--- /dev/null
+++ b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.fixed
@@ -0,0 +1,13 @@
+// Regression test of #43913.
+
+// run-rustfix
+
+#![feature(trait_alias)]
+#![allow(bare_trait_objects, dead_code)]
+
+trait Strings = Iterator<Item=String>;
+
+struct Struct<S: Strings>(S);
+//~^ ERROR: expected trait, found type alias `Strings`
+
+fn main() {}
diff --git a/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.rs b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.rs
new file mode 100644
index 00000000000..40c678c281f
--- /dev/null
+++ b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.rs
@@ -0,0 +1,13 @@
+// Regression test of #43913.
+
+// run-rustfix
+
+#![feature(trait_alias)]
+#![allow(bare_trait_objects, dead_code)]
+
+type Strings = Iterator<Item=String>;
+
+struct Struct<S: Strings>(S);
+//~^ ERROR: expected trait, found type alias `Strings`
+
+fn main() {}
diff --git a/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.stderr b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.stderr
new file mode 100644
index 00000000000..6e03eeada49
--- /dev/null
+++ b/src/test/ui/traits/alias/suggest-trait-alias-instead-of-type.stderr
@@ -0,0 +1,14 @@
+error[E0404]: expected trait, found type alias `Strings`
+  --> $DIR/suggest-trait-alias-instead-of-type.rs:10:18
+   |
+LL | struct Struct<S: Strings>(S);
+   |                  ^^^^^^^ type aliases cannot be used as traits
+   |
+help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias
+   |
+LL | trait Strings = Iterator<Item=String>;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0404`.
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject 7be06139b632ee615fc18af04dd67947e2c794b
+Subproject 7570212a544b8e973a7d57be3657aae6465028a