about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--Cargo.lock4
-rw-r--r--compiler/rustc_ast/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs2
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs14
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_mir/src/const_eval/eval_queries.rs5
-rw-r--r--compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs4
-rw-r--r--compiler/rustc_mir/src/interpret/intrinsics/type_name.rs2
-rw-r--r--compiler/rustc_mir/src/interpret/machine.rs5
-rw-r--r--compiler/rustc_mir/src/interpret/memory.rs15
-rw-r--r--compiler/rustc_mir/src/interpret/place.rs12
-rw-r--r--compiler/rustc_mir/src/interpret/terminator.rs40
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/ops.rs24
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/validation.rs18
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs77
-rw-r--r--compiler/rustc_mir_build/src/thir/constant.rs4
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_none.rs1
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs1
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/avr_gnu_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/dragonfly_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/freebsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/fuchsia_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/haiku_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/hermit_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/hermit_kernel_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/illumos_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/l4re_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/linux_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/linux_kernel_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/mipsel_sony_psp.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs4
-rw-r--r--compiler/rustc_target/src/spec/msvc_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/netbsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs1
-rw-r--r--compiler/rustc_target/src/spec/openbsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/redox_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/solaris_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs1
-rw-r--r--compiler/rustc_target/src/spec/vxworks_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs1
-rw-r--r--compiler/rustc_target/src/spec/windows_gnu_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs1
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs2
-rw-r--r--library/alloc/src/collections/linked_list.rs21
-rw-r--r--library/core/src/ops/control_flow.rs1
-rw-r--r--library/core/src/ops/mod.rs2
-rw-r--r--library/core/src/option.rs2
-rw-r--r--library/core/src/result.rs1
-rw-r--r--library/core/src/task/poll.rs2
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/std/src/io/mod.rs8
-rw-r--r--library/std/src/os/unix/fs.rs2
-rw-r--r--library/std/src/primitive_docs.rs3
-rw-r--r--library/std/src/sys/unix/fs.rs2
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs2
-rw-r--r--library/std/src/sys/unix/process/process_vxworks.rs30
-rw-r--r--library/std/src/sys/windows/c.rs320
-rw-r--r--library/std/src/sys/windows/mod.rs14
-rw-r--r--src/bootstrap/bin/rustc.rs2
-rw-r--r--src/bootstrap/bootstrap.py16
-rw-r--r--src/bootstrap/lib.rs10
-rw-r--r--src/bootstrap/native.rs84
-rw-r--r--src/build_helper/lib.rs1
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/clean/auto_trait.rs2
-rw-r--r--src/librustdoc/clean/inline.rs1
-rw-r--r--src/librustdoc/clean/mod.rs14
-rw-r--r--src/librustdoc/clean/types.rs3
-rw-r--r--src/librustdoc/clean/utils.rs3
-rw-r--r--src/librustdoc/html/format.rs9
-rw-r--r--src/librustdoc/html/render/mod.rs19
-rw-r--r--src/librustdoc/html/static/main.js175
-rw-r--r--src/librustdoc/html/static/rustdoc.css4
-rw-r--r--src/librustdoc/html/static/search.js9
-rw-r--r--src/librustdoc/json/conversions.rs2
-rw-r--r--src/test/rustdoc-gui/search-result-keyword.goml11
-rw-r--r--src/test/rustdoc-gui/src/lib.rs4
-rw-r--r--src/test/rustdoc/issue-85454.rs17
-rw-r--r--src/test/rustdoc/manual_impl.rs3
-rw-r--r--src/test/ui/cast/cast-ptr-to-int-const.mir.stderr19
-rw-r--r--src/test/ui/cast/cast-ptr-to-int-const.rs20
-rw-r--r--src/test/ui/cast/cast-ptr-to-int-const.thir.stderr19
-rw-r--r--src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs13
-rw-r--r--src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.stderr30
-rw-r--r--src/test/ui/consts/const_fn_unsize.gated.stderr8
-rw-r--r--src/test/ui/consts/const_fn_unsize.rs23
-rw-r--r--src/test/ui/consts/const_fn_unsize.stock.stderr12
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.rs6
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.stderr34
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr6
-rw-r--r--src/test/ui/consts/unsizing-cast-non-null.rs10
-rw-r--r--src/test/ui/consts/unsizing-cast-non-null.stderr12
-rw-r--r--src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr (renamed from src/test/ui/generator/issue-45729-unsafe-in-generator.stderr)2
-rw-r--r--src/test/ui/generator/issue-45729-unsafe-in-generator.rs3
-rw-r--r--src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr11
-rw-r--r--src/test/ui/intrinsics/issue-28575.mir.stderr (renamed from src/test/ui/intrinsics/issue-28575.stderr)2
-rw-r--r--src/test/ui/intrinsics/issue-28575.rs3
-rw-r--r--src/test/ui/intrinsics/issue-28575.thir.stderr11
-rw-r--r--src/test/ui/issues/issue-14227.mir.stderr (renamed from src/test/ui/issues/issue-14227.stderr)2
-rw-r--r--src/test/ui/issues/issue-14227.rs3
-rw-r--r--src/test/ui/issues/issue-14227.thir.stderr11
-rw-r--r--src/test/ui/issues/issue-16538.mir.stderr (renamed from src/test/ui/issues/issue-16538.stderr)6
-rw-r--r--src/test/ui/issues/issue-16538.rs3
-rw-r--r--src/test/ui/issues/issue-16538.thir.stderr27
-rw-r--r--src/test/ui/issues/issue-28324.mir.stderr (renamed from src/test/ui/issues/issue-28324.stderr)2
-rw-r--r--src/test/ui/issues/issue-28324.rs3
-rw-r--r--src/test/ui/issues/issue-28324.thir.stderr11
-rw-r--r--src/test/ui/issues/issue-47412.mir.stderr (renamed from src/test/ui/issues/issue-47412.stderr)4
-rw-r--r--src/test/ui/issues/issue-47412.rs6
-rw-r--r--src/test/ui/issues/issue-47412.thir.stderr11
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs2
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs2
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr (renamed from src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr)2
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs2
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr18
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr (renamed from src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr)20
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs2
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr83
-rw-r--r--src/test/ui/safe-extern-statics-mut.mir.stderr (renamed from src/test/ui/safe-extern-statics-mut.stderr)8
-rw-r--r--src/test/ui/safe-extern-statics-mut.rs2
-rw-r--r--src/test/ui/safe-extern-statics-mut.thir.stderr35
-rw-r--r--src/test/ui/safe-extern-statics.mir.stderr (renamed from src/test/ui/safe-extern-statics.stderr)8
-rw-r--r--src/test/ui/safe-extern-statics.rs2
-rw-r--r--src/test/ui/safe-extern-statics.thir.stderr35
-rw-r--r--src/test/ui/static/static-mut-foreign-requires-unsafe.mir.stderr (renamed from src/test/ui/static/static-mut-foreign-requires-unsafe.stderr)6
-rw-r--r--src/test/ui/static/static-mut-foreign-requires-unsafe.rs3
-rw-r--r--src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr27
-rw-r--r--src/test/ui/static/static-mut-requires-unsafe.mir.stderr (renamed from src/test/ui/static/static-mut-requires-unsafe.stderr)6
-rw-r--r--src/test/ui/static/static-mut-requires-unsafe.rs3
-rw-r--r--src/test/ui/static/static-mut-requires-unsafe.thir.stderr27
-rw-r--r--src/test/ui/suggestions/mut-borrow-needed-by-trait.rs1
-rw-r--r--src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr17
-rw-r--r--src/test/ui/traits/safety-fn-body.mir.stderr (renamed from src/test/ui/traits/safety-fn-body.stderr)2
-rw-r--r--src/test/ui/traits/safety-fn-body.rs3
-rw-r--r--src/test/ui/traits/safety-fn-body.thir.stderr11
-rw-r--r--src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr (renamed from src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr)2
-rw-r--r--src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs3
-rw-r--r--src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr11
-rw-r--r--src/test/ui/unsafe/ranged_ints.mir.stderr (renamed from src/test/ui/unsafe/ranged_ints.stderr)2
-rw-r--r--src/test/ui/unsafe/ranged_ints.rs3
-rw-r--r--src/test/ui/unsafe/ranged_ints.thir.stderr11
-rw-r--r--src/test/ui/unsafe/ranged_ints_const.mir.stderr (renamed from src/test/ui/unsafe/ranged_ints_const.stderr)2
-rw-r--r--src/test/ui/unsafe/ranged_ints_const.rs3
-rw-r--r--src/test/ui/unsafe/ranged_ints_const.thir.stderr11
-rw-r--r--src/test/ui/unsafe/ranged_ints_macro.rs3
-rw-r--r--src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.mir.stderr (renamed from src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr)2
-rw-r--r--src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs3
-rw-r--r--src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr11
-rw-r--r--src/test/ui/unsafe/unsafe-fn-deref-ptr.mir.stderr (renamed from src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr)2
-rw-r--r--src/test/ui/unsafe/unsafe-fn-deref-ptr.rs3
-rw-r--r--src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr11
-rw-r--r--src/test/ui/unsafe/unsafe-unstable-const-fn.mir.stderr (renamed from src/test/ui/unsafe/unsafe-unstable-const-fn.stderr)2
-rw-r--r--src/test/ui/unsafe/unsafe-unstable-const-fn.rs3
-rw-r--r--src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr11
-rw-r--r--src/test/ui/wf/wf-static-method.nll.stderr2
-rw-r--r--src/test/ui/wf/wf-static-method.rs3
-rw-r--r--src/test/ui/wf/wf-static-method.stderr29
-rw-r--r--src/tools/clippy/.cargo/config1
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml5
-rw-r--r--src/tools/clippy/CHANGELOG.md198
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs4
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs2
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs134
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_collect.rs57
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs445
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/matches.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs112
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs92
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs283
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs23
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml1
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs39
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs31
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs36
-rw-r--r--src/tools/clippy/doc/basics.md2
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/dogfood.rs68
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7231.rs10
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.fixed5
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.rs5
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.stderr34
-rw-r--r--src/tools/clippy/tests/ui/impl.rs31
-rw-r--r--src/tools/clippy/tests/ui/impl.stderr30
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or.fixed15
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or.rs15
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.fixed5
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.rs10
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.stderr13
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding2.fixed16
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding2.rs18
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding2.stderr36
-rw-r--r--src/tools/clippy/tests/ui/needless_bitwise_bool.fixed40
-rw-r--r--src/tools/clippy/tests/ui/needless_bitwise_bool.rs40
-rw-r--r--src/tools/clippy/tests/ui/needless_bitwise_bool.stderr10
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.fixed19
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.rs17
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.stderr50
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.fixed5
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.rs5
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.stderr2
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed6
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr13
-rw-r--r--src/tools/clippy/tests/ui/unused_async.rs15
-rw-r--r--src/tools/clippy/tests/ui/unused_async.stderr13
-rw-r--r--src/tools/clippy/tests/ui/use_self.fixed30
-rw-r--r--src/tools/clippy/tests/ui/use_self.rs30
-rw-r--r--src/tools/clippy/tests/ui/use_self.stderr8
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.fixed19
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.rs19
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.stderr20
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.fixed175
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.rs175
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.stderr78
-rw-r--r--src/tools/clippy/tests/ui/write_with_newline.stderr4
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention2.rs29
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention2.stderr18
-rw-r--r--src/tools/tidy/src/ui_tests.rs4
243 files changed, 3539 insertions, 1327 deletions
diff --git a/.mailmap b/.mailmap
index cd617ca2f42..213aa6eff66 100644
--- a/.mailmap
+++ b/.mailmap
@@ -43,6 +43,7 @@ Brian Anderson <banderson@mozilla.com> <andersrb@gmail.com>
 Brian Anderson <banderson@mozilla.com> <banderson@mozilla.org>
 Brian Dawn <brian.t.dawn@gmail.com>
 Brian Leibig <brian@brianleibig.com> Brian Leibig <brian.leibig@gmail.com>
+Noah Lev <camelidcamel@gmail.com>
 Noah Lev <camelidcamel@gmail.com> <37223377+camelid@users.noreply.github.com>
 Carl-Anton Ingmarsson <mail@carlanton.se> <ca.ingmarsson@gmail.com>
 Carol (Nichols || Goulding) <carol.nichols@gmail.com> <193874+carols10cents@users.noreply.github.com>
diff --git a/Cargo.lock b/Cargo.lock
index da65b376d19..62734bfaf62 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2195,9 +2195,9 @@ dependencies = [
 
 [[package]]
 name = "minifier"
-version = "0.0.39"
+version = "0.0.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cdf618de5c9c98d4a7b2e0d1f1e44f82a19196cfd94040bb203621c25d28d98"
+checksum = "5594542d20834f2b974f5e5fb8e0cf1c67a2119dcadc29ef5d93a081fb30cc08"
 dependencies = [
  "macro-utils",
 ]
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index ffec28a395f..8061e0b83c0 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -10,8 +10,8 @@
 )]
 #![feature(box_syntax)]
 #![feature(box_patterns)]
+// On bootstrap bump, this will likely have to become const_fn_unsize
 #![cfg_attr(bootstrap, feature(const_fn))] // For the `transmute` in `P::new`
-#![cfg_attr(not(bootstrap), feature(const_fn_unsize))] // For the `transmute` in `P::new`
 #![feature(const_fn_transmute)]
 #![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index c0f2920652f..6b132e4ff0f 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -2,6 +2,7 @@
 
 use rustc_span::DUMMY_SP;
 
+use rustc_ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::ErrorReported;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
@@ -175,6 +176,7 @@ pub(crate) fn codegen_const_value<'tcx>(
                 let mut alloc = Allocation::from_bytes(
                     std::iter::repeat(0).take(size.bytes_usize()).collect::<Vec<u8>>(),
                     align,
+                    Mutability::Not,
                 );
                 alloc.write_scalar(fx, alloc_range(Size::ZERO, size), x.into()).unwrap();
                 let alloc = fx.tcx.intern_const_alloc(alloc);
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index eef71e096a5..945406aed4b 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -283,6 +283,8 @@ declare_features! (
     (accepted, non_ascii_idents, "1.53.0", Some(55467), None),
     /// Allows arbitrary expressions in key-value attributes at parse time.
     (accepted, extended_key_value_attributes, "1.54.0", Some(78835), None),
+    /// Allows unsizing coercions in `const fn`.
+    (accepted, const_fn_unsize, "1.54.0", Some(64992), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 2cef46a844a..62d81304134 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -644,9 +644,6 @@ declare_features! (
     /// Allows trait bounds in `const fn`.
     (active, const_fn_trait_bound, "1.53.0", Some(57563), None),
 
-    /// Allows unsizing coercions in `const fn`.
-    (active, const_fn_unsize, "1.53.0", Some(64992), None),
-
     /// Allows `async {}` expressions in const contexts.
     (active, const_async_blocks, "1.53.0", Some(85368), None),
 
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 622eaf57578..ee3902991e9 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -99,8 +99,12 @@ impl AllocRange {
 
 // The constructors are all without extra; the extra gets added by a machine hook later.
 impl<Tag> Allocation<Tag> {
-    /// Creates a read-only allocation initialized by the given bytes
-    pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
+    /// Creates an allocation initialized by the given bytes
+    pub fn from_bytes<'a>(
+        slice: impl Into<Cow<'a, [u8]>>,
+        align: Align,
+        mutability: Mutability,
+    ) -> Self {
         let bytes = slice.into().into_owned();
         let size = Size::from_bytes(bytes.len());
         Self {
@@ -108,13 +112,13 @@ impl<Tag> Allocation<Tag> {
             relocations: Relocations::new(),
             init_mask: InitMask::new(size, true),
             align,
-            mutability: Mutability::Not,
+            mutability,
             extra: (),
         }
     }
 
-    pub fn from_byte_aligned_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self {
-        Allocation::from_bytes(slice, Align::ONE)
+    pub fn from_bytes_byte_aligned_immutable<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self {
+        Allocation::from_bytes(slice, Align::ONE, Mutability::Not)
     }
 
     pub fn uninit(size: Size, align: Align) -> Self {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index dde5cbadbd9..790463d6fc6 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1072,7 +1072,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Allocates a read-only byte or string literal for `mir::interpret`.
     pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
         // Create an allocation that just contains these bytes.
-        let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
+        let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes);
         let alloc = self.intern_const_alloc(alloc);
         self.create_memory_alloc(alloc)
     }
diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs
index d51adc8864d..a12185393de 100644
--- a/compiler/rustc_mir/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs
@@ -169,8 +169,9 @@ pub(super) fn op_to_const<'tcx>(
                         (ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), ptr.offset.bytes())
                     }
                     Scalar::Int { .. } => (
-                        ecx.tcx
-                            .intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])),
+                        ecx.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable(
+                            b"" as &[u8],
+                        )),
                         0,
                     ),
                 };
diff --git a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
index 2b996cf62a3..792a4749108 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
@@ -1,5 +1,6 @@
 use std::convert::TryFrom;
 
+use rustc_ast::Mutability;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir::TerminatorKind;
 use rustc_middle::ty::subst::Subst;
@@ -79,7 +80,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         line: u32,
         col: u32,
     ) -> MPlaceTy<'tcx, M::PointerTag> {
-        let file = self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation);
+        let file =
+            self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not);
         let line = Scalar::from_u32(line);
         let col = Scalar::from_u32(col);
 
diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
index ae5e78ee33f..4978cc3606d 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
@@ -197,6 +197,6 @@ impl Write for AbsolutePathPrinter<'_> {
 /// Directly returns an `Allocation` containing an absolute path representation of the given type.
 crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation {
     let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
-    let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes());
+    let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
     tcx.intern_const_alloc(alloc)
 }
diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs
index e7d7c38cc8f..0ca99da7304 100644
--- a/compiler/rustc_mir/src/interpret/machine.rs
+++ b/compiler/rustc_mir/src/interpret/machine.rs
@@ -132,6 +132,11 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// Whether to enforce the validity invariant
     fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
+    /// Whether function calls should be [ABI](Abi)-checked.
+    fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+        true
+    }
+
     /// Entry point for obtaining the MIR of anything that should get evaluated.
     /// So not just functions and shims, but also const/static initializers, anonymous
     /// constants, ...
diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs
index 7fb7c51b0b5..77de19ac674 100644
--- a/compiler/rustc_mir/src/interpret/memory.rs
+++ b/compiler/rustc_mir/src/interpret/memory.rs
@@ -219,9 +219,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
     pub fn allocate_bytes(
         &mut self,
         bytes: &[u8],
+        align: Align,
         kind: MemoryKind<M::MemoryKind>,
+        mutability: Mutability,
     ) -> Pointer<M::PointerTag> {
-        let alloc = Allocation::from_byte_aligned_bytes(bytes);
+        let alloc = Allocation::from_bytes(bytes, align, mutability);
         self.allocate_with(alloc, kind)
     }
 
@@ -321,6 +323,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
             }
         };
 
+        if alloc.mutability == Mutability::Not {
+            throw_ub_format!("deallocating immutable allocation {}", ptr.alloc_id);
+        }
         if alloc_kind != kind {
             throw_ub_format!(
                 "deallocating {}, which is {} memory, using {} deallocation operation",
@@ -625,9 +630,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
             // Need to make a copy, even if `get_global_alloc` is able
             // to give us a cheap reference.
             let alloc = Self::get_global_alloc(memory_extra, tcx, id, /*is_write*/ true)?;
-            if alloc.mutability == Mutability::Not {
-                throw_ub!(WriteToReadOnly(id))
-            }
             let kind = M::GLOBAL_KIND.expect(
                 "I got a global allocation that I have to copy but the machine does \
                     not expect that to happen",
@@ -673,8 +675,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
     pub fn get_alloc_extra_mut<'a>(
         &'a mut self,
         id: AllocId,
-    ) -> InterpResult<'tcx, &'a mut M::AllocExtra> {
-        Ok(&mut self.get_raw_mut(id)?.0.extra)
+    ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M::MemoryExtra)> {
+        let (alloc, memory_extra) = self.get_raw_mut(id)?;
+        Ok((&mut alloc.extra, memory_extra))
     }
 
     /// Obtain the size and alignment of an allocation, even if that allocation has
diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs
index ef603b51554..79aaff1c5eb 100644
--- a/compiler/rustc_mir/src/interpret/place.rs
+++ b/compiler/rustc_mir/src/interpret/place.rs
@@ -6,6 +6,7 @@ use std::convert::TryFrom;
 use std::fmt::Debug;
 use std::hash::Hash;
 
+use rustc_ast::Mutability;
 use rustc_macros::HashStable;
 use rustc_middle::mir;
 use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
@@ -1024,18 +1025,23 @@ where
         MPlaceTy::from_aligned_ptr(ptr, layout)
     }
 
-    /// Returns a wide MPlace.
+    /// Returns a wide MPlace of type `&'static [mut] str` to a new 1-aligned allocation.
     pub fn allocate_str(
         &mut self,
         str: &str,
         kind: MemoryKind<M::MemoryKind>,
+        mutbl: Mutability,
     ) -> MPlaceTy<'tcx, M::PointerTag> {
-        let ptr = self.memory.allocate_bytes(str.as_bytes(), kind);
+        let ptr = self.memory.allocate_bytes(str.as_bytes(), Align::ONE, kind, mutbl);
         let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
         let mplace =
             MemPlace { ptr: ptr.into(), align: Align::ONE, meta: MemPlaceMeta::Meta(meta) };
 
-        let layout = self.layout_of(self.tcx.mk_static_str()).unwrap();
+        let ty = self.tcx.mk_ref(
+            self.tcx.lifetimes.re_static,
+            ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
+        );
+        let layout = self.layout_of(ty).unwrap();
         MPlaceTy { mplace, layout }
     }
 
diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs
index a7fcb41f74a..a3dc8aaef32 100644
--- a/compiler/rustc_mir/src/interpret/terminator.rs
+++ b/compiler/rustc_mir/src/interpret/terminator.rs
@@ -232,26 +232,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         // ABI check
         let check_abi = |this: &Self, instance_ty: Ty<'tcx>| -> InterpResult<'tcx> {
-            let callee_abi = match instance_ty.kind() {
-                ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
-                ty::Closure(..) => Abi::RustCall,
-                ty::Generator(..) => Abi::Rust,
-                _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
-            };
-            let normalize_abi = |abi| match abi {
-                Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
-                // These are all the same ABI, really.
-                {
-                    Abi::Rust
+            if M::enforce_abi(this) {
+                let callee_abi = match instance_ty.kind() {
+                    ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
+                    ty::Closure(..) => Abi::RustCall,
+                    ty::Generator(..) => Abi::Rust,
+                    _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
+                };
+                let normalize_abi = |abi| match abi {
+                    Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
+                    // These are all the same ABI, really.
+                    {
+                        Abi::Rust
+                    }
+                    abi => abi,
+                };
+                if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
+                    throw_ub_format!(
+                        "calling a function with ABI {} using caller ABI {}",
+                        callee_abi.name(),
+                        caller_abi.name()
+                    )
                 }
-                abi => abi,
-            };
-            if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
-                throw_ub_format!(
-                    "calling a function with ABI {} using caller ABI {}",
-                    callee_abi.name(),
-                    caller_abi.name()
-                )
             }
             Ok(())
         };
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index 16f5f14f563..dcbc9c523dc 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -541,30 +541,6 @@ impl NonConstOp for UnionAccess {
     }
 }
 
-/// See [#64992].
-///
-/// [#64992]: https://github.com/rust-lang/rust/issues/64992
-#[derive(Debug)]
-pub struct UnsizingCast;
-impl NonConstOp for UnsizingCast {
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
-        if ccx.const_kind() != hir::ConstContext::ConstFn {
-            Status::Allowed
-        } else {
-            Status::Unstable(sym::const_fn_unsize)
-        }
-    }
-
-    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_fn_unsize,
-            span,
-            "unsizing casts to types besides slices are not allowed in const fn",
-        )
-    }
-}
-
 // Types that cannot appear in the signature or locals of a `const fn`.
 pub mod ty {
     use super::*;
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index 63fc66f2b9f..41d9d0d04b5 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -10,9 +10,7 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC
 use rustc_middle::mir::*;
 use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{
-    self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut,
-};
+use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
 use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
 use rustc_span::{sym, Span, Symbol};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
@@ -636,17 +634,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 _,
             ) => self.check_op(ops::FnPtrCast),
 
-            Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, cast_ty) => {
-                if let Some(TypeAndMut { ty, .. }) = cast_ty.builtin_deref(true) {
-                    let unsized_ty = self.tcx.struct_tail_erasing_lifetimes(ty, self.param_env);
-
-                    // Casting/coercing things to slices is fine.
-                    if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
-                        return;
-                    }
-                }
-
-                self.check_op(ops::UnsizingCast);
+            Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
+                // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
+                // in the type of any local, which also excludes casts).
             }
 
             Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 8c2c81c8628..aa8193dab5d 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -7,8 +7,11 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
 use rustc_session::lint::Level;
 use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
+use std::ops::Bound;
+
 struct UnsafetyVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     thir: &'a Thir<'tcx>,
@@ -19,6 +22,10 @@ struct UnsafetyVisitor<'a, 'tcx> {
     /// `unsafe` block, and whether it has been used.
     safety_context: SafetyContext,
     body_unsafety: BodyUnsafety,
+    /// The `#[target_feature]` attributes of the body. Used for checking
+    /// calls to functions with `#[target_feature]` (RFC 2396).
+    body_target_features: &'tcx Vec<Symbol>,
+    is_const: bool,
 }
 
 impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
@@ -148,11 +155,55 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
                 if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
                     self.requires_unsafe(expr.span, CallToUnsafeFunction);
+                } else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
+                    // If the called function has target features the calling function hasn't,
+                    // the call requires `unsafe`.
+                    if !self
+                        .tcx
+                        .codegen_fn_attrs(func_did)
+                        .target_features
+                        .iter()
+                        .all(|feature| self.body_target_features.contains(feature))
+                    {
+                        self.requires_unsafe(expr.span, CallToFunctionWith);
+                    }
+                }
+            }
+            ExprKind::Deref { arg } => {
+                if let ExprKind::StaticRef { def_id, .. } = self.thir[arg].kind {
+                    if self.tcx.is_mutable_static(def_id) {
+                        self.requires_unsafe(expr.span, UseOfMutableStatic);
+                    } else if self.tcx.is_foreign_item(def_id) {
+                        self.requires_unsafe(expr.span, UseOfExternStatic);
+                    }
+                } else if self.thir[arg].ty.is_unsafe_ptr() {
+                    self.requires_unsafe(expr.span, DerefOfRawPointer);
                 }
             }
             ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => {
                 self.requires_unsafe(expr.span, UseOfInlineAssembly);
             }
+            ExprKind::Adt {
+                adt_def,
+                variant_index: _,
+                substs: _,
+                user_ty: _,
+                fields: _,
+                base: _,
+            } => match self.tcx.layout_scalar_valid_range(adt_def.did) {
+                (Bound::Unbounded, Bound::Unbounded) => {}
+                _ => self.requires_unsafe(expr.span, InitializingTypeWith),
+            },
+            ExprKind::Cast { source } => {
+                let source = &self.thir[source];
+                if self.tcx.features().const_raw_ptr_to_usize_cast
+                    && self.is_const
+                    && (source.ty.is_unsafe_ptr() || source.ty.is_fn_ptr())
+                    && expr.ty.is_integral()
+                {
+                    self.requires_unsafe(expr.span, CastOfPointerToInt);
+                }
+            }
             _ => {}
         }
 
@@ -195,15 +246,10 @@ impl BodyUnsafety {
 enum UnsafeOpKind {
     CallToUnsafeFunction,
     UseOfInlineAssembly,
-    #[allow(dead_code)] // FIXME
     InitializingTypeWith,
-    #[allow(dead_code)] // FIXME
     CastOfPointerToInt,
-    #[allow(dead_code)] // FIXME
     UseOfMutableStatic,
-    #[allow(dead_code)] // FIXME
     UseOfExternStatic,
-    #[allow(dead_code)] // FIXME
     DerefOfRawPointer,
     #[allow(dead_code)] // FIXME
     AssignToDroppingUnionField,
@@ -213,7 +259,6 @@ enum UnsafeOpKind {
     MutationOfLayoutConstrainedField,
     #[allow(dead_code)] // FIXME
     BorrowOfLayoutConstrainedField,
-    #[allow(dead_code)] // FIXME
     CallToFunctionWith,
 }
 
@@ -287,6 +332,7 @@ pub fn check_unsafety<'tcx>(
     tcx: TyCtxt<'tcx>,
     thir: &Thir<'tcx>,
     expr: ExprId,
+    def_id: LocalDefId,
     hir_id: hir::HirId,
 ) {
     let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| {
@@ -296,10 +342,23 @@ pub fn check_unsafety<'tcx>(
             BodyUnsafety::Safe
         }
     });
+    let body_target_features = &tcx.codegen_fn_attrs(def_id).target_features;
     let safety_context =
         if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
-    let mut visitor =
-        UnsafetyVisitor { tcx, thir, safety_context, hir_context: hir_id, body_unsafety };
+    let is_const = match tcx.hir().body_owner_kind(hir_id) {
+        hir::BodyOwnerKind::Closure => false,
+        hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def_id.to_def_id()),
+        hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => true,
+    };
+    let mut visitor = UnsafetyVisitor {
+        tcx,
+        thir,
+        safety_context,
+        hir_context: hir_id,
+        body_unsafety,
+        body_target_features,
+        is_const,
+    };
     visitor.visit_expr(&thir[expr]);
 }
 
@@ -311,7 +370,7 @@ crate fn thir_check_unsafety_inner<'tcx>(
     let body_id = tcx.hir().body_owned_by(hir_id);
     let body = tcx.hir().body(body_id);
     let (thir, expr) = cx::build_thir(tcx, def, &body.value);
-    check_unsafety(tcx, &thir, expr, hir_id);
+    check_unsafety(tcx, &thir, expr, def.did, hir_id);
 }
 
 crate fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index ac93d042970..d62fd161e2f 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -25,14 +25,14 @@ crate fn lit_to_const<'tcx>(
     let lit = match (lit, &ty.kind()) {
         (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
             let s = s.as_str();
-            let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
+            let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
             let allocation = tcx.intern_const_alloc(allocation);
             ConstValue::Slice { data: allocation, start: 0, end: s.len() }
         }
         (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
             if matches!(inner_ty.kind(), ty::Slice(_)) =>
         {
-            let allocation = Allocation::from_byte_aligned_bytes(data as &[u8]);
+            let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
             let allocation = tcx.intern_const_alloc(allocation);
             ConstValue::Slice { data: allocation, start: 0, end: data.len() }
         }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
index c9f622820de..de92b167f00 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
@@ -16,7 +16,6 @@ pub fn target() -> Target {
         executables: true,
         relocation_model: RelocModel::Static,
         disable_redzone: true,
-        linker_is_gnu: true,
         max_atomic_width: Some(128),
         panic_strategy: PanicStrategy::Abort,
         unsupported_abis: super::arm_base::unsupported_abis(),
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
index 0811871c993..2566eeae14a 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
@@ -16,7 +16,6 @@ pub fn target() -> Target {
         executables: true,
         relocation_model: RelocModel::Static,
         disable_redzone: true,
-        linker_is_gnu: true,
         max_atomic_width: Some(128),
         panic_strategy: PanicStrategy::Abort,
         unsupported_abis: super::arm_base::unsupported_abis(),
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index bc2ec670901..45c5c1a16e9 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -22,6 +22,7 @@ pub fn opts(os: &str) -> TargetOptions {
         // macOS has -dead_strip, which doesn't rely on function_sections
         function_sections: false,
         dynamic_linking: true,
+        linker_is_gnu: false,
         executables: true,
         families: vec!["unix".to_string()],
         is_like_osx: true,
diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs
index 69ccce875ab..2cb2661a526 100644
--- a/compiler/rustc_target/src/spec/avr_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs
@@ -16,7 +16,6 @@ pub fn target(target_cpu: String) -> Target {
 
             linker: Some("avr-gcc".to_owned()),
             executables: true,
-            linker_is_gnu: true,
             eh_frame_header: false,
             pre_link_args: vec![(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu)])]
                 .into_iter()
diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs
index fb94498c131..e13a640d4d2 100644
--- a/compiler/rustc_target/src/spec/dragonfly_base.rs
+++ b/compiler/rustc_target/src/spec/dragonfly_base.rs
@@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index 5d3c28e5f29..bef2fce7c83 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
         eliminate_frame_pointer: false, // FIXME 43575
diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs
index 13264dffeb4..23a2e65749e 100644
--- a/compiler/rustc_target/src/spec/fuchsia_base.rs
+++ b/compiler/rustc_target/src/spec/fuchsia_base.rs
@@ -27,7 +27,6 @@ pub fn opts() -> TargetOptions {
         executables: true,
         families: vec!["unix".to_string()],
         is_like_fuchsia: true,
-        linker_is_gnu: true,
         pre_link_args,
         pre_link_objects: crt_objects::new(&[
             (LinkOutputKind::DynamicNoPicExe, &["Scrt1.o"]),
diff --git a/compiler/rustc_target/src/spec/haiku_base.rs b/compiler/rustc_target/src/spec/haiku_base.rs
index fae56f6a82d..2b95523d6f7 100644
--- a/compiler/rustc_target/src/spec/haiku_base.rs
+++ b/compiler/rustc_target/src/spec/haiku_base.rs
@@ -7,7 +7,6 @@ pub fn opts() -> TargetOptions {
         executables: true,
         families: vec!["unix".to_string()],
         relro_level: RelroLevel::Full,
-        linker_is_gnu: true,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/hermit_base.rs b/compiler/rustc_target/src/spec/hermit_base.rs
index ad013047e6a..75ca1f79b12 100644
--- a/compiler/rustc_target/src/spec/hermit_base.rs
+++ b/compiler/rustc_target/src/spec/hermit_base.rs
@@ -13,7 +13,6 @@ pub fn opts() -> TargetOptions {
         linker: Some("rust-lld".to_owned()),
         executables: true,
         has_elf_tls: true,
-        linker_is_gnu: true,
         pre_link_args,
         panic_strategy: PanicStrategy::Abort,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/hermit_kernel_base.rs b/compiler/rustc_target/src/spec/hermit_kernel_base.rs
index 6d18a14d6ae..c55a46e69a8 100644
--- a/compiler/rustc_target/src/spec/hermit_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/hermit_kernel_base.rs
@@ -14,7 +14,6 @@ pub fn opts() -> TargetOptions {
         linker: Some("rust-lld".to_owned()),
         executables: true,
         has_elf_tls: true,
-        linker_is_gnu: true,
         pre_link_args,
         panic_strategy: PanicStrategy::Abort,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs
index 2b8e046c46b..9d9da50be7a 100644
--- a/compiler/rustc_target/src/spec/illumos_base.rs
+++ b/compiler/rustc_target/src/spec/illumos_base.rs
@@ -33,6 +33,7 @@ pub fn opts() -> TargetOptions {
         has_rpath: true,
         families: vec!["unix".to_string()],
         is_like_solaris: true,
+        linker_is_gnu: false,
         limit_rdylib_exports: false, // Linker doesn't support this
         eliminate_frame_pointer: false,
         eh_frame_header: false,
diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs
index 65c343a5f21..f6e3102f617 100644
--- a/compiler/rustc_target/src/spec/l4re_base.rs
+++ b/compiler/rustc_target/src/spec/l4re_base.rs
@@ -20,6 +20,7 @@ pub fn opts() -> TargetOptions {
         executables: true,
         panic_strategy: PanicStrategy::Abort,
         linker: Some("ld".to_string()),
+        linker_is_gnu: false,
         families: vec!["unix".to_string()],
         ..Default::default()
     }
diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs
index 184659e22d9..af81bc714c7 100644
--- a/compiler/rustc_target/src/spec/linux_base.rs
+++ b/compiler/rustc_target/src/spec/linux_base.rs
@@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
index 64f47b4aa9b..145aa4a5894 100644
--- a/compiler/rustc_target/src/spec/linux_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs
@@ -8,7 +8,6 @@ pub fn opts() -> TargetOptions {
         // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
         stack_probes: StackProbeType::Call,
         eliminate_frame_pointer: false,
-        linker_is_gnu: true,
         position_independent_executables: true,
         needs_plt: true,
         relro_level: RelroLevel::Full,
diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
index 08c290e6ff1..dc14e4bdf94 100644
--- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
+++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
@@ -21,7 +21,6 @@ pub fn target() -> Target {
             cpu: "mips2".to_string(),
             executables: true,
             linker: Some("rust-lld".to_owned()),
-            linker_is_gnu: true,
             relocation_model: RelocModel::Static,
 
             // PSP FPU only supports single precision floats.
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 4bffd6e8ddd..f1bd8ff237d 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1086,7 +1086,7 @@ pub struct TargetOptions {
     /// Version of DWARF to use if not using the default.
     /// Useful because some platforms (osx, bsd) only want up to DWARF2.
     pub dwarf_version: Option<u32>,
-    /// Whether the linker support GNU-like arguments such as -O. Defaults to false.
+    /// Whether the linker support GNU-like arguments such as -O. Defaults to true.
     pub linker_is_gnu: bool,
     /// The MinGW toolchain has a known issue that prevents it from correctly
     /// handling COFF object files with more than 2<sup>15</sup> sections. Since each weak
@@ -1307,7 +1307,7 @@ impl Default for TargetOptions {
             is_like_fuchsia: false,
             is_like_wasm: false,
             dwarf_version: None,
-            linker_is_gnu: false,
+            linker_is_gnu: true,
             allows_weak_linkage: true,
             has_rpath: false,
             no_default_libraries: true,
diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs
index 4ed7685ca07..f1ed4c154d2 100644
--- a/compiler/rustc_target/src/spec/msvc_base.rs
+++ b/compiler/rustc_target/src/spec/msvc_base.rs
@@ -16,6 +16,7 @@ pub fn opts() -> TargetOptions {
         is_like_windows: true,
         is_like_msvc: true,
         lld_flavor: LldFlavor::Link,
+        linker_is_gnu: false,
         pre_link_args,
         abi_return_struct_as_int: true,
         emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs
index 602fb6eb641..6bb6083d47c 100644
--- a/compiler/rustc_target/src/spec/netbsd_base.rs
+++ b/compiler/rustc_target/src/spec/netbsd_base.rs
@@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         no_default_libraries: false,
         has_rpath: true,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index 15d8e4843f9..97960a75b09 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -14,6 +14,7 @@ pub fn target() -> Target {
             linker_flavor: LinkerFlavor::PtxLinker,
             // The linker can be installed from `crates.io`.
             linker: Some("rust-ptx-linker".to_string()),
+            linker_is_gnu: false,
 
             // With `ptx-linker` approach, it can be later overridden via link flags.
             cpu: "sm_30".to_string(),
diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs
index 8f33bacd922..29b415e7726 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         abi_return_struct_as_int: true,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/redox_base.rs b/compiler/rustc_target/src/spec/redox_base.rs
index 72052b9e2e2..fcf5db3746d 100644
--- a/compiler/rustc_target/src/spec/redox_base.rs
+++ b/compiler/rustc_target/src/spec/redox_base.rs
@@ -7,7 +7,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
diff --git a/compiler/rustc_target/src/spec/solaris_base.rs b/compiler/rustc_target/src/spec/solaris_base.rs
index 4c922eb5cea..bc32b501688 100644
--- a/compiler/rustc_target/src/spec/solaris_base.rs
+++ b/compiler/rustc_target/src/spec/solaris_base.rs
@@ -8,6 +8,7 @@ pub fn opts() -> TargetOptions {
         has_rpath: true,
         families: vec!["unix".to_string()],
         is_like_solaris: true,
+        linker_is_gnu: false,
         limit_rdylib_exports: false, // Linker doesn't support this
         eh_frame_header: false,
 
diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
index ef58824f381..f996009f830 100644
--- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
@@ -28,7 +28,6 @@ pub fn target() -> Target {
         options: TargetOptions {
             linker_flavor: LinkerFlavor::Ld,
             linker: Some("arm-none-eabi-ld".to_string()),
-            linker_is_gnu: true,
 
             // extra args passed to the external assembler (assuming `arm-none-eabi-as`):
             // * activate t32/a32 interworking
diff --git a/compiler/rustc_target/src/spec/vxworks_base.rs b/compiler/rustc_target/src/spec/vxworks_base.rs
index 0e8e87f2dff..a91e7717865 100644
--- a/compiler/rustc_target/src/spec/vxworks_base.rs
+++ b/compiler/rustc_target/src/spec/vxworks_base.rs
@@ -10,7 +10,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         has_elf_tls: true,
         crt_static_default: true,
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index ddf28b423f0..302139395d3 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -34,7 +34,6 @@ pub fn target() -> Target {
         // functionality, and a .wasm file.
         exe_suffix: ".js".to_string(),
         linker: None,
-        linker_is_gnu: true,
         is_like_emscripten: true,
         panic_strategy: PanicStrategy::Unwind,
         post_link_args,
diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs
index 5808391ee06..35a52896f6f 100644
--- a/compiler/rustc_target/src/spec/windows_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs
@@ -66,7 +66,6 @@ pub fn opts() -> TargetOptions {
         // FIXME(#13846) this should be enabled for windows
         function_sections: false,
         linker: Some("gcc".to_string()),
-        linker_is_gnu: true,
         dynamic_linking: true,
         executables: true,
         dll_prefix: String::new(),
diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
index 90705c526f4..06eb33d8d82 100644
--- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
@@ -57,7 +57,6 @@ pub fn target() -> Target {
         vendor: "fortanix".into(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         executables: true,
-        linker_is_gnu: true,
         linker: Some("rust-lld".to_owned()),
         max_atomic_width: Some(64),
         cpu: "x86-64".into(),
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 4de8216884a..96569ae0e77 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1522,7 +1522,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let ty = tcx.type_of(impl_def_id);
 
             let impl_ty = self.instantiate_type_scheme(span, &substs, ty);
-            match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
+            match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) {
                 Ok(ok) => self.register_infer_ok_obligations(ok),
                 Err(_) => {
                     self.tcx.sess.delay_span_bug(
diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs
index a5481fd175e..5dda8c47688 100644
--- a/library/alloc/src/collections/linked_list.rs
+++ b/library/alloc/src/collections/linked_list.rs
@@ -442,27 +442,6 @@ impl<T> LinkedList<T> {
         }
     }
 
-    /// Moves all elements from `other` to the begin of the list.
-    #[unstable(feature = "linked_list_prepend", issue = "none")]
-    pub fn prepend(&mut self, other: &mut Self) {
-        match self.head {
-            None => mem::swap(self, other),
-            Some(mut head) => {
-                // `as_mut` is okay here because we have exclusive access to the entirety
-                // of both lists.
-                if let Some(mut other_tail) = other.tail.take() {
-                    unsafe {
-                        head.as_mut().prev = Some(other_tail);
-                        other_tail.as_mut().next = Some(head);
-                    }
-
-                    self.head = other.head.take();
-                    self.len += mem::replace(&mut other.len, 0);
-                }
-            }
-        }
-    }
-
     /// Provides a forward iterator.
     ///
     /// # Examples
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index dbb51540bd4..f99eb9777d8 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -63,6 +63,7 @@ pub enum ControlFlow<B, C = ()> {
 }
 
 #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+#[cfg(bootstrap)]
 impl<B, C> ops::TryV1 for ControlFlow<B, C> {
     type Output = C;
     type Error = B;
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index beef74de617..139a8c0eec9 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -147,6 +147,7 @@ mod function;
 mod generator;
 mod index;
 mod range;
+#[cfg(bootstrap)]
 mod r#try;
 mod try_trait;
 mod unsize;
@@ -187,6 +188,7 @@ pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
 pub use self::r#try::Try;
 
 #[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
+#[cfg(bootstrap)]
 pub(crate) use self::r#try::Try as TryV1;
 
 #[unstable(feature = "try_trait_v2", issue = "84277")]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index cfc1768dee9..cfb73ed0395 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1641,9 +1641,11 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
 #[rustc_diagnostic_item = "none_error"]
 #[unstable(feature = "try_trait", issue = "42327")]
 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
+#[cfg(bootstrap)]
 pub struct NoneError;
 
 #[unstable(feature = "try_trait", issue = "42327")]
+#[cfg(bootstrap)]
 impl<T> ops::TryV1 for Option<T> {
     type Output = T;
     type Error = NoneError;
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 21e406194bc..babd0a0b552 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1627,6 +1627,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
 }
 
 #[unstable(feature = "try_trait", issue = "42327")]
+#[cfg(bootstrap)]
 impl<T, E> ops::TryV1 for Result<T, E> {
     type Output = T;
     type Error = E;
diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs
index 188639e7962..9cf89623d88 100644
--- a/library/core/src/task/poll.rs
+++ b/library/core/src/task/poll.rs
@@ -129,6 +129,7 @@ impl<T> From<T> for Poll<T> {
 }
 
 #[stable(feature = "futures_api", since = "1.36.0")]
+#[cfg(bootstrap)]
 impl<T, E> ops::TryV1 for Poll<Result<T, E>> {
     type Output = Poll<T>;
     type Error = E;
@@ -184,6 +185,7 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Pol
 }
 
 #[stable(feature = "futures_api", since = "1.36.0")]
+#[cfg(bootstrap)]
 impl<T, E> ops::TryV1 for Poll<Option<Result<T, E>>> {
     type Output = Poll<Option<T>>;
     type Error = E;
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index db12d79c00c..16bce6e35fe 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -44,7 +44,6 @@
 #![feature(str_internals)]
 #![feature(test)]
 #![feature(trusted_len)]
-#![feature(try_trait)]
 #![feature(try_trait_v2)]
 #![feature(slice_internals)]
 #![feature(slice_partition_dedup)]
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index a8f3412c611..b838a655346 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -526,7 +526,12 @@ pub trait Read {
     ///
     /// 1. This reader has reached its "end of file" and will likely no longer
     ///    be able to produce bytes. Note that this does not mean that the
-    ///    reader will *always* no longer be able to produce bytes.
+    ///    reader will *always* no longer be able to produce bytes. As an example,
+    ///    on Linux, this method will call the `recv` syscall for a [`TcpStream`],
+    ///    where returning zero indicates the connection was shut down correctly. While
+    ///    for [`File`], it is possible to reach the end of file and get zero as result,
+    ///    but if more data is appended to the file, future calls to `read` will return
+    ///    more data.
     /// 2. The buffer specified was 0 bytes in length.
     ///
     /// It is not an error if the returned value `n` is smaller than the buffer size,
@@ -568,6 +573,7 @@ pub trait Read {
     ///
     /// [`Ok(n)`]: Ok
     /// [`File`]: crate::fs::File
+    /// [`TcpStream`]: crate::net::TcpStream
     ///
     /// ```no_run
     /// use std::io;
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 9cf51be2836..913c71d4108 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -906,7 +906,7 @@ impl DirBuilderExt for fs::DirBuilder {
 /// }
 /// ```
 #[unstable(feature = "unix_chroot", issue = "84715")]
-#[cfg(not(target_os = "fuchsia"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
 pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
     sys::fs::chroot(dir.as_ref())
 }
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 96ab32104ea..d05b2ffc4e8 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -345,6 +345,9 @@ mod prim_never {}
 mod prim_char {}
 
 #[doc(primitive = "unit")]
+#[doc(alias = "(")]
+#[doc(alias = ")")]
+#[doc(alias = "()")]
 //
 /// The `()` type, also called "unit".
 ///
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index ef14865fbcd..f8ca67c844c 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1329,7 +1329,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     Ok(bytes_copied as u64)
 }
 
-#[cfg(not(target_os = "fuchsia"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
 pub fn chroot(dir: &Path) -> io::Result<()> {
     let dir = cstr(dir)?;
     cvt(unsafe { libc::chroot(dir.as_ptr()) })?;
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 7f8065e7500..ed55e1aa715 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -495,7 +495,7 @@ impl ExitStatus {
 
     pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
         // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0.  This is
-        // true on all actual versios of Unix, is widely assumed, and is specified in SuS
+        // true on all actual versions of Unix, is widely assumed, and is specified in SuS
         // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html .  If it is not
         // true for a platform pretending to be Unix, the tests (our doctests, and also
         // procsss_unix/tests.rs) will spot it.  `ExitStatusError::code` assumes this too.
diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs
index eecdb624b9c..c17822f5125 100644
--- a/library/std/src/sys/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/unix/process/process_vxworks.rs
@@ -1,5 +1,8 @@
+use crate::convert::{TryFrom, TryInto};
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
+use crate::num::NonZeroI32;
+use crate::os::raw::NonZero_c_int;
 use crate::sys;
 use crate::sys::cvt;
 use crate::sys::process::process_common::*;
@@ -187,8 +190,16 @@ impl ExitStatus {
         libc::WIFEXITED(self.0)
     }
 
-    pub fn success(&self) -> bool {
-        self.code() == Some(0)
+    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
+        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0.  This is
+        // true on all actual versions of Unix, is widely assumed, and is specified in SuS
+        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html .  If it is not
+        // true for a platform pretending to be Unix, the tests (our doctests, and also
+        // procsss_unix/tests.rs) will spot it.  `ExitStatusError::code` assumes this too.
+        match NonZero_c_int::try_from(self.0) {
+            Ok(failure) => Err(ExitStatusError(failure)),
+            Err(_) => Ok(()),
+        }
     }
 
     pub fn code(&self) -> Option<i32> {
@@ -235,3 +246,18 @@ impl fmt::Display for ExitStatus {
         }
     }
 }
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatusError(NonZero_c_int);
+
+impl Into<ExitStatus> for ExitStatusError {
+    fn into(self) -> ExitStatus {
+        ExitStatus(self.0.into())
+    }
+}
+
+impl ExitStatusError {
+    pub fn code(self) -> Option<NonZeroI32> {
+        ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
+    }
+}
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 50d6e8cf27a..b7efc884473 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -631,7 +631,7 @@ pub struct timeval {
     pub tv_usec: c_long,
 }
 
-// Functions forbidden when targeting UWP
+// Desktop specific functions & types
 cfg_if::cfg_if! {
 if #[cfg(not(target_vendor = "uwp"))] {
     pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
@@ -645,7 +645,7 @@ if #[cfg(not(target_vendor = "uwp"))] {
         pub ExceptionRecord: *mut EXCEPTION_RECORD,
         pub ExceptionAddress: LPVOID,
         pub NumberParameters: DWORD,
-        pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS]
+        pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS],
     }
 
     pub enum CONTEXT {}
@@ -656,8 +656,8 @@ if #[cfg(not(target_vendor = "uwp"))] {
         pub ContextRecord: *mut CONTEXT,
     }
 
-    pub type PVECTORED_EXCEPTION_HANDLER = extern "system"
-            fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG;
+    pub type PVECTORED_EXCEPTION_HANDLER =
+        extern "system" fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG;
 
     #[repr(C)]
     #[derive(Copy, Clone)]
@@ -691,44 +691,66 @@ if #[cfg(not(target_vendor = "uwp"))] {
 
     pub const TOKEN_READ: DWORD = 0x20008;
 
+    #[link(name = "advapi32")]
     extern "system" {
+        // Forbidden when targeting UWP
         #[link_name = "SystemFunction036"]
         pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
 
-        pub fn ReadConsoleW(hConsoleInput: HANDLE,
-                            lpBuffer: LPVOID,
-                            nNumberOfCharsToRead: DWORD,
-                            lpNumberOfCharsRead: LPDWORD,
-                            pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL;
+        // Allowed but unused by UWP
+        pub fn OpenProcessToken(
+            ProcessHandle: HANDLE,
+            DesiredAccess: DWORD,
+            TokenHandle: *mut HANDLE,
+        ) -> BOOL;
+    }
 
-        pub fn WriteConsoleW(hConsoleOutput: HANDLE,
-                             lpBuffer: LPCVOID,
-                             nNumberOfCharsToWrite: DWORD,
-                             lpNumberOfCharsWritten: LPDWORD,
-                             lpReserved: LPVOID) -> BOOL;
+    #[link(name = "userenv")]
+    extern "system" {
+        // Allowed but unused by UWP
+        pub fn GetUserProfileDirectoryW(
+            hToken: HANDLE,
+            lpProfileDir: LPWSTR,
+            lpcchSize: *mut DWORD,
+        ) -> BOOL;
+    }
 
-        pub fn GetConsoleMode(hConsoleHandle: HANDLE,
-                              lpMode: LPDWORD) -> BOOL;
+    #[link(name = "kernel32")]
+    extern "system" {
+        // Functions forbidden when targeting UWP
+        pub fn ReadConsoleW(
+            hConsoleInput: HANDLE,
+            lpBuffer: LPVOID,
+            nNumberOfCharsToRead: DWORD,
+            lpNumberOfCharsRead: LPDWORD,
+            pInputControl: PCONSOLE_READCONSOLE_CONTROL,
+        ) -> BOOL;
+
+        pub fn WriteConsoleW(
+            hConsoleOutput: HANDLE,
+            lpBuffer: LPCVOID,
+            nNumberOfCharsToWrite: DWORD,
+            lpNumberOfCharsWritten: LPDWORD,
+            lpReserved: LPVOID,
+        ) -> BOOL;
+
+        pub fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
         // Allowed but unused by UWP
-        pub fn OpenProcessToken(ProcessHandle: HANDLE,
-                                DesiredAccess: DWORD,
-                                TokenHandle: *mut HANDLE) -> BOOL;
-        pub fn GetUserProfileDirectoryW(hToken: HANDLE,
-                                        lpProfileDir: LPWSTR,
-                                        lpcchSize: *mut DWORD) -> BOOL;
-        pub fn GetFileInformationByHandle(hFile: HANDLE,
-                            lpFileInformation: LPBY_HANDLE_FILE_INFORMATION)
-                            -> BOOL;
-        pub fn SetHandleInformation(hObject: HANDLE,
-                                    dwMask: DWORD,
-                                    dwFlags: DWORD) -> BOOL;
-        pub fn AddVectoredExceptionHandler(FirstHandler: ULONG,
-                                           VectoredHandler: PVECTORED_EXCEPTION_HANDLER)
-                                           -> LPVOID;
-        pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR,
-                               lpTargetFileName: LPCWSTR,
-                               lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
-                               -> BOOL;
+        pub fn GetFileInformationByHandle(
+            hFile: HANDLE,
+            lpFileInformation: LPBY_HANDLE_FILE_INFORMATION,
+        ) -> BOOL;
+        pub fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) -> BOOL;
+        pub fn AddVectoredExceptionHandler(
+            FirstHandler: ULONG,
+            VectoredHandler: PVECTORED_EXCEPTION_HANDLER,
+        ) -> LPVOID;
+        pub fn CreateHardLinkW(
+            lpSymlinkFileName: LPCWSTR,
+            lpTargetFileName: LPCWSTR,
+            lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
+        ) -> BOOL;
+        pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL;
     }
 }
 }
@@ -747,55 +769,32 @@ if #[cfg(target_vendor = "uwp")] {
         pub Directory: BOOLEAN,
     }
 
+    #[link(name = "bcrypt")]
     extern "system" {
-        pub fn GetFileInformationByHandleEx(hFile: HANDLE,
-                                            fileInfoClass: FILE_INFO_BY_HANDLE_CLASS,
-                                            lpFileInformation: LPVOID,
-                                            dwBufferSize: DWORD) -> BOOL;
-        pub fn BCryptGenRandom(hAlgorithm: LPVOID, pBuffer: *mut u8,
-                               cbBuffer: ULONG, dwFlags: ULONG) -> LONG;
+        pub fn BCryptGenRandom(
+            hAlgorithm: LPVOID,
+            pBuffer: *mut u8,
+            cbBuffer: ULONG,
+            dwFlags: ULONG,
+        ) -> LONG;
+    }
+    #[link(name = "kernel32")]
+    extern "system" {
+        pub fn GetFileInformationByHandleEx(
+            hFile: HANDLE,
+            fileInfoClass: FILE_INFO_BY_HANDLE_CLASS,
+            lpFileInformation: LPVOID,
+            dwBufferSize: DWORD,
+        ) -> BOOL;
     }
 }
 }
 
 // Shared between Desktop & UWP
+
+#[link(name = "kernel32")]
 extern "system" {
-    pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int;
-    pub fn WSACleanup() -> c_int;
-    pub fn WSAGetLastError() -> c_int;
-    pub fn WSADuplicateSocketW(
-        s: SOCKET,
-        dwProcessId: DWORD,
-        lpProtocolInfo: LPWSAPROTOCOL_INFO,
-    ) -> c_int;
-    pub fn WSASend(
-        s: SOCKET,
-        lpBuffers: LPWSABUF,
-        dwBufferCount: DWORD,
-        lpNumberOfBytesSent: LPDWORD,
-        dwFlags: DWORD,
-        lpOverlapped: LPWSAOVERLAPPED,
-        lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
-    ) -> c_int;
-    pub fn WSARecv(
-        s: SOCKET,
-        lpBuffers: LPWSABUF,
-        dwBufferCount: DWORD,
-        lpNumberOfBytesRecvd: LPDWORD,
-        lpFlags: LPDWORD,
-        lpOverlapped: LPWSAOVERLAPPED,
-        lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
-    ) -> c_int;
     pub fn GetCurrentProcessId() -> DWORD;
-    pub fn WSASocketW(
-        af: c_int,
-        kind: c_int,
-        protocol: c_int,
-        lpProtocolInfo: LPWSAPROTOCOL_INFO,
-        g: GROUP,
-        dwFlags: DWORD,
-    ) -> SOCKET;
-    pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int;
     pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
     pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
     pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL;
@@ -882,28 +881,6 @@ extern "system" {
     pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
     pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD;
     pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
-
-    pub fn closesocket(socket: SOCKET) -> c_int;
-    pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int;
-    pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int;
-    pub fn recvfrom(
-        socket: SOCKET,
-        buf: *mut c_void,
-        len: c_int,
-        flags: c_int,
-        addr: *mut SOCKADDR,
-        addrlen: *mut c_int,
-    ) -> c_int;
-    pub fn sendto(
-        socket: SOCKET,
-        buf: *const c_void,
-        len: c_int,
-        flags: c_int,
-        addr: *const SOCKADDR,
-        addrlen: c_int,
-    ) -> c_int;
-    pub fn shutdown(socket: SOCKET, how: c_int) -> c_int;
-    pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET;
     pub fn DuplicateHandle(
         hSourceProcessHandle: HANDLE,
         hSourceHandle: HANDLE,
@@ -950,32 +927,6 @@ extern "system" {
     pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE;
     pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL;
     pub fn FindClose(findFile: HANDLE) -> BOOL;
-    pub fn getsockopt(
-        s: SOCKET,
-        level: c_int,
-        optname: c_int,
-        optval: *mut c_char,
-        optlen: *mut c_int,
-    ) -> c_int;
-    pub fn setsockopt(
-        s: SOCKET,
-        level: c_int,
-        optname: c_int,
-        optval: *const c_void,
-        optlen: c_int,
-    ) -> c_int;
-    pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
-    pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
-    pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int;
-    pub fn listen(socket: SOCKET, backlog: c_int) -> c_int;
-    pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int;
-    pub fn getaddrinfo(
-        node: *const c_char,
-        service: *const c_char,
-        hints: *const ADDRINFOA,
-        res: *mut *mut ADDRINFOA,
-    ) -> c_int;
-    pub fn freeaddrinfo(res: *mut ADDRINFOA);
 
     pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void;
     pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE;
@@ -1012,47 +963,23 @@ extern "system" {
         lpNumberOfBytesTransferred: LPDWORD,
         bWait: BOOL,
     ) -> BOOL;
-    pub fn select(
-        nfds: c_int,
-        readfds: *mut fd_set,
-        writefds: *mut fd_set,
-        exceptfds: *mut fd_set,
-        timeout: *const timeval,
-    ) -> c_int;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
     pub fn CreateSymbolicLinkW(
         lpSymlinkFileName: LPCWSTR,
         lpTargetFileName: LPCWSTR,
         dwFlags: DWORD,
     ) -> BOOLEAN;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
     pub fn GetFinalPathNameByHandleW(
         hFile: HANDLE,
         lpszFilePath: LPCWSTR,
         cchFilePath: DWORD,
         dwFlags: DWORD,
     ) -> DWORD;
-
-    // >= Vista / Server 2003
-    // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadstackguarantee
-    #[cfg(not(target_vendor = "uwp"))]
-    pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle
     pub fn SetFileInformationByHandle(
         hFile: HANDLE,
         FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
         lpFileInformation: LPVOID,
         dwBufferSize: DWORD,
     ) -> BOOL;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepconditionvariablesrw
     pub fn SleepConditionVariableSRW(
         ConditionVariable: PCONDITION_VARIABLE,
         SRWLock: PSRWLOCK,
@@ -1060,13 +987,9 @@ extern "system" {
         Flags: ULONG,
     ) -> BOOL;
 
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakeconditionvariable
     pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE);
     pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE);
 
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockexclusive
     pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK);
     pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK);
     pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK);
@@ -1075,6 +998,99 @@ extern "system" {
     pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN;
 }
 
+#[link(name = "ws2_32")]
+extern "system" {
+    pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int;
+    pub fn WSACleanup() -> c_int;
+    pub fn WSAGetLastError() -> c_int;
+    pub fn WSADuplicateSocketW(
+        s: SOCKET,
+        dwProcessId: DWORD,
+        lpProtocolInfo: LPWSAPROTOCOL_INFO,
+    ) -> c_int;
+    pub fn WSASend(
+        s: SOCKET,
+        lpBuffers: LPWSABUF,
+        dwBufferCount: DWORD,
+        lpNumberOfBytesSent: LPDWORD,
+        dwFlags: DWORD,
+        lpOverlapped: LPWSAOVERLAPPED,
+        lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
+    ) -> c_int;
+    pub fn WSARecv(
+        s: SOCKET,
+        lpBuffers: LPWSABUF,
+        dwBufferCount: DWORD,
+        lpNumberOfBytesRecvd: LPDWORD,
+        lpFlags: LPDWORD,
+        lpOverlapped: LPWSAOVERLAPPED,
+        lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
+    ) -> c_int;
+    pub fn WSASocketW(
+        af: c_int,
+        kind: c_int,
+        protocol: c_int,
+        lpProtocolInfo: LPWSAPROTOCOL_INFO,
+        g: GROUP,
+        dwFlags: DWORD,
+    ) -> SOCKET;
+    pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int;
+    pub fn closesocket(socket: SOCKET) -> c_int;
+    pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int;
+    pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int;
+    pub fn recvfrom(
+        socket: SOCKET,
+        buf: *mut c_void,
+        len: c_int,
+        flags: c_int,
+        addr: *mut SOCKADDR,
+        addrlen: *mut c_int,
+    ) -> c_int;
+    pub fn sendto(
+        socket: SOCKET,
+        buf: *const c_void,
+        len: c_int,
+        flags: c_int,
+        addr: *const SOCKADDR,
+        addrlen: c_int,
+    ) -> c_int;
+    pub fn shutdown(socket: SOCKET, how: c_int) -> c_int;
+    pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET;
+    pub fn getsockopt(
+        s: SOCKET,
+        level: c_int,
+        optname: c_int,
+        optval: *mut c_char,
+        optlen: *mut c_int,
+    ) -> c_int;
+    pub fn setsockopt(
+        s: SOCKET,
+        level: c_int,
+        optname: c_int,
+        optval: *const c_void,
+        optlen: c_int,
+    ) -> c_int;
+    pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
+    pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
+    pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int;
+    pub fn listen(socket: SOCKET, backlog: c_int) -> c_int;
+    pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int;
+    pub fn getaddrinfo(
+        node: *const c_char,
+        service: *const c_char,
+        hints: *const ADDRINFOA,
+        res: *mut *mut ADDRINFOA,
+    ) -> c_int;
+    pub fn freeaddrinfo(res: *mut ADDRINFOA);
+    pub fn select(
+        nfds: c_int,
+        readfds: *mut fd_set,
+        writefds: *mut fd_set,
+        exceptfds: *mut fd_set,
+        timeout: *const timeval,
+    ) -> c_int;
+}
+
 // Functions that aren't available on every version of Windows that we support,
 // but we still use them and just provide some form of a fallback implementation.
 compat_fn! {
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index cc60ca375ea..f23e874f249 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -281,17 +281,3 @@ pub fn abort_internal() -> ! {
     }
     crate::intrinsics::abort();
 }
-
-cfg_if::cfg_if! {
-    if #[cfg(target_vendor = "uwp")] {
-        #[link(name = "ws2_32")]
-        // For BCryptGenRandom
-        #[link(name = "bcrypt")]
-        extern "C" {}
-    } else {
-        #[link(name = "advapi32")]
-        #[link(name = "ws2_32")]
-        #[link(name = "userenv")]
-        extern "C" {}
-    }
-}
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index d462dc4d116..4b98abfb308 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -305,7 +305,7 @@ fn format_rusage_data(_child: Child) -> Option<String> {
     };
     // Mac OS X reports the maxrss in bytes, not kb.
     let divisor = if env::consts::OS == "macos" { 1024 } else { 1 };
-    let maxrss = rusage.ru_maxrss + (divisor - 1) / divisor;
+    let maxrss = (rusage.ru_maxrss + (divisor - 1)) / divisor;
 
     let mut init_str = format!(
         "user: {USER_SEC}.{USER_USEC:03} \
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 149a899cef7..bd5b3797ea8 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -991,28 +991,20 @@ class RustBuild(object):
         ).decode(default_encoding).splitlines()]
         filtered_submodules = []
         submodules_names = []
-        llvm_checked_out = os.path.exists(os.path.join(self.rust_root, "src/llvm-project/.git"))
-        external_llvm_provided = self.get_toml('llvm-config') or self.downloading_llvm()
-        llvm_needed = not self.get_toml('codegen-backends', 'rust') \
-            or "llvm" in self.get_toml('codegen-backends', 'rust')
         for module in submodules:
+            # This is handled by native::Llvm in rustbuild, not here
             if module.endswith("llvm-project"):
-                # Don't sync the llvm-project submodule if an external LLVM was
-                # provided, if we are downloading LLVM or if the LLVM backend is
-                # not being built. Also, if the submodule has been initialized
-                # already, sync it anyways so that it doesn't mess up contributor
-                # pull requests.
-                if external_llvm_provided or not llvm_needed:
-                    if self.get_toml('lld') != 'true' and not llvm_checked_out:
-                        continue
+                continue
             check = self.check_submodule(module, slow_submodules)
             filtered_submodules.append((module, check))
             submodules_names.append(module)
         recorded = subprocess.Popen(["git", "ls-tree", "HEAD"] + submodules_names,
                                     cwd=self.rust_root, stdout=subprocess.PIPE)
         recorded = recorded.communicate()[0].decode(default_encoding).strip().splitlines()
+        # { filename: hash }
         recorded_submodules = {}
         for data in recorded:
+            # [mode, kind, hash, filename]
             data = data.split()
             recorded_submodules[data[3]] = data[2]
         for module in filtered_submodules:
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 2960dd3df6b..a351290a420 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -472,12 +472,22 @@ impl Build {
         slice::from_ref(&self.build.triple)
     }
 
+    /// If the LLVM submodule has been initialized already, sync it unconditionally. This avoids
+    /// contributors checking in a submodule change by accident.
+    pub fn maybe_update_llvm_submodule(&self) {
+        if self.in_tree_llvm_info.is_git() {
+            native::update_llvm_submodule(self);
+        }
+    }
+
     /// Executes the entire build, as configured by the flags and configuration.
     pub fn build(&mut self) {
         unsafe {
             job::setup(self);
         }
 
+        self.maybe_update_llvm_submodule();
+
         if let Subcommand::Format { check, paths } = &self.config.cmd {
             return format::format(self, *check, &paths);
         }
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index bde0a96f030..44c281efe22 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -21,7 +21,7 @@ use build_helper::{output, t};
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::config::TargetSelection;
 use crate::util::{self, exe};
-use crate::GitRepo;
+use crate::{Build, GitRepo};
 use build_helper::up_to_date;
 
 pub struct Meta {
@@ -91,6 +91,85 @@ pub fn prebuilt_llvm_config(
     Err(Meta { stamp, build_llvm_config, out_dir, root: root.into() })
 }
 
+// modified from `check_submodule` and `update_submodule` in bootstrap.py
+pub(crate) fn update_llvm_submodule(build: &Build) {
+    let llvm_project = &Path::new("src").join("llvm-project");
+
+    fn dir_is_empty(dir: &Path) -> bool {
+        t!(std::fs::read_dir(dir)).next().is_none()
+    }
+
+    // NOTE: The check for the empty directory is here because when running x.py
+    // the first time, the llvm submodule won't be checked out. Check it out
+    // now so we can build it.
+    if !build.in_tree_llvm_info.is_git() && !dir_is_empty(&build.config.src.join(llvm_project)) {
+        return;
+    }
+
+    // check_submodule
+    let checked_out = if build.config.fast_submodules {
+        Some(output(
+            Command::new("git")
+                .args(&["rev-parse", "HEAD"])
+                .current_dir(build.config.src.join(llvm_project)),
+        ))
+    } else {
+        None
+    };
+
+    // update_submodules
+    let recorded = output(
+        Command::new("git")
+            .args(&["ls-tree", "HEAD"])
+            .arg(llvm_project)
+            .current_dir(&build.config.src),
+    );
+    let hash =
+        recorded.split(' ').nth(2).unwrap_or_else(|| panic!("unexpected output `{}`", recorded));
+
+    // update_submodule
+    if let Some(llvm_hash) = checked_out {
+        if hash == llvm_hash {
+            // already checked out
+            return;
+        }
+    }
+
+    println!("Updating submodule {}", llvm_project.display());
+    build.run(
+        Command::new("git")
+            .args(&["submodule", "-q", "sync"])
+            .arg(llvm_project)
+            .current_dir(&build.config.src),
+    );
+
+    // Try passing `--progress` to start, then run git again without if that fails.
+    let update = |progress: bool| {
+        let mut git = Command::new("git");
+        git.args(&["submodule", "update", "--init", "--recursive"]);
+        if progress {
+            git.arg("--progress");
+        }
+        git.arg(llvm_project).current_dir(&build.config.src);
+        git
+    };
+    // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
+    if !update(true).status().map_or(false, |status| status.success()) {
+        build.run(&mut update(false));
+    }
+
+    build.run(
+        Command::new("git")
+            .args(&["reset", "-q", "--hard"])
+            .current_dir(build.config.src.join(llvm_project)),
+    );
+    build.run(
+        Command::new("git")
+            .args(&["clean", "-qdfx"])
+            .current_dir(build.config.src.join(llvm_project)),
+    );
+}
+
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Llvm {
     pub target: TargetSelection,
@@ -128,6 +207,9 @@ impl Step for Llvm {
                 Err(m) => m,
             };
 
+        if !builder.config.dry_run {
+            update_llvm_submodule(builder);
+        }
         if builder.config.llvm_link_shared
             && (target.contains("windows") || target.contains("apple-darwin"))
         {
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index 80f804174ed..b1ec072f3f8 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -130,6 +130,7 @@ pub fn make(host: &str) -> PathBuf {
     }
 }
 
+#[track_caller]
 pub fn output(cmd: &mut Command) -> String {
     let output = match cmd.stderr(Stdio::inherit()).output() {
         Ok(status) => status,
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index b816b9d7188..5ce75949457 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -10,7 +10,7 @@ path = "lib.rs"
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 pulldown-cmark = { version = "0.8", default-features = false }
-minifier = "0.0.39"
+minifier = "0.0.41"
 rayon = { version = "0.3.0", package = "rustc-rayon" }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 3bfc9fea62e..35ff57f85a5 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -561,7 +561,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                 }
                 WherePredicate::EqPredicate { lhs, rhs } => {
                     match lhs {
-                        Type::QPath { name: left_name, ref self_type, ref trait_ } => {
+                        Type::QPath { name: left_name, ref self_type, ref trait_, .. } => {
                             let ty = &*self_type;
                             match **trait_ {
                                 Type::ResolvedPath {
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 6d05ac073cc..a14eefaf571 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -588,6 +588,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
                     self_type: box clean::Generic(ref s),
                     trait_: box clean::ResolvedPath { did, .. },
                     name: ref _name,
+                    ..
                 },
             ref bounds,
         } => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did),
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index feeb03b1b67..231f13adeb6 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -418,9 +418,11 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
             GenericBound::TraitBound(t, _) => t.trait_,
             GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"),
         };
+        let self_type = self.self_ty().clean(cx);
         Type::QPath {
             name: cx.tcx.associated_item(self.item_def_id).ident.name,
-            self_type: box self.self_ty().clean(cx),
+            self_def_id: self_type.def_id(),
+            self_type: box self_type,
             trait_: box trait_,
         }
     }
@@ -1104,7 +1106,7 @@ impl Clean<Item> for ty::AssocItem {
                         .filter_map(|pred| {
                             let (name, self_type, trait_, bounds) = match *pred {
                                 WherePredicate::BoundPredicate {
-                                    ty: QPath { ref name, ref self_type, ref trait_ },
+                                    ty: QPath { ref name, ref self_type, ref trait_, .. },
                                     ref bounds,
                                 } => (name, self_type, trait_, bounds),
                                 _ => return None,
@@ -1282,16 +1284,15 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
 
             let segments = if p.is_global() { &p.segments[1..] } else { &p.segments };
             let trait_segments = &segments[..segments.len() - 1];
+            let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id();
             let trait_path = self::Path {
                 global: p.is_global(),
-                res: Res::Def(
-                    DefKind::Trait,
-                    cx.tcx.associated_item(p.res.def_id()).container.id(),
-                ),
+                res: Res::Def(DefKind::Trait, trait_def),
                 segments: trait_segments.clean(cx),
             };
             Type::QPath {
                 name: p.segments.last().expect("segments were empty").ident.name,
+                self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
                 self_type: box qself.clean(cx),
                 trait_: box resolve_type(cx, trait_path, hir_id),
             }
@@ -1306,6 +1307,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
             let trait_path = hir::Path { span, res, segments: &[] }.clean(cx);
             Type::QPath {
                 name: segment.ident.name,
+                self_def_id: res.opt_def_id(),
                 self_type: box qself.clean(cx),
                 trait_: box resolve_type(cx, trait_path, hir_id),
             }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index edd3d77eeb7..de88e249b67 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1519,6 +1519,7 @@ crate enum Type {
     QPath {
         name: Symbol,
         self_type: Box<Type>,
+        self_def_id: Option<DefId>,
         trait_: Box<Type>,
     },
 
@@ -1665,7 +1666,7 @@ impl Type {
 
     crate fn projection(&self) -> Option<(&Type, DefId, Symbol)> {
         let (self_, trait_, name) = match self {
-            QPath { self_type, trait_, name } => (self_type, trait_, name),
+            QPath { self_type, trait_, name, .. } => (self_type, trait_, name),
             _ => return None,
         };
         let trait_did = match **trait_ {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 51a011cf197..2c31a502565 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -175,8 +175,9 @@ crate fn strip_type(ty: Type) -> Type {
         Type::BorrowedRef { lifetime, mutability, type_ } => {
             Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) }
         }
-        Type::QPath { name, self_type, trait_ } => Type::QPath {
+        Type::QPath { name, self_type, trait_, self_def_id } => Type::QPath {
             name,
+            self_def_id,
             self_type: Box::new(strip_type(*self_type)),
             trait_: Box::new(strip_type(*trait_)),
         },
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index fa57c9bda74..3c1d03a78f1 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -18,7 +18,7 @@ use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_target::spec::abi::Abi;
 
 use crate::clean::{
-    self, utils::find_nearest_parent_module, ExternalCrate, FakeDefId, PrimitiveType,
+    self, utils::find_nearest_parent_module, ExternalCrate, FakeDefId, GetDefId, PrimitiveType,
 };
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
@@ -836,10 +836,13 @@ fn fmt_type<'cx>(
                 write!(f, "impl {}", print_generic_bounds(bounds, cx))
             }
         }
-        clean::QPath { ref name, ref self_type, ref trait_ } => {
+        clean::QPath { ref name, ref self_type, ref trait_, ref self_def_id } => {
             let should_show_cast = match *trait_ {
                 box clean::ResolvedPath { ref path, .. } => {
-                    !path.segments.is_empty() && !self_type.is_self_type()
+                    !path.segments.is_empty()
+                        && self_def_id
+                            .zip(trait_.def_id())
+                            .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_)
                 }
                 _ => true,
             };
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 318e1b44f86..29b10fb8457 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1542,24 +1542,33 @@ fn render_impl(
         }
     }
     let toggled = !impl_items.is_empty() || !default_impl_items.is_empty();
-    let open_details = |close_tags: &mut String| {
+    let open_details = |close_tags: &mut String, is_collapsed: bool| {
         if toggled {
             close_tags.insert_str(0, "</details>");
-            "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+            if is_collapsed {
+                "<details class=\"rustdoc-toggle implementors-toggle\"><summary>"
+            } else {
+                "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+            }
         } else {
             ""
         }
     };
     if render_mode == RenderMode::Normal {
+        let is_implementing_trait;
         let id = cx.derive_id(match i.inner_impl().trait_ {
             Some(ref t) => {
+                is_implementing_trait = true;
                 if is_on_foreign_type {
                     get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
                 } else {
                     format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
                 }
             }
-            None => "impl".to_string(),
+            None => {
+                is_implementing_trait = false;
+                "impl".to_string()
+            }
         });
         let aliases = if aliases.is_empty() {
             String::new()
@@ -1570,7 +1579,7 @@ fn render_impl(
             write!(
                 w,
                 "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">",
-                open_details(&mut close_tags),
+                open_details(&mut close_tags, is_implementing_trait),
                 id,
                 aliases
             );
@@ -1597,7 +1606,7 @@ fn render_impl(
             write!(
                 w,
                 "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
-                open_details(&mut close_tags),
+                open_details(&mut close_tags, is_implementing_trait),
                 id,
                 aliases,
                 i.inner_impl().print(false, cx)
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 1ed94ec109c..a96b0c87108 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -764,138 +764,6 @@ function hideThemeButtonState() {
         innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed);
     }
 
-    function collapseDocs(toggle, mode) {
-        if (!toggle || !toggle.parentNode) {
-            return;
-        }
-
-        function adjustToggle(arg) {
-            return function(e) {
-                if (hasClass(e, "toggle-label")) {
-                    if (arg) {
-                        e.style.display = "inline-block";
-                    } else {
-                        e.style.display = "none";
-                    }
-                }
-                if (hasClass(e, "inner")) {
-                    e.innerHTML = labelForToggleButton(arg);
-                }
-            };
-        }
-
-        function implHider(addOrRemove, fullHide) {
-            return function(n) {
-                var shouldHide =
-                    fullHide ||
-                    hasClass(n, "method") ||
-                    hasClass(n, "associatedconstant");
-                if (shouldHide || hasClass(n, "type")) {
-                    if (shouldHide) {
-                        if (addOrRemove) {
-                            addClass(n, "hidden-by-impl-hider");
-                        } else {
-                            removeClass(n, "hidden-by-impl-hider");
-                        }
-                    }
-                    var ns = n.nextElementSibling;
-                    while (ns && (hasClass(ns, "docblock") || hasClass(ns, "item-info"))) {
-                        if (addOrRemove) {
-                            addClass(ns, "hidden-by-impl-hider");
-                        } else {
-                            removeClass(ns, "hidden-by-impl-hider");
-                        }
-                        ns = ns.nextElementSibling;
-                    }
-                }
-            };
-        }
-
-        var relatedDoc;
-        var action = mode;
-        if (!hasClass(toggle.parentNode, "impl")) {
-            relatedDoc = toggle.parentNode.nextElementSibling;
-            if (hasClass(relatedDoc, "item-info")) {
-                relatedDoc = relatedDoc.nextElementSibling;
-            }
-            if (hasClass(relatedDoc, "docblock")) {
-                if (mode === "toggle") {
-                    if (hasClass(relatedDoc, "hidden-by-usual-hider")) {
-                        action = "show";
-                    } else {
-                        action = "hide";
-                    }
-                }
-                if (action === "hide") {
-                    addClass(relatedDoc, "hidden-by-usual-hider");
-                    onEachLazy(toggle.childNodes, adjustToggle(true));
-                    addClass(toggle.parentNode, "collapsed");
-                } else if (action === "show") {
-                    removeClass(relatedDoc, "hidden-by-usual-hider");
-                    removeClass(toggle.parentNode, "collapsed");
-                    onEachLazy(toggle.childNodes, adjustToggle(false));
-                }
-            }
-        } else {
-            // we are collapsing the impl block(s).
-
-            var parentElem = toggle.parentNode;
-            relatedDoc = parentElem;
-            var docblock = relatedDoc.nextElementSibling;
-
-            while (!hasClass(relatedDoc, "impl-items")) {
-                relatedDoc = relatedDoc.nextElementSibling;
-            }
-
-            if (!relatedDoc && !hasClass(docblock, "docblock")) {
-                return;
-            }
-
-            // Hide all functions, but not associated types/consts.
-
-            if (mode === "toggle") {
-                if (hasClass(relatedDoc, "fns-now-collapsed") ||
-                    hasClass(docblock, "hidden-by-impl-hider")) {
-                    action = "show";
-                } else {
-                    action = "hide";
-                }
-            }
-
-            var dontApplyBlockRule = toggle.parentNode.parentNode.id !== "main";
-            if (action === "show") {
-                removeClass(relatedDoc, "fns-now-collapsed");
-                // Stability/deprecation/portability information is never hidden.
-                if (!hasClass(docblock, "item-info")) {
-                    removeClass(docblock, "hidden-by-usual-hider");
-                }
-                onEachLazy(toggle.childNodes, adjustToggle(false, dontApplyBlockRule));
-                onEachLazy(relatedDoc.childNodes, implHider(false, dontApplyBlockRule));
-            } else if (action === "hide") {
-                addClass(relatedDoc, "fns-now-collapsed");
-                // Stability/deprecation/portability information should be shown even when detailed
-                // info is hidden.
-                if (!hasClass(docblock, "item-info")) {
-                    addClass(docblock, "hidden-by-usual-hider");
-                }
-                onEachLazy(toggle.childNodes, adjustToggle(true, dontApplyBlockRule));
-                onEachLazy(relatedDoc.childNodes, implHider(true, dontApplyBlockRule));
-            }
-        }
-    }
-
-    function collapseNonInherent(e) {
-        // inherent impl ids are like "impl" or impl-<number>'.
-        // they will never be hidden by default.
-        var n = e.parentElement;
-        if (n.id.match(/^impl(?:-\d+)?$/) === null) {
-            // Automatically minimize all non-inherent impls
-            if (hasClass(n, "impl")) {
-                collapseDocs(e, "hide");
-            }
-        }
-    }
-
     function insertAfter(newNode, referenceNode) {
         referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
     }
@@ -908,26 +776,29 @@ function hideThemeButtonState() {
 
         var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
         var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
+        var hideImplementations = getSettingValue("auto-hide-trait-implementations") !== "false";
         var hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
 
-        var impl_list = document.getElementById("trait-implementations-list");
-        if (impl_list !== null) {
-            onEachLazy(impl_list.getElementsByClassName("rustdoc-toggle"), function(e) {
-                collapseNonInherent(e);
-            });
+        function openImplementors(id) {
+            var list = document.getElementById(id);
+            if (list !== null) {
+                onEachLazy(list.getElementsByClassName("implementors-toggle"), function(e) {
+                    e.open = true;
+                });
+            }
         }
 
-        var blanket_list = document.getElementById("blanket-implementations-list");
-        if (blanket_list !== null) {
-            onEachLazy(blanket_list.getElementsByClassName("rustdoc-toggle"), function(e) {
-                collapseNonInherent(e);
-            });
+        if (!hideImplementations) {
+            openImplementors("trait-implementations-list");
+            openImplementors("blanket-implementations-list");
         }
 
-        onEachLazy(document.getElementsByTagName("details"), function (e) {
-            var showLargeItem = !hideLargeItemContents && hasClass(e, "type-contents-toggle");
-            var showImplementor = !hideImplementors && hasClass(e, "implementors-toggle");
-            if (showLargeItem || showImplementor) {
+        if (!hideImplementors) {
+            openImplementors("implementors-list");
+        }
+
+        onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function (e) {
+            if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) {
                 e.open = true;
             }
             if (hideMethodDocs && hasClass(e, "method-toggle")) {
@@ -936,18 +807,6 @@ function hideThemeButtonState() {
 
         });
 
-        var currentType = document.getElementsByClassName("type-decl")[0];
-        if (currentType) {
-            currentType = currentType.getElementsByClassName("rust")[0];
-            if (currentType) {
-                onEachLazy(currentType.classList, function(item) {
-                    if (item !== "main") {
-                        return true;
-                    }
-                });
-            }
-        }
-
         var pageId = getPageId();
         if (pageId !== null) {
             expandSection(pageId);
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 6d581108836..9c5e3e8bfb2 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -780,12 +780,12 @@ a {
 	float: left;
 }
 
-tr.result span.primitive::after {
+.result-name span.primitive::after {
 	content: ' (primitive type)';
 	font-style: italic;
 }
 
-tr.result span.keyword::after {
+.result-name span.keyword::after {
 	content: ' (keyword)';
 	font-style: italic;
 }
diff --git a/src/librustdoc/html/static/search.js b/src/librustdoc/html/static/search.js
index 01cfffc5429..c95136d40d3 100644
--- a/src/librustdoc/html/static/search.js
+++ b/src/librustdoc/html/static/search.js
@@ -885,12 +885,12 @@ window.initSearch = function(rawSearchIndex) {
         focusSearchResult();
     }
 
-    // focus the first search result on the active tab, or the result that
+    // Focus the first search result on the active tab, or the result that
     // was focused last time this tab was active.
     function focusSearchResult() {
         var target = searchState.focusedByTab[searchState.currentTab] ||
-          document.querySelectorAll(".search-results.active a").item(0) ||
-          document.querySelectorAll("#titles > button").item(searchState.currentTab);
+            document.querySelectorAll(".search-results.active a").item(0) ||
+            document.querySelectorAll("#titles > button").item(searchState.currentTab);
         if (target) {
             target.focus();
         }
@@ -1076,6 +1076,8 @@ window.initSearch = function(rawSearchIndex) {
             ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
 
         search.innerHTML = output;
+        // Reset focused elements.
+        searchState.focusedByTab = [null, null, null];
         searchState.showResults(search);
         var elems = document.getElementById("titles").childNodes;
         elems[0].onclick = function() { printTab(0); };
@@ -1365,7 +1367,6 @@ window.initSearch = function(rawSearchIndex) {
             if (e.which === 38) { // up
                 var previous = document.activeElement.previousElementSibling;
                 if (previous) {
-                    console.log("previousElementSibling", previous);
                     previous.focus();
                 } else {
                     searchState.focus();
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 5ac43c73646..c6646ba9ae4 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -396,7 +396,7 @@ impl FromWithTcx<clean::Type> for Type {
                 mutable: mutability == ast::Mutability::Mut,
                 type_: Box::new((*type_).into_tcx(tcx)),
             },
-            QPath { name, self_type, trait_ } => Type::QualifiedPath {
+            QPath { name, self_type, trait_, .. } => Type::QualifiedPath {
                 name: name.to_string(),
                 self_type: Box::new((*self_type).into_tcx(tcx)),
                 trait_: Box::new((*trait_).into_tcx(tcx)),
diff --git a/src/test/rustdoc-gui/search-result-keyword.goml b/src/test/rustdoc-gui/search-result-keyword.goml
new file mode 100644
index 00000000000..23552c8ce89
--- /dev/null
+++ b/src/test/rustdoc-gui/search-result-keyword.goml
@@ -0,0 +1,11 @@
+goto: file://|DOC_PATH|/test_docs/index.html
+write: (".search-input", "CookieMonster")
+// Waiting for the search results to appear...
+wait-for: "#titles"
+// Note: The two next assert commands could be merged as one but readability would be
+// less good.
+//
+// Checking that the CSS is displaying " (keyword)"...
+assert: (".result-name span.keyword::after", {"content": '" (keyword)"'})
+// ... in italic.
+assert: (".result-name span.keyword::after", {"font-style": "italic"})
diff --git a/src/test/rustdoc-gui/src/lib.rs b/src/test/rustdoc-gui/src/lib.rs
index eeba3e3f907..7b247a19b8e 100644
--- a/src/test/rustdoc-gui/src/lib.rs
+++ b/src/test/rustdoc-gui/src/lib.rs
@@ -2,6 +2,7 @@
 //! documentation generated so we can test each different features.
 
 #![crate_name = "test_docs"]
+#![feature(doc_keyword)]
 
 use std::fmt;
 
@@ -91,3 +92,6 @@ pub fn check_list_code_block() {}
 pub enum AnEnum {
     WithVariants { and: usize, sub: usize, variants: usize },
 }
+
+#[doc(keyword = "CookieMonster")]
+pub mod keyword {}
diff --git a/src/test/rustdoc/issue-85454.rs b/src/test/rustdoc/issue-85454.rs
new file mode 100644
index 00000000000..45664dfc382
--- /dev/null
+++ b/src/test/rustdoc/issue-85454.rs
@@ -0,0 +1,17 @@
+// @has issue_85454/trait.FromResidual.html
+// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+pub trait FromResidual<R = <Self as Try>::Residual> {
+    fn from_residual(residual: R) -> Self;
+}
+
+pub trait Try: FromResidual {
+    type Output;
+    type Residual;
+    fn from_output(output: Self::Output) -> Self;
+    fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
+}
+
+pub enum ControlFlow<B, C = ()> {
+    Continue(C),
+    Break(B),
+}
diff --git a/src/test/rustdoc/manual_impl.rs b/src/test/rustdoc/manual_impl.rs
index 776a191ceef..5b448bd1923 100644
--- a/src/test/rustdoc/manual_impl.rs
+++ b/src/test/rustdoc/manual_impl.rs
@@ -65,7 +65,8 @@ impl T for S2 {
 }
 
 // @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
-// @has  - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
+// @has  - '//details/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
+// @!has  - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
 // @has  - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
 // @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
 // @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
diff --git a/src/test/ui/cast/cast-ptr-to-int-const.mir.stderr b/src/test/ui/cast/cast-ptr-to-int-const.mir.stderr
new file mode 100644
index 00000000000..dcc9a243f0f
--- /dev/null
+++ b/src/test/ui/cast/cast-ptr-to-int-const.mir.stderr
@@ -0,0 +1,19 @@
+error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
+  --> $DIR/cast-ptr-to-int-const.rs:10:9
+   |
+LL |         &Y as *const u32 as usize
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
+   |
+   = note: casting pointers to integers in constants
+
+error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
+  --> $DIR/cast-ptr-to-int-const.rs:17:5
+   |
+LL |     &0 as *const i32 as usize
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
+   |
+   = note: casting pointers to integers in constants
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/cast/cast-ptr-to-int-const.rs b/src/test/ui/cast/cast-ptr-to-int-const.rs
index aed099a53ea..01ea627679d 100644
--- a/src/test/ui/cast/cast-ptr-to-int-const.rs
+++ b/src/test/ui/cast/cast-ptr-to-int-const.rs
@@ -1,25 +1,19 @@
-// gate-test-const_raw_ptr_to_usize_cast
-// revisions: with_feature without_feature
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 
-#![cfg_attr(with_feature, feature(const_raw_ptr_to_usize_cast))]
+#![feature(const_raw_ptr_to_usize_cast)]
 
 fn main() {
-    const X: usize = unsafe {
-        main as usize //[without_feature]~ ERROR casting pointers to integers in constants is unstable
-    };
     const Y: u32 = 0;
-    const Z: usize = unsafe {
-        &Y as *const u32 as usize //[without_feature]~ ERROR is unstable
-    };
     // Cast in `const` without `unsafe` block
     const SAFE: usize = {
-        &Y as *const u32 as usize //[without_feature]~ ERROR is unstable
-        //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe
+        &Y as *const u32 as usize
+        //~^ ERROR cast of pointer to int is unsafe and requires unsafe
     };
 }
 
 // Cast in `const fn` without `unsafe` block
 const fn test() -> usize {
-    &0 as *const i32 as usize //[without_feature]~ ERROR is unstable
-    //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe
+    &0 as *const i32 as usize
+    //~^ ERROR cast of pointer to int is unsafe and requires unsafe
 }
diff --git a/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr b/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr
new file mode 100644
index 00000000000..dcc9a243f0f
--- /dev/null
+++ b/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr
@@ -0,0 +1,19 @@
+error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
+  --> $DIR/cast-ptr-to-int-const.rs:10:9
+   |
+LL |         &Y as *const u32 as usize
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
+   |
+   = note: casting pointers to integers in constants
+
+error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
+  --> $DIR/cast-ptr-to-int-const.rs:17:5
+   |
+LL |     &0 as *const i32 as usize
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
+   |
+   = note: casting pointers to integers in constants
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs
new file mode 100644
index 00000000000..03e99eb7527
--- /dev/null
+++ b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs
@@ -0,0 +1,13 @@
+fn main() {
+    const X: usize = unsafe {
+        main as usize //~ ERROR casting pointers to integers in constants is unstable
+    };
+    const Y: u32 = 0;
+    const Z: usize = unsafe {
+        &Y as *const u32 as usize //~ ERROR is unstable
+    };
+}
+
+const fn test() -> usize {
+    &0 as *const i32 as usize //~ ERROR is unstable
+}
diff --git a/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.stderr b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.stderr
new file mode 100644
index 00000000000..4a0b424e181
--- /dev/null
+++ b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.stderr
@@ -0,0 +1,30 @@
+error[E0658]: casting pointers to integers in constants is unstable
+  --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:3:9
+   |
+LL |         main as usize
+   |         ^^^^^^^^^^^^^
+   |
+   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
+   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+
+error[E0658]: casting pointers to integers in constants is unstable
+  --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:7:9
+   |
+LL |         &Y as *const u32 as usize
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
+   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+
+error[E0658]: casting pointers to integers in constant functions is unstable
+  --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:12:5
+   |
+LL |     &0 as *const i32 as usize
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
+   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const_fn_unsize.gated.stderr b/src/test/ui/consts/const_fn_unsize.gated.stderr
deleted file mode 100644
index 8a65c274ca9..00000000000
--- a/src/test/ui/consts/const_fn_unsize.gated.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: fatal error triggered by #[rustc_error]
-  --> $DIR/const_fn_unsize.rs:16:1
-   |
-LL | fn main() {}
-   | ^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/consts/const_fn_unsize.rs b/src/test/ui/consts/const_fn_unsize.rs
index 0cab3b0a031..01da57320c2 100644
--- a/src/test/ui/consts/const_fn_unsize.rs
+++ b/src/test/ui/consts/const_fn_unsize.rs
@@ -1,16 +1,21 @@
-// gate-test-const_fn_unsize
-
-// revisions: stock gated
-
-#![feature(rustc_attrs)]
-#![cfg_attr(gated, feature(const_fn_unsize))]
+// run-pass
+#![feature(slice_ptr_len)]
 
 use std::ptr::NonNull;
 
+#[allow(unused)]
 const fn test() {
     let _x = NonNull::<[i32; 0]>::dangling() as NonNull<[i32]>;
-    //[stock]~^ unsizing cast
 }
 
-#[rustc_error]
-fn main() {} //[gated]~ fatal error triggered by #[rustc_error]
+// Regression test for #75118.
+pub const fn dangling_slice<T>() -> NonNull<[T]> {
+    NonNull::<[T; 1]>::dangling()
+}
+
+const C: NonNull<[i32]> = dangling_slice();
+
+fn main() {
+    assert_eq!(C.as_ptr(), NonNull::<[i32; 1]>::dangling().as_ptr() as *mut _);
+    assert_eq!(C.as_ptr().len(), 1);
+}
diff --git a/src/test/ui/consts/const_fn_unsize.stock.stderr b/src/test/ui/consts/const_fn_unsize.stock.stderr
deleted file mode 100644
index cc746d4f175..00000000000
--- a/src/test/ui/consts/const_fn_unsize.stock.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
-  --> $DIR/const_fn_unsize.rs:11:14
-   |
-LL |     let _x = NonNull::<[i32; 0]>::dangling() as NonNull<[i32]>;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs
index e46127c36bf..b7904e6841b 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs
@@ -133,13 +133,13 @@ const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
 //~^ ERROR trait bounds other than `Sized`
 const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
 //~^ ERROR trait bounds other than `Sized`
-//~| ERROR unsizing cast
-//~| ERROR unsizing cast
 
 const fn no_unsafe() { unsafe {} }
 
 const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-//~^ ERROR unsizing cast
+//~^ ERROR trait bounds other than `Sized`
+//~| ERROR trait bounds other than `Sized`
+//~| ERROR trait bounds other than `Sized`
 
 const fn no_fn_ptrs(_x: fn()) {}
 //~^ ERROR function pointer
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
index e6ce7e12520..d31d4121936 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
@@ -288,32 +288,32 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
-  --> $DIR/min_const_fn.rs:134:63
+error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:139:41
    |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-   |                                                               ^^^
+LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
-  --> $DIR/min_const_fn.rs:134:63
+error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:139:42
    |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-   |                                                               ^^^
+LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
-  --> $DIR/min_const_fn.rs:141:42
+error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:139:42
    |
 LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-   |                                          ^^^
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/min_const_fn.rs:144:21
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
index 4a22ef2dffd..6ca1e59b3af 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
@@ -10,6 +10,6 @@ const fn no_inner_dyn_trait2(x: Hide) {
 //~^ ERROR trait bounds other than `Sized`
 }
 const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
-//~^ ERROR unsizing cast
+//~^ ERROR trait bounds other than `Sized`
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
index cf635d65699..ce844a2f071 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
@@ -7,14 +7,14 @@ LL |     x.0.field;
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
+error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
   --> $DIR/min_const_fn_dyn.rs:12:66
    |
 LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
    |                                                                  ^^
    |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/unsizing-cast-non-null.rs b/src/test/ui/consts/unsizing-cast-non-null.rs
deleted file mode 100644
index af6bc2d85fd..00000000000
--- a/src/test/ui/consts/unsizing-cast-non-null.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Regression test for #75118.
-
-use std::ptr::NonNull;
-
-pub const fn dangling_slice<T>() -> NonNull<[T]> {
-    NonNull::<[T; 0]>::dangling()
-    //~^ ERROR: unsizing casts to types besides slices
-}
-
-fn main() {}
diff --git a/src/test/ui/consts/unsizing-cast-non-null.stderr b/src/test/ui/consts/unsizing-cast-non-null.stderr
deleted file mode 100644
index 79691cddfb4..00000000000
--- a/src/test/ui/consts/unsizing-cast-non-null.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
-  --> $DIR/unsizing-cast-non-null.rs:6:5
-   |
-LL |     NonNull::<[T; 0]>::dangling()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr b/src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr
index 0bd3dbf6863..3afbea07931 100644
--- a/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr
+++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/issue-45729-unsafe-in-generator.rs:5:9
+  --> $DIR/issue-45729-unsafe-in-generator.rs:8:9
    |
 LL |         *(1 as *mut u32) = 42;
    |         ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.rs b/src/test/ui/generator/issue-45729-unsafe-in-generator.rs
index 638a1994bb5..379c36d2ca3 100644
--- a/src/test/ui/generator/issue-45729-unsafe-in-generator.rs
+++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![feature(generators)]
 
 fn main() {
diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr b/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr
new file mode 100644
index 00000000000..a0905f98ca7
--- /dev/null
+++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45729-unsafe-in-generator.rs:8:9
+   |
+LL |         *(1 as *mut u32) = 42;
+   |         ^^^^^^^^^^^^^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/intrinsics/issue-28575.stderr b/src/test/ui/intrinsics/issue-28575.mir.stderr
index 66369decf42..c42498390c7 100644
--- a/src/test/ui/intrinsics/issue-28575.stderr
+++ b/src/test/ui/intrinsics/issue-28575.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/issue-28575.rs:8:5
+  --> $DIR/issue-28575.rs:11:5
    |
 LL |     FOO()
    |     ^^^ use of extern static
diff --git a/src/test/ui/intrinsics/issue-28575.rs b/src/test/ui/intrinsics/issue-28575.rs
index 141136d25b2..410f664f89d 100644
--- a/src/test/ui/intrinsics/issue-28575.rs
+++ b/src/test/ui/intrinsics/issue-28575.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![feature(intrinsics)]
 
 extern "C" {
diff --git a/src/test/ui/intrinsics/issue-28575.thir.stderr b/src/test/ui/intrinsics/issue-28575.thir.stderr
new file mode 100644
index 00000000000..c42498390c7
--- /dev/null
+++ b/src/test/ui/intrinsics/issue-28575.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/issue-28575.rs:11:5
+   |
+LL |     FOO()
+   |     ^^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/issues/issue-14227.stderr b/src/test/ui/issues/issue-14227.mir.stderr
index f9cdbe452df..8e7a2514dd6 100644
--- a/src/test/ui/issues/issue-14227.stderr
+++ b/src/test/ui/issues/issue-14227.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/issue-14227.rs:4:21
+  --> $DIR/issue-14227.rs:7:21
    |
 LL | static CRASH: u32 = symbol;
    |                     ^^^^^^ use of extern static
diff --git a/src/test/ui/issues/issue-14227.rs b/src/test/ui/issues/issue-14227.rs
index a1fde14600a..5f866ec9061 100644
--- a/src/test/ui/issues/issue-14227.rs
+++ b/src/test/ui/issues/issue-14227.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 extern "C" {
     pub static symbol: u32;
 }
diff --git a/src/test/ui/issues/issue-14227.thir.stderr b/src/test/ui/issues/issue-14227.thir.stderr
new file mode 100644
index 00000000000..8e7a2514dd6
--- /dev/null
+++ b/src/test/ui/issues/issue-14227.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/issue-14227.rs:7:21
+   |
+LL | static CRASH: u32 = symbol;
+   |                     ^^^^^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/issues/issue-16538.stderr b/src/test/ui/issues/issue-16538.mir.stderr
index 81a91db3711..d7e8c08bb01 100644
--- a/src/test/ui/issues/issue-16538.stderr
+++ b/src/test/ui/issues/issue-16538.mir.stderr
@@ -1,11 +1,11 @@
 error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/issue-16538.rs:11:27
+  --> $DIR/issue-16538.rs:14:27
    |
 LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: `*const usize` cannot be shared between threads safely
-  --> $DIR/issue-16538.rs:11:1
+  --> $DIR/issue-16538.rs:14:1
    |
 LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely
@@ -14,7 +14,7 @@ LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
    = note: shared static variables must have a type that implements `Sync`
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/issue-16538.rs:11:34
+  --> $DIR/issue-16538.rs:14:34
    |
 LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
    |                                  ^^^^ use of extern static
diff --git a/src/test/ui/issues/issue-16538.rs b/src/test/ui/issues/issue-16538.rs
index 7d6eefa5b1e..1e8ecf015c8 100644
--- a/src/test/ui/issues/issue-16538.rs
+++ b/src/test/ui/issues/issue-16538.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 mod Y {
     pub type X = usize;
     extern "C" {
diff --git a/src/test/ui/issues/issue-16538.thir.stderr b/src/test/ui/issues/issue-16538.thir.stderr
new file mode 100644
index 00000000000..d7e8c08bb01
--- /dev/null
+++ b/src/test/ui/issues/issue-16538.thir.stderr
@@ -0,0 +1,27 @@
+error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/issue-16538.rs:14:27
+   |
+LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: `*const usize` cannot be shared between threads safely
+  --> $DIR/issue-16538.rs:14:1
+   |
+LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `*const usize`
+   = note: shared static variables must have a type that implements `Sync`
+
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/issue-16538.rs:14:34
+   |
+LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
+   |                                  ^^^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0015, E0133, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/issues/issue-28324.stderr b/src/test/ui/issues/issue-28324.mir.stderr
index d7dad992152..aff8bf7927d 100644
--- a/src/test/ui/issues/issue-28324.stderr
+++ b/src/test/ui/issues/issue-28324.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/issue-28324.rs:5:24
+  --> $DIR/issue-28324.rs:8:24
    |
 LL | pub static BAZ: u32 = *&error_message_count;
    |                        ^^^^^^^^^^^^^^^^^^^^ use of extern static
diff --git a/src/test/ui/issues/issue-28324.rs b/src/test/ui/issues/issue-28324.rs
index f74726e8166..fbe83e325ed 100644
--- a/src/test/ui/issues/issue-28324.rs
+++ b/src/test/ui/issues/issue-28324.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 extern "C" {
     static error_message_count: u32;
 }
diff --git a/src/test/ui/issues/issue-28324.thir.stderr b/src/test/ui/issues/issue-28324.thir.stderr
new file mode 100644
index 00000000000..c696c359830
--- /dev/null
+++ b/src/test/ui/issues/issue-28324.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/issue-28324.rs:8:25
+   |
+LL | pub static BAZ: u32 = *&error_message_count;
+   |                         ^^^^^^^^^^^^^^^^^^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/issues/issue-47412.stderr b/src/test/ui/issues/issue-47412.mir.stderr
index aebcbf07463..96e50ba6799 100644
--- a/src/test/ui/issues/issue-47412.stderr
+++ b/src/test/ui/issues/issue-47412.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/issue-47412.rs:11:11
+  --> $DIR/issue-47412.rs:14:11
    |
 LL |     match u.void {}
    |           ^^^^^^ access to union field
@@ -7,7 +7,7 @@ LL |     match u.void {}
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/issue-47412.rs:17:11
+  --> $DIR/issue-47412.rs:21:11
    |
 LL |     match *ptr {}
    |           ^^^^ dereference of raw pointer
diff --git a/src/test/ui/issues/issue-47412.rs b/src/test/ui/issues/issue-47412.rs
index 2d1ea72280b..d395285eee0 100644
--- a/src/test/ui/issues/issue-47412.rs
+++ b/src/test/ui/issues/issue-47412.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #[derive(Copy, Clone)]
 enum Void {}
 
@@ -9,7 +12,8 @@ fn union_field() {
     union Union { unit: (), void: Void }
     let u = Union { unit: () };
     match u.void {}
-    //~^ ERROR access to union field is unsafe
+    //[mir]~^ ERROR access to union field is unsafe
+    // FIXME(thir-unsafeck): AccessToUnionField unimplemented
 }
 
 fn raw_ptr_deref() {
diff --git a/src/test/ui/issues/issue-47412.thir.stderr b/src/test/ui/issues/issue-47412.thir.stderr
new file mode 100644
index 00000000000..2d6004b7911
--- /dev/null
+++ b/src/test/ui/issues/issue-47412.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-47412.rs:21:11
+   |
+LL |     match *ptr {}
+   |           ^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs
index 58a2c271ecf..e0842bfa4cd 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs
@@ -8,6 +8,8 @@
 
 // check-pass
 // only-x86_64
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 
 #![feature(target_feature_11)]
 
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs
index af35bc2014b..a59d7c2d784 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs
@@ -1,6 +1,8 @@
 // Tests #73631: closures inherit `#[target_feature]` annotations
 
 // check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 // only-x86_64
 
 #![feature(target_feature_11)]
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
index 06cfdde3fb9..cf5815df56e 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/fn-ptr.rs:9:21
+  --> $DIR/fn-ptr.rs:11:21
    |
 LL | #[target_feature(enable = "sse2")]
    | ---------------------------------- `#[target_feature]` added here
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs
index 3ecea5c5313..c95d4a08e48 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs
@@ -1,3 +1,5 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 // only-x86_64
 
 #![feature(target_feature_11)]
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
new file mode 100644
index 00000000000..cf5815df56e
--- /dev/null
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/fn-ptr.rs:11:21
+   |
+LL | #[target_feature(enable = "sse2")]
+   | ---------------------------------- `#[target_feature]` added here
+...
+LL |     let foo: fn() = foo;
+   |              ----   ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers
+   |              |
+   |              expected due to this
+   |
+   = note: expected fn pointer `fn()`
+                 found fn item `fn() {foo}`
+   = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
index b9f748640b5..79273a1dcbf 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:21:5
+  --> $DIR/safe-calls.rs:23:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -7,7 +7,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:22:5
+  --> $DIR/safe-calls.rs:24:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -15,7 +15,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:23:5
+  --> $DIR/safe-calls.rs:25:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -23,7 +23,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:28:5
+  --> $DIR/safe-calls.rs:30:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -31,7 +31,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:29:5
+  --> $DIR/safe-calls.rs:31:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -39,7 +39,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:34:5
+  --> $DIR/safe-calls.rs:36:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -47,7 +47,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:35:5
+  --> $DIR/safe-calls.rs:37:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -55,7 +55,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:36:5
+  --> $DIR/safe-calls.rs:38:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -63,7 +63,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:42:5
+  --> $DIR/safe-calls.rs:44:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -71,7 +71,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:45:18
+  --> $DIR/safe-calls.rs:47:18
    |
 LL | const name: () = sse2();
    |                  ^^^^^^ call to function with `#[target_feature]`
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
index 8da3affc447..de0b89f46ba 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
@@ -1,3 +1,5 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 // only-x86_64
 
 #![feature(target_feature_11)]
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
new file mode 100644
index 00000000000..79273a1dcbf
--- /dev/null
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
@@ -0,0 +1,83 @@
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:23:5
+   |
+LL |     sse2();
+   |     ^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:24:5
+   |
+LL |     avx_bmi2();
+   |     ^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:25:5
+   |
+LL |     Quux.avx_bmi2();
+   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:30:5
+   |
+LL |     avx_bmi2();
+   |     ^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:31:5
+   |
+LL |     Quux.avx_bmi2();
+   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:36:5
+   |
+LL |     sse2();
+   |     ^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:37:5
+   |
+LL |     avx_bmi2();
+   |     ^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:38:5
+   |
+LL |     Quux.avx_bmi2();
+   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:44:5
+   |
+LL |     sse2();
+   |     ^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:47:18
+   |
+LL | const name: () = sse2();
+   |                  ^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/safe-extern-statics-mut.stderr b/src/test/ui/safe-extern-statics-mut.mir.stderr
index 38803883414..cec5f9d9c9f 100644
--- a/src/test/ui/safe-extern-statics-mut.stderr
+++ b/src/test/ui/safe-extern-statics-mut.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics-mut.rs:11:13
+  --> $DIR/safe-extern-statics-mut.rs:13:13
    |
 LL |     let b = B;
    |             ^ use of mutable static
@@ -7,7 +7,7 @@ LL |     let b = B;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics-mut.rs:12:14
+  --> $DIR/safe-extern-statics-mut.rs:14:14
    |
 LL |     let rb = &B;
    |              ^^ use of mutable static
@@ -15,7 +15,7 @@ LL |     let rb = &B;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics-mut.rs:13:14
+  --> $DIR/safe-extern-statics-mut.rs:15:14
    |
 LL |     let xb = XB;
    |              ^^ use of mutable static
@@ -23,7 +23,7 @@ LL |     let xb = XB;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics-mut.rs:14:15
+  --> $DIR/safe-extern-statics-mut.rs:16:15
    |
 LL |     let xrb = &XB;
    |               ^^^ use of mutable static
diff --git a/src/test/ui/safe-extern-statics-mut.rs b/src/test/ui/safe-extern-statics-mut.rs
index 324fa443aa5..389a4589a71 100644
--- a/src/test/ui/safe-extern-statics-mut.rs
+++ b/src/test/ui/safe-extern-statics-mut.rs
@@ -1,4 +1,6 @@
 // aux-build:extern-statics.rs
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 
 extern crate extern_statics;
 use extern_statics::*;
diff --git a/src/test/ui/safe-extern-statics-mut.thir.stderr b/src/test/ui/safe-extern-statics-mut.thir.stderr
new file mode 100644
index 00000000000..8e6d2805a0b
--- /dev/null
+++ b/src/test/ui/safe-extern-statics-mut.thir.stderr
@@ -0,0 +1,35 @@
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics-mut.rs:13:13
+   |
+LL |     let b = B;
+   |             ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics-mut.rs:14:15
+   |
+LL |     let rb = &B;
+   |               ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics-mut.rs:15:14
+   |
+LL |     let xb = XB;
+   |              ^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics-mut.rs:16:16
+   |
+LL |     let xrb = &XB;
+   |                ^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/safe-extern-statics.stderr b/src/test/ui/safe-extern-statics.mir.stderr
index b42572ea3ee..102abd0816f 100644
--- a/src/test/ui/safe-extern-statics.stderr
+++ b/src/test/ui/safe-extern-statics.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics.rs:11:13
+  --> $DIR/safe-extern-statics.rs:13:13
    |
 LL |     let a = A;
    |             ^ use of extern static
@@ -7,7 +7,7 @@ LL |     let a = A;
    = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics.rs:12:14
+  --> $DIR/safe-extern-statics.rs:14:14
    |
 LL |     let ra = &A;
    |              ^^ use of extern static
@@ -15,7 +15,7 @@ LL |     let ra = &A;
    = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics.rs:13:14
+  --> $DIR/safe-extern-statics.rs:15:14
    |
 LL |     let xa = XA;
    |              ^^ use of extern static
@@ -23,7 +23,7 @@ LL |     let xa = XA;
    = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics.rs:14:15
+  --> $DIR/safe-extern-statics.rs:16:15
    |
 LL |     let xra = &XA;
    |               ^^^ use of extern static
diff --git a/src/test/ui/safe-extern-statics.rs b/src/test/ui/safe-extern-statics.rs
index 6fa4c4aaca5..0aa90c442ea 100644
--- a/src/test/ui/safe-extern-statics.rs
+++ b/src/test/ui/safe-extern-statics.rs
@@ -1,4 +1,6 @@
 // aux-build:extern-statics.rs
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 
 extern crate extern_statics;
 use extern_statics::*;
diff --git a/src/test/ui/safe-extern-statics.thir.stderr b/src/test/ui/safe-extern-statics.thir.stderr
new file mode 100644
index 00000000000..7fd2182c4c6
--- /dev/null
+++ b/src/test/ui/safe-extern-statics.thir.stderr
@@ -0,0 +1,35 @@
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics.rs:13:13
+   |
+LL |     let a = A;
+   |             ^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics.rs:14:15
+   |
+LL |     let ra = &A;
+   |               ^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics.rs:15:14
+   |
+LL |     let xa = XA;
+   |              ^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics.rs:16:16
+   |
+LL |     let xra = &XA;
+   |                ^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr b/src/test/ui/static/static-mut-foreign-requires-unsafe.mir.stderr
index e7ed0b710b2..a4659bc8712 100644
--- a/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr
+++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-foreign-requires-unsafe.rs:6:5
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:9:5
    |
 LL |     a += 3;
    |     ^^^^^^ use of mutable static
@@ -7,7 +7,7 @@ LL |     a += 3;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-foreign-requires-unsafe.rs:7:5
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:10:5
    |
 LL |     a = 4;
    |     ^^^^^ use of mutable static
@@ -15,7 +15,7 @@ LL |     a = 4;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-foreign-requires-unsafe.rs:8:14
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:11:14
    |
 LL |     let _b = a;
    |              ^ use of mutable static
diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.rs b/src/test/ui/static/static-mut-foreign-requires-unsafe.rs
index 90aa2537a82..4f96acb3375 100644
--- a/src/test/ui/static/static-mut-foreign-requires-unsafe.rs
+++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 extern "C" {
     static mut a: i32;
 }
diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr b/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr
new file mode 100644
index 00000000000..2c62d4d8f3b
--- /dev/null
+++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr
@@ -0,0 +1,27 @@
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:9:5
+   |
+LL |     a += 3;
+   |     ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:10:5
+   |
+LL |     a = 4;
+   |     ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:11:14
+   |
+LL |     let _b = a;
+   |              ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/static/static-mut-requires-unsafe.stderr b/src/test/ui/static/static-mut-requires-unsafe.mir.stderr
index 85e468b333c..0d4ce056fc2 100644
--- a/src/test/ui/static/static-mut-requires-unsafe.stderr
+++ b/src/test/ui/static/static-mut-requires-unsafe.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-requires-unsafe.rs:4:5
+  --> $DIR/static-mut-requires-unsafe.rs:7:5
    |
 LL |     a += 3;
    |     ^^^^^^ use of mutable static
@@ -7,7 +7,7 @@ LL |     a += 3;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-requires-unsafe.rs:5:5
+  --> $DIR/static-mut-requires-unsafe.rs:8:5
    |
 LL |     a = 4;
    |     ^^^^^ use of mutable static
@@ -15,7 +15,7 @@ LL |     a = 4;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-requires-unsafe.rs:6:14
+  --> $DIR/static-mut-requires-unsafe.rs:9:14
    |
 LL |     let _b = a;
    |              ^ use of mutable static
diff --git a/src/test/ui/static/static-mut-requires-unsafe.rs b/src/test/ui/static/static-mut-requires-unsafe.rs
index 413b97e431d..ea3ba095007 100644
--- a/src/test/ui/static/static-mut-requires-unsafe.rs
+++ b/src/test/ui/static/static-mut-requires-unsafe.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 static mut a: isize = 3;
 
 fn main() {
diff --git a/src/test/ui/static/static-mut-requires-unsafe.thir.stderr b/src/test/ui/static/static-mut-requires-unsafe.thir.stderr
new file mode 100644
index 00000000000..1a1cf14271a
--- /dev/null
+++ b/src/test/ui/static/static-mut-requires-unsafe.thir.stderr
@@ -0,0 +1,27 @@
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-requires-unsafe.rs:7:5
+   |
+LL |     a += 3;
+   |     ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-requires-unsafe.rs:8:5
+   |
+LL |     a = 4;
+   |     ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-requires-unsafe.rs:9:14
+   |
+LL |     let _b = a;
+   |              ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs
index 924bfd82eb8..66e1e77c905 100644
--- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs
+++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs
@@ -17,7 +17,6 @@ fn main() {
     let fp = BufWriter::new(fp);
     //~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
     //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
-    //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
 
     writeln!(fp, "hello world").unwrap(); //~ ERROR the method
 }
diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
index a9b06214fe8..71b09d43612 100644
--- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
+++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
@@ -11,19 +11,6 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis
   --> $DIR/mut-borrow-needed-by-trait.rs:17:14
    |
 LL |     let fp = BufWriter::new(fp);
-   |              ^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
-   | 
-  ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
-   |
-LL | pub struct BufWriter<W: Write> {
-   |                         ----- required by this bound in `BufWriter`
-   |
-   = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write`
-
-error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
-  --> $DIR/mut-borrow-needed-by-trait.rs:17:14
-   |
-LL |     let fp = BufWriter::new(fp);
    |              ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
    | 
   ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
@@ -34,7 +21,7 @@ LL | pub struct BufWriter<W: Write> {
    = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write`
 
 error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn std::io::Write>`, but its trait bounds were not satisfied
-  --> $DIR/mut-borrow-needed-by-trait.rs:22:5
+  --> $DIR/mut-borrow-needed-by-trait.rs:21:5
    |
 LL |     writeln!(fp, "hello world").unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn std::io::Write>` due to unsatisfied trait bounds
@@ -49,7 +36,7 @@ LL | pub struct BufWriter<W: Write> {
            which is required by `BufWriter<&dyn std::io::Write>: std::io::Write`
    = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0277, E0599.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/traits/safety-fn-body.stderr b/src/test/ui/traits/safety-fn-body.mir.stderr
index 0aeb186828e..ea7b2048e83 100644
--- a/src/test/ui/traits/safety-fn-body.stderr
+++ b/src/test/ui/traits/safety-fn-body.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/safety-fn-body.rs:11:9
+  --> $DIR/safety-fn-body.rs:14:9
    |
 LL |         *self += 1;
    |         ^^^^^^^^^^ dereference of raw pointer
diff --git a/src/test/ui/traits/safety-fn-body.rs b/src/test/ui/traits/safety-fn-body.rs
index df527747305..2cc4fe1b344 100644
--- a/src/test/ui/traits/safety-fn-body.rs
+++ b/src/test/ui/traits/safety-fn-body.rs
@@ -1,6 +1,9 @@
 // Check that an unsafe impl does not imply that unsafe actions are
 // legal in the methods.
 
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 unsafe trait UnsafeTrait : Sized {
     fn foo(self) { }
 }
diff --git a/src/test/ui/traits/safety-fn-body.thir.stderr b/src/test/ui/traits/safety-fn-body.thir.stderr
new file mode 100644
index 00000000000..94a1a2a03cd
--- /dev/null
+++ b/src/test/ui/traits/safety-fn-body.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/safety-fn-body.rs:14:9
+   |
+LL |         *self += 1;
+   |         ^^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr
index 88322c3a0a6..33f762ccf63 100644
--- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr
+++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/issue-45087-unreachable-unsafe.rs:3:5
+  --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
    |
 LL |     *(1 as *mut u32) = 42;
    |     ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs
index 5edf7a47e2f..071cea8fbd7 100644
--- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs
+++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 fn main() {
     return;
     *(1 as *mut u32) = 42;
diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr
new file mode 100644
index 00000000000..b89401ce837
--- /dev/null
+++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
+   |
+LL |     *(1 as *mut u32) = 42;
+   |     ^^^^^^^^^^^^^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/ranged_ints.stderr b/src/test/ui/unsafe/ranged_ints.mir.stderr
index 4e43df495c0..f9ef7834e1e 100644
--- a/src/test/ui/unsafe/ranged_ints.stderr
+++ b/src/test/ui/unsafe/ranged_ints.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
-  --> $DIR/ranged_ints.rs:7:14
+  --> $DIR/ranged_ints.rs:10:14
    |
 LL |     let _x = NonZero(0);
    |              ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr
diff --git a/src/test/ui/unsafe/ranged_ints.rs b/src/test/ui/unsafe/ranged_ints.rs
index 0fa2da917e9..05efe87ba6e 100644
--- a/src/test/ui/unsafe/ranged_ints.rs
+++ b/src/test/ui/unsafe/ranged_ints.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![feature(rustc_attrs)]
 
 #[rustc_layout_scalar_valid_range_start(1)]
diff --git a/src/test/ui/unsafe/ranged_ints.thir.stderr b/src/test/ui/unsafe/ranged_ints.thir.stderr
new file mode 100644
index 00000000000..f9ef7834e1e
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints.rs:10:14
+   |
+LL |     let _x = NonZero(0);
+   |              ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr
+   |
+   = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/ranged_ints_const.stderr b/src/test/ui/unsafe/ranged_ints_const.mir.stderr
index 584ad40a92b..33d134c7ce5 100644
--- a/src/test/ui/unsafe/ranged_ints_const.stderr
+++ b/src/test/ui/unsafe/ranged_ints_const.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
-  --> $DIR/ranged_ints_const.rs:8:34
+  --> $DIR/ranged_ints_const.rs:11:34
    |
 LL | const fn foo() -> NonZero<u32> { NonZero(0) }
    |                                  ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr
diff --git a/src/test/ui/unsafe/ranged_ints_const.rs b/src/test/ui/unsafe/ranged_ints_const.rs
index 8477772867e..472b0968150 100644
--- a/src/test/ui/unsafe/ranged_ints_const.rs
+++ b/src/test/ui/unsafe/ranged_ints_const.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![feature(rustc_attrs)]
 
 #[rustc_layout_scalar_valid_range_start(1)]
diff --git a/src/test/ui/unsafe/ranged_ints_const.thir.stderr b/src/test/ui/unsafe/ranged_ints_const.thir.stderr
new file mode 100644
index 00000000000..33d134c7ce5
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints_const.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints_const.rs:11:34
+   |
+LL | const fn foo() -> NonZero<u32> { NonZero(0) }
+   |                                  ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr
+   |
+   = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/ranged_ints_macro.rs b/src/test/ui/unsafe/ranged_ints_macro.rs
index 9192ecfe196..8293d029951 100644
--- a/src/test/ui/unsafe/ranged_ints_macro.rs
+++ b/src/test/ui/unsafe/ranged_ints_macro.rs
@@ -1,4 +1,7 @@
 // build-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![feature(rustc_attrs)]
 
 macro_rules! apply {
diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.mir.stderr
index b2a30f81e05..fee645e4118 100644
--- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr
+++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/unsafe-fn-assign-deref-ptr.rs:2:5
+  --> $DIR/unsafe-fn-assign-deref-ptr.rs:5:5
    |
 LL |     *p = 0;
    |     ^^^^^^ dereference of raw pointer
diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs
index 91264e790c8..a94e94375ae 100644
--- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs
+++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 fn f(p: *mut u8) {
     *p = 0; //~ ERROR dereference of raw pointer is unsafe
     return;
diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr
new file mode 100644
index 00000000000..498d26d30ff
--- /dev/null
+++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/unsafe-fn-assign-deref-ptr.rs:5:5
+   |
+LL |     *p = 0;
+   |     ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-deref-ptr.mir.stderr
index 98cb7b876f8..a2614992445 100644
--- a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr
+++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/unsafe-fn-deref-ptr.rs:2:12
+  --> $DIR/unsafe-fn-deref-ptr.rs:5:12
    |
 LL |     return *p;
    |            ^^ dereference of raw pointer
diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs b/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs
index 46445aa261d..dc989535bd6 100644
--- a/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs
+++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 fn f(p: *const u8) -> u8 {
     return *p; //~ ERROR dereference of raw pointer is unsafe
 }
diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr b/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr
new file mode 100644
index 00000000000..6897e4e691a
--- /dev/null
+++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/unsafe-fn-deref-ptr.rs:5:12
+   |
+LL |     return *p;
+   |            ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.mir.stderr
index 410d8d3fb40..99808495ea6 100644
--- a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
+++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/unsafe-unstable-const-fn.rs:8:5
+  --> $DIR/unsafe-unstable-const-fn.rs:11:5
    |
 LL |     *a == b
    |     ^^ dereference of raw pointer
diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
index c7120e05007..0476759ca6d 100644
--- a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
+++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![stable(feature = "foo", since = "1.33.0")]
 #![feature(staged_api)]
 #![feature(const_raw_ptr_deref)]
diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr
new file mode 100644
index 00000000000..49d6a96860b
--- /dev/null
+++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/unsafe-unstable-const-fn.rs:11:5
+   |
+LL |     *a == b
+   |     ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/wf/wf-static-method.nll.stderr b/src/test/ui/wf/wf-static-method.nll.stderr
index d031a68a51d..9c066a7bdb0 100644
--- a/src/test/ui/wf/wf-static-method.nll.stderr
+++ b/src/test/ui/wf/wf-static-method.nll.stderr
@@ -68,7 +68,7 @@ LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
    |                  --  -- lifetime `'b` defined here
    |                  |
    |                  lifetime `'a` defined here
-LL |     <Evil>::inherent_evil(b) // bug? shouldn't this be an error
+LL |     <Evil>::inherent_evil(b)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
diff --git a/src/test/ui/wf/wf-static-method.rs b/src/test/ui/wf/wf-static-method.rs
index e5a1092175d..6e805d61265 100644
--- a/src/test/ui/wf/wf-static-method.rs
+++ b/src/test/ui/wf/wf-static-method.rs
@@ -47,7 +47,8 @@ fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
 }
 
 fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
-    <Evil>::inherent_evil(b) // bug? shouldn't this be an error
+    <Evil>::inherent_evil(b)
+    //~^ ERROR cannot infer an appropriate lifetime
 }
 
 
diff --git a/src/test/ui/wf/wf-static-method.stderr b/src/test/ui/wf/wf-static-method.stderr
index 0c98a809025..c02a8fe4aaf 100644
--- a/src/test/ui/wf/wf-static-method.stderr
+++ b/src/test/ui/wf/wf-static-method.stderr
@@ -103,7 +103,34 @@ note: ...so that reference does not outlive borrowed content
 LL |     <IndirectEvil>::static_evil(b)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements
+  --> $DIR/wf-static-method.rs:50:5
+   |
+LL |     <Evil>::inherent_evil(b)
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 49:22...
+  --> $DIR/wf-static-method.rs:49:22
+   |
+LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+   |                      ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/wf-static-method.rs:50:27
+   |
+LL |     <Evil>::inherent_evil(b)
+   |                           ^
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 49:18...
+  --> $DIR/wf-static-method.rs:49:18
+   |
+LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+   |                  ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/wf-static-method.rs:50:5
+   |
+LL |     <Evil>::inherent_evil(b)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0312, E0478, E0495.
 For more information about an error, try `rustc --explain E0312`.
diff --git a/src/tools/clippy/.cargo/config b/src/tools/clippy/.cargo/config
index 9b5add4df1c..e95ea224cb6 100644
--- a/src/tools/clippy/.cargo/config
+++ b/src/tools/clippy/.cargo/config
@@ -2,6 +2,7 @@
 uitest = "test --test compile-test"
 dev = "run --target-dir clippy_dev/target --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
 lintcheck = "run --target-dir lintcheck/target --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml  -- "
+collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored"
 
 [build]
 rustflags = ["-Zunstable-options"]
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index ae6f1aa1b30..f27fee87dc1 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -90,6 +90,11 @@ jobs:
     - name: Checkout
       uses: actions/checkout@v2.3.3
 
+    # FIXME: should not be necessary once 1.24.2 is the default version on the windows runner
+    - name: Update rustup
+      run: rustup self update
+      if: runner.os == 'Windows'
+
     - name: Install toolchain
       run: rustup show active-toolchain
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 204d56e2a98..da5a0712c95 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,195 @@ document.
 
 ## Unreleased / In Rust Nightly
 
-[6ed6f1e...master](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...master)
+[7c7683c...master](https://github.com/rust-lang/rust-clippy/compare/7c7683c...master)
+
+## Rust 1.53
+
+Current beta, release 2021-06-17
+
+[6ed6f1e...7c7683c](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...7c7683c)
+
+### New Lints
+
+* [`option_filter_map`]
+  [#6342](https://github.com/rust-lang/rust-clippy/pull/6342)
+* [`branches_sharing_code`]
+  [#6463](https://github.com/rust-lang/rust-clippy/pull/6463)
+* [`needless_for_each`]
+  [#6706](https://github.com/rust-lang/rust-clippy/pull/6706)
+* [`if_then_some_else_none`]
+  [#6859](https://github.com/rust-lang/rust-clippy/pull/6859)
+* [`non_octal_unix_permissions`]
+  [#7001](https://github.com/rust-lang/rust-clippy/pull/7001)
+* [`unnecessary_self_imports`]
+  [#7072](https://github.com/rust-lang/rust-clippy/pull/7072)
+* [`bool_assert_comparison`]
+  [#7083](https://github.com/rust-lang/rust-clippy/pull/7083)
+* [`cloned_instead_of_copied`]
+  [#7098](https://github.com/rust-lang/rust-clippy/pull/7098)
+* [`flat_map_option`]
+  [#7101](https://github.com/rust-lang/rust-clippy/pull/7101)
+
+### Moves and Deprecations
+
+* Deprecate [`filter_map`] lint
+  [#7059](https://github.com/rust-lang/rust-clippy/pull/7059)
+* Move [`transmute_ptr_to_ptr`] to `pedantic`
+  [#7102](https://github.com/rust-lang/rust-clippy/pull/7102)
+
+### Enhancements
+
+* [`mem_replace_with_default`]: Also lint on common std constructors
+  [#6820](https://github.com/rust-lang/rust-clippy/pull/6820)
+* [`wrong_self_convention`]: Also lint on `to_*_mut` methods
+  [#6828](https://github.com/rust-lang/rust-clippy/pull/6828)
+* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]:
+  [#6863](https://github.com/rust-lang/rust-clippy/pull/6863)
+    * Attempt to find a common path prefix in suggestion
+    * Don't lint on `Option` and `Result`
+    * Consider `Self` prefix
+* [`explicit_deref_methods`]: Also lint on chained `deref` calls
+  [#6865](https://github.com/rust-lang/rust-clippy/pull/6865)
+* [`or_fun_call`]: Also lint on `unsafe` blocks
+  [#6928](https://github.com/rust-lang/rust-clippy/pull/6928)
+* [`vec_box`], [`linkedlist`], [`option_option`]: Also lint in `const` and
+  `static` items [#6938](https://github.com/rust-lang/rust-clippy/pull/6938)
+* [`search_is_some`]: Also check for `is_none`
+  [#6942](https://github.com/rust-lang/rust-clippy/pull/6942)
+* [`string_lit_as_bytes`]: Also lint on `into_bytes`
+  [#6959](https://github.com/rust-lang/rust-clippy/pull/6959)
+* [`len_without_is_empty`]: Also lint if function signatures of `len` and
+  `is_empty` don't match
+  [#6980](https://github.com/rust-lang/rust-clippy/pull/6980)
+* [`redundant_pattern_matching`]: Also lint if the pattern is a `&` pattern
+  [#6991](https://github.com/rust-lang/rust-clippy/pull/6991)
+* [`clone_on_copy`]: Also lint on chained method calls taking `self` by value
+  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
+* [`missing_panics_doc`]: Also lint on `assert_eq!` and `assert_ne!`
+  [#7029](https://github.com/rust-lang/rust-clippy/pull/7029)
+* [`needless_return`]: Also lint in `async` functions
+  [#7067](https://github.com/rust-lang/rust-clippy/pull/7067)
+* [`unused_io_amount`]: Also lint on expressions like `_.read().ok()?`
+  [#7100](https://github.com/rust-lang/rust-clippy/pull/7100)
+* [`iter_cloned_collect`]: Also lint on large arrays, since const-generics are
+  now stable [#7138](https://github.com/rust-lang/rust-clippy/pull/7138)
+
+### False Positive Fixes
+
+* [`upper_case_acronyms`]: No longer lints on public items
+  [#6805](https://github.com/rust-lang/rust-clippy/pull/6805)
+* [`suspicious_map`]: No longer lints when side effects may occur inside the
+  `map` call [#6831](https://github.com/rust-lang/rust-clippy/pull/6831)
+* [`manual_map`], [`manual_unwrap_or`]: No longer lints in `const` functions
+  [#6917](https://github.com/rust-lang/rust-clippy/pull/6917)
+* [`wrong_self_convention`]: Now respects `Copy` types
+  [#6924](https://github.com/rust-lang/rust-clippy/pull/6924)
+* [`needless_question_mark`]: No longer lints if the `?` and the `Some(..)` come
+  from different macro contexts [#6935](https://github.com/rust-lang/rust-clippy/pull/6935)
+* [`map_entry`]: Better detect if the entry API can be used
+  [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
+* [`or_fun_call`]: No longer lints on some `len` function calls
+  [#6950](https://github.com/rust-lang/rust-clippy/pull/6950)
+* [`new_ret_no_self`]: No longer lints when `Self` is returned with different
+  generic arguments [#6952](https://github.com/rust-lang/rust-clippy/pull/6952)
+* [`upper_case_acronyms`]: No longer lints on public items
+  [#6981](https://github.com/rust-lang/rust-clippy/pull/6981)
+* [`explicit_into_iter_loop`]: Only lint when `into_iter` is an implementation
+  of `IntoIterator` [#6982](https://github.com/rust-lang/rust-clippy/pull/6982)
+* [`expl_impl_clone_on_copy`]: Take generic constraints into account before
+  suggesting to use `derive` instead
+  [#6993](https://github.com/rust-lang/rust-clippy/pull/6993)
+* [`missing_panics_doc`]: No longer lints when only debug-assertions are used
+  [#6996](https://github.com/rust-lang/rust-clippy/pull/6996)
+* [`clone_on_copy`]: Only lint when using the `Clone` trait
+  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
+* [`wrong_self_convention`]: No longer lints inside a trait implementation
+  [#7002](https://github.com/rust-lang/rust-clippy/pull/7002)
+* [`redundant_clone`]: No longer lints when the cloned value is modified while
+  the clone is in use
+  [#7011](https://github.com/rust-lang/rust-clippy/pull/7011)
+* [`same_item_push`]: No longer lints if the `Vec` is used in the loop body
+  [#7018](https://github.com/rust-lang/rust-clippy/pull/7018)
+* [`cargo_common_metadata`]: Remove author requirement
+  [#7026](https://github.com/rust-lang/rust-clippy/pull/7026)
+* [`panic_in_result_fn`]: No longer lints on `debug_assert` family
+  [#7060](https://github.com/rust-lang/rust-clippy/pull/7060)
+* [`panic`]: No longer wrongfully lints on `debug_assert` with message
+  [#7063](https://github.com/rust-lang/rust-clippy/pull/7063)
+* [`wrong_self_convention`]: No longer lints in trait implementations where no
+  `self` is involved [#7064](https://github.com/rust-lang/rust-clippy/pull/7064)
+* [`missing_const_for_fn`]: No longer lints when unstable `const` function is
+  involved [#7076](https://github.com/rust-lang/rust-clippy/pull/7076)
+* [`suspicious_else_formatting`]: Allow Allman style braces
+  [#7087](https://github.com/rust-lang/rust-clippy/pull/7087)
+* [`inconsistent_struct_constructor`]: No longer lints in macros
+  [#7097](https://github.com/rust-lang/rust-clippy/pull/7097)
+* [`single_component_path_imports`]: No longer lints on macro re-exports
+  [#7120](https://github.com/rust-lang/rust-clippy/pull/7120)
+
+### Suggestion Fixes/Improvements
+
+* [`redundant_pattern_matching`]: Add a note when applying this lint would
+  change the drop order
+  [#6568](https://github.com/rust-lang/rust-clippy/pull/6568)
+* [`write_literal`], [`print_literal`]: Add auto-applicable suggestion
+  [#6821](https://github.com/rust-lang/rust-clippy/pull/6821)
+* [`manual_map`]: Fix suggestion for complex `if let ... else` chains
+  [#6856](https://github.com/rust-lang/rust-clippy/pull/6856)
+* [`inconsistent_struct_constructor`]: Make lint description and message clearer
+  [#6892](https://github.com/rust-lang/rust-clippy/pull/6892)
+* [`map_entry`]: Now suggests `or_insert`, `insert_with` or `match _.entry(_)`
+  as appropriate [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
+* [`manual_flatten`]: Suggest to insert `copied` if necessary
+  [#6962](https://github.com/rust-lang/rust-clippy/pull/6962)
+* [`redundant_slicing`]: Fix suggestion when a re-borrow might be required or
+  when the value is from a macro call
+  [#6975](https://github.com/rust-lang/rust-clippy/pull/6975)
+* [`match_wildcard_for_single_variants`]: Fix suggestion for hidden variant
+  [#6988](https://github.com/rust-lang/rust-clippy/pull/6988)
+* [`clone_on_copy`]: Correct suggestion when the cloned value is a macro call
+  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
+* [`manual_map`]: Fix suggestion at the end of an if chain
+  [#7004](https://github.com/rust-lang/rust-clippy/pull/7004)
+* Fix needless parenthesis output in multiple lint suggestions
+  [#7013](https://github.com/rust-lang/rust-clippy/pull/7013)
+* [`needless_collect`]: Better explanation in the lint message
+  [#7020](https://github.com/rust-lang/rust-clippy/pull/7020)
+* [`useless_vec`]: Now considers mutability
+  [#7036](https://github.com/rust-lang/rust-clippy/pull/7036)
+* [`useless_format`]: Wrap the content in braces if necessary
+  [#7092](https://github.com/rust-lang/rust-clippy/pull/7092)
+* [`single_match`]: Don't suggest an equality check for types which don't
+  implement `PartialEq`
+  [#7093](https://github.com/rust-lang/rust-clippy/pull/7093)
+* [`from_over_into`]: Mention type in help message
+  [#7099](https://github.com/rust-lang/rust-clippy/pull/7099)
+* [`manual_unwrap_or`]: Fix invalid code suggestion due to a macro call
+  [#7136](https://github.com/rust-lang/rust-clippy/pull/7136)
+
+### ICE Fixes
+
+* [`macro_use_imports`]
+  [#7022](https://github.com/rust-lang/rust-clippy/pull/7022)
+* [`missing_panics_doc`]
+  [#7034](https://github.com/rust-lang/rust-clippy/pull/7034)
+* [`tabs_in_doc_comments`]
+  [#7039](https://github.com/rust-lang/rust-clippy/pull/7039)
+* [`missing_const_for_fn`]
+  [#7128](https://github.com/rust-lang/rust-clippy/pull/7128)
+
+### Others
+
+* [Clippy's lint
+  list](https://rust-lang.github.io/rust-clippy/master/index.html) now supports
+  themes [#7030](https://github.com/rust-lang/rust-clippy/pull/7030)
+* Lints that were uplifted to `rustc` now mention the new `rustc` name in the
+  deprecation warning
+  [#7056](https://github.com/rust-lang/rust-clippy/pull/7056)
 
 ## Rust 1.52
 
-Current beta, release 2021-05-06
+Current stable, released 2021-05-06
 
 [3e41797...6ed6f1e](https://github.com/rust-lang/rust-clippy/compare/3e41797...6ed6f1e)
 
@@ -99,7 +283,7 @@ Current beta, release 2021-05-06
   [#6682](https://github.com/rust-lang/rust-clippy/pull/6682)
 * [`unit_arg`]: No longer lints on unit arguments when they come from a path expression.
   [#6601](https://github.com/rust-lang/rust-clippy/pull/6601)
-* [`cargo_common_metadata`]: No longer lints if 
+* [`cargo_common_metadata`]: No longer lints if
   [`publish = false`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field)
   is defined in the manifest
   [#6650](https://github.com/rust-lang/rust-clippy/pull/6650)
@@ -124,11 +308,11 @@ Current beta, release 2021-05-06
 
 * [`useless_format`]: Improved the documentation example
   [#6854](https://github.com/rust-lang/rust-clippy/pull/6854)
-* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper 
+* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper
   [#6782](https://github.com/rust-lang/rust-clippy/pull/6782)
 
 ### Others
-* Running `cargo clippy` after `cargo check` now works as expected 
+* Running `cargo clippy` after `cargo check` now works as expected
   (`cargo clippy` and `cargo check` no longer shares the same build cache)
   [#6687](https://github.com/rust-lang/rust-clippy/pull/6687)
 * Cargo now re-runs Clippy if arguments after `--` provided to `cargo clippy` are changed.
@@ -145,7 +329,7 @@ Current beta, release 2021-05-06
 
 ## Rust 1.51
 
-Current stable, released 2021-03-25
+Released 2021-03-25
 
 [4911ab1...3e41797](https://github.com/rust-lang/rust-clippy/compare/4911ab1...3e41797)
 
@@ -2365,6 +2549,7 @@ Released 2018-09-13
 [`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer
 [`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount
 [`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
+[`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool
 [`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
 [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
 [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
@@ -2538,6 +2723,7 @@ Released 2018-09-13
 [`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute
 [`unstable_as_mut_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_mut_slice
 [`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice
+[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async
 [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
 [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index f010e609604..848476a9d05 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -49,7 +49,7 @@ rustc-workspace-hack = "1.0.0"
 rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" }
 
 [features]
-deny-warnings = []
+deny-warnings = ["clippy_lints/deny-warnings"]
 integration = ["tempfile"]
 internal-lints = ["clippy_lints/internal-lints"]
 metadata-collector-lint = ["internal-lints", "clippy_lints/metadata-collector-lint"]
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 1e5a140e964..69f42aca8b6 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,5 +1,7 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![feature(once_cell)]
+#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
 
 use itertools::Itertools;
 use regex::Regex;
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index f4da783502c..7040c257c83 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -1,4 +1,6 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
 
 use clap::{App, Arg, ArgMatches, SubCommand};
 use clippy_dev::{bless, fmt, ide_setup, new_lint, serve, stderr_length_check, update_lints};
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 7ceb1da6a6e..48f2972ec58 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -30,7 +30,7 @@ rustc-semver = "1.1.0"
 url = { version = "2.1.0", features = ["serde"] }
 
 [features]
-deny-warnings = []
+deny-warnings = ["clippy_utils/deny-warnings"]
 # build clippy with internal lints enabled, off by default
 internal-lints = ["clippy_utils/internal-lints"]
 metadata-collector-lint = ["serde_json", "clippy_utils/metadata-collector-lint"]
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 4688b3d5105..50ffc2e3f19 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -1,6 +1,13 @@
+/// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This
+/// enables the simple extraction of the metadata without changing the current deprecation
+/// declaration.
+pub struct ClippyDeprecatedLint;
+
 macro_rules! declare_deprecated_lint {
-    (pub $name: ident, $_reason: expr) => {
-        declare_lint!(pub $name, Allow, "deprecated lint")
+    { $(#[$attr:meta])* pub $name: ident, $_reason: expr} => {
+        $(#[$attr])*
+        #[allow(dead_code)]
+        pub static $name: ClippyDeprecatedLint = ClippyDeprecatedLint {};
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index e742cd626ab..840c1eba79d 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{source_map::Span};
+use rustc_span::source_map::Span;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for deriving `Hash` but implementing `PartialEq`
@@ -310,15 +310,11 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &T
     // there's a Copy impl for any instance of the adt.
     if !is_copy(cx, ty) {
         if ty_subs.non_erasable_generics().next().is_some() {
-            let has_copy_impl = cx
-                .tcx
-                .all_local_trait_impls(())
-                .get(&copy_id)
-                .map_or(false, |impls| {
-                    impls
-                        .iter()
-                        .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did))
-                });
+            let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(&copy_id).map_or(false, |impls| {
+                impls
+                    .iter()
+                    .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did))
+            });
             if !has_copy_impl {
                 return;
             }
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index fb53b55ebd6..e67ec4e06c5 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -383,7 +383,7 @@ pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span:
     let mut no_stars = String::with_capacity(doc.len());
     for line in doc.lines() {
         let mut chars = line.chars();
-        while let Some(c) = chars.next() {
+        for c in &mut chars {
             if c.is_whitespace() {
                 no_stars.push(c);
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index e0b687b0205..08f28cd54c5 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -323,7 +323,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                         cx,
                         SUBOPTIMAL_FLOPS,
                         parent.span,
-                        "square can be computed more efficiently",
+                        "multiply and add expressions can be calculated more efficiently and accurately",
                         "consider using",
                         format!(
                             "{}.mul_add({}, {})",
@@ -337,16 +337,6 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                     return;
                 }
             }
-
-            span_lint_and_sugg(
-                cx,
-                SUBOPTIMAL_FLOPS,
-                expr.span,
-                "square can be computed more efficiently",
-                "consider using",
-                format!("{} * {}", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], "..")),
-                Applicability::MachineApplicable,
-            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index 30174fa2100..260a8f50157 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -147,7 +147,11 @@ fn lint_implicit_returns(
             visit_break_exprs(block, |break_expr, dest, sub_expr| {
                 if dest.target_id.ok() == Some(expr.hir_id) {
                     if call_site_span.is_none() && break_expr.span.ctxt() == ctxt {
-                        lint_break(cx, break_expr.span, sub_expr.unwrap().span);
+                        // At this point sub_expr can be `None` in async functions which either diverge, or return the
+                        // unit type.
+                        if let Some(sub_expr) = sub_expr {
+                            lint_break(cx, break_expr.span, sub_expr.span);
+                        }
                     } else {
                         // the break expression is from a macro call, add a return to the loop
                         add_return = true;
diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
index d138c3a8acf..3b635071f28 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -58,7 +58,7 @@ declare_clippy_lint! {
     /// Foo { x, y };
     /// ```
     pub INCONSISTENT_STRUCT_CONSTRUCTOR,
-    style,
+    pedantic,
     "the order of the field init shorthand is inconsistent with the order in the struct definition"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index 4e0b1ae78df..ee41c4aea2f 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -1,12 +1,13 @@
 //! lint on inherent implementations
 
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::in_macro;
-use rustc_hir::def_id::DefIdMap;
-use rustc_hir::{Crate, Impl, Item, ItemKind};
+use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::{in_macro, is_allowed};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{def_id::LocalDefId, Crate, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
+use std::collections::hash_map::Entry;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for multiple inherent implementations of a struct
@@ -40,51 +41,96 @@ declare_clippy_lint! {
     "Multiple inherent impl that could be grouped"
 }
 
-#[allow(clippy::module_name_repetitions)]
-#[derive(Default)]
-pub struct MultipleInherentImpl {
-    impls: DefIdMap<Span>,
-}
-
-impl_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
+declare_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
 
 impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
-    fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Impl(Impl {
-            ref generics,
-            of_trait: None,
-            ..
-        }) = item.kind
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Crate<'_>) {
+        // Map from a type to it's first impl block. Needed to distinguish generic arguments.
+        // e.g. `Foo<Bar>` and `Foo<Baz>`
+        let mut type_map = FxHashMap::default();
+        // List of spans to lint. (lint_span, first_span)
+        let mut lint_spans = Vec::new();
+
+        for (_, impl_ids) in cx
+            .tcx
+            .crate_inherent_impls(())
+            .inherent_impls
+            .iter()
+            .filter(|(&id, impls)| {
+                impls.len() > 1
+                    // Check for `#[allow]` on the type definition
+                    && !is_allowed(
+                        cx,
+                        MULTIPLE_INHERENT_IMPL,
+                        cx.tcx.hir().local_def_id_to_hir_id(id),
+                    )
+            })
         {
-            // Remember for each inherent implementation encountered its span and generics
-            // but filter out implementations that have generic params (type or lifetime)
-            // or are derived from a macro
-            if !in_macro(item.span) && generics.params.is_empty() {
-                self.impls.insert(item.def_id.to_def_id(), item.span);
+            for impl_id in impl_ids.iter().map(|id| id.expect_local()) {
+                match type_map.entry(cx.tcx.type_of(impl_id)) {
+                    Entry::Vacant(e) => {
+                        // Store the id for the first impl block of this type. The span is retrieved lazily.
+                        e.insert(IdOrSpan::Id(impl_id));
+                    },
+                    Entry::Occupied(mut e) => {
+                        if let Some(span) = get_impl_span(cx, impl_id) {
+                            let first_span = match *e.get() {
+                                IdOrSpan::Span(s) => s,
+                                IdOrSpan::Id(id) => {
+                                    if let Some(s) = get_impl_span(cx, id) {
+                                        // Remember the span of the first block.
+                                        *e.get_mut() = IdOrSpan::Span(s);
+                                        s
+                                    } else {
+                                        // The first impl block isn't considered by the lint. Replace it with the
+                                        // current one.
+                                        *e.get_mut() = IdOrSpan::Span(span);
+                                        continue;
+                                    }
+                                },
+                            };
+                            lint_spans.push((span, first_span));
+                        }
+                    },
+                }
             }
+
+            // Switching to the next type definition, no need to keep the current entries around.
+            type_map.clear();
         }
-    }
 
-    fn check_crate_post(&mut self, cx: &LateContext<'tcx>, krate: &'tcx Crate<'_>) {
-        if !krate.items.is_empty() {
-            // Retrieve all inherent implementations from the crate, grouped by type
-            for impls in cx.tcx.crate_inherent_impls(()).inherent_impls.values() {
-                // Filter out implementations that have generic params (type or lifetime)
-                let mut impl_spans = impls.iter().filter_map(|impl_def| self.impls.get(impl_def));
-                if let Some(initial_span) = impl_spans.next() {
-                    impl_spans.for_each(|additional_span| {
-                        span_lint_and_then(
-                            cx,
-                            MULTIPLE_INHERENT_IMPL,
-                            *additional_span,
-                            "multiple implementations of this structure",
-                            |diag| {
-                                diag.span_note(*initial_span, "first implementation here");
-                            },
-                        )
-                    })
-                }
-            }
+        // `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first.
+        lint_spans.sort_by_key(|x| x.0.lo());
+        for (span, first_span) in lint_spans {
+            span_lint_and_note(
+                cx,
+                MULTIPLE_INHERENT_IMPL,
+                span,
+                "multiple implementations of this structure",
+                Some(first_span),
+                "first implementation here",
+            );
         }
     }
 }
+
+/// Gets the span for the given impl block unless it's not being considered by the lint.
+fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
+    let id = cx.tcx.hir().local_def_id_to_hir_id(id);
+    if let Node::Item(&Item {
+        kind: ItemKind::Impl(ref impl_item),
+        span,
+        ..
+    }) = cx.tcx.hir().get(id)
+    {
+        (!in_macro(span) && impl_item.generics.params.is_empty() && !is_allowed(cx, MULTIPLE_INHERENT_IMPL, id))
+            .then(|| span)
+    } else {
+        None
+    }
+}
+
+enum IdOrSpan {
+    Id(LocalDefId),
+    Span(Span),
+}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 725aa54157e..eb85cca0bd3 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -163,6 +163,8 @@ macro_rules! extract_msrv_attr {
 mod consts;
 #[macro_use]
 mod utils;
+#[cfg(feature = "metadata-collector-lint")]
+mod deprecated_lints;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
 mod absurd_extreme_comparisons;
@@ -289,6 +291,7 @@ mod mut_reference;
 mod mutable_debug_assertion;
 mod mutex_atomic;
 mod needless_arbitrary_self_type;
+mod needless_bitwise_bool;
 mod needless_bool;
 mod needless_borrow;
 mod needless_borrowed_ref;
@@ -363,6 +366,7 @@ mod unnecessary_sort_by;
 mod unnecessary_wraps;
 mod unnested_or_patterns;
 mod unsafe_removed_from_name;
+mod unused_async;
 mod unused_io_amount;
 mod unused_self;
 mod unused_unit;
@@ -834,6 +838,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         mutex_atomic::MUTEX_ATOMIC,
         mutex_atomic::MUTEX_INTEGER,
         needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
+        needless_bitwise_bool::NEEDLESS_BITWISE_BOOL,
         needless_bool::BOOL_COMPARISON,
         needless_bool::NEEDLESS_BOOL,
         needless_borrow::NEEDLESS_BORROW,
@@ -960,6 +965,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         unnecessary_wraps::UNNECESSARY_WRAPS,
         unnested_or_patterns::UNNESTED_OR_PATTERNS,
         unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
+        unused_async::UNUSED_ASYNC,
         unused_io_amount::UNUSED_IO_AMOUNT,
         unused_self::UNUSED_SELF,
         unused_unit::UNUSED_UNIT,
@@ -1008,7 +1014,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     #[cfg(feature = "metadata-collector-lint")]
     {
         if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
-            store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::default());
+            store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new());
         }
     }
 
@@ -1019,6 +1025,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let type_complexity_threshold = conf.type_complexity_threshold;
     store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
     store.register_late_pass(|| box booleans::NonminimalBool);
+    store.register_late_pass(|| box needless_bitwise_bool::NeedlessBitwiseBool);
     store.register_late_pass(|| box eq_op::EqOp);
     store.register_late_pass(|| box enum_clike::UnportableVariant);
     store.register_late_pass(|| box float_literal::FloatLiteral);
@@ -1155,7 +1162,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
     store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
     store.register_late_pass(|| box map_unit_fn::MapUnit);
-    store.register_late_pass(|| box inherent_impl::MultipleInherentImpl::default());
+    store.register_late_pass(|| box inherent_impl::MultipleInherentImpl);
     store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
     store.register_late_pass(|| box unwrap::Unwrap);
     store.register_late_pass(|| box duration_subsec::DurationSubsec);
@@ -1272,6 +1279,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box manual_map::ManualMap);
     store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
     store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
+    store.register_late_pass(|| box unused_async::UnusedAsync);
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(arithmetic::FLOAT_ARITHMETIC),
@@ -1365,6 +1373,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(if_not_else::IF_NOT_ELSE),
         LintId::of(implicit_hasher::IMPLICIT_HASHER),
         LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
+        LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
         LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
         LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
         LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
@@ -1392,6 +1401,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(misc::USED_UNDERSCORE_BINDING),
         LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
         LintId::of(mut_mut::MUT_MUT),
+        LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
         LintId::of(needless_continue::NEEDLESS_CONTINUE),
         LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
         LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
@@ -1415,6 +1425,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(unit_types::LET_UNIT_VALUE),
         LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
         LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
+        LintId::of(unused_async::UNUSED_ASYNC),
         LintId::of(unused_self::UNUSED_SELF),
         LintId::of(wildcard_imports::ENUM_GLOB_USE),
         LintId::of(wildcard_imports::WILDCARD_IMPORTS),
@@ -1511,7 +1522,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(identity_op::IDENTITY_OP),
         LintId::of(if_let_mutex::IF_LET_MUTEX),
         LintId::of(if_let_some_result::IF_LET_SOME_RESULT),
-        LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
         LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
         LintId::of(infinite_iter::INFINITE_ITER),
         LintId::of(inherent_to_string::INHERENT_TO_STRING),
@@ -1764,7 +1774,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(functions::MUST_USE_UNIT),
         LintId::of(functions::RESULT_UNIT_ERR),
         LintId::of(if_let_some_result::IF_LET_SOME_RESULT),
-        LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
         LintId::of(inherent_to_string::INHERENT_TO_STRING),
         LintId::of(len_zero::COMPARISON_TO_EMPTY),
         LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
index 9662a0b22a3..d3406780888 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
@@ -1,16 +1,15 @@
 use super::NEEDLESS_COLLECT;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::snippet;
+use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_type_diagnostic_item, match_type};
-use clippy_utils::{is_trait_method, path_to_local_id, paths};
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_trait_method, path_to_local_id};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
 use rustc_hir::{Block, Expr, ExprKind, GenericArg, GenericArgs, HirId, Local, Pat, PatKind, QPath, StmtKind, Ty};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
-
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{MultiSpan, Span};
 
@@ -28,23 +27,37 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
         if let Some(generic_args) = chain_method.args;
         if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
         if let Some(ty) = cx.typeck_results().node_type_opt(ty.hir_id);
-        if is_type_diagnostic_item(cx, ty, sym::vec_type)
-            || is_type_diagnostic_item(cx, ty, sym::vecdeque_type)
-            || match_type(cx, ty, &paths::BTREEMAP)
-            || is_type_diagnostic_item(cx, ty, sym::hashmap_type);
-        if let Some(sugg) = match &*method.ident.name.as_str() {
-            "len" => Some("count()".to_string()),
-            "is_empty" => Some("next().is_none()".to_string()),
-            "contains" => {
-                let contains_arg = snippet(cx, args[1].span, "??");
-                let (arg, pred) = contains_arg
-                    .strip_prefix('&')
-                    .map_or(("&x", &*contains_arg), |s| ("x", s));
-                Some(format!("any(|{}| x == {})", arg, pred))
-            }
-            _ => None,
-        };
         then {
+            let mut applicability = Applicability::MachineApplicable;
+            let is_empty_sugg = "next().is_none()".to_string();
+            let method_name = &*method.ident.name.as_str();
+            let sugg = if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
+                        is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
+                        is_type_diagnostic_item(cx, ty, sym::LinkedList) ||
+                        is_type_diagnostic_item(cx, ty, sym::BinaryHeap) {
+                match method_name {
+                    "len" => "count()".to_string(),
+                    "is_empty" => is_empty_sugg,
+                    "contains" => {
+                        let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability);
+                        let (arg, pred) = contains_arg
+                            .strip_prefix('&')
+                            .map_or(("&x", &*contains_arg), |s| ("x", s));
+                        format!("any(|{}| x == {})", arg, pred)
+                    }
+                    _ => return,
+                }
+            }
+            else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) ||
+                is_type_diagnostic_item(cx, ty, sym::hashmap_type) {
+                match method_name {
+                    "is_empty" => is_empty_sugg,
+                    _ => return,
+                }
+            }
+            else {
+                return;
+            };
             span_lint_and_sugg(
                 cx,
                 NEEDLESS_COLLECT,
@@ -52,7 +65,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
                 NEEDLESS_COLLECT_MSG,
                 "replace with",
                 sugg,
-                Applicability::MachineApplicable,
+                applicability,
             );
         }
     }
@@ -86,7 +99,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
                 if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
                     is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
                     is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
-                    match_type(cx, ty, &paths::LINKED_LIST);
+                    is_type_diagnostic_item(cx, ty, sym::LinkedList);
                 if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
                 if let [iter_call] = &*iter_calls;
                 then {
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index 82715d9bafa..63560047578 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -1,170 +1,347 @@
-use super::utils::{LoopNestVisitor, Nesting};
 use super::WHILE_LET_ON_ITERATOR;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::implements_trait;
-use clippy_utils::usage::mutated_variables;
-use clippy_utils::{
-    get_enclosing_block, is_refutable, is_trait_method, last_path_segment, path_to_local, path_to_local_id,
-};
+use clippy_utils::{get_enclosing_loop, is_refutable, is_trait_method, match_def_path, paths, visitors::is_res_used};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
-use rustc_hir::{Expr, ExprKind, HirId, MatchSource, Node, PatKind};
+use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
+use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, MatchSource, Node, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
-use rustc_span::symbol::sym;
+use rustc_span::{symbol::sym, Span, Symbol};
 
 pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let ExprKind::Match(match_expr, arms, MatchSource::WhileLetDesugar) = expr.kind {
-        let pat = &arms[0].pat.kind;
-        if let (&PatKind::TupleStruct(ref qpath, pat_args, _), &ExprKind::MethodCall(method_path, _, method_args, _)) =
-            (pat, &match_expr.kind)
-        {
-            let iter_expr = &method_args[0];
-
-            // Don't lint when the iterator is recreated on every iteration
-            if_chain! {
-                if let ExprKind::MethodCall(..) | ExprKind::Call(..) = iter_expr.kind;
-                if let Some(iter_def_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
-                if implements_trait(cx, cx.typeck_results().expr_ty(iter_expr), iter_def_id, &[]);
-                then {
-                    return;
-                }
-            }
+    let (scrutinee_expr, iter_expr, some_pat, loop_expr) = if_chain! {
+        if let ExprKind::Match(scrutinee_expr, [arm, _], MatchSource::WhileLetDesugar) = expr.kind;
+        // check for `Some(..)` pattern
+        if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = arm.pat.kind;
+        if let Res::Def(_, pat_did) = pat_path.res;
+        if match_def_path(cx, pat_did, &paths::OPTION_SOME);
+        // check for call to `Iterator::next`
+        if let ExprKind::MethodCall(method_name, _, [iter_expr], _) = scrutinee_expr.kind;
+        if method_name.ident.name == sym::next;
+        if is_trait_method(cx, scrutinee_expr, sym::Iterator);
+        if let Some(iter_expr) = try_parse_iter_expr(cx, iter_expr);
+        // get the loop containing the match expression
+        if let Some((_, Node::Expr(loop_expr))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1);
+        if !uses_iter(cx, &iter_expr, arm.body);
+        then {
+            (scrutinee_expr, iter_expr, some_pat, loop_expr)
+        } else {
+            return;
+        }
+    };
 
-            let lhs_constructor = last_path_segment(qpath);
-            if method_path.ident.name == sym::next
-                && is_trait_method(cx, match_expr, sym::Iterator)
-                && lhs_constructor.ident.name == sym::Some
-                && (pat_args.is_empty()
-                    || !is_refutable(cx, pat_args[0])
-                        && !is_used_inside(cx, iter_expr, arms[0].body)
-                        && !is_iterator_used_after_while_let(cx, iter_expr)
-                        && !is_nested(cx, expr, &method_args[0]))
-            {
-                let mut applicability = Applicability::MachineApplicable;
-                let iterator = snippet_with_applicability(cx, method_args[0].span, "_", &mut applicability);
-                let loop_var = if pat_args.is_empty() {
-                    "_".to_string()
-                } else {
-                    snippet_with_applicability(cx, pat_args[0].span, "_", &mut applicability).into_owned()
-                };
-                span_lint_and_sugg(
-                    cx,
-                    WHILE_LET_ON_ITERATOR,
-                    expr.span.with_hi(match_expr.span.hi()),
-                    "this loop could be written as a `for` loop",
-                    "try",
-                    format!("for {} in {}", loop_var, iterator),
-                    applicability,
-                );
-            }
+    let mut applicability = Applicability::MachineApplicable;
+    let loop_var = if let Some(some_pat) = some_pat.first() {
+        if is_refutable(cx, some_pat) {
+            // Refutable patterns don't work with for loops.
+            return;
         }
-    }
-}
+        snippet_with_applicability(cx, some_pat.span, "..", &mut applicability)
+    } else {
+        "_".into()
+    };
 
-fn is_used_inside<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, container: &'tcx Expr<'_>) -> bool {
-    let def_id = match path_to_local(expr) {
-        Some(id) => id,
-        None => return false,
+    // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be
+    // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
+    // afterwards a mutable borrow of a field isn't necessary.
+    let ref_mut = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) {
+        "&mut "
+    } else {
+        ""
     };
-    if let Some(used_mutably) = mutated_variables(container, cx) {
-        if used_mutably.contains(&def_id) {
-            return true;
+
+    let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability);
+    span_lint_and_sugg(
+        cx,
+        WHILE_LET_ON_ITERATOR,
+        expr.span.with_hi(scrutinee_expr.span.hi()),
+        "this loop could be written as a `for` loop",
+        "try",
+        format!("for {} in {}{}", loop_var, ref_mut, iterator),
+        applicability,
+    );
+}
+
+#[derive(Debug)]
+struct IterExpr {
+    /// The span of the whole expression, not just the path and fields stored here.
+    span: Span,
+    /// The fields used, in order of child to parent.
+    fields: Vec<Symbol>,
+    /// The path being used.
+    path: Res,
+}
+/// Parses any expression to find out which field of which variable is used. Will return `None` if
+/// the expression might have side effects.
+fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExpr> {
+    let span = e.span;
+    let mut fields = Vec::new();
+    loop {
+        match e.kind {
+            ExprKind::Path(ref path) => {
+                break Some(IterExpr {
+                    span,
+                    fields,
+                    path: cx.qpath_res(path, e.hir_id),
+                });
+            },
+            ExprKind::Field(base, name) => {
+                fields.push(name.name);
+                e = base;
+            },
+            // Dereferencing a pointer has no side effects and doesn't affect which field is being used.
+            ExprKind::Unary(UnOp::Deref, base) if cx.typeck_results().expr_ty(base).is_ref() => e = base,
+
+            // Shouldn't have side effects, but there's no way to trace which field is used. So forget which fields have
+            // already been seen.
+            ExprKind::Index(base, idx) if !idx.can_have_side_effects() => {
+                fields.clear();
+                e = base;
+            },
+            ExprKind::Unary(UnOp::Deref, base) => {
+                fields.clear();
+                e = base;
+            },
+
+            // No effect and doesn't affect which field is being used.
+            ExprKind::DropTemps(base) | ExprKind::AddrOf(_, _, base) | ExprKind::Type(base, _) => e = base,
+            _ => break None,
         }
     }
-    false
 }
 
-fn is_iterator_used_after_while_let<'tcx>(cx: &LateContext<'tcx>, iter_expr: &'tcx Expr<'_>) -> bool {
-    let def_id = match path_to_local(iter_expr) {
-        Some(id) => id,
-        None => return false,
-    };
-    let mut visitor = VarUsedAfterLoopVisitor {
-        def_id,
-        iter_expr_id: iter_expr.hir_id,
-        past_while_let: false,
-        var_used_after_while_let: false,
-    };
-    if let Some(enclosing_block) = get_enclosing_block(cx, def_id) {
-        walk_block(&mut visitor, enclosing_block);
+fn is_expr_same_field(cx: &LateContext<'_>, mut e: &Expr<'_>, mut fields: &[Symbol], path_res: Res) -> bool {
+    loop {
+        match (&e.kind, fields) {
+            (&ExprKind::Field(base, name), [head_field, tail_fields @ ..]) if name.name == *head_field => {
+                e = base;
+                fields = tail_fields;
+            },
+            (ExprKind::Path(path), []) => {
+                break cx.qpath_res(path, e.hir_id) == path_res;
+            },
+            (&(ExprKind::DropTemps(base) | ExprKind::AddrOf(_, _, base) | ExprKind::Type(base, _)), _) => e = base,
+            _ => break false,
+        }
     }
-    visitor.var_used_after_while_let
 }
 
-fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool {
-    if_chain! {
-        if let Some(loop_block) = get_enclosing_block(cx, match_expr.hir_id);
-        let parent_node = cx.tcx.hir().get_parent_node(loop_block.hir_id);
-        if let Some(Node::Expr(loop_expr)) = cx.tcx.hir().find(parent_node);
-        then {
-            return is_loop_nested(cx, loop_expr, iter_expr)
-        }
+/// Checks if the given expression is the same field as, is a child of, or is the parent of the
+/// given field. Used to check if the expression can be used while the given field is borrowed
+/// mutably. e.g. if checking for `x.y`, then `x.y`, `x.y.z`, and `x` will all return true, but
+/// `x.z`, and `y` will return false.
+fn is_expr_same_child_or_parent_field(cx: &LateContext<'_>, expr: &Expr<'_>, fields: &[Symbol], path_res: Res) -> bool {
+    match expr.kind {
+        ExprKind::Field(base, name) => {
+            if let Some((head_field, tail_fields)) = fields.split_first() {
+                if name.name == *head_field && is_expr_same_field(cx, base, fields, path_res) {
+                    return true;
+                }
+                // Check if the expression is a parent field
+                let mut fields_iter = tail_fields.iter();
+                while let Some(field) = fields_iter.next() {
+                    if *field == name.name && is_expr_same_field(cx, base, fields_iter.as_slice(), path_res) {
+                        return true;
+                    }
+                }
+            }
+
+            // Check if the expression is a child field.
+            let mut e = base;
+            loop {
+                match e.kind {
+                    ExprKind::Field(..) if is_expr_same_field(cx, e, fields, path_res) => break true,
+                    ExprKind::Field(base, _) | ExprKind::DropTemps(base) | ExprKind::Type(base, _) => e = base,
+                    ExprKind::Path(ref path) if fields.is_empty() => {
+                        break cx.qpath_res(path, e.hir_id) == path_res;
+                    },
+                    _ => break false,
+                }
+            }
+        },
+        // If the path matches, this is either an exact match, or the expression is a parent of the field.
+        ExprKind::Path(ref path) => cx.qpath_res(path, expr.hir_id) == path_res,
+        ExprKind::DropTemps(base) | ExprKind::Type(base, _) | ExprKind::AddrOf(_, _, base) => {
+            is_expr_same_child_or_parent_field(cx, base, fields, path_res)
+        },
+        _ => false,
     }
-    false
 }
 
-fn is_loop_nested(cx: &LateContext<'_>, loop_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool {
-    let mut id = loop_expr.hir_id;
-    let iter_id = if let Some(id) = path_to_local(iter_expr) {
-        id
-    } else {
-        return true;
+/// Strips off all field and path expressions. This will return true if a field or path has been
+/// skipped. Used to skip them after failing to check for equality.
+fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) {
+    let mut e = expr;
+    let e = loop {
+        match e.kind {
+            ExprKind::Field(base, _) | ExprKind::DropTemps(base) | ExprKind::Type(base, _) => e = base,
+            ExprKind::Path(_) => return (None, true),
+            _ => break e,
+        }
     };
-    loop {
-        let parent = cx.tcx.hir().get_parent_node(id);
-        if parent == id {
-            return false;
+    (Some(e), e.hir_id != expr.hir_id)
+}
+
+/// Checks if the given expression uses the iterator.
+fn uses_iter(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool {
+    struct V<'a, 'b, 'tcx> {
+        cx: &'a LateContext<'tcx>,
+        iter_expr: &'b IterExpr,
+        uses_iter: bool,
+    }
+    impl Visitor<'tcx> for V<'_, '_, 'tcx> {
+        type Map = ErasedMap<'tcx>;
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+            NestedVisitorMap::None
         }
-        match cx.tcx.hir().find(parent) {
-            Some(Node::Expr(expr)) => {
-                if let ExprKind::Loop(..) = expr.kind {
-                    return true;
-                };
-            },
-            Some(Node::Block(block)) => {
-                let mut block_visitor = LoopNestVisitor {
-                    hir_id: id,
-                    iterator: iter_id,
-                    nesting: Nesting::Unknown,
-                };
-                walk_block(&mut block_visitor, block);
-                if block_visitor.nesting == Nesting::RuledOut {
-                    return false;
+
+        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+            if self.uses_iter {
+                // return
+            } else if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
+                self.uses_iter = true;
+            } else if let (e, true) = skip_fields_and_path(e) {
+                if let Some(e) = e {
+                    self.visit_expr(e);
                 }
-            },
-            Some(Node::Stmt(_)) => (),
-            _ => {
-                return false;
-            },
+            } else if let ExprKind::Closure(_, _, id, _, _) = e.kind {
+                if is_res_used(self.cx, self.iter_expr.path, id) {
+                    self.uses_iter = true;
+                }
+            } else {
+                walk_expr(self, e);
+            }
         }
-        id = parent;
     }
-}
 
-struct VarUsedAfterLoopVisitor {
-    def_id: HirId,
-    iter_expr_id: HirId,
-    past_while_let: bool,
-    var_used_after_while_let: bool,
+    let mut v = V {
+        cx,
+        iter_expr,
+        uses_iter: false,
+    };
+    v.visit_expr(container);
+    v.uses_iter
 }
 
-impl<'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor {
-    type Map = Map<'tcx>;
+#[allow(clippy::too_many_lines)]
+fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr: &'tcx Expr<'_>) -> bool {
+    struct AfterLoopVisitor<'a, 'b, 'tcx> {
+        cx: &'a LateContext<'tcx>,
+        iter_expr: &'b IterExpr,
+        loop_id: HirId,
+        after_loop: bool,
+        used_iter: bool,
+    }
+    impl Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
+        type Map = ErasedMap<'tcx>;
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+            NestedVisitorMap::None
+        }
 
-    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if self.past_while_let {
-            if path_to_local_id(expr, self.def_id) {
-                self.var_used_after_while_let = true;
+        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+            if self.used_iter {
+                return;
+            }
+            if self.after_loop {
+                if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
+                    self.used_iter = true;
+                } else if let (e, true) = skip_fields_and_path(e) {
+                    if let Some(e) = e {
+                        self.visit_expr(e);
+                    }
+                } else if let ExprKind::Closure(_, _, id, _, _) = e.kind {
+                    self.used_iter = is_res_used(self.cx, self.iter_expr.path, id);
+                } else {
+                    walk_expr(self, e);
+                }
+            } else if self.loop_id == e.hir_id {
+                self.after_loop = true;
+            } else {
+                walk_expr(self, e);
+            }
+        }
+    }
+
+    struct NestedLoopVisitor<'a, 'b, 'tcx> {
+        cx: &'a LateContext<'tcx>,
+        iter_expr: &'b IterExpr,
+        local_id: HirId,
+        loop_id: HirId,
+        after_loop: bool,
+        found_local: bool,
+        used_after: bool,
+    }
+    impl Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
+        type Map = ErasedMap<'tcx>;
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+            NestedVisitorMap::None
+        }
+
+        fn visit_local(&mut self, l: &'tcx Local<'_>) {
+            if !self.after_loop {
+                l.pat.each_binding_or_first(&mut |_, id, _, _| {
+                    if id == self.local_id {
+                        self.found_local = true;
+                    }
+                });
+            }
+            if let Some(e) = l.init {
+                self.visit_expr(e);
+            }
+        }
+
+        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+            if self.used_after {
+                return;
+            }
+            if self.after_loop {
+                if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
+                    self.used_after = true;
+                } else if let (e, true) = skip_fields_and_path(e) {
+                    if let Some(e) = e {
+                        self.visit_expr(e);
+                    }
+                } else if let ExprKind::Closure(_, _, id, _, _) = e.kind {
+                    self.used_after = is_res_used(self.cx, self.iter_expr.path, id);
+                } else {
+                    walk_expr(self, e);
+                }
+            } else if e.hir_id == self.loop_id {
+                self.after_loop = true;
+            } else {
+                walk_expr(self, e);
             }
-        } else if self.iter_expr_id == expr.hir_id {
-            self.past_while_let = true;
         }
-        walk_expr(self, expr);
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
+
+    if let Some(e) = get_enclosing_loop(cx.tcx, loop_expr) {
+        // The iterator expression will be used on the next iteration unless it is declared within the outer
+        // loop.
+        let local_id = match iter_expr.path {
+            Res::Local(id) => id,
+            _ => return true,
+        };
+        let mut v = NestedLoopVisitor {
+            cx,
+            iter_expr,
+            local_id,
+            loop_id: loop_expr.hir_id,
+            after_loop: false,
+            found_local: false,
+            used_after: false,
+        };
+        v.visit_expr(e);
+        v.used_after || !v.found_local
+    } else {
+        let mut v = AfterLoopVisitor {
+            cx,
+            iter_expr,
+            loop_id: loop_expr.hir_id,
+            after_loop: false,
+            used_iter: false,
+        };
+        v.visit_expr(&cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
+        v.used_iter
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 314bf11e2d6..914b583186c 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -47,7 +47,12 @@ pub struct MacroRefData {
 
 impl MacroRefData {
     pub fn new(name: String, callee: Span, cx: &LateContext<'_>) -> Self {
-        let mut path = cx.sess().source_map().span_to_filename(callee).prefer_local().to_string();
+        let mut path = cx
+            .sess()
+            .source_map()
+            .span_to_filename(callee)
+            .prefer_local()
+            .to_string();
 
         // std lib paths are <::std::module::file type>
         // so remove brackets, space and type.
@@ -96,7 +101,8 @@ impl MacroUseImports {
         let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
         if let Some(callee) = span.source_callee() {
             if !self.collected.contains(&call_site) {
-                self.mac_refs.push(MacroRefData::new(name.to_string(), callee.def_site, cx));
+                self.mac_refs
+                    .push(MacroRefData::new(name.to_string(), callee.def_site, cx));
                 self.collected.insert(call_site);
             }
         }
@@ -174,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
                                 .push((*item).to_string());
                             check_dup.push((*item).to_string());
                         }
-                    }
+                    },
                     [root, rest @ ..] => {
                         if rest.iter().all(|item| !check_dup.contains(&(*item).to_string())) {
                             let filtered = rest
@@ -198,7 +204,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
                                 .push(rest.join("::"));
                             check_dup.extend(rest.iter().map(ToString::to_string));
                         }
-                    }
+                    },
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
index 520162559e5..2f579edd6ad 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
@@ -53,21 +53,6 @@ impl LateLintPass<'_> for ManualUnwrapOr {
     }
 }
 
-#[derive(Copy, Clone)]
-enum Case {
-    Option,
-    Result,
-}
-
-impl Case {
-    fn unwrap_fn_path(&self) -> &str {
-        match self {
-            Case::Option => "Option::unwrap_or",
-            Case::Result => "Result::unwrap_or",
-        }
-    }
-}
-
 fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> {
         if_chain! {
@@ -86,6 +71,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk);
             if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind;
             if path_to_local_id(unwrap_arm.body, binding_hir_id);
+            if cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty();
             if !contains_return_break_continue_macro(or_arm.body);
             then {
                 Some(or_arm)
@@ -98,10 +84,10 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     if_chain! {
         if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind;
         let ty = cx.typeck_results().expr_ty(scrutinee);
-        if let Some(case) = if is_type_diagnostic_item(cx, ty, sym::option_type) {
-            Some(Case::Option)
+        if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::option_type) {
+            Some("Option")
         } else if is_type_diagnostic_item(cx, ty, sym::result_type) {
-            Some(Case::Result)
+            Some("Result")
         } else {
             None
         };
@@ -124,7 +110,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             span_lint_and_sugg(
                 cx,
                 MANUAL_UNWRAP_OR, expr.span,
-                &format!("this pattern reimplements `{}`", case.unwrap_fn_path()),
+                &format!("this pattern reimplements `{}::unwrap_or`", ty_name),
                 "replace with",
                 format!(
                     "{}.unwrap_or({})",
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index a70e8b26087..fcd37687010 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -1478,15 +1478,34 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A
             );
         },
         PatKind::Wild => {
-            span_lint_and_sugg(
-                cx,
-                MATCH_SINGLE_BINDING,
-                expr.span,
-                "this match could be replaced by its body itself",
-                "consider using the match body instead",
-                snippet_body,
-                Applicability::MachineApplicable,
-            );
+            if ex.can_have_side_effects() {
+                let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0));
+                let sugg = format!(
+                    "{};\n{}{}",
+                    snippet_with_applicability(cx, ex.span, "..", &mut applicability),
+                    indent,
+                    snippet_body
+                );
+                span_lint_and_sugg(
+                    cx,
+                    MATCH_SINGLE_BINDING,
+                    expr.span,
+                    "this match could be replaced by its scrutinee and body",
+                    "consider using the scrutinee and body instead",
+                    sugg,
+                    applicability,
+                )
+            } else {
+                span_lint_and_sugg(
+                    cx,
+                    MATCH_SINGLE_BINDING,
+                    expr.span,
+                    "this match could be replaced by its body itself",
+                    "consider using the match body instead",
+                    snippet_body,
+                    Applicability::MachineApplicable,
+                );
+            }
         },
         _ => (),
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 0b1b6304def..e0d29682146 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -1838,16 +1838,18 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                     }
                 }
 
-                wrong_self_convention::check(
-                    cx,
-                    &name,
-                    item.vis.node.is_pub(),
-                    self_ty,
-                    first_arg_ty,
-                    first_arg.pat.span,
-                    implements_trait,
-                    false
-                );
+                if sig.decl.implicit_self.has_implicit_self() {
+                    wrong_self_convention::check(
+                        cx,
+                        &name,
+                        item.vis.node.is_pub(),
+                        self_ty,
+                        first_arg_ty,
+                        first_arg.pat.span,
+                        implements_trait,
+                        false
+                    );
+                }
             }
         }
 
@@ -1903,7 +1905,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 
         if_chain! {
             if let TraitItemKind::Fn(ref sig, _) = item.kind;
+            if sig.decl.implicit_self.has_implicit_self();
             if let Some(first_arg_ty) = sig.decl.inputs.iter().next();
+
             then {
                 let first_arg_span = first_arg_ty.span;
                 let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 6e2bcb113c2..1773c26c251 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -22,7 +22,7 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [
     // Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types).
     // Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
     (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), 
-    Convention::IsTraitItem(false)], &[SelfKind::Ref]),
+    Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]),
     (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), 
     Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]),
 ];
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 6966d798c53..b5d2549242b 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -660,7 +660,14 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool {
     use rustc_span::hygiene::MacroKind;
     if expr.span.from_expansion() {
         let data = expr.span.ctxt().outer_expn_data();
-        matches!(data.kind, ExpnKind::Macro { kind: MacroKind::Attr, name: _, proc_macro: _ })
+        matches!(
+            data.kind,
+            ExpnKind::Macro {
+                kind: MacroKind::Attr,
+                name: _,
+                proc_macro: _
+            }
+        )
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs
new file mode 100644
index 00000000000..b30bfbd4294
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs
@@ -0,0 +1,86 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::in_macro;
+use clippy_utils::source::snippet_opt;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:**
+    /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
+    /// a lazy and.
+    ///
+    /// **Why is this bad?**
+    /// The bitwise operators do not support short-circuiting, so it may hinder code performance.
+    /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
+    ///
+    /// **Known problems:**
+    /// This lint evaluates only when the right side is determined to have no side effects. At this time, that
+    /// determination is quite conservative.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let (x,y) = (true, false);
+    /// if x & !y {} // where both x and y are booleans
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let (x,y) = (true, false);
+    /// if x && !y {}
+    /// ```
+    pub NEEDLESS_BITWISE_BOOL,
+    pedantic,
+    "Boolean expressions that use bitwise rather than lazy operators"
+}
+
+declare_lint_pass!(NeedlessBitwiseBool => [NEEDLESS_BITWISE_BOOL]);
+
+fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.typeck_results().expr_ty(expr);
+    if_chain! {
+        if !in_macro(expr.span);
+        if let (&ExprKind::Binary(ref op, _, right), &ty::Bool) = (&expr.kind, &ty.kind());
+        if op.node == BinOpKind::BitAnd || op.node == BinOpKind::BitOr;
+        if let ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) = right.kind;
+        if !right.can_have_side_effects();
+        then {
+            return true;
+        }
+    }
+    false
+}
+
+fn suggession_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
+    if let ExprKind::Binary(ref op, left, right) = expr.kind {
+        if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) {
+            let op_snippet = match op.node {
+                BinOpKind::BitAnd => "&&",
+                _ => "||",
+            };
+            return Some(format!("{} {} {}", l_snippet, op_snippet, r_snippet));
+        }
+    }
+    None
+}
+
+impl LateLintPass<'_> for NeedlessBitwiseBool {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if is_bitwise_operation(cx, expr) {
+            span_lint_and_then(
+                cx,
+                NEEDLESS_BITWISE_BOOL,
+                expr.span,
+                "use of bitwise operator instead of lazy operator between booleans",
+                |diag| {
+                    if let Some(sugg) = suggession_snippet(cx, expr) {
+                        diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable);
+                    }
+                },
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index d8417c7dc70..c64491c63e2 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -1,14 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_lang_ctor;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{differing_macro_contexts, is_lang_ctor};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionSome, ResultOk};
 use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TyS;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:**
@@ -63,12 +62,6 @@ declare_clippy_lint! {
 
 declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]);
 
-#[derive(Debug)]
-enum SomeOkCall<'a> {
-    SomeCall(&'a Expr<'a>, &'a Expr<'a>),
-    OkCall(&'a Expr<'a>, &'a Expr<'a>),
-}
-
 impl LateLintPass<'_> for NeedlessQuestionMark {
     /*
      * The question mark operator is compatible with both Result<T, E> and Option<T>,
@@ -90,104 +83,37 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
      */
 
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
-        let e = match &expr.kind {
-            ExprKind::Ret(Some(e)) => e,
-            _ => return,
-        };
-
-        if let Some(ok_some_call) = is_some_or_ok_call(cx, e) {
-            emit_lint(cx, &ok_some_call);
+        if let ExprKind::Ret(Some(e)) = expr.kind {
+            check(cx, e);
         }
     }
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
-        // Function / Closure block
-        let expr_opt = if let ExprKind::Block(block, _) = &body.value.kind {
-            block.expr
-        } else {
-            // Single line closure
-            Some(&body.value)
-        };
-
-        if_chain! {
-            if let Some(expr) = expr_opt;
-            if let Some(ok_some_call) = is_some_or_ok_call(cx, expr);
-            then {
-                emit_lint(cx, &ok_some_call);
-            }
-        };
+        check(cx, body.value.peel_blocks());
     }
 }
 
-fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) {
-    let (entire_expr, inner_expr) = match expr {
-        SomeOkCall::OkCall(outer, inner) | SomeOkCall::SomeCall(outer, inner) => (outer, inner),
+fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    let inner_expr = if_chain! {
+        if let ExprKind::Call(path, [arg]) = &expr.kind;
+        if let ExprKind::Path(ref qpath) = &path.kind;
+        if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk);
+        if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &arg.kind;
+        if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind;
+        if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)) = &called.kind;
+        if expr.span.ctxt() == inner_expr.span.ctxt();
+        let expr_ty = cx.typeck_results().expr_ty(expr);
+        let inner_ty = cx.typeck_results().expr_ty(inner_expr);
+        if TyS::same_type(expr_ty, inner_ty);
+        then { inner_expr } else { return; }
     };
-
     span_lint_and_sugg(
         cx,
         NEEDLESS_QUESTION_MARK,
-        entire_expr.span,
+        expr.span,
         "question mark operator is useless here",
         "try",
         format!("{}", snippet(cx, inner_expr.span, r#""...""#)),
         Applicability::MachineApplicable,
     );
 }
-
-fn is_some_or_ok_call<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<SomeOkCall<'a>> {
-    if_chain! {
-        // Check outer expression matches CALL_IDENT(ARGUMENT) format
-        if let ExprKind::Call(path, args) = &expr.kind;
-        if let ExprKind::Path(ref qpath) = &path.kind;
-        if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk);
-
-        // Extract inner expression from ARGUMENT
-        if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind;
-        if let ExprKind::Call(called, args) = &inner_expr_with_q.kind;
-        if args.len() == 1;
-
-        if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)) = &called.kind;
-        then {
-            // Extract inner expr type from match argument generated by
-            // question mark operator
-            let inner_expr = &args[0];
-
-            // if the inner expr is inside macro but the outer one is not, do not lint (#6921)
-            if  differing_macro_contexts(expr.span, inner_expr.span) {
-                return None;
-            }
-
-            let inner_ty = cx.typeck_results().expr_ty(inner_expr);
-            let outer_ty = cx.typeck_results().expr_ty(expr);
-
-            // Check if outer and inner type are Option
-            let outer_is_some = is_type_diagnostic_item(cx, outer_ty, sym::option_type);
-            let inner_is_some = is_type_diagnostic_item(cx, inner_ty, sym::option_type);
-
-            // Check for Option MSRV
-            if outer_is_some && inner_is_some {
-                return Some(SomeOkCall::SomeCall(expr, inner_expr));
-            }
-
-            // Check if outer and inner type are Result
-            let outer_is_result = is_type_diagnostic_item(cx, outer_ty, sym::result_type);
-            let inner_is_result = is_type_diagnostic_item(cx, inner_ty, sym::result_type);
-
-            // Additional check: if the error type of the Result can be converted
-            // via the From trait, then don't match
-            let does_not_call_from = !has_implicit_error_from(cx, expr, inner_expr);
-
-            // Must meet Result MSRV
-            if outer_is_result && inner_is_result && does_not_call_from {
-                return Some(SomeOkCall::OkCall(expr, inner_expr));
-            }
-        }
-    }
-
-    None
-}
-
-fn has_implicit_error_from(cx: &LateContext<'_>, entire_expr: &Expr<'_>, inner_result_expr: &Expr<'_>) -> bool {
-    return cx.typeck_results().expr_ty(entire_expr) != cx.typeck_results().expr_ty(inner_result_expr);
-}
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index e527adbb892..b6af4175edf 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::usage::contains_return_break_continue_macro;
-use clippy_utils::{eager_or_lazy, get_enclosing_block, in_macro, is_lang_ctor};
+use clippy_utils::{eager_or_lazy, in_macro, is_else_clause, is_lang_ctor};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionSome;
@@ -81,7 +81,6 @@ struct OptionIfLetElseOccurence {
     method_sugg: String,
     some_expr: String,
     none_expr: String,
-    wrap_braces: bool,
 }
 
 /// Extracts the body of a given arm. If the arm contains only an expression,
@@ -106,37 +105,6 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> {
     }
 }
 
-/// If this is the else body of an if/else expression, then we need to wrap
-/// it in curly braces. Otherwise, we don't.
-fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| {
-        let mut should_wrap = false;
-
-        if let Some(Expr {
-            kind:
-                ExprKind::Match(
-                    _,
-                    arms,
-                    MatchSource::IfLetDesugar {
-                        contains_else_clause: true,
-                    },
-                ),
-            ..
-        }) = parent.expr
-        {
-            should_wrap = expr.hir_id == arms[1].body.hir_id;
-        } else if let Some(Expr {
-            kind: ExprKind::If(_, _, Some(else_clause)),
-            ..
-        }) = parent.expr
-        {
-            should_wrap = expr.hir_id == else_clause.hir_id;
-        }
-
-        should_wrap
-    })
-}
-
 fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String {
     format!(
         "{}{}",
@@ -161,6 +129,7 @@ fn detect_option_if_let_else<'tcx>(
     if_chain! {
         if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly
         if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind;
+        if !is_else_clause(cx.tcx, expr);
         if arms.len() == 2;
         if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already
         if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind;
@@ -168,13 +137,13 @@ fn detect_option_if_let_else<'tcx>(
         if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind;
         if !contains_return_break_continue_macro(arms[0].body);
         if !contains_return_break_continue_macro(arms[1].body);
+
         then {
             let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
             let some_body = extract_body_from_arm(&arms[0])?;
             let none_body = extract_body_from_arm(&arms[1])?;
             let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" };
             let capture_name = id.name.to_ident_string();
-            let wrap_braces = should_wrap_in_braces(cx, expr);
             let (as_ref, as_mut) = match &cond_expr.kind {
                 ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
                 ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
@@ -190,7 +159,6 @@ fn detect_option_if_let_else<'tcx>(
                 method_sugg: method_sugg.to_string(),
                 some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir(cx, some_body, "..")),
                 none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir(cx, none_body, "..")),
-                wrap_braces,
             })
         } else {
             None
@@ -208,13 +176,8 @@ impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
                 format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(),
                 "try",
                 format!(
-                    "{}{}.{}({}, {}){}",
-                    if detection.wrap_braces { "{ " } else { "" },
-                    detection.option,
-                    detection.method_sugg,
-                    detection.none_expr,
-                    detection.some_expr,
-                    if detection.wrap_braces { " }" } else { "" },
+                    "{}.{}({}, {})",
+                    detection.option, detection.method_sugg, detection.none_expr, detection.some_expr,
                 ),
                 Applicability::MaybeIncorrect,
             );
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
index d22f7d9a96b..04542146516 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
@@ -8,7 +8,12 @@ use super::UNIT_CMP;
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if expr.span.from_expansion() {
         if let Some(callee) = expr.span.source_callee() {
-            if let ExpnKind::Macro { kind: MacroKind::Bang, name: symbol, proc_macro: _ } = callee.kind {
+            if let ExpnKind::Macro {
+                kind: MacroKind::Bang,
+                name: symbol,
+                proc_macro: _,
+            } = callee.kind
+            {
                 if let ExprKind::Binary(ref cmp, left, _) = expr.kind {
                     let op = cmp.node;
                     if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() {
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
new file mode 100644
index 00000000000..18ee07d3a95
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -0,0 +1,92 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnHeader, HirId, IsAsync, Item, ItemKind, YieldSource};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for functions that are declared `async` but have no `.await`s inside of them.
+    ///
+    /// **Why is this bad?** Async functions with no async code create overhead, both mentally and computationally.
+    /// Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of which
+    /// causes runtime overhead and hassle for the caller.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // Bad
+    /// async fn get_random_number() -> i64 {
+    ///     4 // Chosen by fair dice roll. Guaranteed to be random.
+    /// }
+    /// let number_future = get_random_number();
+    ///
+    /// // Good
+    /// fn get_random_number_improved() -> i64 {
+    ///     4 // Chosen by fair dice roll. Guaranteed to be random.
+    /// }
+    /// let number_future = async { get_random_number_improved() };
+    /// ```
+    pub UNUSED_ASYNC,
+    pedantic,
+    "finds async functions with no await statements"
+}
+
+declare_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
+
+struct AsyncFnVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    found_await: bool,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
+        if let ExprKind::Yield(_, YieldSource::Await { .. }) = ex.kind {
+            self.found_await = true;
+        }
+        walk_expr(self, ex);
+    }
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
+    fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if let ItemKind::Trait(..) = item.kind {
+            return;
+        }
+    }
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        fn_kind: FnKind<'tcx>,
+        fn_decl: &'tcx FnDecl<'tcx>,
+        body: &Body<'tcx>,
+        span: Span,
+        hir_id: HirId,
+    ) {
+        if let FnKind::ItemFn(_, _, FnHeader { asyncness, .. }, _) = &fn_kind {
+            if matches!(asyncness, IsAsync::Async) {
+                let mut visitor = AsyncFnVisitor { cx, found_await: false };
+                walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), span, hir_id);
+                if !visitor.found_await {
+                    span_lint_and_help(
+                        cx,
+                        UNUSED_ASYNC,
+                        span,
+                        "unused `async` for function with no await statements",
+                        None,
+                        "consider removing the `async` from this function",
+                    );
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index aa4d16633ff..2ad6fa77f48 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::same_type_and_consts;
 use clippy_utils::{in_macro, meets_msrv, msrvs};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_hir::def::DefKind;
 use rustc_hir::{
-    def,
+    self as hir,
+    def::{self, DefKind},
     def_id::LocalDefId,
     intravisit::{walk_ty, NestedVisitorMap, Visitor},
     Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Node, Path, PathSegment,
@@ -14,7 +14,7 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
-use rustc_middle::ty::{AssocKind, Ty, TyS};
+use rustc_middle::ty::{AssocKind, Ty};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{BytePos, Span};
@@ -459,7 +459,7 @@ fn in_impl(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> bool {
 
 fn should_lint_ty(hir_ty: &hir::Ty<'_>, ty: Ty<'_>, self_ty: Ty<'_>) -> bool {
     if_chain! {
-        if TyS::same_type(ty, self_ty);
+        if same_type_and_consts(ty, self_ty);
         if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
         then {
             !matches!(path.res, def::Res::SelfTy(..))
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 7edb280be73..2be99fb761b 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::source::{snippet, snippet_with_macro_callsite};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
 use clippy_utils::{get_parent_expr, match_def_path, match_trait_method, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, TyS};
+use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::sym;
 
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                 if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(&args[0]);
-                    if TyS::same_type(a, b) {
+                    if same_type_and_consts(a, b) {
                         let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
                         span_lint_and_sugg(
                             cx,
@@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     }
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(&args[0]);
-                    if TyS::same_type(a, b) {
+                    if same_type_and_consts(a, b) {
                         let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
                         span_lint_and_sugg(
                             cx,
@@ -110,7 +110,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     if is_type_diagnostic_item(cx, a, sym::result_type);
                     if let ty::Adt(_, substs) = a.kind();
                     if let Some(a_type) = substs.types().next();
-                    if TyS::same_type(a_type, b);
+                    if same_type_and_consts(a_type, b);
+
                     then {
                         span_lint_and_help(
                             cx,
@@ -137,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                             if is_type_diagnostic_item(cx, a, sym::result_type);
                             if let ty::Adt(_, substs) = a.kind();
                             if let Some(a_type) = substs.types().next();
-                            if TyS::same_type(a_type, b);
+                            if same_type_and_consts(a_type, b);
 
                             then {
                                 let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
@@ -154,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
 
                         if_chain! {
                             if match_def_path(cx, def_id, &paths::FROM_FROM);
-                            if TyS::same_type(a, b);
+                            if same_type_and_consts(a, b);
 
                             then {
                                 let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par();
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 52c1dc3bdd2..fd2dddb3b96 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -26,13 +26,13 @@ impl TryConf {
 
 macro_rules! define_Conf {
     ($(
-        #[$doc:meta]
+        #[doc = $doc:literal]
         $(#[conf_deprecated($dep:literal)])?
         ($name:ident: $ty:ty = $default:expr),
     )*) => {
         /// Clippy lint configuration
         pub struct Conf {
-            $(#[$doc] pub $name: $ty,)*
+            $(#[doc = $doc] pub $name: $ty,)*
         }
 
         mod defaults {
@@ -89,6 +89,34 @@ macro_rules! define_Conf {
                 Ok(TryConf { conf, errors })
             }
         }
+
+        #[cfg(feature = "metadata-collector-lint")]
+        pub mod metadata {
+            use crate::utils::internal_lints::metadata_collector::ClippyConfiguration;
+
+            macro_rules! wrap_option {
+                () => (None);
+                ($x:literal) => (Some($x));
+            }
+
+            pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
+                vec![
+                    $(
+                        {
+                            let deprecation_reason = wrap_option!($($dep)?);
+
+                            ClippyConfiguration::new(
+                                stringify!($name),
+                                stringify!($ty),
+                                format!("{:?}", super::defaults::$name()),
+                                $doc,
+                                deprecation_reason,
+                            )
+                        },
+                    )+
+                ]
+            }
+        }
     };
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index e85637ca758..e9fa043b20f 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -8,9 +8,6 @@
 //! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
 //! a simple mistake)
 
-// # NITs
-// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames
-
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{
@@ -22,13 +19,14 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, Loc, Span, Symbol};
 use serde::{ser::SerializeStruct, Serialize, Serializer};
 use std::collections::BinaryHeap;
+use std::fmt;
 use std::fs::{self, OpenOptions};
 use std::io::prelude::*;
 use std::path::Path;
 
 use crate::utils::internal_lints::is_lint_ref_type;
 use clippy_utils::{
-    diagnostics::span_lint, last_path_segment, match_function_call, match_path, paths, ty::match_type,
+    diagnostics::span_lint, last_path_segment, match_def_path, match_function_call, match_path, paths, ty::match_type,
     ty::walk_ptrs_ty_depth,
 };
 
@@ -39,8 +37,52 @@ const BLACK_LISTED_LINTS: [&str; 3] = ["lint_author", "deep_code_inspection", "i
 /// These groups will be ignored by the lint group matcher. This is useful for collections like
 /// `clippy::all`
 const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"];
-/// Lints within this group will be excluded from the collection
-const EXCLUDED_LINT_GROUPS: [&str; 1] = ["clippy::internal"];
+/// Lints within this group will be excluded from the collection. These groups
+/// have to be defined without the `clippy::` prefix.
+const EXCLUDED_LINT_GROUPS: [&str; 1] = ["internal"];
+/// Collected deprecated lint will be assigned to this group in the JSON output
+const DEPRECATED_LINT_GROUP_STR: &str = "deprecated";
+/// This is the lint level for deprecated lints that will be displayed in the lint list
+const DEPRECATED_LINT_LEVEL: &str = "none";
+/// This array holds Clippy's lint groups with their corresponding default lint level. The
+/// lint level for deprecated lints is set in `DEPRECATED_LINT_LEVEL`.
+const DEFAULT_LINT_LEVELS: [(&str, &str); 8] = [
+    ("correctness", "deny"),
+    ("restriction", "allow"),
+    ("style", "warn"),
+    ("pedantic", "allow"),
+    ("complexity", "warn"),
+    ("perf", "warn"),
+    ("cargo", "allow"),
+    ("nursery", "allow"),
+];
+/// This prefix is in front of the lint groups in the lint store. The prefix will be trimmed
+/// to only keep the actual lint group in the output.
+const CLIPPY_LINT_GROUP_PREFIX: &str = "clippy::";
+
+/// This template will be used to format the configuration section in the lint documentation.
+/// The `configurations` parameter will be replaced with one or multiple formatted
+/// `ClippyConfiguration` instances. See `CONFIGURATION_VALUE_TEMPLATE` for further customizations
+macro_rules! CONFIGURATION_SECTION_TEMPLATE {
+    () => {
+        r#"
+**Configuration**
+This lint has the following configuration variables:
+
+{configurations}
+"#
+    };
+}
+/// This template will be used to format an individual `ClippyConfiguration` instance in the
+/// lint documentation.
+///
+/// The format function will provide strings for the following parameters: `name`, `ty`, `doc` and
+/// `default`
+macro_rules! CONFIGURATION_VALUE_TEMPLATE {
+    () => {
+        "* {name}: {ty}: {doc} (defaults to `{default}`)\n"
+    };
+}
 
 const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [
     &["clippy_utils", "diagnostics", "span_lint"],
@@ -66,6 +108,7 @@ const SUGGESTION_FUNCTIONS: [&[&str]; 2] = [
     &["clippy_utils", "diagnostics", "multispan_sugg"],
     &["clippy_utils", "diagnostics", "multispan_sugg_with_applicability"],
 ];
+const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "ClippyDeprecatedLint"];
 
 /// The index of the applicability name of `paths::APPLICABILITY_VALUES`
 const APPLICABILITY_NAME_INDEX: usize = 2;
@@ -102,13 +145,33 @@ declare_clippy_lint! {
 impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]);
 
 #[allow(clippy::module_name_repetitions)]
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone)]
 pub struct MetadataCollector {
     /// All collected lints
     ///
     /// We use a Heap here to have the lints added in alphabetic order in the export
     lints: BinaryHeap<LintMetadata>,
     applicability_info: FxHashMap<String, ApplicabilityInfo>,
+    config: Vec<ClippyConfiguration>,
+}
+
+impl MetadataCollector {
+    pub fn new() -> Self {
+        Self {
+            lints: BinaryHeap::<LintMetadata>::default(),
+            applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(),
+            config: collect_configs(),
+        }
+    }
+
+    fn get_lint_configs(&self, lint_name: &str) -> Option<String> {
+        self.config
+            .iter()
+            .filter(|config| config.lints.iter().any(|lint| lint == lint_name))
+            .map(ToString::to_string)
+            .reduce(|acc, x| acc + &x)
+            .map(|configurations| format!(CONFIGURATION_SECTION_TEMPLATE!(), configurations = configurations))
+    }
 }
 
 impl Drop for MetadataCollector {
@@ -143,6 +206,7 @@ struct LintMetadata {
     id: String,
     id_span: SerializableSpan,
     group: String,
+    level: &'static str,
     docs: String,
     /// This field is only used in the output and will only be
     /// mapped shortly before the actual output.
@@ -150,11 +214,12 @@ struct LintMetadata {
 }
 
 impl LintMetadata {
-    fn new(id: String, id_span: SerializableSpan, group: String, docs: String) -> Self {
+    fn new(id: String, id_span: SerializableSpan, group: String, level: &'static str, docs: String) -> Self {
         Self {
             id,
             id_span,
             group,
+            level,
             docs,
             applicability: None,
         }
@@ -182,7 +247,7 @@ impl SerializableSpan {
         let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo());
 
         Self {
-            path: format!("{}", loc.file.name),
+            path: format!("{}", loc.file.name.prefer_remapped()),
             line: loc.line,
         }
     }
@@ -214,6 +279,95 @@ impl Serialize for ApplicabilityInfo {
     }
 }
 
+// ==================================================================
+// Configuration
+// ==================================================================
+#[derive(Debug, Clone, Default)]
+pub struct ClippyConfiguration {
+    name: String,
+    config_type: &'static str,
+    default: String,
+    lints: Vec<String>,
+    doc: String,
+    deprecation_reason: Option<&'static str>,
+}
+
+impl ClippyConfiguration {
+    pub fn new(
+        name: &'static str,
+        config_type: &'static str,
+        default: String,
+        doc_comment: &'static str,
+        deprecation_reason: Option<&'static str>,
+    ) -> Self {
+        let (lints, doc) = parse_config_field_doc(doc_comment)
+            .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
+
+        Self {
+            name: to_kebab(name),
+            lints,
+            doc,
+            config_type,
+            default,
+            deprecation_reason,
+        }
+    }
+}
+
+fn collect_configs() -> Vec<ClippyConfiguration> {
+    crate::utils::conf::metadata::get_configuration_metadata()
+}
+
+/// This parses the field documentation of the config struct.
+///
+/// ```rust, ignore
+/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
+/// ```
+///
+/// Would yield:
+/// ```rust, ignore
+/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
+/// ```
+fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
+    const DOC_START: &str = " Lint: ";
+    if_chain! {
+        if doc_comment.starts_with(DOC_START);
+        if let Some(split_pos) = doc_comment.find('.');
+        then {
+            let mut doc_comment = doc_comment.to_string();
+            let documentation = doc_comment.split_off(split_pos);
+
+            doc_comment.make_ascii_lowercase();
+            let lints: Vec<String> = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect();
+
+            Some((lints, documentation))
+        } else {
+            None
+        }
+    }
+}
+
+/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
+fn to_kebab(config_name: &str) -> String {
+    config_name.replace('_', "-")
+}
+
+impl fmt::Display for ClippyConfiguration {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            CONFIGURATION_VALUE_TEMPLATE!(),
+            name = self.name,
+            ty = self.config_type,
+            doc = self.doc,
+            default = self.default
+        )
+    }
+}
+
+// ==================================================================
+// Lint pass
+// ==================================================================
 impl<'hir> LateLintPass<'hir> for MetadataCollector {
     /// Collecting lint declarations like:
     /// ```rust, ignore
@@ -225,23 +379,48 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
     /// }
     /// ```
     fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) {
-        if_chain! {
-            // item validation
-            if let ItemKind::Static(ref ty, Mutability::Not, _) = item.kind;
-            if is_lint_ref_type(cx, ty);
-            // blacklist check
-            let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
-            if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
-            // metadata extraction
-            if let Some(group) = get_lint_group_or_lint(cx, &lint_name, item);
-            if let Some(docs) = extract_attr_docs_or_lint(cx, item);
-            then {
-                self.lints.push(LintMetadata::new(
-                    lint_name,
-                    SerializableSpan::from_item(cx, item),
-                    group,
-                    docs,
-                ));
+        if let ItemKind::Static(ref ty, Mutability::Not, _) = item.kind {
+            // Normal lint
+            if_chain! {
+                // item validation
+                if is_lint_ref_type(cx, ty);
+                // blacklist check
+                let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
+                if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
+                // metadata extraction
+                if let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item);
+                if let Some(mut docs) = extract_attr_docs_or_lint(cx, item);
+                then {
+                    if let Some(configuration_section) = self.get_lint_configs(&lint_name) {
+                        docs.push_str(&configuration_section);
+                    }
+
+                    self.lints.push(LintMetadata::new(
+                        lint_name,
+                        SerializableSpan::from_item(cx, item),
+                        group,
+                        level,
+                        docs,
+                    ));
+                }
+            }
+
+            if_chain! {
+                if is_deprecated_lint(cx, ty);
+                // blacklist check
+                let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
+                if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
+                // Metadata the little we can get from a deprecated lint
+                if let Some(docs) = extract_attr_docs_or_lint(cx, item);
+                then {
+                    self.lints.push(LintMetadata::new(
+                        lint_name,
+                        SerializableSpan::from_item(cx, item),
+                        DEPRECATED_LINT_GROUP_STR.to_string(),
+                        DEPRECATED_LINT_LEVEL,
+                        docs,
+                    ));
+                }
             }
         }
     }
@@ -268,7 +447,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
                 // - src/misc.rs:734:9
                 // - src/methods/mod.rs:3545:13
                 // - src/methods/mod.rs:3496:13
-                // We are basically unable to resolve the lint name it self.
+                // We are basically unable to resolve the lint name itself.
                 return;
             }
 
@@ -318,15 +497,32 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
         })
 }
 
-fn get_lint_group_or_lint(cx: &LateContext<'_>, lint_name: &str, item: &'hir Item<'_>) -> Option<String> {
+fn get_lint_group_and_level_or_lint(
+    cx: &LateContext<'_>,
+    lint_name: &str,
+    item: &'hir Item<'_>,
+) -> Option<(String, &'static str)> {
     let result = cx.lint_store.check_lint_name(lint_name, Some(sym::clippy));
     if let CheckLintNameResult::Tool(Ok(lint_lst)) = result {
-        get_lint_group(cx, lint_lst[0])
-            .or_else(|| {
-                lint_collection_error_item(cx, item, "Unable to determine lint group");
+        if let Some(group) = get_lint_group(cx, lint_lst[0]) {
+            if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) {
+                return None;
+            }
+
+            if let Some(level) = get_lint_level_from_group(&group) {
+                Some((group, level))
+            } else {
+                lint_collection_error_item(
+                    cx,
+                    item,
+                    &format!("Unable to determine lint level for found group `{}`", group),
+                );
                 None
-            })
-            .filter(|group| !EXCLUDED_LINT_GROUPS.contains(&group.as_str()))
+            }
+        } else {
+            lint_collection_error_item(cx, item, "Unable to determine lint group");
+            None
+        }
     } else {
         lint_collection_error_item(cx, item, "Unable to find lint in lint_store");
         None
@@ -339,14 +535,31 @@ fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option<String> {
             continue;
         }
 
-        if lints.iter().any(|x| *x == lint_id) {
-            return Some((*group_name).to_string());
+        if lints.iter().any(|group_lint| *group_lint == lint_id) {
+            let group = group_name.strip_prefix(CLIPPY_LINT_GROUP_PREFIX).unwrap_or(group_name);
+            return Some((*group).to_string());
         }
     }
 
     None
 }
 
+fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> {
+    DEFAULT_LINT_LEVELS
+        .iter()
+        .find_map(|(group_name, group_level)| (*group_name == lint_group).then(|| *group_level))
+}
+
+fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
+    if let hir::TyKind::Path(ref path) = ty.kind {
+        if let hir::def::Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, ty.hir_id) {
+            return match_def_path(cx, def_id, &DEPRECATED_LINT_TYPE);
+        }
+    }
+
+    false
+}
+
 // ==================================================================
 // Lint emission
 // ==================================================================
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 7e962472c07..d0e79efa70d 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -279,8 +279,15 @@ impl EarlyLintPass for Write {
             span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`");
             self.lint_println_empty_string(cx, mac);
         } else if mac.path == sym!(write) {
-            if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), true) {
+            if let (Some(fmt_str), dest) = self.check_tts(cx, mac.args.inner_tokens(), true) {
                 if check_newlines(&fmt_str) {
+                    let (nl_span, only_nl) = newline_span(&fmt_str);
+                    let nl_span = match (dest, only_nl) {
+                        // Special case of `write!(buf, "\n")`: Mark everything from the end of
+                        // `buf` for removal so no trailing comma [`writeln!(buf, )`] remains.
+                        (Some(dest_expr), true) => Span::new(dest_expr.span.hi(), nl_span.hi(), nl_span.ctxt()),
+                        _ => nl_span,
+                    };
                     span_lint_and_then(
                         cx,
                         WRITE_WITH_NEWLINE,
@@ -289,10 +296,7 @@ impl EarlyLintPass for Write {
                         |err| {
                             err.multipart_suggestion(
                                 "use `writeln!()` instead",
-                                vec![
-                                    (mac.path.span, String::from("writeln")),
-                                    (newline_span(&fmt_str), String::new()),
-                                ],
+                                vec![(mac.path.span, String::from("writeln")), (nl_span, String::new())],
                                 Applicability::MachineApplicable,
                             );
                         },
@@ -329,12 +333,13 @@ impl EarlyLintPass for Write {
 
 /// Given a format string that ends in a newline and its span, calculates the span of the
 /// newline, or the format string itself if the format string consists solely of a newline.
-fn newline_span(fmtstr: &StrLit) -> Span {
+/// Return this and a boolean indicating whether it only consisted of a newline.
+fn newline_span(fmtstr: &StrLit) -> (Span, bool) {
     let sp = fmtstr.span;
     let contents = &fmtstr.symbol.as_str();
 
     if *contents == r"\n" {
-        return sp;
+        return (sp, true);
     }
 
     let newline_sp_hi = sp.hi()
@@ -351,7 +356,7 @@ fn newline_span(fmtstr: &StrLit) -> Span {
         panic!("expected format string to contain a newline");
     };
 
-    sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi)
+    (sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi), false)
 }
 
 /// Stores a list of replacement spans for each argument, but only if all the replacements used an
@@ -613,7 +618,7 @@ impl Write {
                     |err| {
                         err.multipart_suggestion(
                             &format!("use `{}!` instead", suggested),
-                            vec![(mac.path.span, suggested), (newline_span(&fmt_str), String::new())],
+                            vec![(mac.path.span, suggested), (newline_span(&fmt_str).0, String::new())],
                             Applicability::MachineApplicable,
                         );
                     },
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 0a1d4e11142..93ed3b18400 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -14,6 +14,7 @@ unicode-normalization = "0.1"
 rustc-semver="1.1.0"
 
 [features]
+deny-warnings = []
 internal-lints = []
 metadata-collector-lint = []
 
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 9ac9500b4eb..d6dcd4abbd9 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -4,7 +4,14 @@
 #![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(rustc_private)]
 #![recursion_limit = "512"]
+#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
+// warn on the same lints as `clippy_lints`
+#![warn(trivial_casts, trivial_numeric_casts)]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
+// warn on rustc internal lints
+#![warn(rustc::internal)]
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
@@ -855,6 +862,24 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio
     })
 }
 
+/// Gets the loop enclosing the given expression, if any.
+pub fn get_enclosing_loop(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+    let map = tcx.hir();
+    for (_, node) in map.parent_iter(expr.hir_id) {
+        match node {
+            Node::Expr(
+                e @ Expr {
+                    kind: ExprKind::Loop(..),
+                    ..
+                },
+            ) => return Some(e),
+            Node::Expr(_) | Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
+            _ => break,
+        }
+    }
+    None
+}
+
 /// Gets the parent node if it's an impl block.
 pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
     let map = tcx.hir();
@@ -947,7 +972,12 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
             let data = span.ctxt().outer_expn_data();
             let new_span = data.call_site;
 
-            if let ExpnKind::Macro { kind: MacroKind::Bang, name: mac_name, proc_macro: _ } = data.kind {
+            if let ExpnKind::Macro {
+                kind: MacroKind::Bang,
+                name: mac_name,
+                proc_macro: _,
+            } = data.kind
+            {
                 if mac_name.as_str() == name {
                     return Some(new_span);
                 }
@@ -975,7 +1005,12 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
         let data = span.ctxt().outer_expn_data();
         let new_span = data.call_site;
 
-        if let ExpnKind::Macro { kind: MacroKind::Bang, name: mac_name, proc_macro: _ } = data.kind {
+        if let ExpnKind::Macro {
+            kind: MacroKind::Bang,
+            name: mac_name,
+            proc_macro: _,
+        } = data.kind
+        {
             if mac_name.as_str() == name {
                 return Some(new_span);
             }
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 0633a19391f..0c950661757 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -289,7 +289,7 @@ fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool {
     let mut chars = sugg.as_ref().chars();
     if let Some('(') = chars.next() {
         let mut depth = 1;
-        while let Some(c) = chars.next() {
+        for c in &mut chars {
             if c == '(' {
                 depth += 1;
             } else if c == ')' {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 64a80f2554f..c36e215f184 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -2,9 +2,8 @@
 
 #![allow(clippy::module_name_repetitions)]
 
-use std::collections::HashMap;
-
 use rustc_ast::ast::Mutability;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{TyKind, Unsafety};
@@ -184,14 +183,14 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 /// Checks if `Ty` is normalizable. This function is useful
 /// to avoid crashes on `layout_of`.
 pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
-    is_normalizable_helper(cx, param_env, ty, &mut HashMap::new())
+    is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default())
 }
 
 fn is_normalizable_helper<'tcx>(
     cx: &LateContext<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
-    cache: &mut HashMap<Ty<'tcx>, bool>,
+    cache: &mut FxHashMap<Ty<'tcx>, bool>,
 ) -> bool {
     if let Some(&cached_result) = cache.get(ty) {
         return cached_result;
@@ -322,3 +321,27 @@ pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
     }
     inner(ty, 0)
 }
+
+/// Returns `true` if types `a` and `b` are same types having same `Const` generic args,
+/// otherwise returns `false`
+pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+    match (&a.kind(), &b.kind()) {
+        (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
+            if did_a != did_b {
+                return false;
+            }
+
+            substs_a
+                .iter()
+                .zip(substs_b.iter())
+                .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
+                    (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
+                    (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
+                        same_type_and_consts(type_a, type_b)
+                    },
+                    _ => true,
+                })
+        },
+        _ => a == b,
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index d431bdf34ee..ecdc666b5f6 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -1,7 +1,7 @@
 use crate::path_to_local_id;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, walk_expr, ErasedMap, NestedVisitorMap, Visitor};
-use rustc_hir::{Arm, Block, Body, Destination, Expr, ExprKind, HirId, Stmt};
+use rustc_hir::{def::Res, Arm, Block, Body, BodyId, Destination, Expr, ExprKind, HirId, Stmt};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
 
@@ -218,6 +218,7 @@ impl<'tcx> Visitable<'tcx> for &'tcx Arm<'tcx> {
     }
 }
 
+/// Calls the given function for each break expression.
 pub fn visit_break_exprs<'tcx>(
     node: impl Visitable<'tcx>,
     f: impl FnMut(&'tcx Expr<'tcx>, Destination, Option<&'tcx Expr<'tcx>>),
@@ -239,3 +240,36 @@ pub fn visit_break_exprs<'tcx>(
 
     node.visit(&mut V(f));
 }
+
+/// Checks if the given resolved path is used in the given body.
+pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
+    struct V<'a, 'tcx> {
+        cx: &'a LateContext<'tcx>,
+        res: Res,
+        found: bool,
+    }
+    impl Visitor<'tcx> for V<'_, 'tcx> {
+        type Map = Map<'tcx>;
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+            NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+        }
+
+        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+            if self.found {
+                return;
+            }
+
+            if let ExprKind::Path(p) = &e.kind {
+                if self.cx.qpath_res(p, e.hir_id) == self.res {
+                    self.found = true;
+                }
+            } else {
+                walk_expr(self, e)
+            }
+        }
+    }
+
+    let mut v = V { cx, res, found: false };
+    v.visit_expr(&cx.tcx.hir().body(body).value);
+    v.found
+}
diff --git a/src/tools/clippy/doc/basics.md b/src/tools/clippy/doc/basics.md
index 5226875cc21..e2e307ce4f6 100644
--- a/src/tools/clippy/doc/basics.md
+++ b/src/tools/clippy/doc/basics.md
@@ -28,6 +28,8 @@ git clone git@github.com:<your-username>/rust-clippy
 If you've already cloned Clippy in the past, update it to the latest version:
 
 ```bash
+# If the upstream remote has not been added yet
+git remote add upstream https://github.com/rust-lang/rust-clippy
 # upstream has to be the remote of the rust-lang/rust-clippy repo
 git fetch upstream
 # make sure that you are on the master branch
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 593162f09a7..cb8cb0978f6 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-05-06"
+channel = "nightly-2021-05-20"
 components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 6524fd4706c..5d9f128753f 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -22,14 +22,12 @@ fn dogfood_clippy() {
         return;
     }
     let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
-    let enable_metadata_collection = std::env::var("ENABLE_METADATA_COLLECTION").unwrap_or_else(|_| "0".to_string());
 
     let mut command = Command::new(&*CLIPPY_PATH);
     command
         .current_dir(root_dir)
         .env("CLIPPY_DOGFOOD", "1")
         .env("CARGO_INCREMENTAL", "0")
-        .env("ENABLE_METADATA_COLLECTION", &enable_metadata_collection)
         .arg("clippy")
         .arg("--all-targets")
         .arg("--all-features")
@@ -157,10 +155,9 @@ fn dogfood_subprojects() {
     if cargo::is_rustc_test_suite() {
         return;
     }
-    let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
 
     // NOTE: `path_dep` crate is omitted on purpose here
-    for d in &[
+    for project in &[
         "clippy_workspace_tests",
         "clippy_workspace_tests/src",
         "clippy_workspace_tests/subcrate",
@@ -170,34 +167,49 @@ fn dogfood_subprojects() {
         "clippy_utils",
         "rustc_tools_util",
     ] {
-        let mut command = Command::new(&*CLIPPY_PATH);
-        command
-            .current_dir(root_dir.join(d))
-            .env("CLIPPY_DOGFOOD", "1")
-            .env("CARGO_INCREMENTAL", "0")
-            .arg("clippy")
-            .arg("--all-targets")
-            .arg("--all-features")
-            .arg("--")
-            .args(&["-D", "clippy::all"])
-            .args(&["-D", "clippy::pedantic"])
-            .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
+        run_clippy_for_project(project);
+    }
+
+    // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the
+    // same time, so we test this immediately after the dogfood for workspaces.
+    test_no_deps_ignores_path_deps_in_workspaces();
+}
 
-        // internal lints only exist if we build with the internal-lints feature
-        if cfg!(feature = "internal-lints") {
-            command.args(&["-D", "clippy::internal"]);
-        }
+#[test]
+#[ignore]
+#[cfg(feature = "metadata-collector-lint")]
+fn run_metadata_collection_lint() {
+    std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
+    run_clippy_for_project("clippy_lints");
+}
 
-        let output = command.output().unwrap();
+fn run_clippy_for_project(project: &str) {
+    let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
 
-        println!("status: {}", output.status);
-        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
-        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
+    let mut command = Command::new(&*CLIPPY_PATH);
 
-        assert!(output.status.success());
+    command
+        .current_dir(root_dir.join(project))
+        .env("CLIPPY_DOGFOOD", "1")
+        .env("CARGO_INCREMENTAL", "0")
+        .arg("clippy")
+        .arg("--all-targets")
+        .arg("--all-features")
+        .arg("--")
+        .args(&["-D", "clippy::all"])
+        .args(&["-D", "clippy::pedantic"])
+        .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
+
+    // internal lints only exist if we build with the internal-lints feature
+    if cfg!(feature = "internal-lints") {
+        command.args(&["-D", "clippy::internal"]);
     }
 
-    // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the
-    // same time, so we test this immediately after the dogfood for workspaces.
-    test_no_deps_ignores_path_deps_in_workspaces();
+    let output = command.output().unwrap();
+
+    println!("status: {}", output.status);
+    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
+    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
+
+    assert!(output.status.success());
 }
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7231.rs b/src/tools/clippy/tests/ui/crashes/ice-7231.rs
new file mode 100644
index 00000000000..5595d8d1d62
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-7231.rs
@@ -0,0 +1,10 @@
+// edition:2018
+#![allow(clippy::never_loop)]
+
+async fn f() {
+    loop {
+        break;
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.fixed b/src/tools/clippy/tests/ui/floating_point_powi.fixed
index 56762400593..85f7c531e39 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_powi.fixed
@@ -4,8 +4,6 @@
 fn main() {
     let one = 1;
     let x = 3f32;
-    let _ = x * x;
-    let _ = x * x;
 
     let y = 4f32;
     let _ = x.mul_add(x, y);
@@ -13,7 +11,10 @@ fn main() {
     let _ = x.mul_add(x, y).sqrt();
     let _ = y.mul_add(y, x).sqrt();
     // Cases where the lint shouldn't be applied
+    let _ = x.powi(2);
+    let _ = x.powi(1 + 1);
     let _ = x.powi(3);
+    let _ = x.powi(4) + y;
     let _ = x.powi(one + 1);
     let _ = (x.powi(2) + y.powi(2)).sqrt();
 }
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.rs b/src/tools/clippy/tests/ui/floating_point_powi.rs
index 1f800e4628d..ece61d1bec4 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.rs
+++ b/src/tools/clippy/tests/ui/floating_point_powi.rs
@@ -4,8 +4,6 @@
 fn main() {
     let one = 1;
     let x = 3f32;
-    let _ = x.powi(2);
-    let _ = x.powi(1 + 1);
 
     let y = 4f32;
     let _ = x.powi(2) + y;
@@ -13,7 +11,10 @@ fn main() {
     let _ = (x.powi(2) + y).sqrt();
     let _ = (x + y.powi(2)).sqrt();
     // Cases where the lint shouldn't be applied
+    let _ = x.powi(2);
+    let _ = x.powi(1 + 1);
     let _ = x.powi(3);
+    let _ = x.powi(4) + y;
     let _ = x.powi(one + 1);
     let _ = (x.powi(2) + y.powi(2)).sqrt();
 }
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.stderr b/src/tools/clippy/tests/ui/floating_point_powi.stderr
index d5a5f1bcca1..37d840988bb 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_powi.stderr
@@ -1,40 +1,28 @@
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:7:13
-   |
-LL |     let _ = x.powi(2);
-   |             ^^^^^^^^^ help: consider using: `x * x`
-   |
-   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
-
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:8:13
-   |
-LL |     let _ = x.powi(1 + 1);
-   |             ^^^^^^^^^^^^^ help: consider using: `x * x`
-
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:11:13
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:9:13
    |
 LL |     let _ = x.powi(2) + y;
    |             ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
+   |
+   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
 
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:12:13
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:10:13
    |
 LL |     let _ = x + y.powi(2);
    |             ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
 
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:13:13
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:11:13
    |
 LL |     let _ = (x.powi(2) + y).sqrt();
    |             ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
 
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:14:13
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:12:13
    |
 LL |     let _ = (x + y.powi(2)).sqrt();
    |             ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
 
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/impl.rs b/src/tools/clippy/tests/ui/impl.rs
index 1c46e3a5337..39443775015 100644
--- a/src/tools/clippy/tests/ui/impl.rs
+++ b/src/tools/clippy/tests/ui/impl.rs
@@ -33,4 +33,35 @@ impl fmt::Debug for MyStruct {
     }
 }
 
+// issue #5772
+struct WithArgs<T>(T);
+impl WithArgs<u32> {
+    fn f1() {}
+}
+impl WithArgs<u64> {
+    fn f2() {}
+}
+impl WithArgs<u64> {
+    fn f3() {}
+}
+
+// Ok, the struct is allowed to have multiple impls.
+#[allow(clippy::multiple_inherent_impl)]
+struct Allowed;
+impl Allowed {}
+impl Allowed {}
+impl Allowed {}
+
+struct AllowedImpl;
+#[allow(clippy::multiple_inherent_impl)]
+impl AllowedImpl {}
+// Ok, the first block is skipped by this lint.
+impl AllowedImpl {}
+
+struct OneAllowedImpl;
+impl OneAllowedImpl {}
+#[allow(clippy::multiple_inherent_impl)]
+impl OneAllowedImpl {}
+impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed.
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/impl.stderr b/src/tools/clippy/tests/ui/impl.stderr
index aab688cc2d8..8703ecac93e 100644
--- a/src/tools/clippy/tests/ui/impl.stderr
+++ b/src/tools/clippy/tests/ui/impl.stderr
@@ -31,5 +31,33 @@ LL | |     fn first() {}
 LL | | }
    | |_^
 
-error: aborting due to 2 previous errors
+error: multiple implementations of this structure
+  --> $DIR/impl.rs:44:1
+   |
+LL | / impl WithArgs<u64> {
+LL | |     fn f3() {}
+LL | | }
+   | |_^
+   |
+note: first implementation here
+  --> $DIR/impl.rs:41:1
+   |
+LL | / impl WithArgs<u64> {
+LL | |     fn f2() {}
+LL | | }
+   | |_^
+
+error: multiple implementations of this structure
+  --> $DIR/impl.rs:65:1
+   |
+LL | impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed.
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first implementation here
+  --> $DIR/impl.rs:62:1
+   |
+LL | impl OneAllowedImpl {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
index e7a29596b73..3717f962745 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
@@ -163,4 +163,19 @@ mod issue6965 {
     }
 }
 
+use std::rc::Rc;
+fn format_name(name: Option<&Rc<str>>) -> &str {
+    match name {
+        None => "<anon>",
+        Some(name) => name,
+    }
+}
+
+fn implicit_deref_ref() {
+    let _: &str = match Some(&"bye") {
+        None => "hi",
+        Some(s) => s,
+    };
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs
index 66006b6c616..989adde1f5b 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs
@@ -205,4 +205,19 @@ mod issue6965 {
     }
 }
 
+use std::rc::Rc;
+fn format_name(name: Option<&Rc<str>>) -> &str {
+    match name {
+        None => "<anon>",
+        Some(name) => name,
+    }
+}
+
+fn implicit_deref_ref() {
+    let _: &str = match Some(&"bye") {
+        None => "hi",
+        Some(s) => s,
+    };
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed
index 526e94b10bd..30bf6402253 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.fixed
+++ b/src/tools/clippy/tests/ui/match_single_binding.fixed
@@ -94,10 +94,7 @@ fn main() {
         0 => println!("Disabled branch"),
         _ => println!("Enabled branch"),
     }
-    // Lint
-    let x = 1;
-    let y = 1;
-    println!("Single branch");
+
     // Ok
     let x = 1;
     let y = 1;
diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs
index 6a2ca7c5e93..d8bb80d8b96 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.rs
+++ b/src/tools/clippy/tests/ui/match_single_binding.rs
@@ -106,15 +106,7 @@ fn main() {
         0 => println!("Disabled branch"),
         _ => println!("Enabled branch"),
     }
-    // Lint
-    let x = 1;
-    let y = 1;
-    match match y {
-        0 => 1,
-        _ => 2,
-    } {
-        _ => println!("Single branch"),
-    }
+
     // Ok
     let x = 1;
     let y = 1;
diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr
index cbbf5d29c02..795c8c3e24d 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.stderr
+++ b/src/tools/clippy/tests/ui/match_single_binding.stderr
@@ -167,16 +167,5 @@ LL |             unwrapped
 LL |         })
    |
 
-error: this match could be replaced by its body itself
-  --> $DIR/match_single_binding.rs:112:5
-   |
-LL | /     match match y {
-LL | |         0 => 1,
-LL | |         _ => 2,
-LL | |     } {
-LL | |         _ => println!("Single branch"),
-LL | |     }
-   | |_____^ help: consider using the match body instead: `println!("Single branch");`
-
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_single_binding2.fixed b/src/tools/clippy/tests/ui/match_single_binding2.fixed
index e73a85b73d7..a91fcc2125d 100644
--- a/src/tools/clippy/tests/ui/match_single_binding2.fixed
+++ b/src/tools/clippy/tests/ui/match_single_binding2.fixed
@@ -34,4 +34,20 @@ fn main() {
         },
         None => println!("nothing"),
     }
+
+    fn side_effects() {}
+
+    // Lint (scrutinee has side effects)
+    // issue #7094
+    side_effects();
+    println!("Side effects");
+
+    // Lint (scrutinee has side effects)
+    // issue #7094
+    let x = 1;
+    match x {
+        0 => 1,
+        _ => 2,
+    };
+    println!("Single branch");
 }
diff --git a/src/tools/clippy/tests/ui/match_single_binding2.rs b/src/tools/clippy/tests/ui/match_single_binding2.rs
index 7362cb390e5..476386ebabe 100644
--- a/src/tools/clippy/tests/ui/match_single_binding2.rs
+++ b/src/tools/clippy/tests/ui/match_single_binding2.rs
@@ -34,4 +34,22 @@ fn main() {
         },
         None => println!("nothing"),
     }
+
+    fn side_effects() {}
+
+    // Lint (scrutinee has side effects)
+    // issue #7094
+    match side_effects() {
+        _ => println!("Side effects"),
+    }
+
+    // Lint (scrutinee has side effects)
+    // issue #7094
+    let x = 1;
+    match match x {
+        0 => 1,
+        _ => 2,
+    } {
+        _ => println!("Single branch"),
+    }
 }
diff --git a/src/tools/clippy/tests/ui/match_single_binding2.stderr b/src/tools/clippy/tests/ui/match_single_binding2.stderr
index bc18d191aa3..4372f55af87 100644
--- a/src/tools/clippy/tests/ui/match_single_binding2.stderr
+++ b/src/tools/clippy/tests/ui/match_single_binding2.stderr
@@ -30,5 +30,39 @@ LL |             let (a, b) = get_tup();
 LL |             println!("a {:?} and b {:?}", a, b);
    |
 
-error: aborting due to 2 previous errors
+error: this match could be replaced by its scrutinee and body
+  --> $DIR/match_single_binding2.rs:42:5
+   |
+LL | /     match side_effects() {
+LL | |         _ => println!("Side effects"),
+LL | |     }
+   | |_____^
+   |
+help: consider using the scrutinee and body instead
+   |
+LL |     side_effects();
+LL |     println!("Side effects");
+   |
+
+error: this match could be replaced by its scrutinee and body
+  --> $DIR/match_single_binding2.rs:49:5
+   |
+LL | /     match match x {
+LL | |         0 => 1,
+LL | |         _ => 2,
+LL | |     } {
+LL | |         _ => println!("Single branch"),
+LL | |     }
+   | |_____^
+   |
+help: consider using the scrutinee and body instead
+   |
+LL |     match x {
+LL |         0 => 1,
+LL |         _ => 2,
+LL |     };
+LL |     println!("Single branch");
+   |
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed
new file mode 100644
index 00000000000..5e1ea663a10
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed
@@ -0,0 +1,40 @@
+// run-rustfix
+
+#![warn(clippy::needless_bitwise_bool)]
+
+fn returns_bool() -> bool {
+    true
+}
+
+const fn const_returns_bool() -> bool {
+    false
+}
+
+fn main() {
+    let (x, y) = (false, true);
+    if x & y {
+        println!("true")
+    }
+    if returns_bool() & x {
+        println!("true")
+    }
+    if !returns_bool() & returns_bool() {
+        println!("true")
+    }
+    if y && !x {
+        println!("true")
+    }
+
+    // BELOW: lints we hope to catch as `Expr::can_have_side_effects` improves.
+    if y & !const_returns_bool() {
+        println!("true") // This is a const function, in an UnOp
+    }
+
+    if y & "abcD".is_empty() {
+        println!("true") // This is a const method call
+    }
+
+    if y & (0 < 1) {
+        println!("true") // This is a BinOp with no side effects
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs
new file mode 100644
index 00000000000..f3075fba0a2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs
@@ -0,0 +1,40 @@
+// run-rustfix
+
+#![warn(clippy::needless_bitwise_bool)]
+
+fn returns_bool() -> bool {
+    true
+}
+
+const fn const_returns_bool() -> bool {
+    false
+}
+
+fn main() {
+    let (x, y) = (false, true);
+    if x & y {
+        println!("true")
+    }
+    if returns_bool() & x {
+        println!("true")
+    }
+    if !returns_bool() & returns_bool() {
+        println!("true")
+    }
+    if y & !x {
+        println!("true")
+    }
+
+    // BELOW: lints we hope to catch as `Expr::can_have_side_effects` improves.
+    if y & !const_returns_bool() {
+        println!("true") // This is a const function, in an UnOp
+    }
+
+    if y & "abcD".is_empty() {
+        println!("true") // This is a const method call
+    }
+
+    if y & (0 < 1) {
+        println!("true") // This is a BinOp with no side effects
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr
new file mode 100644
index 00000000000..63c88ef63f5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr
@@ -0,0 +1,10 @@
+error: use of bitwise operator instead of lazy operator between booleans
+  --> $DIR/needless_bitwise_bool.rs:24:8
+   |
+LL |     if y & !x {
+   |        ^^^^^^ help: try: `y && !x`
+   |
+   = note: `-D clippy::needless-bitwise-bool` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed
index af6c7bf15ea..6ecbbcb6249 100644
--- a/src/tools/clippy/tests/ui/needless_collect.fixed
+++ b/src/tools/clippy/tests/ui/needless_collect.fixed
@@ -2,7 +2,7 @@
 
 #![allow(unused, clippy::suspicious_map, clippy::iter_count)]
 
-use std::collections::{BTreeSet, HashMap, HashSet};
+use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList};
 
 #[warn(clippy::needless_collect)]
 #[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)]
@@ -13,9 +13,24 @@ fn main() {
         // Empty
     }
     sample.iter().cloned().any(|x| x == 1);
-    sample.iter().map(|x| (x, x)).count();
+    // #7164 HashMap's and BTreeMap's `len` usage should not be linted
+    sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len();
+    sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().len();
+
+    sample.iter().map(|x| (x, x)).next().is_none();
+    sample.iter().map(|x| (x, x)).next().is_none();
+
     // Notice the `HashSet`--this should not be linted
     sample.iter().collect::<HashSet<_>>().len();
     // Neither should this
     sample.iter().collect::<BTreeSet<_>>().len();
+
+    sample.iter().count();
+    sample.iter().next().is_none();
+    sample.iter().cloned().any(|x| x == 1);
+    sample.iter().any(|x| x == &1);
+
+    // `BinaryHeap` doesn't have `contains` method
+    sample.iter().count();
+    sample.iter().next().is_none();
 }
diff --git a/src/tools/clippy/tests/ui/needless_collect.rs b/src/tools/clippy/tests/ui/needless_collect.rs
index 6ae14f370b1..8dc69bcf5b3 100644
--- a/src/tools/clippy/tests/ui/needless_collect.rs
+++ b/src/tools/clippy/tests/ui/needless_collect.rs
@@ -2,7 +2,7 @@
 
 #![allow(unused, clippy::suspicious_map, clippy::iter_count)]
 
-use std::collections::{BTreeSet, HashMap, HashSet};
+use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList};
 
 #[warn(clippy::needless_collect)]
 #[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)]
@@ -13,9 +13,24 @@ fn main() {
         // Empty
     }
     sample.iter().cloned().collect::<Vec<_>>().contains(&1);
+    // #7164 HashMap's and BTreeMap's `len` usage should not be linted
     sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len();
+    sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().len();
+
+    sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().is_empty();
+    sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().is_empty();
+
     // Notice the `HashSet`--this should not be linted
     sample.iter().collect::<HashSet<_>>().len();
     // Neither should this
     sample.iter().collect::<BTreeSet<_>>().len();
+
+    sample.iter().collect::<LinkedList<_>>().len();
+    sample.iter().collect::<LinkedList<_>>().is_empty();
+    sample.iter().cloned().collect::<LinkedList<_>>().contains(&1);
+    sample.iter().collect::<LinkedList<_>>().contains(&&1);
+
+    // `BinaryHeap` doesn't have `contains` method
+    sample.iter().collect::<BinaryHeap<_>>().len();
+    sample.iter().collect::<BinaryHeap<_>>().is_empty();
 }
diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr
index 2a9539d5975..039091627a8 100644
--- a/src/tools/clippy/tests/ui/needless_collect.stderr
+++ b/src/tools/clippy/tests/ui/needless_collect.stderr
@@ -19,10 +19,52 @@ LL |     sample.iter().cloned().collect::<Vec<_>>().contains(&1);
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)`
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect.rs:16:35
+  --> $DIR/needless_collect.rs:20:35
    |
-LL |     sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len();
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()`
+LL |     sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().is_empty();
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
 
-error: aborting due to 4 previous errors
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:21:35
+   |
+LL |     sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().is_empty();
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:28:19
+   |
+LL |     sample.iter().collect::<LinkedList<_>>().len();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:29:19
+   |
+LL |     sample.iter().collect::<LinkedList<_>>().is_empty();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:30:28
+   |
+LL |     sample.iter().cloned().collect::<LinkedList<_>>().contains(&1);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:31:19
+   |
+LL |     sample.iter().collect::<LinkedList<_>>().contains(&&1);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &1)`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:34:19
+   |
+LL |     sample.iter().collect::<BinaryHeap<_>>().len();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:35:19
+   |
+LL |     sample.iter().collect::<BinaryHeap<_>>().is_empty();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.fixed b/src/tools/clippy/tests/ui/needless_question_mark.fixed
index 52ddd9d2dc8..f1fc81aa12b 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.fixed
+++ b/src/tools/clippy/tests/ui/needless_question_mark.fixed
@@ -94,6 +94,11 @@ where
     Ok(x?)
 }
 
+// not quite needless
+fn deref_ref(s: Option<&String>) -> Option<&str> {
+    Some(s?)
+}
+
 fn main() {}
 
 // #6921 if a macro wraps an expr in Some(  ) and the ? is in the macro use,
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.rs b/src/tools/clippy/tests/ui/needless_question_mark.rs
index 1ea4ba0d83f..44a0c5f61b5 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.rs
+++ b/src/tools/clippy/tests/ui/needless_question_mark.rs
@@ -94,6 +94,11 @@ where
     Ok(x?)
 }
 
+// not quite needless
+fn deref_ref(s: Option<&String>) -> Option<&str> {
+    Some(s?)
+}
+
 fn main() {}
 
 // #6921 if a macro wraps an expr in Some(  ) and the ? is in the macro use,
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr
index f1f05d1af3a..02bf50d077a 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.stderr
+++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr
@@ -67,7 +67,7 @@ LL |         return Ok(t.magic?);
    |                ^^^^^^^^^^^^ help: try: `t.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:115:27
+  --> $DIR/needless_question_mark.rs:120:27
    |
 LL |         || -> Option<_> { Some(Some($expr)?) }()
    |                           ^^^^^^^^^^^^^^^^^^ help: try: `Some($expr)`
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index 47e7460fa7a..769ccc14bc1 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -10,7 +10,11 @@ fn bad1(string: Option<&str>) -> (bool, &str) {
 fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> {
     if string.is_none() {
         None
-    } else { string.map_or(Some((false, "")), |x| Some((true, x))) }
+    } else if let Some(x) = string {
+        Some((true, x))
+    } else {
+        Some((false, ""))
+    }
 }
 
 fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index 7aab068800a..4ebb068d22e 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -11,17 +11,6 @@ LL | |     }
    = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:17:12
-   |
-LL |       } else if let Some(x) = string {
-   |  ____________^
-LL | |         Some((true, x))
-LL | |     } else {
-LL | |         Some((false, ""))
-LL | |     }
-   | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }`
-
-error: use Option::map_or instead of an if let/else
   --> $DIR/option_if_let_else.rs:25:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
@@ -159,5 +148,5 @@ error: use Option::map_or instead of an if let/else
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs
new file mode 100644
index 00000000000..4f4203f5fdb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_async.rs
@@ -0,0 +1,15 @@
+// edition:2018
+#![warn(clippy::unused_async)]
+
+async fn foo() -> i32 {
+    4
+}
+
+async fn bar() -> i32 {
+    foo().await
+}
+
+fn main() {
+    foo();
+    bar();
+}
diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr
new file mode 100644
index 00000000000..8b834d205b1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_async.stderr
@@ -0,0 +1,13 @@
+error: unused `async` for function with no await statements
+  --> $DIR/unused_async.rs:4:1
+   |
+LL | / async fn foo() -> i32 {
+LL | |     4
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::unused-async` implied by `-D warnings`
+   = help: consider removing the `async` from this function
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed
index 1282befdfb3..631da6fe066 100644
--- a/src/tools/clippy/tests/ui/use_self.fixed
+++ b/src/tools/clippy/tests/ui/use_self.fixed
@@ -462,3 +462,33 @@ mod issue6818 {
         a: i32,
     }
 }
+
+mod issue7206 {
+    struct MyStruct<const C: char>;
+    impl From<MyStruct<'a'>> for MyStruct<'b'> {
+        fn from(_s: MyStruct<'a'>) -> Self {
+            Self
+        }
+    }
+
+    // keep linting non-`Const` generic args
+    struct S<'a> {
+        inner: &'a str,
+    }
+
+    struct S2<T> {
+        inner: T,
+    }
+
+    impl<T> S2<T> {
+        fn new() -> Self {
+            unimplemented!();
+        }
+    }
+
+    impl<'a> S2<S<'a>> {
+        fn new_again() -> Self {
+            Self::new()
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs
index 7aaac7b2414..7a10d755faa 100644
--- a/src/tools/clippy/tests/ui/use_self.rs
+++ b/src/tools/clippy/tests/ui/use_self.rs
@@ -462,3 +462,33 @@ mod issue6818 {
         a: i32,
     }
 }
+
+mod issue7206 {
+    struct MyStruct<const C: char>;
+    impl From<MyStruct<'a'>> for MyStruct<'b'> {
+        fn from(_s: MyStruct<'a'>) -> Self {
+            Self
+        }
+    }
+
+    // keep linting non-`Const` generic args
+    struct S<'a> {
+        inner: &'a str,
+    }
+
+    struct S2<T> {
+        inner: T,
+    }
+
+    impl<T> S2<T> {
+        fn new() -> Self {
+            unimplemented!();
+        }
+    }
+
+    impl<'a> S2<S<'a>> {
+        fn new_again() -> Self {
+            S2::new()
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr
index a32a9b9157d..cf6222c9b45 100644
--- a/src/tools/clippy/tests/ui/use_self.stderr
+++ b/src/tools/clippy/tests/ui/use_self.stderr
@@ -162,5 +162,11 @@ error: unnecessary structure name repetition
 LL |             A::new::<submod::B>(submod::B {})
    |             ^ help: use the applicable keyword: `Self`
 
-error: aborting due to 27 previous errors
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:491:13
+   |
+LL |             S2::new()
+   |             ^^ help: use the applicable keyword: `Self`
+
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed
index 03977de9455..76aa82068d6 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.fixed
+++ b/src/tools/clippy/tests/ui/useless_conversion.fixed
@@ -70,4 +70,23 @@ fn main() {
     let a: i32 = 1;
     let b: i32 = 1;
     let _ = (a + b) * 3;
+
+    // see #7205
+    let s: Foo<'a'> = Foo;
+    let _: Foo<'b'> = s.into();
+    let s2: Foo<'a'> = Foo;
+    let _: Foo<'a'> = s2;
+    let s3: Foo<'a'> = Foo;
+    let _ = s3;
+    let s4: Foo<'a'> = Foo;
+    let _ = vec![s4, s4, s4].into_iter();
+}
+
+#[derive(Copy, Clone)]
+struct Foo<const C: char>;
+
+impl From<Foo<'a'>> for Foo<'b'> {
+    fn from(_s: Foo<'a'>) -> Self {
+        Foo
+    }
 }
diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs
index f6e094c1661..ccee7abb404 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.rs
+++ b/src/tools/clippy/tests/ui/useless_conversion.rs
@@ -70,4 +70,23 @@ fn main() {
     let a: i32 = 1;
     let b: i32 = 1;
     let _ = i32::from(a + b) * 3;
+
+    // see #7205
+    let s: Foo<'a'> = Foo;
+    let _: Foo<'b'> = s.into();
+    let s2: Foo<'a'> = Foo;
+    let _: Foo<'a'> = s2.into();
+    let s3: Foo<'a'> = Foo;
+    let _ = Foo::<'a'>::from(s3);
+    let s4: Foo<'a'> = Foo;
+    let _ = vec![s4, s4, s4].into_iter().into_iter();
+}
+
+#[derive(Copy, Clone)]
+struct Foo<const C: char>;
+
+impl From<Foo<'a'>> for Foo<'b'> {
+    fn from(_s: Foo<'a'>) -> Self {
+        Foo
+    }
 }
diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr
index 26a33595031..e6760f700f3 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.stderr
+++ b/src/tools/clippy/tests/ui/useless_conversion.stderr
@@ -70,5 +70,23 @@ error: useless conversion to the same type: `i32`
 LL |     let _ = i32::from(a + b) * 3;
    |             ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)`
 
-error: aborting due to 11 previous errors
+error: useless conversion to the same type: `Foo<'a'>`
+  --> $DIR/useless_conversion.rs:78:23
+   |
+LL |     let _: Foo<'a'> = s2.into();
+   |                       ^^^^^^^^^ help: consider removing `.into()`: `s2`
+
+error: useless conversion to the same type: `Foo<'a'>`
+  --> $DIR/useless_conversion.rs:80:13
+   |
+LL |     let _ = Foo::<'a'>::from(s3);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3`
+
+error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>`
+  --> $DIR/useless_conversion.rs:82:13
+   |
+LL |     let _ = vec![s4, s4, s4].into_iter().into_iter();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
index 749393db124..c3e2cf0c4a4 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
@@ -1,7 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::while_let_on_iterator)]
-#![allow(clippy::never_loop, unreachable_code, unused_mut)]
+#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)]
 
 fn base() {
     let mut iter = 1..20;
@@ -41,13 +41,6 @@ fn base() {
     // or this
     let mut iter = 1u32..20;
     while let Some(_) = iter.next() {
-        break;
-    }
-    println!("Remaining iter {:?}", iter);
-
-    // or this
-    let mut iter = 1u32..20;
-    while let Some(_) = iter.next() {
         iter = 1..20;
     }
 }
@@ -135,18 +128,6 @@ fn refutable2() {
 
 fn nested_loops() {
     let a = [42, 1337];
-    let mut y = a.iter();
-    loop {
-        // x is reused, so don't lint here
-        while let Some(_) = y.next() {}
-    }
-
-    let mut y = a.iter();
-    for _ in 0..2 {
-        while let Some(_) = y.next() {
-            // y is reused, don't lint
-        }
-    }
 
     loop {
         let mut y = a.iter();
@@ -167,10 +148,8 @@ fn issue1121() {
 }
 
 fn issue2965() {
-    // This should not cause an ICE and suggest:
-    //
-    // for _ in values.iter() {}
-    //
+    // This should not cause an ICE
+
     use std::collections::HashSet;
     let mut values = HashSet::new();
     values.insert(1);
@@ -205,13 +184,145 @@ fn issue1654() {
     }
 }
 
+fn issue6491() {
+    // Used in outer loop, needs &mut
+    let mut it = 1..40;
+    while let Some(n) = it.next() {
+        for m in &mut it {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("n still is {}", n);
+    }
+
+    // This is fine, inner loop uses a new iterator.
+    let mut it = 1..40;
+    for n in it {
+        let mut it = 1..40;
+        for m in it {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+
+        // Weird binding shouldn't change anything.
+        let (mut it, _) = (1..40, 0);
+        for m in it {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+
+        // Used after the loop, needs &mut.
+        let mut it = 1..40;
+        for m in &mut it {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("next item {}", it.next().unwrap());
+
+        println!("n still is {}", n);
+    }
+}
+
+fn issue6231() {
+    // Closure in the outer loop, needs &mut
+    let mut it = 1..40;
+    let mut opt = Some(0);
+    while let Some(n) = opt.take().or_else(|| it.next()) {
+        for m in &mut it {
+            if n % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("n still is {}", n);
+    }
+}
+
+fn issue1924() {
+    struct S<T>(T);
+    impl<T: Iterator<Item = u32>> S<T> {
+        fn f(&mut self) -> Option<u32> {
+            // Used as a field.
+            for i in &mut self.0 {
+                if !(3..=7).contains(&i) {
+                    return Some(i);
+                }
+            }
+            None
+        }
+
+        fn f2(&mut self) -> Option<u32> {
+            // Don't lint, self borrowed inside the loop
+            while let Some(i) = self.0.next() {
+                if i == 1 {
+                    return self.f();
+                }
+            }
+            None
+        }
+    }
+    impl<T: Iterator<Item = u32>> S<(S<T>, Option<u32>)> {
+        fn f3(&mut self) -> Option<u32> {
+            // Don't lint, self borrowed inside the loop
+            while let Some(i) = self.0.0.0.next() {
+                if i == 1 {
+                    return self.0.0.f();
+                }
+            }
+            while let Some(i) = self.0.0.0.next() {
+                if i == 1 {
+                    return self.f3();
+                }
+            }
+            // This one is fine, a different field is borrowed
+            for i in &mut self.0.0.0 {
+                if i == 1 {
+                    return self.0.1.take();
+                } else {
+                    self.0.1 = Some(i);
+                }
+            }
+            None
+        }
+    }
+
+    struct S2<T>(T, u32);
+    impl<T: Iterator<Item = u32>> Iterator for S2<T> {
+        type Item = u32;
+        fn next(&mut self) -> Option<u32> {
+            self.0.next()
+        }
+    }
+
+    // Don't lint, field of the iterator is accessed in the loop
+    let mut it = S2(1..40, 0);
+    while let Some(n) = it.next() {
+        if n == it.1 {
+            break;
+        }
+    }
+
+    // Needs &mut, field of the iterator is accessed after the loop
+    let mut it = S2(1..40, 0);
+    for n in &mut it {
+        if n == 0 {
+            break;
+        }
+    }
+    println!("iterator field {}", it.1);
+}
+
 fn main() {
-    base();
-    refutable();
-    refutable2();
-    nested_loops();
-    issue1121();
-    issue2965();
-    issue3670();
-    issue1654();
+    let mut it = 0..20;
+    for _ in it {
+        println!("test");
+    }
 }
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
index 30e3b82a7cc..1717006a449 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
@@ -1,7 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::while_let_on_iterator)]
-#![allow(clippy::never_loop, unreachable_code, unused_mut)]
+#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)]
 
 fn base() {
     let mut iter = 1..20;
@@ -41,13 +41,6 @@ fn base() {
     // or this
     let mut iter = 1u32..20;
     while let Some(_) = iter.next() {
-        break;
-    }
-    println!("Remaining iter {:?}", iter);
-
-    // or this
-    let mut iter = 1u32..20;
-    while let Some(_) = iter.next() {
         iter = 1..20;
     }
 }
@@ -135,18 +128,6 @@ fn refutable2() {
 
 fn nested_loops() {
     let a = [42, 1337];
-    let mut y = a.iter();
-    loop {
-        // x is reused, so don't lint here
-        while let Some(_) = y.next() {}
-    }
-
-    let mut y = a.iter();
-    for _ in 0..2 {
-        while let Some(_) = y.next() {
-            // y is reused, don't lint
-        }
-    }
 
     loop {
         let mut y = a.iter();
@@ -167,10 +148,8 @@ fn issue1121() {
 }
 
 fn issue2965() {
-    // This should not cause an ICE and suggest:
-    //
-    // for _ in values.iter() {}
-    //
+    // This should not cause an ICE
+
     use std::collections::HashSet;
     let mut values = HashSet::new();
     values.insert(1);
@@ -205,13 +184,145 @@ fn issue1654() {
     }
 }
 
+fn issue6491() {
+    // Used in outer loop, needs &mut
+    let mut it = 1..40;
+    while let Some(n) = it.next() {
+        while let Some(m) = it.next() {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("n still is {}", n);
+    }
+
+    // This is fine, inner loop uses a new iterator.
+    let mut it = 1..40;
+    while let Some(n) = it.next() {
+        let mut it = 1..40;
+        while let Some(m) = it.next() {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+
+        // Weird binding shouldn't change anything.
+        let (mut it, _) = (1..40, 0);
+        while let Some(m) = it.next() {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+
+        // Used after the loop, needs &mut.
+        let mut it = 1..40;
+        while let Some(m) = it.next() {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("next item {}", it.next().unwrap());
+
+        println!("n still is {}", n);
+    }
+}
+
+fn issue6231() {
+    // Closure in the outer loop, needs &mut
+    let mut it = 1..40;
+    let mut opt = Some(0);
+    while let Some(n) = opt.take().or_else(|| it.next()) {
+        while let Some(m) = it.next() {
+            if n % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("n still is {}", n);
+    }
+}
+
+fn issue1924() {
+    struct S<T>(T);
+    impl<T: Iterator<Item = u32>> S<T> {
+        fn f(&mut self) -> Option<u32> {
+            // Used as a field.
+            while let Some(i) = self.0.next() {
+                if i < 3 || i > 7 {
+                    return Some(i);
+                }
+            }
+            None
+        }
+
+        fn f2(&mut self) -> Option<u32> {
+            // Don't lint, self borrowed inside the loop
+            while let Some(i) = self.0.next() {
+                if i == 1 {
+                    return self.f();
+                }
+            }
+            None
+        }
+    }
+    impl<T: Iterator<Item = u32>> S<(S<T>, Option<u32>)> {
+        fn f3(&mut self) -> Option<u32> {
+            // Don't lint, self borrowed inside the loop
+            while let Some(i) = self.0.0.0.next() {
+                if i == 1 {
+                    return self.0.0.f();
+                }
+            }
+            while let Some(i) = self.0.0.0.next() {
+                if i == 1 {
+                    return self.f3();
+                }
+            }
+            // This one is fine, a different field is borrowed
+            while let Some(i) = self.0.0.0.next() {
+                if i == 1 {
+                    return self.0.1.take();
+                } else {
+                    self.0.1 = Some(i);
+                }
+            }
+            None
+        }
+    }
+
+    struct S2<T>(T, u32);
+    impl<T: Iterator<Item = u32>> Iterator for S2<T> {
+        type Item = u32;
+        fn next(&mut self) -> Option<u32> {
+            self.0.next()
+        }
+    }
+
+    // Don't lint, field of the iterator is accessed in the loop
+    let mut it = S2(1..40, 0);
+    while let Some(n) = it.next() {
+        if n == it.1 {
+            break;
+        }
+    }
+
+    // Needs &mut, field of the iterator is accessed after the loop
+    let mut it = S2(1..40, 0);
+    while let Some(n) = it.next() {
+        if n == 0 {
+            break;
+        }
+    }
+    println!("iterator field {}", it.1);
+}
+
 fn main() {
-    base();
-    refutable();
-    refutable2();
-    nested_loops();
-    issue1121();
-    issue2965();
-    issue3670();
-    issue1654();
+    let mut it = 0..20;
+    while let Some(..) = it.next() {
+        println!("test");
+    }
 }
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
index 6554977c798..eff559bef7e 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
@@ -19,28 +19,96 @@ LL |     while let Some(_) = iter.next() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:101:9
+  --> $DIR/while_let_on_iterator.rs:94:9
    |
 LL |         while let Some([..]) = it.next() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:108:9
+  --> $DIR/while_let_on_iterator.rs:101:9
    |
 LL |         while let Some([_x]) = it.next() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:121:9
+  --> $DIR/while_let_on_iterator.rs:114:9
    |
 LL |         while let Some(x @ [_]) = it.next() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:153:9
+  --> $DIR/while_let_on_iterator.rs:134:9
    |
 LL |         while let Some(_) = y.next() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y`
 
-error: aborting due to 7 previous errors
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:191:9
+   |
+LL |         while let Some(m) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:202:5
+   |
+LL |     while let Some(n) = it.next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:204:9
+   |
+LL |         while let Some(m) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:213:9
+   |
+LL |         while let Some(m) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:222:9
+   |
+LL |         while let Some(m) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:239:9
+   |
+LL |         while let Some(m) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:254:13
+   |
+LL |             while let Some(i) = self.0.next() {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in &mut self.0`
+
+error: manual `!RangeInclusive::contains` implementation
+  --> $DIR/while_let_on_iterator.rs:255:20
+   |
+LL |                 if i < 3 || i > 7 {
+   |                    ^^^^^^^^^^^^^^ help: use: `!(3..=7).contains(&i)`
+   |
+   = note: `-D clippy::manual-range-contains` implied by `-D warnings`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:286:13
+   |
+LL |             while let Some(i) = self.0.0.0.next() {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in &mut self.0.0.0`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:315:5
+   |
+LL |     while let Some(n) = it.next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in &mut it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:325:5
+   |
+LL |     while let Some(..) = it.next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
+
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/write_with_newline.stderr b/src/tools/clippy/tests/ui/write_with_newline.stderr
index a14e86122ee..cecc2ea9406 100644
--- a/src/tools/clippy/tests/ui/write_with_newline.stderr
+++ b/src/tools/clippy/tests/ui/write_with_newline.stderr
@@ -51,8 +51,8 @@ LL |     write!(&mut v, "/n");
    |
 help: use `writeln!()` instead
    |
-LL |     writeln!(&mut v, );
-   |     ^^^^^^^         --
+LL |     writeln!(&mut v);
+   |     ^^^^^^^       --
 
 error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:36:5
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.rs b/src/tools/clippy/tests/ui/wrong_self_convention2.rs
index ae3a740d405..3a72174d03d 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention2.rs
+++ b/src/tools/clippy/tests/ui/wrong_self_convention2.rs
@@ -23,7 +23,7 @@ mod issue6983 {
     }
 
     struct FooNoCopy;
-    // trigger lint
+    // don't trigger
     impl ToU64 for FooNoCopy {
         fn to_u64(self) -> u64 {
             2
@@ -42,3 +42,30 @@ mod issue7032 {
         }
     }
 }
+
+mod issue7179 {
+    pub struct S(i32);
+
+    impl S {
+        // don't trigger (`s` is not `self`)
+        pub fn from_be(s: Self) -> Self {
+            S(i32::from_be(s.0))
+        }
+
+        // lint
+        pub fn from_be_self(self) -> Self {
+            S(i32::from_be(self.0))
+        }
+    }
+
+    trait T {
+        // don't trigger (`s` is not `self`)
+        fn from_be(s: Self) -> Self;
+        // lint
+        fn from_be_self(self) -> Self;
+    }
+
+    trait Foo: Sized {
+        fn as_byte_slice(slice: &[Self]) -> &[u8];
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
index 0ca1a390974..d2d74ce099e 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
+++ b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
@@ -1,11 +1,19 @@
-error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention2.rs:28:19
+error: methods called `from_*` usually take no `self`
+  --> $DIR/wrong_self_convention2.rs:56:29
    |
-LL |         fn to_u64(self) -> u64 {
-   |                   ^^^^
+LL |         pub fn from_be_self(self) -> Self {
+   |                             ^^^^
    |
    = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
    = help: consider choosing a less ambiguous name
 
-error: aborting due to previous error
+error: methods called `from_*` usually take no `self`
+  --> $DIR/wrong_self_convention2.rs:65:25
+   |
+LL |         fn from_be_self(self) -> Self;
+   |                         ^^^^
+   |
+   = help: consider choosing a less ambiguous name
+
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 7b42de0ec43..3f983884460 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -7,8 +7,8 @@ use std::path::Path;
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 1370;
-const ISSUES_ENTRY_LIMIT: usize = 2555;
+const ROOT_ENTRY_LIMIT: usize = 1371;
+const ISSUES_ENTRY_LIMIT: usize = 2558;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     let dirs = walkdir::WalkDir::new(&path.join("test/ui"))