about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/clippy/CHANGELOG.md3
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/vscode.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_used.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs83
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs207
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs5
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr3
-rw-r--r--src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr4
-rw-r--r--src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr39
-rw-r--r--src/tools/clippy/tests/ui/const_comparisons.rs93
-rw-r--r--src/tools/clippy/tests/ui/const_comparisons.stderr228
-rw-r--r--src/tools/clippy/tests/ui/expect.stderr6
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.fixed16
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.rs16
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.stderr18
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.stderr39
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.fixed17
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.rs17
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.stderr28
-rw-r--r--src/tools/clippy/tests/ui/mut_reference.rs15
-rw-r--r--src/tools/clippy/tests/ui/mut_reference.stderr8
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.fixed16
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.rs16
-rw-r--r--src/tools/clippy/tests/ui/ptr_as_ptr.stderr28
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed17
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs17
-rw-r--r--src/tools/clippy/tests/ui/question_mark.stderr6
-rw-r--r--src/tools/clippy/tests/ui/range_contains.fixed2
-rw-r--r--src/tools/clippy/tests/ui/range_contains.rs2
-rw-r--r--src/tools/clippy/tests/ui/range_contains.stderr42
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.fixed13
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.rs13
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.stderr16
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.rs9
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.stderr22
-rw-r--r--src/tools/clippy/tests/ui/redundant_type_annotations.rs20
-rw-r--r--src/tools/clippy/tests/ui/redundant_type_annotations.stderr28
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed2
-rw-r--r--src/tools/clippy/tests/ui/rename.rs2
-rw-r--r--src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr10
-rw-r--r--src/tools/clippy/tests/ui/unwrap.stderr9
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.rs11
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.stderr24
-rw-r--r--src/tools/compiletest/src/runtest.rs2
-rw-r--r--src/tools/miri/miri-script/src/commands.rs2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs2
-rw-r--r--src/tools/miri/src/concurrency/range_object_map.rs23
-rw-r--r--src/tools/miri/src/eval.rs2
-rw-r--r--src/tools/miri/src/helpers.rs19
-rw-r--r--src/tools/miri/src/lib.rs3
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs57
-rw-r--r--src/tools/miri/src/shims/mod.rs1
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs26
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd.rs7
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs1
-rw-r--r--src/tools/miri/src/shims/x86/sse.rs609
-rw-r--r--src/tools/miri/tests/pass/intrinsics-math.rs19
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-sse.rs1075
-rw-r--r--src/tools/opt-dist/src/bolt.rs7
-rw-r--r--src/tools/opt-dist/src/main.rs2
-rw-r--r--src/tools/opt-dist/src/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs2
-rw-r--r--src/tools/tidy/config/black.toml15
-rw-r--r--src/tools/tidy/config/requirements.in10
-rw-r--r--src/tools/tidy/config/requirements.txt117
-rw-r--r--src/tools/tidy/config/ruff.toml41
-rw-r--r--src/tools/tidy/src/deps.rs1
-rw-r--r--src/tools/tidy/src/ext_tool_checks.rs435
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs13
-rw-r--r--src/tools/tidy/src/pal.rs1
103 files changed, 3786 insertions, 454 deletions
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 2655d93599e..71671273c57 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -4890,12 +4890,14 @@ Released 2018-09-13
 [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
 [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
+[`ignored_unit_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns
 [`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params
 [`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
 [`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
 [`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
 [`implicit_saturating_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_add
 [`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
+[`impossible_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#impossible_comparisons
 [`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
 [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
 [`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
@@ -5190,6 +5192,7 @@ Released 2018-09-13
 [`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
 [`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
 [`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls
+[`redundant_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_comparisons
 [`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
 [`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
 [`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 43eaccdf5a3..fca750fafc7 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -41,7 +41,7 @@ fn main() {
                 matches.get_one::<String>("type").map(String::as_str),
                 matches.get_flag("msrv"),
             ) {
-                Ok(_) => update_lints::update(update_lints::UpdateMode::Change),
+                Ok(()) => update_lints::update(update_lints::UpdateMode::Change),
                 Err(e) => eprintln!("Unable to create lint: {e}"),
             }
         },
diff --git a/src/tools/clippy/clippy_dev/src/setup/vscode.rs b/src/tools/clippy/clippy_dev/src/setup/vscode.rs
index dbcdc9b59e5..204f4af2cf1 100644
--- a/src/tools/clippy/clippy_dev/src/setup/vscode.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/vscode.rs
@@ -47,7 +47,7 @@ fn check_install_precondition(force_override: bool) -> bool {
         }
     } else {
         match fs::create_dir(vs_dir_path) {
-            Ok(_) => {
+            Ok(()) => {
                 println!("info: created `{VSCODE_DIR}` directory for clippy");
             },
             Err(err) => {
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 15ffb00da88..181dbcf6e9a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -1,9 +1,7 @@
-use std::borrow::Cow;
-
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
-use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Mutability, TyKind};
 use rustc_lint::LateContext;
@@ -16,33 +14,41 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
         return;
     }
 
-    if_chain! {
-        if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind;
-        let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr));
-        if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind();
-        if let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind();
-        if matches!((from_mutbl, to_mutbl),
-            (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut));
+    if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind
+        && let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr))
+        && let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind()
+        && let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind()
+        && matches!((from_mutbl, to_mutbl),
+            (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut))
         // The `U` in `pointer::cast` have to be `Sized`
         // as explained here: https://github.com/rust-lang/rust/issues/60602.
-        if to_pointee_ty.is_sized(cx.tcx, cx.param_env);
-        then {
-            let mut applicability = Applicability::MachineApplicable;
-            let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut applicability);
-            let turbofish = match &cast_to_hir_ty.kind {
-                    TyKind::Infer => Cow::Borrowed(""),
-                    TyKind::Ptr(mut_ty) if matches!(mut_ty.ty.kind, TyKind::Infer) => Cow::Borrowed(""),
-                    _ => Cow::Owned(format!("::<{to_pointee_ty}>")),
-                };
-            span_lint_and_sugg(
-                cx,
-                PTR_AS_PTR,
-                expr.span,
-                "`as` casting between raw pointers without changing its mutability",
-                "try `pointer::cast`, a safer alternative",
-                format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
-                applicability,
-            );
-        }
+        && to_pointee_ty.is_sized(cx.tcx, cx.param_env)
+    {
+        let mut app = Applicability::MachineApplicable;
+        let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
+        let turbofish = match &cast_to_hir_ty.kind {
+            TyKind::Infer => String::new(),
+            TyKind::Ptr(mut_ty) => {
+                if matches!(mut_ty.ty.kind, TyKind::Infer) {
+                    String::new()
+                } else {
+                    format!(
+                        "::<{}>",
+                        snippet_with_applicability(cx, mut_ty.ty.span, "/* type */", &mut app)
+                    )
+                }
+            },
+            _ => return,
+        };
+
+        span_lint_and_sugg(
+            cx,
+            PTR_AS_PTR,
+            expr.span,
+            "`as` casting between raw pointers without changing its mutability",
+            "try `pointer::cast`, a safer alternative",
+            format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
+            app,
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index d4e0d286334..db114abfc86 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -203,6 +203,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::if_let_mutex::IF_LET_MUTEX_INFO,
     crate::if_not_else::IF_NOT_ELSE_INFO,
     crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO,
+    crate::ignored_unit_patterns::IGNORED_UNIT_PATTERNS_INFO,
     crate::implicit_hasher::IMPLICIT_HASHER_INFO,
     crate::implicit_return::IMPLICIT_RETURN_INFO,
     crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
@@ -517,6 +518,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::operators::FLOAT_CMP_CONST_INFO,
     crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO,
     crate::operators::IDENTITY_OP_INFO,
+    crate::operators::IMPOSSIBLE_COMPARISONS_INFO,
     crate::operators::INEFFECTIVE_BIT_MASK_INFO,
     crate::operators::INTEGER_DIVISION_INFO,
     crate::operators::MISREFACTORED_ASSIGN_OP_INFO,
@@ -525,6 +527,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::operators::NEEDLESS_BITWISE_BOOL_INFO,
     crate::operators::OP_REF_INFO,
     crate::operators::PTR_EQ_INFO,
+    crate::operators::REDUNDANT_COMPARISONS_INFO,
     crate::operators::SELF_ASSIGNMENT_INFO,
     crate::operators::VERBOSE_BIT_MASK_INFO,
     crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 9900dbdee6b..d3311792cfa 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -1,6 +1,4 @@
-use clippy_utils::diagnostics::{
-    span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
-};
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
 use clippy_utils::{is_lint_allowed, match_def_path, paths};
 use if_chain::if_chain;
@@ -8,15 +6,14 @@ use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
 use rustc_hir::{
-    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind,
-    UnsafeSource, Unsafety,
+    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource, Unsafety,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv,
-    ToPredicate, TraitPredicate, Ty, TyCtxt,
+    self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate, TraitPredicate, Ty,
+    TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
@@ -207,10 +204,13 @@ declare_lint_pass!(Derive => [
 
 impl<'tcx> LateLintPass<'tcx> for Derive {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), .. }) = item.kind {
+        if let ItemKind::Impl(Impl {
+            of_trait: Some(ref trait_ref),
+            ..
+        }) = item.kind
+        {
             let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
-            let is_automatically_derived =
-                cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
+            let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
 
             check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
             check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
@@ -327,12 +327,7 @@ fn check_ord_partial_ord<'tcx>(
 }
 
 /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
-fn check_copy_clone<'tcx>(
-    cx: &LateContext<'tcx>,
-    item: &Item<'_>,
-    trait_ref: &hir::TraitRef<'_>,
-    ty: Ty<'tcx>,
-) {
+fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
     let clone_id = match cx.tcx.lang_items().clone_trait() {
         Some(id) if trait_ref.trait_def_id() == Some(id) => id,
         _ => return,
@@ -350,9 +345,10 @@ fn check_copy_clone<'tcx>(
     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).instantiate_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()))
+                impls.iter().any(|&id| {
+                    matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _)
+                                        if ty_adt.did() == adt.did())
+                })
             });
             if !has_copy_impl {
                 return;
@@ -431,14 +427,7 @@ struct UnsafeVisitor<'a, 'tcx> {
 impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn visit_fn(
-        &mut self,
-        kind: FnKind<'tcx>,
-        decl: &'tcx FnDecl<'_>,
-        body_id: BodyId,
-        _: Span,
-        id: LocalDefId,
-    ) {
+    fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: LocalDefId) {
         if self.has_unsafe {
             return;
         }
@@ -474,12 +463,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
 }
 
 /// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
-fn check_partial_eq_without_eq<'tcx>(
-    cx: &LateContext<'tcx>,
-    span: Span,
-    trait_ref: &hir::TraitRef<'_>,
-    ty: Ty<'tcx>,
-) {
+fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
     if_chain! {
         if let ty::Adt(adt, args) = ty.kind();
         if cx.tcx.visibility(adt.did()).is_public();
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 2c4d93e33ba..e29ab634c97 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -716,10 +716,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
                 let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
                 let fallback_bundle =
                     rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
-                let emitter = EmitterWriter::new(
-                    Box::new(io::sink()),
-                    fallback_bundle,
-                );
+                let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
                 let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
                 let sess = ParseSess::with_span_handler(handler, sm);
 
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index ba7957b0dec..38066503c07 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -10,8 +10,8 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPat
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
-    self, Binder, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind,
-    GenericArgsRef, ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults,
+    self, Binder, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
+    ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
diff --git a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
new file mode 100644
index 00000000000..c635120b882
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
@@ -0,0 +1,52 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use hir::PatKind;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `_` in patterns of type `()`.
+    ///
+    /// ### Why is this bad?
+    /// Matching with `()` explicitly instead of `_` outlines
+    /// the fact that the pattern contains no data. Also it
+    /// would detect a type change that `_` would ignore.
+    ///
+    /// ### Example
+    /// ```rust
+    /// match std::fs::create_dir("tmp-work-dir") {
+    ///    Ok(_) => println!("Working directory created"),
+    ///    Err(s) => eprintln!("Could not create directory: {s}"),
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// match std::fs::create_dir("tmp-work-dir") {
+    ///    Ok(()) => println!("Working directory created"),
+    ///    Err(s) => eprintln!("Could not create directory: {s}"),
+    /// }
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub IGNORED_UNIT_PATTERNS,
+    pedantic,
+    "suggest replacing `_` by `()` in patterns where appropriate"
+}
+declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]);
+
+impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
+    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
+        if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).is_unit() {
+            span_lint_and_sugg(
+                cx,
+                IGNORED_UNIT_PATTERNS,
+                pat.span,
+                "matching over `()` is more explicit",
+                "use `()` instead of `_`",
+                String::from("()"),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 9d6096ccb2a..358004cf460 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -147,6 +147,7 @@ mod future_not_send;
 mod if_let_mutex;
 mod if_not_else;
 mod if_then_some_else_none;
+mod ignored_unit_patterns;
 mod implicit_hasher;
 mod implicit_return;
 mod implicit_saturating_add;
@@ -1093,6 +1094,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         })
     });
     store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals));
+    store.register_late_pass(|_| Box::new(ignored_unit_patterns::IgnoredUnitPatterns));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index dd77c69ef88..cc19ac55e5e 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -162,7 +162,9 @@ fn never_loop_expr<'tcx>(
         ExprKind::Binary(_, e1, e2)
         | ExprKind::Assign(e1, e2, _)
         | ExprKind::AssignOp(_, e1, e2)
-        | ExprKind::Index(e1, e2, _) => never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
+        | ExprKind::Index(e1, e2, _) => {
+            never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id)
+        },
         ExprKind::Loop(b, _, _, _) => {
             // Break can come from the inner loop so remove them.
             absorb_break(never_loop_block(cx, b, ignore_ids, main_loop_id))
diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
index f48a5d9d245..88db7ae6aec 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if !in_external_macro(cx.sess(), expr.span)
             && (
-                matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst) 
+                matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
                     || cx.tcx.features().active(sym!(const_float_classify))
             ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind
             && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
index 6383326aa38..29af4812351 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::path_to_local;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::visitors::{for_each_expr, is_local_used};
+use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, Guard, MatchSource, Node, Pat, PatKind};
@@ -160,6 +161,11 @@ fn emit_redundant_guards<'tcx>(
 }
 
 /// Checks if the given `Expr` can also be represented as a `Pat`.
+///
+/// All literals generally also work as patterns, however float literals are special.
+/// They are currently (as of 2023/08/08) still allowed in patterns, but that will become
+/// an error in the future, and rustc already actively warns against this (see rust#41620),
+/// so we don't consider those as usable within patterns for linting purposes.
 fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     for_each_expr(expr, |expr| {
         if match expr.kind {
@@ -177,8 +183,8 @@ fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
             ExprKind::AddrOf(..)
             | ExprKind::Array(..)
             | ExprKind::Tup(..)
-            | ExprKind::Struct(..)
-            | ExprKind::Lit(..) => true,
+            | ExprKind::Struct(..) => true,
+            ExprKind::Lit(lit) if !matches!(lit.node, LitKind::Float(..)) => true,
             _ => false,
         } {
             return ControlFlow::Continue(());
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
deleted file mode 100644
index 614610335a1..00000000000
--- a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_in_cfg_test, is_in_test_function};
-use rustc_hir as hir;
-use rustc_lint::LateContext;
-use rustc_span::sym;
-
-use super::EXPECT_USED;
-
-/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`.
-pub(super) fn check(
-    cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    recv: &hir::Expr<'_>,
-    is_err: bool,
-    allow_expect_in_tests: bool,
-) {
-    let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
-
-    let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
-        Some((EXPECT_USED, "an `Option`", "None", ""))
-    } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((EXPECT_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
-    } else {
-        None
-    };
-
-    let method = if is_err { "expect_err" } else { "expect" };
-
-    if allow_expect_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
-        return;
-    }
-
-    if let Some((lint, kind, none_value, none_prefix)) = mess {
-        span_lint_and_help(
-            cx,
-            lint,
-            expr.span,
-            &format!("used `{method}()` on {kind} value"),
-            None,
-            &format!("if this value is {none_prefix}`{none_value}`, it will panic"),
-        );
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
index 4aee22a4afc..fafc9709770 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -1,3 +1,4 @@
+use super::FILTER_MAP_BOOL_THEN;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::paths::BOOL_THEN;
 use clippy_utils::source::snippet_opt;
@@ -7,10 +8,9 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::Binder;
 use rustc_span::{sym, Span};
 
-use super::FILTER_MAP_BOOL_THEN;
-
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) {
     if !in_external_macro(cx.sess(), expr.span)
         && is_trait_method(cx, expr, sym::Iterator)
@@ -21,7 +21,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
         // `inputs` and `params` here as we need both the type and the span
         && let param_ty = closure.fn_decl.inputs[0]
         && let param = body.params[0]
-        && is_copy(cx, cx.typeck_results().node_type(param_ty.hir_id).peel_refs())
+        // Issue #11309
+        && let param_ty = cx.tcx.liberate_late_bound_regions(
+            closure.def_id.to_def_id(),
+            Binder::bind_with_vars(
+                cx.typeck_results().node_type(param_ty.hir_id),
+                cx.tcx.late_bound_vars(cx.tcx.hir().local_def_id_to_hir_id(closure.def_id)),
+            ),
+        )
+        && is_copy(cx, param_ty)
         && let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind
         && let ExprKind::Closure(then_closure) = then_arg.kind
         && let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value)
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index dd694ce7393..42756b27d01 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -17,7 +17,6 @@ mod collapsible_str_replace;
 mod drain_collect;
 mod err_expect;
 mod expect_fun_call;
-mod expect_used;
 mod extend_with_drain;
 mod filetype_is_file;
 mod filter_map;
@@ -105,7 +104,7 @@ mod unnecessary_lazy_eval;
 mod unnecessary_literal_unwrap;
 mod unnecessary_sort_by;
 mod unnecessary_to_owned;
-mod unwrap_used;
+mod unwrap_expect_used;
 mod useless_asref;
 mod utils;
 mod vec_resize_to_zero;
@@ -3881,6 +3880,13 @@ impl Methods {
                         unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
                     }
                 },
+                ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
+                    && let body = cx.tcx.hir().body(arg.body)
+                    && let [param] = body.params
+                    && let Some(("chars", recv, _, _, _)) = method_call(recv) =>
+                {
+                    string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
+                }
                 ("arg", [arg]) => {
                     suspicious_command_arg_space::check(cx, recv, arg, span);
                 }
@@ -3941,13 +3947,27 @@ impl Methods {
                     match method_call(recv) {
                         Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
                         Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
-                        _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
+                        _ => unwrap_expect_used::check(
+                            cx,
+                            expr,
+                            recv,
+                            false,
+                            self.allow_expect_in_tests,
+                            unwrap_expect_used::Variant::Expect,
+                        ),
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
                 ("expect_err", [_]) => {
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests);
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        true,
+                        self.allow_expect_in_tests,
+                        unwrap_expect_used::Variant::Expect,
+                    );
                 },
                 ("extend", [arg]) => {
                     string_extend_chars::check(cx, expr, recv, arg);
@@ -3999,20 +4019,9 @@ impl Methods {
                         unnecessary_join::check(cx, expr, recv, join_arg, span);
                     }
                 },
-                ("skip", [arg]) => {
-                    iter_skip_zero::check(cx, expr, arg);
-
-                    if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
-                        if let ("cloned", []) = (name2, args2) {
-                            iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
-                        }
-                    }
-                }
                 ("last", []) => {
-                    if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
-                        if let ("cloned", []) = (name2, args2) {
-                            iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
-                        }
+                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                        iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
                     }
                 },
                 ("lock", []) => {
@@ -4060,13 +4069,6 @@ impl Methods {
                         }
                     }
                 },
-                ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
-                    && let body = cx.tcx.hir().body(arg.body)
-                    && let [param] = body.params
-                    && let Some(("chars", recv, _, _, _)) = method_call(recv) =>
-                {
-                    string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
-                }
                 ("nth", [n_arg]) => match method_call(recv) {
                     Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
                     Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
@@ -4120,6 +4122,13 @@ impl Methods {
                         seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
                     }
                 },
+                ("skip", [arg]) => {
+                    iter_skip_zero::check(cx, expr, arg);
+
+                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                        iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
+                    }
+                }
                 ("sort", []) => {
                     stable_sort_primitive::check(cx, expr, recv);
                 },
@@ -4142,10 +4151,8 @@ impl Methods {
                 },
                 ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
                 ("take", [_arg]) => {
-                    if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
-                        if let ("cloned", []) = (name2, args2) {
-                            iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
-                        }
+                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                        iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
                     }
                 },
                 ("take", []) => needless_option_take::check(cx, expr, recv),
@@ -4180,11 +4187,25 @@ impl Methods {
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        false,
+                        self.allow_unwrap_in_tests,
+                        unwrap_expect_used::Variant::Unwrap,
+                    );
                 },
                 ("unwrap_err", []) => {
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
-                    unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests);
+                    unwrap_expect_used::check(
+                        cx,
+                        expr,
+                        recv,
+                        true,
+                        self.allow_unwrap_in_tests,
+                        unwrap_expect_used::Variant::Unwrap,
+                    );
                 },
                 ("unwrap_or", [u_arg]) => {
                     match method_call(recv) {
@@ -4214,6 +4235,9 @@ impl Methods {
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
+                ("write", []) => {
+                    readonly_write_lock::check(cx, expr, recv);
+                }
                 ("zip", [arg]) => {
                     if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
                         && name.ident.name == sym::iter
@@ -4221,9 +4245,6 @@ impl Methods {
                         range_zip_with_len::check(cx, expr, iter_recv, arg);
                     }
                 },
-                ("write", []) => {
-                    readonly_write_lock::check(cx, expr, recv);
-                }
                 _ => {},
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
new file mode 100644
index 00000000000..7bd16b473ce
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
@@ -0,0 +1,83 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::{is_never_like, is_type_diagnostic_item};
+use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
+use rustc_hir::Expr;
+use rustc_lint::{LateContext, Lint};
+use rustc_middle::ty;
+use rustc_span::sym;
+
+use super::{EXPECT_USED, UNWRAP_USED};
+
+#[derive(Clone, Copy, Eq, PartialEq)]
+pub(super) enum Variant {
+    Unwrap,
+    Expect,
+}
+
+impl Variant {
+    fn method_name(self, is_err: bool) -> &'static str {
+        match (self, is_err) {
+            (Variant::Unwrap, true) => "unwrap_err",
+            (Variant::Unwrap, false) => "unwrap",
+            (Variant::Expect, true) => "expect_err",
+            (Variant::Expect, false) => "expect",
+        }
+    }
+
+    fn lint(self) -> &'static Lint {
+        match self {
+            Variant::Unwrap => UNWRAP_USED,
+            Variant::Expect => EXPECT_USED,
+        }
+    }
+}
+
+/// Lint usage of `unwrap` or `unwrap_err` for `Result` and `unwrap()` for `Option` (and their
+/// `expect` counterparts).
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    recv: &Expr<'_>,
+    is_err: bool,
+    allow_unwrap_in_tests: bool,
+    variant: Variant,
+) {
+    let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+
+    let (kind, none_value, none_prefix) = if is_type_diagnostic_item(cx, ty, sym::Option) && !is_err {
+        ("an `Option`", "None", "")
+    } else if is_type_diagnostic_item(cx, ty, sym::Result)
+        && let ty::Adt(_, substs) = ty.kind()
+        && let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type()
+    {
+        if is_never_like(t_or_e_ty) {
+            return;
+        }
+
+        ("a `Result`", if is_err { "Ok" } else { "Err" }, "an ")
+    } else {
+        return;
+    };
+
+    let method_suffix = if is_err { "_err" } else { "" };
+
+    if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
+        return;
+    }
+
+    span_lint_and_then(
+        cx,
+        variant.lint(),
+        expr.span,
+        &format!("used `{}()` on {kind} value", variant.method_name(is_err)),
+        |diag| {
+            diag.note(format!("if this value is {none_prefix}`{none_value}`, it will panic"));
+
+            if variant == Variant::Unwrap && is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
+                diag.help(format!(
+                    "consider using `expect{method_suffix}()` to provide a better panic message"
+                ));
+            }
+        },
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
deleted file mode 100644
index 5e4c3daee64..00000000000
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
-use rustc_hir as hir;
-use rustc_lint::LateContext;
-use rustc_span::sym;
-
-use super::{EXPECT_USED, UNWRAP_USED};
-
-/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`.
-pub(super) fn check(
-    cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    recv: &hir::Expr<'_>,
-    is_err: bool,
-    allow_unwrap_in_tests: bool,
-) {
-    let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
-
-    let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
-        Some((UNWRAP_USED, "an `Option`", "None", ""))
-    } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((UNWRAP_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
-    } else {
-        None
-    };
-
-    let method_suffix = if is_err { "_err" } else { "" };
-
-    if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
-        return;
-    }
-
-    if let Some((lint, kind, none_value, none_prefix)) = mess {
-        let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
-            format!(
-                "if you don't want to handle the `{none_value}` case gracefully, consider \
-                using `expect{method_suffix}()` to provide a better panic message"
-            )
-        } else {
-            format!("if this value is {none_prefix}`{none_value}`, it will panic")
-        };
-
-        span_lint_and_help(
-            cx,
-            lint,
-            expr.span,
-            &format!("used `unwrap{method_suffix}()` on {kind} value"),
-            None,
-            &help,
-        );
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index a41d5a9ce8d..93f6025c71d 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -74,7 +74,6 @@ fn is_executable_or_proc_macro(cx: &LateContext<'_>) -> bool {
     use rustc_session::config::CrateType;
 
     cx.tcx
-        .sess
         .crate_types()
         .iter()
         .any(|t: &CrateType| matches!(t, CrateType::Executable | CrateType::ProcMacro))
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index 4b20aecad4a..e53e146ec5d 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -37,6 +37,11 @@ declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]);
 
 impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        if e.span.from_expansion() {
+            // Issue #11268
+            return;
+        }
+
         match e.kind {
             ExprKind::Call(fn_expr, arguments) => {
                 if let ExprKind::Path(ref path) = fn_expr.kind {
diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
new file mode 100644
index 00000000000..abe8df19543
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
@@ -0,0 +1,207 @@
+#![allow(clippy::match_same_arms)]
+
+use std::cmp::Ordering;
+
+use clippy_utils::consts::{constant, Constant};
+use if_chain::if_chain;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::ty::{Ty, TypeckResults};
+use rustc_span::source_map::{Span, Spanned};
+
+use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::source::snippet;
+use clippy_utils::SpanlessEq;
+
+use super::{IMPOSSIBLE_COMPARISONS, REDUNDANT_COMPARISONS};
+
+// Extract a comparison between a const and non-const
+// Flip yoda conditionals, turnings expressions like `42 < x` into `x > 42`
+fn comparison_to_const<'tcx>(
+    cx: &LateContext<'tcx>,
+    typeck: &TypeckResults<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+) -> Option<(CmpOp, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Constant<'tcx>, Ty<'tcx>)> {
+    if_chain! {
+        if let ExprKind::Binary(operator, left, right) = expr.kind;
+        if let Ok(cmp_op) = CmpOp::try_from(operator.node);
+        then {
+            match (constant(cx, typeck, left), constant(cx, typeck, right)) {
+                (Some(_), Some(_)) => None,
+                (_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))),
+                (Some(con), _) => Some((cmp_op.reverse(), right, left, con, typeck.expr_ty(left))),
+                _ => None,
+            }
+        } else {
+            None
+        }
+    }
+}
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    and_op: Spanned<BinOpKind>,
+    left_cond: &'tcx Expr<'tcx>,
+    right_cond: &'tcx Expr<'tcx>,
+    span: Span,
+) {
+    if_chain! {
+        // Ensure that the binary operator is &&
+        if and_op.node == BinOpKind::And;
+
+        // Check that both operands to '&&' are themselves a binary operation
+        // The `comparison_to_const` step also checks this, so this step is just an optimization
+        if let ExprKind::Binary(_, _, _) = left_cond.kind;
+        if let ExprKind::Binary(_, _, _) = right_cond.kind;
+
+        let typeck = cx.typeck_results();
+
+        // Check that both operands to '&&' compare a non-literal to a literal
+        if let Some((left_cmp_op, left_expr, left_const_expr, left_const, left_type)) =
+            comparison_to_const(cx, typeck, left_cond);
+        if let Some((right_cmp_op, right_expr, right_const_expr, right_const, right_type)) =
+            comparison_to_const(cx, typeck, right_cond);
+
+        if left_type == right_type;
+
+        // Check that the same expression is compared in both comparisons
+        if SpanlessEq::new(cx).eq_expr(left_expr, right_expr);
+
+        if !left_expr.can_have_side_effects();
+
+        // Compare the two constant expressions
+        if let Some(ordering) = Constant::partial_cmp(cx.tcx(), left_type, &left_const, &right_const);
+
+        // Rule out the `x >= 42 && x <= 42` corner case immediately
+        // Mostly to simplify the implementation, but it is also covered by `clippy::double_comparisons`
+        if !matches!(
+            (&left_cmp_op, &right_cmp_op, ordering),
+            (CmpOp::Le | CmpOp::Ge, CmpOp::Le | CmpOp::Ge, Ordering::Equal)
+        );
+
+        then {
+            if left_cmp_op.direction() == right_cmp_op.direction() {
+                let lhs_str = snippet(cx, left_cond.span, "<lhs>");
+                let rhs_str = snippet(cx, right_cond.span, "<rhs>");
+                // We already know that either side of `&&` has no effect,
+                // but emit a different error message depending on which side it is
+                if left_side_is_useless(left_cmp_op, ordering) {
+                    span_lint_and_note(
+                        cx,
+                        REDUNDANT_COMPARISONS,
+                        span,
+                        "left-hand side of `&&` operator has no effect",
+                        Some(left_cond.span.until(right_cond.span)),
+                        &format!("`if `{rhs_str}` evaluates to true, {lhs_str}` will always evaluate to true as well"),
+                    );
+                } else {
+                    span_lint_and_note(
+                        cx,
+                        REDUNDANT_COMPARISONS,
+                        span,
+                        "right-hand side of `&&` operator has no effect",
+                        Some(and_op.span.to(right_cond.span)),
+                        &format!("`if `{lhs_str}` evaluates to true, {rhs_str}` will always evaluate to true as well"),
+                    );
+                }
+                // We could autofix this error but choose not to,
+                // because code triggering this lint probably not behaving correctly in the first place
+            }
+            else if !comparison_is_possible(left_cmp_op.direction(), ordering) {
+                let expr_str = snippet(cx, left_expr.span, "..");
+                let lhs_str = snippet(cx, left_const_expr.span, "<lhs>");
+                let rhs_str = snippet(cx, right_const_expr.span, "<rhs>");
+                let note = match ordering {
+                    Ordering::Less => format!("since `{lhs_str}` < `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"),
+                    Ordering::Equal => format!("`{expr_str}` cannot simultaneously be greater than and less than `{lhs_str}`"),
+                    Ordering::Greater => format!("since `{lhs_str}` > `{rhs_str}`, the expression evaluates to false for any value of `{expr_str}`"),
+                };
+                span_lint_and_note(
+                    cx,
+                    IMPOSSIBLE_COMPARISONS,
+                    span,
+                    "boolean expression will never evaluate to 'true'",
+                    None,
+                    &note,
+                );
+            };
+        }
+    }
+}
+
+fn left_side_is_useless(left_cmp_op: CmpOp, ordering: Ordering) -> bool {
+    // Special-case for equal constants with an inclusive comparison
+    if ordering == Ordering::Equal {
+        match left_cmp_op {
+            CmpOp::Lt | CmpOp::Gt => false,
+            CmpOp::Le | CmpOp::Ge => true,
+        }
+    } else {
+        match (left_cmp_op.direction(), ordering) {
+            (CmpOpDirection::Lesser, Ordering::Less) => false,
+            (CmpOpDirection::Lesser, Ordering::Equal) => false,
+            (CmpOpDirection::Lesser, Ordering::Greater) => true,
+            (CmpOpDirection::Greater, Ordering::Less) => true,
+            (CmpOpDirection::Greater, Ordering::Equal) => false,
+            (CmpOpDirection::Greater, Ordering::Greater) => false,
+        }
+    }
+}
+
+fn comparison_is_possible(left_cmp_direction: CmpOpDirection, ordering: Ordering) -> bool {
+    match (left_cmp_direction, ordering) {
+        (CmpOpDirection::Lesser, Ordering::Less | Ordering::Equal) => false,
+        (CmpOpDirection::Lesser, Ordering::Greater) => true,
+        (CmpOpDirection::Greater, Ordering::Greater | Ordering::Equal) => false,
+        (CmpOpDirection::Greater, Ordering::Less) => true,
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy)]
+enum CmpOpDirection {
+    Lesser,
+    Greater,
+}
+
+#[derive(Clone, Copy)]
+enum CmpOp {
+    Lt,
+    Le,
+    Ge,
+    Gt,
+}
+
+impl CmpOp {
+    fn reverse(self) -> Self {
+        match self {
+            CmpOp::Lt => CmpOp::Gt,
+            CmpOp::Le => CmpOp::Ge,
+            CmpOp::Ge => CmpOp::Le,
+            CmpOp::Gt => CmpOp::Lt,
+        }
+    }
+
+    fn direction(self) -> CmpOpDirection {
+        match self {
+            CmpOp::Lt => CmpOpDirection::Lesser,
+            CmpOp::Le => CmpOpDirection::Lesser,
+            CmpOp::Ge => CmpOpDirection::Greater,
+            CmpOp::Gt => CmpOpDirection::Greater,
+        }
+    }
+}
+
+impl TryFrom<BinOpKind> for CmpOp {
+    type Error = ();
+
+    fn try_from(bin_op: BinOpKind) -> Result<Self, Self::Error> {
+        match bin_op {
+            BinOpKind::Lt => Ok(CmpOp::Lt),
+            BinOpKind::Le => Ok(CmpOp::Le),
+            BinOpKind::Ge => Ok(CmpOp::Ge),
+            BinOpKind::Gt => Ok(CmpOp::Gt),
+            _ => Err(()),
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index 2cf15adda01..4635e1164cd 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -2,6 +2,7 @@ mod absurd_extreme_comparisons;
 mod assign_op_pattern;
 mod bit_mask;
 mod cmp_owned;
+mod const_comparisons;
 mod double_comparison;
 mod duration_subsec;
 mod eq_op;
@@ -300,6 +301,45 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for double comparisons that can never succeed
+    ///
+    /// ### Why is this bad?
+    /// The whole expression can be replaced by `false`,
+    /// which is probably not the programmer's intention
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let status_code = 200;
+    /// if status_code <= 400 && status_code > 500 {}
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub IMPOSSIBLE_COMPARISONS,
+    correctness,
+    "double comparisons that will never evaluate to `true`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for ineffective double comparisons against constants.
+    ///
+    /// ### Why is this bad?
+    /// Only one of the comparisons has any effect on the result, the programmer
+    /// probably intended to flip one of the comparison operators, or compare a
+    /// different value entirely.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let status_code = 200;
+    /// if status_code <= 400 && status_code < 500 {}
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub REDUNDANT_COMPARISONS,
+    correctness,
+    "double comparisons where one of them can be removed"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for calculation of subsecond microseconds or milliseconds
     /// from other `Duration` methods.
     ///
@@ -742,6 +782,8 @@ impl_lint_pass!(Operators => [
     INEFFECTIVE_BIT_MASK,
     VERBOSE_BIT_MASK,
     DOUBLE_COMPARISONS,
+    IMPOSSIBLE_COMPARISONS,
+    REDUNDANT_COMPARISONS,
     DURATION_SUBSEC,
     EQ_OP,
     OP_REF,
@@ -786,6 +828,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
                 bit_mask::check(cx, e, op.node, lhs, rhs);
                 verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold);
                 double_comparison::check(cx, op.node, lhs, rhs, e.span);
+                const_comparisons::check(cx, op, lhs, rhs, e.span);
                 duration_subsec::check(cx, e, op.node, lhs, rhs);
                 float_equality_without_abs::check(cx, e, op.node, lhs, rhs);
                 integer_division::check(cx, e, op.node, lhs, rhs);
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 40da002f4ff..a7a7f4fd8fa 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
@@ -155,7 +155,7 @@ fn try_get_option_occurrence<'tcx>(
                 });
                 if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(local_id), .. })) = e.kind {
                     match some_captures.get(local_id)
-                        .or_else(|| (method_sugg == "map_or_else").then_some(()).and_then(|_| none_captures.get(local_id)))
+                        .or_else(|| (method_sugg == "map_or_else").then_some(()).and_then(|()| none_captures.get(local_id)))
                     {
                         Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
                         Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None,
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index f5502cffb66..734ca2914f5 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -1,11 +1,13 @@
 use crate::manual_let_else::{MatchLintBehaviour, MANUAL_LET_ELSE};
+use crate::question_mark_used::QUESTION_MARK_USED;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::Msrv;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{
-    eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_path_lang_item, is_res_lang_ctor,
-    pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
+    eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item,
+    is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks,
+    peel_blocks_with_stmt,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -299,13 +301,17 @@ fn is_try_block(cx: &LateContext<'_>, bl: &rustc_hir::Block<'_>) -> bool {
 
 impl<'tcx> LateLintPass<'tcx> for QuestionMark {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) {
+            return;
+        }
+
         if !in_constant(cx, stmt.hir_id) {
             check_let_some_else_return_none(cx, stmt);
         }
         self.check_manual_let_else(cx, stmt);
     }
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !in_constant(cx, expr.hir_id) {
+        if !in_constant(cx, expr.hir_id) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id) {
             self.check_is_none_or_err_and_early_return(cx, expr);
             self.check_if_let_some_or_err_and_early_return(cx, expr);
         }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 896bd79b20b..0c89c7ee47d 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::ty::needs_ordered_drop;
+use rustc_ast::Mutability;
 use rustc_hir::def::Res;
 use rustc_hir::{
     BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath,
@@ -9,6 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::{in_external_macro, is_from_async_await};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::Ident;
+use rustc_span::DesugaringKind;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -47,6 +49,7 @@ declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
 impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
         if_chain! {
+            if !local.span.is_desugaring(DesugaringKind::Async);
             // the pattern is a single by-value binding
             if let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind;
             // the binding is not type-ascribed
@@ -62,6 +65,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
             if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id);
             // the previous binding has the same mutability
             if find_binding(binding_pat, ident).unwrap().1 == mutability;
+            // the local does not change the effect of assignments to the binding. see #11290
+            if !affects_assignments(cx, mutability, binding_id, local.hir_id);
             // the local does not affect the code's drop behavior
             if !affects_drop_behavior(cx, binding_id, local.hir_id, expr);
             // the local is user-controlled
@@ -97,6 +102,14 @@ fn find_binding(pat: &Pat<'_>, name: Ident) -> Option<BindingAnnotation> {
     ret
 }
 
+/// Check if a rebinding of a local changes the effect of assignments to the binding.
+fn affects_assignments(cx: &LateContext<'_>, mutability: Mutability, bind: HirId, rebind: HirId) -> bool {
+    let hir = cx.tcx.hir();
+
+    // the binding is mutable and the rebinding is in a different scope than the original binding
+    mutability == Mutability::Mut && hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
+}
+
 /// Check if a rebinding of a local affects the code's drop behavior.
 fn affects_drop_behavior<'tcx>(
     cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
index 8e9234bba3c..3e963d79892 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
@@ -1,6 +1,8 @@
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::is_lint_allowed;
 use rustc_ast::LitKind;
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -45,8 +47,8 @@ fn is_same_type<'tcx>(cx: &LateContext<'tcx>, ty_resolved_path: hir::def::Res, f
         return primty.name() == func_return_type_sym;
     }
 
-    // type annotation is any other non generic type
-    if let hir::def::Res::Def(_, defid) = ty_resolved_path
+    // type annotation is a non generic type
+    if let hir::def::Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, defid) = ty_resolved_path
         && let Some(annotation_ty) = cx.tcx.type_of(defid).no_bound_vars()
     {
         return annotation_ty == func_return_type;
@@ -130,8 +132,9 @@ fn extract_primty(ty_kind: &hir::TyKind<'_>) -> Option<hir::PrimTy> {
 
 impl LateLintPass<'_> for RedundantTypeAnnotations {
     fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::Local<'tcx>) {
-        // type annotation part
-        if !local.span.from_expansion()
+        if !is_lint_allowed(cx, REDUNDANT_TYPE_ANNOTATIONS, local.hir_id)
+            // type annotation part
+            && !local.span.from_expansion()
             && let Some(ty) = &local.ty
 
             // initialization part
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 54a33eb2986..c9ab622ad25 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -20,18 +20,27 @@ declare_clippy_lint! {
     /// These structures are non-idiomatic and less efficient than simply using
     /// `vec![0; len]`.
     ///
+    /// Specifically, for `vec![0; len]`, the compiler can use a specialized type of allocation
+    /// that also zero-initializes the allocated memory in the same call
+    /// (see: [alloc_zeroed](https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html#method.alloc_zeroed)).
+    ///
+    /// Writing `Vec::new()` followed by `vec.resize(len, 0)` is suboptimal because,
+    /// while it does do the same number of allocations,
+    /// it involves two operations for allocating and initializing.
+    /// The `resize` call first allocates memory (since `Vec::new()` did not), and only *then* zero-initializes it.
+    ///
     /// ### Example
     /// ```rust
     /// # use core::iter::repeat;
     /// # let len = 4;
-    /// let mut vec1 = Vec::with_capacity(len);
+    /// let mut vec1 = Vec::new();
     /// vec1.resize(len, 0);
     ///
-    /// let mut vec1 = Vec::with_capacity(len);
-    /// vec1.resize(vec1.capacity(), 0);
-    ///
     /// let mut vec2 = Vec::with_capacity(len);
-    /// vec2.extend(repeat(0).take(len));
+    /// vec2.resize(len, 0);
+    ///
+    /// let mut vec3 = Vec::with_capacity(len);
+    /// vec3.extend(repeat(0).take(len));
     /// ```
     ///
     /// Use instead:
@@ -39,6 +48,7 @@ declare_clippy_lint! {
     /// # let len = 4;
     /// let mut vec1 = vec![0; len];
     /// let mut vec2 = vec![0; len];
+    /// let mut vec3 = vec![0; len];
     /// ```
     #[clippy::version = "1.32.0"]
     pub SLOW_VECTOR_INITIALIZATION,
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
index 6fa49afe0ec..8e156b8829b 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
@@ -1,5 +1,7 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::numeric_literal::NumericLiteral;
-use clippy_utils::source::snippet_with_context;
+use clippy_utils::source::snippet;
+use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -28,27 +30,29 @@ declare_lint_pass!(ConfusingXorAndPow => [SUSPICIOUS_XOR_USED_AS_POW]);
 
 impl LateLintPass<'_> for ConfusingXorAndPow {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if !in_external_macro(cx.sess(), expr.span) &&
-        	let ExprKind::Binary(op, left, right) = &expr.kind &&
-            op.node == BinOpKind::BitXor &&
-            left.span.ctxt() == right.span.ctxt() &&
-            let ExprKind::Lit(lit_left) = &left.kind &&
-            let ExprKind::Lit(lit_right) = &right.kind &&
-            let snip_left = snippet_with_context(cx, lit_left.span, lit_left.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
-            let snip_right = snippet_with_context(cx, lit_right.span, lit_right.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
-            let Some(left_val) = NumericLiteral::from_lit_kind(&snip_left.0, &lit_left.node) &&
-            let Some(right_val) = NumericLiteral::from_lit_kind(&snip_right.0, &lit_right.node) &&
-			left_val.is_decimal() &&
-			right_val.is_decimal() {
-					clippy_utils::diagnostics::span_lint_and_sugg(
-					        cx,
-					        SUSPICIOUS_XOR_USED_AS_POW,
-					        expr.span,
-					        "`^` is not the exponentiation operator",
-					        "did you mean to write",
-					        format!("{}.pow({})", left_val.format(), right_val.format()),
-					        Applicability::MaybeIncorrect,
-					    );
+        if !in_external_macro(cx.sess(), expr.span)
+            && let ExprKind::Binary(op, left, right) = &expr.kind
+            && op.node == BinOpKind::BitXor
+            && left.span.ctxt() == right.span.ctxt()
+            && let ExprKind::Lit(lit_left) = &left.kind
+            && let ExprKind::Lit(lit_right) = &right.kind
+            && matches!(lit_right.node, LitKind::Int(..) | LitKind::Float(..))
+            && matches!(lit_left.node, LitKind::Int(..) | LitKind::Float(..))
+            && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node).is_some_and(|x| x.is_decimal())
+            {
+                span_lint_and_sugg(
+                    cx,
+                    SUSPICIOUS_XOR_USED_AS_POW,
+                    expr.span,
+                    "`^` is not the exponentiation operator",
+                    "did you mean to write",
+                    format!(
+                        "{}.pow({})",
+                        lit_left.node,
+                        lit_right.node
+                    ),
+                    Applicability::MaybeIncorrect,
+                );
 		}
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index e4906944c8d..4ed985f54d0 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -34,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
         let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
         if_chain! {
             if mod_name.as_str() == "paths";
-            if let hir::ItemKind::Const(ty, body_id) = item.kind;
+            if let hir::ItemKind::Const(ty, _, body_id) = item.kind;
             let ty = hir_ty_to_ty(cx.tcx, ty);
             if let ty::Array(el_ty, _) = &ty.kind();
             if let ty::Ref(_, el_ty, _) = &el_ty.kind();
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 2d0d6f559ad..140cfa2194f 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -178,7 +178,9 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r),
         (Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re),
         (Continue(ll), Continue(rl)) => eq_label(ll, rl),
-        (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => eq_expr(l1, r1) && eq_expr(l2, r2),
+        (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => {
+            eq_expr(l1, r1) && eq_expr(l2, r2)
+        },
         (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
         (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
         (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm),
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index d38e3f1ae76..adeb673b6b9 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -329,7 +329,7 @@ pub struct ConstEvalLateContext<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
-    fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
+    pub fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
         Self {
             lcx,
             typeck_results,
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index f0a777c5b89..4c695cb9b6e 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -14,7 +14,7 @@ use rustc_middle::mir::{
     Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind,
     Terminator, TerminatorKind,
 };
-use rustc_middle::traits::{ImplSource, ObligationCause, BuiltinImplSource};
+use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause};
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt};
 use rustc_semver::RustcVersion;
@@ -425,5 +425,5 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
         ocx.select_all_or_error().is_empty()
     }
 
-    !ty.needs_drop(tcx, ConstCx::new(tcx, body).param_env)    
+    !ty.needs_drop(tcx, ConstCx::new(tcx, body).param_env)
 }
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index a43a81bc63a..ee5a49a2073 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -1010,7 +1010,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
                             projections_handled = true;
                         },
                         // note: unable to trigger `Subslice` kind in tests
-                        ProjectionKind::Subslice => (),
+                        ProjectionKind::Subslice |
                         // Doesn't have surface syntax. Only occurs in patterns.
                         ProjectionKind::OpaqueCast => (),
                         ProjectionKind::Deref => {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 71766480535..a05f682aa8c 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -1093,6 +1093,11 @@ fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[Generi
     }
 }
 
+/// Returns whether `ty` is never-like; i.e., `!` (never) or an enum with zero variants.
+pub fn is_never_like(ty: Ty<'_>) -> bool {
+    ty.is_never() || (ty.is_enum() && ty.ty_adt_def().is_some_and(|def| def.variants().is_empty()))
+}
+
 /// Makes the projection type for the named associated type in the given impl or trait impl.
 ///
 /// This function is for associated types which are "known" to exist, and as such, will only return
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 833608faff0..8b3f819f0cd 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-07-28"
+channel = "nightly-2023-08-10"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index 31df0ebd9fd..d8b158816c9 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -1,4 +1,5 @@
-thread '<unnamed>' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs
+thread '<unnamed>' panicked at clippy_lints/src/utils/internal_lints/produce_ice.rs:
+Would you like some help with that?
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 error: the compiler unexpectedly panicked. this is a bug.
diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
index 9eef0e1bfaa..815d009350f 100644
--- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
@@ -4,7 +4,7 @@ error: used `expect()` on an `Option` value
 LL |     let _ = opt.expect("");
    |             ^^^^^^^^^^^^^^
    |
-   = help: if this value is `None`, it will panic
+   = note: if this value is `None`, it will panic
    = note: `-D clippy::expect-used` implied by `-D warnings`
 
 error: used `expect()` on a `Result` value
@@ -13,7 +13,7 @@ error: used `expect()` on a `Result` value
 LL |     let _ = res.expect("");
    |             ^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Err`, it will panic
+   = note: if this value is an `Err`, it will panic
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
index 4c9bdfa9dba..10219beaf97 100644
--- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr
@@ -12,7 +12,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = boxed_slice.get(1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
@@ -27,7 +28,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_slice.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:40:17
@@ -41,7 +43,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_vec.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:41:17
@@ -55,7 +58,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_vecdeque.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:42:17
@@ -69,7 +73,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_hashmap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:43:17
@@ -83,7 +88,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_btreemap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:47:21
@@ -97,7 +103,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:52:9
@@ -111,7 +118,8 @@ error: used `unwrap()` on an `Option` value
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:53:9
@@ -125,7 +133,8 @@ error: used `unwrap()` on an `Option` value
 LL |         *some_slice.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:54:9
@@ -139,7 +148,8 @@ error: used `unwrap()` on an `Option` value
 LL |         *some_vec.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:55:9
@@ -153,7 +163,8 @@ error: used `unwrap()` on an `Option` value
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:67:17
@@ -167,7 +178,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:68:17
@@ -181,7 +193,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
   --> $DIR/unwrap_used.rs:75:13
diff --git a/src/tools/clippy/tests/ui/const_comparisons.rs b/src/tools/clippy/tests/ui/const_comparisons.rs
new file mode 100644
index 00000000000..8e265c9141c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/const_comparisons.rs
@@ -0,0 +1,93 @@
+#![allow(unused)]
+#![warn(clippy::impossible_comparisons)]
+#![warn(clippy::redundant_comparisons)]
+#![allow(clippy::no_effect)]
+#![allow(clippy::short_circuit_statement)]
+#![allow(clippy::manual_range_contains)]
+
+const STATUS_BAD_REQUEST: u16 = 400;
+const STATUS_SERVER_ERROR: u16 = 500;
+
+struct Status {
+    code: u16,
+}
+
+impl PartialEq<u16> for Status {
+    fn eq(&self, other: &u16) -> bool {
+        self.code == *other
+    }
+}
+
+impl PartialOrd<u16> for Status {
+    fn partial_cmp(&self, other: &u16) -> Option<std::cmp::Ordering> {
+        self.code.partial_cmp(other)
+    }
+}
+
+impl PartialEq<Status> for u16 {
+    fn eq(&self, other: &Status) -> bool {
+        *self == other.code
+    }
+}
+
+impl PartialOrd<Status> for u16 {
+    fn partial_cmp(&self, other: &Status) -> Option<std::cmp::Ordering> {
+        self.partial_cmp(&other.code)
+    }
+}
+
+fn main() {
+    let status_code = 500; // Value doesn't matter for the lint
+    let status = Status { code: status_code };
+
+    status_code >= 400 && status_code < 500; // Correct
+    status_code <= 400 && status_code > 500;
+    status_code > 500 && status_code < 400;
+    status_code < 500 && status_code > 500;
+
+    // More complex expressions
+    status_code < { 400 } && status_code > { 500 };
+    status_code < STATUS_BAD_REQUEST && status_code > STATUS_SERVER_ERROR;
+    status_code <= u16::MIN + 1 && status_code > STATUS_SERVER_ERROR;
+    status_code < STATUS_SERVER_ERROR && status_code > STATUS_SERVER_ERROR;
+
+    // Comparing two different types, via the `impl PartialOrd<u16> for Status`
+    status < { 400 } && status > { 500 };
+    status < STATUS_BAD_REQUEST && status > STATUS_SERVER_ERROR;
+    status <= u16::MIN + 1 && status > STATUS_SERVER_ERROR;
+    status < STATUS_SERVER_ERROR && status > STATUS_SERVER_ERROR;
+
+    // Yoda conditions
+    500 <= status_code && 600 > status_code; // Correct
+    500 <= status_code && status_code <= 600; // Correct
+    500 >= status_code && 600 < status_code; // Incorrect
+    500 >= status_code && status_code > 600; // Incorrect
+
+    // Yoda conditions, comparing two different types
+    500 <= status && 600 > status; // Correct
+    500 <= status && status <= 600; // Correct
+    500 >= status && 600 < status; // Incorrect
+    500 >= status && status > 600; // Incorrect
+
+    // Expressions where one of the sides has no effect
+    status_code < 200 && status_code <= 299;
+    status_code > 200 && status_code >= 299;
+
+    status_code >= 500 && status_code > 500; // Useless left
+    status_code > 500 && status_code >= 500; // Useless right
+    status_code <= 500 && status_code < 500; // Useless left
+    status_code < 500 && status_code <= 500; // Useless right
+
+    // Other types
+    let name = "Steve";
+    name < "Jennifer" && name > "Shannon";
+
+    let numbers = [1, 2];
+    numbers < [3, 4] && numbers > [5, 6];
+
+    let letter = 'a';
+    letter < 'b' && letter > 'c';
+
+    let area = 42.0;
+    area < std::f32::consts::E && area > std::f32::consts::PI;
+}
diff --git a/src/tools/clippy/tests/ui/const_comparisons.stderr b/src/tools/clippy/tests/ui/const_comparisons.stderr
new file mode 100644
index 00000000000..90e6db64762
--- /dev/null
+++ b/src/tools/clippy/tests/ui/const_comparisons.stderr
@@ -0,0 +1,228 @@
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:44:5
+   |
+LL |     status_code <= 400 && status_code > 500;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `400` < `500`, the expression evaluates to false for any value of `status_code`
+   = note: `-D clippy::impossible-comparisons` implied by `-D warnings`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:45:5
+   |
+LL |     status_code > 500 && status_code < 400;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `500` > `400`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:46:5
+   |
+LL |     status_code < 500 && status_code > 500;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `status_code` cannot simultaneously be greater than and less than `500`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:49:5
+   |
+LL |     status_code < { 400 } && status_code > { 500 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:50:5
+   |
+LL |     status_code < STATUS_BAD_REQUEST && status_code > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:51:5
+   |
+LL |     status_code <= u16::MIN + 1 && status_code > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:52:5
+   |
+LL |     status_code < STATUS_SERVER_ERROR && status_code > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `status_code` cannot simultaneously be greater than and less than `STATUS_SERVER_ERROR`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:55:5
+   |
+LL |     status < { 400 } && status > { 500 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:56:5
+   |
+LL |     status < STATUS_BAD_REQUEST && status > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:57:5
+   |
+LL |     status <= u16::MIN + 1 && status > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:58:5
+   |
+LL |     status < STATUS_SERVER_ERROR && status > STATUS_SERVER_ERROR;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `status` cannot simultaneously be greater than and less than `STATUS_SERVER_ERROR`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:63:5
+   |
+LL |     500 >= status_code && 600 < status_code; // Incorrect
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `500` < `600`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:64:5
+   |
+LL |     500 >= status_code && status_code > 600; // Incorrect
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `500` < `600`, the expression evaluates to false for any value of `status_code`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:69:5
+   |
+LL |     500 >= status && 600 < status; // Incorrect
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `500` < `600`, the expression evaluates to false for any value of `status`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:70:5
+   |
+LL |     500 >= status && status > 600; // Incorrect
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `500` < `600`, the expression evaluates to false for any value of `status`
+
+error: right-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:73:5
+   |
+LL |     status_code < 200 && status_code <= 299;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code < 200` evaluates to true, status_code <= 299` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:73:23
+   |
+LL |     status_code < 200 && status_code <= 299;
+   |                       ^^^^^^^^^^^^^^^^^^^^^
+   = note: `-D clippy::redundant-comparisons` implied by `-D warnings`
+
+error: left-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:74:5
+   |
+LL |     status_code > 200 && status_code >= 299;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code >= 299` evaluates to true, status_code > 200` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:74:5
+   |
+LL |     status_code > 200 && status_code >= 299;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: left-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:76:5
+   |
+LL |     status_code >= 500 && status_code > 500; // Useless left
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code > 500` evaluates to true, status_code >= 500` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:76:5
+   |
+LL |     status_code >= 500 && status_code > 500; // Useless left
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: right-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:77:5
+   |
+LL |     status_code > 500 && status_code >= 500; // Useless right
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code > 500` evaluates to true, status_code >= 500` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:77:23
+   |
+LL |     status_code > 500 && status_code >= 500; // Useless right
+   |                       ^^^^^^^^^^^^^^^^^^^^^
+
+error: left-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:78:5
+   |
+LL |     status_code <= 500 && status_code < 500; // Useless left
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code < 500` evaluates to true, status_code <= 500` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:78:5
+   |
+LL |     status_code <= 500 && status_code < 500; // Useless left
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: right-hand side of `&&` operator has no effect
+  --> $DIR/const_comparisons.rs:79:5
+   |
+LL |     status_code < 500 && status_code <= 500; // Useless right
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: `if `status_code < 500` evaluates to true, status_code <= 500` will always evaluate to true as well
+  --> $DIR/const_comparisons.rs:79:23
+   |
+LL |     status_code < 500 && status_code <= 500; // Useless right
+   |                       ^^^^^^^^^^^^^^^^^^^^^
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:83:5
+   |
+LL |     name < "Jennifer" && name > "Shannon";
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `"Jennifer"` < `"Shannon"`, the expression evaluates to false for any value of `name`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:86:5
+   |
+LL |     numbers < [3, 4] && numbers > [5, 6];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `[3, 4]` < `[5, 6]`, the expression evaluates to false for any value of `numbers`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:89:5
+   |
+LL |     letter < 'b' && letter > 'c';
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `'b'` < `'c'`, the expression evaluates to false for any value of `letter`
+
+error: boolean expression will never evaluate to 'true'
+  --> $DIR/const_comparisons.rs:92:5
+   |
+LL |     area < std::f32::consts::E && area > std::f32::consts::PI;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: since `std::f32::consts::E` < `std::f32::consts::PI`, the expression evaluates to false for any value of `area`
+
+error: aborting due to 25 previous errors
+
diff --git a/src/tools/clippy/tests/ui/expect.stderr b/src/tools/clippy/tests/ui/expect.stderr
index be340340d47..f787fa973a3 100644
--- a/src/tools/clippy/tests/ui/expect.stderr
+++ b/src/tools/clippy/tests/ui/expect.stderr
@@ -4,7 +4,7 @@ error: used `expect()` on an `Option` value
 LL |     let _ = opt.expect("");
    |             ^^^^^^^^^^^^^^
    |
-   = help: if this value is `None`, it will panic
+   = note: if this value is `None`, it will panic
    = note: `-D clippy::expect-used` implied by `-D warnings`
 
 error: used `expect()` on a `Result` value
@@ -13,7 +13,7 @@ error: used `expect()` on a `Result` value
 LL |     let _ = res.expect("");
    |             ^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Err`, it will panic
+   = note: if this value is an `Err`, it will panic
 
 error: used `expect_err()` on a `Result` value
   --> $DIR/expect.rs:12:13
@@ -21,7 +21,7 @@ error: used `expect_err()` on a `Result` value
 LL |     let _ = res.expect_err("");
    |             ^^^^^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Ok`, it will panic
+   = note: if this value is an `Ok`, it will panic
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.fixed b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
index 3e72fee4b07..e5c9f783f6b 100644
--- a/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
@@ -4,6 +4,7 @@
     clippy::clone_on_copy,
     clippy::map_identity,
     clippy::unnecessary_lazy_evaluations,
+    clippy::unnecessary_filter_map,
     unused
 )]
 #![warn(clippy::filter_map_bool_then)]
@@ -29,9 +30,18 @@ fn main() {
         .copied()
         .filter(|&i| i != 1000)
         .filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1);
+    // Despite this is non-copy, `is_copy` still returns true (at least now) because it's `&NonCopy`,
+    // and any `&` is `Copy`. So since we can dereference it in `filter` (since it's then `&&NonCopy`),
+    // we can lint this and still get the same input type.
+    // See: <https://doc.rust-lang.org/std/primitive.reference.html#trait-implementations-1>
+    let v = vec![NonCopy, NonCopy];
+    v.clone().iter().filter(|&i| (i == &NonCopy)).map(|i| i);
     // Do not lint
     let v = vec![NonCopy, NonCopy];
-    v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i));
+    v.clone().into_iter().filter_map(|i| (i == NonCopy).then(|| i));
+    // `&mut` is `!Copy`.
+    let v = vec![NonCopy, NonCopy];
+    v.clone().iter_mut().filter_map(|i| (i == &mut NonCopy).then(|| i));
     external! {
         let v = vec![1, 2, 3, 4, 5, 6];
         v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
@@ -42,3 +52,7 @@ fn main() {
         v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
     }
 }
+
+fn issue11309<'a>(iter: impl Iterator<Item = (&'a str, &'a str)>) -> Vec<&'a str> {
+    iter.filter_map(|(_, s): (&str, _)| Some(s)).collect()
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.rs b/src/tools/clippy/tests/ui/filter_map_bool_then.rs
index 38a04e57de4..7c9b99df78c 100644
--- a/src/tools/clippy/tests/ui/filter_map_bool_then.rs
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.rs
@@ -4,6 +4,7 @@
     clippy::clone_on_copy,
     clippy::map_identity,
     clippy::unnecessary_lazy_evaluations,
+    clippy::unnecessary_filter_map,
     unused
 )]
 #![warn(clippy::filter_map_bool_then)]
@@ -29,9 +30,18 @@ fn main() {
         .copied()
         .filter(|&i| i != 1000)
         .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1));
-    // Do not lint
+    // Despite this is non-copy, `is_copy` still returns true (at least now) because it's `&NonCopy`,
+    // and any `&` is `Copy`. So since we can dereference it in `filter` (since it's then `&&NonCopy`),
+    // we can lint this and still get the same input type.
+    // See: <https://doc.rust-lang.org/std/primitive.reference.html#trait-implementations-1>
     let v = vec![NonCopy, NonCopy];
     v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i));
+    // Do not lint
+    let v = vec![NonCopy, NonCopy];
+    v.clone().into_iter().filter_map(|i| (i == NonCopy).then(|| i));
+    // `&mut` is `!Copy`.
+    let v = vec![NonCopy, NonCopy];
+    v.clone().iter_mut().filter_map(|i| (i == &mut NonCopy).then(|| i));
     external! {
         let v = vec![1, 2, 3, 4, 5, 6];
         v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
@@ -42,3 +52,7 @@ fn main() {
         v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
     }
 }
+
+fn issue11309<'a>(iter: impl Iterator<Item = (&'a str, &'a str)>) -> Vec<&'a str> {
+    iter.filter_map(|(_, s): (&str, _)| Some(s)).collect()
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
index b411cd83dfd..fffa5252e5f 100644
--- a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
@@ -1,5 +1,5 @@
 error: usage of `bool::then` in `filter_map`
-  --> $DIR/filter_map_bool_then.rs:19:22
+  --> $DIR/filter_map_bool_then.rs:20:22
    |
 LL |     v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
@@ -7,28 +7,34 @@ LL |     v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
    = note: `-D clippy::filter-map-bool-then` implied by `-D warnings`
 
 error: usage of `bool::then` in `filter_map`
-  --> $DIR/filter_map_bool_then.rs:20:27
+  --> $DIR/filter_map_bool_then.rs:21:27
    |
 LL |     v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
 
 error: usage of `bool::then` in `filter_map`
-  --> $DIR/filter_map_bool_then.rs:23:10
+  --> $DIR/filter_map_bool_then.rs:24:10
    |
 LL |         .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) });
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
 
 error: usage of `bool::then` in `filter_map`
-  --> $DIR/filter_map_bool_then.rs:27:10
+  --> $DIR/filter_map_bool_then.rs:28:10
    |
 LL |         .filter_map(|i| (i % 2 == 0).then(|| i + 1));
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
 
 error: usage of `bool::then` in `filter_map`
-  --> $DIR/filter_map_bool_then.rs:31:10
+  --> $DIR/filter_map_bool_then.rs:32:10
    |
 LL |         .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1));
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1)`
 
-error: aborting due to 5 previous errors
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:38:22
+   |
+LL |     v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i == &NonCopy)).map(|i| i)`
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr
index c567ed319b5..19dc9071fe7 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/get_unwrap.stderr
@@ -16,7 +16,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = boxed_slice.get(1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
@@ -31,7 +32,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_slice.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:40:17
@@ -45,7 +47,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_vec.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:41:17
@@ -59,7 +62,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_vecdeque.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:42:17
@@ -73,7 +77,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_hashmap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:43:17
@@ -87,7 +92,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_btreemap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:47:21
@@ -101,7 +107,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:52:9
@@ -115,7 +122,8 @@ error: used `unwrap()` on an `Option` value
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:53:9
@@ -129,7 +137,8 @@ error: used `unwrap()` on an `Option` value
 LL |         *some_slice.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:54:9
@@ -143,7 +152,8 @@ error: used `unwrap()` on an `Option` value
 LL |         *some_vec.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:55:9
@@ -157,7 +167,8 @@ error: used `unwrap()` on an `Option` value
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:67:17
@@ -171,7 +182,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:68:17
@@ -185,7 +197,8 @@ error: used `unwrap()` on an `Option` value
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
   --> $DIR/get_unwrap.rs:78:24
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
new file mode 100644
index 00000000000..492219fe447
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
@@ -0,0 +1,17 @@
+//@run-rustfix
+
+#![warn(clippy::ignored_unit_patterns)]
+#![allow(clippy::redundant_pattern_matching, clippy::single_match)]
+
+fn foo() -> Result<(), ()> {
+    unimplemented!()
+}
+
+fn main() {
+    match foo() {
+        Ok(()) => {},
+        Err(()) => {},
+    }
+    if let Ok(()) = foo() {}
+    let _ = foo().map_err(|()| todo!());
+}
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
new file mode 100644
index 00000000000..90af36f8e5e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
@@ -0,0 +1,17 @@
+//@run-rustfix
+
+#![warn(clippy::ignored_unit_patterns)]
+#![allow(clippy::redundant_pattern_matching, clippy::single_match)]
+
+fn foo() -> Result<(), ()> {
+    unimplemented!()
+}
+
+fn main() {
+    match foo() {
+        Ok(_) => {},
+        Err(_) => {},
+    }
+    if let Ok(_) = foo() {}
+    let _ = foo().map_err(|_| todo!());
+}
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
new file mode 100644
index 00000000000..8feea3cc2a8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
@@ -0,0 +1,28 @@
+error: matching over `()` is more explicit
+  --> $DIR/ignored_unit_patterns.rs:12:12
+   |
+LL |         Ok(_) => {},
+   |            ^ help: use `()` instead of `_`: `()`
+   |
+   = note: `-D clippy::ignored-unit-patterns` implied by `-D warnings`
+
+error: matching over `()` is more explicit
+  --> $DIR/ignored_unit_patterns.rs:13:13
+   |
+LL |         Err(_) => {},
+   |             ^ help: use `()` instead of `_`: `()`
+
+error: matching over `()` is more explicit
+  --> $DIR/ignored_unit_patterns.rs:15:15
+   |
+LL |     if let Ok(_) = foo() {}
+   |               ^ help: use `()` instead of `_`: `()`
+
+error: matching over `()` is more explicit
+  --> $DIR/ignored_unit_patterns.rs:16:28
+   |
+LL |     let _ = foo().map_err(|_| todo!());
+   |                            ^ help: use `()` instead of `_`: `()`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/mut_reference.rs b/src/tools/clippy/tests/ui/mut_reference.rs
index 73906121c40..00661c51a78 100644
--- a/src/tools/clippy/tests/ui/mut_reference.rs
+++ b/src/tools/clippy/tests/ui/mut_reference.rs
@@ -1,8 +1,21 @@
-#![allow(unused_variables)]
+#![allow(unused_variables, dead_code)]
 
 fn takes_an_immutable_reference(a: &i32) {}
 fn takes_a_mutable_reference(a: &mut i32) {}
 
+mod issue11268 {
+    macro_rules! x {
+        ($f:expr) => {
+            $f(&mut 1);
+        };
+    }
+
+    fn f() {
+        x!(super::takes_an_immutable_reference);
+        x!(super::takes_a_mutable_reference);
+    }
+}
+
 struct MyStruct;
 
 impl MyStruct {
diff --git a/src/tools/clippy/tests/ui/mut_reference.stderr b/src/tools/clippy/tests/ui/mut_reference.stderr
index 1fdfbf9227e..d8a71d26461 100644
--- a/src/tools/clippy/tests/ui/mut_reference.stderr
+++ b/src/tools/clippy/tests/ui/mut_reference.stderr
@@ -1,5 +1,5 @@
 error: the function `takes_an_immutable_reference` doesn't need a mutable reference
-  --> $DIR/mut_reference.rs:17:34
+  --> $DIR/mut_reference.rs:30:34
    |
 LL |     takes_an_immutable_reference(&mut 42);
    |                                  ^^^^^^^
@@ -7,19 +7,19 @@ LL |     takes_an_immutable_reference(&mut 42);
    = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings`
 
 error: the function `as_ptr` doesn't need a mutable reference
-  --> $DIR/mut_reference.rs:19:12
+  --> $DIR/mut_reference.rs:32:12
    |
 LL |     as_ptr(&mut 42);
    |            ^^^^^^^
 
 error: the method `takes_an_immutable_reference` doesn't need a mutable reference
-  --> $DIR/mut_reference.rs:23:44
+  --> $DIR/mut_reference.rs:36:44
    |
 LL |     my_struct.takes_an_immutable_reference(&mut 42);
    |                                            ^^^^^^^
 
 error: this argument is a mutable reference, but not used mutably
-  --> $DIR/mut_reference.rs:11:44
+  --> $DIR/mut_reference.rs:24:44
    |
 LL |     fn takes_a_mutable_reference(&self, a: &mut i32) {}
    |                                            ^^^^^^^^ help: consider changing to: `&i32`
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
index 26a64c861cf..84babb97416 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed
@@ -3,8 +3,22 @@
 
 #![warn(clippy::ptr_as_ptr)]
 
+#[macro_use]
 extern crate proc_macros;
-use proc_macros::{external, inline_macros};
+
+mod issue_11278_a {
+    #[derive(Debug)]
+    pub struct T<D: std::fmt::Debug + ?Sized> {
+        pub p: D,
+    }
+}
+
+mod issue_11278_b {
+    pub fn f(o: &mut super::issue_11278_a::T<dyn std::fmt::Debug>) -> super::issue_11278_a::T<String> {
+        // Retain `super`
+        *unsafe { Box::from_raw(Box::into_raw(Box::new(o)).cast::<super::issue_11278_a::T<String>>()) }
+    }
+}
 
 #[inline_macros]
 fn main() {
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
index ea40d494733..34fd76428b2 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs
@@ -3,8 +3,22 @@
 
 #![warn(clippy::ptr_as_ptr)]
 
+#[macro_use]
 extern crate proc_macros;
-use proc_macros::{external, inline_macros};
+
+mod issue_11278_a {
+    #[derive(Debug)]
+    pub struct T<D: std::fmt::Debug + ?Sized> {
+        pub p: D,
+    }
+}
+
+mod issue_11278_b {
+    pub fn f(o: &mut super::issue_11278_a::T<dyn std::fmt::Debug>) -> super::issue_11278_a::T<String> {
+        // Retain `super`
+        *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T<String>) }
+    }
+}
 
 #[inline_macros]
 fn main() {
diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
index 78d733994ac..e64f3351505 100644
--- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr
@@ -1,37 +1,43 @@
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:14:13
+  --> $DIR/ptr_as_ptr.rs:19:33
    |
-LL |     let _ = ptr as *const i32;
-   |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
+LL |         *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T<String>) }
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `Box::into_raw(Box::new(o)).cast::<super::issue_11278_a::T<String>>()`
    |
    = note: `-D clippy::ptr-as-ptr` implied by `-D warnings`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:15:13
+  --> $DIR/ptr_as_ptr.rs:28:13
+   |
+LL |     let _ = ptr as *const i32;
+   |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
+
+error: `as` casting between raw pointers without changing its mutability
+  --> $DIR/ptr_as_ptr.rs:29:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:20:17
+  --> $DIR/ptr_as_ptr.rs:34:17
    |
 LL |         let _ = *ptr_ptr as *const i32;
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:33:25
+  --> $DIR/ptr_as_ptr.rs:47:25
    |
 LL |     let _: *const i32 = ptr as *const _;
    |                         ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:34:23
+  --> $DIR/ptr_as_ptr.rs:48:23
    |
 LL |     let _: *mut i32 = mut_ptr as _;
    |                       ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:37:21
+  --> $DIR/ptr_as_ptr.rs:51:21
    |
 LL |     let _ = inline!($ptr as *const i32);
    |                     ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()`
@@ -39,16 +45,16 @@ LL |     let _ = inline!($ptr as *const i32);
    = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:58:13
+  --> $DIR/ptr_as_ptr.rs:72:13
    |
 LL |     let _ = ptr as *const i32;
    |             ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()`
 
 error: `as` casting between raw pointers without changing its mutability
-  --> $DIR/ptr_as_ptr.rs:59:13
+  --> $DIR/ptr_as_ptr.rs:73:13
    |
 LL |     let _ = mut_ptr as *mut i32;
    |             ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()`
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 2d8920ccc42..20b9e42a7aa 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -138,6 +138,23 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
     // no warning
     let _ = if let Err(e) = x { Err(e) } else { Ok(0) };
 
+    // issue #11283
+    // no warning
+    #[warn(clippy::question_mark_used)]
+    {
+        if let Err(err) = Ok(()) {
+            return Err(err);
+        }
+
+        if Err::<i32, _>(0).is_err() {
+            return Err(0);
+        } else {
+            return Ok(0);
+        }
+
+        unreachable!()
+    }
+
     Ok(y)
 }
 
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index 69451c17ee7..8bdafd46e8f 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -170,6 +170,23 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
     // no warning
     let _ = if let Err(e) = x { Err(e) } else { Ok(0) };
 
+    // issue #11283
+    // no warning
+    #[warn(clippy::question_mark_used)]
+    {
+        if let Err(err) = Ok(()) {
+            return Err(err);
+        }
+
+        if Err::<i32, _>(0).is_err() {
+            return Err(0);
+        } else {
+            return Ok(0);
+        }
+
+        unreachable!()
+    }
+
     Ok(y)
 }
 
diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr
index 2cfd7586308..62489c8c8c4 100644
--- a/src/tools/clippy/tests/ui/question_mark.stderr
+++ b/src/tools/clippy/tests/ui/question_mark.stderr
@@ -115,7 +115,7 @@ LL | |     }
    | |_____^ help: replace it with: `x?;`
 
 error: this block may be rewritten with the `?` operator
-  --> $DIR/question_mark.rs:197:5
+  --> $DIR/question_mark.rs:214:5
    |
 LL | /     if let Err(err) = func_returning_result() {
 LL | |         return Err(err);
@@ -123,7 +123,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> $DIR/question_mark.rs:204:5
+  --> $DIR/question_mark.rs:221:5
    |
 LL | /     if let Err(err) = func_returning_result() {
 LL | |         return Err(err);
@@ -131,7 +131,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> $DIR/question_mark.rs:281:13
+  --> $DIR/question_mark.rs:298:13
    |
 LL | /             if a.is_none() {
 LL | |                 return None;
diff --git a/src/tools/clippy/tests/ui/range_contains.fixed b/src/tools/clippy/tests/ui/range_contains.fixed
index 0a92ee7c8dd..47c5248118e 100644
--- a/src/tools/clippy/tests/ui/range_contains.fixed
+++ b/src/tools/clippy/tests/ui/range_contains.fixed
@@ -5,6 +5,8 @@
 #![allow(clippy::no_effect)]
 #![allow(clippy::short_circuit_statement)]
 #![allow(clippy::unnecessary_operation)]
+#![allow(clippy::impossible_comparisons)]
+#![allow(clippy::redundant_comparisons)]
 
 fn main() {
     let x = 9_i32;
diff --git a/src/tools/clippy/tests/ui/range_contains.rs b/src/tools/clippy/tests/ui/range_contains.rs
index 7a83be60957..a35315a649d 100644
--- a/src/tools/clippy/tests/ui/range_contains.rs
+++ b/src/tools/clippy/tests/ui/range_contains.rs
@@ -5,6 +5,8 @@
 #![allow(clippy::no_effect)]
 #![allow(clippy::short_circuit_statement)]
 #![allow(clippy::unnecessary_operation)]
+#![allow(clippy::impossible_comparisons)]
+#![allow(clippy::redundant_comparisons)]
 
 fn main() {
     let x = 9_i32;
diff --git a/src/tools/clippy/tests/ui/range_contains.stderr b/src/tools/clippy/tests/ui/range_contains.stderr
index ea34023a466..1265db695bf 100644
--- a/src/tools/clippy/tests/ui/range_contains.stderr
+++ b/src/tools/clippy/tests/ui/range_contains.stderr
@@ -1,5 +1,5 @@
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:13:5
+  --> $DIR/range_contains.rs:15:5
    |
 LL |     x >= 8 && x < 12;
    |     ^^^^^^^^^^^^^^^^ help: use: `(8..12).contains(&x)`
@@ -7,121 +7,121 @@ LL |     x >= 8 && x < 12;
    = note: `-D clippy::manual-range-contains` implied by `-D warnings`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:14:5
+  --> $DIR/range_contains.rs:16:5
    |
 LL |     x < 42 && x >= 21;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(21..42).contains(&x)`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:15:5
+  --> $DIR/range_contains.rs:17:5
    |
 LL |     100 > x && 1 <= x;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(1..100).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:18:5
+  --> $DIR/range_contains.rs:20:5
    |
 LL |     x >= 9 && x <= 99;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(9..=99).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:19:5
+  --> $DIR/range_contains.rs:21:5
    |
 LL |     x <= 33 && x >= 1;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(1..=33).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:20:5
+  --> $DIR/range_contains.rs:22:5
    |
 LL |     999 >= x && 1 <= x;
    |     ^^^^^^^^^^^^^^^^^^ help: use: `(1..=999).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:23:5
+  --> $DIR/range_contains.rs:25:5
    |
 LL |     x < 8 || x >= 12;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(8..12).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:24:5
+  --> $DIR/range_contains.rs:26:5
    |
 LL |     x >= 42 || x < 21;
    |     ^^^^^^^^^^^^^^^^^ help: use: `!(21..42).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:25:5
+  --> $DIR/range_contains.rs:27:5
    |
 LL |     100 <= x || 1 > x;
    |     ^^^^^^^^^^^^^^^^^ help: use: `!(1..100).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:28:5
+  --> $DIR/range_contains.rs:30:5
    |
 LL |     x < 9 || x > 99;
    |     ^^^^^^^^^^^^^^^ help: use: `!(9..=99).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:29:5
+  --> $DIR/range_contains.rs:31:5
    |
 LL |     x > 33 || x < 1;
    |     ^^^^^^^^^^^^^^^ help: use: `!(1..=33).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:30:5
+  --> $DIR/range_contains.rs:32:5
    |
 LL |     999 < x || 1 > x;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:45:5
+  --> $DIR/range_contains.rs:47:5
    |
 LL |     y >= 0. && y < 1.;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:46:5
+  --> $DIR/range_contains.rs:48:5
    |
 LL |     y < 0. || y > 1.;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:49:5
+  --> $DIR/range_contains.rs:51:5
    |
 LL |     x >= -10 && x <= 10;
    |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-10..=10).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:51:5
+  --> $DIR/range_contains.rs:53:5
    |
 LL |     y >= -3. && y <= 3.;
    |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:56:30
+  --> $DIR/range_contains.rs:58:30
    |
 LL |     (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
    |                              ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&z)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:56:5
+  --> $DIR/range_contains.rs:58:5
    |
 LL |     (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
    |     ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:57:29
+  --> $DIR/range_contains.rs:59:29
    |
 LL |     (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
    |                             ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&z)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:57:5
+  --> $DIR/range_contains.rs:59:5
    |
 LL |     (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
    |     ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&x)`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:76:5
+  --> $DIR/range_contains.rs:78:5
    |
 LL |     x >= 8 && x < 35;
    |     ^^^^^^^^^^^^^^^^ help: use: `(8..35).contains(&x)`
diff --git a/src/tools/clippy/tests/ui/redundant_guards.fixed b/src/tools/clippy/tests/ui/redundant_guards.fixed
index 77ac7666864..49d7336ee37 100644
--- a/src/tools/clippy/tests/ui/redundant_guards.fixed
+++ b/src/tools/clippy/tests/ui/redundant_guards.fixed
@@ -15,6 +15,19 @@ struct B {
 
 struct C(u32, u32);
 
+#[derive(PartialEq)]
+struct FloatWrapper(f32);
+fn issue11304() {
+    match 0.1 {
+        x if x == 0.0 => todo!(),
+        _ => todo!(),
+    }
+    match FloatWrapper(0.1) {
+        x if x == FloatWrapper(0.0) => todo!(),
+        _ => todo!(),
+    }
+}
+
 fn main() {
     let c = C(1, 2);
     match c {
diff --git a/src/tools/clippy/tests/ui/redundant_guards.rs b/src/tools/clippy/tests/ui/redundant_guards.rs
index b072e4ea14d..87761010de2 100644
--- a/src/tools/clippy/tests/ui/redundant_guards.rs
+++ b/src/tools/clippy/tests/ui/redundant_guards.rs
@@ -15,6 +15,19 @@ struct B {
 
 struct C(u32, u32);
 
+#[derive(PartialEq)]
+struct FloatWrapper(f32);
+fn issue11304() {
+    match 0.1 {
+        x if x == 0.0 => todo!(),
+        _ => todo!(),
+    }
+    match FloatWrapper(0.1) {
+        x if x == FloatWrapper(0.0) => todo!(),
+        _ => todo!(),
+    }
+}
+
 fn main() {
     let c = C(1, 2);
     match c {
diff --git a/src/tools/clippy/tests/ui/redundant_guards.stderr b/src/tools/clippy/tests/ui/redundant_guards.stderr
index c2a92071d1d..5bdf43d23c5 100644
--- a/src/tools/clippy/tests/ui/redundant_guards.stderr
+++ b/src/tools/clippy/tests/ui/redundant_guards.stderr
@@ -1,5 +1,5 @@
 error: redundant guard
-  --> $DIR/redundant_guards.rs:21:20
+  --> $DIR/redundant_guards.rs:34:20
    |
 LL |         C(x, y) if let 1 = y => ..,
    |                    ^^^^^^^^^
@@ -12,7 +12,7 @@ LL +         C(x, 1) => ..,
    |
 
 error: redundant guard
-  --> $DIR/redundant_guards.rs:27:20
+  --> $DIR/redundant_guards.rs:40:20
    |
 LL |         Some(x) if matches!(x, Some(1) if true) => ..,
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL |         Some(Some(1)) if true => ..,
    |              ~~~~~~~  ~~~~~~~
 
 error: redundant guard
-  --> $DIR/redundant_guards.rs:28:20
+  --> $DIR/redundant_guards.rs:41:20
    |
 LL |         Some(x) if matches!(x, Some(1)) => {
    |                    ^^^^^^^^^^^^^^^^^^^^
@@ -35,7 +35,7 @@ LL +         Some(Some(1)) => {
    |
 
 error: redundant guard
-  --> $DIR/redundant_guards.rs:32:20
+  --> $DIR/redundant_guards.rs:45:20
    |
 LL |         Some(x) if let Some(1) = x => ..,
    |                    ^^^^^^^^^^^^^^^
@@ -47,7 +47,7 @@ LL +         Some(Some(1)) => ..,
    |
 
 error: redundant guard
-  --> $DIR/redundant_guards.rs:33:20
+  --> $DIR/redundant_guards.rs:46:20
    |
 LL |         Some(x) if x == Some(2) => ..,
    |                    ^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL +         Some(Some(2)) => ..,
    |
 
 error: redundant guard
-  --> $DIR/redundant_guards.rs:56:20
+  --> $DIR/redundant_guards.rs:69:20
    |
 LL |         B { e } if matches!(e, Some(A(2))) => ..,
    |                    ^^^^^^^^^^^^^^^^^^^^^^^
@@ -71,7 +71,7 @@ LL +         B { e: Some(A(2)) } => ..,
    |
 
 error: redundant guard
-  --> $DIR/redundant_guards.rs:93:20
+  --> $DIR/redundant_guards.rs:106:20
    |
 LL |         E::A(y) if y == "not from an or pattern" => {},
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,7 +83,7 @@ LL +         E::A("not from an or pattern") => {},
    |
 
 error: redundant guard
-  --> $DIR/redundant_guards.rs:100:14
+  --> $DIR/redundant_guards.rs:113:14
    |
 LL |         x if matches!(x, Some(0)) => ..,
    |              ^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/redundant_locals.rs b/src/tools/clippy/tests/ui/redundant_locals.rs
index e74c78a50b6..80af38f47b8 100644
--- a/src/tools/clippy/tests/ui/redundant_locals.rs
+++ b/src/tools/clippy/tests/ui/redundant_locals.rs
@@ -27,6 +27,15 @@ fn downgraded_mutability() {
     let x = x;
 }
 
+// see #11290
+fn shadow_mutation() {
+    let mut x = 1;
+    {
+        let mut x = x;
+        x = 2;
+    }
+}
+
 fn coercion(par: &mut i32) {
     let par: &i32 = par;
 
diff --git a/src/tools/clippy/tests/ui/redundant_locals.stderr b/src/tools/clippy/tests/ui/redundant_locals.stderr
index df07dd2f453..587de057524 100644
--- a/src/tools/clippy/tests/ui/redundant_locals.stderr
+++ b/src/tools/clippy/tests/ui/redundant_locals.stderr
@@ -20,7 +20,7 @@ LL |     let mut x = x;
    = help: remove the redefinition of `x`
 
 error: redundant redefinition of a binding
-  --> $DIR/redundant_locals.rs:37:14
+  --> $DIR/redundant_locals.rs:46:14
    |
 LL | fn parameter(x: i32) {
    |              ^
@@ -30,7 +30,7 @@ LL |     let x = x;
    = help: remove the redefinition of `x`
 
 error: redundant redefinition of a binding
-  --> $DIR/redundant_locals.rs:42:9
+  --> $DIR/redundant_locals.rs:51:9
    |
 LL |     let x = 1;
    |         ^
@@ -40,7 +40,7 @@ LL |     let x = x;
    = help: remove the redefinition of `x`
 
 error: redundant redefinition of a binding
-  --> $DIR/redundant_locals.rs:43:9
+  --> $DIR/redundant_locals.rs:52:9
    |
 LL |     let x = x;
    |         ^
@@ -50,7 +50,7 @@ LL |     let x = x;
    = help: remove the redefinition of `x`
 
 error: redundant redefinition of a binding
-  --> $DIR/redundant_locals.rs:44:9
+  --> $DIR/redundant_locals.rs:53:9
    |
 LL |     let x = x;
    |         ^
@@ -60,7 +60,7 @@ LL |     let x = x;
    = help: remove the redefinition of `x`
 
 error: redundant redefinition of a binding
-  --> $DIR/redundant_locals.rs:45:9
+  --> $DIR/redundant_locals.rs:54:9
    |
 LL |     let x = x;
    |         ^
@@ -70,7 +70,7 @@ LL |     let x = x;
    = help: remove the redefinition of `x`
 
 error: redundant redefinition of a binding
-  --> $DIR/redundant_locals.rs:50:9
+  --> $DIR/redundant_locals.rs:59:9
    |
 LL |     let a = 1;
    |         ^
@@ -81,7 +81,7 @@ LL |     let a = a;
    = help: remove the redefinition of `a`
 
 error: redundant redefinition of a binding
-  --> $DIR/redundant_locals.rs:51:9
+  --> $DIR/redundant_locals.rs:60:9
    |
 LL |     let b = 2;
    |         ^
@@ -92,7 +92,7 @@ LL |     let b = b;
    = help: remove the redefinition of `b`
 
 error: redundant redefinition of a binding
-  --> $DIR/redundant_locals.rs:58:13
+  --> $DIR/redundant_locals.rs:67:13
    |
 LL |         let x = 1;
    |             ^
@@ -102,7 +102,7 @@ LL |         let x = x;
    = help: remove the redefinition of `x`
 
 error: redundant redefinition of a binding
-  --> $DIR/redundant_locals.rs:65:13
+  --> $DIR/redundant_locals.rs:74:13
    |
 LL |         let x = 1;
    |             ^
@@ -112,7 +112,7 @@ LL |         let x = x;
    = help: remove the redefinition of `x`
 
 error: redundant redefinition of a binding
-  --> $DIR/redundant_locals.rs:68:6
+  --> $DIR/redundant_locals.rs:77:6
    |
 LL |     |x: i32| {
    |      ^
@@ -122,7 +122,7 @@ LL |         let x = x;
    = help: remove the redefinition of `x`
 
 error: redundant redefinition of a binding
-  --> $DIR/redundant_locals.rs:85:9
+  --> $DIR/redundant_locals.rs:94:9
    |
 LL |     let x = 1;
    |         ^
diff --git a/src/tools/clippy/tests/ui/redundant_type_annotations.rs b/src/tools/clippy/tests/ui/redundant_type_annotations.rs
index cc507b8d658..09dbd3c9b39 100644
--- a/src/tools/clippy/tests/ui/redundant_type_annotations.rs
+++ b/src/tools/clippy/tests/ui/redundant_type_annotations.rs
@@ -6,8 +6,8 @@ struct Cake<T> {
     _data: T,
 }
 
-fn make_something<T: Default>() -> T {
-    T::default()
+fn make_something<T>() -> T {
+    unimplemented!()
 }
 
 fn make_cake<T: Default>() -> Cake<T> {
@@ -117,7 +117,15 @@ fn test_non_locals() {
     let _closure_arg = |x: u32| x;
 }
 
-fn test_complex_types() {
+trait Trait {
+    type AssocTy;
+}
+
+impl Trait for () {
+    type AssocTy = String;
+}
+
+fn test_complex_types<T>() {
     // Shouldn't be lint, since the literal will be i32 otherwise
     let _u8: u8 = 128;
 
@@ -135,6 +143,10 @@ fn test_complex_types() {
 
     // Shouldn't be lint
     let _array: [u32; 2] = [8, 9];
+
+    let ty_param: T = make_something();
+
+    let assoc_ty: <() as Trait>::AssocTy = String::new();
 }
 
 fn test_functions() {
@@ -173,4 +185,6 @@ fn test_simple_types() {
     let _var: bool = false;
 }
 
+fn issue11190() {}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_type_annotations.stderr b/src/tools/clippy/tests/ui/redundant_type_annotations.stderr
index e8b2fe5c384..988ebe63722 100644
--- a/src/tools/clippy/tests/ui/redundant_type_annotations.stderr
+++ b/src/tools/clippy/tests/ui/redundant_type_annotations.stderr
@@ -19,85 +19,85 @@ LL |         let v: &Slice = self.return_a_ref_to_struct();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:143:5
+  --> $DIR/redundant_type_annotations.rs:155:5
    |
 LL |     let _return: String = return_a_string();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:145:5
+  --> $DIR/redundant_type_annotations.rs:157:5
    |
 LL |     let _return: Pie = return_a_struct();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:147:5
+  --> $DIR/redundant_type_annotations.rs:159:5
    |
 LL |     let _return: Pizza = return_an_enum();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:149:5
+  --> $DIR/redundant_type_annotations.rs:161:5
    |
 LL |     let _return: u32 = return_an_int();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:151:5
+  --> $DIR/redundant_type_annotations.rs:163:5
    |
 LL |     let _return: String = String::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:153:5
+  --> $DIR/redundant_type_annotations.rs:165:5
    |
 LL |     let new_pie: Pie = Pie::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:155:5
+  --> $DIR/redundant_type_annotations.rs:167:5
    |
 LL |     let _return: u32 = new_pie.return_an_int();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:157:5
+  --> $DIR/redundant_type_annotations.rs:169:5
    |
 LL |     let _return: u32 = Pie::associated_return_an_int();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:159:5
+  --> $DIR/redundant_type_annotations.rs:171:5
    |
 LL |     let _return: String = Pie::associated_return_a_string();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:165:5
+  --> $DIR/redundant_type_annotations.rs:177:5
    |
 LL |     let _var: u32 = u32::MAX;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:167:5
+  --> $DIR/redundant_type_annotations.rs:179:5
    |
 LL |     let _var: u32 = 5_u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:169:5
+  --> $DIR/redundant_type_annotations.rs:181:5
    |
 LL |     let _var: &str = "test";
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:171:5
+  --> $DIR/redundant_type_annotations.rs:183:5
    |
 LL |     let _var: &[u8] = b"test";
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: redundant type annotation
-  --> $DIR/redundant_type_annotations.rs:173:5
+  --> $DIR/redundant_type_annotations.rs:185:5
    |
 LL |     let _var: bool = false;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 8257bf2947a..e78b9e5c9c1 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -29,9 +29,9 @@
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
+#![allow(invalid_reference_casting)]
 #![allow(suspicious_double_ref_op)]
 #![allow(invalid_nan_comparisons)]
-#![allow(invalid_reference_casting)]
 #![allow(drop_bounds)]
 #![allow(dropping_copy_types)]
 #![allow(dropping_references)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 6569dad18d4..2e6ef60cb79 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -29,9 +29,9 @@
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
+#![allow(invalid_reference_casting)]
 #![allow(suspicious_double_ref_op)]
 #![allow(invalid_nan_comparisons)]
-#![allow(invalid_reference_casting)]
 #![allow(drop_bounds)]
 #![allow(dropping_copy_types)]
 #![allow(dropping_references)]
diff --git a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
index 8bb3c8fbeeb..d93a55ba906 100644
--- a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr
@@ -10,31 +10,31 @@ error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:20:13
    |
 LL |     let _ = 2i32 ^ 9i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(9_i32)`
+   |             ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(9i32)`
 
 error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:21:13
    |
 LL |     let _ = 2i32 ^ 2i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(2_i32)`
+   |             ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(2i32)`
 
 error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:22:13
    |
 LL |     let _ = 50i32 ^ 3i32;
-   |             ^^^^^^^^^^^^ help: did you mean to write: `50_i32.pow(3_i32)`
+   |             ^^^^^^^^^^^^ help: did you mean to write: `50i32.pow(3i32)`
 
 error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:23:13
    |
 LL |     let _ = 5i32 ^ 8i32;
-   |             ^^^^^^^^^^^ help: did you mean to write: `5_i32.pow(8_i32)`
+   |             ^^^^^^^^^^^ help: did you mean to write: `5i32.pow(8i32)`
 
 error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:24:13
    |
 LL |     let _ = 2i32 ^ 32i32;
-   |             ^^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(32_i32)`
+   |             ^^^^^^^^^^^^ help: did you mean to write: `2i32.pow(32i32)`
 
 error: `^` is not the exponentiation operator
   --> $DIR/suspicious_xor_used_as_pow.rs:13:9
diff --git a/src/tools/clippy/tests/ui/unwrap.stderr b/src/tools/clippy/tests/ui/unwrap.stderr
index 3796d942ff9..41db819f6fb 100644
--- a/src/tools/clippy/tests/ui/unwrap.stderr
+++ b/src/tools/clippy/tests/ui/unwrap.stderr
@@ -4,7 +4,8 @@ error: used `unwrap()` on an `Option` value
 LL |     let _ = opt.unwrap();
    |             ^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
 
 error: used `unwrap()` on a `Result` value
@@ -13,7 +14,8 @@ error: used `unwrap()` on a `Result` value
 LL |     let _ = res.unwrap();
    |             ^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message
+   = note: if this value is an `Err`, it will panic
+   = help: consider using `expect()` to provide a better panic message
 
 error: used `unwrap_err()` on a `Result` value
   --> $DIR/unwrap.rs:12:13
@@ -21,7 +23,8 @@ error: used `unwrap_err()` on a `Result` value
 LL |     let _ = res.unwrap_err();
    |             ^^^^^^^^^^^^^^^^
    |
-   = help: if you don't want to handle the `Ok` case gracefully, consider using `expect_err()` to provide a better panic message
+   = note: if this value is an `Ok`, it will panic
+   = help: consider using `expect_err()` to provide a better panic message
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.rs b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
index 7f57efc53c9..26f92ccdefa 100644
--- a/src/tools/clippy/tests/ui/unwrap_expect_used.rs
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
@@ -1,5 +1,8 @@
 #![warn(clippy::unwrap_used, clippy::expect_used)]
 #![allow(clippy::unnecessary_literal_unwrap)]
+#![feature(never_type)]
+
+use std::convert::Infallible;
 
 trait OptionExt {
     type Item;
@@ -28,6 +31,14 @@ fn main() {
     Some(3).unwrap_err();
     Some(3).expect_err("Hellow none!");
 
+    // Issue #11245: The `Err` variant can never be constructed so do not lint this.
+    let x: Result<(), !> = Ok(());
+    x.unwrap();
+    x.expect("is `!` (never)");
+    let x: Result<(), Infallible> = Ok(());
+    x.unwrap();
+    x.expect("is never-like (0 variants)");
+
     let a: Result<i32, i32> = Ok(3);
     a.unwrap();
     a.expect("Hello world!");
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
index 1a551ab5ab8..f66e47612ad 100644
--- a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
@@ -1,52 +1,52 @@
 error: used `unwrap()` on an `Option` value
-  --> $DIR/unwrap_expect_used.rs:24:5
+  --> $DIR/unwrap_expect_used.rs:27:5
    |
 LL |     Some(3).unwrap();
    |     ^^^^^^^^^^^^^^^^
    |
-   = help: if this value is `None`, it will panic
+   = note: if this value is `None`, it will panic
    = note: `-D clippy::unwrap-used` implied by `-D warnings`
 
 error: used `expect()` on an `Option` value
-  --> $DIR/unwrap_expect_used.rs:25:5
+  --> $DIR/unwrap_expect_used.rs:28:5
    |
 LL |     Some(3).expect("Hello world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if this value is `None`, it will panic
+   = note: if this value is `None`, it will panic
    = note: `-D clippy::expect-used` implied by `-D warnings`
 
 error: used `unwrap()` on a `Result` value
-  --> $DIR/unwrap_expect_used.rs:32:5
+  --> $DIR/unwrap_expect_used.rs:43:5
    |
 LL |     a.unwrap();
    |     ^^^^^^^^^^
    |
-   = help: if this value is an `Err`, it will panic
+   = note: if this value is an `Err`, it will panic
 
 error: used `expect()` on a `Result` value
-  --> $DIR/unwrap_expect_used.rs:33:5
+  --> $DIR/unwrap_expect_used.rs:44:5
    |
 LL |     a.expect("Hello world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Err`, it will panic
+   = note: if this value is an `Err`, it will panic
 
 error: used `unwrap_err()` on a `Result` value
-  --> $DIR/unwrap_expect_used.rs:34:5
+  --> $DIR/unwrap_expect_used.rs:45:5
    |
 LL |     a.unwrap_err();
    |     ^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Ok`, it will panic
+   = note: if this value is an `Ok`, it will panic
 
 error: used `expect_err()` on a `Result` value
-  --> $DIR/unwrap_expect_used.rs:35:5
+  --> $DIR/unwrap_expect_used.rs:46:5
    |
 LL |     a.expect_err("Hello error!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if this value is an `Ok`, it will panic
+   = note: if this value is an `Ok`, it will panic
 
 error: aborting due to 6 previous errors
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index c1987420417..3d237eb25cc 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1645,7 +1645,7 @@ impl<'test> TestCx<'test> {
         if self.props.known_bug {
             if !expected_errors.is_empty() {
                 self.fatal_proc_rec(
-                    "`known_bug` tests should not have an expected errors",
+                    "`known_bug` tests should not have an expected error",
                     proc_res,
                 );
             }
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index fe66f1a9bdb..ed78f80c023 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -173,7 +173,7 @@ impl Command {
         // the merge has confused the heck out of josh in the past.
         // We pass `--no-verify` to avoid running git hooks like `./miri fmt` that could in turn
         // trigger auto-actions.
-        sh.write_file("rust-version", &commit)?;
+        sh.write_file("rust-version", format!("{commit}\n"))?;
         const PREPARING_COMMIT_MESSAGE: &str = "Preparing for merge from rustc";
         cmd!(sh, "git commit rust-version --no-verify -m {PREPARING_COMMIT_MESSAGE}")
             .run()
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 716b690daaa..22a3d439861 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-fca59ab5f0e7df7d816bed77a32abc0045ebe80b
\ No newline at end of file
+9fa6bdd764a1f7bdf69eccceeace6d13f38cb2e1
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 1ec4cbc4de7..97718f1f4a9 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -69,7 +69,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
             }
 
             init_late_loggers(handler, tcx);
-            if !tcx.sess.crate_types().contains(&CrateType::Executable) {
+            if !tcx.crate_types().contains(&CrateType::Executable) {
                 tcx.sess.fatal("miri only makes sense on bin crates");
             }
 
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index 0fbe66360b2..08b138c68ae 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -283,7 +283,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
                 // interleaving, but wether UB happens can depend on whether a write occurs in the
                 // future...
                 let is_write = new_perm.initial_state.is_active()
-                    || (new_perm.initial_state.is_resrved() && new_perm.protector.is_some());
+                    || (new_perm.initial_state.is_reserved() && new_perm.protector.is_some());
                 if is_write {
                     // Need to get mutable access to alloc_extra.
                     // (Cannot always do this as we can do read-only reborrowing on read-only allocations.)
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
index b4a9a768e27..0ce29ac5437 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -152,7 +152,7 @@ impl Permission {
         matches!(self.inner, Active)
     }
 
-    pub fn is_resrved(self) -> bool {
+    pub fn is_reserved(self) -> bool {
         matches!(self.inner, Reserved { .. })
     }
 
diff --git a/src/tools/miri/src/concurrency/range_object_map.rs b/src/tools/miri/src/concurrency/range_object_map.rs
index 89c009933bb..859eb4bbb60 100644
--- a/src/tools/miri/src/concurrency/range_object_map.rs
+++ b/src/tools/miri/src/concurrency/range_object_map.rs
@@ -42,30 +42,19 @@ impl<T> RangeObjectMap<T> {
     /// in an existing allocation, then returns Err containing the position
     /// where such allocation should be inserted
     fn find_offset(&self, offset: Size) -> Result<Position, Position> {
-        // We do a binary search.
-        let mut left = 0usize; // inclusive
-        let mut right = self.v.len(); // exclusive
-        loop {
-            if left == right {
-                // No element contains the given offset. But the
-                // position is where such element should be placed at.
-                return Err(left);
-            }
-            let candidate = left.checked_add(right).unwrap() / 2;
-            let elem = &self.v[candidate];
+        self.v.binary_search_by(|elem| -> std::cmp::Ordering {
             if offset < elem.range.start {
                 // We are too far right (offset is further left).
-                debug_assert!(candidate < right); // we are making progress
-                right = candidate;
+                // (`Greater` means that `elem` is greater than the desired target.)
+                std::cmp::Ordering::Greater
             } else if offset >= elem.range.end() {
                 // We are too far left (offset is further right).
-                debug_assert!(candidate >= left); // we are making progress
-                left = candidate + 1;
+                std::cmp::Ordering::Less
             } else {
                 // This is it!
-                return Ok(candidate);
+                std::cmp::Ordering::Equal
             }
-        }
+        })
     }
 
     /// Determines whether a given access on `range` overlaps with
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index b761a6cf475..88e7d5386db 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -301,7 +301,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
     // Third argument (`argv`): created from `config.args`.
     let argv = {
         // Put each argument in memory, collect pointers.
-        let mut argvs = Vec::<Immediate<Provenance>>::new();
+        let mut argvs = Vec::<Immediate<Provenance>>::with_capacity(config.args.len());
         for arg in config.args.iter() {
             // Make space for `0` terminator.
             let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap();
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index e0f74d03ff6..ea1931f7a18 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -1,6 +1,5 @@
 pub mod convert;
 
-use std::any::Any;
 use std::cmp;
 use std::iter;
 use std::num::NonZeroUsize;
@@ -25,24 +24,6 @@ use rand::RngCore;
 
 use crate::*;
 
-/// A trait to work around not having trait object upcasting:
-/// Add `AsAny` as supertrait and your trait objects can be turned into `&dyn Any` on which you can
-/// then call `downcast`.
-pub trait AsAny: Any {
-    fn as_any(&self) -> &dyn Any;
-    fn as_any_mut(&mut self) -> &mut dyn Any;
-}
-impl<T: Any> AsAny for T {
-    #[inline(always)]
-    fn as_any(&self) -> &dyn Any {
-        self
-    }
-    #[inline(always)]
-    fn as_any_mut(&mut self) -> &mut dyn Any {
-        self
-    }
-}
-
 // This mapping should match `decode_error_kind` in
 // <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/unix/mod.rs>.
 const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 5327c2f24e0..0e50618ad9e 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,4 +1,5 @@
 #![feature(rustc_private)]
+#![feature(float_gamma)]
 #![feature(map_try_insert)]
 #![feature(never_type)]
 #![feature(try_blocks)]
@@ -10,6 +11,7 @@
 #![feature(round_ties_even)]
 #![feature(os_str_bytes)]
 #![feature(lint_reasons)]
+#![feature(trait_upcasting)]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
@@ -19,6 +21,7 @@
     clippy::enum_variant_names,
     clippy::field_reassign_with_default,
     clippy::manual_map,
+    clippy::neg_cmp_op_on_partial_ord,
     clippy::new_without_default,
     clippy::single_match,
     clippy::useless_format,
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 167d1fd4518..953677d3290 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -815,6 +815,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             | "atanf"
             | "log1pf"
             | "expm1f"
+            | "tgammaf"
             => {
                 let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 // FIXME: Using host floats.
@@ -830,6 +831,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     "atanf" => f.atan(),
                     "log1pf" => f.ln_1p(),
                     "expm1f" => f.exp_m1(),
+                    "tgammaf" => f.gamma(),
                     _ => bug!(),
                 };
                 this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?;
@@ -866,6 +868,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             | "atan"
             | "log1p"
             | "expm1"
+            | "tgamma"
             => {
                 let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 // FIXME: Using host floats.
@@ -881,6 +884,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     "atan" => f.atan(),
                     "log1p" => f.ln_1p(),
                     "expm1" => f.exp_m1(),
+                    "tgamma" => f.gamma(),
                     _ => bug!(),
                 };
                 this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?;
@@ -917,6 +921,53 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let res = x.scalbn(exp);
                 this.write_scalar(Scalar::from_f64(res), dest)?;
             }
+            "lgammaf_r" => {
+                let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                // FIXME: Using host floats.
+                let x = f32::from_bits(this.read_scalar(x)?.to_u32()?);
+                let signp = this.deref_pointer(signp)?;
+
+                let (res, sign) = x.ln_gamma();
+                this.write_int(sign, &signp)?;
+                this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?;
+            }
+            "lgamma_r" => {
+                let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                // FIXME: Using host floats.
+                let x = f64::from_bits(this.read_scalar(x)?.to_u64()?);
+                let signp = this.deref_pointer(signp)?;
+
+                let (res, sign) = x.ln_gamma();
+                this.write_int(sign, &signp)?;
+                this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?;
+            }
+
+            "llvm.prefetch" => {
+                let [p, rw, loc, ty] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let _ = this.read_pointer(p)?;
+                let rw = this.read_scalar(rw)?.to_i32()?;
+                let loc = this.read_scalar(loc)?.to_i32()?;
+                let ty = this.read_scalar(ty)?.to_i32()?;
+
+                if ty == 1 {
+                    // Data cache prefetch.
+                    // Notably, we do not have to check the pointer, this operation is never UB!
+
+                    if !matches!(rw, 0 | 1) {
+                        throw_unsup_format!("invalid `rw` value passed to `llvm.prefetch`: {}", rw);
+                    }
+                    if !matches!(loc, 0..=3) {
+                        throw_unsup_format!(
+                            "invalid `loc` value passed to `llvm.prefetch`: {}",
+                            loc
+                        );
+                    }
+                } else {
+                    throw_unsup_format!("unsupported `llvm.prefetch` type argument: {}", ty);
+                }
+            }
 
             // Architecture-specific shims
             "llvm.x86.addcarry.64" if this.tcx.sess.target.arch == "x86_64" => {
@@ -970,6 +1021,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 }
             }
 
+            name if name.starts_with("llvm.x86.sse.") => {
+                return shims::x86::sse::EvalContextExt::emulate_x86_sse_intrinsic(
+                    this, link_name, abi, args, dest,
+                );
+            }
+
             // Platform-specific shims
             _ =>
                 return match this.tcx.sess.target.os.as_ref() {
diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs
index 1027b24e301..5a9574766f3 100644
--- a/src/tools/miri/src/shims/mod.rs
+++ b/src/tools/miri/src/shims/mod.rs
@@ -7,6 +7,7 @@ pub mod foreign_items;
 pub mod intrinsics;
 pub mod unix;
 pub mod windows;
+mod x86;
 
 pub mod dlsym;
 pub mod env;
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 09349bfdead..beaef22075b 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -1,3 +1,4 @@
+use std::any::Any;
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::convert::TryInto;
@@ -24,7 +25,7 @@ pub struct FileHandle {
     writable: bool,
 }
 
-pub trait FileDescriptor: std::fmt::Debug + helpers::AsAny {
+pub trait FileDescriptor: std::fmt::Debug + Any {
     fn name(&self) -> &'static str;
 
     fn read<'tcx>(
@@ -72,6 +73,18 @@ pub trait FileDescriptor: std::fmt::Debug + helpers::AsAny {
     }
 }
 
+impl dyn FileDescriptor {
+    #[inline(always)]
+    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
+        (self as &dyn Any).downcast_ref()
+    }
+
+    #[inline(always)]
+    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
+        (self as &mut dyn Any).downcast_mut()
+    }
+}
+
 impl FileDescriptor for FileHandle {
     fn name(&self) -> &'static str {
         "FILE"
@@ -689,7 +702,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
                 // FIXME: Support fullfsync for all FDs
                 let FileHandle { file, writable } =
-                    file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| {
+                    file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
                         err_unsup_format!(
                             "`F_FULLFSYNC` is only supported on file-backed file descriptors"
                         )
@@ -1522,7 +1535,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) {
                 // FIXME: Support ftruncate64 for all FDs
                 let FileHandle { file, writable } =
-                    file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| {
+                    file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
                         err_unsup_format!(
                             "`ftruncate64` is only supported on file-backed file descriptors"
                         )
@@ -1568,7 +1581,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
             // FIXME: Support fsync for all FDs
             let FileHandle { file, writable } =
-                file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| {
+                file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
                     err_unsup_format!("`fsync` is only supported on file-backed file descriptors")
                 })?;
             let io_result = maybe_sync_file(file, *writable, File::sync_all);
@@ -1593,7 +1606,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
             // FIXME: Support fdatasync for all FDs
             let FileHandle { file, writable } =
-                file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| {
+                file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
                     err_unsup_format!(
                         "`fdatasync` is only supported on file-backed file descriptors"
                     )
@@ -1643,7 +1656,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
             // FIXME: Support sync_data_range for all FDs
             let FileHandle { file, writable } =
-                file_descriptor.as_any().downcast_ref::<FileHandle>().ok_or_else(|| {
+                file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
                     err_unsup_format!(
                         "`sync_data_range` is only supported on file-backed file descriptors"
                     )
@@ -1953,7 +1966,6 @@ impl FileMetadata {
         let file = match option {
             Some(file_descriptor) =>
                 &file_descriptor
-                    .as_any()
                     .downcast_ref::<FileHandle>()
                     .ok_or_else(|| {
                         err_unsup_format!(
diff --git a/src/tools/miri/src/shims/unix/linux/fd.rs b/src/tools/miri/src/shims/unix/linux/fd.rs
index f2be89ce637..22fbb6da95a 100644
--- a/src/tools/miri/src/shims/unix/linux/fd.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd.rs
@@ -1,3 +1,5 @@
+use std::cell::Cell;
+
 use rustc_middle::ty::ScalarInt;
 
 use crate::*;
@@ -7,8 +9,6 @@ use socketpair::SocketPair;
 
 use shims::unix::fs::EvalContextExt as _;
 
-use std::cell::Cell;
-
 pub mod epoll;
 pub mod event;
 pub mod socketpair;
@@ -81,7 +81,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
             if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
                 let epfd = epfd
-                    .as_any_mut()
                     .downcast_mut::<Epoll>()
                     .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
 
@@ -93,7 +92,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         } else if op == epoll_ctl_del {
             if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
                 let epfd = epfd
-                    .as_any_mut()
                     .downcast_mut::<Epoll>()
                     .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
 
@@ -154,7 +152,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) {
             let _epfd = epfd
-                .as_any_mut()
                 .downcast_mut::<Epoll>()
                 .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
 
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
new file mode 100644
index 00000000000..36e673129de
--- /dev/null
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -0,0 +1 @@
+pub(super) mod sse;
diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs
new file mode 100644
index 00000000000..deae0875fb9
--- /dev/null
+++ b/src/tools/miri/src/shims/x86/sse.rs
@@ -0,0 +1,609 @@
+use rustc_apfloat::{ieee::Single, Float as _};
+use rustc_middle::mir;
+use rustc_span::Symbol;
+use rustc_target::spec::abi::Abi;
+
+use rand::Rng as _;
+
+use crate::*;
+use shims::foreign_items::EmulateByNameResult;
+
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    fn emulate_x86_sse_intrinsic(
+        &mut self,
+        link_name: Symbol,
+        abi: Abi,
+        args: &[OpTy<'tcx, Provenance>],
+        dest: &PlaceTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
+        let this = self.eval_context_mut();
+        // Prefix should have already been checked.
+        let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse.").unwrap();
+        // All these intrinsics operate on 128-bit (f32x4) SIMD vectors unless stated otherwise.
+        // Many intrinsic names are sufixed with "ps" (packed single) or "ss" (scalar single),
+        // where single means single precision floating point (f32). "ps" means thet the operation
+        // is performed on each element of the vector, while "ss" means that the operation is
+        // performed only on the first element, copying the remaining elements from the input
+        // vector (for binary operations, from the left-hand side).
+        match unprefixed_name {
+            // Used to implement _mm_{add,sub,mul,div,min,max}_ss functions.
+            // Performs the operations on the first component of `left` and
+            // `right` and copies the remaining components from `left`.
+            "add.ss" | "sub.ss" | "mul.ss" | "div.ss" | "min.ss" | "max.ss" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let which = match unprefixed_name {
+                    "add.ss" => FloatBinOp::Arith(mir::BinOp::Add),
+                    "sub.ss" => FloatBinOp::Arith(mir::BinOp::Sub),
+                    "mul.ss" => FloatBinOp::Arith(mir::BinOp::Mul),
+                    "div.ss" => FloatBinOp::Arith(mir::BinOp::Div),
+                    "min.ss" => FloatBinOp::Min,
+                    "max.ss" => FloatBinOp::Max,
+                    _ => unreachable!(),
+                };
+
+                bin_op_ss(this, which, left, right, dest)?;
+            }
+            // Used to implement _mm_min_ps and _mm_max_ps functions.
+            // Note that the semantics are a bit different from Rust simd_min
+            // and simd_max intrinsics regarding handling of NaN and -0.0: Rust
+            // matches the IEEE min/max operations, while x86 has different
+            // semantics.
+            "min.ps" | "max.ps" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let which = match unprefixed_name {
+                    "min.ps" => FloatBinOp::Min,
+                    "max.ps" => FloatBinOp::Max,
+                    _ => unreachable!(),
+                };
+
+                bin_op_ps(this, which, left, right, dest)?;
+            }
+            // Used to implement _mm_{sqrt,rcp,rsqrt}_ss functions.
+            // Performs the operations on the first component of `op` and
+            // copies the remaining components from `op`.
+            "sqrt.ss" | "rcp.ss" | "rsqrt.ss" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let which = match unprefixed_name {
+                    "sqrt.ss" => FloatUnaryOp::Sqrt,
+                    "rcp.ss" => FloatUnaryOp::Rcp,
+                    "rsqrt.ss" => FloatUnaryOp::Rsqrt,
+                    _ => unreachable!(),
+                };
+
+                unary_op_ss(this, which, op, dest)?;
+            }
+            // Used to implement _mm_{sqrt,rcp,rsqrt}_ss functions.
+            // Performs the operations on all components of `op`.
+            "sqrt.ps" | "rcp.ps" | "rsqrt.ps" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let which = match unprefixed_name {
+                    "sqrt.ps" => FloatUnaryOp::Sqrt,
+                    "rcp.ps" => FloatUnaryOp::Rcp,
+                    "rsqrt.ps" => FloatUnaryOp::Rsqrt,
+                    _ => unreachable!(),
+                };
+
+                unary_op_ps(this, which, op, dest)?;
+            }
+            // Used to implement the _mm_cmp_ss function.
+            // Performs a comparison operation on the first component of `left`
+            // and `right`, returning 0 if false or `u32::MAX` if true. The remaining
+            // components are copied from `left`.
+            "cmp.ss" => {
+                let [left, right, imm] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let which = match this.read_scalar(imm)?.to_i8()? {
+                    0 => FloatBinOp::Cmp(FloatCmpOp::Eq),
+                    1 => FloatBinOp::Cmp(FloatCmpOp::Lt),
+                    2 => FloatBinOp::Cmp(FloatCmpOp::Le),
+                    3 => FloatBinOp::Cmp(FloatCmpOp::Unord),
+                    4 => FloatBinOp::Cmp(FloatCmpOp::Neq),
+                    5 => FloatBinOp::Cmp(FloatCmpOp::Nlt),
+                    6 => FloatBinOp::Cmp(FloatCmpOp::Nle),
+                    7 => FloatBinOp::Cmp(FloatCmpOp::Ord),
+                    imm => {
+                        throw_unsup_format!(
+                            "invalid 3rd parameter of llvm.x86.sse.cmp.ps: {}",
+                            imm
+                        );
+                    }
+                };
+
+                bin_op_ss(this, which, left, right, dest)?;
+            }
+            // Used to implement the _mm_cmp_ps function.
+            // Performs a comparison operation on each component of `left`
+            // and `right`. For each component, returns 0 if false or u32::MAX
+            // if true.
+            "cmp.ps" => {
+                let [left, right, imm] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let which = match this.read_scalar(imm)?.to_i8()? {
+                    0 => FloatBinOp::Cmp(FloatCmpOp::Eq),
+                    1 => FloatBinOp::Cmp(FloatCmpOp::Lt),
+                    2 => FloatBinOp::Cmp(FloatCmpOp::Le),
+                    3 => FloatBinOp::Cmp(FloatCmpOp::Unord),
+                    4 => FloatBinOp::Cmp(FloatCmpOp::Neq),
+                    5 => FloatBinOp::Cmp(FloatCmpOp::Nlt),
+                    6 => FloatBinOp::Cmp(FloatCmpOp::Nle),
+                    7 => FloatBinOp::Cmp(FloatCmpOp::Ord),
+                    imm => {
+                        throw_unsup_format!(
+                            "invalid 3rd parameter of llvm.x86.sse.cmp.ps: {}",
+                            imm
+                        );
+                    }
+                };
+
+                bin_op_ps(this, which, left, right, dest)?;
+            }
+            // Used to implement _mm_{,u}comi{eq,lt,le,gt,ge,neq}_ps functions.
+            // Compares the first component of `left` and `right` and returns
+            // a scalar value (0 or 1).
+            "comieq.ss" | "comilt.ss" | "comile.ss" | "comigt.ss" | "comige.ss" | "comineq.ss"
+            | "ucomieq.ss" | "ucomilt.ss" | "ucomile.ss" | "ucomigt.ss" | "ucomige.ss"
+            | "ucomineq.ss" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (right, right_len) = this.operand_to_simd(right)?;
+
+                assert_eq!(left_len, right_len);
+
+                let left = this.read_scalar(&this.project_index(&left, 0)?)?.to_f32()?;
+                let right = this.read_scalar(&this.project_index(&right, 0)?)?.to_f32()?;
+                // The difference between the com* and *ucom variants is signaling
+                // of exceptions when either argument is a quiet NaN. We do not
+                // support accessing the SSE status register from miri (or from Rust,
+                // for that matter), so we treat equally both variants.
+                let res = match unprefixed_name {
+                    "comieq.ss" | "ucomieq.ss" => left == right,
+                    "comilt.ss" | "ucomilt.ss" => left < right,
+                    "comile.ss" | "ucomile.ss" => left <= right,
+                    "comigt.ss" | "ucomigt.ss" => left > right,
+                    "comige.ss" | "ucomige.ss" => left >= right,
+                    "comineq.ss" | "ucomineq.ss" => left != right,
+                    _ => unreachable!(),
+                };
+                this.write_scalar(Scalar::from_i32(i32::from(res)), dest)?;
+            }
+            // Use to implement _mm_cvtss_si32 and _mm_cvttss_si32.
+            // Converts the first component of `op` from f32 to i32.
+            "cvtss2si" | "cvttss2si" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let (op, _) = this.operand_to_simd(op)?;
+
+                let op = this.read_scalar(&this.project_index(&op, 0)?)?.to_f32()?;
+
+                let rnd = match unprefixed_name {
+                    // "current SSE rounding mode", assume nearest
+                    // https://www.felixcloutier.com/x86/cvtss2si
+                    "cvtss2si" => rustc_apfloat::Round::NearestTiesToEven,
+                    // always truncate
+                    // https://www.felixcloutier.com/x86/cvttss2si
+                    "cvttss2si" => rustc_apfloat::Round::TowardZero,
+                    _ => unreachable!(),
+                };
+
+                let mut exact = false;
+                let cvt = op.to_i128_r(32, rnd, &mut exact);
+                let res = if cvt.status.intersects(
+                    rustc_apfloat::Status::INVALID_OP
+                        | rustc_apfloat::Status::OVERFLOW
+                        | rustc_apfloat::Status::UNDERFLOW,
+                ) {
+                    // Input is NaN (flagged with INVALID_OP) or does not fit
+                    // in an i32 (flagged with OVERFLOW or UNDERFLOW), fallback
+                    // to minimum acording to SSE semantics. The INEXACT flag
+                    // is ignored on purpose because rounding can happen during
+                    // float-to-int conversion.
+                    i32::MIN
+                } else {
+                    i32::try_from(cvt.value).unwrap()
+                };
+
+                this.write_scalar(Scalar::from_i32(res), dest)?;
+            }
+            // Use to implement _mm_cvtss_si64 and _mm_cvttss_si64.
+            // Converts the first component of `op` from f32 to i64.
+            "cvtss2si64" | "cvttss2si64" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let (op, _) = this.operand_to_simd(op)?;
+
+                let op = this.read_scalar(&this.project_index(&op, 0)?)?.to_f32()?;
+
+                let rnd = match unprefixed_name {
+                    // "current SSE rounding mode", assume nearest
+                    // https://www.felixcloutier.com/x86/cvtss2si
+                    "cvtss2si64" => rustc_apfloat::Round::NearestTiesToEven,
+                    // always truncate
+                    // https://www.felixcloutier.com/x86/cvttss2si
+                    "cvttss2si64" => rustc_apfloat::Round::TowardZero,
+                    _ => unreachable!(),
+                };
+
+                let mut exact = false;
+                let cvt = op.to_i128_r(64, rnd, &mut exact);
+                let res = if cvt.status.intersects(
+                    rustc_apfloat::Status::INVALID_OP
+                        | rustc_apfloat::Status::OVERFLOW
+                        | rustc_apfloat::Status::UNDERFLOW,
+                ) {
+                    // Input is NaN (flagged with INVALID_OP) or does not fit
+                    // in an i64 (flagged with OVERFLOW or UNDERFLOW), fallback
+                    // to minimum acording to SSE semantics. The INEXACT flag
+                    // is ignored on purpose because rounding can happen during
+                    // float-to-int conversion.
+                    i64::MIN
+                } else {
+                    i64::try_from(cvt.value).unwrap()
+                };
+
+                this.write_scalar(Scalar::from_i64(res), dest)?;
+            }
+            // Used to implement the _mm_cvtsi32_ss function.
+            // Converts `right` from i32 to f32. Returns a SIMD vector with
+            // the result in the first component and the remaining components
+            // are copied from `left`.
+            // https://www.felixcloutier.com/x86/cvtsi2ss
+            "cvtsi2ss" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, left_len);
+
+                let right = this.read_scalar(right)?.to_i32()?;
+
+                let res0 = Scalar::from_f32(Single::from_i128(right.into()).value);
+                this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
+
+                for i in 1..dest_len {
+                    let left = this.read_immediate(&this.project_index(&left, i)?)?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    this.write_immediate(*left, &dest)?;
+                }
+            }
+            // Used to implement the _mm_cvtsi64_ss function.
+            // Converts `right` from i64 to f32. Returns a SIMD vector with
+            // the result in the first component and the remaining components
+            // are copied from `left`.
+            // https://www.felixcloutier.com/x86/cvtsi2ss
+            "cvtsi642ss" => {
+                let [left, right] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+
+                let (left, left_len) = this.operand_to_simd(left)?;
+                let (dest, dest_len) = this.place_to_simd(dest)?;
+
+                assert_eq!(dest_len, left_len);
+
+                let right = this.read_scalar(right)?.to_i64()?;
+
+                let res0 = Scalar::from_f32(Single::from_i128(right.into()).value);
+                this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
+
+                for i in 1..dest_len {
+                    let left = this.read_immediate(&this.project_index(&left, i)?)?;
+                    let dest = this.project_index(&dest, i)?;
+
+                    this.write_immediate(*left, &dest)?;
+                }
+            }
+            // Used to implement the _mm_movemask_ps function.
+            // Returns a scalar integer where the i-th bit is the highest
+            // bit of the i-th component of `op`.
+            // https://www.felixcloutier.com/x86/movmskps
+            "movmsk.ps" => {
+                let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let (op, op_len) = this.operand_to_simd(op)?;
+
+                let mut res = 0;
+                for i in 0..op_len {
+                    let op = this.read_scalar(&this.project_index(&op, i)?)?;
+                    let op = op.to_u32()?;
+
+                    res |= (op >> 31) << i;
+                }
+
+                this.write_scalar(Scalar::from_u32(res), dest)?;
+            }
+            _ => return Ok(EmulateByNameResult::NotSupported),
+        }
+        Ok(EmulateByNameResult::NeedsJumping)
+    }
+}
+
+/// Floating point comparison operation
+///
+/// <https://www.felixcloutier.com/x86/cmpss>
+/// <https://www.felixcloutier.com/x86/cmpps>
+#[derive(Copy, Clone)]
+enum FloatCmpOp {
+    Eq,
+    Lt,
+    Le,
+    Unord,
+    Neq,
+    /// Not less-than
+    Nlt,
+    /// Not less-or-equal
+    Nle,
+    /// Ordered, i.e. neither of them is NaN
+    Ord,
+}
+
+#[derive(Copy, Clone)]
+enum FloatBinOp {
+    /// Arithmetic operation
+    Arith(mir::BinOp),
+    /// Comparison
+    Cmp(FloatCmpOp),
+    /// Minimum value (with SSE semantics)
+    ///
+    /// <https://www.felixcloutier.com/x86/minss>
+    /// <https://www.felixcloutier.com/x86/minps>
+    Min,
+    /// Maximum value (with SSE semantics)
+    ///
+    /// <https://www.felixcloutier.com/x86/maxss>
+    /// <https://www.felixcloutier.com/x86/maxps>
+    Max,
+}
+
+/// Performs `which` scalar operation on `left` and `right` and returns
+/// the result.
+fn bin_op_f32<'tcx>(
+    this: &crate::MiriInterpCx<'_, 'tcx>,
+    which: FloatBinOp,
+    left: &ImmTy<'tcx, Provenance>,
+    right: &ImmTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, Scalar<Provenance>> {
+    match which {
+        FloatBinOp::Arith(which) => {
+            let (res, _, _) = this.overflowing_binary_op(which, left, right)?;
+            Ok(res)
+        }
+        FloatBinOp::Cmp(which) => {
+            let left = left.to_scalar().to_f32()?;
+            let right = right.to_scalar().to_f32()?;
+            // FIXME: Make sure that these operations match the semantics of cmpps
+            let res = match which {
+                FloatCmpOp::Eq => left == right,
+                FloatCmpOp::Lt => left < right,
+                FloatCmpOp::Le => left <= right,
+                FloatCmpOp::Unord => left.is_nan() || right.is_nan(),
+                FloatCmpOp::Neq => left != right,
+                FloatCmpOp::Nlt => !(left < right),
+                FloatCmpOp::Nle => !(left <= right),
+                FloatCmpOp::Ord => !left.is_nan() && !right.is_nan(),
+            };
+            Ok(Scalar::from_u32(if res { u32::MAX } else { 0 }))
+        }
+        FloatBinOp::Min => {
+            let left = left.to_scalar().to_f32()?;
+            let right = right.to_scalar().to_f32()?;
+            // SSE semantics to handle zero and NaN. Note that `x == Single::ZERO`
+            // is true when `x` is either +0 or -0.
+            if (left == Single::ZERO && right == Single::ZERO)
+                || left.is_nan()
+                || right.is_nan()
+                || left >= right
+            {
+                Ok(Scalar::from_f32(right))
+            } else {
+                Ok(Scalar::from_f32(left))
+            }
+        }
+        FloatBinOp::Max => {
+            let left = left.to_scalar().to_f32()?;
+            let right = right.to_scalar().to_f32()?;
+            // SSE semantics to handle zero and NaN. Note that `x == Single::ZERO`
+            // is true when `x` is either +0 or -0.
+            if (left == Single::ZERO && right == Single::ZERO)
+                || left.is_nan()
+                || right.is_nan()
+                || left <= right
+            {
+                Ok(Scalar::from_f32(right))
+            } else {
+                Ok(Scalar::from_f32(left))
+            }
+        }
+    }
+}
+
+/// Performs `which` operation on the first component of `left` and `right`
+/// and copies the other components from `left`. The result is stored in `dest`.
+fn bin_op_ss<'tcx>(
+    this: &mut crate::MiriInterpCx<'_, 'tcx>,
+    which: FloatBinOp,
+    left: &OpTy<'tcx, Provenance>,
+    right: &OpTy<'tcx, Provenance>,
+    dest: &PlaceTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, ()> {
+    let (left, left_len) = this.operand_to_simd(left)?;
+    let (right, right_len) = this.operand_to_simd(right)?;
+    let (dest, dest_len) = this.place_to_simd(dest)?;
+
+    assert_eq!(dest_len, left_len);
+    assert_eq!(dest_len, right_len);
+
+    let res0 = bin_op_f32(
+        this,
+        which,
+        &this.read_immediate(&this.project_index(&left, 0)?)?,
+        &this.read_immediate(&this.project_index(&right, 0)?)?,
+    )?;
+    this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
+
+    for i in 1..dest_len {
+        let left = this.read_immediate(&this.project_index(&left, i)?)?;
+        let dest = this.project_index(&dest, i)?;
+
+        this.write_immediate(*left, &dest)?;
+    }
+
+    Ok(())
+}
+
+/// Performs `which` operation on each component of `left`, and
+/// `right` storing the result is stored in `dest`.
+fn bin_op_ps<'tcx>(
+    this: &mut crate::MiriInterpCx<'_, 'tcx>,
+    which: FloatBinOp,
+    left: &OpTy<'tcx, Provenance>,
+    right: &OpTy<'tcx, Provenance>,
+    dest: &PlaceTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, ()> {
+    let (left, left_len) = this.operand_to_simd(left)?;
+    let (right, right_len) = this.operand_to_simd(right)?;
+    let (dest, dest_len) = this.place_to_simd(dest)?;
+
+    assert_eq!(dest_len, left_len);
+    assert_eq!(dest_len, right_len);
+
+    for i in 0..dest_len {
+        let left = this.read_immediate(&this.project_index(&left, i)?)?;
+        let right = this.read_immediate(&this.project_index(&right, i)?)?;
+        let dest = this.project_index(&dest, i)?;
+
+        let res = bin_op_f32(this, which, &left, &right)?;
+        this.write_scalar(res, &dest)?;
+    }
+
+    Ok(())
+}
+
+#[derive(Copy, Clone)]
+enum FloatUnaryOp {
+    /// sqrt(x)
+    ///
+    /// <https://www.felixcloutier.com/x86/sqrtss>
+    /// <https://www.felixcloutier.com/x86/sqrtps>
+    Sqrt,
+    /// Approximation of 1/x
+    ///
+    /// <https://www.felixcloutier.com/x86/rcpss>
+    /// <https://www.felixcloutier.com/x86/rcpps>
+    Rcp,
+    /// Approximation of 1/sqrt(x)
+    ///
+    /// <https://www.felixcloutier.com/x86/rsqrtss>
+    /// <https://www.felixcloutier.com/x86/rsqrtps>
+    Rsqrt,
+}
+
+/// Performs `which` scalar operation on `op` and returns the result.
+#[allow(clippy::arithmetic_side_effects)] // floating point operations without side effects
+fn unary_op_f32<'tcx>(
+    this: &mut crate::MiriInterpCx<'_, 'tcx>,
+    which: FloatUnaryOp,
+    op: &ImmTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, Scalar<Provenance>> {
+    match which {
+        FloatUnaryOp::Sqrt => {
+            let op = op.to_scalar();
+            // FIXME using host floats
+            Ok(Scalar::from_u32(f32::from_bits(op.to_u32()?).sqrt().to_bits()))
+        }
+        FloatUnaryOp::Rcp => {
+            let op = op.to_scalar().to_f32()?;
+            let div = (Single::from_u128(1).value / op).value;
+            // Apply a relative error with a magnitude on the order of 2^-12 to simulate the
+            // inaccuracy of RCP.
+            let res = apply_random_float_error(this, div, -12);
+            Ok(Scalar::from_f32(res))
+        }
+        FloatUnaryOp::Rsqrt => {
+            let op = op.to_scalar().to_u32()?;
+            // FIXME using host floats
+            let sqrt = Single::from_bits(f32::from_bits(op).sqrt().to_bits().into());
+            let rsqrt = (Single::from_u128(1).value / sqrt).value;
+            // Apply a relative error with a magnitude on the order of 2^-12 to simulate the
+            // inaccuracy of RSQRT.
+            let res = apply_random_float_error(this, rsqrt, -12);
+            Ok(Scalar::from_f32(res))
+        }
+    }
+}
+
+/// Disturbes a floating-point result by a relative error on the order of (-2^scale, 2^scale).
+#[allow(clippy::arithmetic_side_effects)] // floating point arithmetic cannot panic
+fn apply_random_float_error<F: rustc_apfloat::Float>(
+    this: &mut crate::MiriInterpCx<'_, '_>,
+    val: F,
+    err_scale: i32,
+) -> F {
+    let rng = this.machine.rng.get_mut();
+    // generates rand(0, 2^64) * 2^(scale - 64) = rand(0, 1) * 2^scale
+    let err =
+        F::from_u128(rng.gen::<u64>().into()).value.scalbn(err_scale.checked_sub(64).unwrap());
+    // give it a random sign
+    let err = if rng.gen::<bool>() { -err } else { err };
+    // multiple the value with (1+err)
+    (val * (F::from_u128(1).value + err).value).value
+}
+
+/// Performs `which` operation on the first component of `op` and copies
+/// the other components. The result is stored in `dest`.
+fn unary_op_ss<'tcx>(
+    this: &mut crate::MiriInterpCx<'_, 'tcx>,
+    which: FloatUnaryOp,
+    op: &OpTy<'tcx, Provenance>,
+    dest: &PlaceTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, ()> {
+    let (op, op_len) = this.operand_to_simd(op)?;
+    let (dest, dest_len) = this.place_to_simd(dest)?;
+
+    assert_eq!(dest_len, op_len);
+
+    let res0 = unary_op_f32(this, which, &this.read_immediate(&this.project_index(&op, 0)?)?)?;
+    this.write_scalar(res0, &this.project_index(&dest, 0)?)?;
+
+    for i in 1..dest_len {
+        let op = this.read_immediate(&this.project_index(&op, i)?)?;
+        let dest = this.project_index(&dest, i)?;
+
+        this.write_immediate(*op, &dest)?;
+    }
+
+    Ok(())
+}
+
+/// Performs `which` operation on each component of `op`, storing the
+/// result is stored in `dest`.
+fn unary_op_ps<'tcx>(
+    this: &mut crate::MiriInterpCx<'_, 'tcx>,
+    which: FloatUnaryOp,
+    op: &OpTy<'tcx, Provenance>,
+    dest: &PlaceTy<'tcx, Provenance>,
+) -> InterpResult<'tcx, ()> {
+    let (op, op_len) = this.operand_to_simd(op)?;
+    let (dest, dest_len) = this.place_to_simd(dest)?;
+
+    assert_eq!(dest_len, op_len);
+
+    for i in 0..dest_len {
+        let op = this.read_immediate(&this.project_index(&op, i)?)?;
+        let dest = this.project_index(&dest, i)?;
+
+        let res = unary_op_f32(this, which, &op)?;
+        this.write_scalar(res, &dest)?;
+    }
+
+    Ok(())
+}
diff --git a/src/tools/miri/tests/pass/intrinsics-math.rs b/src/tools/miri/tests/pass/intrinsics-math.rs
index 9f2dc333f33..e0e4f5654d6 100644
--- a/src/tools/miri/tests/pass/intrinsics-math.rs
+++ b/src/tools/miri/tests/pass/intrinsics-math.rs
@@ -1,5 +1,4 @@
-// SPDX-License-Identifier: MIT OR Apache-2.0
-// SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org)
+#![feature(float_gamma)]
 
 macro_rules! assert_approx_eq {
     ($a:expr, $b:expr) => {{
@@ -130,4 +129,20 @@ pub fn main() {
     );
     assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
     assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
+
+    assert_approx_eq!(5.0f32.gamma(), 24.0);
+    assert_approx_eq!(5.0f64.gamma(), 24.0);
+    // These fail even on the host, precision seems to be terrible.
+    //assert_approx_eq!(-0.5f32.gamma(), -2.0 * f32::consts::PI.sqrt());
+    //assert_approx_eq!(-0.5f64.gamma(), -2.0 * f64::consts::PI.sqrt());
+
+    assert_eq!(2.0f32.ln_gamma(), (0.0, 1));
+    assert_eq!(2.0f64.ln_gamma(), (0.0, 1));
+    // Gamma(-0.5) = -2*sqrt(π)
+    let (val, sign) = (-0.5f32).ln_gamma();
+    assert_approx_eq!(val, (2.0 * f32::consts::PI.sqrt()).ln());
+    assert_eq!(sign, -1);
+    let (val, sign) = (-0.5f64).ln_gamma();
+    assert_approx_eq!(val, (2.0 * f64::consts::PI.sqrt()).ln());
+    assert_eq!(sign, -1);
 }
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse.rs b/src/tools/miri/tests/pass/intrinsics-x86-sse.rs
new file mode 100644
index 00000000000..677d7cc030e
--- /dev/null
+++ b/src/tools/miri/tests/pass/intrinsics-x86-sse.rs
@@ -0,0 +1,1075 @@
+//@only-target-x86_64
+
+use std::arch::x86_64::*;
+use std::f32::NAN;
+use std::mem::transmute;
+
+fn main() {
+    assert!(is_x86_feature_detected!("sse"));
+
+    unsafe {
+        test_sse();
+    }
+}
+
+macro_rules! assert_approx_eq {
+    ($a:expr, $b:expr, $eps:expr) => {{
+        let (a, b) = (&$a, &$b);
+        assert!(
+            (*a - *b).abs() < $eps,
+            "assertion failed: `(left !== right)` \
+             (left: `{:?}`, right: `{:?}`, expect diff: `{:?}`, real diff: `{:?}`)",
+            *a,
+            *b,
+            $eps,
+            (*a - *b).abs()
+        );
+    }};
+}
+
+#[target_feature(enable = "sse")]
+unsafe fn test_sse() {
+    // Mostly copied from library/stdarch/crates/core_arch/src/x86{,_64}/sse.rs
+
+    #[target_feature(enable = "sse")]
+    unsafe fn assert_eq_m128(a: __m128, b: __m128) {
+        let r = _mm_cmpeq_ps(a, b);
+        if _mm_movemask_ps(r) != 0b1111 {
+            panic!("{:?} != {:?}", a, b);
+        }
+    }
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_add_ss() {
+        let a = _mm_set_ps(-1.0, 5.0, 0.0, -10.0);
+        let b = _mm_set_ps(-100.0, 20.0, 0.0, -5.0);
+        let r = _mm_add_ss(a, b);
+        assert_eq_m128(r, _mm_set_ps(-1.0, 5.0, 0.0, -15.0));
+    }
+    test_mm_add_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_sub_ss() {
+        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
+        let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
+        let r = _mm_sub_ss(a, b);
+        assert_eq_m128(r, _mm_setr_ps(99.0, 5.0, 0.0, -10.0));
+    }
+    test_mm_sub_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_mul_ss() {
+        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
+        let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
+        let r = _mm_mul_ss(a, b);
+        assert_eq_m128(r, _mm_setr_ps(100.0, 5.0, 0.0, -10.0));
+    }
+    test_mm_mul_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_div_ss() {
+        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
+        let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
+        let r = _mm_div_ss(a, b);
+        assert_eq_m128(r, _mm_setr_ps(0.01, 5.0, 0.0, -10.0));
+    }
+    test_mm_div_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_sqrt_ss() {
+        let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0);
+        let r = _mm_sqrt_ss(a);
+        let e = _mm_setr_ps(2.0, 13.0, 16.0, 100.0);
+        assert_eq_m128(r, e);
+    }
+    test_mm_sqrt_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_sqrt_ps() {
+        let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0);
+        let r = _mm_sqrt_ps(a);
+        let e = _mm_setr_ps(2.0, 3.6055512, 4.0, 10.0);
+        assert_eq_m128(r, e);
+    }
+    test_mm_sqrt_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_rcp_ss() {
+        let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0);
+        let r = _mm_rcp_ss(a);
+        let e = _mm_setr_ps(0.24993896, 13.0, 16.0, 100.0);
+        let rel_err = 0.00048828125;
+
+        let r: [f32; 4] = transmute(r);
+        let e: [f32; 4] = transmute(e);
+        assert_approx_eq!(r[0], e[0], 2. * rel_err);
+        for i in 1..4 {
+            assert_eq!(r[i], e[i]);
+        }
+    }
+    test_mm_rcp_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_rcp_ps() {
+        let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0);
+        let r = _mm_rcp_ps(a);
+        let e = _mm_setr_ps(0.24993896, 0.0769043, 0.06248474, 0.0099983215);
+        let rel_err = 0.00048828125;
+
+        let r: [f32; 4] = transmute(r);
+        let e: [f32; 4] = transmute(e);
+        for i in 0..4 {
+            assert_approx_eq!(r[i], e[i], 2. * rel_err);
+        }
+    }
+    test_mm_rcp_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_rsqrt_ss() {
+        let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0);
+        let r = _mm_rsqrt_ss(a);
+        let e = _mm_setr_ps(0.49987793, 13.0, 16.0, 100.0);
+        let rel_err = 0.00048828125;
+
+        let r: [f32; 4] = transmute(r);
+        let e: [f32; 4] = transmute(e);
+        assert_approx_eq!(r[0], e[0], 2. * rel_err);
+        for i in 1..4 {
+            assert_eq!(r[i], e[i]);
+        }
+    }
+    test_mm_rsqrt_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_rsqrt_ps() {
+        let a = _mm_setr_ps(4.0, 13.0, 16.0, 100.0);
+        let r = _mm_rsqrt_ps(a);
+        let e = _mm_setr_ps(0.49987793, 0.2772827, 0.24993896, 0.099990845);
+        let rel_err = 0.00048828125;
+
+        let r: [f32; 4] = transmute(r);
+        let e: [f32; 4] = transmute(e);
+        for i in 0..4 {
+            assert_approx_eq!(r[i], e[i], 2. * rel_err);
+        }
+    }
+    test_mm_rsqrt_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_min_ss() {
+        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
+        let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
+        let r = _mm_min_ss(a, b);
+        assert_eq_m128(r, _mm_setr_ps(-100.0, 5.0, 0.0, -10.0));
+    }
+    test_mm_min_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_min_ps() {
+        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
+        let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
+        let r = _mm_min_ps(a, b);
+        assert_eq_m128(r, _mm_setr_ps(-100.0, 5.0, 0.0, -10.0));
+
+        // `_mm_min_ps` can **not** be implemented using the `simd_min` rust intrinsic because
+        // the semantics of `simd_min` are different to those of `_mm_min_ps` regarding handling
+        // of `-0.0`.
+        let a = _mm_setr_ps(-0.0, 0.0, 0.0, 0.0);
+        let b = _mm_setr_ps(0.0, 0.0, 0.0, 0.0);
+        let r1: [u8; 16] = transmute(_mm_min_ps(a, b));
+        let r2: [u8; 16] = transmute(_mm_min_ps(b, a));
+        let a: [u8; 16] = transmute(a);
+        let b: [u8; 16] = transmute(b);
+        assert_eq!(r1, b);
+        assert_eq!(r2, a);
+        assert_ne!(a, b); // sanity check that -0.0 is actually present
+    }
+    test_mm_min_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_max_ss() {
+        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
+        let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
+        let r = _mm_max_ss(a, b);
+        assert_eq_m128(r, _mm_setr_ps(-1.0, 5.0, 0.0, -10.0));
+    }
+    test_mm_max_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_max_ps() {
+        let a = _mm_setr_ps(-1.0, 5.0, 0.0, -10.0);
+        let b = _mm_setr_ps(-100.0, 20.0, 0.0, -5.0);
+        let r = _mm_max_ps(a, b);
+        assert_eq_m128(r, _mm_setr_ps(-1.0, 20.0, 0.0, -5.0));
+
+        // `_mm_max_ps` can **not** be implemented using the `simd_max` rust intrinsic because
+        // the semantics of `simd_max` are different to those of `_mm_max_ps` regarding handling
+        // of `-0.0`.
+        let a = _mm_setr_ps(-0.0, 0.0, 0.0, 0.0);
+        let b = _mm_setr_ps(0.0, 0.0, 0.0, 0.0);
+        let r1: [u8; 16] = transmute(_mm_max_ps(a, b));
+        let r2: [u8; 16] = transmute(_mm_max_ps(b, a));
+        let a: [u8; 16] = transmute(a);
+        let b: [u8; 16] = transmute(b);
+        assert_eq!(r1, b);
+        assert_eq!(r2, a);
+        assert_ne!(a, b); // sanity check that -0.0 is actually present
+    }
+    test_mm_max_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpeq_ss() {
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(-1.0, 5.0, 6.0, 7.0);
+        let r: [u32; 4] = transmute(_mm_cmpeq_ss(a, b));
+        let e: [u32; 4] = transmute(_mm_setr_ps(transmute(0u32), 2.0, 3.0, 4.0));
+        assert_eq!(r, e);
+
+        let b2 = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
+        let r2: [u32; 4] = transmute(_mm_cmpeq_ss(a, b2));
+        let e2: [u32; 4] = transmute(_mm_setr_ps(transmute(0xffffffffu32), 2.0, 3.0, 4.0));
+        assert_eq!(r2, e2);
+    }
+    test_mm_cmpeq_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmplt_ss() {
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
+        let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
+        let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0);
+
+        let b1 = 0u32; // a.extract(0) < b.extract(0)
+        let c1 = 0u32; // a.extract(0) < c.extract(0)
+        let d1 = !0u32; // a.extract(0) < d.extract(0)
+
+        let rb: [u32; 4] = transmute(_mm_cmplt_ss(a, b));
+        let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0));
+        assert_eq!(rb, eb);
+
+        let rc: [u32; 4] = transmute(_mm_cmplt_ss(a, c));
+        let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0));
+        assert_eq!(rc, ec);
+
+        let rd: [u32; 4] = transmute(_mm_cmplt_ss(a, d));
+        let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0));
+        assert_eq!(rd, ed);
+    }
+    test_mm_cmplt_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmple_ss() {
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
+        let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
+        let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0);
+
+        let b1 = 0u32; // a.extract(0) <= b.extract(0)
+        let c1 = !0u32; // a.extract(0) <= c.extract(0)
+        let d1 = !0u32; // a.extract(0) <= d.extract(0)
+
+        let rb: [u32; 4] = transmute(_mm_cmple_ss(a, b));
+        let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0));
+        assert_eq!(rb, eb);
+
+        let rc: [u32; 4] = transmute(_mm_cmple_ss(a, c));
+        let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0));
+        assert_eq!(rc, ec);
+
+        let rd: [u32; 4] = transmute(_mm_cmple_ss(a, d));
+        let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0));
+        assert_eq!(rd, ed);
+    }
+    test_mm_cmple_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpgt_ss() {
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
+        let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
+        let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0);
+
+        let b1 = !0u32; // a.extract(0) > b.extract(0)
+        let c1 = 0u32; // a.extract(0) > c.extract(0)
+        let d1 = 0u32; // a.extract(0) > d.extract(0)
+
+        let rb: [u32; 4] = transmute(_mm_cmpgt_ss(a, b));
+        let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0));
+        assert_eq!(rb, eb);
+
+        let rc: [u32; 4] = transmute(_mm_cmpgt_ss(a, c));
+        let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0));
+        assert_eq!(rc, ec);
+
+        let rd: [u32; 4] = transmute(_mm_cmpgt_ss(a, d));
+        let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0));
+        assert_eq!(rd, ed);
+    }
+    test_mm_cmpgt_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpge_ss() {
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
+        let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
+        let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0);
+
+        let b1 = !0u32; // a.extract(0) >= b.extract(0)
+        let c1 = !0u32; // a.extract(0) >= c.extract(0)
+        let d1 = 0u32; // a.extract(0) >= d.extract(0)
+
+        let rb: [u32; 4] = transmute(_mm_cmpge_ss(a, b));
+        let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0));
+        assert_eq!(rb, eb);
+
+        let rc: [u32; 4] = transmute(_mm_cmpge_ss(a, c));
+        let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0));
+        assert_eq!(rc, ec);
+
+        let rd: [u32; 4] = transmute(_mm_cmpge_ss(a, d));
+        let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0));
+        assert_eq!(rd, ed);
+    }
+    test_mm_cmpge_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpneq_ss() {
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
+        let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
+        let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0);
+
+        let b1 = !0u32; // a.extract(0) != b.extract(0)
+        let c1 = 0u32; // a.extract(0) != c.extract(0)
+        let d1 = !0u32; // a.extract(0) != d.extract(0)
+
+        let rb: [u32; 4] = transmute(_mm_cmpneq_ss(a, b));
+        let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0));
+        assert_eq!(rb, eb);
+
+        let rc: [u32; 4] = transmute(_mm_cmpneq_ss(a, c));
+        let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0));
+        assert_eq!(rc, ec);
+
+        let rd: [u32; 4] = transmute(_mm_cmpneq_ss(a, d));
+        let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0));
+        assert_eq!(rd, ed);
+    }
+    test_mm_cmpneq_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpnlt_ss() {
+        // TODO: this test is exactly the same as for `_mm_cmpge_ss`, but there
+        // must be a difference. It may have to do with behavior in the
+        // presence of NaNs (signaling or quiet). If so, we should add tests
+        // for those.
+
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
+        let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
+        let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0);
+
+        let b1 = !0u32; // a.extract(0) >= b.extract(0)
+        let c1 = !0u32; // a.extract(0) >= c.extract(0)
+        let d1 = 0u32; // a.extract(0) >= d.extract(0)
+
+        let rb: [u32; 4] = transmute(_mm_cmpnlt_ss(a, b));
+        let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0));
+        assert_eq!(rb, eb);
+
+        let rc: [u32; 4] = transmute(_mm_cmpnlt_ss(a, c));
+        let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0));
+        assert_eq!(rc, ec);
+
+        let rd: [u32; 4] = transmute(_mm_cmpnlt_ss(a, d));
+        let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0));
+        assert_eq!(rd, ed);
+    }
+    test_mm_cmpnlt_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpnle_ss() {
+        // TODO: this test is exactly the same as for `_mm_cmpgt_ss`, but there
+        // must be a difference. It may have to do with behavior in the
+        // presence
+        // of NaNs (signaling or quiet). If so, we should add tests for those.
+
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
+        let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
+        let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0);
+
+        let b1 = !0u32; // a.extract(0) > b.extract(0)
+        let c1 = 0u32; // a.extract(0) > c.extract(0)
+        let d1 = 0u32; // a.extract(0) > d.extract(0)
+
+        let rb: [u32; 4] = transmute(_mm_cmpnle_ss(a, b));
+        let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0));
+        assert_eq!(rb, eb);
+
+        let rc: [u32; 4] = transmute(_mm_cmpnle_ss(a, c));
+        let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0));
+        assert_eq!(rc, ec);
+
+        let rd: [u32; 4] = transmute(_mm_cmpnle_ss(a, d));
+        let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0));
+        assert_eq!(rd, ed);
+    }
+    test_mm_cmpnle_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpngt_ss() {
+        // TODO: this test is exactly the same as for `_mm_cmple_ss`, but there
+        // must be a difference. It may have to do with behavior in the
+        // presence of NaNs (signaling or quiet). If so, we should add tests
+        // for those.
+
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
+        let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
+        let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0);
+
+        let b1 = 0u32; // a.extract(0) <= b.extract(0)
+        let c1 = !0u32; // a.extract(0) <= c.extract(0)
+        let d1 = !0u32; // a.extract(0) <= d.extract(0)
+
+        let rb: [u32; 4] = transmute(_mm_cmpngt_ss(a, b));
+        let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0));
+        assert_eq!(rb, eb);
+
+        let rc: [u32; 4] = transmute(_mm_cmpngt_ss(a, c));
+        let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0));
+        assert_eq!(rc, ec);
+
+        let rd: [u32; 4] = transmute(_mm_cmpngt_ss(a, d));
+        let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0));
+        assert_eq!(rd, ed);
+    }
+    test_mm_cmpngt_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpnge_ss() {
+        // TODO: this test is exactly the same as for `_mm_cmplt_ss`, but there
+        // must be a difference. It may have to do with behavior in the
+        // presence of NaNs (signaling or quiet). If so, we should add tests
+        // for those.
+
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
+        let c = _mm_setr_ps(1.0, 5.0, 6.0, 7.0);
+        let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0);
+
+        let b1 = 0u32; // a.extract(0) < b.extract(0)
+        let c1 = 0u32; // a.extract(0) < c.extract(0)
+        let d1 = !0u32; // a.extract(0) < d.extract(0)
+
+        let rb: [u32; 4] = transmute(_mm_cmpnge_ss(a, b));
+        let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0));
+        assert_eq!(rb, eb);
+
+        let rc: [u32; 4] = transmute(_mm_cmpnge_ss(a, c));
+        let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0));
+        assert_eq!(rc, ec);
+
+        let rd: [u32; 4] = transmute(_mm_cmpnge_ss(a, d));
+        let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0));
+        assert_eq!(rd, ed);
+    }
+    test_mm_cmpnge_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpord_ss() {
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
+        let c = _mm_setr_ps(NAN, 5.0, 6.0, 7.0);
+        let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0);
+
+        let b1 = !0u32; // a.extract(0) ord b.extract(0)
+        let c1 = 0u32; // a.extract(0) ord c.extract(0)
+        let d1 = !0u32; // a.extract(0) ord d.extract(0)
+
+        let rb: [u32; 4] = transmute(_mm_cmpord_ss(a, b));
+        let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0));
+        assert_eq!(rb, eb);
+
+        let rc: [u32; 4] = transmute(_mm_cmpord_ss(a, c));
+        let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0));
+        assert_eq!(rc, ec);
+
+        let rd: [u32; 4] = transmute(_mm_cmpord_ss(a, d));
+        let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0));
+        assert_eq!(rd, ed);
+    }
+    test_mm_cmpord_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpunord_ss() {
+        let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0);
+        let b = _mm_setr_ps(0.0, 5.0, 6.0, 7.0);
+        let c = _mm_setr_ps(NAN, 5.0, 6.0, 7.0);
+        let d = _mm_setr_ps(2.0, 5.0, 6.0, 7.0);
+
+        let b1 = 0u32; // a.extract(0) unord b.extract(0)
+        let c1 = !0u32; // a.extract(0) unord c.extract(0)
+        let d1 = 0u32; // a.extract(0) unord d.extract(0)
+
+        let rb: [u32; 4] = transmute(_mm_cmpunord_ss(a, b));
+        let eb: [u32; 4] = transmute(_mm_setr_ps(transmute(b1), 2.0, 3.0, 4.0));
+        assert_eq!(rb, eb);
+
+        let rc: [u32; 4] = transmute(_mm_cmpunord_ss(a, c));
+        let ec: [u32; 4] = transmute(_mm_setr_ps(transmute(c1), 2.0, 3.0, 4.0));
+        assert_eq!(rc, ec);
+
+        let rd: [u32; 4] = transmute(_mm_cmpunord_ss(a, d));
+        let ed: [u32; 4] = transmute(_mm_setr_ps(transmute(d1), 2.0, 3.0, 4.0));
+        assert_eq!(rd, ed);
+    }
+    test_mm_cmpunord_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpeq_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
+        let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [fls, fls, tru, fls];
+        let r: [u32; 4] = transmute(_mm_cmpeq_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmpeq_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmplt_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
+        let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [tru, fls, fls, fls];
+        let r: [u32; 4] = transmute(_mm_cmplt_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmplt_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmple_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, 1.0, 4.0);
+        let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [tru, fls, tru, fls];
+        let r: [u32; 4] = transmute(_mm_cmple_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmple_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpgt_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
+        let b = _mm_setr_ps(15.0, 20.0, 1.0, 42.0);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [fls, tru, fls, fls];
+        let r: [u32; 4] = transmute(_mm_cmpgt_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmpgt_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpge_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
+        let b = _mm_setr_ps(15.0, 20.0, 1.0, 42.0);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [fls, tru, tru, fls];
+        let r: [u32; 4] = transmute(_mm_cmpge_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmpge_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpneq_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
+        let b = _mm_setr_ps(15.0, 20.0, 1.0, NAN);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [tru, tru, fls, tru];
+        let r: [u32; 4] = transmute(_mm_cmpneq_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmpneq_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpnlt_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
+        let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [fls, tru, tru, tru];
+        let r: [u32; 4] = transmute(_mm_cmpnlt_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmpnlt_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpnle_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
+        let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [fls, tru, fls, tru];
+        let r: [u32; 4] = transmute(_mm_cmpnle_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmpnle_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpngt_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
+        let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [tru, fls, tru, tru];
+        let r: [u32; 4] = transmute(_mm_cmpngt_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmpngt_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpnge_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, 1.0, NAN);
+        let b = _mm_setr_ps(15.0, 20.0, 1.0, 5.0);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [tru, fls, fls, tru];
+        let r: [u32; 4] = transmute(_mm_cmpnge_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmpnge_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpord_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, NAN, NAN);
+        let b = _mm_setr_ps(15.0, NAN, 1.0, NAN);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [tru, fls, fls, fls];
+        let r: [u32; 4] = transmute(_mm_cmpord_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmpord_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cmpunord_ps() {
+        let a = _mm_setr_ps(10.0, 50.0, NAN, NAN);
+        let b = _mm_setr_ps(15.0, NAN, 1.0, NAN);
+        let tru = !0u32;
+        let fls = 0u32;
+
+        let e = [fls, tru, tru, tru];
+        let r: [u32; 4] = transmute(_mm_cmpunord_ps(a, b));
+        assert_eq!(r, e);
+    }
+    test_mm_cmpunord_ps();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_comieq_ss() {
+        let aa = &[3.0f32, 12.0, 23.0, NAN];
+        let bb = &[3.0f32, 47.5, 1.5, NAN];
+
+        let ee = &[1i32, 0, 0, 0];
+
+        for i in 0..4 {
+            let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0);
+            let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0);
+
+            let r = _mm_comieq_ss(a, b);
+
+            assert_eq!(
+                ee[i], r,
+                "_mm_comieq_ss({:?}, {:?}) = {}, expected: {} (i={})",
+                a, b, r, ee[i], i
+            );
+        }
+    }
+    test_mm_comieq_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_comilt_ss() {
+        let aa = &[3.0f32, 12.0, 23.0, NAN];
+        let bb = &[3.0f32, 47.5, 1.5, NAN];
+
+        let ee = &[0i32, 1, 0, 0];
+
+        for i in 0..4 {
+            let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0);
+            let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0);
+
+            let r = _mm_comilt_ss(a, b);
+
+            assert_eq!(
+                ee[i], r,
+                "_mm_comilt_ss({:?}, {:?}) = {}, expected: {} (i={})",
+                a, b, r, ee[i], i
+            );
+        }
+    }
+    test_mm_comilt_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_comile_ss() {
+        let aa = &[3.0f32, 12.0, 23.0, NAN];
+        let bb = &[3.0f32, 47.5, 1.5, NAN];
+
+        let ee = &[1i32, 1, 0, 0];
+
+        for i in 0..4 {
+            let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0);
+            let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0);
+
+            let r = _mm_comile_ss(a, b);
+
+            assert_eq!(
+                ee[i], r,
+                "_mm_comile_ss({:?}, {:?}) = {}, expected: {} (i={})",
+                a, b, r, ee[i], i
+            );
+        }
+    }
+    test_mm_comile_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_comigt_ss() {
+        let aa = &[3.0f32, 12.0, 23.0, NAN];
+        let bb = &[3.0f32, 47.5, 1.5, NAN];
+
+        let ee = &[1i32, 0, 1, 0];
+
+        for i in 0..4 {
+            let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0);
+            let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0);
+
+            let r = _mm_comige_ss(a, b);
+
+            assert_eq!(
+                ee[i], r,
+                "_mm_comige_ss({:?}, {:?}) = {}, expected: {} (i={})",
+                a, b, r, ee[i], i
+            );
+        }
+    }
+    test_mm_comigt_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_comineq_ss() {
+        let aa = &[3.0f32, 12.0, 23.0, NAN];
+        let bb = &[3.0f32, 47.5, 1.5, NAN];
+
+        let ee = &[0i32, 1, 1, 1];
+
+        for i in 0..4 {
+            let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0);
+            let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0);
+
+            let r = _mm_comineq_ss(a, b);
+
+            assert_eq!(
+                ee[i], r,
+                "_mm_comineq_ss({:?}, {:?}) = {}, expected: {} (i={})",
+                a, b, r, ee[i], i
+            );
+        }
+    }
+    test_mm_comineq_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_ucomieq_ss() {
+        let aa = &[3.0f32, 12.0, 23.0, NAN];
+        let bb = &[3.0f32, 47.5, 1.5, NAN];
+
+        let ee = &[1i32, 0, 0, 0];
+
+        for i in 0..4 {
+            let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0);
+            let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0);
+
+            let r = _mm_ucomieq_ss(a, b);
+
+            assert_eq!(
+                ee[i], r,
+                "_mm_ucomieq_ss({:?}, {:?}) = {}, expected: {} (i={})",
+                a, b, r, ee[i], i
+            );
+        }
+    }
+    test_mm_ucomieq_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_ucomilt_ss() {
+        let aa = &[3.0f32, 12.0, 23.0, NAN];
+        let bb = &[3.0f32, 47.5, 1.5, NAN];
+
+        let ee = &[0i32, 1, 0, 0];
+
+        for i in 0..4 {
+            let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0);
+            let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0);
+
+            let r = _mm_ucomilt_ss(a, b);
+
+            assert_eq!(
+                ee[i], r,
+                "_mm_ucomilt_ss({:?}, {:?}) = {}, expected: {} (i={})",
+                a, b, r, ee[i], i
+            );
+        }
+    }
+    test_mm_ucomilt_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_ucomile_ss() {
+        let aa = &[3.0f32, 12.0, 23.0, NAN];
+        let bb = &[3.0f32, 47.5, 1.5, NAN];
+
+        let ee = &[1i32, 1, 0, 0];
+
+        for i in 0..4 {
+            let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0);
+            let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0);
+
+            let r = _mm_ucomile_ss(a, b);
+
+            assert_eq!(
+                ee[i], r,
+                "_mm_ucomile_ss({:?}, {:?}) = {}, expected: {} (i={})",
+                a, b, r, ee[i], i
+            );
+        }
+    }
+    test_mm_ucomile_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_ucomigt_ss() {
+        let aa = &[3.0f32, 12.0, 23.0, NAN];
+        let bb = &[3.0f32, 47.5, 1.5, NAN];
+
+        let ee = &[0i32, 0, 1, 0];
+
+        for i in 0..4 {
+            let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0);
+            let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0);
+
+            let r = _mm_ucomigt_ss(a, b);
+
+            assert_eq!(
+                ee[i], r,
+                "_mm_ucomigt_ss({:?}, {:?}) = {}, expected: {} (i={})",
+                a, b, r, ee[i], i
+            );
+        }
+    }
+    test_mm_ucomigt_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_ucomige_ss() {
+        let aa = &[3.0f32, 12.0, 23.0, NAN];
+        let bb = &[3.0f32, 47.5, 1.5, NAN];
+
+        let ee = &[1i32, 0, 1, 0];
+
+        for i in 0..4 {
+            let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0);
+            let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0);
+
+            let r = _mm_ucomige_ss(a, b);
+
+            assert_eq!(
+                ee[i], r,
+                "_mm_ucomige_ss({:?}, {:?}) = {}, expected: {} (i={})",
+                a, b, r, ee[i], i
+            );
+        }
+    }
+    test_mm_ucomige_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_ucomineq_ss() {
+        let aa = &[3.0f32, 12.0, 23.0, NAN];
+        let bb = &[3.0f32, 47.5, 1.5, NAN];
+
+        let ee = &[0i32, 1, 1, 1];
+
+        for i in 0..4 {
+            let a = _mm_setr_ps(aa[i], 1.0, 2.0, 3.0);
+            let b = _mm_setr_ps(bb[i], 0.0, 2.0, 4.0);
+
+            let r = _mm_ucomineq_ss(a, b);
+
+            assert_eq!(
+                ee[i], r,
+                "_mm_ucomineq_ss({:?}, {:?}) = {}, expected: {} (i={})",
+                a, b, r, ee[i], i
+            );
+        }
+    }
+    test_mm_ucomineq_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cvtss_si32() {
+        let inputs = &[42.0f32, -3.1, 4.0e10, 4.0e-20, NAN, 2147483500.1];
+        let result = &[42i32, -3, i32::MIN, 0, i32::MIN, 2147483520];
+        for i in 0..inputs.len() {
+            let x = _mm_setr_ps(inputs[i], 1.0, 3.0, 4.0);
+            let e = result[i];
+            let r = _mm_cvtss_si32(x);
+            assert_eq!(e, r, "TestCase #{} _mm_cvtss_si32({:?}) = {}, expected: {}", i, x, r, e);
+        }
+    }
+    test_mm_cvtss_si32();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cvttss_si32() {
+        let inputs = &[
+            (42.0f32, 42i32),
+            (-31.4, -31),
+            (-33.5, -33),
+            (-34.5, -34),
+            (10.999, 10),
+            (-5.99, -5),
+            (4.0e10, i32::MIN),
+            (4.0e-10, 0),
+            (NAN, i32::MIN),
+            (2147483500.1, 2147483520),
+        ];
+        for i in 0..inputs.len() {
+            let (xi, e) = inputs[i];
+            let x = _mm_setr_ps(xi, 1.0, 3.0, 4.0);
+            let r = _mm_cvttss_si32(x);
+            assert_eq!(e, r, "TestCase #{} _mm_cvttss_si32({:?}) = {}, expected: {}", i, x, r, e);
+        }
+    }
+    test_mm_cvttss_si32();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cvtss_f32() {
+        let a = _mm_setr_ps(312.0134, 5.0, 6.0, 7.0);
+        assert_eq!(_mm_cvtss_f32(a), 312.0134);
+    }
+    test_mm_cvtss_f32();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cvtsi32_ss() {
+        let inputs = &[
+            (4555i32, 4555.0f32),
+            (322223333, 322223330.0),
+            (-432, -432.0),
+            (-322223333, -322223330.0),
+        ];
+
+        for i in 0..inputs.len() {
+            let (x, f) = inputs[i];
+            let a = _mm_setr_ps(5.0, 6.0, 7.0, 8.0);
+            let r = _mm_cvtsi32_ss(a, x);
+            let e = _mm_setr_ps(f, 6.0, 7.0, 8.0);
+            assert_eq_m128(e, r);
+        }
+    }
+    test_mm_cvtsi32_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cvtss_si64() {
+        let inputs = &[
+            (42.0f32, 42i64),
+            (-31.4, -31),
+            (-33.5, -34),
+            (-34.5, -34),
+            (4.0e10, 40_000_000_000),
+            (4.0e-10, 0),
+            (f32::NAN, i64::MIN),
+            (2147483500.1, 2147483520),
+            (9.223371e18, 9223370937343148032),
+        ];
+        for i in 0..inputs.len() {
+            let (xi, e) = inputs[i];
+            let x = _mm_setr_ps(xi, 1.0, 3.0, 4.0);
+            let r = _mm_cvtss_si64(x);
+            assert_eq!(e, r, "TestCase #{} _mm_cvtss_si64({:?}) = {}, expected: {}", i, x, r, e);
+        }
+    }
+    test_mm_cvtss_si64();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cvttss_si64() {
+        let inputs = &[
+            (42.0f32, 42i64),
+            (-31.4, -31),
+            (-33.5, -33),
+            (-34.5, -34),
+            (10.999, 10),
+            (-5.99, -5),
+            (4.0e10, 40_000_000_000),
+            (4.0e-10, 0),
+            (f32::NAN, i64::MIN),
+            (2147483500.1, 2147483520),
+            (9.223371e18, 9223370937343148032),
+            (9.223372e18, i64::MIN),
+        ];
+        for i in 0..inputs.len() {
+            let (xi, e) = inputs[i];
+            let x = _mm_setr_ps(xi, 1.0, 3.0, 4.0);
+            let r = _mm_cvttss_si64(x);
+            assert_eq!(e, r, "TestCase #{} _mm_cvttss_si64({:?}) = {}, expected: {}", i, x, r, e);
+        }
+    }
+    test_mm_cvttss_si64();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_cvtsi64_ss() {
+        let inputs = &[
+            (4555i64, 4555.0f32),
+            (322223333, 322223330.0),
+            (-432, -432.0),
+            (-322223333, -322223330.0),
+            (9223372036854775807, 9.223372e18),
+            (-9223372036854775808, -9.223372e18),
+        ];
+
+        for i in 0..inputs.len() {
+            let (x, f) = inputs[i];
+            let a = _mm_setr_ps(5.0, 6.0, 7.0, 8.0);
+            let r = _mm_cvtsi64_ss(a, x);
+            let e = _mm_setr_ps(f, 6.0, 7.0, 8.0);
+            assert_eq_m128(e, r);
+        }
+    }
+    test_mm_cvtsi64_ss();
+
+    #[target_feature(enable = "sse")]
+    unsafe fn test_mm_movemask_ps() {
+        let r = _mm_movemask_ps(_mm_setr_ps(-1.0, 5.0, -5.0, 0.0));
+        assert_eq!(r, 0b0101);
+
+        let r = _mm_movemask_ps(_mm_setr_ps(-1.0, -5.0, -5.0, 0.0));
+        assert_eq!(r, 0b0111);
+    }
+    test_mm_movemask_ps();
+
+    let x = 0i8;
+    _mm_prefetch(&x, _MM_HINT_T0);
+    _mm_prefetch(&x, _MM_HINT_T1);
+    _mm_prefetch(&x, _MM_HINT_T2);
+    _mm_prefetch(&x, _MM_HINT_NTA);
+    _mm_prefetch(&x, _MM_HINT_ET0);
+    _mm_prefetch(&x, _MM_HINT_ET1);
+}
diff --git a/src/tools/opt-dist/src/bolt.rs b/src/tools/opt-dist/src/bolt.rs
index e44b8a4db92..cf9f4fabcec 100644
--- a/src/tools/opt-dist/src/bolt.rs
+++ b/src/tools/opt-dist/src/bolt.rs
@@ -65,8 +65,13 @@ pub fn bolt_optimize(path: &Utf8Path, profile: &LlvmBoltProfile) -> anyhow::Resu
         .arg("-jump-tables=move")
         // Fold functions with identical code
         .arg("-icf=1")
+        // The following flag saves about 50 MiB of libLLVM.so size.
+        // However, it succeeds very non-deterministically. To avoid frequent artifact size swings,
+        // it is kept disabled for now.
+        // FIXME(kobzol): try to re-enable this once BOLT in-place rewriting is merged or after
+        // we bump LLVM.
         // Try to reuse old text segments to reduce binary size
-        .arg("--use-old-text")
+        // .arg("--use-old-text")
         // Update DWARF debug info in the final binary
         .arg("-update-debug-sections")
         // Print optimization statistics
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index f6edd008845..8ab19674d05 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -197,7 +197,7 @@ fn main() -> anyhow::Result<()> {
             "miri",
             "rustfmt",
         ] {
-            build_args.extend(["--exclude".to_string(), target.to_string()]);
+            build_args.extend(["--skip".to_string(), target.to_string()]);
         }
     }
 
diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs
index c85418baecd..3dd1a3223f5 100644
--- a/src/tools/opt-dist/src/tests.rs
+++ b/src/tools/opt-dist/src/tests.rs
@@ -96,7 +96,7 @@ llvm-config = "{llvm_config}"
         "tests/ui",
     ];
     for test_path in env.skipped_tests() {
-        args.extend(["--exclude", test_path]);
+        args.extend(["--skip", test_path]);
     }
     cmd(&args).env("COMPILETEST_FORCE_STAGE0", "1").run().context("Cannot execute tests")
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
index c717a9cb55b..e411c1c869c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
@@ -30,6 +30,8 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[
     "efiapi",
     "avr-interrupt",
     "avr-non-blocking-interrupt",
+    "riscv-interrupt-m",
+    "riscv-interrupt-s",
     "C-cmse-nonsecure-call",
     "wasm",
     "system",
diff --git a/src/tools/tidy/config/black.toml b/src/tools/tidy/config/black.toml
new file mode 100644
index 00000000000..51a722979f5
--- /dev/null
+++ b/src/tools/tidy/config/black.toml
@@ -0,0 +1,15 @@
+[tool.black]
+# Ignore all submodules
+extend-exclude = """(\
+    src/doc/nomicon|\
+    src/tools/cargo/|\
+    src/doc/reference/|\
+    src/doc/book/|\
+    src/doc/rust-by-example/|\
+    library/stdarch/|\
+    src/doc/rustc-dev-guide/|\
+    src/doc/edition-guide/|\
+    src/llvm-project/|\
+    src/doc/embedded-book/|\
+    library/backtrace/
+    )"""
diff --git a/src/tools/tidy/config/requirements.in b/src/tools/tidy/config/requirements.in
new file mode 100644
index 00000000000..882e09dae45
--- /dev/null
+++ b/src/tools/tidy/config/requirements.in
@@ -0,0 +1,10 @@
+# requirements.in This is the source file for our pinned version requirements
+# file "requirements.txt" To regenerate that file, pip-tools is required
+# (`python -m pip install pip-tools`). Once installed, run: `pip-compile
+# --generate-hashes src/tools/tidy/config/requirements.in`
+#
+# Note: this generation step should be run with the oldest supported python
+# version (currently 3.7) to ensure backward compatibility
+
+black==23.3.0
+ruff==0.0.272
diff --git a/src/tools/tidy/config/requirements.txt b/src/tools/tidy/config/requirements.txt
new file mode 100644
index 00000000000..9fd617ad621
--- /dev/null
+++ b/src/tools/tidy/config/requirements.txt
@@ -0,0 +1,117 @@
+#
+# This file is autogenerated by pip-compile with Python 3.11
+# by the following command:
+#
+#    pip-compile --generate-hashes src/tools/tidy/config/requirements.in
+#
+black==23.3.0 \
+    --hash=sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5 \
+    --hash=sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915 \
+    --hash=sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326 \
+    --hash=sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940 \
+    --hash=sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b \
+    --hash=sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30 \
+    --hash=sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c \
+    --hash=sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c \
+    --hash=sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab \
+    --hash=sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27 \
+    --hash=sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2 \
+    --hash=sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961 \
+    --hash=sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9 \
+    --hash=sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb \
+    --hash=sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70 \
+    --hash=sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331 \
+    --hash=sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2 \
+    --hash=sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266 \
+    --hash=sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d \
+    --hash=sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6 \
+    --hash=sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b \
+    --hash=sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925 \
+    --hash=sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8 \
+    --hash=sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4 \
+    --hash=sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3
+    # via -r src/tools/tidy/config/requirements.in
+click==8.1.3 \
+    --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \
+    --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48
+    # via black
+importlib-metadata==6.7.0 \
+    --hash=sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4 \
+    --hash=sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5
+    # via click
+mypy-extensions==1.0.0 \
+    --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \
+    --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782
+    # via black
+packaging==23.1 \
+    --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+    --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+    # via black
+pathspec==0.11.1 \
+    --hash=sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687 \
+    --hash=sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293
+    # via black
+platformdirs==3.6.0 \
+    --hash=sha256:57e28820ca8094678b807ff529196506d7a21e17156cb1cddb3e74cebce54640 \
+    --hash=sha256:ffa199e3fbab8365778c4a10e1fbf1b9cd50707de826eb304b50e57ec0cc8d38
+    # via black
+ruff==0.0.272 \
+    --hash=sha256:06b8ee4eb8711ab119db51028dd9f5384b44728c23586424fd6e241a5b9c4a3b \
+    --hash=sha256:1609b864a8d7ee75a8c07578bdea0a7db75a144404e75ef3162e0042bfdc100d \
+    --hash=sha256:19643d448f76b1eb8a764719072e9c885968971bfba872e14e7257e08bc2f2b7 \
+    --hash=sha256:273a01dc8c3c4fd4c2af7ea7a67c8d39bb09bce466e640dd170034da75d14cab \
+    --hash=sha256:27b2ea68d2aa69fff1b20b67636b1e3e22a6a39e476c880da1282c3e4bf6ee5a \
+    --hash=sha256:48eccf225615e106341a641f826b15224b8a4240b84269ead62f0afd6d7e2d95 \
+    --hash=sha256:677284430ac539bb23421a2b431b4ebc588097ef3ef918d0e0a8d8ed31fea216 \
+    --hash=sha256:691d72a00a99707a4e0b2846690961157aef7b17b6b884f6b4420a9f25cd39b5 \
+    --hash=sha256:86bc788245361a8148ff98667da938a01e1606b28a45e50ac977b09d3ad2c538 \
+    --hash=sha256:905ff8f3d6206ad56fcd70674453527b9011c8b0dc73ead27618426feff6908e \
+    --hash=sha256:9c4bfb75456a8e1efe14c52fcefb89cfb8f2a0d31ed8d804b82c6cf2dc29c42c \
+    --hash=sha256:a37ec80e238ead2969b746d7d1b6b0d31aa799498e9ba4281ab505b93e1f4b28 \
+    --hash=sha256:ae9b57546e118660175d45d264b87e9b4c19405c75b587b6e4d21e6a17bf4fdf \
+    --hash=sha256:bd2bbe337a3f84958f796c77820d55ac2db1e6753f39d1d1baed44e07f13f96d \
+    --hash=sha256:d5a208f8ef0e51d4746930589f54f9f92f84bb69a7d15b1de34ce80a7681bc00 \
+    --hash=sha256:dc406e5d756d932da95f3af082814d2467943631a587339ee65e5a4f4fbe83eb \
+    --hash=sha256:ee76b4f05fcfff37bd6ac209d1370520d509ea70b5a637bdf0a04d0c99e13dff
+    # via -r src/tools/tidy/config/requirements.in
+tomli==2.0.1 \
+    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
+    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
+    # via black
+typed-ast==1.5.4 \
+    --hash=sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2 \
+    --hash=sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1 \
+    --hash=sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6 \
+    --hash=sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62 \
+    --hash=sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac \
+    --hash=sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d \
+    --hash=sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc \
+    --hash=sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2 \
+    --hash=sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97 \
+    --hash=sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35 \
+    --hash=sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6 \
+    --hash=sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1 \
+    --hash=sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4 \
+    --hash=sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c \
+    --hash=sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e \
+    --hash=sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec \
+    --hash=sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f \
+    --hash=sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72 \
+    --hash=sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47 \
+    --hash=sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72 \
+    --hash=sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe \
+    --hash=sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6 \
+    --hash=sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3 \
+    --hash=sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66
+    # via black
+typing-extensions==4.6.3 \
+    --hash=sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26 \
+    --hash=sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5
+    # via
+    #   black
+    #   importlib-metadata
+    #   platformdirs
+zipp==3.15.0 \
+    --hash=sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b \
+    --hash=sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556
+    # via importlib-metadata
diff --git a/src/tools/tidy/config/ruff.toml b/src/tools/tidy/config/ruff.toml
new file mode 100644
index 00000000000..cf08c62648b
--- /dev/null
+++ b/src/tools/tidy/config/ruff.toml
@@ -0,0 +1,41 @@
+# Configuration for ruff python linter, run as part of tidy external tools
+
+# B (bugbear), E (pycodestyle, standard), EXE (executables) F (flakes, standard)
+# ERM for error messages would be beneficial at some point
+select = ["B", "E", "EXE", "F"]
+
+ignore = [
+    "E501", # line-too-long
+    "F403", # undefined-local-with-import-star
+    "F405", # undefined-local-with-import-star-usage
+]
+
+# lowest possible for ruff
+target-version = "py37"
+
+# Ignore all submodules
+extend-exclude = [
+    "src/doc/nomicon/",
+    "src/tools/cargo/",
+    "src/doc/reference/",
+    "src/doc/book/",
+    "src/doc/rust-by-example/",
+    "library/stdarch/",
+    "src/doc/rustc-dev-guide/",
+    "src/doc/edition-guide/",
+    "src/llvm-project/",
+    "src/doc/embedded-book/",
+    "library/backtrace/",
+    # Hack: CI runs from a subdirectory under the main checkout
+    "../src/doc/nomicon/",
+    "../src/tools/cargo/",
+    "../src/doc/reference/",
+    "../src/doc/book/",
+    "../src/doc/rust-by-example/",
+    "../library/stdarch/",
+    "../src/doc/rustc-dev-guide/",
+    "../src/doc/edition-guide/",
+    "../src/llvm-project/",
+    "../src/doc/embedded-book/",
+    "../library/backtrace/",
+]
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 22e9b46347a..a9ab696cdf4 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -113,7 +113,6 @@ const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!());
 /// rustc. Please check with the compiler team before adding an entry.
 const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     // tidy-alphabetical-start
-    "addr2line",
     "adler",
     "ahash",
     "aho-corasick",
diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs
new file mode 100644
index 00000000000..40e75d1d3fa
--- /dev/null
+++ b/src/tools/tidy/src/ext_tool_checks.rs
@@ -0,0 +1,435 @@
+//! Optional checks for file types other than Rust source
+//!
+//! Handles python tool version managment via a virtual environment in
+//! `build/venv`.
+//!
+//! # Functional outline
+//!
+//! 1. Run tidy with an extra option: `--extra-checks=py,shell`,
+//!    `--extra-checks=py:lint`, or similar. Optionally provide specific
+//!    configuration after a double dash (`--extra-checks=py -- foo.py`)
+//! 2. Build configuration based on args/environment:
+//!    - Formatters by default are in check only mode
+//!    - If in CI (TIDY_PRINT_DIFF=1 is set), check and print the diff
+//!    - If `--bless` is provided, formatters may run
+//!    - Pass any additional config after the `--`. If no files are specified,
+//!      use a default.
+//! 3. Print the output of the given command. If it fails and `TIDY_PRINT_DIFF`
+//!    is set, rerun the tool to print a suggestion diff (for e.g. CI)
+
+use std::ffi::OsStr;
+use std::fmt;
+use std::fs;
+use std::io;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+
+/// Minimum python revision is 3.7 for ruff
+const MIN_PY_REV: (u32, u32) = (3, 7);
+const MIN_PY_REV_STR: &str = "≥3.7";
+
+/// Path to find the python executable within a virtual environment
+#[cfg(target_os = "windows")]
+const REL_PY_PATH: &[&str] = &["Scripts", "python3.exe"];
+#[cfg(not(target_os = "windows"))]
+const REL_PY_PATH: &[&str] = &["bin", "python3"];
+
+const RUFF_CONFIG_PATH: &[&str] = &["src", "tools", "tidy", "config", "ruff.toml"];
+const BLACK_CONFIG_PATH: &[&str] = &["src", "tools", "tidy", "config", "black.toml"];
+/// Location within build directory
+const RUFF_CACH_PATH: &[&str] = &["cache", "ruff_cache"];
+const PIP_REQ_PATH: &[&str] = &["src", "tools", "tidy", "config", "requirements.txt"];
+
+pub fn check(
+    root_path: &Path,
+    outdir: &Path,
+    bless: bool,
+    extra_checks: Option<&str>,
+    pos_args: &[String],
+    bad: &mut bool,
+) {
+    if let Err(e) = check_impl(root_path, outdir, bless, extra_checks, pos_args) {
+        tidy_error!(bad, "{e}");
+    }
+}
+
+fn check_impl(
+    root_path: &Path,
+    outdir: &Path,
+    bless: bool,
+    extra_checks: Option<&str>,
+    pos_args: &[String],
+) -> Result<(), Error> {
+    let show_diff = std::env::var("TIDY_PRINT_DIFF")
+        .map_or(false, |v| v.eq_ignore_ascii_case("true") || v == "1");
+
+    // Split comma-separated args up
+    let lint_args = match extra_checks {
+        Some(s) => s.strip_prefix("--extra-checks=").unwrap().split(',').collect(),
+        None => vec![],
+    };
+
+    let python_all = lint_args.contains(&"py");
+    let python_lint = lint_args.contains(&"py:lint") || python_all;
+    let python_fmt = lint_args.contains(&"py:fmt") || python_all;
+    let shell_all = lint_args.contains(&"shell");
+    let shell_lint = lint_args.contains(&"shell:lint") || shell_all;
+
+    let mut py_path = None;
+
+    let (cfg_args, file_args): (Vec<_>, Vec<_>) = pos_args
+        .into_iter()
+        .map(OsStr::new)
+        .partition(|arg| arg.to_str().is_some_and(|s| s.starts_with("-")));
+
+    if python_lint || python_fmt {
+        let venv_path = outdir.join("venv");
+        let mut reqs_path = root_path.to_owned();
+        reqs_path.extend(PIP_REQ_PATH);
+        py_path = Some(get_or_create_venv(&venv_path, &reqs_path)?);
+    }
+
+    if python_lint {
+        eprintln!("linting python files");
+        let mut cfg_args_ruff = cfg_args.clone();
+        let mut file_args_ruff = file_args.clone();
+
+        let mut cfg_path = root_path.to_owned();
+        cfg_path.extend(RUFF_CONFIG_PATH);
+        let mut cache_dir = outdir.to_owned();
+        cache_dir.extend(RUFF_CACH_PATH);
+
+        cfg_args_ruff.extend([
+            "--config".as_ref(),
+            cfg_path.as_os_str(),
+            "--cache-dir".as_ref(),
+            cache_dir.as_os_str(),
+        ]);
+
+        if file_args_ruff.is_empty() {
+            file_args_ruff.push(root_path.as_os_str());
+        }
+
+        let mut args = merge_args(&cfg_args_ruff, &file_args_ruff);
+        let res = py_runner(py_path.as_ref().unwrap(), "ruff", &args);
+
+        if res.is_err() && show_diff {
+            eprintln!("\npython linting failed! Printing diff suggestions:");
+
+            args.insert(0, "--diff".as_ref());
+            let _ = py_runner(py_path.as_ref().unwrap(), "ruff", &args);
+        }
+        // Rethrow error
+        let _ = res?;
+    }
+
+    if python_fmt {
+        let mut cfg_args_black = cfg_args.clone();
+        let mut file_args_black = file_args.clone();
+
+        if bless {
+            eprintln!("formatting python files");
+        } else {
+            eprintln!("checking python file formatting");
+            cfg_args_black.push("--check".as_ref());
+        }
+
+        let mut cfg_path = root_path.to_owned();
+        cfg_path.extend(BLACK_CONFIG_PATH);
+
+        cfg_args_black.extend(["--config".as_ref(), cfg_path.as_os_str()]);
+
+        if file_args_black.is_empty() {
+            file_args_black.push(root_path.as_os_str());
+        }
+
+        let mut args = merge_args(&cfg_args_black, &file_args_black);
+        let res = py_runner(py_path.as_ref().unwrap(), "black", &args);
+
+        if res.is_err() && show_diff {
+            eprintln!("\npython formatting does not match! Printing diff:");
+
+            args.insert(0, "--diff".as_ref());
+            let _ = py_runner(py_path.as_ref().unwrap(), "black", &args);
+        }
+        // Rethrow error
+        let _ = res?;
+    }
+
+    if shell_lint {
+        eprintln!("linting shell files");
+
+        let mut file_args_shc = file_args.clone();
+        let files;
+        if file_args_shc.is_empty() {
+            files = find_with_extension(root_path, "sh")?;
+            file_args_shc.extend(files.iter().map(|p| p.as_os_str()));
+        }
+
+        shellcheck_runner(&merge_args(&cfg_args, &file_args_shc))?;
+    }
+
+    Ok(())
+}
+
+/// Helper to create `cfg1 cfg2 -- file1 file2` output
+fn merge_args<'a>(cfg_args: &[&'a OsStr], file_args: &[&'a OsStr]) -> Vec<&'a OsStr> {
+    let mut args = cfg_args.to_owned();
+    args.push("--".as_ref());
+    args.extend(file_args);
+    args
+}
+
+/// Run a python command with given arguments. `py_path` should be a virtualenv.
+fn py_runner(py_path: &Path, bin: &'static str, args: &[&OsStr]) -> Result<(), Error> {
+    let status = Command::new(py_path).arg("-m").arg(bin).args(args).status()?;
+    if status.success() { Ok(()) } else { Err(Error::FailedCheck(bin)) }
+}
+
+/// Create a virtuaenv at a given path if it doesn't already exist, or validate
+/// the install if it does. Returns the path to that venv's python executable.
+fn get_or_create_venv(venv_path: &Path, src_reqs_path: &Path) -> Result<PathBuf, Error> {
+    let mut should_create = true;
+    let dst_reqs_path = venv_path.join("requirements.txt");
+    let mut py_path = venv_path.to_owned();
+    py_path.extend(REL_PY_PATH);
+
+    if let Ok(req) = fs::read_to_string(&dst_reqs_path) {
+        if req == fs::read_to_string(src_reqs_path)? {
+            // found existing environment
+            should_create = false;
+        } else {
+            eprintln!("requirements.txt file mismatch, recreating environment");
+        }
+    }
+
+    if should_create {
+        eprintln!("removing old virtual environment");
+        if venv_path.is_dir() {
+            fs::remove_dir_all(venv_path).unwrap_or_else(|_| {
+                panic!("failed to remove directory at {}", venv_path.display())
+            });
+        }
+        create_venv_at_path(venv_path)?;
+        install_requirements(&py_path, src_reqs_path, &dst_reqs_path)?;
+    }
+
+    verify_py_version(&py_path)?;
+    Ok(py_path)
+}
+
+/// Attempt to create a virtualenv at this path. Cycles through all expected
+/// valid python versions to find one that is installed.
+fn create_venv_at_path(path: &Path) -> Result<(), Error> {
+    /// Preferred python versions in order. Newest to oldest then current
+    /// development versions
+    const TRY_PY: &[&str] = &[
+        "python3.11",
+        "python3.10",
+        "python3.9",
+        "python3.8",
+        "python3.7",
+        "python3",
+        "python",
+        "python3.12",
+        "python3.13",
+    ];
+
+    let mut sys_py = None;
+    let mut found = Vec::new();
+
+    for py in TRY_PY {
+        match verify_py_version(Path::new(py)) {
+            Ok(_) => {
+                sys_py = Some(*py);
+                break;
+            }
+            // Skip not found errors
+            Err(Error::Io(e)) if e.kind() == io::ErrorKind::NotFound => (),
+            // Skip insufficient version errors
+            Err(Error::Version { installed, .. }) => found.push(installed),
+            // just log and skip unrecognized errors
+            Err(e) => eprintln!("note: error running '{py}': {e}"),
+        }
+    }
+
+    let Some(sys_py) = sys_py else {
+        let ret = if found.is_empty() {
+            Error::MissingReq("python3", "python file checks", None)
+        } else {
+            found.sort();
+            found.dedup();
+            Error::Version {
+                program: "python3",
+                required: MIN_PY_REV_STR,
+                installed: found.join(", "),
+            }
+        };
+        return Err(ret);
+    };
+
+    eprintln!("creating virtual environment at '{}' using '{sys_py}'", path.display());
+    let out = Command::new(sys_py).args(["-m", "virtualenv"]).arg(path).output().unwrap();
+
+    if out.status.success() {
+        return Ok(());
+    }
+    let err = if String::from_utf8_lossy(&out.stderr).contains("No module named virtualenv") {
+        Error::Generic(format!(
+            "virtualenv not found: you may need to install it \
+                               (`python3 -m pip install venv`)"
+        ))
+    } else {
+        Error::Generic(format!("failed to create venv at '{}' using {sys_py}", path.display()))
+    };
+    Err(err)
+}
+
+/// Parse python's version output (`Python x.y.z`) and ensure we have a
+/// suitable version.
+fn verify_py_version(py_path: &Path) -> Result<(), Error> {
+    let out = Command::new(py_path).arg("--version").output()?;
+    let outstr = String::from_utf8_lossy(&out.stdout);
+    let vers = outstr.trim().split_ascii_whitespace().nth(1).unwrap().trim();
+    let mut vers_comps = vers.split('.');
+    let major: u32 = vers_comps.next().unwrap().parse().unwrap();
+    let minor: u32 = vers_comps.next().unwrap().parse().unwrap();
+
+    if (major, minor) < MIN_PY_REV {
+        Err(Error::Version {
+            program: "python",
+            required: MIN_PY_REV_STR,
+            installed: vers.to_owned(),
+        })
+    } else {
+        Ok(())
+    }
+}
+
+fn install_requirements(
+    py_path: &Path,
+    src_reqs_path: &Path,
+    dst_reqs_path: &Path,
+) -> Result<(), Error> {
+    let stat = Command::new(py_path)
+        .args(["-m", "pip", "install", "--upgrade", "pip"])
+        .status()
+        .expect("failed to launch pip");
+    if !stat.success() {
+        return Err(Error::Generic(format!("pip install failed with status {stat}")));
+    }
+
+    let stat = Command::new(py_path)
+        .args(["-m", "pip", "install", "--require-hashes", "-r"])
+        .arg(src_reqs_path)
+        .status()?;
+    if !stat.success() {
+        return Err(Error::Generic(format!(
+            "failed to install requirements at {}",
+            src_reqs_path.display()
+        )));
+    }
+    fs::copy(src_reqs_path, dst_reqs_path)?;
+    assert_eq!(
+        fs::read_to_string(src_reqs_path).unwrap(),
+        fs::read_to_string(dst_reqs_path).unwrap()
+    );
+    Ok(())
+}
+
+/// Check that shellcheck is installed then run it at the given path
+fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> {
+    match Command::new("shellcheck").arg("--version").status() {
+        Ok(_) => (),
+        Err(e) if e.kind() == io::ErrorKind::NotFound => {
+            return Err(Error::MissingReq(
+                "shellcheck",
+                "shell file checks",
+                Some(
+                    "see <https://github.com/koalaman/shellcheck#installing> \
+                    for installation instructions"
+                        .to_owned(),
+                ),
+            ));
+        }
+        Err(e) => return Err(e.into()),
+    }
+
+    let status = Command::new("shellcheck").args(args).status()?;
+    if status.success() { Ok(()) } else { Err(Error::FailedCheck("black")) }
+}
+
+/// Check git for tracked files matching an extension
+fn find_with_extension(root_path: &Path, extension: &str) -> Result<Vec<PathBuf>, Error> {
+    // Untracked files show up for short status and are indicated with a leading `?`
+    // -C changes git to be as if run from that directory
+    let stat_output =
+        Command::new("git").arg("-C").arg(root_path).args(["status", "--short"]).output()?.stdout;
+
+    if String::from_utf8_lossy(&stat_output).lines().filter(|ln| ln.starts_with('?')).count() > 0 {
+        eprintln!("found untracked files, ignoring");
+    }
+
+    let mut output = Vec::new();
+    let binding = Command::new("git").arg("-C").arg(root_path).args(["ls-files"]).output()?;
+    let tracked = String::from_utf8_lossy(&binding.stdout);
+
+    for line in tracked.lines() {
+        let line = line.trim();
+        let path = Path::new(line);
+
+        if path.extension() == Some(OsStr::new(extension)) {
+            output.push(path.to_owned());
+        }
+    }
+
+    Ok(output)
+}
+
+#[derive(Debug)]
+enum Error {
+    Io(io::Error),
+    /// a is required to run b. c is extra info
+    MissingReq(&'static str, &'static str, Option<String>),
+    /// Tool x failed the check
+    FailedCheck(&'static str),
+    /// Any message, just print it
+    Generic(String),
+    /// Installed but wrong version
+    Version {
+        program: &'static str,
+        required: &'static str,
+        installed: String,
+    },
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::MissingReq(a, b, ex) => {
+                write!(
+                    f,
+                    "{a} is required to run {b} but it could not be located. Is it installed?"
+                )?;
+                if let Some(s) = ex {
+                    write!(f, "\n{s}")?;
+                };
+                Ok(())
+            }
+            Self::Version { program, required, installed } => write!(
+                f,
+                "insufficient version of '{program}' to run external tools: \
+                {required} required but found {installed}",
+            ),
+            Self::Generic(s) => f.write_str(s),
+            Self::Io(e) => write!(f, "IO error: {e}"),
+            Self::FailedCheck(s) => write!(f, "checks with external tool '{s}' failed"),
+        }
+    }
+}
+
+impl From<io::Error> for Error {
+    fn from(value: io::Error) -> Self {
+        Self::Io(value)
+    }
+}
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index e467514a7a3..9b19b8eecc7 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -57,6 +57,7 @@ pub mod debug_artifacts;
 pub mod deps;
 pub mod edition;
 pub mod error_codes;
+pub mod ext_tool_checks;
 pub mod extdeps;
 pub mod features;
 pub mod fluent_alphabetical;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index e21068490b6..5fa91715a07 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -37,9 +37,14 @@ fn main() {
     let librustdoc_path = src_path.join("librustdoc");
 
     let args: Vec<String> = env::args().skip(1).collect();
-
-    let verbose = args.iter().any(|s| *s == "--verbose");
-    let bless = args.iter().any(|s| *s == "--bless");
+    let (cfg_args, pos_args) = match args.iter().position(|arg| arg == "--") {
+        Some(pos) => (&args[..pos], &args[pos + 1..]),
+        None => (&args[..], [].as_slice()),
+    };
+    let verbose = cfg_args.iter().any(|s| *s == "--verbose");
+    let bless = cfg_args.iter().any(|s| *s == "--bless");
+    let extra_checks =
+        cfg_args.iter().find(|s| s.starts_with("--extra-checks=")).map(String::as_str);
 
     let bad = std::sync::Arc::new(AtomicBool::new(false));
 
@@ -150,6 +155,8 @@ fn main() {
             r
         };
         check!(unstable_book, &src_path, collected);
+
+        check!(ext_tool_checks, &root_path, &output_directory, bless, extra_checks, pos_args);
     });
 
     if bad.load(Ordering::Relaxed) {
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index b386b000bef..3a4d9c53d7b 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -52,6 +52,7 @@ const EXCEPTION_PATHS: &[&str] = &[
     // FIXME: platform-specific code should be moved to `sys`
     "library/std/src/io/copy.rs",
     "library/std/src/io/stdio.rs",
+    "library/std/src/lib.rs", // for miniz_oxide leaking docs, which itself workaround
     "library/std/src/path.rs",
     "library/std/src/sys_common", // Should only contain abstractions over platforms
     "library/std/src/net/test.rs", // Utility helpers for tests