Rollup merge of #147783 - durin42:object-unification, r=Zalathar

bootstrap: migrate to object 0.37

I noticed we had a mix of 0.37 and 0.36 at work, and this was why. As far as I can tell everything still builds and works correctly.
diff --git a/Cargo.lock b/Cargo.lock
index 018d03e..bcb7dd1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -645,6 +645,7 @@
 dependencies = [
  "clippy_config",
  "clippy_utils",
+ "itertools",
  "regex",
  "rustc-semver",
 ]
@@ -1164,7 +1165,7 @@
  "libc",
  "option-ext",
  "redox_users 0.5.2",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
@@ -2106,9 +2107,9 @@
 
 [[package]]
 name = "libffi"
-version = "4.1.1"
+version = "5.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7681c6fab541f799a829e44a445a0666cf8d8a6cfebf89419e6aed52c604e87"
+checksum = "0444124f3ffd67e1b0b0c661a7f81a278a135eb54aaad4078e79fbc8be50c8a5"
 dependencies = [
  "libc",
  "libffi-sys",
@@ -2116,9 +2117,9 @@
 
 [[package]]
 name = "libffi-sys"
-version = "3.3.2"
+version = "4.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b0d828d367b4450ed08e7d510dc46636cd660055f50d67ac943bfe788767c29"
+checksum = "3d722da8817ea580d0669da6babe2262d7b86a1af1103da24102b8bb9c101ce7"
 dependencies = [
  "cc",
 ]
@@ -2374,7 +2375,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "536bfad37a309d62069485248eeaba1e8d9853aaf951caaeaed0585a95346f08"
 dependencies = [
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
@@ -5262,9 +5263,9 @@
 
 [[package]]
 name = "stringdex"
-version = "0.0.1-alpha10"
+version = "0.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa846a7d509d1828a4f90962dc09810e161abcada7fc6a921e92c168d0811d7"
+checksum = "18b3bd4f10d15ef859c40291769f0d85209de6b0f1c30713ff9cdf45ac43ea36"
 dependencies = [
  "stacker",
 ]
diff --git a/compiler/rustc_ast_lowering/src/contract.rs b/compiler/rustc_ast_lowering/src/contract.rs
new file mode 100644
index 0000000..2f1c3d6
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/contract.rs
@@ -0,0 +1,324 @@
+use thin_vec::thin_vec;
+
+use crate::LoweringContext;
+
+impl<'a, 'hir> LoweringContext<'a, 'hir> {
+    /// Lowered contracts are guarded with the `contract_checks` compiler flag,
+    /// i.e. the flag turns into a boolean guard in the lowered HIR. The reason
+    /// for not eliminating the contract code entirely when the `contract_checks`
+    /// flag is disabled is so that contracts can be type checked, even when
+    /// they are disabled, which avoids them becoming stale (i.e. out of sync
+    /// with the codebase) over time.
+    ///
+    /// The optimiser should be able to eliminate all contract code guarded
+    /// by `if false`, leaving the original body intact when runtime contract
+    /// checks are disabled.
+    pub(super) fn lower_contract(
+        &mut self,
+        body: impl FnOnce(&mut Self) -> rustc_hir::Expr<'hir>,
+        contract: &rustc_ast::FnContract,
+    ) -> rustc_hir::Expr<'hir> {
+        match (&contract.requires, &contract.ensures) {
+            (Some(req), Some(ens)) => {
+                // Lower the fn contract, which turns:
+                //
+                // { body }
+                //
+                // into:
+                //
+                // let __postcond = if contract_checks {
+                //     contract_check_requires(PRECOND);
+                //     Some(|ret_val| POSTCOND)
+                // } else {
+                //     None
+                // };
+                // {
+                //     let ret = { body };
+                //
+                //     if contract_checks {
+                //         contract_check_ensures(__postcond, ret)
+                //     } else {
+                //         ret
+                //     }
+                // }
+
+                let precond = self.lower_precond(req);
+                let postcond_checker = self.lower_postcond_checker(ens);
+
+                let contract_check =
+                    self.lower_contract_check_with_postcond(Some(precond), postcond_checker);
+
+                let wrapped_body =
+                    self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span);
+                self.expr_block(wrapped_body)
+            }
+            (None, Some(ens)) => {
+                // Lower the fn contract, which turns:
+                //
+                // { body }
+                //
+                // into:
+                //
+                // let __postcond = if contract_checks {
+                //     Some(|ret_val| POSTCOND)
+                // } else {
+                //     None
+                // };
+                // {
+                //     let ret = { body };
+                //
+                //     if contract_checks {
+                //         contract_check_ensures(__postcond, ret)
+                //     } else {
+                //         ret
+                //     }
+                // }
+
+                let postcond_checker = self.lower_postcond_checker(ens);
+                let contract_check =
+                    self.lower_contract_check_with_postcond(None, postcond_checker);
+
+                let wrapped_body =
+                    self.wrap_body_with_contract_check(body, contract_check, postcond_checker.span);
+                self.expr_block(wrapped_body)
+            }
+            (Some(req), None) => {
+                // Lower the fn contract, which turns:
+                //
+                // { body }
+                //
+                // into:
+                //
+                // {
+                //      if contracts_checks {
+                //          contract_requires(PRECOND);
+                //      }
+                //      body
+                // }
+                let precond = self.lower_precond(req);
+                let precond_check = self.lower_contract_check_just_precond(precond);
+
+                let body = self.arena.alloc(body(self));
+
+                // Flatten the body into precond check, then body.
+                let wrapped_body = self.block_all(
+                    body.span,
+                    self.arena.alloc_from_iter([precond_check].into_iter()),
+                    Some(body),
+                );
+                self.expr_block(wrapped_body)
+            }
+            (None, None) => body(self),
+        }
+    }
+
+    /// Lower the precondition check intrinsic.
+    fn lower_precond(&mut self, req: &Box<rustc_ast::Expr>) -> rustc_hir::Stmt<'hir> {
+        let lowered_req = self.lower_expr_mut(&req);
+        let req_span = self.mark_span_with_reason(
+            rustc_span::DesugaringKind::Contract,
+            lowered_req.span,
+            None,
+        );
+        let precond = self.expr_call_lang_item_fn_mut(
+            req_span,
+            rustc_hir::LangItem::ContractCheckRequires,
+            &*arena_vec![self; lowered_req],
+        );
+        self.stmt_expr(req.span, precond)
+    }
+
+    fn lower_postcond_checker(
+        &mut self,
+        ens: &Box<rustc_ast::Expr>,
+    ) -> &'hir rustc_hir::Expr<'hir> {
+        let ens_span = self.lower_span(ens.span);
+        let ens_span =
+            self.mark_span_with_reason(rustc_span::DesugaringKind::Contract, ens_span, None);
+        let lowered_ens = self.lower_expr_mut(&ens);
+        self.expr_call_lang_item_fn(
+            ens_span,
+            rustc_hir::LangItem::ContractBuildCheckEnsures,
+            &*arena_vec![self; lowered_ens],
+        )
+    }
+
+    fn lower_contract_check_just_precond(
+        &mut self,
+        precond: rustc_hir::Stmt<'hir>,
+    ) -> rustc_hir::Stmt<'hir> {
+        let stmts = self.arena.alloc_from_iter([precond].into_iter());
+
+        let then_block_stmts = self.block_all(precond.span, stmts, None);
+        let then_block = self.arena.alloc(self.expr_block(&then_block_stmts));
+
+        let precond_check = rustc_hir::ExprKind::If(
+            self.arena.alloc(self.expr_bool_literal(precond.span, self.tcx.sess.contract_checks())),
+            then_block,
+            None,
+        );
+
+        let precond_check = self.expr(precond.span, precond_check);
+        self.stmt_expr(precond.span, precond_check)
+    }
+
+    fn lower_contract_check_with_postcond(
+        &mut self,
+        precond: Option<rustc_hir::Stmt<'hir>>,
+        postcond_checker: &'hir rustc_hir::Expr<'hir>,
+    ) -> &'hir rustc_hir::Expr<'hir> {
+        let stmts = self.arena.alloc_from_iter(precond.into_iter());
+        let span = match precond {
+            Some(precond) => precond.span,
+            None => postcond_checker.span,
+        };
+
+        let postcond_checker = self.arena.alloc(self.expr_enum_variant_lang_item(
+            postcond_checker.span,
+            rustc_hir::lang_items::LangItem::OptionSome,
+            &*arena_vec![self; *postcond_checker],
+        ));
+        let then_block_stmts = self.block_all(span, stmts, Some(postcond_checker));
+        let then_block = self.arena.alloc(self.expr_block(&then_block_stmts));
+
+        let none_expr = self.arena.alloc(self.expr_enum_variant_lang_item(
+            postcond_checker.span,
+            rustc_hir::lang_items::LangItem::OptionNone,
+            Default::default(),
+        ));
+        let else_block = self.block_expr(none_expr);
+        let else_block = self.arena.alloc(self.expr_block(else_block));
+
+        let contract_check = rustc_hir::ExprKind::If(
+            self.arena.alloc(self.expr_bool_literal(span, self.tcx.sess.contract_checks())),
+            then_block,
+            Some(else_block),
+        );
+        self.arena.alloc(self.expr(span, contract_check))
+    }
+
+    fn wrap_body_with_contract_check(
+        &mut self,
+        body: impl FnOnce(&mut Self) -> rustc_hir::Expr<'hir>,
+        contract_check: &'hir rustc_hir::Expr<'hir>,
+        postcond_span: rustc_span::Span,
+    ) -> &'hir rustc_hir::Block<'hir> {
+        let check_ident: rustc_span::Ident =
+            rustc_span::Ident::from_str_and_span("__ensures_checker", postcond_span);
+        let (check_hir_id, postcond_decl) = {
+            // Set up the postcondition `let` statement.
+            let (checker_pat, check_hir_id) = self.pat_ident_binding_mode_mut(
+                postcond_span,
+                check_ident,
+                rustc_hir::BindingMode::NONE,
+            );
+            (
+                check_hir_id,
+                self.stmt_let_pat(
+                    None,
+                    postcond_span,
+                    Some(contract_check),
+                    self.arena.alloc(checker_pat),
+                    rustc_hir::LocalSource::Contract,
+                ),
+            )
+        };
+
+        // Install contract_ensures so we will intercept `return` statements,
+        // then lower the body.
+        self.contract_ensures = Some((postcond_span, check_ident, check_hir_id));
+        let body = self.arena.alloc(body(self));
+
+        // Finally, inject an ensures check on the implicit return of the body.
+        let body = self.inject_ensures_check(body, postcond_span, check_ident, check_hir_id);
+
+        // Flatten the body into precond, then postcond, then wrapped body.
+        let wrapped_body = self.block_all(
+            body.span,
+            self.arena.alloc_from_iter([postcond_decl].into_iter()),
+            Some(body),
+        );
+        wrapped_body
+    }
+
+    /// Create an `ExprKind::Ret` that is optionally wrapped by a call to check
+    /// a contract ensures clause, if it exists.
+    pub(super) fn checked_return(
+        &mut self,
+        opt_expr: Option<&'hir rustc_hir::Expr<'hir>>,
+    ) -> rustc_hir::ExprKind<'hir> {
+        let checked_ret =
+            if let Some((check_span, check_ident, check_hir_id)) = self.contract_ensures {
+                let expr = opt_expr.unwrap_or_else(|| self.expr_unit(check_span));
+                Some(self.inject_ensures_check(expr, check_span, check_ident, check_hir_id))
+            } else {
+                opt_expr
+            };
+        rustc_hir::ExprKind::Ret(checked_ret)
+    }
+
+    /// Wraps an expression with a call to the ensures check before it gets returned.
+    pub(super) fn inject_ensures_check(
+        &mut self,
+        expr: &'hir rustc_hir::Expr<'hir>,
+        span: rustc_span::Span,
+        cond_ident: rustc_span::Ident,
+        cond_hir_id: rustc_hir::HirId,
+    ) -> &'hir rustc_hir::Expr<'hir> {
+        // {
+        //     let ret = { body };
+        //
+        //     if contract_checks {
+        //         contract_check_ensures(__postcond, ret)
+        //     } else {
+        //         ret
+        //     }
+        // }
+        let ret_ident: rustc_span::Ident = rustc_span::Ident::from_str_and_span("__ret", span);
+
+        // Set up the return `let` statement.
+        let (ret_pat, ret_hir_id) =
+            self.pat_ident_binding_mode_mut(span, ret_ident, rustc_hir::BindingMode::NONE);
+
+        let ret_stmt = self.stmt_let_pat(
+            None,
+            span,
+            Some(expr),
+            self.arena.alloc(ret_pat),
+            rustc_hir::LocalSource::Contract,
+        );
+
+        let ret = self.expr_ident(span, ret_ident, ret_hir_id);
+
+        let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id);
+        let contract_check = self.expr_call_lang_item_fn_mut(
+            span,
+            rustc_hir::LangItem::ContractCheckEnsures,
+            arena_vec![self; *cond_fn, *ret],
+        );
+        let contract_check = self.arena.alloc(contract_check);
+        let call_expr = self.block_expr_block(contract_check);
+
+        // same ident can't be used in 2 places, so we create a new one for the
+        // else branch
+        let ret = self.expr_ident(span, ret_ident, ret_hir_id);
+        let ret_block = self.block_expr_block(ret);
+
+        let contracts_enabled: rustc_hir::Expr<'_> =
+            self.expr_bool_literal(span, self.tcx.sess.contract_checks());
+        let contract_check = self.arena.alloc(self.expr(
+            span,
+            rustc_hir::ExprKind::If(
+                self.arena.alloc(contracts_enabled),
+                call_expr,
+                Some(ret_block),
+            ),
+        ));
+
+        let attrs: rustc_ast::AttrVec = thin_vec![self.unreachable_code_attr(span)];
+        self.lower_attrs(contract_check.hir_id, &attrs, span, rustc_hir::Target::Expression);
+
+        let ret_block = self.block_all(span, arena_vec![self; ret_stmt], Some(contract_check));
+        self.arena.alloc(self.expr_block(self.arena.alloc(ret_block)))
+    }
+}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index bb6b25b..4a9b9f5 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -383,36 +383,6 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
         })
     }
 
-    /// Create an `ExprKind::Ret` that is optionally wrapped by a call to check
-    /// a contract ensures clause, if it exists.
-    fn checked_return(&mut self, opt_expr: Option<&'hir hir::Expr<'hir>>) -> hir::ExprKind<'hir> {
-        let checked_ret =
-            if let Some((check_span, check_ident, check_hir_id)) = self.contract_ensures {
-                let expr = opt_expr.unwrap_or_else(|| self.expr_unit(check_span));
-                Some(self.inject_ensures_check(expr, check_span, check_ident, check_hir_id))
-            } else {
-                opt_expr
-            };
-        hir::ExprKind::Ret(checked_ret)
-    }
-
-    /// Wraps an expression with a call to the ensures check before it gets returned.
-    pub(crate) fn inject_ensures_check(
-        &mut self,
-        expr: &'hir hir::Expr<'hir>,
-        span: Span,
-        cond_ident: Ident,
-        cond_hir_id: HirId,
-    ) -> &'hir hir::Expr<'hir> {
-        let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id);
-        let call_expr = self.expr_call_lang_item_fn_mut(
-            span,
-            hir::LangItem::ContractCheckEnsures,
-            arena_vec![self; *cond_fn, *expr],
-        );
-        self.arena.alloc(call_expr)
-    }
-
     pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
         self.with_new_scopes(c.value.span, |this| {
             let def_id = this.local_def_id(c.id);
@@ -1971,16 +1941,7 @@ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir>
             )
         };
 
-        // `#[allow(unreachable_code)]`
-        let attr = attr::mk_attr_nested_word(
-            &self.tcx.sess.psess.attr_id_generator,
-            AttrStyle::Outer,
-            Safety::Default,
-            sym::allow,
-            sym::unreachable_code,
-            try_span,
-        );
-        let attrs: AttrVec = thin_vec![attr];
+        let attrs: AttrVec = thin_vec![self.unreachable_code_attr(try_span)];
 
         // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
         let continue_arm = {
@@ -2120,7 +2081,7 @@ fn expr_mut_addr_of(&mut self, span: Span, e: &'hir hir::Expr<'hir>) -> hir::Exp
         self.expr(span, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e))
     }
 
-    fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
+    pub(super) fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
         self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[])))
     }
 
@@ -2161,6 +2122,43 @@ pub(super) fn expr_call_mut(
         self.expr(span, hir::ExprKind::Call(e, args))
     }
 
+    pub(super) fn expr_struct(
+        &mut self,
+        span: Span,
+        path: &'hir hir::QPath<'hir>,
+        fields: &'hir [hir::ExprField<'hir>],
+    ) -> hir::Expr<'hir> {
+        self.expr(span, hir::ExprKind::Struct(path, fields, rustc_hir::StructTailExpr::None))
+    }
+
+    pub(super) fn expr_enum_variant(
+        &mut self,
+        span: Span,
+        path: &'hir hir::QPath<'hir>,
+        fields: &'hir [hir::Expr<'hir>],
+    ) -> hir::Expr<'hir> {
+        let fields = self.arena.alloc_from_iter(fields.into_iter().enumerate().map(|(i, f)| {
+            hir::ExprField {
+                hir_id: self.next_id(),
+                ident: Ident::from_str(&i.to_string()),
+                expr: f,
+                span: f.span,
+                is_shorthand: false,
+            }
+        }));
+        self.expr_struct(span, path, fields)
+    }
+
+    pub(super) fn expr_enum_variant_lang_item(
+        &mut self,
+        span: Span,
+        lang_item: hir::LangItem,
+        fields: &'hir [hir::Expr<'hir>],
+    ) -> hir::Expr<'hir> {
+        let path = self.arena.alloc(self.lang_item_path(span, lang_item));
+        self.expr_enum_variant(span, path, fields)
+    }
+
     pub(super) fn expr_call(
         &mut self,
         span: Span,
@@ -2189,8 +2187,21 @@ pub(super) fn expr_call_lang_item_fn(
         self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args))
     }
 
-    fn expr_lang_item_path(&mut self, span: Span, lang_item: hir::LangItem) -> hir::Expr<'hir> {
-        self.expr(span, hir::ExprKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span))))
+    pub(super) fn expr_lang_item_path(
+        &mut self,
+        span: Span,
+        lang_item: hir::LangItem,
+    ) -> hir::Expr<'hir> {
+        let path = self.lang_item_path(span, lang_item);
+        self.expr(span, hir::ExprKind::Path(path))
+    }
+
+    pub(super) fn lang_item_path(
+        &mut self,
+        span: Span,
+        lang_item: hir::LangItem,
+    ) -> hir::QPath<'hir> {
+        hir::QPath::LangItem(lang_item, self.lower_span(span))
     }
 
     /// `<LangItem>::name`
@@ -2270,6 +2281,17 @@ pub(super) fn expr_block(&mut self, b: &'hir hir::Block<'hir>) -> hir::Expr<'hir
         self.expr(b.span, hir::ExprKind::Block(b, None))
     }
 
+    /// Wrap an expression in a block, and wrap that block in an expression again.
+    /// Useful for constructing if-expressions, which require expressions of
+    /// kind block.
+    pub(super) fn block_expr_block(
+        &mut self,
+        expr: &'hir hir::Expr<'hir>,
+    ) -> &'hir hir::Expr<'hir> {
+        let b = self.block_expr(expr);
+        self.arena.alloc(self.expr_block(b))
+    }
+
     pub(super) fn expr_array_ref(
         &mut self,
         span: Span,
@@ -2283,6 +2305,10 @@ pub(super) fn expr_ref(&mut self, span: Span, expr: &'hir hir::Expr<'hir>) -> hi
         self.expr(span, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr))
     }
 
+    pub(super) fn expr_bool_literal(&mut self, span: Span, val: bool) -> hir::Expr<'hir> {
+        self.expr(span, hir::ExprKind::Lit(Spanned { node: LitKind::Bool(val), span }))
+    }
+
     pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> {
         let hir_id = self.next_id();
         hir::Expr { hir_id, kind, span: self.lower_span(span) }
@@ -2316,6 +2342,19 @@ pub(super) fn arm(
             body: expr,
         }
     }
+
+    /// `#[allow(unreachable_code)]`
+    pub(super) fn unreachable_code_attr(&mut self, span: Span) -> Attribute {
+        let attr = attr::mk_attr_nested_word(
+            &self.tcx.sess.psess.attr_id_generator,
+            AttrStyle::Outer,
+            Safety::Default,
+            sym::allow,
+            sym::unreachable_code,
+            span,
+        );
+        attr
+    }
 }
 
 /// Used by [`LoweringContext::make_lowered_await`] to customize the desugaring based on what kind
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 53351f9..d11b7f7 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1214,76 +1214,9 @@ pub(super) fn lower_fn_body(
             let params =
                 this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x)));
 
-            // Optionally lower the fn contract, which turns:
-            //
-            // { body }
-            //
-            // into:
-            //
-            // { contract_requires(PRECOND); let __postcond = |ret_val| POSTCOND; postcond({ body }) }
+            // Optionally lower the fn contract
             if let Some(contract) = contract {
-                let precond = if let Some(req) = &contract.requires {
-                    // Lower the precondition check intrinsic.
-                    let lowered_req = this.lower_expr_mut(&req);
-                    let req_span = this.mark_span_with_reason(
-                        DesugaringKind::Contract,
-                        lowered_req.span,
-                        None,
-                    );
-                    let precond = this.expr_call_lang_item_fn_mut(
-                        req_span,
-                        hir::LangItem::ContractCheckRequires,
-                        &*arena_vec![this; lowered_req],
-                    );
-                    Some(this.stmt_expr(req.span, precond))
-                } else {
-                    None
-                };
-                let (postcond, body) = if let Some(ens) = &contract.ensures {
-                    let ens_span = this.lower_span(ens.span);
-                    let ens_span =
-                        this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None);
-                    // Set up the postcondition `let` statement.
-                    let check_ident: Ident =
-                        Ident::from_str_and_span("__ensures_checker", ens_span);
-                    let (checker_pat, check_hir_id) = this.pat_ident_binding_mode_mut(
-                        ens_span,
-                        check_ident,
-                        hir::BindingMode::NONE,
-                    );
-                    let lowered_ens = this.lower_expr_mut(&ens);
-                    let postcond_checker = this.expr_call_lang_item_fn(
-                        ens_span,
-                        hir::LangItem::ContractBuildCheckEnsures,
-                        &*arena_vec![this; lowered_ens],
-                    );
-                    let postcond = this.stmt_let_pat(
-                        None,
-                        ens_span,
-                        Some(postcond_checker),
-                        this.arena.alloc(checker_pat),
-                        hir::LocalSource::Contract,
-                    );
-
-                    // Install contract_ensures so we will intercept `return` statements,
-                    // then lower the body.
-                    this.contract_ensures = Some((ens_span, check_ident, check_hir_id));
-                    let body = this.arena.alloc(body(this));
-
-                    // Finally, inject an ensures check on the implicit return of the body.
-                    let body = this.inject_ensures_check(body, ens_span, check_ident, check_hir_id);
-                    (Some(postcond), body)
-                } else {
-                    let body = &*this.arena.alloc(body(this));
-                    (None, body)
-                };
-                // Flatten the body into precond, then postcond, then wrapped body.
-                let wrapped_body = this.block_all(
-                    body.span,
-                    this.arena.alloc_from_iter([precond, postcond].into_iter().flatten()),
-                    Some(body),
-                );
-                (params, this.expr_block(wrapped_body))
+                (params, this.lower_contract(body, contract))
             } else {
                 (params, body(this))
             }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 4e2243e..282a62c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -77,6 +77,7 @@ macro_rules! arena_vec {
 
 mod asm;
 mod block;
+mod contract;
 mod delegation;
 mod errors;
 mod expr;
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index 8b6b762..a2a5f8a 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -4,6 +4,8 @@
 attr_parsing_bundle_needs_static =
     linking modifier `bundle` is only compatible with `static` linking kind
 
+attr_parsing_cfg_attr_bad_delim = wrong `cfg_attr` delimiters
+
 attr_parsing_cfg_predicate_identifier =
     `cfg` predicate key must be an identifier
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index 7085561..af94e8a 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -1,19 +1,28 @@
-use rustc_ast::{LitKind, NodeId};
+use rustc_ast::token::Delimiter;
+use rustc_ast::tokenstream::DelimSpan;
+use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token};
+use rustc_errors::{Applicability, PResult};
 use rustc_feature::{AttributeTemplate, Features, template};
-use rustc_hir::RustcVersion;
 use rustc_hir::attrs::CfgEntry;
+use rustc_hir::{AttrPath, RustcVersion};
+use rustc_parse::parser::{ForceCollect, Parser};
+use rustc_parse::{exp, parse_in};
 use rustc_session::Session;
 use rustc_session::config::ExpectedValues;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::UNEXPECTED_CFGS;
-use rustc_session::parse::feature_err;
+use rustc_session::parse::{ParseSess, feature_err};
 use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
 
 use crate::context::{AcceptContext, ShouldEmit, Stage};
 use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser};
+use crate::session_diagnostics::{
+    AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
+};
 use crate::{
-    CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg,
+    AttributeParser, CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics,
+    try_gate_cfg,
 };
 
 pub const CFG_TEMPLATE: AttributeTemplate = template!(
@@ -21,7 +30,12 @@
     "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute"
 );
 
-pub fn parse_cfg_attr<'c, S: Stage>(
+const CFG_ATTR_TEMPLATE: AttributeTemplate = template!(
+    List: &["predicate, attr1, attr2, ..."],
+    "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute"
+);
+
+pub fn parse_cfg<'c, S: Stage>(
     cx: &'c mut AcceptContext<'_, '_, S>,
     args: &'c ArgParser<'_>,
 ) -> Option<CfgEntry> {
@@ -70,9 +84,7 @@ pub(crate) fn parse_cfg_entry<S: Stage>(
             },
             a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => {
                 let Some(name) = meta.path().word_sym() else {
-                    cx.emit_err(session_diagnostics::CfgPredicateIdentifier {
-                        span: meta.path().span(),
-                    });
+                    cx.expected_identifier(meta.path().span());
                     return None;
                 };
                 parse_name_value(name, meta.path().span(), a.name_value(), meta.span(), cx)?
@@ -81,7 +93,7 @@ pub(crate) fn parse_cfg_entry<S: Stage>(
         MetaItemOrLitParser::Lit(lit) => match lit.kind {
             LitKind::Bool(b) => CfgEntry::Bool(b, lit.span),
             _ => {
-                cx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: lit.span });
+                cx.expected_identifier(lit.span);
                 return None;
             }
         },
@@ -149,9 +161,7 @@ fn parse_cfg_entry_target<S: Stage>(
 
         // Then, parse it as a name-value item
         let Some(name) = sub_item.path().word_sym() else {
-            cx.emit_err(session_diagnostics::CfgPredicateIdentifier {
-                span: sub_item.path().span(),
-            });
+            cx.expected_identifier(sub_item.path().span());
             return None;
         };
         let name = Symbol::intern(&format!("target_{name}"));
@@ -300,3 +310,120 @@ pub fn as_bool(&self) -> bool {
         }
     }
 }
+
+pub fn parse_cfg_attr(
+    cfg_attr: &Attribute,
+    sess: &Session,
+    features: Option<&Features>,
+) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> {
+    match cfg_attr.get_normal_item().args {
+        ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
+            if !tokens.is_empty() =>
+        {
+            check_cfg_attr_bad_delim(&sess.psess, dspan, delim);
+            match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| {
+                parse_cfg_attr_internal(p, sess, features, cfg_attr)
+            }) {
+                Ok(r) => return Some(r),
+                Err(e) => {
+                    let suggestions = CFG_ATTR_TEMPLATE.suggestions(cfg_attr.style, sym::cfg_attr);
+                    e.with_span_suggestions(
+                        cfg_attr.span,
+                        "must be of the form",
+                        suggestions,
+                        Applicability::HasPlaceholders,
+                    )
+                    .with_note(format!(
+                        "for more information, visit <{}>",
+                        CFG_ATTR_TEMPLATE.docs.expect("cfg_attr has docs")
+                    ))
+                    .emit();
+                }
+            }
+        }
+        _ => {
+            let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) =
+                cfg_attr.get_normal_item().args
+            {
+                (dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument)
+            } else {
+                (cfg_attr.span, AttributeParseErrorReason::ExpectedList)
+            };
+
+            sess.dcx().emit_err(AttributeParseError {
+                span,
+                attr_span: cfg_attr.span,
+                template: CFG_ATTR_TEMPLATE,
+                attribute: AttrPath::from_ast(&cfg_attr.get_normal_item().path),
+                reason,
+                attr_style: cfg_attr.style,
+            });
+        }
+    }
+    None
+}
+
+fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) {
+    if let Delimiter::Parenthesis = delim {
+        return;
+    }
+    psess.dcx().emit_err(CfgAttrBadDelim {
+        span: span.entire(),
+        sugg: MetaBadDelimSugg { open: span.open, close: span.close },
+    });
+}
+
+/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
+fn parse_cfg_attr_internal<'a>(
+    parser: &mut Parser<'a>,
+    sess: &'a Session,
+    features: Option<&Features>,
+    attribute: &Attribute,
+) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
+    // Parse cfg predicate
+    let pred_start = parser.token.span;
+    let meta = MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints)?;
+    let pred_span = pred_start.with_hi(parser.token.span.hi());
+
+    let cfg_predicate = AttributeParser::parse_single_args(
+        sess,
+        attribute.span,
+        attribute.style,
+        AttrPath {
+            segments: attribute
+                .ident_path()
+                .expect("cfg_attr is not a doc comment")
+                .into_boxed_slice(),
+            span: attribute.span,
+        },
+        pred_span,
+        CRATE_NODE_ID,
+        features,
+        ShouldEmit::ErrorsAndLints,
+        &meta,
+        parse_cfg_entry,
+        &CFG_ATTR_TEMPLATE,
+    )
+    .ok_or_else(|| {
+        let mut diag = sess.dcx().struct_err(
+            "cfg_entry parsing failing with `ShouldEmit::ErrorsAndLints` should emit a error.",
+        );
+        diag.downgrade_to_delayed_bug();
+        diag
+    })?;
+
+    parser.expect(exp!(Comma))?;
+
+    // Presumably, the majority of the time there will only be one attr.
+    let mut expanded_attrs = Vec::with_capacity(1);
+    while parser.token != token::Eof {
+        let lo = parser.token.span;
+        let item = parser.parse_attr_item(ForceCollect::Yes)?;
+        expanded_attrs.push((item, lo.to(parser.prev_token.span)));
+        if !parser.eat(exp!(Comma)) {
+            break;
+        }
+    }
+
+    Ok((cfg_predicate, expanded_attrs))
+}
diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs
index 8f2de4a..b8ef11c 100644
--- a/compiler/rustc_attr_parsing/src/interface.rs
+++ b/compiler/rustc_attr_parsing/src/interface.rs
@@ -1,7 +1,7 @@
 use std::borrow::Cow;
 
 use rustc_ast as ast;
-use rustc_ast::NodeId;
+use rustc_ast::{AttrStyle, NodeId};
 use rustc_errors::DiagCtxtHandle;
 use rustc_feature::{AttributeTemplate, Features};
 use rustc_hir::attrs::AttributeKind;
@@ -62,7 +62,8 @@ pub fn parse_limited(
         )
     }
 
-    /// Usually you want `parse_limited`, which defaults to no errors.
+    /// This does the same as `parse_limited`, except it has a `should_emit` parameter which allows it to emit errors.
+    /// Usually you want `parse_limited`, which emits no errors.
     pub fn parse_limited_should_emit(
         sess: &'sess Session,
         attrs: &[ast::Attribute],
@@ -86,6 +87,13 @@ pub fn parse_limited_should_emit(
         parsed.pop()
     }
 
+    /// This method allows you to parse a list of attributes *before* `rustc_ast_lowering`.
+    /// This can be used for attributes that would be removed before `rustc_ast_lowering`, such as attributes on macro calls.
+    ///
+    /// Try to use this as little as possible. Attributes *should* be lowered during
+    /// `rustc_ast_lowering`. Some attributes require access to features to parse, which would
+    /// crash if you tried to do so through [`parse_limited_all`](Self::parse_limited_all).
+    /// Therefore, if `parse_only` is None, then features *must* be provided.
     pub fn parse_limited_all(
         sess: &'sess Session,
         attrs: &[ast::Attribute],
@@ -111,6 +119,8 @@ pub fn parse_limited_all(
         )
     }
 
+    /// This method parses a single attribute, using `parse_fn`.
+    /// This is useful if you already know what exact attribute this is, and want to parse it.
     pub fn parse_single<T>(
         sess: &'sess Session,
         attr: &ast::Attribute,
@@ -121,13 +131,6 @@ pub fn parse_single<T>(
         parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option<T>,
         template: &AttributeTemplate,
     ) -> Option<T> {
-        let mut parser = Self {
-            features,
-            tools: Vec::new(),
-            parse_only: None,
-            sess,
-            stage: Early { emit_errors },
-        };
         let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
             panic!("parse_single called on a doc attr")
         };
@@ -136,6 +139,43 @@ pub fn parse_single<T>(
         let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?;
         let path = meta_parser.path();
         let args = meta_parser.args();
+        Self::parse_single_args(
+            sess,
+            attr.span,
+            attr.style,
+            path.get_attribute_path(),
+            target_span,
+            target_node_id,
+            features,
+            emit_errors,
+            args,
+            parse_fn,
+            template,
+        )
+    }
+
+    /// This method is equivalent to `parse_single`, but parses arguments using `parse_fn` using manually created `args`.
+    /// This is useful when you want to parse other things than attributes using attribute parsers.
+    pub fn parse_single_args<T, I>(
+        sess: &'sess Session,
+        attr_span: Span,
+        attr_style: AttrStyle,
+        attr_path: AttrPath,
+        target_span: Span,
+        target_node_id: NodeId,
+        features: Option<&'sess Features>,
+        emit_errors: ShouldEmit,
+        args: &I,
+        parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &I) -> Option<T>,
+        template: &AttributeTemplate,
+    ) -> Option<T> {
+        let mut parser = Self {
+            features,
+            tools: Vec::new(),
+            parse_only: None,
+            sess,
+            stage: Early { emit_errors },
+        };
         let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
             shared: SharedContext {
                 cx: &mut parser,
@@ -145,10 +185,10 @@ pub fn parse_single<T>(
                     crate::lints::emit_attribute_lint(&lint, sess);
                 },
             },
-            attr_span: attr.span,
-            attr_style: attr.style,
+            attr_span,
+            attr_style,
             template,
-            attr_path: path.get_attribute_path(),
+            attr_path,
         };
         parse_fn(&mut cx, args)
     }
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs
index f51cc8c..bcd0d67 100644
--- a/compiler/rustc_attr_parsing/src/lib.rs
+++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -105,7 +105,9 @@
 mod target_checking;
 pub mod validate_attr;
 
-pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr};
+pub use attributes::cfg::{
+    CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr,
+};
 pub use attributes::cfg_old::*;
 pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version};
 pub use context::{Early, Late, OmitDoc, ShouldEmit};
diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs
index 3f4f567..7474471 100644
--- a/compiler/rustc_attr_parsing/src/parser.rs
+++ b/compiler/rustc_attr_parsing/src/parser.rs
@@ -8,7 +8,7 @@
 
 use rustc_ast::token::{self, Delimiter, MetaVarKind};
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path};
+use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path};
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Diag, PResult};
 use rustc_hir::{self as hir, AttrPath};
@@ -124,7 +124,11 @@ pub fn from_attr_args<'sess>(
                     return None;
                 }
 
-                Self::List(MetaItemListParser::new(args, psess, should_emit)?)
+                Self::List(
+                    MetaItemListParser::new(&args.tokens, args.dspan.entire(), psess, should_emit)
+                        .map_err(|e| should_emit.emit_err(e))
+                        .ok()?,
+                )
             }
             AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
                 eq_span: *eq_span,
@@ -186,7 +190,15 @@ pub enum MetaItemOrLitParser<'a> {
     Err(Span, ErrorGuaranteed),
 }
 
-impl<'a> MetaItemOrLitParser<'a> {
+impl<'sess> MetaItemOrLitParser<'sess> {
+    pub fn parse_single(
+        parser: &mut Parser<'sess>,
+        should_emit: ShouldEmit,
+    ) -> PResult<'sess, MetaItemOrLitParser<'static>> {
+        let mut this = MetaItemListParserContext { parser, should_emit };
+        this.parse_meta_item_inner()
+    }
+
     pub fn span(&self) -> Span {
         match self {
             MetaItemOrLitParser::MetaItemParser(generic_meta_item_parser) => {
@@ -204,7 +216,7 @@ pub fn lit(&self) -> Option<&MetaItemLit> {
         }
     }
 
-    pub fn meta_item(&self) -> Option<&MetaItemParser<'a>> {
+    pub fn meta_item(&self) -> Option<&MetaItemParser<'sess>> {
         match self {
             MetaItemOrLitParser::MetaItemParser(parser) => Some(parser),
             _ => None,
@@ -542,23 +554,13 @@ pub struct MetaItemListParser<'a> {
 }
 
 impl<'a> MetaItemListParser<'a> {
-    fn new<'sess>(
-        delim: &'a DelimArgs,
+    pub(crate) fn new<'sess>(
+        tokens: &'a TokenStream,
+        span: Span,
         psess: &'sess ParseSess,
         should_emit: ShouldEmit,
-    ) -> Option<Self> {
-        match MetaItemListParserContext::parse(
-            delim.tokens.clone(),
-            psess,
-            delim.dspan.entire(),
-            should_emit,
-        ) {
-            Ok(s) => Some(s),
-            Err(e) => {
-                should_emit.emit_err(e);
-                None
-            }
-        }
+    ) -> Result<Self, Diag<'sess>> {
+        MetaItemListParserContext::parse(tokens.clone(), psess, span, should_emit)
     }
 
     /// Lets you pick and choose as what you want to parse each element in the list
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 1194ac5..7b82f3b 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -971,3 +971,12 @@ pub(crate) struct LimitInvalid<'a> {
     pub value_span: Span,
     pub error_str: &'a str,
 }
+
+#[derive(Diagnostic)]
+#[diag(attr_parsing_cfg_attr_bad_delim)]
+pub(crate) struct CfgAttrBadDelim {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sugg: MetaBadDelimSugg,
+}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 6b5af15..b4990ff 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -708,8 +708,7 @@ fn is_error_in_trait(&self, local: Local) -> (bool, bool, Option<Span>) {
             return (false, false, None);
         }
         let my_def = self.body.source.def_id();
-        let Some(td) =
-            tcx.trait_impl_of_assoc(my_def).and_then(|id| self.infcx.tcx.trait_id_of_impl(id))
+        let Some(td) = tcx.trait_impl_of_assoc(my_def).map(|id| self.infcx.tcx.impl_trait_id(id))
         else {
             return (false, false, None);
         };
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index fa3064a..d6dbc7d 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -21,10 +21,10 @@ pub(crate) fn renumber_mir<'tcx>(
     let mut renumberer = RegionRenumberer { infcx };
 
     for body in promoted.iter_mut() {
-        renumberer.visit_body(body);
+        renumberer.visit_body_preserves_cfg(body);
     }
 
-    renumberer.visit_body(body);
+    renumberer.visit_body_preserves_cfg(body);
 }
 
 // The fields are used only for debugging output in `sccs_info`.
diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs
index 13c6326..118efd1 100644
--- a/compiler/rustc_builtin_macros/src/contracts.rs
+++ b/compiler/rustc_builtin_macros/src/contracts.rs
@@ -149,7 +149,7 @@ fn expand_requires_tts(
         new_tts.push_tree(TokenTree::Delimited(
             DelimSpan::from_single(attr_span),
             DelimSpacing::new(Spacing::JointHidden, Spacing::JointHidden),
-            token::Delimiter::Parenthesis,
+            token::Delimiter::Brace,
             annotation,
         ));
         Ok(())
@@ -171,7 +171,7 @@ fn expand_ensures_tts(
         new_tts.push_tree(TokenTree::Delimited(
             DelimSpan::from_single(attr_span),
             DelimSpacing::new(Spacing::JointHidden, Spacing::JointHidden),
-            token::Delimiter::Parenthesis,
+            token::Delimiter::Brace,
             annotation,
         ));
         Ok(())
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 29ee461..9a9a1f4 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -467,7 +467,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
         true
     } else {
         instance.is_some_and(|inst| {
-            fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD)
+            fx.tcx.codegen_instance_attrs(inst.def).flags.contains(CodegenFnAttrFlags::COLD)
         })
     };
     if is_cold {
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 293459c..3243e12 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -5,7 +5,9 @@
 use cranelift_module::*;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::interpret::{AllocId, GlobalAlloc, Scalar, read_target_uint};
+use rustc_middle::mir::interpret::{
+    AllocId, GlobalAlloc, PointerArithmetic, Scalar, read_target_uint,
+};
 use rustc_middle::ty::{ExistentialTraitRef, ScalarInt};
 
 use crate::prelude::*;
@@ -138,8 +140,11 @@ pub(crate) fn codegen_const_value<'tcx>(
                 let base_addr = match fx.tcx.global_alloc(alloc_id) {
                     GlobalAlloc::Memory(alloc) => {
                         if alloc.inner().len() == 0 {
-                            assert_eq!(offset, Size::ZERO);
-                            fx.bcx.ins().iconst(fx.pointer_type, alloc.inner().align.bytes() as i64)
+                            let val = alloc.inner().align.bytes().wrapping_add(offset.bytes());
+                            fx.bcx.ins().iconst(
+                                fx.pointer_type,
+                                fx.tcx.truncate_to_target_usize(val) as i64,
+                            )
                         } else {
                             let data_id = data_id_for_alloc_id(
                                 &mut fx.constants_cx,
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index 28848ca..7c2969e 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -5,7 +5,7 @@
     BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods,
 };
 use rustc_middle::mir::Mutability;
-use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
+use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, PointerArithmetic, Scalar};
 use rustc_middle::ty::layout::LayoutOf;
 
 use crate::context::CodegenCx;
@@ -247,8 +247,8 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) ->
                         // This avoids generating a zero-sized constant value and actually needing a
                         // real address at runtime.
                         if alloc.inner().len() == 0 {
-                            assert_eq!(offset.bytes(), 0);
-                            let val = self.const_usize(alloc.inner().align.bytes());
+                            let val = alloc.inner().align.bytes().wrapping_add(offset.bytes());
+                            let val = self.const_usize(self.tcx.truncate_to_target_usize(val));
                             return if matches!(layout.primitive(), Pointer(_)) {
                                 self.context.new_cast(None, val, ty)
                             } else {
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 175fc85..b0cf992 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -12,7 +12,7 @@
 use rustc_hashes::Hash128;
 use rustc_hir::def_id::DefId;
 use rustc_middle::bug;
-use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
+use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, PointerArithmetic, Scalar};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cstore::DllImport;
 use tracing::debug;
@@ -281,8 +281,8 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) ->
                         // This avoids generating a zero-sized constant value and actually needing a
                         // real address at runtime.
                         if alloc.inner().len() == 0 {
-                            assert_eq!(offset.bytes(), 0);
-                            let llval = self.const_usize(alloc.inner().align.bytes());
+                            let val = alloc.inner().align.bytes().wrapping_add(offset.bytes());
+                            let llval = self.const_usize(self.tcx.truncate_to_target_usize(val));
                             return if matches!(layout.primitive(), Pointer(_)) {
                                 unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
                             } else {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index e371f1a..e2241a7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -200,10 +200,11 @@ fn do_call<Bx: BuilderMethods<'a, 'tcx>>(
         let fn_ty = bx.fn_decl_backend_type(fn_abi);
 
         let fn_attrs = if bx.tcx().def_kind(fx.instance.def_id()).has_codegen_attrs() {
-            Some(bx.tcx().codegen_fn_attrs(fx.instance.def_id()))
+            Some(bx.tcx().codegen_instance_attrs(fx.instance.def))
         } else {
             None
         };
+        let fn_attrs = fn_attrs.as_deref();
 
         if !fn_abi.can_unwind {
             unwind = mir::UnwindAction::Unreachable;
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index b63e929..5b65f17 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -234,7 +234,7 @@ pub fn in_rvalue<'tcx, Q, F>(
 
         Rvalue::Discriminant(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
 
-        Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"),
+        Rvalue::CopyForDeref(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
 
         Rvalue::Use(operand)
         | Rvalue::Repeat(operand, _)
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index 35c3e3e..530d8d4 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -7,7 +7,7 @@
 fn parent_impl_or_trait_constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
     let parent_id = tcx.local_parent(def_id);
     match tcx.def_kind(parent_id) {
-        DefKind::Impl { of_trait: true } => tcx.impl_trait_header(parent_id).unwrap().constness,
+        DefKind::Impl { of_trait: true } => tcx.impl_trait_header(parent_id).constness,
         DefKind::Trait => {
             if tcx.is_const_trait(parent_id.into()) {
                 hir::Constness::Const
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 2925e33..8278c29 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -13,7 +13,7 @@
 use rustc_attr_parsing as attr;
 use rustc_attr_parsing::validate_attr::deny_builtin_meta_unsafety;
 use rustc_attr_parsing::{
-    AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg_attr,
+    AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg,
     validate_attr,
 };
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
@@ -303,7 +303,7 @@ pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> V
         let trace_attr = attr_into_trace(cfg_attr.clone(), sym::cfg_attr_trace);
 
         let Some((cfg_predicate, expanded_attrs)) =
-            rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess)
+            rustc_attr_parsing::parse_cfg_attr(cfg_attr, &self.sess, self.features)
         else {
             return vec![trace_attr];
         };
@@ -318,7 +318,15 @@ pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> V
             );
         }
 
-        if !attr::cfg_matches(&cfg_predicate, &self.sess, self.lint_node_id, self.features) {
+        if !attr::eval_config_entry(
+            self.sess,
+            &cfg_predicate,
+            ast::CRATE_NODE_ID,
+            self.features,
+            ShouldEmit::ErrorsAndLints,
+        )
+        .as_bool()
+        {
             return vec![trace_attr];
         }
 
@@ -428,7 +436,7 @@ pub(crate) fn cfg_true(
             node,
             self.features,
             emit_errors,
-            parse_cfg_attr,
+            parse_cfg,
             &CFG_TEMPLATE,
         ) else {
             // Cfg attribute was not parsable, give up
@@ -488,7 +496,7 @@ pub fn configure_expr(&self, expr: &mut ast::Expr, method_receiver: bool) {
 }
 
 /// FIXME: Still used by Rustdoc, should be removed after
-pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItemInner> {
+pub fn parse_cfg_old<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItemInner> {
     let span = meta_item.span;
     match meta_item.meta_item_list() {
         None => {
diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs
index 0ff0147..f39d1b7 100644
--- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs
+++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs
@@ -148,8 +148,7 @@ fn ensure_impl_params_and_item_params_correspond<'tcx>(
         ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
         ty::ImplPolarity::Negative => "!",
     };
-    let trait_name = tcx
-        .item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait"));
+    let trait_name = tcx.item_name(tcx.impl_trait_id(impl_def_id.to_def_id()));
     let mut err = struct_span_code_err!(
         tcx.dcx(),
         impl_span,
@@ -187,8 +186,7 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>(
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     let impl_span = tcx.def_span(impl_def_id.to_def_id());
-    let trait_name = tcx
-        .item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait"));
+    let trait_name = tcx.item_name(tcx.impl_trait_id(impl_def_id.to_def_id()));
     let polarity = match tcx.impl_polarity(impl_def_id) {
         ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
         ty::ImplPolarity::Negative => "!",
@@ -212,8 +210,7 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>(
         ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);
 
     let fresh_impl_args = infcx.fresh_args_for_item(impl_span, impl_def_id.to_def_id());
-    let fresh_adt_ty =
-        tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty();
+    let fresh_adt_ty = tcx.impl_trait_ref(impl_def_id).instantiate(tcx, fresh_impl_args).self_ty();
 
     ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty)
         .expect("equating fully generic trait ref should never fail");
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 4c910d2..95b47c8 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -806,10 +806,10 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
         DefKind::Impl { of_trait } => {
             tcx.ensure_ok().generics_of(def_id);
             tcx.ensure_ok().type_of(def_id);
-            tcx.ensure_ok().impl_trait_header(def_id);
             tcx.ensure_ok().predicates_of(def_id);
             tcx.ensure_ok().associated_items(def_id);
-            if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) {
+            if of_trait {
+                let impl_trait_header = tcx.impl_trait_header(def_id);
                 res = res.and(
                     tcx.ensure_ok()
                         .coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id),
@@ -1191,9 +1191,7 @@ fn check_impl_items_against_trait<'tcx>(
                         tcx,
                         ty_impl_item,
                         ty_trait_item,
-                        tcx.impl_trait_ref(ty_impl_item.container_id(tcx))
-                            .unwrap()
-                            .instantiate_identity(),
+                        tcx.impl_trait_ref(ty_impl_item.container_id(tcx)).instantiate_identity(),
                     );
                 }
                 ty::AssocKind::Const { .. } => {}
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 5b504cc..936b02c 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -38,8 +38,7 @@ pub(super) fn compare_impl_item(
 ) -> Result<(), ErrorGuaranteed> {
     let impl_item = tcx.associated_item(impl_item_def_id);
     let trait_item = tcx.associated_item(impl_item.expect_trait_impl()?);
-    let impl_trait_ref =
-        tcx.impl_trait_ref(impl_item.container_id(tcx)).unwrap().instantiate_identity();
+    let impl_trait_ref = tcx.impl_trait_ref(impl_item.container_id(tcx)).instantiate_identity();
     debug!(?impl_trait_ref);
 
     match impl_item.kind {
@@ -443,7 +442,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
     let impl_m = tcx.associated_item(impl_m_def_id.to_def_id());
     let trait_m = tcx.associated_item(impl_m.expect_trait_impl()?);
     let impl_trait_ref =
-        tcx.impl_trait_ref(tcx.parent(impl_m_def_id.to_def_id())).unwrap().instantiate_identity();
+        tcx.impl_trait_ref(tcx.parent(impl_m_def_id.to_def_id())).instantiate_identity();
     // First, check a few of the same things as `compare_impl_method`,
     // just so we don't ICE during instantiation later.
     check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index bc3448b..a665991 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -647,11 +647,11 @@ pub(crate) fn check_intrinsic_type(
 
         sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))),
 
-        // contract_checks() -> bool
-        sym::contract_checks => (0, 0, Vec::new(), tcx.types.bool),
         // contract_check_requires::<C>(C) -> bool, where C: impl Fn() -> bool
         sym::contract_check_requires => (1, 0, vec![param(0)], tcx.types.unit),
-        sym::contract_check_ensures => (2, 0, vec![param(0), param(1)], param(1)),
+        sym::contract_check_ensures => {
+            (2, 0, vec![Ty::new_option(tcx, param(0)), param(1)], param(1))
+        }
 
         sym::simd_eq | sym::simd_ne | sym::simd_lt | sym::simd_le | sym::simd_gt | sym::simd_ge => {
             (2, 0, vec![param(0), param(0)], param(1))
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 0166c3b..f1c84a1 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -244,7 +244,7 @@ fn missing_items_err(
         let snippet = with_types_for_signature!(suggestion_signature(
             tcx,
             trait_item,
-            tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(),
+            tcx.impl_trait_ref(impl_def_id).instantiate_identity(),
         ));
         let code = format!("{padding}{snippet}\n{padding}");
         if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 6e537c6..f3d6398 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -245,10 +245,10 @@ pub(super) fn check_item<'tcx>(
         // won't be allowed unless there's an *explicit* implementation of `Send`
         // for `T`
         hir::ItemKind::Impl(ref impl_) => {
-            crate::impl_wf_check::check_impl_wf(tcx, def_id)?;
+            crate::impl_wf_check::check_impl_wf(tcx, def_id, impl_.of_trait.is_some())?;
             let mut res = Ok(());
             if let Some(of_trait) = impl_.of_trait {
-                let header = tcx.impl_trait_header(def_id).unwrap();
+                let header = tcx.impl_trait_header(def_id);
                 let is_auto = tcx.trait_is_auto(header.trait_ref.skip_binder().def_id);
                 if let (hir::Defaultness::Default { .. }, true) = (of_trait.defaultness, is_auto) {
                     let sp = of_trait.trait_ref.path.span;
@@ -1258,7 +1258,7 @@ fn check_impl<'tcx>(
                 // `#[rustc_reservation_impl]` impls are not real impls and
                 // therefore don't need to be WF (the trait's `Self: Trait` predicate
                 // won't hold).
-                let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().instantiate_identity();
+                let trait_ref = tcx.impl_trait_ref(item.owner_id).instantiate_identity();
                 // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
                 // other `Foo` impls are incoherent.
                 tcx.ensure_ok().coherent_trait(trait_ref.def_id)?;
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index b7a74ac..6dee167 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -377,7 +377,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
     let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span);
 
     let source = tcx.type_of(impl_did).instantiate_identity();
-    let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
+    let trait_ref = tcx.impl_trait_ref(impl_did).instantiate_identity();
 
     assert_eq!(trait_ref.def_id, coerce_unsized_trait);
     let target = trait_ref.args.type_at(1);
@@ -707,7 +707,7 @@ fn visit_implementation_of_coerce_pointee_validity(
     checker: &Checker<'_>,
 ) -> Result<(), ErrorGuaranteed> {
     let tcx = checker.tcx;
-    let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
+    let self_ty = tcx.impl_trait_ref(checker.impl_def_id).instantiate_identity().self_ty();
     let span = tcx.def_span(checker.impl_def_id);
     if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
         return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index fbb4424..bc3231c 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -163,7 +163,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
     let mut res = tcx.ensure_ok().specialization_graph_of(def_id);
 
     for &impl_def_id in impls {
-        let impl_header = tcx.impl_trait_header(impl_def_id).unwrap();
+        let impl_header = tcx.impl_trait_header(impl_def_id);
         let trait_ref = impl_header.trait_ref.instantiate_identity();
         let trait_def = tcx.trait_def(trait_ref.def_id);
 
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index c4aeb4c..27682d0 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -22,7 +22,7 @@ pub(crate) fn orphan_check_impl(
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
 ) -> Result<(), ErrorGuaranteed> {
-    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
+    let trait_ref = tcx.impl_trait_ref(impl_def_id).instantiate_identity();
     trait_ref.error_reported()?;
 
     match orphan_check(tcx, impl_def_id, OrphanCheckMode::Proper) {
@@ -294,7 +294,7 @@ fn orphan_check<'tcx>(
 ) -> Result<(), OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>> {
     // We only accept this routine to be invoked on implementations
     // of a trait, not inherent implementations.
-    let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+    let trait_ref = tcx.impl_trait_ref(impl_def_id);
     debug!(trait_ref = ?trait_ref.skip_binder());
 
     // If the *trait* is local to the crate, ok.
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index b6a662f..89ab710 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1291,28 +1291,26 @@ pub fn suggest_impl_trait<'tcx>(
     None
 }
 
-fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTraitHeader<'_>> {
+fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplTraitHeader<'_> {
     let icx = ItemCtxt::new(tcx, def_id);
     let item = tcx.hir_expect_item(def_id);
     let impl_ = item.expect_impl();
+    let of_trait = impl_
+        .of_trait
+        .unwrap_or_else(|| panic!("expected impl trait, found inherent impl on {def_id:?}"));
+    let selfty = tcx.type_of(def_id).instantiate_identity();
     let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
-    if is_rustc_reservation && impl_.of_trait.is_none() {
-        tcx.dcx().span_err(item.span, "reservation impls can't be inherent");
+
+    check_impl_constness(tcx, of_trait.constness, &of_trait.trait_ref);
+
+    let trait_ref = icx.lowerer().lower_impl_trait_ref(&of_trait.trait_ref, selfty);
+
+    ty::ImplTraitHeader {
+        trait_ref: ty::EarlyBinder::bind(trait_ref),
+        safety: of_trait.safety,
+        polarity: polarity_of_impl(tcx, of_trait, is_rustc_reservation),
+        constness: of_trait.constness,
     }
-    impl_.of_trait.map(|of_trait| {
-        let selfty = tcx.type_of(def_id).instantiate_identity();
-
-        check_impl_constness(tcx, of_trait.constness, &of_trait.trait_ref);
-
-        let trait_ref = icx.lowerer().lower_impl_trait_ref(&of_trait.trait_ref, selfty);
-
-        ty::ImplTraitHeader {
-            trait_ref: ty::EarlyBinder::bind(trait_ref),
-            safety: of_trait.safety,
-            polarity: polarity_of_impl(tcx, of_trait, is_rustc_reservation),
-            constness: of_trait.constness,
-        }
-    })
 }
 
 fn check_impl_constness(
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
index 44cc2de..b167f31 100644
--- a/compiler/rustc_hir_analysis/src/collect/dump.rs
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -108,7 +108,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
 
         let vtable_entries = match tcx.hir_item(id).kind {
             hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
-                let trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate_identity();
+                let trait_ref = tcx.impl_trait_ref(def_id).instantiate_identity();
                 if trait_ref.has_non_region_param() {
                     tcx.dcx().span_err(
                         attr.span(),
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 129b26d..67284e1 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -514,17 +514,15 @@ pub(super) fn impl_super_outlives(
     tcx: TyCtxt<'_>,
     def_id: DefId,
 ) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
-    tcx.impl_trait_header(def_id).expect("expected an impl of trait").trait_ref.map_bound(
-        |trait_ref| {
-            let clause: ty::Clause<'_> = trait_ref.upcast(tcx);
-            tcx.mk_clauses_from_iter(util::elaborate(tcx, [clause]).filter(|clause| {
-                matches!(
-                    clause.kind().skip_binder(),
-                    ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::RegionOutlives(_)
-                )
-            }))
-        },
-    )
+    tcx.impl_trait_header(def_id).trait_ref.map_bound(|trait_ref| {
+        let clause: ty::Clause<'_> = trait_ref.upcast(tcx);
+        tcx.mk_clauses_from_iter(util::elaborate(tcx, [clause]).filter(|clause| {
+            matches!(
+                clause.kind().skip_binder(),
+                ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::RegionOutlives(_)
+            )
+        }))
+    })
 }
 
 struct AssocTyToOpaque<'tcx> {
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index ffdf2a2..e66accc 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -118,8 +118,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
 
             let impl_assoc_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
             let impl_def_id = tcx.parent(fn_def_id);
-            let impl_trait_ref_args =
-                tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity().args;
+            let impl_trait_ref_args = tcx.impl_trait_ref(impl_def_id).instantiate_identity().args;
 
             let impl_assoc_args =
                 impl_assoc_identity_args.rebase_onto(tcx, impl_def_id, impl_trait_ref_args);
@@ -162,9 +161,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                 if let Some(of_trait) = impl_.of_trait
                     && of_trait.defaultness.is_default()
                 {
-                    is_default_impl_trait = tcx
-                        .impl_trait_ref(def_id)
-                        .map(|t| ty::Binder::dummy(t.instantiate_identity()));
+                    is_default_impl_trait =
+                        Some(ty::Binder::dummy(tcx.impl_trait_ref(def_id).instantiate_identity()));
                 }
             }
             ItemKind::Trait(_, _, _, _, _, self_bounds, ..)
@@ -350,9 +348,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // before uses of `U`. This avoids false ambiguity errors
     // in trait checking. See `setup_constraining_predicates`
     // for details.
-    if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
+    if let Node::Item(&Item { kind: ItemKind::Impl(impl_), .. }) = node {
         let self_ty = tcx.type_of(def_id).instantiate_identity();
-        let trait_ref = tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::instantiate_identity);
+        let trait_ref =
+            impl_.of_trait.is_some().then(|| tcx.impl_trait_ref(def_id).instantiate_identity());
         cgp::setup_constraining_predicates(
             tcx,
             &mut predicates,
@@ -460,11 +459,12 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) {
     }
 
     if let hir::Node::Item(item) = node
-        && let hir::ItemKind::Impl(_) = item.kind
+        && let hir::ItemKind::Impl(impl_) = item.kind
     {
-        if let Some(of_trait) = tcx.impl_trait_ref(def_id) {
+        if impl_.of_trait.is_some() {
             debug!("visit impl trait_ref");
-            of_trait.instantiate_identity().visit_with(&mut collector);
+            let trait_ref = tcx.impl_trait_ref(def_id);
+            trait_ref.instantiate_identity().visit_with(&mut collector);
         }
 
         debug!("visit self_ty");
diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs
index f5821ae..125fc21 100644
--- a/compiler/rustc_hir_analysis/src/delegation.rs
+++ b/compiler/rustc_hir_analysis/src/delegation.rs
@@ -272,8 +272,7 @@ fn create_generic_args<'tcx>(
         (FnKind::AssocTraitImpl, FnKind::AssocTrait) => {
             let callee_generics = tcx.generics_of(sig_id);
             let parent = tcx.parent(def_id.into());
-            let parent_args =
-                tcx.impl_trait_header(parent).unwrap().trait_ref.instantiate_identity().args;
+            let parent_args = tcx.impl_trait_header(parent).trait_ref.instantiate_identity().args;
 
             let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id);
             let method_args = tcx.mk_args(&trait_args[callee_generics.parent_count..]);
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 1650517..25ba888 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -473,7 +473,7 @@ pub(crate) fn report_missing_self_ty_for_resolved_path(
         } else {
             // Find all the types that have an `impl` for the trait.
             tcx.all_impls(trait_def_id)
-                .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
+                .map(|impl_def_id| tcx.impl_trait_header(impl_def_id))
                 .filter(|header| {
                     // Consider only accessible traits
                     tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx)
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index eb66080..4ff8f5d 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -1387,10 +1387,7 @@ fn resolve_type_relative_path(
             (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
                 // `Self` in an impl of a trait -- we have a concrete self type and a
                 // trait reference.
-                let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
-                    // A cycle error occurred, most likely.
-                    self.dcx().span_bug(span, "expected cycle error");
-                };
+                let trait_ref = tcx.impl_trait_ref(impl_def_id);
 
                 self.probe_single_bound_for_assoc_item(
                     || {
@@ -1618,7 +1615,7 @@ fn probe_traits_that_match_assoc_ty(
                         .is_accessible_from(self.item_def_id(), tcx)
                     && tcx.all_impls(*trait_def_id)
                         .any(|impl_def_id| {
-                            let header = tcx.impl_trait_header(impl_def_id).unwrap();
+                            let header = tcx.impl_trait_header(impl_def_id);
                             let trait_ref = header.trait_ref.instantiate(
                                 tcx,
                                 infcx.fresh_args_for_item(DUMMY_SP, impl_def_id),
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 19ba166..3dede69 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -56,6 +56,7 @@
 pub(crate) fn check_impl_wf(
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
+    of_trait: bool,
 ) -> Result<(), ErrorGuaranteed> {
     debug_assert_matches!(tcx.def_kind(impl_def_id), DefKind::Impl { .. });
 
@@ -63,9 +64,9 @@ pub(crate) fn check_impl_wf(
     // since unconstrained type/const params cause ICEs in projection, so we want to
     // detect those specifically and project those to `TyKind::Error`.
     let mut res = tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id);
-    res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id));
+    res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id, of_trait));
 
-    if tcx.features().min_specialization() {
+    if of_trait && tcx.features().min_specialization() {
         res = res.and(check_min_specialization(tcx, impl_def_id));
     }
     res
@@ -74,6 +75,7 @@ pub(crate) fn check_impl_wf(
 pub(crate) fn enforce_impl_lifetime_params_are_constrained(
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
+    of_trait: bool,
 ) -> Result<(), ErrorGuaranteed> {
     let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();
 
@@ -83,7 +85,7 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
 
     let impl_generics = tcx.generics_of(impl_def_id);
     let impl_predicates = tcx.predicates_of(impl_def_id);
-    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
+    let impl_trait_ref = of_trait.then(|| tcx.impl_trait_ref(impl_def_id).instantiate_identity());
 
     impl_trait_ref.error_reported()?;
 
@@ -171,7 +173,8 @@ pub(crate) fn enforce_impl_non_lifetime_params_are_constrained(
 
     let impl_generics = tcx.generics_of(impl_def_id);
     let impl_predicates = tcx.predicates_of(impl_def_id);
-    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
+    let impl_trait_ref =
+        tcx.impl_opt_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
 
     impl_trait_ref.error_reported()?;
 
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 64a36e2..41af593 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -93,7 +93,7 @@ pub(super) fn check_min_specialization(
 }
 
 fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> {
-    let trait_ref = tcx.impl_trait_ref(impl1_def_id)?;
+    let trait_ref = tcx.impl_trait_ref(impl1_def_id);
     let trait_def = tcx.trait_def(trait_ref.skip_binder().def_id);
 
     let impl2_node = trait_def.ancestors(tcx, impl1_def_id.to_def_id()).ok()?.nth(1)?;
@@ -215,7 +215,7 @@ fn unconstrained_parent_impl_args<'tcx>(
     let impl_generic_predicates = tcx.predicates_of(impl_def_id);
     let mut unconstrained_parameters = FxHashSet::default();
     let mut constrained_params = FxHashSet::default();
-    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).instantiate_identity();
 
     // Unfortunately the functions in `constrained_generic_parameters` don't do
     // what we want here. We want only a list of constrained parameters while
@@ -224,7 +224,7 @@ fn unconstrained_parent_impl_args<'tcx>(
     for (clause, _) in impl_generic_predicates.predicates.iter() {
         if let ty::ClauseKind::Projection(proj) = clause.kind().skip_binder() {
             let unbound_trait_ref = proj.projection_term.trait_ref(tcx);
-            if Some(unbound_trait_ref) == impl_trait_ref {
+            if unbound_trait_ref == impl_trait_ref {
                 continue;
             }
 
@@ -373,7 +373,7 @@ fn check_predicates<'tcx>(
         .map(|(c, _span)| c.as_predicate());
 
     // Include the well-formed predicates of the type parameters of the impl.
-    for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().instantiate_identity().args {
+    for arg in tcx.impl_trait_ref(impl1_def_id).instantiate_identity().args {
         let Some(term) = arg.as_term() else {
             continue;
         };
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index fb6ebe0..880b0ca 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -792,7 +792,9 @@ fn annotate_expected_due_to_let_ty(
                 hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(_, lhs, rhs), .. }),
                 Some(TypeError::Sorts(ExpectedFound { expected, .. })),
             ) if rhs.hir_id == expr.hir_id
-                && self.typeck_results.borrow().expr_ty_adjusted_opt(lhs) == Some(expected) =>
+                && self.typeck_results.borrow().expr_ty_adjusted_opt(lhs) == Some(expected)
+                // let expressions being marked as `bool` is confusing (see issue #147665)
+                && !matches!(lhs.kind, hir::ExprKind::Let(..)) =>
             {
                 err.span_label(lhs.span, format!("expected because this is `{expected}`"));
             }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index c1dbf90..2605aa1 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -3629,7 +3629,7 @@ fn find_and_report_unsatisfied_index_impl(
             let ocx = ObligationCtxt::new_with_diagnostics(self);
             let impl_args = self.fresh_args_for_item(base_expr.span, impl_def_id);
             let impl_trait_ref =
-                self.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(self.tcx, impl_args);
+                self.tcx.impl_trait_ref(impl_def_id).instantiate(self.tcx, impl_args);
             let cause = self.misc(base_expr.span);
 
             // Match the impl self type against the base ty. If this fails,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index ed88e32..f478cab 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -711,7 +711,7 @@ fn blame_specific_expr_if_possible_for_derived_predicate_obligation(
             )
         } else {
             self.tcx
-                .impl_trait_ref(obligation.impl_or_alias_def_id)
+                .impl_opt_trait_ref(obligation.impl_or_alias_def_id)
                 .map(|impl_def| impl_def.skip_binder())
                 // It is possible that this is absent. In this case, we make no progress.
                 .ok_or(expr)?
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index a615ac9..99a9566 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -285,7 +285,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
             && let ty::AssocContainer::TraitImpl(Ok(trait_item_def_id)) = item.container
         {
             let impl_def_id = item.container_id(tcx);
-            let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
+            let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).instantiate_identity();
             let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto(
                 tcx,
                 impl_def_id,
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index b23e7ae..f7a0a55 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -18,8 +18,8 @@
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
 };
 use rustc_middle::ty::{
-    self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
-    TypeVisitableExt, UserArgs,
+    self, AssocContainer, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt,
+    TypeFoldable, TypeVisitableExt, UserArgs,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::{DUMMY_SP, Span};
@@ -272,7 +272,7 @@ fn fresh_receiver_args(
             probe::InherentImplPick => {
                 let impl_def_id = pick.item.container_id(self.tcx);
                 assert!(
-                    self.tcx.impl_trait_ref(impl_def_id).is_none(),
+                    matches!(pick.item.container, AssocContainer::InherentImpl),
                     "impl {impl_def_id:?} is not an inherent impl"
                 );
                 self.fresh_args_for_item(self.span, impl_def_id)
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 04f112e..35be28f 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -242,7 +242,7 @@ pub(crate) fn lookup_method(
                         match *source {
                             // Note: this cannot come from an inherent impl,
                             // because the first probing succeeded.
-                            CandidateSource::Impl(def) => self.tcx.trait_id_of_impl(def),
+                            CandidateSource::Impl(def) => Some(self.tcx.impl_trait_id(def)),
                             CandidateSource::Trait(_) => None,
                         }
                     })
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 8a9d394..14043be 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1176,9 +1176,6 @@ fn pick(mut self) -> PickResult<'tcx> {
         // things failed, so lets look at all traits, for diagnostic purposes now:
         self.reset();
 
-        let span = self.span;
-        let tcx = self.tcx;
-
         self.assemble_extension_candidates_for_all_traits();
 
         let out_of_scope_traits = match self.pick_core(&mut Vec::new()) {
@@ -1187,10 +1184,7 @@ fn pick(mut self) -> PickResult<'tcx> {
                 .into_iter()
                 .map(|source| match source {
                     CandidateSource::Trait(id) => id,
-                    CandidateSource::Impl(impl_id) => match tcx.trait_id_of_impl(impl_id) {
-                        Some(id) => id,
-                        None => span_bug!(span, "found inherent method when looking at traits"),
-                    },
+                    CandidateSource::Impl(impl_id) => self.tcx.impl_trait_id(impl_id),
                 })
                 .collect(),
             Some(Err(MethodError::NoMatch(NoMatchData {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 44602e6..aacd2f5 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1962,8 +1962,8 @@ fn note_candidates_on_method_error(
                     // Provide the best span we can. Use the item, if local to crate, else
                     // the impl, if local to crate (item may be defaulted), else nothing.
                     let Some(item) = self.associated_value(impl_did, item_name).or_else(|| {
-                        let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
-                        self.associated_value(impl_trait_ref.skip_binder().def_id, item_name)
+                        let impl_trait_id = self.tcx.impl_opt_trait_id(impl_did)?;
+                        self.associated_value(impl_trait_id, item_name)
                     }) else {
                         continue;
                     };
@@ -1978,7 +1978,7 @@ fn note_candidates_on_method_error(
 
                     let impl_ty = self.tcx.at(span).type_of(impl_did).instantiate_identity();
 
-                    let insertion = match self.tcx.impl_trait_ref(impl_did) {
+                    let insertion = match self.tcx.impl_opt_trait_ref(impl_did) {
                         None => String::new(),
                         Some(trait_ref) => {
                             format!(
@@ -2013,7 +2013,7 @@ fn note_candidates_on_method_error(
                         err.note(note_str);
                     }
                     if let Some(sugg_span) = sugg_span
-                        && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did)
+                        && let Some(trait_ref) = self.tcx.impl_opt_trait_ref(impl_did)
                         && let Some(sugg) = print_disambiguation_help(
                             self.tcx,
                             err,
@@ -3720,7 +3720,7 @@ fn suggest_traits_to_import(
                 static_candidates.iter().all(|sc| match *sc {
                     CandidateSource::Trait(def_id) => def_id != info.def_id,
                     CandidateSource::Impl(def_id) => {
-                        self.tcx.trait_id_of_impl(def_id) != Some(info.def_id)
+                        self.tcx.impl_opt_trait_id(def_id) != Some(info.def_id)
                     }
                 })
             })
@@ -3980,11 +3980,7 @@ enum Introducer {
                     if self
                         .tcx
                         .all_impls(candidate.def_id)
-                        .map(|imp_did| {
-                            self.tcx.impl_trait_header(imp_did).expect(
-                                "inherent impls can't be candidates, only trait impls can be",
-                            )
-                        })
+                        .map(|imp_did| self.tcx.impl_trait_header(imp_did))
                         .filter(|header| header.polarity != ty::ImplPolarity::Positive)
                         .any(|header| {
                             let imp = header.trait_ref.instantiate_identity();
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index f7728ba..96e85fd 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -872,7 +872,7 @@ fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool {
                     let mut self_chunk_words = **other_chunk_words;
                     for word in self_chunk_words[0..num_words].iter_mut().rev() {
                         *word = !*word & tail_mask;
-                        tail_mask = u64::MAX;
+                        tail_mask = Word::MAX;
                     }
                     let self_chunk_count = chunk_domain_size - *other_chunk_count;
                     debug_assert_eq!(
@@ -887,7 +887,7 @@ fn subtract(&mut self, other: &ChunkedBitSet<T>) -> bool {
                 ) => {
                     // See `ChunkedBitSet::union` for details on what is happening here.
                     let num_words = num_words(chunk_domain_size as usize);
-                    let op = |a: u64, b: u64| a & !b;
+                    let op = |a: Word, b: Word| a & !b;
                     if !bitwise_changes(
                         &self_chunk_words[0..num_words],
                         &other_chunk_words[0..num_words],
diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs
index 1d92cfb..8f028b1 100644
--- a/compiler/rustc_lint/src/default_could_be_derived.rs
+++ b/compiler/rustc_lint/src/default_could_be_derived.rs
@@ -1,14 +1,12 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
-use rustc_hir::attrs::AttributeKind;
-use rustc_hir::find_attr;
 use rustc_middle::ty;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::{declare_lint, impl_lint_pass};
-use rustc_span::Symbol;
+use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
 
 use crate::{LateContext, LateLintPass};
 
@@ -52,27 +50,24 @@
     @feature_gate = default_field_values;
 }
 
-#[derive(Default)]
-pub(crate) struct DefaultCouldBeDerived;
-
-impl_lint_pass!(DefaultCouldBeDerived => [DEFAULT_OVERRIDES_DEFAULT_FIELDS]);
+declare_lint_pass!(DefaultCouldBeDerived => [DEFAULT_OVERRIDES_DEFAULT_FIELDS]);
 
 impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
         // Look for manual implementations of `Default`.
-        let Some(default_def_id) = cx.tcx.get_diagnostic_item(sym::Default) else { return };
+        let hir::ImplItemImplKind::Trait { trait_item_def_id, .. } = impl_item.impl_kind else {
+            return;
+        };
+        if !trait_item_def_id.is_ok_and(|id| cx.tcx.is_diagnostic_item(sym::default_fn, id)) {
+            return;
+        }
         let hir::ImplItemKind::Fn(_sig, body_id) = impl_item.kind else { return };
-        let parent = cx.tcx.parent(impl_item.owner_id.to_def_id());
-        if find_attr!(cx.tcx.get_all_attrs(parent), AttributeKind::AutomaticallyDerived(..)) {
+        let impl_id = cx.tcx.local_parent(impl_item.owner_id.def_id);
+        if cx.tcx.is_automatically_derived(impl_id.to_def_id()) {
             // We don't care about what `#[derive(Default)]` produces in this lint.
             return;
         }
-        let Some(trait_ref) = cx.tcx.impl_trait_ref(parent) else { return };
-        let trait_ref = trait_ref.instantiate_identity();
-        if trait_ref.def_id != default_def_id {
-            return;
-        }
-        let ty = trait_ref.self_ty();
+        let ty = cx.tcx.type_of(impl_id).instantiate_identity();
         let ty::Adt(def, _) = ty.kind() else { return };
 
         // We now know we have a manually written definition of a `<Type as Default>::default()`.
@@ -150,11 +145,10 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
             return;
         }
 
-        let Some(local) = parent.as_local() else { return };
-        let hir_id = cx.tcx.local_def_id_to_hir_id(local);
-        let hir::Node::Item(item) = cx.tcx.hir_node(hir_id) else { return };
-        cx.tcx.node_span_lint(DEFAULT_OVERRIDES_DEFAULT_FIELDS, hir_id, item.span, |diag| {
-            mk_lint(cx.tcx, diag, type_def_id, parent, orig_fields, fields);
+        let hir_id = cx.tcx.local_def_id_to_hir_id(impl_id);
+        let span = cx.tcx.hir_span_with_body(hir_id);
+        cx.tcx.node_span_lint(DEFAULT_OVERRIDES_DEFAULT_FIELDS, hir_id, span, |diag| {
+            mk_lint(cx.tcx, diag, type_def_id, orig_fields, fields, span);
         });
     }
 }
@@ -163,9 +157,9 @@ fn mk_lint(
     tcx: TyCtxt<'_>,
     diag: &mut Diag<'_, ()>,
     type_def_id: DefId,
-    impl_def_id: DefId,
     orig_fields: FxHashMap<Symbol, &hir::FieldDef<'_>>,
     fields: &[hir::ExprField<'_>],
+    impl_span: Span,
 ) {
     diag.primary_message("`Default` impl doesn't use the declared default field values");
 
@@ -186,18 +180,14 @@ fn mk_lint(
     if removed_all_fields {
         let msg = "to avoid divergence in behavior between `Struct { .. }` and \
                    `<Struct as Default>::default()`, derive the `Default`";
-        if let Some(hir::Node::Item(impl_)) = tcx.hir_get_if_local(impl_def_id) {
-            diag.multipart_suggestion_verbose(
-                msg,
-                vec![
-                    (tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()),
-                    (impl_.span, String::new()),
-                ],
-                Applicability::MachineApplicable,
-            );
-        } else {
-            diag.help(msg);
-        }
+        diag.multipart_suggestion_verbose(
+            msg,
+            vec![
+                (tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()),
+                (impl_span, String::new()),
+            ],
+            Applicability::MachineApplicable,
+        );
     } else {
         let msg = "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \
                    avoid them diverging over time";
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index b2abd0e..b4c1848 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -191,7 +191,7 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
         BuiltinCombinedModuleLateLintPass,
         [
             ForLoopsOverFallibles: ForLoopsOverFallibles,
-            DefaultCouldBeDerived: DefaultCouldBeDerived::default(),
+            DefaultCouldBeDerived: DefaultCouldBeDerived,
             DerefIntoDynSupertrait: DerefIntoDynSupertrait,
             DropForgetUseless: DropForgetUseless,
             ImproperCTypesLint: ImproperCTypesLint,
diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs
index 413525e..0cac91c 100644
--- a/compiler/rustc_lint/src/lifetime_syntax.rs
+++ b/compiler/rustc_lint/src/lifetime_syntax.rs
@@ -3,6 +3,7 @@
 use rustc_hir::{self as hir, LifetimeSource};
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::Span;
+use rustc_span::def_id::LocalDefId;
 use tracing::instrument;
 
 use crate::{LateContext, LateLintPass, LintContext, lints};
@@ -78,11 +79,11 @@ impl<'tcx> LateLintPass<'tcx> for LifetimeSyntax {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
-        _: hir::intravisit::FnKind<'tcx>,
+        _: intravisit::FnKind<'tcx>,
         fd: &'tcx hir::FnDecl<'tcx>,
         _: &'tcx hir::Body<'tcx>,
-        _: rustc_span::Span,
-        _: rustc_span::def_id::LocalDefId,
+        _: Span,
+        _: LocalDefId,
     ) {
         check_fn_like(cx, fd);
     }
@@ -97,11 +98,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, ti: &'tcx hir::TraitItem<
     }
 
     #[instrument(skip_all)]
-    fn check_foreign_item(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        fi: &'tcx rustc_hir::ForeignItem<'tcx>,
-    ) {
+    fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, fi: &'tcx hir::ForeignItem<'tcx>) {
         match fi.kind {
             hir::ForeignItemKind::Fn(fn_sig, _idents, _generics) => check_fn_like(cx, fn_sig.decl),
             hir::ForeignItemKind::Static(..) => {}
@@ -111,35 +108,47 @@ fn check_foreign_item(
 }
 
 fn check_fn_like<'tcx>(cx: &LateContext<'tcx>, fd: &'tcx hir::FnDecl<'tcx>) {
-    let mut input_map = Default::default();
-    let mut output_map = Default::default();
+    if fd.inputs.is_empty() {
+        return;
+    }
+    let hir::FnRetTy::Return(output) = fd.output else {
+        return;
+    };
+
+    let mut map: FxIndexMap<hir::LifetimeKind, LifetimeGroup<'_>> = FxIndexMap::default();
+
+    LifetimeInfoCollector::collect(output, |info| {
+        let group = map.entry(info.lifetime.kind).or_default();
+        group.outputs.push(info);
+    });
+    if map.is_empty() {
+        return;
+    }
 
     for input in fd.inputs {
-        LifetimeInfoCollector::collect(input, &mut input_map);
-    }
-
-    if let hir::FnRetTy::Return(output) = fd.output {
-        LifetimeInfoCollector::collect(output, &mut output_map);
-    }
-
-    report_mismatches(cx, &input_map, &output_map);
-}
-
-#[instrument(skip_all)]
-fn report_mismatches<'tcx>(
-    cx: &LateContext<'tcx>,
-    inputs: &LifetimeInfoMap<'tcx>,
-    outputs: &LifetimeInfoMap<'tcx>,
-) {
-    for (resolved_lifetime, output_info) in outputs {
-        if let Some(input_info) = inputs.get(resolved_lifetime) {
-            if !lifetimes_use_matched_syntax(input_info, output_info) {
-                emit_mismatch_diagnostic(cx, input_info, output_info);
+        LifetimeInfoCollector::collect(input, |info| {
+            if let Some(group) = map.get_mut(&info.lifetime.kind) {
+                group.inputs.push(info);
             }
+        });
+    }
+
+    for LifetimeGroup { ref inputs, ref outputs } in map.into_values() {
+        if inputs.is_empty() {
+            continue;
+        }
+        if !lifetimes_use_matched_syntax(inputs, outputs) {
+            emit_mismatch_diagnostic(cx, inputs, outputs);
         }
     }
 }
 
+#[derive(Default)]
+struct LifetimeGroup<'tcx> {
+    inputs: Vec<Info<'tcx>>,
+    outputs: Vec<Info<'tcx>>,
+}
+
 #[derive(Debug, Copy, Clone, PartialEq)]
 enum LifetimeSyntaxCategory {
     Hidden,
@@ -148,11 +157,11 @@ enum LifetimeSyntaxCategory {
 }
 
 impl LifetimeSyntaxCategory {
-    fn new(syntax_source: (hir::LifetimeSyntax, LifetimeSource)) -> Option<Self> {
+    fn new(lifetime: &hir::Lifetime) -> Option<Self> {
         use LifetimeSource::*;
         use hir::LifetimeSyntax::*;
 
-        match syntax_source {
+        match (lifetime.syntax, lifetime.source) {
             // E.g. `&T`.
             (Implicit, Reference) |
             // E.g. `&'_ T`.
@@ -216,7 +225,7 @@ pub fn len(&self) -> LifetimeSyntaxCategories<usize> {
 
     pub fn iter_unnamed(&self) -> impl Iterator<Item = &T> {
         let Self { hidden, elided, named: _ } = self;
-        [hidden.iter(), elided.iter()].into_iter().flatten()
+        std::iter::chain(hidden, elided)
     }
 }
 
@@ -233,22 +242,8 @@ fn add(self, rhs: Self) -> Self::Output {
 }
 
 fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool {
-    let mut syntax_counts = LifetimeSyntaxCategories::<usize>::default();
-
-    for info in input_info.iter().chain(output_info) {
-        if let Some(category) = info.lifetime_syntax_category() {
-            *syntax_counts.select(category) += 1;
-        }
-    }
-
-    tracing::debug!(?syntax_counts);
-
-    matches!(
-        syntax_counts,
-        LifetimeSyntaxCategories { hidden: _, elided: 0, named: 0 }
-            | LifetimeSyntaxCategories { hidden: 0, elided: _, named: 0 }
-            | LifetimeSyntaxCategories { hidden: 0, elided: 0, named: _ }
-    )
+    let (first, inputs) = input_info.split_first().unwrap();
+    std::iter::chain(inputs, output_info).all(|info| info.syntax_category == first.syntax_category)
 }
 
 fn emit_mismatch_diagnostic<'tcx>(
@@ -310,18 +305,13 @@ fn emit_mismatch_diagnostic<'tcx>(
         use LifetimeSource::*;
         use hir::LifetimeSyntax::*;
 
-        let syntax_source = info.syntax_source();
+        let lifetime = info.lifetime;
 
-        if let (_, Other) = syntax_source {
-            // Ignore any other kind of lifetime.
-            continue;
-        }
-
-        if let (ExplicitBound, _) = syntax_source {
+        if lifetime.syntax == ExplicitBound {
             bound_lifetime = Some(info);
         }
 
-        match syntax_source {
+        match (lifetime.syntax, lifetime.source) {
             // E.g. `&T`.
             (Implicit, Reference) => {
                 suggest_change_to_explicit_anonymous.push(info);
@@ -341,8 +331,8 @@ fn emit_mismatch_diagnostic<'tcx>(
                 suggest_change_to_explicit_bound.push(info);
             }
 
-            // E.g. `ContainsLifetime<'_>`.
-            (ExplicitAnonymous, Path { .. }) => {
+            // E.g. `ContainsLifetime<'_>`, `+ '_`, `+ use<'_>`.
+            (ExplicitAnonymous, Path { .. } | OutlivesBound | PreciseCapturing) => {
                 suggest_change_to_explicit_bound.push(info);
             }
 
@@ -353,8 +343,8 @@ fn emit_mismatch_diagnostic<'tcx>(
                 suggest_change_to_explicit_anonymous.push(info);
             }
 
-            // E.g. `ContainsLifetime<'a>`.
-            (ExplicitBound, Path { .. }) => {
+            // E.g. `ContainsLifetime<'a>`, `+ 'a`, `+ use<'a>`.
+            (ExplicitBound, Path { .. } | OutlivesBound | PreciseCapturing) => {
                 suggest_change_to_mixed_explicit_anonymous.push(info);
                 suggest_change_to_explicit_anonymous.push(info);
             }
@@ -363,29 +353,18 @@ fn emit_mismatch_diagnostic<'tcx>(
                 panic!("This syntax / source combination is not possible");
             }
 
-            // E.g. `+ '_`, `+ use<'_>`.
-            (ExplicitAnonymous, OutlivesBound | PreciseCapturing) => {
-                suggest_change_to_explicit_bound.push(info);
-            }
-
-            // E.g. `+ 'a`, `+ use<'a>`.
-            (ExplicitBound, OutlivesBound | PreciseCapturing) => {
-                suggest_change_to_mixed_explicit_anonymous.push(info);
-                suggest_change_to_explicit_anonymous.push(info);
-            }
-
             (_, Other) => {
                 panic!("This syntax / source combination has already been skipped");
             }
         }
 
-        if matches!(syntax_source, (_, Path { .. } | OutlivesBound | PreciseCapturing)) {
+        if matches!(lifetime.source, Path { .. } | OutlivesBound | PreciseCapturing) {
             allow_suggesting_implicit = false;
         }
 
-        match syntax_source {
-            (_, Reference) => saw_a_reference = true,
-            (_, Path { .. }) => saw_a_path = true,
+        match lifetime.source {
+            Reference => saw_a_reference = true,
+            Path { .. } => saw_a_path = true,
             _ => {}
         }
     }
@@ -393,9 +372,7 @@ fn emit_mismatch_diagnostic<'tcx>(
     let categorize = |infos: &[Info<'_>]| {
         let mut categories = LifetimeSyntaxCategories::<Vec<_>>::default();
         for info in infos {
-            if let Some(category) = info.lifetime_syntax_category() {
-                categories.select(category).push(info.reporting_span());
-            }
+            categories.select(info.syntax_category).push(info.reporting_span());
         }
         categories
     };
@@ -407,10 +384,10 @@ fn emit_mismatch_diagnostic<'tcx>(
         |infos: &[&Info<'_>]| infos.iter().map(|i| i.removing_span()).collect::<Vec<_>>();
 
     let explicit_bound_suggestion = bound_lifetime.map(|info| {
-        build_mismatch_suggestion(info.lifetime_name(), &suggest_change_to_explicit_bound)
+        build_mismatch_suggestion(info.lifetime.ident.as_str(), &suggest_change_to_explicit_bound)
     });
 
-    let is_bound_static = bound_lifetime.is_some_and(|info| info.is_static());
+    let is_bound_static = bound_lifetime.is_some_and(|info| info.lifetime.is_static());
 
     tracing::debug!(?bound_lifetime, ?explicit_bound_suggestion, ?is_bound_static);
 
@@ -517,33 +494,17 @@ fn build_mismatch_suggestion(
 
 #[derive(Debug)]
 struct Info<'tcx> {
-    type_span: Span,
-    referenced_type_span: Option<Span>,
     lifetime: &'tcx hir::Lifetime,
+    syntax_category: LifetimeSyntaxCategory,
+    ty: &'tcx hir::Ty<'tcx>,
 }
 
 impl<'tcx> Info<'tcx> {
-    fn syntax_source(&self) -> (hir::LifetimeSyntax, LifetimeSource) {
-        (self.lifetime.syntax, self.lifetime.source)
-    }
-
-    fn lifetime_syntax_category(&self) -> Option<LifetimeSyntaxCategory> {
-        LifetimeSyntaxCategory::new(self.syntax_source())
-    }
-
-    fn lifetime_name(&self) -> &str {
-        self.lifetime.ident.as_str()
-    }
-
-    fn is_static(&self) -> bool {
-        self.lifetime.is_static()
-    }
-
     /// When reporting a lifetime that is implicit, we expand the span
     /// to include the type. Otherwise we end up pointing at nothing,
     /// which is a bit confusing.
     fn reporting_span(&self) -> Span {
-        if self.lifetime.is_implicit() { self.type_span } else { self.lifetime.ident.span }
+        if self.lifetime.is_implicit() { self.ty.span } else { self.lifetime.ident.span }
     }
 
     /// When removing an explicit lifetime from a reference,
@@ -560,12 +521,10 @@ fn reporting_span(&self) -> Span {
     /// ```
     // FIXME: Ideally, we'd also remove the lifetime declaration.
     fn removing_span(&self) -> Span {
-        let mut span = self.suggestion("'dummy").0;
-
-        if let Some(referenced_type_span) = self.referenced_type_span {
-            span = span.until(referenced_type_span);
+        let mut span = self.lifetime.ident.span;
+        if let hir::TyKind::Ref(_, mut_ty) = self.ty.kind {
+            span = span.until(mut_ty.ty.span);
         }
-
         span
     }
 
@@ -574,46 +533,38 @@ fn suggestion(&self, lifetime_name: &str) -> (Span, String) {
     }
 }
 
-type LifetimeInfoMap<'tcx> = FxIndexMap<&'tcx hir::LifetimeKind, Vec<Info<'tcx>>>;
-
-struct LifetimeInfoCollector<'a, 'tcx> {
-    type_span: Span,
-    referenced_type_span: Option<Span>,
-    map: &'a mut LifetimeInfoMap<'tcx>,
+struct LifetimeInfoCollector<'tcx, F> {
+    info_func: F,
+    ty: &'tcx hir::Ty<'tcx>,
 }
 
-impl<'a, 'tcx> LifetimeInfoCollector<'a, 'tcx> {
-    fn collect(ty: &'tcx hir::Ty<'tcx>, map: &'a mut LifetimeInfoMap<'tcx>) {
-        let mut this = Self { type_span: ty.span, referenced_type_span: None, map };
+impl<'tcx, F> LifetimeInfoCollector<'tcx, F>
+where
+    F: FnMut(Info<'tcx>),
+{
+    fn collect(ty: &'tcx hir::Ty<'tcx>, info_func: F) {
+        let mut this = Self { info_func, ty };
 
         intravisit::walk_unambig_ty(&mut this, ty);
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for LifetimeInfoCollector<'a, 'tcx> {
+impl<'tcx, F> Visitor<'tcx> for LifetimeInfoCollector<'tcx, F>
+where
+    F: FnMut(Info<'tcx>),
+{
     #[instrument(skip(self))]
     fn visit_lifetime(&mut self, lifetime: &'tcx hir::Lifetime) {
-        let type_span = self.type_span;
-        let referenced_type_span = self.referenced_type_span;
-
-        let info = Info { type_span, referenced_type_span, lifetime };
-
-        self.map.entry(&lifetime.kind).or_default().push(info);
+        if let Some(syntax_category) = LifetimeSyntaxCategory::new(lifetime) {
+            let info = Info { lifetime, syntax_category, ty: self.ty };
+            (self.info_func)(info);
+        }
     }
 
     #[instrument(skip(self))]
     fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) -> Self::Result {
-        let old_type_span = self.type_span;
-        let old_referenced_type_span = self.referenced_type_span;
-
-        self.type_span = ty.span;
-        if let hir::TyKind::Ref(_, ty) = ty.kind {
-            self.referenced_type_span = Some(ty.ty.span);
-        }
-
+        let old_ty = std::mem::replace(&mut self.ty, ty.as_unambig_ty());
         intravisit::walk_ty(self, ty);
-
-        self.type_span = old_type_span;
-        self.referenced_type_span = old_referenced_type_span;
+        self.ty = old_ty;
     }
 }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index eaec0c9..7c66559 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -814,7 +814,7 @@ fn get_nullable_type<'tcx>(
 
 /// A type is niche-optimization candidate iff:
 /// - Is a zero-sized type with alignment 1 (a “1-ZST”).
-/// - Has no fields.
+/// - Is either a struct/tuple with no fields, or an enum with no variants.
 /// - Does not have the `#[non_exhaustive]` attribute.
 fn is_niche_optimization_candidate<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -828,7 +828,7 @@ fn is_niche_optimization_candidate<'tcx>(
     match ty.kind() {
         ty::Adt(ty_def, _) => {
             let non_exhaustive = ty_def.is_variant_list_non_exhaustive();
-            let empty = (ty_def.is_struct() && ty_def.all_fields().next().is_none())
+            let empty = (ty_def.is_struct() && ty_def.non_enum_variant().fields.is_empty())
                 || (ty_def.is_enum() && ty_def.variants().is_empty());
 
             !non_exhaustive && empty
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index db66938..e13ef7e 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -2115,7 +2115,8 @@ fn encode_impls(&mut self) -> LazyArray<TraitImpls> {
             };
             let def_id = id.owner_id.to_def_id();
 
-            if of_trait && let Some(header) = tcx.impl_trait_header(def_id) {
+            if of_trait {
+                let header = tcx.impl_trait_header(def_id);
                 record!(self.tables.impl_trait_header[def_id] <- header);
 
                 self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id));
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index f0d96c6..d47d811 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -13,6 +13,8 @@ pub fn codegen_instance_attrs(
         self,
         instance_kind: InstanceKind<'_>,
     ) -> Cow<'tcx, CodegenFnAttrs> {
+        // NOTE: we try to not clone the `CodegenFnAttrs` when that is not needed.
+        // The `to_mut` method used below clones the inner value.
         let mut attrs = Cow::Borrowed(self.codegen_fn_attrs(instance_kind.def_id()));
 
         // Drop the `#[naked]` attribute on non-item `InstanceKind`s, like the shims that
@@ -23,6 +25,28 @@ pub fn codegen_instance_attrs(
             }
         }
 
+        // A shim created by `#[track_caller]` should not inherit any attributes
+        // that modify the symbol name. Failing to remove these attributes from
+        // the shim leads to errors like `symbol `foo` is already defined`.
+        //
+        // A `ClosureOnceShim` with the track_caller attribute does not have a symbol,
+        // and therefore can be skipped here.
+        if let InstanceKind::ReifyShim(_, _) = instance_kind
+            && attrs.flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
+        {
+            if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
+                attrs.to_mut().flags.remove(CodegenFnAttrFlags::NO_MANGLE);
+            }
+
+            if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
+                attrs.to_mut().flags.remove(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
+            }
+
+            if attrs.symbol_name.is_some() {
+                attrs.to_mut().symbol_name = None;
+            }
+        }
+
         attrs
     }
 }
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index 0d2e236..aae815c 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -1,4 +1,4 @@
-use std::sync::OnceLock;
+use std::sync::{Arc, OnceLock};
 
 use rustc_data_structures::graph;
 use rustc_data_structures::graph::dominators::{Dominators, dominators};
@@ -14,7 +14,8 @@
 #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct BasicBlocks<'tcx> {
     basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
-    cache: Cache,
+    /// Use an `Arc` so we can share the cache when we clone the MIR body, as borrowck does.
+    cache: Arc<Cache>,
 }
 
 // Typically 95%+ of basic blocks have 4 or fewer predecessors.
@@ -38,9 +39,10 @@ struct Cache {
 impl<'tcx> BasicBlocks<'tcx> {
     #[inline]
     pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
-        BasicBlocks { basic_blocks, cache: Cache::default() }
+        BasicBlocks { basic_blocks, cache: Arc::new(Cache::default()) }
     }
 
+    #[inline]
     pub fn dominators(&self) -> &Dominators<BasicBlock> {
         self.cache.dominators.get_or_init(|| dominators(self))
     }
@@ -104,7 +106,14 @@ pub fn as_mut_preserves_cfg(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockDa
     /// All other methods that allow you to mutate the basic blocks also call this method
     /// themselves, thereby avoiding any risk of accidentally cache invalidation.
     pub fn invalidate_cfg_cache(&mut self) {
-        self.cache = Cache::default();
+        if let Some(cache) = Arc::get_mut(&mut self.cache) {
+            // If we only have a single reference to this cache, clear it.
+            *cache = Cache::default();
+        } else {
+            // If we have several references to this cache, overwrite the pointer itself so other
+            // users can continue to use their (valid) cache.
+            self.cache = Arc::new(Cache::default());
+        }
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 4249914..62711ad 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -696,6 +696,28 @@ pub fn as_goto(&self) -> Option<BasicBlock> {
             _ => None,
         }
     }
+
+    /// Returns true if the terminator can write to memory.
+    pub fn can_write_to_memory(&self) -> bool {
+        match self {
+            TerminatorKind::Goto { .. }
+            | TerminatorKind::SwitchInt { .. }
+            | TerminatorKind::UnwindResume
+            | TerminatorKind::UnwindTerminate(_)
+            | TerminatorKind::Return
+            | TerminatorKind::Assert { .. }
+            | TerminatorKind::CoroutineDrop
+            | TerminatorKind::FalseEdge { .. }
+            | TerminatorKind::FalseUnwind { .. }
+            | TerminatorKind::Unreachable => false,
+            TerminatorKind::Call { .. }
+            | TerminatorKind::Drop { .. }
+            | TerminatorKind::TailCall { .. }
+            // Yield writes to the resume_arg place.
+            | TerminatorKind::Yield { .. }
+            | TerminatorKind::InlineAsm { .. } => true,
+        }
+    }
 }
 
 #[derive(Copy, Clone, Debug)]
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index cad10fc..fd46a65 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -200,8 +200,8 @@ impl EraseType for Option<mir::DestructuredConstant<'_>> {
     type Result = [u8; size_of::<Option<mir::DestructuredConstant<'static>>>()];
 }
 
-impl EraseType for Option<ty::ImplTraitHeader<'_>> {
-    type Result = [u8; size_of::<Option<ty::ImplTraitHeader<'static>>>()];
+impl EraseType for ty::ImplTraitHeader<'_> {
+    type Result = [u8; size_of::<ty::ImplTraitHeader<'static>>()];
 }
 
 impl EraseType for Option<ty::EarlyBinder<'_, Ty<'_>>> {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 448c26e..3c4a4d2 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1104,8 +1104,7 @@
     }
 
     /// Given an `impl_id`, return the trait it implements along with some header information.
-    /// Return `None` if this is an inherent impl.
-    query impl_trait_header(impl_id: DefId) -> Option<ty::ImplTraitHeader<'tcx>> {
+    query impl_trait_header(impl_id: DefId) -> ty::ImplTraitHeader<'tcx> {
         desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
         cache_on_disk_if { impl_id.is_local() }
         separate_provide_extern
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index de2b2e6..545235c 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -679,7 +679,7 @@ fn impl_is_default(self, impl_def_id: DefId) -> bool {
     }
 
     fn impl_trait_ref(self, impl_def_id: DefId) -> ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>> {
-        self.impl_trait_ref(impl_def_id).unwrap()
+        self.impl_trait_ref(impl_def_id)
     }
 
     fn impl_polarity(self, impl_def_id: DefId) -> ty::ImplPolarity {
@@ -3472,7 +3472,7 @@ pub fn is_stable_const_fn(self, def_id: DefId) -> bool {
     /// Whether the trait impl is marked const. This does not consider stability or feature gates.
     pub fn is_const_trait_impl(self, def_id: DefId) -> bool {
         self.def_kind(def_id) == DefKind::Impl { of_trait: true }
-            && self.impl_trait_header(def_id).unwrap().constness == hir::Constness::Const
+            && self.impl_trait_header(def_id).constness == hir::Constness::Const
     }
 
     pub fn is_sdylib_interface_build(self) -> bool {
@@ -3530,19 +3530,6 @@ pub fn metadata_dep_node(self) -> crate::dep_graph::DepNode {
         crate::dep_graph::make_metadata(self)
     }
 
-    /// Given an `impl_id`, return the trait it implements.
-    /// Return `None` if this is an inherent impl.
-    pub fn impl_trait_ref(
-        self,
-        def_id: impl IntoQueryParam<DefId>,
-    ) -> Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>> {
-        Some(self.impl_trait_header(def_id)?.trait_ref)
-    }
-
-    pub fn impl_polarity(self, def_id: impl IntoQueryParam<DefId>) -> ty::ImplPolarity {
-        self.impl_trait_header(def_id).map_or(ty::ImplPolarity::Positive, |h| h.polarity)
-    }
-
     pub fn needs_coroutine_by_move_body_def_id(self, def_id: DefId) -> bool {
         if let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure)) =
             self.coroutine_kind(def_id)
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index b6adc60..5ca631f 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1614,8 +1614,8 @@ pub fn impls_are_allowed_to_overlap(
         def_id1: DefId,
         def_id2: DefId,
     ) -> Option<ImplOverlapKind> {
-        let impl1 = self.impl_trait_header(def_id1).unwrap();
-        let impl2 = self.impl_trait_header(def_id2).unwrap();
+        let impl1 = self.impl_trait_header(def_id1);
+        let impl2 = self.impl_trait_header(def_id2);
 
         let trait_ref1 = impl1.trait_ref.skip_binder();
         let trait_ref2 = impl2.trait_ref.skip_binder();
@@ -1913,12 +1913,6 @@ pub fn coroutine_layout(
         }
     }
 
-    /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.
-    /// If it implements no trait, returns `None`.
-    pub fn trait_id_of_impl(self, def_id: DefId) -> Option<DefId> {
-        self.impl_trait_ref(def_id).map(|tr| tr.skip_binder().def_id)
-    }
-
     /// If the given `DefId` is an associated item, returns the `DefId` and `DefKind` of the parent trait or impl.
     pub fn assoc_parent(self, def_id: DefId) -> Option<(DefId, DefKind)> {
         if !self.def_kind(def_id).is_assoc() {
@@ -1943,6 +1937,14 @@ pub fn trait_of_assoc(self, def_id: DefId) -> Option<DefId> {
         }
     }
 
+    pub fn impl_is_of_trait(self, def_id: impl IntoQueryParam<DefId>) -> bool {
+        let def_id = def_id.into_query_param();
+        let DefKind::Impl { of_trait } = self.def_kind(def_id) else {
+            panic!("expected Impl for {def_id:?}");
+        };
+        of_trait
+    }
+
     /// If the given `DefId` is an associated item of an impl,
     /// returns the `DefId` of the impl; otherwise returns `None`.
     pub fn impl_of_assoc(self, def_id: DefId) -> Option<DefId> {
@@ -1970,6 +1972,40 @@ pub fn trait_impl_of_assoc(self, def_id: DefId) -> Option<DefId> {
         }
     }
 
+    pub fn impl_polarity(self, def_id: impl IntoQueryParam<DefId>) -> ty::ImplPolarity {
+        self.impl_trait_header(def_id).polarity
+    }
+
+    /// Given an `impl_id`, return the trait it implements.
+    pub fn impl_trait_ref(
+        self,
+        def_id: impl IntoQueryParam<DefId>,
+    ) -> ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>> {
+        self.impl_trait_header(def_id).trait_ref
+    }
+
+    /// Given an `impl_id`, return the trait it implements.
+    /// Returns `None` if it is an inherent impl.
+    pub fn impl_opt_trait_ref(
+        self,
+        def_id: impl IntoQueryParam<DefId>,
+    ) -> Option<ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>>> {
+        let def_id = def_id.into_query_param();
+        self.impl_is_of_trait(def_id).then(|| self.impl_trait_ref(def_id))
+    }
+
+    /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.
+    pub fn impl_trait_id(self, def_id: impl IntoQueryParam<DefId>) -> DefId {
+        self.impl_trait_ref(def_id).skip_binder().def_id
+    }
+
+    /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.
+    /// Returns `None` if it is an inherent impl.
+    pub fn impl_opt_trait_id(self, def_id: impl IntoQueryParam<DefId>) -> Option<DefId> {
+        let def_id = def_id.into_query_param();
+        self.impl_is_of_trait(def_id).then(|| self.impl_trait_id(def_id))
+    }
+
     pub fn is_exportable(self, def_id: DefId) -> bool {
         self.exportable_items(def_id.krate).contains(&def_id)
     }
@@ -2062,7 +2098,7 @@ pub fn is_conditionally_const(self, def_id: impl Into<DefId>) -> bool {
         let def_id: DefId = def_id.into();
         match self.def_kind(def_id) {
             DefKind::Impl { of_trait: true } => {
-                let header = self.impl_trait_header(def_id).unwrap();
+                let header = self.impl_trait_header(def_id);
                 header.constness == hir::Constness::Const
                     && self.is_const_trait(header.trait_ref.skip_binder().def_id)
             }
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index d636e8e..0fd68e7 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -45,7 +45,7 @@ fn print_impl_path(
     ) -> Result<(), PrintError> {
         let tcx = self.tcx();
         let self_ty = tcx.type_of(impl_def_id);
-        let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+        let impl_trait_ref = tcx.impl_opt_trait_ref(impl_def_id);
         let (self_ty, impl_trait_ref) = if tcx.generics_of(impl_def_id).count() <= args.len() {
             (
                 self_ty.instantiate(tcx, args),
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index a3fdd4e..ad8b1fd 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -920,6 +920,12 @@ pub fn new_box(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
     }
 
     #[inline]
+    pub fn new_option(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+        let def_id = tcx.require_lang_item(LangItem::Option, DUMMY_SP);
+        Ty::new_generic_adt(tcx, def_id, ty)
+    }
+
+    #[inline]
     pub fn new_maybe_uninit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
         let def_id = tcx.require_lang_item(LangItem::MaybeUninit, DUMMY_SP);
         Ty::new_generic_adt(tcx, def_id, ty)
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 4e38d96..691cb43 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -271,9 +271,7 @@ pub(super) fn traits_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] {
 pub(super) fn trait_impls_in_crate_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] {
     let mut trait_impls = Vec::new();
     for id in tcx.hir_free_items() {
-        if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. })
-            && tcx.impl_trait_ref(id.owner_id).is_some()
-        {
+        if tcx.def_kind(id.owner_id) == (DefKind::Impl { of_trait: true }) {
             trait_impls.push(id.owner_id.to_def_id())
         }
     }
diff --git a/compiler/rustc_mir_transform/src/check_call_recursion.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs
index a9acb1d..cac6308 100644
--- a/compiler/rustc_mir_transform/src/check_call_recursion.rs
+++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs
@@ -44,7 +44,7 @@ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         // First check if `body` is an `fn drop()` of `Drop`
         if let DefKind::AssocFn = tcx.def_kind(def_id)
         && let Some(impl_id) = tcx.trait_impl_of_assoc(def_id.to_def_id())
-        && let trait_ref = tcx.impl_trait_ref(impl_id).unwrap()
+        && let trait_ref = tcx.impl_trait_ref(impl_id)
         && tcx.is_lang_item(trait_ref.instantiate_identity().def_id, LangItem::Drop)
         // avoid erroneous `Drop` impls from causing ICEs below
         && let sig = tcx.fn_sig(def_id).instantiate_identity()
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 0d97571..bdf53f4 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -1926,13 +1926,8 @@ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Loca
                 self.assign(local, opaque);
             }
         }
-        // Function calls and ASM may invalidate (nested) derefs. We must handle them carefully.
-        // Currently, only preserving derefs for trivial terminators like SwitchInt and Goto.
-        let safe_to_preserve_derefs = matches!(
-            terminator.kind,
-            TerminatorKind::SwitchInt { .. } | TerminatorKind::Goto { .. }
-        );
-        if !safe_to_preserve_derefs {
+        // Terminators that can write to memory may invalidate (nested) derefs.
+        if terminator.kind.can_write_to_memory() {
             self.invalidate_derefs();
         }
         self.super_terminator(terminator, location);
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 38c7d83..dc60888 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -245,7 +245,7 @@ fn on_inline_success(
     fn on_inline_failure(&self, callsite: &CallSite<'tcx>, reason: &'static str) {
         let tcx = self.tcx();
         let InlineAttr::Force { attr_span, reason: justification } =
-            tcx.codegen_fn_attrs(callsite.callee.def_id()).inline
+            tcx.codegen_instance_attrs(callsite.callee.def).inline
         else {
             bug!("called on item without required inlining");
         };
@@ -603,7 +603,8 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>(
     let tcx = inliner.tcx();
     check_mir_is_available(inliner, caller_body, callsite.callee)?;
 
-    let callee_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id());
+    let callee_attrs = tcx.codegen_instance_attrs(callsite.callee.def);
+    let callee_attrs = callee_attrs.as_ref();
     check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?;
     check_codegen_attributes(inliner, callsite, callee_attrs)?;
     inliner.check_codegen_attributes_extra(callee_attrs)?;
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 3ffd263..4625b20 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -189,6 +189,7 @@ pub mod simplify :
             Final
         };
     mod simplify_branches : SimplifyConstCondition {
+        AfterInstSimplify,
         AfterConstProp,
         Final
     };
@@ -708,6 +709,15 @@ fn o1<T>(x: T) -> WithMinOptLevel<T> {
             // optimizations. This invalidates CFG caches, so avoid putting between
             // `ReferencePropagation` and `GVN` which both use the dominator tree.
             &instsimplify::InstSimplify::AfterSimplifyCfg,
+            // After `InstSimplify-after-simplifycfg` with `-Zub_checks=false`, simplify
+            // ```
+            // _13 = const false;
+            // assume(copy _13);
+            // Call(precondition_check);
+            // ```
+            // to unreachable to eliminate the call to help later passes.
+            // This invalidates CFG caches also.
+            &o1(simplify_branches::SimplifyConstCondition::AfterInstSimplify),
             &ref_prop::ReferencePropagation,
             &sroa::ScalarReplacementOfAggregates,
             &simplify::SimplifyLocals::BeforeConstProp,
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 8dadce0..fc8092f 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -34,17 +34,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                         ));
                         terminator.kind = TerminatorKind::Goto { target };
                     }
-                    sym::contract_checks => {
-                        let target = target.unwrap();
-                        block.statements.push(Statement::new(
-                            terminator.source_info,
-                            StatementKind::Assign(Box::new((
-                                *destination,
-                                Rvalue::NullaryOp(NullOp::ContractChecks, tcx.types.bool),
-                            ))),
-                        ));
-                        terminator.kind = TerminatorKind::Goto { target };
-                    }
                     sym::forget => {
                         let target = target.unwrap();
                         block.statements.push(Statement::new(
diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
index ed94a05..ba2286f 100644
--- a/compiler/rustc_mir_transform/src/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -5,6 +5,7 @@
 use crate::patch::MirPatch;
 
 pub(super) enum SimplifyConstCondition {
+    AfterInstSimplify,
     AfterConstProp,
     Final,
 }
@@ -13,6 +14,9 @@ pub(super) enum SimplifyConstCondition {
 impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
     fn name(&self) -> &'static str {
         match self {
+            SimplifyConstCondition::AfterInstSimplify => {
+                "SimplifyConstCondition-after-inst-simplify"
+            }
             SimplifyConstCondition::AfterConstProp => "SimplifyConstCondition-after-const-prop",
             SimplifyConstCondition::Final => "SimplifyConstCondition-final",
         }
@@ -23,12 +27,33 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let typing_env = body.typing_env(tcx);
         let mut patch = MirPatch::new(body);
 
+        fn try_get_const<'tcx, 'a>(
+            operand: &'a Operand<'tcx>,
+            has_place_const: Option<(Place<'tcx>, &'a ConstOperand<'tcx>)>,
+        ) -> Option<&'a ConstOperand<'tcx>> {
+            match operand {
+                Operand::Constant(const_operand) => Some(const_operand),
+                // `has_place_const` must be the LHS of the previous statement.
+                // Soundness: There is nothing can modify the place, as there are no statements between the two statements.
+                Operand::Copy(place) | Operand::Move(place)
+                    if let Some((place_const, const_operand)) = has_place_const
+                        && place_const == *place =>
+                {
+                    Some(const_operand)
+                }
+                Operand::Copy(_) | Operand::Move(_) => None,
+            }
+        }
+
         'blocks: for (bb, block) in body.basic_blocks.iter_enumerated() {
+            let mut pre_place_const: Option<(Place<'tcx>, &ConstOperand<'tcx>)> = None;
+
             for (statement_index, stmt) in block.statements.iter().enumerate() {
+                let has_place_const = pre_place_const.take();
                 // Simplify `assume` of a known value: either a NOP or unreachable.
                 if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind
                     && let NonDivergingIntrinsic::Assume(discr) = intrinsic
-                    && let Operand::Constant(c) = discr
+                    && let Some(c) = try_get_const(discr, has_place_const)
                     && let Some(constant) = c.const_.try_eval_bool(tcx, typing_env)
                 {
                     if constant {
@@ -37,28 +62,29 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                         patch.patch_terminator(bb, TerminatorKind::Unreachable);
                         continue 'blocks;
                     }
+                } else if let StatementKind::Assign(box (lhs, ref rvalue)) = stmt.kind
+                    && let Rvalue::Use(Operand::Constant(c)) = rvalue
+                {
+                    pre_place_const = Some((lhs, c));
                 }
             }
 
             let terminator = block.terminator();
             let terminator = match terminator.kind {
-                TerminatorKind::SwitchInt {
-                    discr: Operand::Constant(ref c), ref targets, ..
-                } => {
-                    let constant = c.const_.try_eval_bits(tcx, typing_env);
-                    if let Some(constant) = constant {
-                        let target = targets.target_for_value(constant);
-                        TerminatorKind::Goto { target }
-                    } else {
-                        continue;
-                    }
+                TerminatorKind::SwitchInt { ref discr, ref targets, .. }
+                    if let Some(c) = try_get_const(discr, pre_place_const.take())
+                        && let Some(constant) = c.const_.try_eval_bits(tcx, typing_env) =>
+                {
+                    let target = targets.target_for_value(constant);
+                    TerminatorKind::Goto { target }
                 }
-                TerminatorKind::Assert {
-                    target, cond: Operand::Constant(ref c), expected, ..
-                } => match c.const_.try_eval_bool(tcx, typing_env) {
-                    Some(v) if v == expected => TerminatorKind::Goto { target },
-                    _ => continue,
-                },
+                TerminatorKind::Assert { target, ref cond, expected, .. }
+                    if let Some(c) = try_get_const(&cond, pre_place_const.take())
+                        && let Some(constant) = c.const_.try_eval_bool(tcx, typing_env)
+                        && constant == expected =>
+                {
+                    TerminatorKind::Goto { target }
+                }
                 _ => continue,
             };
             patch.patch_terminator(bb, terminator);
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 2169ed3..93f647c 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1568,7 +1568,7 @@ fn process_item(&mut self, id: hir::ItemId) {
                     }
                 }
             }
-            DefKind::Impl { .. } => {
+            DefKind::Impl { of_trait: true } => {
                 if self.strategy == MonoItemCollectionStrategy::Eager {
                     create_mono_items_for_default_impls(self.tcx, id, self.output);
                 }
@@ -1715,9 +1715,7 @@ fn create_mono_items_for_default_impls<'tcx>(
     item: hir::ItemId,
     output: &mut MonoItems<'tcx>,
 ) {
-    let Some(impl_) = tcx.impl_trait_header(item.owner_id) else {
-        return;
-    };
+    let impl_ = tcx.impl_trait_header(item.owner_id);
 
     if matches!(impl_.polarity, ty::ImplPolarity::Negative) {
         return;
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index d784d35..b87ab84 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -649,7 +649,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
             if let Some((impl_def_id, DefKind::Impl { of_trait })) = assoc_parent {
                 if of_trait
                     && tcx.sess.opts.incremental.is_some()
-                    && tcx.is_lang_item(tcx.trait_id_of_impl(impl_def_id).unwrap(), LangItem::Drop)
+                    && tcx.is_lang_item(tcx.impl_trait_id(impl_def_id), LangItem::Drop)
                 {
                     // Put `Drop::drop` into the same cgu as `drop_in_place`
                     // since `drop_in_place` is the only thing that can
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index b1894ab..52a35c9 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -122,7 +122,6 @@
 parse_catch_after_try = keyword `catch` cannot follow a `try` block
     .help = try using `match` on the result of the `try` block instead
 
-parse_cfg_attr_bad_delim = wrong `cfg_attr` delimiters
 parse_colon_as_semi = statements are terminated with a semicolon
     .suggestion = use a semicolon instead
 
@@ -573,10 +572,6 @@
 parse_macro_rules_visibility = can't qualify macro_rules invocation with `{$vis}`
     .suggestion = try exporting the macro
 
-parse_malformed_cfg_attr = malformed `cfg_attr` attribute input
-    .suggestion = missing condition and attribute
-    .note = for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
-
 parse_malformed_loop_label = malformed loop label
     .suggestion = use the correct loop label format
 
@@ -610,8 +605,6 @@
     ambiguous `+` in a type
     .suggestion = use parentheses to disambiguate
 
-parse_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
-
 parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}`
     .label_unmatched = mismatched closing delimiter
     .label_opening_candidate = closing delimiter possibly meant for this
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 1abeee6..6d536aa 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -3352,34 +3352,6 @@ pub(crate) struct KwBadCase<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(parse_cfg_attr_bad_delim)]
-pub(crate) struct CfgAttrBadDelim {
-    #[primary_span]
-    pub span: Span,
-    #[subdiagnostic]
-    pub sugg: MetaBadDelimSugg,
-}
-
-#[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_meta_bad_delim_suggestion, applicability = "machine-applicable")]
-pub(crate) struct MetaBadDelimSugg {
-    #[suggestion_part(code = "(")]
-    pub open: Span,
-    #[suggestion_part(code = ")")]
-    pub close: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(parse_malformed_cfg_attr)]
-#[note]
-pub(crate) struct MalformedCfgAttr {
-    #[primary_span]
-    #[suggestion(style = "verbose", code = "{sugg}")]
-    pub span: Span,
-    pub sugg: &'static str,
-}
-
-#[derive(Diagnostic)]
 #[diag(parse_unknown_builtin_construct)]
 pub(crate) struct UnknownBuiltinConstruct {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index c26c7b9..edec44c 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -18,8 +18,8 @@
 use std::sync::Arc;
 
 use rustc_ast as ast;
-use rustc_ast::tokenstream::{DelimSpan, TokenStream};
-use rustc_ast::{AttrItem, Attribute, MetaItemInner, token};
+use rustc_ast::token;
+use rustc_ast::tokenstream::TokenStream;
 use rustc_ast_pretty::pprust;
 use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize};
 use rustc_session::parse::ParseSess;
@@ -32,7 +32,6 @@
 #[macro_use]
 pub mod parser;
 use parser::Parser;
-use rustc_ast::token::Delimiter;
 
 use crate::lexer::StripTokens;
 
@@ -230,45 +229,3 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok
         Some(krate.spans.inner_span),
     ))
 }
-
-pub fn parse_cfg_attr(
-    cfg_attr: &Attribute,
-    psess: &ParseSess,
-) -> Option<(MetaItemInner, Vec<(AttrItem, Span)>)> {
-    const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
-    const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
-        <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>";
-
-    match cfg_attr.get_normal_item().args {
-        ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
-            if !tokens.is_empty() =>
-        {
-            check_cfg_attr_bad_delim(psess, dspan, delim);
-            match parse_in(psess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
-                Ok(r) => return Some(r),
-                Err(e) => {
-                    e.with_help(format!("the valid syntax is `{CFG_ATTR_GRAMMAR_HELP}`"))
-                        .with_note(CFG_ATTR_NOTE_REF)
-                        .emit();
-                }
-            }
-        }
-        _ => {
-            psess.dcx().emit_err(errors::MalformedCfgAttr {
-                span: cfg_attr.span,
-                sugg: CFG_ATTR_GRAMMAR_HELP,
-            });
-        }
-    }
-    None
-}
-
-fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) {
-    if let Delimiter::Parenthesis = delim {
-        return;
-    }
-    psess.dcx().emit_err(errors::CfgAttrBadDelim {
-        span: span.entire(),
-        sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close },
-    });
-}
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index acd3381..5725f4c 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -377,27 +377,6 @@ pub(crate) fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'a, ast::Meta
         Ok(lit)
     }
 
-    /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited.
-    pub fn parse_cfg_attr(
-        &mut self,
-    ) -> PResult<'a, (ast::MetaItemInner, Vec<(ast::AttrItem, Span)>)> {
-        let cfg_predicate = self.parse_meta_item_inner()?;
-        self.expect(exp!(Comma))?;
-
-        // Presumably, the majority of the time there will only be one attr.
-        let mut expanded_attrs = Vec::with_capacity(1);
-        while self.token != token::Eof {
-            let lo = self.token.span;
-            let item = self.parse_attr_item(ForceCollect::Yes)?;
-            expanded_attrs.push((item, lo.to(self.prev_token.span)));
-            if !self.eat(exp!(Comma)) {
-                break;
-            }
-        }
-
-        Ok((cfg_predicate, expanded_attrs))
-    }
-
     /// Matches `COMMASEP(meta_item_inner)`.
     pub fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::MetaItemInner>> {
         // Presumably, the majority of the time there will only be one attr.
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 3c2c968..49dd21f 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -377,7 +377,7 @@ fn should_ignore_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) -> bool {
         if let hir::ImplItemImplKind::Trait { .. } = impl_item.impl_kind
             && let impl_of = self.tcx.parent(impl_item.owner_id.to_def_id())
             && self.tcx.is_automatically_derived(impl_of)
-            && let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().instantiate_identity()
+            && let trait_ref = self.tcx.impl_trait_ref(impl_of).instantiate_identity()
             && self.tcx.has_attr(trait_ref.def_id, sym::rustc_trivial_field_reads)
         {
             if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind()
@@ -486,12 +486,9 @@ fn check_impl_or_impl_item_live(&mut self, local_def_id: LocalDefId) -> bool {
                 (self.tcx.local_parent(local_def_id), trait_item_id)
             }
             // impl items are live if the corresponding traits are live
-            DefKind::Impl { of_trait: true } => (
-                local_def_id,
-                self.tcx
-                    .impl_trait_ref(local_def_id)
-                    .and_then(|trait_ref| trait_ref.skip_binder().def_id.as_local()),
-            ),
+            DefKind::Impl { of_trait: true } => {
+                (local_def_id, self.tcx.impl_trait_id(local_def_id).as_local())
+            }
             _ => bug!(),
         };
 
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index d1a703f..74f6892 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -404,9 +404,7 @@ fn check_item<'tcx>(
     let items = tcx.associated_item_def_ids(id.owner_id);
     worklist.extend(items.iter().map(|ii_ref| ii_ref.expect_local()));
 
-    let Some(trait_def_id) = tcx.trait_id_of_impl(id.owner_id.to_def_id()) else {
-        unreachable!();
-    };
+    let trait_def_id = tcx.impl_trait_id(id.owner_id.to_def_id());
 
     if !trait_def_id.is_local() {
         return;
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index c9dbb20..85646b5 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -344,13 +344,14 @@ fn new_min<const SHALLOW: bool>(
     // associated types for which we can't determine visibility precisely.
     fn of_impl<const SHALLOW: bool>(
         def_id: LocalDefId,
+        of_trait: bool,
         tcx: TyCtxt<'_>,
         effective_visibilities: &EffectiveVisibilities,
     ) -> Self {
         let mut find = FindMin::<_, SHALLOW> { tcx, effective_visibilities, min: Self::MAX };
         find.visit(tcx.type_of(def_id).instantiate_identity());
-        if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
-            find.visit_trait(trait_ref.instantiate_identity());
+        if of_trait {
+            find.visit_trait(tcx.impl_trait_ref(def_id).instantiate_identity());
         }
         find.min
     }
@@ -699,13 +700,20 @@ fn check_def_id(&mut self, owner_id: OwnerId) {
                 // its trait if it exists (which require reaching the `DefId`s in them).
                 let item_ev = EffectiveVisibility::of_impl::<true>(
                     owner_id.def_id,
+                    of_trait,
                     self.tcx,
                     &self.effective_visibilities,
                 );
 
                 self.update_eff_vis(owner_id.def_id, item_ev, None, Level::Direct);
 
-                self.reach(owner_id.def_id, item_ev).generics().predicates().ty().trait_ref();
+                {
+                    let mut reach = self.reach(owner_id.def_id, item_ev);
+                    reach.generics().predicates().ty();
+                    if of_trait {
+                        reach.trait_ref();
+                    }
+                }
 
                 for assoc_item in self.tcx.associated_items(owner_id).in_definition_order() {
                     if assoc_item.is_impl_trait_in_trait() {
@@ -820,9 +828,7 @@ fn ty(&mut self) -> &mut Self {
     }
 
     fn trait_ref(&mut self) -> &mut Self {
-        if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
-            self.visit_trait(trait_ref.instantiate_identity());
-        }
+        self.visit_trait(self.ev.tcx.impl_trait_ref(self.item_def_id).instantiate_identity());
         self
     }
 }
@@ -1395,9 +1401,7 @@ fn ty(&mut self) -> &mut Self {
 
     fn trait_ref(&mut self) -> &mut Self {
         self.in_primary_interface = true;
-        if let Some(trait_ref) = self.tcx.impl_trait_ref(self.item_def_id) {
-            let _ = self.visit_trait(trait_ref.instantiate_identity());
-        }
+        let _ = self.visit_trait(self.tcx.impl_trait_ref(self.item_def_id).instantiate_identity());
         self
     }
 
@@ -1666,7 +1670,8 @@ fn check_item(&self, id: ItemId) {
             // A trait impl is public when both its type and its trait are public
             // Subitems of trait impls have inherited publicity.
             DefKind::Impl { of_trait } => {
-                let impl_vis = ty::Visibility::of_impl::<false>(def_id, tcx, &Default::default());
+                let impl_vis =
+                    ty::Visibility::of_impl::<false>(def_id, of_trait, tcx, &Default::default());
 
                 // We are using the non-shallow version here, unlike when building the
                 // effective visisibilities table to avoid large number of false positives.
@@ -1679,8 +1684,12 @@ fn check_item(&self, id: ItemId) {
                 // lints shouldn't be emitted even if `from` effective visibility
                 // is larger than `Priv` nominal visibility and if `Priv` can leak
                 // in some scenarios due to type inference.
-                let impl_ev =
-                    EffectiveVisibility::of_impl::<false>(def_id, tcx, self.effective_visibilities);
+                let impl_ev = EffectiveVisibility::of_impl::<false>(
+                    def_id,
+                    of_trait,
+                    tcx,
+                    self.effective_visibilities,
+                );
 
                 let mut check = self.check(def_id, impl_vis, Some(impl_ev));
 
@@ -1694,7 +1703,10 @@ fn check_item(&self, id: ItemId) {
                 // normalization they produce very ridiculous false positives.
                 // FIXME: Remove this when full normalization is implemented.
                 check.skip_assoc_tys = true;
-                check.ty().trait_ref();
+                check.ty();
+                if of_trait {
+                    check.trait_ref();
+                }
 
                 for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() {
                     if assoc_item.is_impl_trait_in_trait() {
@@ -1763,7 +1775,7 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
         }
 
         if let DefKind::Impl { of_trait: true } = tcx.def_kind(def_id) {
-            let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
+            let trait_ref = tcx.impl_trait_ref(def_id);
             let trait_ref = trait_ref.instantiate_identity();
             visitor.span =
                 tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().trait_ref.path.span;
diff --git a/compiler/rustc_public_bridge/src/context/impls.rs b/compiler/rustc_public_bridge/src/context/impls.rs
index 9b3948d..d9fa654 100644
--- a/compiler/rustc_public_bridge/src/context/impls.rs
+++ b/compiler/rustc_public_bridge/src/context/impls.rs
@@ -189,7 +189,7 @@ pub fn trait_impls(&self, crate_num: CrateNum) -> Vec<DefId> {
     }
 
     pub fn trait_impl(&self, impl_def: DefId) -> EarlyBinder<'tcx, TraitRef<'tcx>> {
-        self.tcx.impl_trait_ref(impl_def).unwrap()
+        self.tcx.impl_trait_ref(impl_def)
     }
 
     pub fn generics_of(&self, def_id: DefId) -> &'tcx ty::Generics {
diff --git a/compiler/rustc_query_system/src/dep_graph/edges.rs b/compiler/rustc_query_system/src/dep_graph/edges.rs
index 9a3763b..092e9c1 100644
--- a/compiler/rustc_query_system/src/dep_graph/edges.rs
+++ b/compiler/rustc_query_system/src/dep_graph/edges.rs
@@ -8,7 +8,7 @@
 #[derive(Default, Debug)]
 pub(crate) struct EdgesVec {
     max: u32,
-    edges: SmallVec<[DepNodeIndex; EdgesVec::INLINE_CAPACITY]>,
+    edges: SmallVec<[DepNodeIndex; 8]>,
 }
 
 impl Hash for EdgesVec {
@@ -19,8 +19,6 @@ fn hash<H: Hasher>(&self, hasher: &mut H) {
 }
 
 impl EdgesVec {
-    pub(crate) const INLINE_CAPACITY: usize = 8;
-
     #[inline]
     pub(crate) fn new() -> Self {
         Self::default()
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 58bacb1..f6f0547 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -339,13 +339,11 @@ pub(crate) fn with_task<Ctxt: HasDepContext<Deps = D>, A: Debug, R>(
         let (result, edges) = if cx.dep_context().is_eval_always(key.kind) {
             (with_deps(TaskDepsRef::EvalAlways), EdgesVec::new())
         } else {
-            let task_deps = Lock::new(TaskDeps {
+            let task_deps = Lock::new(TaskDeps::new(
                 #[cfg(debug_assertions)]
-                node: Some(key),
-                reads: EdgesVec::new(),
-                read_set: Default::default(),
-                phantom_data: PhantomData,
-            });
+                Some(key),
+                0,
+            ));
             (with_deps(TaskDepsRef::Allow(&task_deps)), task_deps.into_inner().reads)
         };
 
@@ -377,12 +375,18 @@ pub(crate) fn with_anon_task_inner<Tcx: DepContext<Deps = D>, OP, R>(
     {
         debug_assert!(!cx.is_eval_always(dep_kind));
 
-        let task_deps = Lock::new(TaskDeps::default());
+        // Large numbers of reads are common enough here that pre-sizing `read_set`
+        // to 128 actually helps perf on some benchmarks.
+        let task_deps = Lock::new(TaskDeps::new(
+            #[cfg(debug_assertions)]
+            None,
+            128,
+        ));
         let result = D::with_deps(TaskDepsRef::Allow(&task_deps), op);
         let task_deps = task_deps.into_inner();
-        let task_deps = task_deps.reads;
+        let reads = task_deps.reads;
 
-        let dep_node_index = match task_deps.len() {
+        let dep_node_index = match reads.len() {
             0 => {
                 // Because the dep-node id of anon nodes is computed from the sets of its
                 // dependencies we already know what the ID of this dependency-less node is
@@ -393,7 +397,7 @@ pub(crate) fn with_anon_task_inner<Tcx: DepContext<Deps = D>, OP, R>(
             }
             1 => {
                 // When there is only one dependency, don't bother creating a node.
-                task_deps[0]
+                reads[0]
             }
             _ => {
                 // The dep node indices are hashed here instead of hashing the dep nodes of the
@@ -402,7 +406,7 @@ pub(crate) fn with_anon_task_inner<Tcx: DepContext<Deps = D>, OP, R>(
                 // combining it with the per session random number `anon_id_seed`. This hash only need
                 // to map the dependencies to a single value on a per session basis.
                 let mut hasher = StableHasher::new();
-                task_deps.hash(&mut hasher);
+                reads.hash(&mut hasher);
 
                 let target_dep_node = DepNode {
                     kind: dep_kind,
@@ -420,7 +424,7 @@ pub(crate) fn with_anon_task_inner<Tcx: DepContext<Deps = D>, OP, R>(
                 // memory impact of this `anon_node_to_index` map remains tolerable, and helps
                 // us avoid useless growth of the graph with almost-equivalent nodes.
                 self.current.anon_node_to_index.get_or_insert_with(target_dep_node, || {
-                    self.current.alloc_new_node(target_dep_node, task_deps, Fingerprint::ZERO)
+                    self.current.alloc_new_node(target_dep_node, reads, Fingerprint::ZERO)
                 })
             }
         };
@@ -471,18 +475,17 @@ pub fn read_index(&self, dep_node_index: DepNodeIndex) {
                     data.current.total_read_count.fetch_add(1, Ordering::Relaxed);
                 }
 
-                // As long as we only have a low number of reads we can avoid doing a hash
-                // insert and potentially allocating/reallocating the hashmap
-                let new_read = if task_deps.reads.len() < EdgesVec::INLINE_CAPACITY {
-                    task_deps.reads.iter().all(|other| *other != dep_node_index)
+                // Has `dep_node_index` been seen before? Use either a linear scan or a hashset
+                // lookup to determine this. See `TaskDeps::read_set` for details.
+                let new_read = if task_deps.reads.len() <= TaskDeps::LINEAR_SCAN_MAX {
+                    !task_deps.reads.contains(&dep_node_index)
                 } else {
                     task_deps.read_set.insert(dep_node_index)
                 };
                 if new_read {
                     task_deps.reads.push(dep_node_index);
-                    if task_deps.reads.len() == EdgesVec::INLINE_CAPACITY {
-                        // Fill `read_set` with what we have so far so we can use the hashset
-                        // next time
+                    if task_deps.reads.len() == TaskDeps::LINEAR_SCAN_MAX + 1 {
+                        // Fill `read_set` with what we have so far. Future lookups will use it.
                         task_deps.read_set.extend(task_deps.reads.iter().copied());
                     }
 
@@ -1292,18 +1295,30 @@ pub enum TaskDepsRef<'a> {
 pub struct TaskDeps {
     #[cfg(debug_assertions)]
     node: Option<DepNode>,
+
+    /// A vector of `DepNodeIndex`, basically.
     reads: EdgesVec,
+
+    /// When adding new edges to `reads` in `DepGraph::read_index` we need to determine if the edge
+    /// has been seen before. If the number of elements in `reads` is small, we just do a linear
+    /// scan. If the number is higher, a hashset has better perf. This field is that hashset. It's
+    /// only used if the number of elements in `reads` exceeds `LINEAR_SCAN_MAX`.
     read_set: FxHashSet<DepNodeIndex>,
+
     phantom_data: PhantomData<DepNode>,
 }
 
-impl Default for TaskDeps {
-    fn default() -> Self {
-        Self {
+impl TaskDeps {
+    /// See `TaskDeps::read_set` above.
+    const LINEAR_SCAN_MAX: usize = 16;
+
+    #[inline]
+    fn new(#[cfg(debug_assertions)] node: Option<DepNode>, read_set_capacity: usize) -> Self {
+        TaskDeps {
             #[cfg(debug_assertions)]
-            node: None,
+            node,
             reads: EdgesVec::new(),
-            read_set: FxHashSet::with_capacity_and_hasher(128, Default::default()),
+            read_set: FxHashSet::with_capacity_and_hasher(read_set_capacity, Default::default()),
             phantom_data: PhantomData,
         }
     }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index a0cb6c4..88fbc6d 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -77,6 +77,7 @@ fn define_extern(
         parent: Module<'ra>,
         ident: Ident,
         ns: Namespace,
+        child_index: usize,
         res: Res,
         vis: Visibility<DefId>,
         span: Span,
@@ -86,10 +87,8 @@ fn define_extern(
         // Even if underscore names cannot be looked up, we still need to add them to modules,
         // because they can be fetched by glob imports from those modules, and bring traits
         // into scope both directly and through glob imports.
-        let key = BindingKey::new_disambiguated(ident, ns, || {
-            parent.underscore_disambiguator.update_unchecked(|d| d + 1);
-            parent.underscore_disambiguator.get()
-        });
+        let key =
+            BindingKey::new_disambiguated(ident, ns, || (child_index + 1).try_into().unwrap()); // 0 indicates no underscore
         if self
             .resolution_or_default(parent, key)
             .borrow_mut_unchecked()
@@ -233,9 +232,9 @@ pub(crate) fn build_reduced_graph(
     }
 
     pub(crate) fn build_reduced_graph_external(&self, module: Module<'ra>) {
-        for child in self.tcx.module_children(module.def_id()) {
+        for (i, child) in self.tcx.module_children(module.def_id()).into_iter().enumerate() {
             let parent_scope = ParentScope::module(module, self.arenas);
-            self.build_reduced_graph_for_external_crate_res(child, parent_scope)
+            self.build_reduced_graph_for_external_crate_res(child, parent_scope, i)
         }
     }
 
@@ -244,6 +243,7 @@ fn build_reduced_graph_for_external_crate_res(
         &self,
         child: &ModChild,
         parent_scope: ParentScope<'ra>,
+        child_index: usize,
     ) {
         let parent = parent_scope.module;
         let ModChild { ident, res, vis, ref reexport_chain } = *child;
@@ -272,7 +272,9 @@ fn build_reduced_graph_for_external_crate_res(
                 _,
             )
             | Res::PrimTy(..)
-            | Res::ToolMod => self.define_extern(parent, ident, TypeNS, res, vis, span, expansion),
+            | Res::ToolMod => {
+                self.define_extern(parent, ident, TypeNS, child_index, res, vis, span, expansion)
+            }
             Res::Def(
                 DefKind::Fn
                 | DefKind::AssocFn
@@ -281,9 +283,9 @@ fn build_reduced_graph_for_external_crate_res(
                 | DefKind::AssocConst
                 | DefKind::Ctor(..),
                 _,
-            ) => self.define_extern(parent, ident, ValueNS, res, vis, span, expansion),
+            ) => self.define_extern(parent, ident, ValueNS, child_index, res, vis, span, expansion),
             Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => {
-                self.define_extern(parent, ident, MacroNS, res, vis, span, expansion)
+                self.define_extern(parent, ident, MacroNS, child_index, res, vis, span, expansion)
             }
             Res::Def(
                 DefKind::TyParam
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index 82a2a64..021b206 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -10,8 +10,9 @@
 use rustc_hir::LangItem;
 use rustc_middle::bug;
 use rustc_middle::ty::{
-    self, ExistentialPredicateStableCmpExt as _, Instance, InstanceKind, IntTy, List, TraitRef, Ty,
-    TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UintTy,
+    self, AssocContainer, ExistentialPredicateStableCmpExt as _, Instance, InstanceKind, IntTy,
+    List, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    UintTy,
 };
 use rustc_span::def_id::DefId;
 use rustc_span::{DUMMY_SP, sym};
@@ -466,20 +467,20 @@ fn implemented_method<'tcx>(
     let method_id;
     let trait_id;
     let trait_method;
-    let ancestor = if let Some(impl_id) = tcx.impl_of_assoc(instance.def_id()) {
-        // Implementation in an `impl` block
-        trait_ref = tcx.impl_trait_ref(impl_id)?;
-        method_id = tcx.trait_item_of(instance.def_id())?;
+    let assoc = tcx.opt_associated_item(instance.def_id())?;
+    let ancestor = if let AssocContainer::TraitImpl(Ok(trait_method_id)) = assoc.container {
+        let impl_id = tcx.parent(instance.def_id());
+        trait_ref = tcx.impl_trait_ref(impl_id);
+        method_id = trait_method_id;
         trait_method = tcx.associated_item(method_id);
         trait_id = trait_ref.skip_binder().def_id;
         impl_id
-    } else if let InstanceKind::Item(def_id) = instance.def
-        && let Some(trait_method_bound) = tcx.opt_associated_item(def_id)
+    } else if let AssocContainer::Trait = assoc.container
+        && let InstanceKind::Item(def_id) = instance.def
     {
-        // Provided method in a `trait` block
-        trait_method = trait_method_bound;
-        method_id = instance.def_id();
-        trait_id = tcx.trait_of_assoc(method_id)?;
+        trait_method = assoc;
+        method_id = def_id;
+        trait_id = tcx.parent(method_id);
         trait_ref = ty::EarlyBinder::bind(TraitRef::from_assoc(tcx, trait_id, instance.args));
         trait_id
     } else {
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 95a7ec6..ee2621a 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -403,7 +403,7 @@ fn print_impl_path(
         args: &'tcx [GenericArg<'tcx>],
     ) -> Result<(), PrintError> {
         let self_ty = self.tcx.type_of(impl_def_id);
-        let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
+        let impl_trait_ref = self.tcx.impl_opt_trait_ref(impl_def_id);
         let generics = self.tcx.generics_of(impl_def_id);
         // We have two cases to worry about here:
         // 1. We're printing a nested item inside of an impl item, like an inner
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index aeac40a..d5bc831 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -311,7 +311,7 @@ fn print_impl_path(
         let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
 
         let self_ty = self.tcx.type_of(impl_def_id);
-        let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
+        let impl_trait_ref = self.tcx.impl_opt_trait_ref(impl_def_id);
         let generics = self.tcx.generics_of(impl_def_id);
         // We have two cases to worry about here:
         // 1. We're printing a nested item inside of an impl item, like an inner
diff --git a/compiler/rustc_target/src/spec/base/nto_qnx.rs b/compiler/rustc_target/src/spec/base/nto_qnx.rs
index 3f35b8b..6498742 100644
--- a/compiler/rustc_target/src/spec/base/nto_qnx.rs
+++ b/compiler/rustc_target/src/spec/base/nto_qnx.rs
@@ -12,6 +12,9 @@ pub(crate) fn opts() -> TargetOptions {
         has_thread_local: false,
         linker: Some("qcc".into()),
         os: "nto".into(),
+        // We want backtraces to work by default and they rely on unwind tables
+        // (regardless of `-C panic` strategy).
+        default_uwtable: true,
         position_independent_executables: true,
         static_position_independent_executables: true,
         relro_level: RelroLevel::Full,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 9a8ccea..0765434 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -574,7 +574,7 @@ pub fn suggest_copy_trait_method_bounds(
         let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(impl_item_def_id.to_def_id()) else {
             return;
         };
-        let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
+        let trait_ref = self.tcx.impl_trait_ref(impl_def_id);
         let trait_args = trait_ref
             .instantiate_identity()
             // Replace the explicit self type with `Self` for better suggestion rendering
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index edb002c..eb72f71 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -47,8 +47,7 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>(
             );
 
             let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
-            let impl_trait_ref =
-                tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args);
+            let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).instantiate(tcx, impl_args);
             let impl_trait_ref =
                 ocx.normalize(&ObligationCause::dummy(), param_env, impl_trait_ref);
 
@@ -58,7 +57,7 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>(
                 return false;
             }
 
-            let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
+            let impl_trait_header = tcx.impl_trait_header(impl_def_id);
             let impl_polarity = impl_trait_header.polarity;
 
             match (impl_polarity, predicate_polarity) {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
index f54ebd7..2c18ffc 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
@@ -77,7 +77,7 @@ pub fn call_kind<'tcx>(
         let container_id = assoc.container_id(tcx);
         match assoc.container {
             AssocContainer::InherentImpl => None,
-            AssocContainer::TraitImpl(_) => tcx.trait_id_of_impl(container_id),
+            AssocContainer::TraitImpl(_) => Some(tcx.impl_trait_id(container_id)),
             AssocContainer::Trait => Some(container_id),
         }
     });
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 4305d41..373819d 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1867,7 +1867,7 @@ pub(super) fn find_similar_impl_candidates(
             .tcx
             .all_impls(trait_pred.def_id())
             .filter_map(|def_id| {
-                let imp = self.tcx.impl_trait_header(def_id).unwrap();
+                let imp = self.tcx.impl_trait_header(def_id);
                 if imp.polarity != ty::ImplPolarity::Positive
                     || !self.tcx.is_user_visible_dep(def_id.krate)
                 {
@@ -1906,7 +1906,7 @@ pub(super) fn report_similar_impl_candidates(
                 // ignore `do_not_recommend` items
                 .filter(|def_id| !self.tcx.do_not_recommend_impl(*def_id))
                 // Ignore automatically derived impls and `!Trait` impls.
-                .filter_map(|def_id| self.tcx.impl_trait_header(def_id))
+                .map(|def_id| self.tcx.impl_trait_header(def_id))
                 .filter_map(|header| {
                     (header.polarity != ty::ImplPolarity::Negative
                         || self.tcx.is_automatically_derived(def_id))
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index 9052031..ded5969 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -354,7 +354,7 @@ fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuara
 pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
     use std::fmt::Write;
 
-    let trait_ref = tcx.impl_trait_ref(impl_def_id)?.instantiate_identity();
+    let trait_ref = tcx.impl_opt_trait_ref(impl_def_id)?.instantiate_identity();
     let mut w = "impl".to_owned();
 
     #[derive(Debug, Default)]
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index b7d470d..a5cb374 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -44,8 +44,7 @@ fn impl_similar_to(
 
             self.tcx.for_each_relevant_impl(trait_pred.def_id(), trait_self_ty, |def_id| {
                 let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id);
-                let impl_trait_ref =
-                    tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args);
+                let impl_trait_ref = tcx.impl_trait_ref(def_id).instantiate(tcx, impl_args);
 
                 let impl_self_ty = impl_trait_ref.self_ty();
 
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 22ef214..e488fb6 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -137,8 +137,8 @@ pub fn overlapping_trait_impls(
     // Before doing expensive operations like entering an inference context, do
     // a quick check via fast_reject to tell if the impl headers could possibly
     // unify.
-    let impl1_args = tcx.impl_trait_ref(impl1_def_id).unwrap().skip_binder().args;
-    let impl2_args = tcx.impl_trait_ref(impl2_def_id).unwrap().skip_binder().args;
+    let impl1_args = tcx.impl_trait_ref(impl1_def_id).skip_binder().args;
+    let impl2_args = tcx.impl_trait_ref(impl2_def_id).skip_binder().args;
     let may_overlap =
         DeepRejectCtxt::relate_infer_infer(tcx).args_may_unify(impl1_args, impl2_args);
 
@@ -209,8 +209,7 @@ fn fresh_impl_header<'tcx>(
         impl_def_id,
         impl_args,
         self_ty: tcx.type_of(impl_def_id).instantiate(tcx, impl_args),
-        trait_ref: is_of_trait
-            .then(|| tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args)),
+        trait_ref: is_of_trait.then(|| tcx.impl_trait_ref(impl_def_id).instantiate(tcx, impl_args)),
         predicates: tcx
             .predicates_of(impl_def_id)
             .instantiate(tcx, impl_args)
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
index d694a09..7f2a999 100644
--- a/compiler/rustc_trait_selection/src/traits/effects.rs
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -458,9 +458,7 @@ fn evaluate_host_effect_from_selection_candidate<'tcx>(
             Err(_) => Err(EvaluationFailure::NoSolution),
             Ok(Some(source)) => match source {
                 ImplSource::UserDefined(impl_) => {
-                    if tcx.impl_trait_header(impl_.impl_def_id).unwrap().constness
-                        != hir::Constness::Const
-                    {
+                    if tcx.impl_trait_header(impl_.impl_def_id).constness != hir::Constness::Const {
                         return Err(EvaluationFailure::NoSolution);
                     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 3d27756..0f3b38e 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -835,10 +835,7 @@ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
     let param_env = ty::ParamEnv::empty();
     let fresh_args = infcx.fresh_args_for_item(tcx.def_span(impl_def_id), impl_def_id);
 
-    let impl_trait_ref = tcx
-        .impl_trait_ref(impl_def_id)
-        .expect("expected impl to correspond to trait")
-        .instantiate(tcx, fresh_args);
+    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).instantiate(tcx, fresh_args);
 
     let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
     let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| {
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index fab5102..fea4b7c 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1979,7 +1979,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     let ImplSourceUserDefinedData { impl_def_id, args, mut nested } = impl_impl_source;
 
     let assoc_item_id = obligation.predicate.def_id;
-    let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
+    let trait_def_id = tcx.impl_trait_id(impl_def_id);
 
     let param_env = obligation.param_env;
     let assoc_term = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) {
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index cb980d5..cecb43e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -604,7 +604,7 @@ fn assemble_candidates_from_impls(
                 // Before we create the generic parameters and everything, first
                 // consider a "quick reject". This avoids creating more types
                 // and so forth that we need to.
-                let impl_trait_header = self.tcx().impl_trait_header(impl_def_id).unwrap();
+                let impl_trait_header = self.tcx().impl_trait_header(impl_def_id);
                 if !drcx
                     .args_may_unify(obligation_args, impl_trait_header.trait_ref.skip_binder().args)
                 {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 9be5d06..614c09d 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2487,7 +2487,7 @@ fn rematch_impl(
         impl_def_id: DefId,
         obligation: &PolyTraitObligation<'tcx>,
     ) -> Normalized<'tcx, GenericArgsRef<'tcx>> {
-        let impl_trait_header = self.tcx().impl_trait_header(impl_def_id).unwrap();
+        let impl_trait_header = self.tcx().impl_trait_header(impl_def_id);
         match self.match_impl(impl_def_id, impl_trait_header, obligation) {
             Ok(args) => args,
             Err(()) => {
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index ab01d07..ca6fd78 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -117,7 +117,7 @@ pub fn translate_args_with_cause<'tcx>(
         param_env, source_impl, source_args, target_node
     );
     let source_trait_ref =
-        infcx.tcx.impl_trait_ref(source_impl).unwrap().instantiate(infcx.tcx, source_args);
+        infcx.tcx.impl_trait_ref(source_impl).instantiate(infcx.tcx, source_args);
 
     // translate the Self and Param parts of the generic parameters, since those
     // vary across impls
@@ -176,11 +176,7 @@ fn fulfill_implication<'tcx>(
     let target_trait_ref = ocx.normalize(
         cause,
         param_env,
-        infcx
-            .tcx
-            .impl_trait_ref(target_impl)
-            .expect("expected source impl to be a trait impl")
-            .instantiate(infcx.tcx, target_args),
+        infcx.tcx.impl_trait_ref(target_impl).instantiate(infcx.tcx, target_args),
     );
 
     // do the impls unify? If not, no specialization.
@@ -256,7 +252,7 @@ pub(super) fn specializes(
         }
     }
 
-    let specializing_impl_trait_header = tcx.impl_trait_header(specializing_impl_def_id).unwrap();
+    let specializing_impl_trait_header = tcx.impl_trait_header(specializing_impl_def_id);
 
     // We determine whether there's a subset relationship by:
     //
@@ -307,11 +303,7 @@ pub(super) fn specializes(
     let parent_impl_trait_ref = ocx.normalize(
         cause,
         param_env,
-        infcx
-            .tcx
-            .impl_trait_ref(parent_impl_def_id)
-            .expect("expected source impl to be a trait impl")
-            .instantiate(infcx.tcx, parent_args),
+        infcx.tcx.impl_trait_ref(parent_impl_def_id).instantiate(infcx.tcx, parent_args),
     );
 
     // do the impls unify? If not, no specialization.
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 12ba12b..02db81d 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -38,7 +38,7 @@ enum Inserted<'tcx> {
 impl<'tcx> Children {
     /// Insert an impl into this set of children without comparing to any existing impls.
     fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
-        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).skip_binder();
         if let Some(st) =
             fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::InstantiateWithInfer)
         {
@@ -54,7 +54,7 @@ fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
     /// an impl with a parent. The impl must be present in the list of
     /// children already.
     fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
-        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).skip_binder();
         let vec: &mut Vec<DefId>;
         if let Some(st) =
             fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::InstantiateWithInfer)
@@ -164,7 +164,7 @@ fn insert(
             if le && !ge {
                 debug!(
                     "descending as child of TraitRef {:?}",
-                    tcx.impl_trait_ref(possible_sibling).unwrap().instantiate_identity()
+                    tcx.impl_trait_ref(possible_sibling).instantiate_identity()
                 );
 
                 // The impl specializes `possible_sibling`.
@@ -172,7 +172,7 @@ fn insert(
             } else if ge && !le {
                 debug!(
                     "placing as parent of TraitRef {:?}",
-                    tcx.impl_trait_ref(possible_sibling).unwrap().instantiate_identity()
+                    tcx.impl_trait_ref(possible_sibling).instantiate_identity()
                 );
 
                 replace_children.push(possible_sibling);
@@ -242,7 +242,7 @@ fn insert(
         assert!(impl_def_id.is_local());
 
         // FIXME: use `EarlyBinder` in `self.children`
-        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
+        let trait_ref = tcx.impl_trait_ref(impl_def_id).skip_binder();
         let trait_def_id = trait_ref.def_id;
 
         debug!(
@@ -354,7 +354,7 @@ pub(crate) fn assoc_def(
     impl_def_id: DefId,
     assoc_def_id: DefId,
 ) -> Result<LeafDef, ErrorGuaranteed> {
-    let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
+    let trait_def_id = tcx.impl_trait_id(impl_def_id);
     let trait_def = tcx.trait_def(trait_def_id);
 
     // This function may be called while we are still building the
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index 543f6a3..990120d 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -42,12 +42,14 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
             ));
             tcx.arena.alloc_slice(&assumed_wf_types)
         }
-        DefKind::Impl { .. } => {
+        DefKind::Impl { of_trait } => {
             // Trait arguments and the self type for trait impls or only the self type for
             // inherent impls.
-            let tys = match tcx.impl_trait_ref(def_id) {
-                Some(trait_ref) => trait_ref.skip_binder().args.types().collect(),
-                None => vec![tcx.type_of(def_id).instantiate_identity()],
+            let tys = if of_trait {
+                let trait_ref = tcx.impl_trait_ref(def_id);
+                trait_ref.skip_binder().args.types().collect()
+            } else {
+                vec![tcx.type_of(def_id).instantiate_identity()]
             };
 
             let mut impl_spans = impl_spans(tcx, def_id);
@@ -111,7 +113,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
                     let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto(
                         tcx,
                         impl_def_id.to_def_id(),
-                        tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity().args,
+                        tcx.impl_trait_ref(impl_def_id).instantiate_identity().args,
                     );
                     tcx.arena.alloc_from_iter(
                         ty::EarlyBinder::bind(tcx.assumed_wf_types_for_rpitit(rpitit_def_id))
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index e28ebaa..23bbd9c 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -131,7 +131,7 @@ fn resolve_associated_item<'tcx>(
             assert!(!rcvr_args.has_infer());
             assert!(!trait_ref.has_infer());
 
-            let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
+            let trait_def_id = tcx.impl_trait_id(impl_data.impl_def_id);
             let trait_def = tcx.trait_def(trait_def_id);
             let leaf_def = trait_def
                 .ancestors(tcx, impl_data.impl_def_id)?
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index eb3236d..4dd45a0 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -62,24 +62,6 @@ fn visit_spanned(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>)
         self.span = old;
     }
 
-    fn parent_impl_trait_ref(&self) -> Option<ty::TraitRef<'tcx>> {
-        let parent = self.parent()?;
-        if matches!(self.tcx.def_kind(parent), DefKind::Impl { .. }) {
-            Some(self.tcx.impl_trait_ref(parent)?.instantiate_identity())
-        } else {
-            None
-        }
-    }
-
-    fn parent(&self) -> Option<LocalDefId> {
-        match self.tcx.def_kind(self.item) {
-            DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
-                Some(self.tcx.local_parent(self.item))
-            }
-            _ => None,
-        }
-    }
-
     #[instrument(level = "trace", skip(self))]
     fn collect_taits_declared_in_body(&mut self) {
         let body = self.tcx.hir_body_owned_by(self.item).value;
@@ -236,13 +218,12 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
                 // This avoids having to do normalization of `Self::AssocTy` by only
                 // supporting the case of a method defining opaque types from assoc types
                 // in the same impl block.
-                if let Some(impl_trait_ref) = self.parent_impl_trait_ref() {
+                if let Some(parent) = self.tcx.trait_impl_of_assoc(self.item.to_def_id()) {
+                    let impl_trait_ref = self.tcx.impl_trait_ref(parent).instantiate_identity();
                     // If the trait ref of the associated item and the impl differs,
                     // then we can't use the impl's identity args below, so
                     // just skip.
                     if alias_ty.trait_ref(self.tcx) == impl_trait_ref {
-                        let parent = self.parent().expect("we should have a parent here");
-
                         for &assoc in self.tcx.associated_items(parent).in_definition_order() {
                             trace!(?assoc);
                             if assoc.expect_trait_impl() != Ok(alias_ty.def_id) {
diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs
index d956608..07f379d 100644
--- a/compiler/rustc_ty_utils/src/sig_types.rs
+++ b/compiler/rustc_ty_utils/src/sig_types.rs
@@ -88,7 +88,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
         DefKind::Impl { of_trait } => {
             if of_trait {
                 let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().trait_ref.path.span;
-                let args = &tcx.impl_trait_ref(item).unwrap().instantiate_identity().args[1..];
+                let args = &tcx.impl_trait_ref(item).instantiate_identity().args[1..];
                 try_visit!(visitor.visit(span, args));
             }
             let span = match tcx.hir_node_by_def_id(item).ty() {
diff --git a/library/Cargo.lock b/library/Cargo.lock
index b5b534c..50fb060 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -167,6 +167,16 @@
 ]
 
 [[package]]
+name = "moto-rt"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "058a2807a30527bee4c30df7ababe971cdde94372d4dbd1ff145bb403381436c"
+dependencies = [
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
 name = "object"
 version = "0.37.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -316,6 +326,7 @@
  "hermit-abi",
  "libc",
  "miniz_oxide",
+ "moto-rt",
  "object",
  "panic_abort",
  "panic_unwind",
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 5927d03..c78f2c8 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -886,7 +886,6 @@ pub fn try_pin_in(data: T, alloc: A) -> Result<Pin<Arc<T, A>>, AllocError>
     /// let five = Arc::try_new_in(5, System)?;
     /// # Ok::<(), std::alloc::AllocError>(())
     /// ```
-    #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn try_new_in(data: T, alloc: A) -> Result<Arc<T, A>, AllocError> {
diff --git a/library/alloc/src/wtf8/tests.rs b/library/alloc/src/wtf8/tests.rs
index 291f63f..a72ad08 100644
--- a/library/alloc/src/wtf8/tests.rs
+++ b/library/alloc/src/wtf8/tests.rs
@@ -580,6 +580,17 @@ fn wtf8_encode_wide_size_hint() {
 }
 
 #[test]
+fn wtf8_encode_wide_debug() {
+    let mut string = Wtf8Buf::from_str("aé ");
+    string.push(CodePoint::from_u32(0xD83D).unwrap());
+    string.push_char('💩');
+    assert_eq!(
+        format!("{:?}", string.encode_wide()),
+        r#"EncodeWide(['a', 'é', ' ', 0xD83D, 0xD83D, 0xDCA9])"#
+    );
+}
+
+#[test]
 fn wtf8_clone_into() {
     let mut string = Wtf8Buf::new();
     clone_into(Wtf8::from_str("green"), &mut string);
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index cef700b..c397e76 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -2631,23 +2631,6 @@ pub const fn ub_checks() -> bool {
     ptr
 }
 
-/// Returns whether we should perform contract-checking at runtime.
-///
-/// This is meant to be similar to the ub_checks intrinsic, in terms
-/// of not prematurely committing at compile-time to whether contract
-/// checking is turned on, so that we can specify contracts in libstd
-/// and let an end user opt into turning them on.
-#[rustc_const_unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
-#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
-#[inline(always)]
-#[rustc_intrinsic]
-pub const fn contract_checks() -> bool {
-    // FIXME: should this be `false` or `cfg!(contract_checks)`?
-
-    // cfg!(contract_checks)
-    false
-}
-
 /// Check if the pre-condition `cond` has been met.
 ///
 /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
@@ -2668,7 +2651,7 @@ pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
         if const {
                 // Do nothing
         } else {
-            if contract_checks() && !cond() {
+            if !cond() {
                 // Emit no unwind panic in case this was a safety requirement.
                 crate::panicking::panic_nounwind("failed requires check");
             }
@@ -2681,6 +2664,8 @@ pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
 /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
 /// returns false.
 ///
+/// If `cond` is `None`, then no postcondition checking is performed.
+///
 /// Note that this function is a no-op during constant evaluation.
 #[unstable(feature = "contracts_internals", issue = "128044")]
 // Similar to `contract_check_requires`, we need to use the user-facing
@@ -2689,16 +2674,24 @@ pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
 #[rustc_const_unstable(feature = "contracts", issue = "128044")]
 #[lang = "contract_check_ensures"]
 #[rustc_intrinsic]
-pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(cond: C, ret: Ret) -> Ret {
+pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(
+    cond: Option<C>,
+    ret: Ret,
+) -> Ret {
     const_eval_select!(
-        @capture[C: Fn(&Ret) -> bool + Copy, Ret] { cond: C, ret: Ret } -> Ret :
+        @capture[C: Fn(&Ret) -> bool + Copy, Ret] { cond: Option<C>, ret: Ret } -> Ret :
         if const {
             // Do nothing
             ret
         } else {
-            if contract_checks() && !cond(&ret) {
-                // Emit no unwind panic in case this was a safety requirement.
-                crate::panicking::panic_nounwind("failed ensures check");
+            match cond {
+                crate::option::Option::Some(cond) => {
+                    if !cond(&ret) {
+                        // Emit no unwind panic in case this was a safety requirement.
+                        crate::panicking::panic_nounwind("failed ensures check");
+                    }
+                },
+                crate::option::Option::None => {},
             }
             ret
         }
diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs
index 7fcd6f8..f578ae8 100644
--- a/library/core/src/iter/sources/repeat.rs
+++ b/library/core/src/iter/sources/repeat.rs
@@ -101,8 +101,9 @@ fn nth(&mut self, n: usize) -> Option<A> {
         Some(self.element.clone())
     }
 
+    #[track_caller]
     fn last(self) -> Option<A> {
-        Some(self.element)
+        panic!("iterator is infinite");
     }
 
     #[track_caller]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 430ee34..e3c4758 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -118,9 +118,14 @@
 //!
 //! # Representation
 //!
-//! Rust guarantees to optimize the following types `T` such that
-//! [`Option<T>`] has the same size, alignment, and [function call ABI] as `T`. In some
-//! of these cases, Rust further guarantees the following:
+//! Rust guarantees to optimize the following types `T` such that [`Option<T>`]
+//! has the same size, alignment, and [function call ABI] as `T`. It is
+//! therefore sound, when `T` is one of these types, to transmute a value `t` of
+//! type `T` to type `Option<T>` (producing the value `Some(t)`) and to
+//! transmute a value `Some(t)` of type `Option<T>` to type `T` (producing the
+//! value `t`).
+//!
+//! In some of these cases, Rust further guarantees the following:
 //! - `transmute::<_, Option<T>>([0u8; size_of::<T>()])` is sound and produces
 //!   `Option::<T>::None`
 //! - `transmute::<_, [u8; size_of::<T>()]>(Option::<T>::None)` is sound and produces
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index c69762a..6fee7fe 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -230,24 +230,31 @@
 //!
 //! # Representation
 //!
-//! In some cases, [`Result<T, E>`] will gain the same size, alignment, and ABI
-//! guarantees as [`Option<U>`] has. One of either the `T` or `E` type must be a
-//! type that qualifies for the `Option` [representation guarantees][opt-rep],
-//! and the *other* type must meet all of the following conditions:
-//! * Is a zero-sized type with alignment 1 (a "1-ZST").
-//! * Has no fields.
-//! * Does not have the `#[non_exhaustive]` attribute.
+//! In some cases, [`Result<T, E>`] comes with size, alignment, and ABI
+//! guarantees. Specifically, one of either the `T` or `E` type must be a type
+//! that qualifies for the `Option` [representation guarantees][opt-rep] (let's
+//! call that type `I`), and the *other* type is a zero-sized type with
+//! alignment 1 (a "1-ZST").
+//!
+//! If that is the case, then `Result<T, E>` has the same size, alignment, and
+//! [function call ABI] as `I` (and therefore, as `Option<I>`). If `I` is `T`,
+//! it is therefore sound to transmute a value `t` of type `I` to type
+//! `Result<T, E>` (producing the value `Ok(t)`) and to transmute a value
+//! `Ok(t)` of type `Result<T, E>` to type `I` (producing the value `t`). If `I`
+//! is `E`, the same applies with `Ok` replaced by `Err`.
 //!
 //! For example, `NonZeroI32` qualifies for the `Option` representation
-//! guarantees, and `()` is a zero-sized type with alignment 1, no fields, and
-//! it isn't `non_exhaustive`. This means that both `Result<NonZeroI32, ()>` and
-//! `Result<(), NonZeroI32>` have the same size, alignment, and ABI guarantees
-//! as `Option<NonZeroI32>`. The only difference is the implied semantics:
+//! guarantees and `()` is a zero-sized type with alignment 1. This means that
+//! both `Result<NonZeroI32, ()>` and `Result<(), NonZeroI32>` have the same
+//! size, alignment, and ABI as `NonZeroI32` (and `Option<NonZeroI32>`). The
+//! only difference between these is in the implied semantics:
+//!
 //! * `Option<NonZeroI32>` is "a non-zero i32 might be present"
 //! * `Result<NonZeroI32, ()>` is "a non-zero i32 success result, if any"
 //! * `Result<(), NonZeroI32>` is "a non-zero i32 error result, if any"
 //!
 //! [opt-rep]: ../option/index.html#representation "Option Representation"
+//! [function call ABI]: ../primitive.fn.html#abi-compatibility
 //!
 //! # Method overview
 //!
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index e17a2e0..4291655 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -9,6 +9,8 @@
 
 impl [u8] {
     /// Checks if all bytes in this slice are within the ASCII range.
+    ///
+    /// An empty slice returns `true`.
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[rustc_const_stable(feature = "const_slice_is_ascii", since = "1.74.0")]
     #[must_use]
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 3a5efa7..82019b9 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -2704,6 +2704,8 @@ pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
 
     /// Checks if all characters in this string are within the ASCII range.
     ///
+    /// An empty string returns `true`.
+    ///
     /// # Examples
     ///
     /// ```
diff --git a/library/core/src/wtf8.rs b/library/core/src/wtf8.rs
index de0dfa5..0c03496 100644
--- a/library/core/src/wtf8.rs
+++ b/library/core/src/wtf8.rs
@@ -562,15 +562,36 @@ fn size_hint(&self) -> (usize, Option<usize>) {
     }
 }
 
-impl fmt::Debug for EncodeWide<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("EncodeWide").finish_non_exhaustive()
-    }
-}
-
 #[stable(feature = "encode_wide_fused_iterator", since = "1.62.0")]
 impl FusedIterator for EncodeWide<'_> {}
 
+#[stable(feature = "encode_wide_debug", since = "CURRENT_RUSTC_VERSION")]
+impl fmt::Debug for EncodeWide<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        struct CodeUnit(u16);
+        impl fmt::Debug for CodeUnit {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                // This output attempts to balance readability with precision.
+                // Render characters which take only one WTF-16 code unit using
+                // `char` syntax and everything else as code units with hex
+                // integer syntax (including paired and unpaired surrogate
+                // halves). Since Rust has no `char`-like type for WTF-16, this
+                // isn't perfect, so if this output isn't suitable, it is open
+                // to being changed (see #140153).
+                match char::from_u32(self.0 as u32) {
+                    Some(c) => write!(f, "{c:?}"),
+                    None => write!(f, "0x{:04X}", self.0),
+                }
+            }
+        }
+
+        write!(f, "EncodeWide(")?;
+        f.debug_list().entries(self.clone().map(CodeUnit)).finish()?;
+        write!(f, ")")?;
+        Ok(())
+    }
+}
+
 impl Hash for CodePoint {
     #[inline]
     fn hash<H: Hasher>(&self, state: &mut H) {
diff --git a/library/coretests/tests/iter/sources.rs b/library/coretests/tests/iter/sources.rs
index 5a391cb..420f308 100644
--- a/library/coretests/tests/iter/sources.rs
+++ b/library/coretests/tests/iter/sources.rs
@@ -37,6 +37,7 @@ fn test_repeat_count() {
 }
 
 #[test]
+#[should_panic = "iterator is infinite"]
 fn test_repeat_last() {
     assert_eq!(repeat(42).last(), Some(42));
 }
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index d4108a5..685c2cf 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -70,6 +70,9 @@
     'rustc-dep-of-std',
 ], public = true }
 
+[target.'cfg(target_os = "motor")'.dependencies]
+moto-rt = { version = "0.15", features = ['rustc-dep-of-std'], public = true }
+
 [target.'cfg(target_os = "hermit")'.dependencies]
 hermit-abi = { version = "0.5.0", features = [
     'rustc-dep-of-std',
diff --git a/library/std/build.rs b/library/std/build.rs
index 8a5a785..bee28e8 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -30,6 +30,7 @@ fn main() {
         || target_os == "windows"
         || target_os == "fuchsia"
         || (target_vendor == "fortanix" && target_env == "sgx")
+        || target_os == "motor"
         || target_os == "hermit"
         || target_os == "trusty"
         || target_os == "l4re"
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 6c09803..09bd911 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -1215,6 +1215,8 @@ pub fn to_ascii_uppercase(&self) -> OsString {
 
     /// Checks if all characters in this string are within the ASCII range.
     ///
+    /// An empty string returns `true`.
+    ///
     /// # Examples
     ///
     /// ```
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 28b2c71..b548eb4 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -387,6 +387,87 @@ fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
     inner(path.as_ref(), contents.as_ref())
 }
 
+/// Changes the timestamps of the file or directory at the specified path.
+///
+/// This function will attempt to set the access and modification times
+/// to the times specified. If the path refers to a symbolic link, this function
+/// will follow the link and change the timestamps of the target file.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `utimensat` function on Unix platforms, the
+/// `setattrlist` function on Apple platforms, and the `SetFileTime` function on Windows.
+///
+/// # Errors
+///
+/// This function will return an error if the user lacks permission to change timestamps on the
+/// target file or symlink. It may also return an error if the OS does not support it.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(fs_set_times)]
+/// use std::fs::{self, FileTimes};
+/// use std::time::SystemTime;
+///
+/// fn main() -> std::io::Result<()> {
+///     let now = SystemTime::now();
+///     let times = FileTimes::new()
+///         .set_accessed(now)
+///         .set_modified(now);
+///     fs::set_times("foo.txt", times)?;
+///     Ok(())
+/// }
+/// ```
+#[unstable(feature = "fs_set_times", issue = "147455")]
+#[doc(alias = "utimens")]
+#[doc(alias = "utimes")]
+#[doc(alias = "utime")]
+pub fn set_times<P: AsRef<Path>>(path: P, times: FileTimes) -> io::Result<()> {
+    fs_imp::set_times(path.as_ref(), times.0)
+}
+
+/// Changes the timestamps of the file or symlink at the specified path.
+///
+/// This function will attempt to set the access and modification times
+/// to the times specified. Differ from `set_times`, if the path refers to a symbolic link,
+/// this function will change the timestamps of the symlink itself, not the target file.
+///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `utimensat` function with `AT_SYMLINK_NOFOLLOW` on
+/// Unix platforms, the `setattrlist` function with `FSOPT_NOFOLLOW` on Apple platforms, and the
+/// `SetFileTime` function on Windows.
+///
+/// # Errors
+///
+/// This function will return an error if the user lacks permission to change timestamps on the
+/// target file or symlink. It may also return an error if the OS does not support it.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(fs_set_times)]
+/// use std::fs::{self, FileTimes};
+/// use std::time::SystemTime;
+///
+/// fn main() -> std::io::Result<()> {
+///     let now = SystemTime::now();
+///     let times = FileTimes::new()
+///         .set_accessed(now)
+///         .set_modified(now);
+///     fs::set_times_nofollow("symlink.txt", times)?;
+///     Ok(())
+/// }
+/// ```
+#[unstable(feature = "fs_set_times", issue = "147455")]
+#[doc(alias = "utimensat")]
+#[doc(alias = "lutimens")]
+#[doc(alias = "lutimes")]
+pub fn set_times_nofollow<P: AsRef<Path>>(path: P, times: FileTimes) -> io::Result<()> {
+    fs_imp::set_times_nofollow(path.as_ref(), times.0)
+}
+
 #[stable(feature = "file_lock", since = "1.89.0")]
 impl error::Error for TryLockError {}
 
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index f8dfb0d..4d67ba9 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -2226,3 +2226,222 @@ fn test_open_options_invalid_combinations() {
     assert_eq!(err.kind(), ErrorKind::InvalidInput);
     assert_eq!(err.to_string(), "must specify at least one of read, write, or append access");
 }
+
+#[test]
+fn test_fs_set_times() {
+    #[cfg(target_vendor = "apple")]
+    use crate::os::darwin::fs::FileTimesExt;
+    #[cfg(windows)]
+    use crate::os::windows::fs::FileTimesExt;
+
+    let tmp = tmpdir();
+    let path = tmp.join("foo");
+    File::create(&path).unwrap();
+
+    let mut times = FileTimes::new();
+    let accessed = SystemTime::UNIX_EPOCH + Duration::from_secs(12345);
+    let modified = SystemTime::UNIX_EPOCH + Duration::from_secs(54321);
+    times = times.set_accessed(accessed).set_modified(modified);
+
+    #[cfg(any(windows, target_vendor = "apple"))]
+    let created = SystemTime::UNIX_EPOCH + Duration::from_secs(32123);
+    #[cfg(any(windows, target_vendor = "apple"))]
+    {
+        times = times.set_created(created);
+    }
+
+    match fs::set_times(&path, times) {
+        // Allow unsupported errors on platforms which don't support setting times.
+        #[cfg(not(any(
+            windows,
+            all(
+                unix,
+                not(any(
+                    target_os = "android",
+                    target_os = "redox",
+                    target_os = "espidf",
+                    target_os = "horizon"
+                ))
+            )
+        )))]
+        Err(e) if e.kind() == ErrorKind::Unsupported => return,
+        Err(e) => panic!("error setting file times: {e:?}"),
+        Ok(_) => {}
+    }
+
+    let metadata = fs::metadata(&path).unwrap();
+    assert_eq!(metadata.accessed().unwrap(), accessed);
+    assert_eq!(metadata.modified().unwrap(), modified);
+    #[cfg(any(windows, target_vendor = "apple"))]
+    {
+        assert_eq!(metadata.created().unwrap(), created);
+    }
+}
+
+#[test]
+fn test_fs_set_times_follows_symlink() {
+    #[cfg(target_vendor = "apple")]
+    use crate::os::darwin::fs::FileTimesExt;
+    #[cfg(windows)]
+    use crate::os::windows::fs::FileTimesExt;
+
+    let tmp = tmpdir();
+
+    // Create a target file
+    let target = tmp.join("target");
+    File::create(&target).unwrap();
+
+    // Create a symlink to the target
+    #[cfg(unix)]
+    let link = tmp.join("link");
+    #[cfg(unix)]
+    crate::os::unix::fs::symlink(&target, &link).unwrap();
+
+    #[cfg(windows)]
+    let link = tmp.join("link.txt");
+    #[cfg(windows)]
+    crate::os::windows::fs::symlink_file(&target, &link).unwrap();
+
+    // Get the symlink's own modified time BEFORE calling set_times (to compare later)
+    // We don't check accessed time because reading metadata may update atime on some platforms.
+    let link_metadata_before = fs::symlink_metadata(&link).unwrap();
+    let link_modified_before = link_metadata_before.modified().unwrap();
+
+    let mut times = FileTimes::new();
+    let accessed = SystemTime::UNIX_EPOCH + Duration::from_secs(12345);
+    let modified = SystemTime::UNIX_EPOCH + Duration::from_secs(54321);
+    times = times.set_accessed(accessed).set_modified(modified);
+
+    #[cfg(any(windows, target_vendor = "apple"))]
+    let created = SystemTime::UNIX_EPOCH + Duration::from_secs(32123);
+    #[cfg(any(windows, target_vendor = "apple"))]
+    {
+        times = times.set_created(created);
+    }
+
+    // Call fs::set_times on the symlink - it should follow the link and modify the target
+    match fs::set_times(&link, times) {
+        // Allow unsupported errors on platforms which don't support setting times.
+        #[cfg(not(any(
+            windows,
+            all(
+                unix,
+                not(any(
+                    target_os = "android",
+                    target_os = "redox",
+                    target_os = "espidf",
+                    target_os = "horizon"
+                ))
+            )
+        )))]
+        Err(e) if e.kind() == ErrorKind::Unsupported => return,
+        Err(e) => panic!("error setting file times through symlink: {e:?}"),
+        Ok(_) => {}
+    }
+
+    // Verify that the TARGET file's times were changed (following the symlink)
+    let target_metadata = fs::metadata(&target).unwrap();
+    assert_eq!(
+        target_metadata.accessed().unwrap(),
+        accessed,
+        "target file accessed time should match"
+    );
+    assert_eq!(
+        target_metadata.modified().unwrap(),
+        modified,
+        "target file modified time should match"
+    );
+    #[cfg(any(windows, target_vendor = "apple"))]
+    {
+        assert_eq!(
+            target_metadata.created().unwrap(),
+            created,
+            "target file created time should match"
+        );
+    }
+
+    // Also verify through the symlink (fs::metadata follows symlinks)
+    let link_followed_metadata = fs::metadata(&link).unwrap();
+    assert_eq!(link_followed_metadata.accessed().unwrap(), accessed);
+    assert_eq!(link_followed_metadata.modified().unwrap(), modified);
+
+    // Verify that the SYMLINK ITSELF was NOT modified
+    // Note: We only check modified time, not accessed time, because reading the symlink
+    // metadata may update its atime on some platforms (e.g., Linux).
+    let link_metadata_after = fs::symlink_metadata(&link).unwrap();
+    assert_eq!(
+        link_metadata_after.modified().unwrap(),
+        link_modified_before,
+        "symlink's own modified time should not change"
+    );
+}
+
+#[test]
+fn test_fs_set_times_nofollow() {
+    #[cfg(target_vendor = "apple")]
+    use crate::os::darwin::fs::FileTimesExt;
+    #[cfg(windows)]
+    use crate::os::windows::fs::FileTimesExt;
+
+    let tmp = tmpdir();
+
+    // Create a target file and a symlink to it
+    let target = tmp.join("target");
+    File::create(&target).unwrap();
+
+    #[cfg(unix)]
+    let link = tmp.join("link");
+    #[cfg(unix)]
+    crate::os::unix::fs::symlink(&target, &link).unwrap();
+
+    #[cfg(windows)]
+    let link = tmp.join("link.txt");
+    #[cfg(windows)]
+    crate::os::windows::fs::symlink_file(&target, &link).unwrap();
+
+    let mut times = FileTimes::new();
+    let accessed = SystemTime::UNIX_EPOCH + Duration::from_secs(11111);
+    let modified = SystemTime::UNIX_EPOCH + Duration::from_secs(22222);
+    times = times.set_accessed(accessed).set_modified(modified);
+
+    #[cfg(any(windows, target_vendor = "apple"))]
+    let created = SystemTime::UNIX_EPOCH + Duration::from_secs(33333);
+    #[cfg(any(windows, target_vendor = "apple"))]
+    {
+        times = times.set_created(created);
+    }
+
+    // Set times on the symlink itself (not following it)
+    match fs::set_times_nofollow(&link, times) {
+        // Allow unsupported errors on platforms which don't support setting times.
+        #[cfg(not(any(
+            windows,
+            all(
+                unix,
+                not(any(
+                    target_os = "android",
+                    target_os = "redox",
+                    target_os = "espidf",
+                    target_os = "horizon"
+                ))
+            )
+        )))]
+        Err(e) if e.kind() == ErrorKind::Unsupported => return,
+        Err(e) => panic!("error setting symlink times: {e:?}"),
+        Ok(_) => {}
+    }
+
+    // Read symlink metadata (without following)
+    let metadata = fs::symlink_metadata(&link).unwrap();
+    assert_eq!(metadata.accessed().unwrap(), accessed);
+    assert_eq!(metadata.modified().unwrap(), modified);
+    #[cfg(any(windows, target_vendor = "apple"))]
+    {
+        assert_eq!(metadata.created().unwrap(), created);
+    }
+
+    // Verify that the target file's times were NOT changed
+    let target_metadata = fs::metadata(&target).unwrap();
+    assert_ne!(target_metadata.accessed().unwrap(), accessed);
+    assert_ne!(target_metadata.modified().unwrap(), modified);
+}
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 10e1e73..6a0e7a6 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -3,6 +3,9 @@
 #![stable(feature = "io_safety", since = "1.63.0")]
 #![deny(unsafe_op_in_unsafe_fn)]
 
+#[cfg(target_os = "motor")]
+use moto_rt::libc;
+
 use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 #[cfg(not(target_os = "trusty"))]
 use crate::fs;
@@ -12,7 +15,8 @@
     target_arch = "wasm32",
     target_env = "sgx",
     target_os = "hermit",
-    target_os = "trusty"
+    target_os = "trusty",
+    target_os = "motor"
 )))]
 use crate::sys::cvt;
 #[cfg(not(target_os = "trusty"))]
@@ -95,7 +99,12 @@ pub fn try_clone(&self) -> crate::io::Result<Self> {
 impl BorrowedFd<'_> {
     /// Creates a new `OwnedFd` instance that shares the same underlying file
     /// description as the existing `BorrowedFd` instance.
-    #[cfg(not(any(target_arch = "wasm32", target_os = "hermit", target_os = "trusty")))]
+    #[cfg(not(any(
+        target_arch = "wasm32",
+        target_os = "hermit",
+        target_os = "trusty",
+        target_os = "motor"
+    )))]
     #[stable(feature = "io_safety", since = "1.63.0")]
     pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
         // We want to atomically duplicate this file descriptor and set the
@@ -123,6 +132,15 @@ pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
     pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
         Err(crate::io::Error::UNSUPPORTED_PLATFORM)
     }
+
+    /// Creates a new `OwnedFd` instance that shares the same underlying file
+    /// description as the existing `BorrowedFd` instance.
+    #[cfg(target_os = "motor")]
+    #[stable(feature = "io_safety", since = "1.63.0")]
+    pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
+        let fd = moto_rt::fs::duplicate(self.as_raw_fd()).map_err(crate::sys::map_motor_error)?;
+        Ok(unsafe { OwnedFd::from_raw_fd(fd) })
+    }
 }
 
 #[stable(feature = "io_safety", since = "1.63.0")]
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index 34a6cf1..c01e6b8 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -4,13 +4,17 @@
 
 #[cfg(target_os = "hermit")]
 use hermit_abi as libc;
+#[cfg(target_os = "motor")]
+use moto_rt::libc;
 
+#[cfg(target_os = "motor")]
+use super::owned::OwnedFd;
 #[cfg(not(target_os = "trusty"))]
 use crate::fs;
 use crate::io;
 #[cfg(target_os = "hermit")]
 use crate::os::hermit::io::OwnedFd;
-#[cfg(not(target_os = "hermit"))]
+#[cfg(all(not(target_os = "hermit"), not(target_os = "motor")))]
 use crate::os::raw;
 #[cfg(all(doc, not(target_arch = "wasm32")))]
 use crate::os::unix::io::AsFd;
@@ -23,10 +27,10 @@
 
 /// Raw file descriptors.
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg(not(target_os = "hermit"))]
+#[cfg(all(not(target_os = "hermit"), not(target_os = "motor")))]
 pub type RawFd = raw::c_int;
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg(target_os = "hermit")]
+#[cfg(any(target_os = "hermit", target_os = "motor"))]
 pub type RawFd = i32;
 
 /// A trait to extract the raw file descriptor from an underlying object.
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index fd7a114..7637440 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -155,6 +155,8 @@ pub mod windows {}
 pub mod l4re;
 #[cfg(target_os = "macos")]
 pub mod macos;
+#[cfg(target_os = "motor")]
+pub mod motor;
 #[cfg(target_os = "netbsd")]
 pub mod netbsd;
 #[cfg(target_os = "nto")]
@@ -182,7 +184,14 @@ pub mod windows {}
 #[cfg(target_os = "xous")]
 pub mod xous;
 
-#[cfg(any(unix, target_os = "hermit", target_os = "trusty", target_os = "wasi", doc))]
+#[cfg(any(
+    unix,
+    target_os = "hermit",
+    target_os = "trusty",
+    target_os = "wasi",
+    target_os = "motor",
+    doc
+))]
 pub mod fd;
 
 #[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin", doc))]
diff --git a/library/std/src/os/motor/ffi.rs b/library/std/src/os/motor/ffi.rs
new file mode 100644
index 0000000..509fe64
--- /dev/null
+++ b/library/std/src/os/motor/ffi.rs
@@ -0,0 +1,37 @@
+//! Motor OS-specific extensions to primitives in the [`std::ffi`] module.
+#![unstable(feature = "motor_ext", issue = "147456")]
+
+use crate::ffi::{OsStr, OsString};
+use crate::sealed::Sealed;
+
+/// Motor OS-specific extensions to [`OsString`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+pub trait OsStringExt: Sealed {
+    /// Motor OS strings are utf-8, and thus just strings.
+    fn as_str(&self) -> &str;
+}
+
+impl OsStringExt for OsString {
+    #[inline]
+    fn as_str(&self) -> &str {
+        self.to_str().unwrap()
+    }
+}
+
+/// Motor OS-specific extensions to [`OsString`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+pub trait OsStrExt: Sealed {
+    /// Motor OS strings are utf-8, and thus just strings.
+    fn as_str(&self) -> &str;
+}
+
+impl OsStrExt for OsStr {
+    #[inline]
+    fn as_str(&self) -> &str {
+        self.to_str().unwrap()
+    }
+}
diff --git a/library/std/src/os/motor/mod.rs b/library/std/src/os/motor/mod.rs
new file mode 100644
index 0000000..18da079
--- /dev/null
+++ b/library/std/src/os/motor/mod.rs
@@ -0,0 +1,4 @@
+#![unstable(feature = "motor_ext", issue = "147456")]
+
+pub mod ffi;
+pub mod process;
diff --git a/library/std/src/os/motor/process.rs b/library/std/src/os/motor/process.rs
new file mode 100644
index 0000000..015fbcb
--- /dev/null
+++ b/library/std/src/os/motor/process.rs
@@ -0,0 +1,15 @@
+#![unstable(feature = "motor_ext", issue = "147456")]
+
+use crate::sealed::Sealed;
+use crate::sys_common::AsInner;
+
+pub trait ChildExt: Sealed {
+    /// Extracts the main thread raw handle, without taking ownership
+    fn sys_handle(&self) -> u64;
+}
+
+impl ChildExt for crate::process::Child {
+    fn sys_handle(&self) -> u64 {
+        self.as_inner().handle()
+    }
+}
diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs
index 2045b2f..f2f1d1c 100644
--- a/library/std/src/sys/alloc/mod.rs
+++ b/library/std/src/sys/alloc/mod.rs
@@ -83,6 +83,9 @@ unsafe fn realloc_fallback(
     target_os = "hermit" => {
         mod hermit;
     }
+    target_os = "motor" => {
+        mod motor;
+    }
     all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
     }
diff --git a/library/std/src/sys/alloc/motor.rs b/library/std/src/sys/alloc/motor.rs
new file mode 100644
index 0000000..271e3c4
--- /dev/null
+++ b/library/std/src/sys/alloc/motor.rs
@@ -0,0 +1,28 @@
+use crate::alloc::{GlobalAlloc, Layout, System};
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    #[inline]
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        // SAFETY: same requirements as in GlobalAlloc::alloc.
+        moto_rt::alloc::alloc(layout)
+    }
+
+    #[inline]
+    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+        // SAFETY: same requirements as in GlobalAlloc::alloc_zeroed.
+        moto_rt::alloc::alloc_zeroed(layout)
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        // SAFETY: same requirements as in GlobalAlloc::dealloc.
+        unsafe { moto_rt::alloc::dealloc(ptr, layout) }
+    }
+
+    #[inline]
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        // SAFETY: same requirements as in GlobalAlloc::realloc.
+        unsafe { moto_rt::alloc::realloc(ptr, layout, new_size) }
+    }
+}
diff --git a/library/std/src/sys/anonymous_pipe/mod.rs b/library/std/src/sys/anonymous_pipe/mod.rs
index b6f4641..64b2c01 100644
--- a/library/std/src/sys/anonymous_pipe/mod.rs
+++ b/library/std/src/sys/anonymous_pipe/mod.rs
@@ -9,6 +9,10 @@
         mod windows;
         pub use windows::{AnonPipe, pipe};
     }
+    target_os = "motor" => {
+        mod motor;
+        pub use motor::{AnonPipe, pipe};
+    }
     _ => {
         mod unsupported;
         pub use unsupported::{AnonPipe, pipe};
diff --git a/library/std/src/sys/anonymous_pipe/motor.rs b/library/std/src/sys/anonymous_pipe/motor.rs
new file mode 100644
index 0000000..dfe10f7
--- /dev/null
+++ b/library/std/src/sys/anonymous_pipe/motor.rs
@@ -0,0 +1,11 @@
+use crate::io;
+use crate::sys::fd::FileDesc;
+use crate::sys::pipe::anon_pipe;
+use crate::sys_common::IntoInner;
+
+pub type AnonPipe = FileDesc;
+
+#[inline]
+pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+    anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner()))
+}
diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs
index 75c59da..5424d40 100644
--- a/library/std/src/sys/args/mod.rs
+++ b/library/std/src/sys/args/mod.rs
@@ -6,6 +6,7 @@
     all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))),
     target_family = "windows",
     target_os = "hermit",
+    target_os = "motor",
     target_os = "uefi",
     target_os = "wasi",
     target_os = "xous",
@@ -28,6 +29,10 @@
         mod sgx;
         pub use sgx::*;
     }
+    target_os = "motor" => {
+        mod motor;
+        pub use motor::*;
+    }
     target_os = "uefi" => {
         mod uefi;
         pub use uefi::*;
diff --git a/library/std/src/sys/args/motor.rs b/library/std/src/sys/args/motor.rs
new file mode 100644
index 0000000..c3dbe87
--- /dev/null
+++ b/library/std/src/sys/args/motor.rs
@@ -0,0 +1,13 @@
+pub use super::common::Args;
+use crate::ffi::OsString;
+
+pub fn args() -> Args {
+    let motor_args: Vec<String> = moto_rt::process::args();
+    let mut rust_args = Vec::new();
+
+    for arg in motor_args {
+        rust_args.push(OsString::from(arg));
+    }
+
+    Args::new(rust_args)
+}
diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs
index f211a9f..8985651 100644
--- a/library/std/src/sys/env/mod.rs
+++ b/library/std/src/sys/env/mod.rs
@@ -5,6 +5,7 @@
 #[cfg(any(
     target_family = "unix",
     target_os = "hermit",
+    target_os = "motor",
     all(target_vendor = "fortanix", target_env = "sgx"),
     target_os = "solid_asp3",
     target_os = "uefi",
@@ -26,6 +27,10 @@
         mod hermit;
         pub use hermit::*;
     }
+    target_os = "motor" => {
+        mod motor;
+        pub use motor::*;
+    }
     all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
diff --git a/library/std/src/sys/env/motor.rs b/library/std/src/sys/env/motor.rs
new file mode 100644
index 0000000..1f756cc
--- /dev/null
+++ b/library/std/src/sys/env/motor.rs
@@ -0,0 +1,27 @@
+pub use super::common::Env;
+use crate::ffi::{OsStr, OsString};
+use crate::io;
+use crate::os::motor::ffi::OsStrExt;
+
+pub fn env() -> Env {
+    let motor_env: Vec<(String, String)> = moto_rt::process::env();
+    let mut rust_env = vec![];
+
+    for (k, v) in motor_env {
+        rust_env.push((OsString::from(k), OsString::from(v)));
+    }
+
+    Env::new(rust_env)
+}
+
+pub fn getenv(key: &OsStr) -> Option<OsString> {
+    moto_rt::process::getenv(key.as_str()).map(|s| OsString::from(s))
+}
+
+pub unsafe fn setenv(key: &OsStr, val: &OsStr) -> io::Result<()> {
+    Ok(moto_rt::process::setenv(key.as_str(), val.as_str()))
+}
+
+pub unsafe fn unsetenv(key: &OsStr) -> io::Result<()> {
+    Ok(moto_rt::process::unsetenv(key.as_str()))
+}
diff --git a/library/std/src/sys/fd/mod.rs b/library/std/src/sys/fd/mod.rs
index 7cb9dd1..330499e 100644
--- a/library/std/src/sys/fd/mod.rs
+++ b/library/std/src/sys/fd/mod.rs
@@ -11,6 +11,10 @@
         mod hermit;
         pub use hermit::*;
     }
+    target_os = "motor" => {
+        mod motor;
+        pub use motor::*;
+    }
     all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::*;
diff --git a/library/std/src/sys/fd/motor.rs b/library/std/src/sys/fd/motor.rs
new file mode 100644
index 0000000..4211fef
--- /dev/null
+++ b/library/std/src/sys/fd/motor.rs
@@ -0,0 +1,124 @@
+#![unstable(reason = "not public", issue = "none", feature = "fd")]
+
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read};
+use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::sys::map_motor_error;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+#[derive(Debug)]
+pub struct FileDesc(OwnedFd);
+
+impl FileDesc {
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        moto_rt::fs::read(self.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        crate::io::default_read_buf(|buf| self.read(buf), cursor)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        io::default_read_vectored(|b| self.read(b), bufs)
+    }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let mut me = self;
+        (&mut me).read_to_end(buf)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        moto_rt::fs::write(self.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        crate::io::default_write_vectored(|b| self.write(b), bufs)
+    }
+
+    pub fn is_write_vectored(&self) -> bool {
+        false
+    }
+
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        moto_rt::net::set_nonblocking(self.as_raw_fd(), nonblocking).map_err(map_motor_error)
+    }
+
+    #[inline]
+    pub fn duplicate(&self) -> io::Result<FileDesc> {
+        let fd = moto_rt::fs::duplicate(self.as_raw_fd()).map_err(map_motor_error)?;
+        // SAFETY: safe because we just got it from the OS runtime.
+        unsafe { Ok(Self::from_raw_fd(fd)) }
+    }
+
+    #[inline]
+    pub fn try_clone(&self) -> io::Result<Self> {
+        self.duplicate()
+    }
+}
+
+impl<'a> Read for &'a FileDesc {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (**self).read(buf)
+    }
+
+    fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        (**self).read_buf(cursor)
+    }
+
+    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        (**self).read_vectored(bufs)
+    }
+
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        (**self).is_read_vectored()
+    }
+}
+
+impl AsInner<OwnedFd> for FileDesc {
+    #[inline]
+    fn as_inner(&self) -> &OwnedFd {
+        &self.0
+    }
+}
+
+impl IntoInner<OwnedFd> for FileDesc {
+    fn into_inner(self) -> OwnedFd {
+        self.0
+    }
+}
+
+impl FromInner<OwnedFd> for FileDesc {
+    fn from_inner(owned_fd: OwnedFd) -> Self {
+        Self(owned_fd)
+    }
+}
+
+impl AsFd for FileDesc {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl AsRawFd for FileDesc {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for FileDesc {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl FromRawFd for FileDesc {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
+    }
+}
diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs
index 175d919..21235bc 100644
--- a/library/std/src/sys/fs/hermit.rs
+++ b/library/std/src/sys/fs/hermit.rs
@@ -566,6 +566,14 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
     Err(Error::from_raw_os_error(22))
 }
 
+pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> {
+    Err(Error::from_raw_os_error(22))
+}
+
+pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> {
+    Err(Error::from_raw_os_error(22))
+}
+
 pub fn rmdir(path: &Path) -> io::Result<()> {
     run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::rmdir(path.as_ptr()) }).map(|_| ()))
 }
diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs
index 64f5a6b..7435422 100644
--- a/library/std/src/sys/fs/mod.rs
+++ b/library/std/src/sys/fs/mod.rs
@@ -27,6 +27,10 @@
         mod hermit;
         use hermit as imp;
     }
+    target_os = "motor" => {
+        mod motor;
+        use motor as imp;
+    }
     target_os = "solid_asp3" => {
         mod solid;
         use solid as imp;
@@ -161,3 +165,11 @@ pub fn exists(path: &Path) -> io::Result<bool> {
     #[cfg(windows)]
     with_native_path(path, &imp::exists)
 }
+
+pub fn set_times(path: &Path, times: FileTimes) -> io::Result<()> {
+    with_native_path(path, &|path| imp::set_times(path, times.clone()))
+}
+
+pub fn set_times_nofollow(path: &Path, times: FileTimes) -> io::Result<()> {
+    with_native_path(path, &|path| imp::set_times_nofollow(path, times.clone()))
+}
diff --git a/library/std/src/sys/fs/motor.rs b/library/std/src/sys/fs/motor.rs
new file mode 100644
index 0000000..656b6e8
--- /dev/null
+++ b/library/std/src/sys/fs/motor.rs
@@ -0,0 +1,478 @@
+use crate::ffi::OsString;
+use crate::hash::Hash;
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
+use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
+use crate::path::{Path, PathBuf};
+use crate::sys::fd::FileDesc;
+pub use crate::sys::fs::common::exists;
+use crate::sys::time::SystemTime;
+use crate::sys::{map_motor_error, unsupported};
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct FileType {
+    rt_filetype: u8,
+}
+
+impl FileType {
+    pub fn is_dir(&self) -> bool {
+        self.rt_filetype == moto_rt::fs::FILETYPE_DIRECTORY
+    }
+
+    pub fn is_file(&self) -> bool {
+        self.rt_filetype == moto_rt::fs::FILETYPE_FILE
+    }
+
+    pub fn is_symlink(&self) -> bool {
+        false
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct FilePermissions {
+    rt_perm: u64,
+}
+
+impl FilePermissions {
+    pub fn readonly(&self) -> bool {
+        (self.rt_perm & moto_rt::fs::PERM_WRITE == 0)
+            && (self.rt_perm & moto_rt::fs::PERM_READ != 0)
+    }
+
+    pub fn set_readonly(&mut self, readonly: bool) {
+        if readonly {
+            self.rt_perm = moto_rt::fs::PERM_READ;
+        } else {
+            self.rt_perm = moto_rt::fs::PERM_READ | moto_rt::fs::PERM_WRITE;
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {
+    modified: u128,
+    accessed: u128,
+}
+
+impl FileTimes {
+    pub fn set_accessed(&mut self, t: SystemTime) {
+        self.accessed = t.as_u128();
+    }
+
+    pub fn set_modified(&mut self, t: SystemTime) {
+        self.modified = t.as_u128();
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct FileAttr {
+    inner: moto_rt::fs::FileAttr,
+}
+
+impl FileAttr {
+    pub fn size(&self) -> u64 {
+        self.inner.size
+    }
+
+    pub fn perm(&self) -> FilePermissions {
+        FilePermissions { rt_perm: self.inner.perm }
+    }
+
+    pub fn file_type(&self) -> FileType {
+        FileType { rt_filetype: self.inner.file_type }
+    }
+
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        match self.inner.modified {
+            0 => Err(crate::io::Error::from(crate::io::ErrorKind::Other)),
+            x => Ok(SystemTime::from_u128(x)),
+        }
+    }
+
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        match self.inner.accessed {
+            0 => Err(crate::io::Error::from(crate::io::ErrorKind::Other)),
+            x => Ok(SystemTime::from_u128(x)),
+        }
+    }
+
+    pub fn created(&self) -> io::Result<SystemTime> {
+        match self.inner.created {
+            0 => Err(crate::io::Error::from(crate::io::ErrorKind::Other)),
+            x => Ok(SystemTime::from_u128(x)),
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+    rt_open_options: u32,
+}
+
+impl OpenOptions {
+    pub fn new() -> OpenOptions {
+        OpenOptions { rt_open_options: 0 }
+    }
+
+    pub fn read(&mut self, read: bool) {
+        if read {
+            self.rt_open_options |= moto_rt::fs::O_READ;
+        } else {
+            self.rt_open_options &= !moto_rt::fs::O_READ;
+        }
+    }
+
+    pub fn write(&mut self, write: bool) {
+        if write {
+            self.rt_open_options |= moto_rt::fs::O_WRITE;
+        } else {
+            self.rt_open_options &= !moto_rt::fs::O_WRITE;
+        }
+    }
+
+    pub fn append(&mut self, append: bool) {
+        if append {
+            self.rt_open_options |= moto_rt::fs::O_APPEND;
+        } else {
+            self.rt_open_options &= !moto_rt::fs::O_APPEND;
+        }
+    }
+
+    pub fn truncate(&mut self, truncate: bool) {
+        if truncate {
+            self.rt_open_options |= moto_rt::fs::O_TRUNCATE;
+        } else {
+            self.rt_open_options &= !moto_rt::fs::O_TRUNCATE;
+        }
+    }
+
+    pub fn create(&mut self, create: bool) {
+        if create {
+            self.rt_open_options |= moto_rt::fs::O_CREATE;
+        } else {
+            self.rt_open_options &= !moto_rt::fs::O_CREATE;
+        }
+    }
+
+    pub fn create_new(&mut self, create_new: bool) {
+        if create_new {
+            self.rt_open_options |= moto_rt::fs::O_CREATE_NEW;
+        } else {
+            self.rt_open_options &= !moto_rt::fs::O_CREATE_NEW;
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct File(FileDesc);
+
+impl File {
+    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+        let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+        moto_rt::fs::open(path, opts.rt_open_options)
+            .map(|fd| unsafe { Self::from_raw_fd(fd) })
+            .map_err(map_motor_error)
+    }
+
+    pub fn file_attr(&self) -> io::Result<FileAttr> {
+        moto_rt::fs::get_file_attr(self.as_raw_fd())
+            .map(|inner| -> FileAttr { FileAttr { inner } })
+            .map_err(map_motor_error)
+    }
+
+    pub fn fsync(&self) -> io::Result<()> {
+        moto_rt::fs::fsync(self.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn datasync(&self) -> io::Result<()> {
+        moto_rt::fs::datasync(self.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn truncate(&self, size: u64) -> io::Result<()> {
+        moto_rt::fs::truncate(self.as_raw_fd(), size).map_err(map_motor_error)
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        moto_rt::fs::read(self.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        crate::io::default_read_vectored(|b| self.read(b), bufs)
+    }
+
+    pub fn is_read_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        crate::io::default_read_buf(|buf| self.read(buf), cursor)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        moto_rt::fs::write(self.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        crate::io::default_write_vectored(|b| self.write(b), bufs)
+    }
+
+    pub fn is_write_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        moto_rt::fs::flush(self.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+        match pos {
+            SeekFrom::Start(offset) => {
+                moto_rt::fs::seek(self.as_raw_fd(), offset as i64, moto_rt::fs::SEEK_SET)
+                    .map_err(map_motor_error)
+            }
+            SeekFrom::End(offset) => {
+                moto_rt::fs::seek(self.as_raw_fd(), offset, moto_rt::fs::SEEK_END)
+                    .map_err(map_motor_error)
+            }
+            SeekFrom::Current(offset) => {
+                moto_rt::fs::seek(self.as_raw_fd(), offset, moto_rt::fs::SEEK_CUR)
+                    .map_err(map_motor_error)
+            }
+        }
+    }
+
+    pub fn tell(&self) -> io::Result<u64> {
+        self.seek(SeekFrom::Current(0))
+    }
+
+    pub fn duplicate(&self) -> io::Result<File> {
+        moto_rt::fs::duplicate(self.as_raw_fd())
+            .map(|fd| unsafe { Self::from_raw_fd(fd) })
+            .map_err(map_motor_error)
+    }
+
+    pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
+        moto_rt::fs::set_file_perm(self.as_raw_fd(), perm.rt_perm).map_err(map_motor_error)
+    }
+
+    pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+        unsupported() // Let's not do that.
+    }
+
+    pub fn lock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn lock_shared(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn try_lock(&self) -> Result<(), crate::fs::TryLockError> {
+        Err(crate::fs::TryLockError::Error(io::Error::from(io::ErrorKind::Unsupported)))
+    }
+
+    pub fn try_lock_shared(&self) -> Result<(), crate::fs::TryLockError> {
+        Err(crate::fs::TryLockError::Error(io::Error::from(io::ErrorKind::Unsupported)))
+    }
+
+    pub fn unlock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn size(&self) -> Option<io::Result<u64>> {
+        None
+    }
+}
+
+#[derive(Debug)]
+pub struct DirBuilder {}
+
+impl DirBuilder {
+    pub fn new() -> DirBuilder {
+        DirBuilder {}
+    }
+
+    pub fn mkdir(&self, path: &Path) -> io::Result<()> {
+        let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+        moto_rt::fs::mkdir(path).map_err(map_motor_error)
+    }
+}
+
+pub fn unlink(path: &Path) -> io::Result<()> {
+    let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+    moto_rt::fs::unlink(path).map_err(map_motor_error)
+}
+
+pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
+    let old = old.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+    let new = new.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+    moto_rt::fs::rename(old, new).map_err(map_motor_error)
+}
+
+pub fn rmdir(path: &Path) -> io::Result<()> {
+    let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+    moto_rt::fs::rmdir(path).map_err(map_motor_error)
+}
+
+pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+    let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+    moto_rt::fs::rmdir_all(path).map_err(map_motor_error)
+}
+
+pub fn set_perm(path: &Path, perm: FilePermissions) -> io::Result<()> {
+    let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+    moto_rt::fs::set_perm(path, perm.rt_perm).map_err(map_motor_error)
+}
+
+pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn stat(path: &Path) -> io::Result<FileAttr> {
+    let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+    let inner = moto_rt::fs::stat(path).map_err(map_motor_error)?;
+    Ok(FileAttr { inner })
+}
+
+pub fn lstat(path: &Path) -> io::Result<FileAttr> {
+    stat(path)
+}
+
+pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
+    let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+    let path = moto_rt::fs::canonicalize(path).map_err(map_motor_error)?;
+    Ok(path.into())
+}
+
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+    let from = from.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+    let to = to.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+    moto_rt::fs::copy(from, to).map_err(map_motor_error)
+}
+
+#[derive(Debug)]
+pub struct ReadDir {
+    rt_fd: moto_rt::RtFd,
+    path: String,
+}
+
+impl Drop for ReadDir {
+    fn drop(&mut self) {
+        moto_rt::fs::closedir(self.rt_fd).unwrap();
+    }
+}
+
+pub fn readdir(path: &Path) -> io::Result<ReadDir> {
+    let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
+    Ok(ReadDir {
+        rt_fd: moto_rt::fs::opendir(path).map_err(map_motor_error)?,
+        path: path.to_owned(),
+    })
+}
+
+impl Iterator for ReadDir {
+    type Item = io::Result<DirEntry>;
+
+    fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        match moto_rt::fs::readdir(self.rt_fd).map_err(map_motor_error) {
+            Ok(maybe_item) => match maybe_item {
+                Some(inner) => Some(Ok(DirEntry { inner, parent_path: self.path.clone() })),
+                None => None,
+            },
+            Err(err) => Some(Err(err)),
+        }
+    }
+}
+
+pub struct DirEntry {
+    parent_path: String,
+    inner: moto_rt::fs::DirEntry,
+}
+
+impl DirEntry {
+    fn filename(&self) -> &str {
+        core::str::from_utf8(unsafe {
+            core::slice::from_raw_parts(self.inner.fname.as_ptr(), self.inner.fname_size as usize)
+        })
+        .unwrap()
+    }
+
+    pub fn path(&self) -> PathBuf {
+        let mut path = self.parent_path.clone();
+        path.push_str("/");
+        path.push_str(self.filename());
+        path.into()
+    }
+
+    pub fn file_name(&self) -> OsString {
+        self.filename().to_owned().into()
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        Ok(FileAttr { inner: self.inner.attr })
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        Ok(FileType { rt_filetype: self.inner.attr.file_type })
+    }
+}
+
+impl AsInner<FileDesc> for File {
+    #[inline]
+    fn as_inner(&self) -> &FileDesc {
+        &self.0
+    }
+}
+
+impl AsInnerMut<FileDesc> for File {
+    #[inline]
+    fn as_inner_mut(&mut self) -> &mut FileDesc {
+        &mut self.0
+    }
+}
+
+impl IntoInner<FileDesc> for File {
+    fn into_inner(self) -> FileDesc {
+        self.0
+    }
+}
+
+impl FromInner<FileDesc> for File {
+    fn from_inner(file_desc: FileDesc) -> Self {
+        Self(file_desc)
+    }
+}
+
+impl AsFd for File {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl AsRawFd for File {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for File {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl FromRawFd for File {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
+    }
+}
diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs
index 808a958..f6d5d3b 100644
--- a/library/std/src/sys/fs/solid.rs
+++ b/library/std/src/sys/fs/solid.rs
@@ -538,6 +538,14 @@ pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
     Ok(())
 }
 
+pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> {
+    unsupported()
+}
+
 pub fn rmdir(p: &Path) -> io::Result<()> {
     if stat(p)?.file_type().is_dir() {
         error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) })
diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs
index 5763d78..e4e7274 100644
--- a/library/std/src/sys/fs/uefi.rs
+++ b/library/std/src/sys/fs/uefi.rs
@@ -333,6 +333,14 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
     unsupported()
 }
 
+pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> {
+    unsupported()
+}
+
 pub fn rmdir(_p: &Path) -> io::Result<()> {
     unsupported()
 }
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index 33a1e7f..d9a7fcb 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -1604,24 +1604,6 @@ pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
     }
 
     pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
-        #[cfg(not(any(
-            target_os = "redox",
-            target_os = "espidf",
-            target_os = "horizon",
-            target_os = "nuttx",
-        )))]
-        let to_timespec = |time: Option<SystemTime>| match time {
-            Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts),
-            Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_error!(
-                io::ErrorKind::InvalidInput,
-                "timestamp is too large to set as a file time",
-            )),
-            Some(_) => Err(io::const_error!(
-                io::ErrorKind::InvalidInput,
-                "timestamp is too small to set as a file time",
-            )),
-            None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
-        };
         cfg_select! {
             any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx") => {
                 // Redox doesn't appear to support `UTIME_OMIT`.
@@ -1634,36 +1616,18 @@ pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
                 ))
             }
             target_vendor = "apple" => {
-                let mut buf = [mem::MaybeUninit::<libc::timespec>::uninit(); 3];
-                let mut num_times = 0;
-                let mut attrlist: libc::attrlist = unsafe { mem::zeroed() };
-                attrlist.bitmapcount = libc::ATTR_BIT_MAP_COUNT;
-                if times.created.is_some() {
-                    buf[num_times].write(to_timespec(times.created)?);
-                    num_times += 1;
-                    attrlist.commonattr |= libc::ATTR_CMN_CRTIME;
-                }
-                if times.modified.is_some() {
-                    buf[num_times].write(to_timespec(times.modified)?);
-                    num_times += 1;
-                    attrlist.commonattr |= libc::ATTR_CMN_MODTIME;
-                }
-                if times.accessed.is_some() {
-                    buf[num_times].write(to_timespec(times.accessed)?);
-                    num_times += 1;
-                    attrlist.commonattr |= libc::ATTR_CMN_ACCTIME;
-                }
+                let ta = TimesAttrlist::from_times(&times)?;
                 cvt(unsafe { libc::fsetattrlist(
                     self.as_raw_fd(),
-                    (&raw const attrlist).cast::<libc::c_void>().cast_mut(),
-                    buf.as_ptr().cast::<libc::c_void>().cast_mut(),
-                    num_times * size_of::<libc::timespec>(),
+                    ta.attrlist(),
+                    ta.times_buf(),
+                    ta.times_buf_size(),
                     0
                 ) })?;
                 Ok(())
             }
             target_os = "android" => {
-                let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?];
+                let times = [file_time_to_timespec(times.accessed)?, file_time_to_timespec(times.modified)?];
                 // futimens requires Android API level 19
                 cvt(unsafe {
                     weak!(
@@ -1697,7 +1661,7 @@ pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
                         return Ok(());
                     }
                 }
-                let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?];
+                let times = [file_time_to_timespec(times.accessed)?, file_time_to_timespec(times.modified)?];
                 cvt(unsafe { libc::futimens(self.as_raw_fd(), times.as_ptr()) })?;
                 Ok(())
             }
@@ -1705,6 +1669,74 @@ pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
     }
 }
 
+#[cfg(not(any(
+    target_os = "redox",
+    target_os = "espidf",
+    target_os = "horizon",
+    target_os = "nuttx",
+)))]
+fn file_time_to_timespec(time: Option<SystemTime>) -> io::Result<libc::timespec> {
+    match time {
+        Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts),
+        Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_error!(
+            io::ErrorKind::InvalidInput,
+            "timestamp is too large to set as a file time",
+        )),
+        Some(_) => Err(io::const_error!(
+            io::ErrorKind::InvalidInput,
+            "timestamp is too small to set as a file time",
+        )),
+        None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
+    }
+}
+
+#[cfg(target_vendor = "apple")]
+struct TimesAttrlist {
+    buf: [mem::MaybeUninit<libc::timespec>; 3],
+    attrlist: libc::attrlist,
+    num_times: usize,
+}
+
+#[cfg(target_vendor = "apple")]
+impl TimesAttrlist {
+    fn from_times(times: &FileTimes) -> io::Result<Self> {
+        let mut this = Self {
+            buf: [mem::MaybeUninit::<libc::timespec>::uninit(); 3],
+            attrlist: unsafe { mem::zeroed() },
+            num_times: 0,
+        };
+        this.attrlist.bitmapcount = libc::ATTR_BIT_MAP_COUNT;
+        if times.created.is_some() {
+            this.buf[this.num_times].write(file_time_to_timespec(times.created)?);
+            this.num_times += 1;
+            this.attrlist.commonattr |= libc::ATTR_CMN_CRTIME;
+        }
+        if times.modified.is_some() {
+            this.buf[this.num_times].write(file_time_to_timespec(times.modified)?);
+            this.num_times += 1;
+            this.attrlist.commonattr |= libc::ATTR_CMN_MODTIME;
+        }
+        if times.accessed.is_some() {
+            this.buf[this.num_times].write(file_time_to_timespec(times.accessed)?);
+            this.num_times += 1;
+            this.attrlist.commonattr |= libc::ATTR_CMN_ACCTIME;
+        }
+        Ok(this)
+    }
+
+    fn attrlist(&self) -> *mut libc::c_void {
+        (&raw const self.attrlist).cast::<libc::c_void>().cast_mut()
+    }
+
+    fn times_buf(&self) -> *mut libc::c_void {
+        self.buf.as_ptr().cast::<libc::c_void>().cast_mut()
+    }
+
+    fn times_buf_size(&self) -> usize {
+        self.num_times * size_of::<libc::timespec>()
+    }
+}
+
 impl DirBuilder {
     pub fn new() -> DirBuilder {
         DirBuilder { mode: 0o777 }
@@ -2081,6 +2113,87 @@ fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)>
     Ok((reader, metadata))
 }
 
+fn set_times_impl(p: &CStr, times: FileTimes, follow_symlinks: bool) -> io::Result<()> {
+    cfg_select! {
+       any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx") => {
+            let _ = (p, times, follow_symlinks);
+            Err(io::const_error!(
+                io::ErrorKind::Unsupported,
+                "setting file times not supported",
+            ))
+       }
+       target_vendor = "apple" => {
+            // Apple platforms use setattrlist which supports setting times on symlinks
+            let ta = TimesAttrlist::from_times(&times)?;
+            let options = if follow_symlinks {
+                0
+            } else {
+                libc::FSOPT_NOFOLLOW
+            };
+
+            cvt(unsafe { libc::setattrlist(
+                p.as_ptr(),
+                ta.attrlist(),
+                ta.times_buf(),
+                ta.times_buf_size(),
+                options as u32
+            ) })?;
+            Ok(())
+       }
+       target_os = "android" => {
+            let times = [file_time_to_timespec(times.accessed)?, file_time_to_timespec(times.modified)?];
+            let flags = if follow_symlinks { 0 } else { libc::AT_SYMLINK_NOFOLLOW };
+            // utimensat requires Android API level 19
+            cvt(unsafe {
+                weak!(
+                    fn utimensat(dirfd: c_int, path: *const libc::c_char, times: *const libc::timespec, flags: c_int) -> c_int;
+                );
+                match utimensat.get() {
+                    Some(utimensat) => utimensat(libc::AT_FDCWD, p.as_ptr(), times.as_ptr(), flags),
+                    None => return Err(io::const_error!(
+                        io::ErrorKind::Unsupported,
+                        "setting file times requires Android API level >= 19",
+                    )),
+                }
+            })?;
+            Ok(())
+       }
+       _ => {
+            let flags = if follow_symlinks { 0 } else { libc::AT_SYMLINK_NOFOLLOW };
+            #[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32", not(target_arch = "riscv32")))]
+            {
+                use crate::sys::{time::__timespec64, weak::weak};
+
+                // Added in glibc 2.34
+                weak!(
+                    fn __utimensat64(dirfd: c_int, path: *const c_char, times: *const __timespec64, flags: c_int) -> c_int;
+                );
+
+                if let Some(utimensat64) = __utimensat64.get() {
+                    let to_timespec = |time: Option<SystemTime>| time.map(|time| time.t.to_timespec64())
+                        .unwrap_or(__timespec64::new(0, libc::UTIME_OMIT as _));
+                    let times = [to_timespec(times.accessed), to_timespec(times.modified)];
+                    cvt(unsafe { utimensat64(libc::AT_FDCWD, p.as_ptr(), times.as_ptr(), flags) })?;
+                    return Ok(());
+                }
+            }
+            let times = [file_time_to_timespec(times.accessed)?, file_time_to_timespec(times.modified)?];
+            cvt(unsafe { libc::utimensat(libc::AT_FDCWD, p.as_ptr(), times.as_ptr(), flags) })?;
+            Ok(())
+         }
+    }
+}
+
+#[inline(always)]
+pub fn set_times(p: &CStr, times: FileTimes) -> io::Result<()> {
+    set_times_impl(p, times, true)
+}
+
+#[inline(always)]
+pub fn set_times_nofollow(p: &CStr, times: FileTimes) -> io::Result<()> {
+    set_times_impl(p, times, false)
+}
+
 #[cfg(target_os = "espidf")]
 fn open_to_and_set_permissions(
     to: &Path,
diff --git a/library/std/src/sys/fs/unsupported.rs b/library/std/src/sys/fs/unsupported.rs
index efaddb5..f222151 100644
--- a/library/std/src/sys/fs/unsupported.rs
+++ b/library/std/src/sys/fs/unsupported.rs
@@ -312,6 +312,14 @@ pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
     match perm.0 {}
 }
 
+pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> {
+    unsupported()
+}
+
 pub fn rmdir(_p: &Path) -> io::Result<()> {
     unsupported()
 }
diff --git a/library/std/src/sys/fs/vexos.rs b/library/std/src/sys/fs/vexos.rs
index f642e7c..99b156d 100644
--- a/library/std/src/sys/fs/vexos.rs
+++ b/library/std/src/sys/fs/vexos.rs
@@ -492,6 +492,14 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
     unsupported()
 }
 
+pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> {
+    unsupported()
+}
+
 pub fn exists(path: &Path) -> io::Result<bool> {
     run_path_with_cstr(path, &|path| Ok(unsafe { vex_sdk::vexFileStatus(path.as_ptr()) } != 0))
 }
diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs
index 0b65b9c..92eb353 100644
--- a/library/std/src/sys/fs/wasi.rs
+++ b/library/std/src/sys/fs/wasi.rs
@@ -536,17 +536,9 @@ pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
     }
 
     pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
-        let to_timestamp = |time: Option<SystemTime>| match time {
-            Some(time) if let Some(ts) = time.to_wasi_timestamp() => Ok(ts),
-            Some(_) => Err(io::const_error!(
-                io::ErrorKind::InvalidInput,
-                "timestamp is too large to set as a file time",
-            )),
-            None => Ok(0),
-        };
         self.fd.filestat_set_times(
-            to_timestamp(times.accessed)?,
-            to_timestamp(times.modified)?,
+            to_wasi_timestamp_or_now(times.accessed)?,
+            to_wasi_timestamp_or_now(times.modified)?,
             times.accessed.map_or(0, |_| wasi::FSTFLAGS_ATIM)
                 | times.modified.map_or(0, |_| wasi::FSTFLAGS_MTIM),
         )
@@ -643,6 +635,45 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
     unsupported()
 }
 
+#[inline(always)]
+pub fn set_times(p: &Path, times: FileTimes) -> io::Result<()> {
+    let (dir, file) = open_parent(p)?;
+    set_times_impl(&dir, &file, times, wasi::LOOKUPFLAGS_SYMLINK_FOLLOW)
+}
+
+#[inline(always)]
+pub fn set_times_nofollow(p: &Path, times: FileTimes) -> io::Result<()> {
+    let (dir, file) = open_parent(p)?;
+    set_times_impl(&dir, &file, times, 0)
+}
+
+fn to_wasi_timestamp_or_now(time: Option<SystemTime>) -> io::Result<wasi::Timestamp> {
+    match time {
+        Some(time) if let Some(ts) = time.to_wasi_timestamp() => Ok(ts),
+        Some(_) => Err(io::const_error!(
+            io::ErrorKind::InvalidInput,
+            "timestamp is too large to set as a file time",
+        )),
+        None => Ok(0),
+    }
+}
+
+fn set_times_impl(
+    fd: &WasiFd,
+    path: &Path,
+    times: FileTimes,
+    flags: wasi::Lookupflags,
+) -> io::Result<()> {
+    fd.path_filestat_set_times(
+        flags,
+        osstr2str(path.as_ref())?,
+        to_wasi_timestamp_or_now(times.accessed)?,
+        to_wasi_timestamp_or_now(times.modified)?,
+        times.accessed.map_or(0, |_| wasi::FSTFLAGS_ATIM)
+            | times.modified.map_or(0, |_| wasi::FSTFLAGS_MTIM),
+    )
+}
+
 pub fn rmdir(p: &Path) -> io::Result<()> {
     let (dir, file) = open_parent(p)?;
     dir.remove_directory(osstr2str(file.as_ref())?)
diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs
index ccfe410..f2d325d 100644
--- a/library/std/src/sys/fs/windows.rs
+++ b/library/std/src/sys/fs/windows.rs
@@ -1514,6 +1514,23 @@ pub fn set_perm(p: &WCStr, perm: FilePermissions) -> io::Result<()> {
     }
 }
 
+pub fn set_times(p: &WCStr, times: FileTimes) -> io::Result<()> {
+    let mut opts = OpenOptions::new();
+    opts.write(true);
+    opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
+    let file = File::open_native(p, &opts)?;
+    file.set_times(times)
+}
+
+pub fn set_times_nofollow(p: &WCStr, times: FileTimes) -> io::Result<()> {
+    let mut opts = OpenOptions::new();
+    opts.write(true);
+    // `FILE_FLAG_OPEN_REPARSE_POINT` for no_follow behavior
+    opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT);
+    let file = File::open_native(p, &opts)?;
+    file.set_times(times)
+}
+
 fn get_path(f: &File) -> io::Result<PathBuf> {
     fill_utf16_buf(
         |buf, sz| unsafe {
diff --git a/library/std/src/sys/io/is_terminal/motor.rs b/library/std/src/sys/io/is_terminal/motor.rs
new file mode 100644
index 0000000..0b70299
--- /dev/null
+++ b/library/std/src/sys/io/is_terminal/motor.rs
@@ -0,0 +1,6 @@
+use crate::os::fd::{AsFd, AsRawFd};
+
+pub fn is_terminal(fd: &impl AsFd) -> bool {
+    let fd = fd.as_fd();
+    moto_rt::fs::is_terminal(fd.as_raw_fd())
+}
diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs
index fe8ec1d..0916eda 100644
--- a/library/std/src/sys/io/mod.rs
+++ b/library/std/src/sys/io/mod.rs
@@ -39,6 +39,10 @@ mod is_terminal {
             mod hermit;
             pub use hermit::*;
         }
+        target_os = "motor" => {
+            mod motor;
+            pub use motor::*;
+        }
         _ => {
             mod unsupported;
             pub use unsupported::*;
diff --git a/library/std/src/sys/net/connection/mod.rs b/library/std/src/sys/net/connection/mod.rs
index 41e7159..2f06491 100644
--- a/library/std/src/sys/net/connection/mod.rs
+++ b/library/std/src/sys/net/connection/mod.rs
@@ -17,6 +17,10 @@
         mod wasip1;
         pub use wasip1::*;
     }
+    target_os = "motor" => {
+        mod motor;
+        pub use motor::*;
+    }
     target_os = "xous" => {
         mod xous;
         pub use xous::*;
diff --git a/library/std/src/sys/net/connection/motor.rs b/library/std/src/sys/net/connection/motor.rs
new file mode 100644
index 0000000..e9bf29e
--- /dev/null
+++ b/library/std/src/sys/net/connection/motor.rs
@@ -0,0 +1,521 @@
+pub use moto_rt::netc;
+
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
+use crate::net::SocketAddr::{V4, V6};
+use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
+use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
+use crate::sys::fd::FileDesc;
+use crate::sys::map_motor_error;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+
+// We want to re-use as much of Rust's stdlib code as possible,
+// and most of it is unixy, but with a lot of nesting.
+#[derive(Debug)]
+pub struct Socket(FileDesc);
+
+#[derive(Debug)]
+pub struct TcpStream {
+    inner: Socket,
+}
+
+impl TcpStream {
+    pub fn socket(&self) -> &Socket {
+        &self.inner
+    }
+
+    pub fn into_socket(self) -> Socket {
+        self.inner
+    }
+
+    pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
+        let addr = into_netc(&addr.to_socket_addrs()?.next().unwrap());
+        moto_rt::net::tcp_connect(&addr, Duration::MAX, false)
+            .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } })
+            .map_err(map_motor_error)
+    }
+
+    pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
+        let addr = into_netc(addr);
+        moto_rt::net::tcp_connect(&addr, timeout, false)
+            .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } })
+            .map_err(map_motor_error)
+    }
+
+    pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        moto_rt::net::set_read_timeout(self.inner.as_raw_fd(), timeout).map_err(map_motor_error)
+    }
+
+    pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        moto_rt::net::set_write_timeout(self.inner.as_raw_fd(), timeout).map_err(map_motor_error)
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        moto_rt::net::read_timeout(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        moto_rt::net::write_timeout(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        moto_rt::net::peek(self.inner.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        moto_rt::fs::read(self.inner.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        crate::io::default_read_buf(|buf| self.read(buf), cursor)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        let bufs: &mut [&mut [u8]] = unsafe { core::mem::transmute(bufs) };
+        moto_rt::fs::read_vectored(self.inner.as_raw_fd(), bufs).map_err(map_motor_error)
+    }
+
+    pub fn is_read_vectored(&self) -> bool {
+        true
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        moto_rt::fs::write(self.inner.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let bufs: &[&[u8]] = unsafe { core::mem::transmute(bufs) };
+        moto_rt::fs::write_vectored(self.inner.as_raw_fd(), bufs).map_err(map_motor_error)
+    }
+
+    pub fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        moto_rt::net::peer_addr(self.inner.as_raw_fd())
+            .map(|addr| from_netc(&addr))
+            .map_err(map_motor_error)
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        moto_rt::net::socket_addr(self.inner.as_raw_fd())
+            .map(|addr| from_netc(&addr))
+            .map_err(map_motor_error)
+    }
+
+    pub fn shutdown(&self, shutdown: Shutdown) -> io::Result<()> {
+        let shutdown = match shutdown {
+            Shutdown::Read => moto_rt::net::SHUTDOWN_READ,
+            Shutdown::Write => moto_rt::net::SHUTDOWN_WRITE,
+            Shutdown::Both => moto_rt::net::SHUTDOWN_READ | moto_rt::net::SHUTDOWN_WRITE,
+        };
+
+        moto_rt::net::shutdown(self.inner.as_raw_fd(), shutdown).map_err(map_motor_error)
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpStream> {
+        moto_rt::fs::duplicate(self.inner.as_raw_fd())
+            .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } })
+            .map_err(map_motor_error)
+    }
+
+    pub fn set_linger(&self, timeout: Option<Duration>) -> io::Result<()> {
+        moto_rt::net::set_linger(self.inner.as_raw_fd(), timeout).map_err(map_motor_error)
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        moto_rt::net::linger(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+        moto_rt::net::set_nodelay(self.inner.as_raw_fd(), nodelay).map_err(map_motor_error)
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        moto_rt::net::nodelay(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+        moto_rt::net::set_ttl(self.inner.as_raw_fd(), ttl).map_err(map_motor_error)
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        moto_rt::net::ttl(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        let e = moto_rt::net::take_error(self.inner.as_raw_fd()).map_err(map_motor_error)?;
+        if e == moto_rt::E_OK { Ok(None) } else { Ok(Some(map_motor_error(e))) }
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        moto_rt::net::set_nonblocking(self.inner.as_raw_fd(), nonblocking).map_err(map_motor_error)
+    }
+}
+
+#[derive(Debug)]
+pub struct TcpListener {
+    inner: Socket,
+}
+
+impl TcpListener {
+    #[inline]
+    pub fn socket(&self) -> &Socket {
+        &self.inner
+    }
+
+    pub fn into_socket(self) -> Socket {
+        self.inner
+    }
+
+    pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
+        let addr = into_netc(&addr.to_socket_addrs()?.next().unwrap());
+        moto_rt::net::bind(moto_rt::net::PROTO_TCP, &addr)
+            .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } })
+            .map_err(map_motor_error)
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        moto_rt::net::socket_addr(self.inner.as_raw_fd())
+            .map(|addr| from_netc(&addr))
+            .map_err(map_motor_error)
+    }
+
+    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        moto_rt::net::accept(self.inner.as_raw_fd())
+            .map(|(fd, addr)| {
+                (TcpStream { inner: unsafe { Socket::from_raw_fd(fd) } }, from_netc(&addr))
+            })
+            .map_err(map_motor_error)
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpListener> {
+        moto_rt::fs::duplicate(self.inner.as_raw_fd())
+            .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } })
+            .map_err(map_motor_error)
+    }
+
+    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+        moto_rt::net::set_ttl(self.inner.as_raw_fd(), ttl).map_err(map_motor_error)
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        moto_rt::net::ttl(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
+        moto_rt::net::set_only_v6(self.inner.as_raw_fd(), only_v6).map_err(map_motor_error)
+    }
+
+    pub fn only_v6(&self) -> io::Result<bool> {
+        moto_rt::net::only_v6(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        let e = moto_rt::net::take_error(self.inner.as_raw_fd()).map_err(map_motor_error)?;
+        if e == moto_rt::E_OK { Ok(None) } else { Ok(Some(map_motor_error(e))) }
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        moto_rt::net::set_nonblocking(self.inner.as_raw_fd(), nonblocking).map_err(map_motor_error)
+    }
+}
+
+#[derive(Debug)]
+pub struct UdpSocket {
+    inner: Socket,
+}
+
+impl UdpSocket {
+    pub fn socket(&self) -> &Socket {
+        &self.inner
+    }
+
+    pub fn into_socket(self) -> Socket {
+        self.inner
+    }
+
+    pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
+        let addr = into_netc(&addr.to_socket_addrs()?.next().unwrap());
+        moto_rt::net::bind(moto_rt::net::PROTO_UDP, &addr)
+            .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } })
+            .map_err(map_motor_error)
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        moto_rt::net::peer_addr(self.inner.as_raw_fd())
+            .map(|addr| from_netc(&addr))
+            .map_err(map_motor_error)
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        moto_rt::net::socket_addr(self.inner.as_raw_fd())
+            .map(|addr| from_netc(&addr))
+            .map_err(map_motor_error)
+    }
+
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        moto_rt::net::udp_recv_from(self.inner.as_raw_fd(), buf)
+            .map(|(sz, addr)| (sz, from_netc(&addr)))
+            .map_err(map_motor_error)
+    }
+
+    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        moto_rt::net::udp_peek_from(self.inner.as_raw_fd(), buf)
+            .map(|(sz, addr)| (sz, from_netc(&addr)))
+            .map_err(map_motor_error)
+    }
+
+    pub fn send_to(&self, buf: &[u8], addr: &SocketAddr) -> io::Result<usize> {
+        let addr = into_netc(addr);
+        moto_rt::net::udp_send_to(self.inner.as_raw_fd(), buf, &addr).map_err(map_motor_error)
+    }
+
+    pub fn duplicate(&self) -> io::Result<UdpSocket> {
+        moto_rt::fs::duplicate(self.inner.as_raw_fd())
+            .map(|fd| Self { inner: unsafe { Socket::from_raw_fd(fd) } })
+            .map_err(map_motor_error)
+    }
+
+    pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        moto_rt::net::set_read_timeout(self.inner.as_raw_fd(), timeout).map_err(map_motor_error)
+    }
+
+    pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        moto_rt::net::set_write_timeout(self.inner.as_raw_fd(), timeout).map_err(map_motor_error)
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        moto_rt::net::read_timeout(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        moto_rt::net::write_timeout(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
+        moto_rt::net::set_udp_broadcast(self.inner.as_raw_fd(), broadcast).map_err(map_motor_error)
+    }
+
+    pub fn broadcast(&self) -> io::Result<bool> {
+        moto_rt::net::udp_broadcast(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn set_multicast_loop_v4(&self, val: bool) -> io::Result<()> {
+        moto_rt::net::set_udp_multicast_loop_v4(self.inner.as_raw_fd(), val)
+            .map_err(map_motor_error)
+    }
+
+    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+        moto_rt::net::udp_multicast_loop_v4(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn set_multicast_ttl_v4(&self, val: u32) -> io::Result<()> {
+        moto_rt::net::set_udp_multicast_ttl_v4(self.inner.as_raw_fd(), val).map_err(map_motor_error)
+    }
+
+    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+        moto_rt::net::udp_multicast_ttl_v4(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn set_multicast_loop_v6(&self, val: bool) -> io::Result<()> {
+        moto_rt::net::set_udp_multicast_loop_v6(self.inner.as_raw_fd(), val)
+            .map_err(map_motor_error)
+    }
+
+    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+        moto_rt::net::udp_multicast_loop_v6(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn join_multicast_v4(&self, addr: &Ipv4Addr, iface: &Ipv4Addr) -> io::Result<()> {
+        let addr = (*addr).into();
+        let iface = (*iface).into();
+        moto_rt::net::join_udp_multicast_v4(self.inner.as_raw_fd(), &addr, &iface)
+            .map_err(map_motor_error)
+    }
+
+    pub fn join_multicast_v6(&self, addr: &Ipv6Addr, iface: u32) -> io::Result<()> {
+        let addr = (*addr).into();
+        moto_rt::net::join_udp_multicast_v6(self.inner.as_raw_fd(), &addr, iface)
+            .map_err(map_motor_error)
+    }
+
+    pub fn leave_multicast_v4(&self, addr: &Ipv4Addr, iface: &Ipv4Addr) -> io::Result<()> {
+        let addr = (*addr).into();
+        let iface = (*iface).into();
+        moto_rt::net::leave_udp_multicast_v4(self.inner.as_raw_fd(), &addr, &iface)
+            .map_err(map_motor_error)
+    }
+
+    pub fn leave_multicast_v6(&self, addr: &Ipv6Addr, iface: u32) -> io::Result<()> {
+        let addr = (*addr).into();
+        moto_rt::net::leave_udp_multicast_v6(self.inner.as_raw_fd(), &addr, iface)
+            .map_err(map_motor_error)
+    }
+
+    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
+        moto_rt::net::set_ttl(self.inner.as_raw_fd(), ttl).map_err(map_motor_error)
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        moto_rt::net::ttl(self.inner.as_raw_fd()).map_err(map_motor_error)
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        moto_rt::net::take_error(self.inner.as_raw_fd())
+            .map(|e| match e {
+                moto_rt::E_OK => None,
+                e => Some(map_motor_error(e)),
+            })
+            .map_err(map_motor_error)
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        moto_rt::net::set_nonblocking(self.inner.as_raw_fd(), nonblocking).map_err(map_motor_error)
+    }
+
+    pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+        moto_rt::fs::read(self.inner.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        moto_rt::net::peek(self.inner.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+        moto_rt::fs::write(self.inner.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
+        let addr = into_netc(&addr.to_socket_addrs()?.next().unwrap());
+        moto_rt::net::udp_connect(self.inner.as_raw_fd(), &addr).map_err(map_motor_error)
+    }
+}
+
+pub struct LookupHost {
+    addresses: alloc::collections::VecDeque<netc::sockaddr>,
+}
+
+pub fn lookup_host(host: &str, port: u16) -> io::Result<LookupHost> {
+    let (_port, addresses) = moto_rt::net::lookup_host(host, port).map_err(map_motor_error)?;
+    Ok(LookupHost { addresses })
+}
+
+impl Iterator for LookupHost {
+    type Item = SocketAddr;
+    fn next(&mut self) -> Option<SocketAddr> {
+        self.addresses.pop_front().map(|addr| from_netc(&addr))
+    }
+}
+
+impl TryFrom<&str> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(host_port: &str) -> io::Result<LookupHost> {
+        let (host, port_str) = host_port
+            .rsplit_once(':')
+            .ok_or(moto_rt::E_INVALID_ARGUMENT)
+            .map_err(map_motor_error)?;
+        let port: u16 =
+            port_str.parse().map_err(|_| moto_rt::E_INVALID_ARGUMENT).map_err(map_motor_error)?;
+        (host, port).try_into()
+    }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(host_port: (&'a str, u16)) -> io::Result<LookupHost> {
+        let (host, port) = host_port;
+
+        let (_port, addresses) = moto_rt::net::lookup_host(host, port).map_err(map_motor_error)?;
+        Ok(LookupHost { addresses })
+    }
+}
+
+fn into_netc(addr: &SocketAddr) -> netc::sockaddr {
+    match addr {
+        V4(addr4) => netc::sockaddr { v4: (*addr4).into() },
+        V6(addr6) => netc::sockaddr { v6: (*addr6).into() },
+    }
+}
+
+fn from_netc(addr: &netc::sockaddr) -> SocketAddr {
+    // SAFETY: all variants of union netc::sockaddr have `sin_family` at the same offset.
+    let family = unsafe { addr.v4.sin_family };
+    match family {
+        netc::AF_INET => SocketAddr::V4(crate::net::SocketAddrV4::from(unsafe { addr.v4 })),
+        netc::AF_INET6 => SocketAddr::V6(crate::net::SocketAddrV6::from(unsafe { addr.v6 })),
+        _ => panic!("bad sin_family {family}"),
+    }
+}
+
+impl AsInner<FileDesc> for Socket {
+    #[inline]
+    fn as_inner(&self) -> &FileDesc {
+        &self.0
+    }
+}
+
+impl IntoInner<FileDesc> for Socket {
+    fn into_inner(self) -> FileDesc {
+        self.0
+    }
+}
+
+impl FromInner<FileDesc> for Socket {
+    fn from_inner(file_desc: FileDesc) -> Self {
+        Self(file_desc)
+    }
+}
+
+impl AsFd for Socket {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl AsRawFd for Socket {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl IntoRawFd for Socket {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl FromRawFd for Socket {
+    unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+        Self(FromRawFd::from_raw_fd(raw_fd))
+    }
+}
+
+impl AsInner<Socket> for TcpStream {
+    #[inline]
+    fn as_inner(&self) -> &Socket {
+        &self.inner
+    }
+}
+
+impl FromInner<Socket> for TcpStream {
+    fn from_inner(socket: Socket) -> TcpStream {
+        TcpStream { inner: socket }
+    }
+}
+
+impl FromInner<Socket> for TcpListener {
+    fn from_inner(socket: Socket) -> TcpListener {
+        TcpListener { inner: socket }
+    }
+}
+
+impl FromInner<Socket> for UdpSocket {
+    fn from_inner(socket: Socket) -> UdpSocket {
+        UdpSocket { inner: socket }
+    }
+}
diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs
index 9e96454..e11df38 100644
--- a/library/std/src/sys/pal/mod.rs
+++ b/library/std/src/sys/pal/mod.rs
@@ -41,6 +41,10 @@
         mod hermit;
         pub use self::hermit::*;
     }
+    target_os = "motor" => {
+        mod motor;
+        pub use self::motor::*;
+    }
     target_os = "trusty" => {
         mod trusty;
         pub use self::trusty::*;
diff --git a/library/std/src/sys/pal/motor/mod.rs b/library/std/src/sys/pal/motor/mod.rs
new file mode 100644
index 0000000..c64f8ff
--- /dev/null
+++ b/library/std/src/sys/pal/motor/mod.rs
@@ -0,0 +1,77 @@
+#![allow(unsafe_op_in_unsafe_fn)]
+
+pub mod os;
+pub mod pipe;
+pub mod time;
+
+pub use moto_rt::futex;
+
+use crate::io as std_io;
+use crate::sys::RawOsError;
+
+pub(crate) fn map_motor_error(err: moto_rt::ErrorCode) -> crate::io::Error {
+    crate::io::Error::from_raw_os_error(err.into())
+}
+
+#[cfg(not(test))]
+#[unsafe(no_mangle)]
+pub extern "C" fn motor_start() -> ! {
+    // Initialize the runtime.
+    moto_rt::start();
+
+    // Call main.
+    unsafe extern "C" {
+        fn main(_: isize, _: *const *const u8, _: u8) -> i32;
+    }
+    let result = unsafe { main(0, core::ptr::null(), 0) };
+
+    // Terminate the process.
+    moto_rt::process::exit(result)
+}
+
+// SAFETY: must be called only once during runtime initialization.
+// NOTE: Motor OS uses moto_rt::start() to initialize runtime (see above).
+pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
+
+// SAFETY: must be called only once during runtime cleanup.
+// NOTE: this is not guaranteed to run, for example when the program aborts.
+pub unsafe fn cleanup() {}
+
+pub fn unsupported<T>() -> std_io::Result<T> {
+    Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> std_io::Error {
+    std_io::Error::UNSUPPORTED_PLATFORM
+}
+
+pub fn is_interrupted(_code: RawOsError) -> bool {
+    false // Motor OS doesn't have signals.
+}
+
+pub fn decode_error_kind(code: RawOsError) -> crate::io::ErrorKind {
+    use moto_rt::error::*;
+    use std_io::ErrorKind;
+
+    if code < 0 || code > u16::MAX.into() {
+        return std_io::ErrorKind::Uncategorized;
+    }
+
+    match code as moto_rt::ErrorCode /* u16 */ {
+        E_ALREADY_IN_USE => ErrorKind::AlreadyExists,
+        E_INVALID_FILENAME => ErrorKind::InvalidFilename,
+        E_NOT_FOUND => ErrorKind::NotFound,
+        E_TIMED_OUT => ErrorKind::TimedOut,
+        E_NOT_IMPLEMENTED => ErrorKind::Unsupported,
+        E_FILE_TOO_LARGE => ErrorKind::FileTooLarge,
+        E_UNEXPECTED_EOF => ErrorKind::UnexpectedEof,
+        E_INVALID_ARGUMENT => ErrorKind::InvalidInput,
+        E_NOT_READY => ErrorKind::WouldBlock,
+        E_NOT_CONNECTED => ErrorKind::NotConnected,
+        _ => crate::io::ErrorKind::Uncategorized,
+    }
+}
+
+pub fn abort_internal() -> ! {
+    core::intrinsics::abort();
+}
diff --git a/library/std/src/sys/pal/motor/os.rs b/library/std/src/sys/pal/motor/os.rs
new file mode 100644
index 0000000..052e3b2
--- /dev/null
+++ b/library/std/src/sys/pal/motor/os.rs
@@ -0,0 +1,100 @@
+use super::map_motor_error;
+use crate::error::Error as StdError;
+use crate::ffi::{OsStr, OsString};
+use crate::marker::PhantomData;
+use crate::os::motor::ffi::OsStrExt;
+use crate::path::{self, PathBuf};
+use crate::sys::RawOsError;
+use crate::{fmt, io};
+
+pub fn errno() -> RawOsError {
+    // Not used in Motor OS because it is ambiguous: Motor OS
+    // is micro-kernel-based, and I/O happens via a shared-memory
+    // ring buffer, so an I/O operation that on a unix is a syscall
+    // may involve no sycalls on Motor OS at all, or a syscall
+    // that e.g. waits for a notification from the I/O driver
+    // (sys-io); and the wait syscall may succeed, but the
+    // driver may report an I/O error; or a bunch of results
+    // for several I/O operations, some successful and some
+    // not.
+    //
+    // Also I/O operations in a Motor OS process are handled by a
+    // separate runtime background/I/O thread, so it is really hard
+    // to define what "last system error in the current thread"
+    // actually means.
+    moto_rt::E_UNKNOWN.into()
+}
+
+pub fn error_string(errno: RawOsError) -> String {
+    let error_code: moto_rt::ErrorCode = match errno {
+        x if x < 0 => moto_rt::E_UNKNOWN,
+        x if x > u16::MAX.into() => moto_rt::E_UNKNOWN,
+        x => x as moto_rt::ErrorCode, /* u16 */
+    };
+    format!("{}", moto_rt::Error::from(error_code))
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+    moto_rt::fs::getcwd().map(PathBuf::from).map_err(map_motor_error)
+}
+
+pub fn chdir(path: &path::Path) -> io::Result<()> {
+    moto_rt::fs::chdir(path.as_os_str().as_str()).map_err(map_motor_error)
+}
+
+pub struct SplitPaths<'a>(!, PhantomData<&'a ()>);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+    panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = PathBuf;
+    fn next(&mut self) -> Option<PathBuf> {
+        self.0
+    }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+where
+    I: Iterator<Item = T>,
+    T: AsRef<OsStr>,
+{
+    Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "not supported on this platform yet".fmt(f)
+    }
+}
+
+impl StdError for JoinPathsError {
+    #[allow(deprecated)]
+    fn description(&self) -> &str {
+        "not supported on this platform yet"
+    }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+    moto_rt::process::current_exe().map(PathBuf::from).map_err(map_motor_error)
+}
+
+pub fn temp_dir() -> PathBuf {
+    PathBuf::from(moto_rt::fs::TEMP_DIR)
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+    None
+}
+
+pub fn exit(code: i32) -> ! {
+    moto_rt::process::exit(code)
+}
+
+pub fn getpid() -> u32 {
+    panic!("Pids on Motor OS are u64.")
+}
diff --git a/library/std/src/sys/pal/motor/pipe.rs b/library/std/src/sys/pal/motor/pipe.rs
new file mode 100644
index 0000000..d3be6dd
--- /dev/null
+++ b/library/std/src/sys/pal/motor/pipe.rs
@@ -0,0 +1,121 @@
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
+use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::sys::fd::FileDesc;
+use crate::sys::map_motor_error;
+use crate::sys_common::{FromInner, IntoInner};
+
+#[derive(Debug)]
+pub struct AnonPipe(FileDesc);
+
+impl From<moto_rt::RtFd> for AnonPipe {
+    fn from(rt_fd: moto_rt::RtFd) -> AnonPipe {
+        unsafe { AnonPipe::from_raw_fd(rt_fd) }
+    }
+}
+
+impl AnonPipe {
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        moto_rt::fs::read(self.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        crate::io::default_read_buf(|buf| self.read(buf), cursor)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        crate::io::default_read_vectored(|b| self.read(b), bufs)
+    }
+
+    pub fn is_read_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        moto_rt::fs::write(self.as_raw_fd(), buf).map_err(map_motor_error)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        crate::io::default_write_vectored(|b| self.write(b), bufs)
+    }
+
+    pub fn is_write_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let mut temp_vec = Vec::new();
+        let mut size = 0_usize;
+        loop {
+            temp_vec.resize(256, 0_u8);
+            match self.read(&mut temp_vec[..]) {
+                Ok(sz) => {
+                    if sz == 0 {
+                        return Ok(size);
+                    }
+                    size += sz;
+                    temp_vec.truncate(sz);
+                    buf.append(&mut temp_vec);
+                }
+                Err(err) => {
+                    if size != 0 {
+                        return Ok(size);
+                    } else {
+                        return Err(err);
+                    }
+                }
+            }
+        }
+    }
+}
+
+impl AsRawFd for AnonPipe {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
+impl FromRawFd for AnonPipe {
+    unsafe fn from_raw_fd(fd: RawFd) -> Self {
+        let desc = FileDesc::from_raw_fd(fd);
+        Self(desc)
+    }
+}
+
+impl IntoRawFd for AnonPipe {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
+impl AsFd for AnonPipe {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.0.as_fd()
+    }
+}
+
+impl IntoInner<OwnedFd> for AnonPipe {
+    fn into_inner(self) -> OwnedFd {
+        self.0.into_inner()
+    }
+}
+
+impl IntoInner<FileDesc> for AnonPipe {
+    fn into_inner(self) -> FileDesc {
+        self.0
+    }
+}
+
+impl FromInner<OwnedFd> for AnonPipe {
+    fn from_inner(owned_fd: OwnedFd) -> Self {
+        Self(FileDesc::from_inner(owned_fd))
+    }
+}
+
+pub fn read2(_p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
+    Err(io::Error::from_raw_os_error(moto_rt::E_NOT_IMPLEMENTED.into()))
+}
+
+#[inline]
+pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+    Err(io::Error::UNSUPPORTED_PLATFORM)
+}
diff --git a/library/std/src/sys/pal/motor/time.rs b/library/std/src/sys/pal/motor/time.rs
new file mode 100644
index 0000000..e917fd4
--- /dev/null
+++ b/library/std/src/sys/pal/motor/time.rs
@@ -0,0 +1 @@
+pub use moto_rt::time::{Instant, SystemTime, UNIX_EPOCH};
diff --git a/library/std/src/sys/path/unix.rs b/library/std/src/sys/path/unix.rs
index faa2616..15530323 100644
--- a/library/std/src/sys/path/unix.rs
+++ b/library/std/src/sys/path/unix.rs
@@ -62,7 +62,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
 }
 
 pub(crate) fn is_absolute(path: &Path) -> bool {
-    if cfg!(any(unix, target_os = "hermit", target_os = "wasi")) {
+    if cfg!(any(unix, target_os = "hermit", target_os = "wasi", target_os = "motor")) {
         path.has_root()
     } else {
         path.has_root() && path.prefix().is_some()
diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs
index 158e44e..eabef92 100644
--- a/library/std/src/sys/personality/mod.rs
+++ b/library/std/src/sys/personality/mod.rs
@@ -17,7 +17,7 @@
     target_os = "emscripten" => {
         mod emcc;
     }
-    any(target_env = "msvc", target_family = "wasm") => {
+    any(target_env = "msvc", target_family = "wasm", target_os = "motor") => {
         // This is required by the compiler to exist (e.g., it's a lang item),
         // but it's never actually called by the compiler because
         // __CxxFrameHandler3 (msvc) / __gxx_wasm_personality_v0 (wasm) is the
diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs
index a1ed0cd..92e4592 100644
--- a/library/std/src/sys/process/mod.rs
+++ b/library/std/src/sys/process/mod.rs
@@ -11,6 +11,10 @@
         mod uefi;
         use uefi as imp;
     }
+    target_os = "motor" => {
+        mod motor;
+        use motor as imp;
+    }
     _ => {
         mod unsupported;
         use unsupported as imp;
@@ -38,6 +42,7 @@
         ))
     ),
     target_os = "windows",
+    target_os = "motor"
 ))]
 pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
     use crate::sys::pipe::read2;
@@ -77,5 +82,6 @@ pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec<u8>, Vec<
         ))
     ),
     target_os = "windows",
+    target_os = "motor"
 )))]
 pub use imp::output;
diff --git a/library/std/src/sys/process/motor.rs b/library/std/src/sys/process/motor.rs
new file mode 100644
index 0000000..9060902
--- /dev/null
+++ b/library/std/src/sys/process/motor.rs
@@ -0,0 +1,313 @@
+use super::CommandEnvs;
+use super::env::CommandEnv;
+use crate::ffi::OsStr;
+pub use crate::ffi::OsString as EnvKey;
+use crate::num::NonZeroI32;
+use crate::os::fd::{FromRawFd, IntoRawFd};
+use crate::os::motor::ffi::OsStrExt;
+use crate::path::Path;
+use crate::process::StdioPipes;
+use crate::sys::fs::File;
+use crate::sys::map_motor_error;
+use crate::sys::pipe::AnonPipe;
+use crate::sys_common::{AsInner, FromInner};
+use crate::{fmt, io};
+
+pub enum Stdio {
+    Inherit,
+    Null,
+    MakePipe,
+    Fd(crate::sys::fd::FileDesc),
+}
+
+impl Stdio {
+    fn into_rt(self) -> moto_rt::RtFd {
+        match self {
+            Stdio::Inherit => moto_rt::process::STDIO_INHERIT,
+            Stdio::Null => moto_rt::process::STDIO_NULL,
+            Stdio::MakePipe => moto_rt::process::STDIO_MAKE_PIPE,
+            Stdio::Fd(fd) => fd.into_raw_fd(),
+        }
+    }
+
+    fn try_clone(&self) -> io::Result<Self> {
+        match self {
+            Self::Fd(fd) => {
+                Ok(Self::Fd(crate::sys::fd::FileDesc::from_inner(fd.as_inner().try_clone()?)))
+            }
+            Self::Inherit => Ok(Self::Inherit),
+            Self::Null => Ok(Self::Null),
+            Self::MakePipe => Ok(Self::MakePipe),
+        }
+    }
+}
+
+#[derive(Default)]
+pub struct Command {
+    program: String,
+    args: Vec<String>,
+    cwd: Option<String>,
+    stdin: Option<Stdio>,
+    stdout: Option<Stdio>,
+    stderr: Option<Stdio>,
+    env: CommandEnv,
+}
+
+impl Command {
+    pub fn new(program: &OsStr) -> Command {
+        let mut env = CommandEnv::default();
+        env.remove(OsStr::new(moto_rt::process::STDIO_IS_TERMINAL_ENV_KEY));
+
+        Command { program: program.as_str().to_owned(), env, ..Default::default() }
+    }
+
+    pub fn arg(&mut self, arg: &OsStr) {
+        self.args.push(arg.as_str().to_owned())
+    }
+
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
+        &mut self.env
+    }
+
+    pub fn cwd(&mut self, dir: &OsStr) {
+        self.cwd = Some(dir.as_str().to_owned())
+    }
+
+    pub fn stdin(&mut self, stdin: Stdio) {
+        self.stdin = Some(stdin);
+    }
+
+    pub fn stdout(&mut self, stdout: Stdio) {
+        self.stdout = Some(stdout);
+    }
+
+    pub fn stderr(&mut self, stderr: Stdio) {
+        self.stderr = Some(stderr);
+    }
+
+    pub fn get_program(&self) -> &OsStr {
+        OsStr::new(self.program.as_str())
+    }
+
+    pub fn get_args(&self) -> CommandArgs<'_> {
+        let iter = self.args.iter();
+        CommandArgs { iter }
+    }
+
+    pub fn get_envs(&self) -> CommandEnvs<'_> {
+        self.env.iter()
+    }
+
+    pub fn get_current_dir(&self) -> Option<&Path> {
+        self.cwd.as_ref().map(Path::new)
+    }
+
+    pub fn spawn(
+        &mut self,
+        default: Stdio,
+        needs_stdin: bool,
+    ) -> io::Result<(Process, StdioPipes)> {
+        let stdin = if let Some(stdin) = self.stdin.as_ref() {
+            stdin.try_clone()?.into_rt()
+        } else if needs_stdin {
+            default.try_clone()?.into_rt()
+        } else {
+            Stdio::Null.into_rt()
+        };
+        let stdout = if let Some(stdout) = self.stdout.as_ref() {
+            stdout.try_clone()?.into_rt()
+        } else {
+            default.try_clone()?.into_rt()
+        };
+        let stderr = if let Some(stderr) = self.stdout.as_ref() {
+            stderr.try_clone()?.into_rt()
+        } else {
+            default.try_clone()?.into_rt()
+        };
+
+        let mut env = Vec::<(String, String)>::new();
+        for (k, v) in self.env.capture() {
+            env.push((k.as_str().to_owned(), v.as_str().to_owned()));
+        }
+
+        let args = moto_rt::process::SpawnArgs {
+            program: self.program.clone(),
+            args: self.args.clone(),
+            env,
+            cwd: self.cwd.clone(),
+            stdin,
+            stdout,
+            stderr,
+        };
+
+        let (handle, stdin, stdout, stderr) =
+            moto_rt::process::spawn(args).map_err(map_motor_error)?;
+
+        Ok((
+            Process { handle },
+            StdioPipes {
+                stdin: if stdin >= 0 { Some(stdin.into()) } else { None },
+                stdout: if stdout >= 0 { Some(stdout.into()) } else { None },
+                stderr: if stderr >= 0 { Some(stderr.into()) } else { None },
+            },
+        ))
+    }
+}
+
+impl From<AnonPipe> for Stdio {
+    fn from(pipe: AnonPipe) -> Stdio {
+        unsafe { Stdio::Fd(crate::sys::fd::FileDesc::from_raw_fd(pipe.into_raw_fd())) }
+    }
+}
+
+impl From<crate::sys::fd::FileDesc> for Stdio {
+    fn from(fd: crate::sys::fd::FileDesc) -> Stdio {
+        Stdio::Fd(fd)
+    }
+}
+
+impl From<File> for Stdio {
+    fn from(_file: File) -> Stdio {
+        panic!("Not implemented")
+    }
+}
+
+impl From<io::Stdout> for Stdio {
+    fn from(_: io::Stdout) -> Stdio {
+        panic!("Not implemented")
+    }
+}
+
+impl From<io::Stderr> for Stdio {
+    fn from(_: io::Stderr) -> Stdio {
+        panic!("Not implemented")
+    }
+}
+
+impl fmt::Debug for Command {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        Ok(())
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
+pub struct ExitStatus(i32);
+
+impl ExitStatus {
+    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
+        if self.0 == 0 { Ok(()) } else { Err(ExitStatusError(*self)) }
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        Some(self.0)
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "exit code: {}", self.0)
+    }
+}
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatusError(ExitStatus);
+
+impl Into<ExitStatus> for ExitStatusError {
+    fn into(self) -> ExitStatus {
+        self.0
+    }
+}
+
+impl ExitStatusError {
+    pub fn code(self) -> Option<NonZeroI32> {
+        NonZeroI32::new(self.0.0)
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(i32);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(0);
+    pub const FAILURE: ExitCode = ExitCode(1);
+
+    pub fn as_i32(&self) -> i32 {
+        self.0
+    }
+}
+
+impl From<u8> for ExitCode {
+    fn from(code: u8) -> Self {
+        Self(code as i32)
+    }
+}
+
+pub struct Process {
+    handle: u64,
+}
+
+impl Drop for Process {
+    fn drop(&mut self) {
+        moto_rt::alloc::release_handle(self.handle).unwrap();
+    }
+}
+
+impl Process {
+    pub fn id(&self) -> u32 {
+        0
+    }
+
+    pub fn kill(&mut self) -> io::Result<()> {
+        match moto_rt::process::kill(self.handle) {
+            moto_rt::E_OK => Ok(()),
+            err => Err(map_motor_error(err)),
+        }
+    }
+
+    pub fn wait(&mut self) -> io::Result<ExitStatus> {
+        moto_rt::process::wait(self.handle).map(|c| ExitStatus(c)).map_err(map_motor_error)
+    }
+
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+        match moto_rt::process::try_wait(self.handle) {
+            Ok(s) => Ok(Some(ExitStatus(s))),
+            Err(err) => match err {
+                moto_rt::E_NOT_READY => Ok(None),
+                err => Err(map_motor_error(err)),
+            },
+        }
+    }
+
+    #[allow(unused)]
+    pub fn handle(&self) -> u64 {
+        self.handle
+    }
+}
+
+pub struct CommandArgs<'a> {
+    iter: crate::slice::Iter<'a, String>,
+}
+
+impl<'a> Iterator for CommandArgs<'a> {
+    type Item = &'a OsStr;
+    fn next(&mut self) -> Option<&'a OsStr> {
+        self.iter.next().map(|arg| OsStr::new(arg))
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+impl<'a> ExactSizeIterator for CommandArgs<'a> {
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
+
+impl<'a> fmt::Debug for CommandArgs<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.iter.clone()).finish()
+    }
+}
diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs
index ec81d89..91f72d0 100644
--- a/library/std/src/sys/random/mod.rs
+++ b/library/std/src/sys/random/mod.rs
@@ -62,6 +62,10 @@
         mod redox;
         pub use redox::fill_bytes;
     }
+    target_os = "motor" => {
+        mod motor;
+        pub use motor::fill_bytes;
+    }
     all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::fill_bytes;
diff --git a/library/std/src/sys/random/motor.rs b/library/std/src/sys/random/motor.rs
new file mode 100644
index 0000000..386b370
--- /dev/null
+++ b/library/std/src/sys/random/motor.rs
@@ -0,0 +1,3 @@
+pub fn fill_bytes(bytes: &mut [u8]) {
+    moto_rt::fill_random_bytes(bytes)
+}
diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs
index 660317e..d51ea9a 100644
--- a/library/std/src/sys/stdio/mod.rs
+++ b/library/std/src/sys/stdio/mod.rs
@@ -13,6 +13,10 @@
         mod sgx;
         pub use sgx::*;
     }
+    target_os = "motor" => {
+        mod motor;
+        pub use motor::*;
+    }
     target_os = "solid_asp3" => {
         mod solid;
         pub use solid::*;
diff --git a/library/std/src/sys/stdio/motor.rs b/library/std/src/sys/stdio/motor.rs
new file mode 100644
index 0000000..0a44fea
--- /dev/null
+++ b/library/std/src/sys/stdio/motor.rs
@@ -0,0 +1,232 @@
+use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
+use crate::sys::map_motor_error;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::{io, process, sys};
+
+pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE;
+
+pub struct Stdin {}
+
+impl Stdin {
+    pub const fn new() -> Self {
+        Self {}
+    }
+}
+
+pub struct Stdout {}
+
+impl Stdout {
+    pub const fn new() -> Self {
+        Self {}
+    }
+}
+
+pub struct Stderr {}
+
+impl Stderr {
+    pub const fn new() -> Self {
+        Self {}
+    }
+}
+
+impl crate::sealed::Sealed for Stdin {}
+
+impl crate::io::IsTerminal for Stdin {
+    fn is_terminal(&self) -> bool {
+        moto_rt::fs::is_terminal(moto_rt::FD_STDIN)
+    }
+}
+
+impl io::Read for Stdin {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        moto_rt::fs::read(moto_rt::FD_STDIN, buf).map_err(map_motor_error)
+    }
+}
+
+impl io::Write for Stdout {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        moto_rt::fs::write(moto_rt::FD_STDOUT, buf).map_err(map_motor_error)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        moto_rt::fs::flush(moto_rt::FD_STDOUT).map_err(map_motor_error)
+    }
+}
+
+impl io::Write for Stderr {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        moto_rt::fs::write(moto_rt::FD_STDERR, buf).map_err(map_motor_error)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        moto_rt::fs::flush(moto_rt::FD_STDERR).map_err(map_motor_error)
+    }
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+    Some(Stderr::new())
+}
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+    true
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawFd for process::Stdio {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+        let fd = unsafe { sys::fd::FileDesc::from_raw_fd(fd) };
+        let io = sys::process::Stdio::Fd(fd);
+        process::Stdio::from_inner(io)
+    }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<OwnedFd> for process::Stdio {
+    /// Takes ownership of a file descriptor and returns a [`Stdio`](process::Stdio)
+    /// that can attach a stream to it.
+    #[inline]
+    fn from(fd: OwnedFd) -> process::Stdio {
+        let fd = sys::fd::FileDesc::from_inner(fd);
+        let io = sys::process::Stdio::Fd(fd);
+        process::Stdio::from_inner(io)
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdin {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().as_raw_fd()
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdout {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().as_raw_fd()
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStderr {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().as_raw_fd()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdin {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_raw_fd()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdout {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_raw_fd()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStderr {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_raw_fd()
+    }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::process::ChildStdin {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.as_inner().as_fd()
+    }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStdin> for OwnedFd {
+    /// Takes ownership of a [`ChildStdin`](crate::process::ChildStdin)'s file descriptor.
+    #[inline]
+    fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd {
+        child_stdin.into_inner().into_inner()
+    }
+}
+
+/// Creates a `ChildStdin` from the provided `OwnedFd`.
+///
+/// The provided file descriptor must point to a pipe
+/// with the `CLOEXEC` flag set.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedFd> for process::ChildStdin {
+    #[inline]
+    fn from(fd: OwnedFd) -> process::ChildStdin {
+        let pipe = sys::pipe::AnonPipe::from_inner(fd);
+        process::ChildStdin::from_inner(pipe)
+    }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::process::ChildStdout {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.as_inner().as_fd()
+    }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStdout> for OwnedFd {
+    /// Takes ownership of a [`ChildStdout`](crate::process::ChildStdout)'s file descriptor.
+    #[inline]
+    fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd {
+        child_stdout.into_inner().into_inner()
+    }
+}
+
+/// Creates a `ChildStdout` from the provided `OwnedFd`.
+///
+/// The provided file descriptor must point to a pipe
+/// with the `CLOEXEC` flag set.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedFd> for process::ChildStdout {
+    #[inline]
+    fn from(fd: OwnedFd) -> process::ChildStdout {
+        let pipe = sys::pipe::AnonPipe::from_inner(fd);
+        process::ChildStdout::from_inner(pipe)
+    }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl AsFd for crate::process::ChildStderr {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.as_inner().as_fd()
+    }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl From<crate::process::ChildStderr> for OwnedFd {
+    /// Takes ownership of a [`ChildStderr`](crate::process::ChildStderr)'s file descriptor.
+    #[inline]
+    fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd {
+        child_stderr.into_inner().into_inner()
+    }
+}
+
+/// Creates a `ChildStderr` from the provided `OwnedFd`.
+///
+/// The provided file descriptor must point to a pipe
+/// with the `CLOEXEC` flag set.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedFd> for process::ChildStderr {
+    #[inline]
+    fn from(fd: OwnedFd) -> process::ChildStderr {
+        let pipe = sys::pipe::AnonPipe::from_inner(fd);
+        process::ChildStderr::from_inner(pipe)
+    }
+}
diff --git a/library/std/src/sys/sync/condvar/mod.rs b/library/std/src/sys/sync/condvar/mod.rs
index cb67d27..83cf0ae 100644
--- a/library/std/src/sys/sync/condvar/mod.rs
+++ b/library/std/src/sys/sync/condvar/mod.rs
@@ -6,6 +6,7 @@
         target_os = "freebsd",
         target_os = "openbsd",
         target_os = "dragonfly",
+        target_os = "motor",
         target_os = "fuchsia",
         all(target_family = "wasm", target_feature = "atomics"),
         target_os = "hermit",
diff --git a/library/std/src/sys/sync/mutex/mod.rs b/library/std/src/sys/sync/mutex/mod.rs
index c885b0e..e3d6ad1 100644
--- a/library/std/src/sys/sync/mutex/mod.rs
+++ b/library/std/src/sys/sync/mutex/mod.rs
@@ -5,6 +5,7 @@
         target_os = "android",
         target_os = "freebsd",
         target_os = "openbsd",
+        target_os = "motor",
         target_os = "dragonfly",
         all(target_family = "wasm", target_feature = "atomics"),
         target_os = "hermit",
diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs
index 8adeb1f..aeea884 100644
--- a/library/std/src/sys/sync/once/mod.rs
+++ b/library/std/src/sys/sync/once/mod.rs
@@ -14,6 +14,7 @@
         target_os = "android",
         all(target_arch = "wasm32", target_feature = "atomics"),
         target_os = "freebsd",
+        target_os = "motor",
         target_os = "openbsd",
         target_os = "dragonfly",
         target_os = "fuchsia",
diff --git a/library/std/src/sys/sync/rwlock/mod.rs b/library/std/src/sys/sync/rwlock/mod.rs
index 82f1dd1..ab5715b 100644
--- a/library/std/src/sys/sync/rwlock/mod.rs
+++ b/library/std/src/sys/sync/rwlock/mod.rs
@@ -9,6 +9,7 @@
         target_os = "fuchsia",
         all(target_family = "wasm", target_feature = "atomics"),
         target_os = "hermit",
+       target_os = "motor",
     ) => {
         mod futex;
         pub use futex::RwLock;
diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs
index b9fb27b..e8a9dc8 100644
--- a/library/std/src/sys/sync/thread_parking/mod.rs
+++ b/library/std/src/sys/sync/thread_parking/mod.rs
@@ -8,6 +8,7 @@
         target_os = "openbsd",
         target_os = "dragonfly",
         target_os = "fuchsia",
+        target_os = "motor",
         target_os = "hermit",
     ) => {
         mod futex;
diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs
index a20b2a3..b98be62 100644
--- a/library/std/src/sys/thread/mod.rs
+++ b/library/std/src/sys/thread/mod.rs
@@ -6,6 +6,10 @@
         mod unsupported;
         pub use unsupported::{current_os_id, set_name};
     }
+    target_os = "motor" => {
+        mod motor;
+        pub use motor::*;
+    }
     all(target_vendor = "fortanix", target_env = "sgx") => {
         mod sgx;
         pub use sgx::{Thread, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
diff --git a/library/std/src/sys/thread/motor.rs b/library/std/src/sys/thread/motor.rs
new file mode 100644
index 0000000..0457d88
--- /dev/null
+++ b/library/std/src/sys/thread/motor.rs
@@ -0,0 +1,63 @@
+use crate::ffi::CStr;
+use crate::io;
+use crate::num::NonZeroUsize;
+use crate::sys::map_motor_error;
+use crate::time::Duration;
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 256;
+
+pub struct Thread {
+    sys_thread: moto_rt::thread::ThreadHandle,
+}
+
+unsafe impl Send for Thread {}
+unsafe impl Sync for Thread {}
+
+impl Thread {
+    pub unsafe fn new(
+        stack: usize,
+        _name: Option<&str>,
+        p: Box<dyn FnOnce()>,
+    ) -> io::Result<Thread> {
+        extern "C" fn __moto_rt_thread_fn(thread_arg: u64) {
+            unsafe {
+                Box::from_raw(
+                    core::ptr::with_exposed_provenance::<Box<dyn FnOnce()>>(thread_arg as usize)
+                        .cast_mut(),
+                )();
+            }
+        }
+
+        let thread_arg = Box::into_raw(Box::new(p)).expose_provenance() as u64;
+        let sys_thread = moto_rt::thread::spawn(__moto_rt_thread_fn, stack, thread_arg)
+            .map_err(map_motor_error)?;
+        Ok(Self { sys_thread })
+    }
+
+    pub fn join(self) {
+        assert!(moto_rt::thread::join(self.sys_thread) == moto_rt::E_OK)
+    }
+}
+
+pub fn set_name(name: &CStr) {
+    let bytes = name.to_bytes();
+    if let Ok(s) = core::str::from_utf8(bytes) {
+        let _ = moto_rt::thread::set_name(s);
+    }
+}
+
+pub fn current_os_id() -> Option<u64> {
+    None
+}
+
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+    Ok(unsafe { NonZeroUsize::new_unchecked(moto_rt::num_cpus()) })
+}
+
+pub fn yield_now() {
+    moto_rt::thread::yield_now()
+}
+
+pub fn sleep(dur: Duration) {
+    moto_rt::thread::sleep_until(moto_rt::time::Instant::now() + dur)
+}
diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs
index f7f051b..e88011a 100644
--- a/library/std/src/sys/thread_local/mod.rs
+++ b/library/std/src/sys/thread_local/mod.rs
@@ -187,6 +187,14 @@ pub(crate) mod key {
             pub(super) use xous::{Key, get, set};
             use xous::{create, destroy};
         }
+        target_os = "motor" => {
+            mod racy;
+            #[cfg(test)]
+            mod tests;
+            pub(super) use racy::LazyKey;
+            pub(super) use moto_rt::tls::{Key, get, set};
+            use moto_rt::tls::{create, destroy};
+        }
         _ => {}
     }
 }
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index ec45c72..c6cb1b0 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -15,7 +15,6 @@
 //! Progress on this is tracked in #84187.
 
 #![allow(missing_docs)]
-#![allow(missing_debug_implementations)]
 
 #[cfg(test)]
 mod tests;
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index fd7cce3..16313da 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -620,9 +620,8 @@ fn drop(&mut self) {
 /// (It is the responsibility of the program to either eventually join threads it
 /// creates or detach them; otherwise, a resource leak will result.)
 ///
-/// This call will create a thread using default parameters of [`Builder`], if you
-/// want to specify the stack size or the name of the thread, use this API
-/// instead.
+/// This function creates a thread with the default parameters of [`Builder`].
+/// To specify the new thread's stack size or the name, use [`Builder::spawn`].
 ///
 /// As you can see in the signature of `spawn` there are two constraints on
 /// both the closure given to `spawn` and its return value, let's explain them:
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
index a4c0ca5..75a5303 100644
--- a/library/std/src/thread/scoped.rs
+++ b/library/std/src/thread/scoped.rs
@@ -181,9 +181,8 @@ impl<'scope, 'env> Scope<'scope, 'env> {
     /// end of the scope. In that case, if the spawned thread panics, [`scope`] will
     /// panic after all threads are joined.
     ///
-    /// This call will create a thread using default parameters of [`Builder`].
-    /// If you want to specify the stack size or the name of the thread, use
-    /// [`Builder::spawn_scoped`] instead.
+    /// This function creates a thread with the default parameters of [`Builder`].
+    /// To specify the new thread's stack size or the name, use [`Builder::spawn_scoped`].
     ///
     /// # Panics
     ///
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 87fc404..4eb0dab 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -432,7 +432,7 @@
 `x86_64-unknown-l4re-uclibc` | ? |  |
 [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * |  | 64-bit Linux with no libc
 [`x86_64-unknown-managarm-mlibc`](platform-support/managarm.md) | ? |   | x86_64 Managarm
-[`x86_64-unknown-motor`](platform-support/motor.md) | ? |  | x86_64 Motor OS
+[`x86_64-unknown-motor`](platform-support/motor.md) | ✓ |  | x86_64 Motor OS
 [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
 [`x86_64-unknown-trusty`](platform-support/trusty.md) | ✓ |  |
 `x86_64-uwp-windows-gnu` | ✓ |  |
diff --git a/src/doc/rustc/src/platform-support/motor.md b/src/doc/rustc/src/platform-support/motor.md
index e7aa7b2..6d44d17 100644
--- a/src/doc/rustc/src/platform-support/motor.md
+++ b/src/doc/rustc/src/platform-support/motor.md
@@ -15,27 +15,35 @@
 
 Motor OS uses the ELF file format.
 
-## Building the target
+## Building the target toolchain
 
-The target can be built by enabling it for a `rustc` build, for example:
+Motor OS target toolchain can be
+[built using `x.py`](https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html):
+
+The bootstrap file:
 
 ```toml
 [build]
-build-stage = 2
-target = ["x86_64-unknown-motor"]
+host = ["x86_64-unknown-linux-gnu"]
+target = ["x86_64-unknown-linux-gnu", "x86_64-unknown-motor"]
+```
+
+The build command:
+
+```sh
+./x.py build --stage 2 clippy library
 ```
 
 ## Building Rust programs
 
-Rust standard library is fully supported/implemented, but is not yet part of
-the official Rust repo, so an out-of-tree building process should be
-followed, as described in the
-[build doc](https://github.com/moturus/motor-os/blob/main/docs/build.md).
+See the [Hello Motor OS](https://github.com/moturus/motor-os/blob/main/docs/recipes/hello-motor-os.md)
+example.
 
 ## Testing
 
 Cross-compiled Rust binaries and test artifacts can be executed in Motor OS VMs,
-as described in e.g.
+as described in the [build doc](https://github.com/moturus/motor-os/blob/main/docs/build.md)
+and the
 [Hello Motor OS](https://github.com/moturus/motor-os/blob/main/docs/recipes/hello-motor-os.md)
 example.
 
diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md
index be361ee..090dc00 100644
--- a/src/doc/style-guide/src/items.md
+++ b/src/doc/style-guide/src/items.md
@@ -123,7 +123,7 @@
 Prefer using a unit struct (e.g., `struct Foo;`) to an empty struct (e.g.,
 `struct Foo();` or `struct Foo {}`, these only exist to simplify code
 generation), but if you must use an empty struct, keep it on one line with no
-space between the braces: `struct Foo;` or `struct Foo {}`.
+space between the braces: `struct Foo();` or `struct Foo {}`.
 
 The same guidelines are used for untagged union declarations.
 
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index f9c2465..63412e2 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -21,7 +21,7 @@
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 smallvec = "1.8.1"
-stringdex = { version = "0.0.1-alpha10" }
+stringdex = "=0.0.2"
 tempfile = "3"
 threadpool = "1.8.1"
 tracing = "0.1"
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 100e07f..ddfce7a 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -34,7 +34,7 @@ pub(crate) fn synthesize_blanket_impls(
         'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() {
             trace!("considering impl `{impl_def_id:?}` for trait `{trait_def_id:?}`");
 
-            let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+            let trait_ref = tcx.impl_trait_ref(impl_def_id);
             if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
                 continue;
             }
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 881a81b..6c77e41 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -751,7 +751,7 @@ fn check_changed_auto_active_status(
         }
         for attr in doc_cfg {
             if let Some(cfg_mi) =
-                attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg(attr, sess))
+                attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg_old(attr, sess))
             {
                 match Cfg::parse(cfg_mi) {
                     Ok(new_cfg) => cfg_info.current_cfg &= new_cfg,
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 971c7f6..b470af5 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -448,7 +448,7 @@ pub(crate) fn build_impl(
     let tcx = cx.tcx;
     let _prof_timer = tcx.sess.prof.generic_activity("build_impl");
 
-    let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder);
+    let associated_trait = tcx.impl_opt_trait_ref(did).map(ty::EarlyBinder::skip_binder);
 
     // Do not inline compiler-internal items unless we're a compiler-internal crate.
     let is_compiler_internal = |did| {
@@ -566,7 +566,11 @@ pub(crate) fn build_impl(
             clean::enter_impl_trait(cx, |cx| clean_ty_generics(cx, did)),
         ),
     };
-    let polarity = tcx.impl_polarity(did);
+    let polarity = if associated_trait.is_some() {
+        tcx.impl_polarity(did)
+    } else {
+        ty::ImplPolarity::Positive
+    };
     let trait_ = associated_trait
         .map(|t| clean_trait_ref_with_constraints(cx, ty::Binder::dummy(t), ThinVec::new()));
     if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 481395f..4a95f21 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2934,7 +2934,11 @@ fn clean_impl<'tcx>(
             trait_,
             for_,
             items,
-            polarity: tcx.impl_polarity(def_id),
+            polarity: if impl_.of_trait.is_some() {
+                tcx.impl_polarity(def_id)
+            } else {
+                ty::ImplPolarity::Positive
+            },
             kind: if utils::has_doc_flag(tcx, def_id.to_def_id(), sym::fake_variadic) {
                 ImplKind::FakeVariadic
             } else {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index c3b1e3e..13178ee 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2403,7 +2403,7 @@ fn get_id_for_impl(tcx: TyCtxt<'_>, impl_id: ItemId) -> String {
             (ty, Some(ty::TraitRef::new(tcx, trait_, [ty])))
         }
         ItemId::Blanket { impl_id, .. } | ItemId::DefId(impl_id) => {
-            if let Some(trait_ref) = tcx.impl_trait_ref(impl_id) {
+            if let Some(trait_ref) = tcx.impl_opt_trait_ref(impl_id) {
                 let trait_ref = trait_ref.skip_binder();
                 (trait_ref.self_ty(), Some(trait_ref))
             } else {
diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js
index 6299576..d8b8c5b 100644
--- a/src/librustdoc/html/static/js/stringdex.js
+++ b/src/librustdoc/html/static/js/stringdex.js
@@ -1447,7 +1447,7 @@
         makeSearchTreeBranchesAlphaBitmapClass(LONG_ALPHABITMAP_CHARS, 4);
 
     /**
-     * @typedef {PrefixSearchTree|SuffixSearchTree} SearchTree
+     * @typedef {PrefixSearchTree|SuffixSearchTree|InlineNeighborsTree} SearchTree
      * @typedef {PrefixTrie|SuffixTrie} Trie
      */
 
@@ -1675,9 +1675,12 @@
                         yield leaves;
                     }
                 }
-                /** @type {HashTable<[number, SearchTree][]>} */
+                /** @type {HashTable<[number, PrefixSearchTree|SuffixSearchTree][]>} */
                 const subnodes = new HashTable();
-                for await (const node of current_layer) {
+                for await (const nodeEncoded of current_layer) {
+                    const node = nodeEncoded instanceof InlineNeighborsTree ?
+                        nodeEncoded.decode() :
+                        nodeEncoded;
                     const branches = node.branches;
                     const l = branches.subtrees.length;
                     for (let i = 0; i < l; ++i) {
@@ -1741,7 +1744,10 @@
                 // we then yield the smallest ones (can't yield bigger ones
                 // if we want to do them in order)
                 for (const {node, len} of current_layer) {
-                    const tree = await node;
+                    const treeEncoded = await node;
+                    const tree = treeEncoded instanceof InlineNeighborsTree ?
+                        treeEncoded.decode() :
+                        treeEncoded;
                     if (!(tree instanceof PrefixSearchTree)) {
                         continue;
                     }
@@ -1804,7 +1810,10 @@
                 /** @type {HashTable<{byte: number, tree: PrefixSearchTree, len: number}[]>} */
                 const subnodes = new HashTable();
                 for await (const {node, len} of current_layer) {
-                    const tree = await node;
+                    const treeEncoded = await node;
+                    const tree = treeEncoded instanceof InlineNeighborsTree ?
+                        treeEncoded.decode() :
+                        treeEncoded;
                     if (!(tree instanceof PrefixSearchTree)) {
                         continue;
                     }
@@ -2166,9 +2175,12 @@
                         yield leaves;
                     }
                 }
-                /** @type {HashTable<[number, SearchTree][]>} */
+                /** @type {HashTable<[number, PrefixSearchTree|SuffixSearchTree][]>} */
                 const subnodes = new HashTable();
-                for await (const node of current_layer) {
+                for await (const nodeEncoded of current_layer) {
+                    const node = nodeEncoded instanceof InlineNeighborsTree ?
+                        nodeEncoded.decode() :
+                        nodeEncoded;
                     const branches = node.branches;
                     const l = branches.subtrees.length;
                     for (let i = 0; i < l; ++i) {
@@ -2264,6 +2276,174 @@
         }
     }
 
+    /**
+     * Represents a subtree where all transitive leaves
+     * have a shared 16bit prefix and there are no sub-branches.
+     */
+    class InlineNeighborsTree {
+        /**
+         * @param {Uint8Array} encoded
+         * @param {number} start
+         */
+        constructor(
+            encoded,
+            start,
+        ) {
+            this.encoded = encoded;
+            this.start = start;
+        }
+        /**
+         * @return {PrefixSearchTree|SuffixSearchTree}
+         */
+        decode() {
+            let i = this.start;
+            const encoded = this.encoded;
+            const has_branches = (encoded[i] & 0x04) !== 0;
+            /** @type {boolean} */
+            const is_suffixes_only = (encoded[i] & 0x01) !== 0;
+            let leaves_count = ((encoded[i] >> 4) & 0x0f) + 1;
+            i += 1;
+            let branch_count = 0;
+            if (has_branches) {
+                branch_count = encoded[i] + 1;
+                i += 1;
+            }
+            const dlen = encoded[i] & 0x3f;
+            if ((encoded[i] & 0x80) !== 0) {
+                leaves_count = 0;
+            }
+            i += 1;
+            let data = EMPTY_UINT8;
+            if (!is_suffixes_only && dlen !== 0) {
+                data = encoded.subarray(i, i + dlen);
+                i += dlen;
+            }
+            const leaf_value_upper = encoded[i] | (encoded[i + 1] << 8);
+            i += 2;
+            /** @type {Promise<SearchTree>[]} */
+            const branch_nodes = [];
+            for (let j = 0; j < branch_count; j += 1) {
+                const branch_dlen = encoded[i] & 0x0f;
+                const branch_leaves_count = ((encoded[i] >> 4) & 0x0f) + 1;
+                i += 1;
+                let branch_data = EMPTY_UINT8;
+                if (!is_suffixes_only && branch_dlen !== 0) {
+                    branch_data = encoded.subarray(i, i + branch_dlen);
+                    i += branch_dlen;
+                }
+                const branch_leaves = new RoaringBitmap(null);
+                branch_leaves.keysAndCardinalities = Uint8Array.of(
+                    leaf_value_upper & 0xff,
+                    (leaf_value_upper >> 8) & 0xff,
+                    (branch_leaves_count - 1) & 0xff,
+                    ((branch_leaves_count - 1) >> 8) & 0xff,
+                );
+                branch_leaves.containers = [
+                    new RoaringBitmapArray(
+                        branch_leaves_count,
+                        encoded.subarray(i, i + (branch_leaves_count * 2)),
+                    ),
+                ];
+                i += branch_leaves_count * 2;
+                branch_nodes.push(Promise.resolve(
+                    is_suffixes_only ?
+                        new SuffixSearchTree(
+                            EMPTY_SEARCH_TREE_BRANCHES,
+                            branch_dlen,
+                            branch_leaves,
+                        ) :
+                        new PrefixSearchTree(
+                            EMPTY_SEARCH_TREE_BRANCHES,
+                            EMPTY_SEARCH_TREE_BRANCHES,
+                            branch_data,
+                            branch_leaves,
+                            EMPTY_BITMAP,
+                        ),
+                ));
+            }
+            /** @type {SearchTreeBranchesArray<SearchTree>} */
+            const branches = branch_count === 0 ?
+                EMPTY_SEARCH_TREE_BRANCHES :
+                new SearchTreeBranchesArray(
+                    encoded.subarray(i, i + branch_count),
+                    EMPTY_UINT8,
+                );
+            i += branch_count;
+            branches.subtrees = branch_nodes;
+            let leaves = EMPTY_BITMAP;
+            if (leaves_count !== 0) {
+                leaves = new RoaringBitmap(null);
+                leaves.keysAndCardinalities = Uint8Array.of(
+                    leaf_value_upper & 0xff,
+                    (leaf_value_upper >> 8) & 0xff,
+                    (leaves_count - 1) & 0xff,
+                    ((leaves_count - 1) >> 8) & 0xff,
+                );
+                leaves.containers = [
+                    new RoaringBitmapArray(
+                        leaves_count,
+                        encoded.subarray(i, i + (leaves_count * 2)),
+                    ),
+                ];
+                i += leaves_count * 2;
+            }
+            return is_suffixes_only ?
+                new SuffixSearchTree(
+                    branches,
+                    dlen,
+                    leaves,
+                ) :
+                new PrefixSearchTree(
+                    branches,
+                    branches,
+                    data,
+                    leaves,
+                    EMPTY_BITMAP,
+                );
+        }
+
+        /**
+         * Returns the Trie for the root node.
+         *
+         * A Trie pointer refers to a single node in a logical decompressed search tree
+         * (the real search tree is compressed).
+         *
+         * @param {DataColumn} dataColumn
+         * @param {Uint8ArraySearchPattern} searchPattern
+         * @return {Trie}
+         */
+        trie(dataColumn, searchPattern) {
+            const tree = this.decode();
+            return tree instanceof SuffixSearchTree ?
+                new SuffixTrie(tree, 0, dataColumn, searchPattern) :
+                new PrefixTrie(tree, 0, dataColumn, searchPattern);
+        }
+
+        /**
+         * Return the trie representing `name`
+         * @param {Uint8Array|string} name
+         * @param {DataColumn} dataColumn
+         * @returns {Promise<Trie?>}
+         */
+        search(name, dataColumn) {
+            return this.decode().search(name, dataColumn);
+        }
+
+        /**
+         * @param {Uint8Array|string} name
+         * @param {DataColumn} dataColumn
+         * @returns {AsyncGenerator<Trie>}
+         */
+        searchLev(name, dataColumn) {
+            return this.decode().searchLev(name, dataColumn);
+        }
+
+        /** @returns {RoaringBitmap} */
+        getCurrentLeaves() {
+            return this.decode().getCurrentLeaves();
+        }
+    }
+
     class DataColumn {
         /**
          * Construct the wrapper object for a data column.
@@ -2765,21 +2945,37 @@
             // because that's the canonical, hashed version of the data
             let compression_tag = input[i];
             const is_pure_suffixes_only_node = (compression_tag & 0x01) !== 0;
+            const is_long_compressed = (compression_tag & 0x04) !== 0;
+            const is_data_compressed = (compression_tag & 0x08) !== 0;
+            i += 1;
+            if (is_long_compressed) {
+                compression_tag |= input[i] << 8;
+                i += 1;
+            }
+            /** @type {number} */
+            let dlen;
+            /** @type {number} */
             let no_leaves_flag;
-            if (compression_tag > 1) {
-                // compressed node
-                const is_long_compressed = (compression_tag & 0x04) !== 0;
-                const is_data_compressed = (compression_tag & 0x08) !== 0;
-                i += 1;
-                if (is_long_compressed) {
-                    compression_tag |= input[i] << 8;
-                    i += 1;
-                    compression_tag |= input[i] << 16;
-                    i += 1;
-                }
-                let dlen = input[i] & 0x7F;
+            /** @type {number} */
+            let inline_neighbors_flag;
+            if (is_data_compressed && is_pure_suffixes_only_node) {
+                dlen = 0;
+                no_leaves_flag = 0x80;
+                inline_neighbors_flag = 0;
+            } else {
+                dlen = input[i] & 0x3F;
                 no_leaves_flag = input[i] & 0x80;
+                inline_neighbors_flag = input[i] & 0x40;
                 i += 1;
+            }
+            if (inline_neighbors_flag !== 0) {
+                // node with packed leaves and common 16bit prefix
+                const leaves_count = no_leaves_flag !== 0 ?
+                    0 :
+                    ((compression_tag >> 4) & 0x0f) + 1;
+                const branch_count = is_long_compressed ?
+                    ((compression_tag >> 8) & 0xff) + 1 :
+                    0;
                 if (is_data_compressed) {
                     data = data_history[data_history.length - dlen - 1];
                     dlen = data.length;
@@ -2791,6 +2987,72 @@
                         new Uint8Array(input.buffer, i + input.byteOffset, dlen);
                     i += dlen;
                 }
+                const branches_start = i;
+                // leaf_value_upper
+                i += 2;
+                // branch_nodes
+                for (let j = 0; j < branch_count; j += 1) {
+                    const branch_dlen = input[i] & 0x0f;
+                    const branch_leaves_count = ((input[i] >> 4) & 0x0f) + 1;
+                    i += 1;
+                    if (!is_pure_suffixes_only_node) {
+                        i += branch_dlen;
+                    }
+                    i += branch_leaves_count * 2;
+                }
+                // branch keys
+                i += branch_count;
+                // leaves
+                i += leaves_count * 2;
+                if (is_data_compressed) {
+                    const clen = (
+                        1 + // first compression header byte
+                        (is_long_compressed ? 1 : 0) + // branch count
+                        1 + // data length and other flags
+                        dlen + // data
+                        (i - branches_start) // branches and leaves
+                    );
+                    const canonical = new Uint8Array(clen);
+                    let ci = 0;
+                    canonical[ci] = input[start] ^ 0x08;
+                    ci += 1;
+                    if (is_long_compressed) {
+                        canonical[ci] = input[start + ci];
+                        ci += 1;
+                    }
+                    canonical[ci] = dlen | no_leaves_flag | 0x40;
+                    ci += 1;
+                    for (let j = 0; j < dlen; j += 1) {
+                        canonical[ci] = data[j];
+                        ci += 1;
+                    }
+                    for (let j = branches_start; j < i; j += 1) {
+                        canonical[ci] = input[j];
+                        ci += 1;
+                    }
+                    tree = new InlineNeighborsTree(canonical, 0);
+                    siphashOfBytes(canonical, 0, 0, 0, 0, hash);
+                } else {
+                    tree = new InlineNeighborsTree(input, start);
+                    siphashOfBytes(new Uint8Array(
+                        input.buffer,
+                        start + input.byteOffset,
+                        i - start,
+                    ), 0, 0, 0, 0, hash);
+                }
+            } else if (compression_tag > 1) {
+                // compressed node
+                if (is_pure_suffixes_only_node) {
+                    data = EMPTY_UINT8;
+                } else if (is_data_compressed) {
+                    data = data_history[data_history.length - dlen - 1];
+                    dlen = data.length;
+                } else {
+                    data = dlen === 0 ?
+                        EMPTY_UINT8 :
+                        new Uint8Array(input.buffer, i + input.byteOffset, dlen);
+                    i += dlen;
+                }
                 const coffset = i;
                 const {
                     cpbranches,
@@ -2820,19 +3082,27 @@
                         suffix,
                     );
                     const clen = (
-                        3 + // lengths of children and data
+                        // lengths of children and data
+                        (is_data_compressed ? 2 : 3) +
+                        // branches
                         csnodes.length +
                         csbranches.length +
+                        // leaves
                         suffix.consumed_len_bytes
                     );
                     if (canonical.length < clen) {
                         canonical = new Uint8Array(clen);
                     }
                     let ci = 0;
-                    canonical[ci] = 1;
-                    ci += 1;
-                    canonical[ci] = dlen | no_leaves_flag;
-                    ci += 1;
+                    if (is_data_compressed) {
+                        canonical[ci] = 0x09;
+                        ci += 1;
+                    } else {
+                        canonical[ci] = 1;
+                        ci += 1;
+                        canonical[ci] = dlen | no_leaves_flag;
+                        ci += 1;
+                    }
                     canonical[ci] = input[coffset]; // suffix child count
                     ci += 1;
                     canonical.set(csnodes, ci);
@@ -2901,13 +3171,8 @@
                     }
                     siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash);
                 }
-                hash[2] &= 0x7f;
             } else {
-                i += 1;
                 // uncompressed node
-                const dlen = input[i] & 0x7F;
-                no_leaves_flag = input[i] & 0x80;
-                i += 1;
                 if (dlen === 0 || is_pure_suffixes_only_node) {
                     data = EMPTY_UINT8;
                 } else {
@@ -2946,7 +3211,6 @@
                     start + input.byteOffset,
                     i - start,
                 ), 0, 0, 0, 0, hash);
-                hash[2] &= 0x7f;
                 tree = is_pure_suffixes_only_node ?
                     new SuffixSearchTree(
                         branches,
@@ -2961,30 +3225,33 @@
                         suffix,
                     );
             }
+            hash[2] &= 0x7f;
             hash_history.push({hash: truncatedHash.slice(), used: false});
             if (data.length !== 0) {
                 data_history.push(data);
             }
-            const tree_branch_nodeids = tree.branches.nodeids;
-            const tree_branch_subtrees = tree.branches.subtrees;
-            let j = 0;
-            let lb = tree.branches.subtrees.length;
-            while (j < lb) {
-                // node id with a 1 in its most significant bit is inlined, and, so
-                // it won't be in the stash
-                if ((tree_branch_nodeids[j * 6] & 0x80) === 0) {
-                    const subtree = stash.getWithOffsetKey(tree_branch_nodeids, j * 6);
-                    if (subtree !== undefined) {
-                        tree_branch_subtrees[j] = Promise.resolve(subtree);
+            if (!(tree instanceof InlineNeighborsTree)) {
+                const tree_branch_nodeids = tree.branches.nodeids;
+                const tree_branch_subtrees = tree.branches.subtrees;
+                let j = 0;
+                const lb = tree.branches.subtrees.length;
+                while (j < lb) {
+                    // node id with a 1 in its most significant bit is inlined, and, so
+                    // it won't be in the stash
+                    if ((tree_branch_nodeids[j * 6] & 0x80) === 0) {
+                        const subtree = stash.getWithOffsetKey(tree_branch_nodeids, j * 6);
+                        if (subtree !== undefined) {
+                            tree_branch_subtrees[j] = Promise.resolve(subtree);
+                        }
                     }
+                    j += 1;
                 }
-                j += 1;
             }
             if (tree instanceof PrefixSearchTree) {
                 const tree_mhp_branch_nodeids = tree.might_have_prefix_branches.nodeids;
                 const tree_mhp_branch_subtrees = tree.might_have_prefix_branches.subtrees;
-                j = 0;
-                lb = tree.might_have_prefix_branches.subtrees.length;
+                let j = 0;
+                const lb = tree.might_have_prefix_branches.subtrees.length;
                 while (j < lb) {
                     // node id with a 1 in its most significant bit is inlined, and, so
                     // it won't be in the stash
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 155abef..d09949e 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -847,7 +847,7 @@ fn trait_impls_for<'a>(
 
     for &trait_ in tcx.doc_link_traits_in_scope(module) {
         tcx.for_each_relevant_impl(trait_, ty, |impl_| {
-            let trait_ref = tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
+            let trait_ref = tcx.impl_trait_ref(impl_);
             // Check if these are the same type.
             let impl_type = trait_ref.skip_binder().self_ty();
             trace!(
diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml
index c9d350e..c2cc48a 100644
--- a/src/tools/clippy/.github/workflows/remark.yml
+++ b/src/tools/clippy/.github/workflows/remark.yml
@@ -17,9 +17,9 @@
         persist-credentials: false
 
     - name: Setup Node.js
-      uses: actions/setup-node@v4
+      uses: actions/setup-node@v5
       with:
-        node-version: '18.x'
+        node-version: '20.x'
 
     - name: Install remark
       run: npm install remark-cli remark-lint remark-lint-maximum-line-length@^3.1.3 remark-preset-lint-recommended remark-gfm
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 30781d3..37d46d3 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -28,19 +28,19 @@
 
 ### Enhancements
 
-* [`or_fun_call`] now lints `Option::get_or_insert`, `Result::map_or`, `Option/Result::and` methods 
-  [#15071](https://github.com/rust-lang/rust-clippy/pull/15071) 
-  [#15073](https://github.com/rust-lang/rust-clippy/pull/15073) 
+* [`or_fun_call`] now lints `Option::get_or_insert`, `Result::map_or`, `Option/Result::and` methods
+  [#15071](https://github.com/rust-lang/rust-clippy/pull/15071)
+  [#15073](https://github.com/rust-lang/rust-clippy/pull/15073)
   [#15074](https://github.com/rust-lang/rust-clippy/pull/15074)
-* [`incompatible_msrv`] now recognizes types exceeding MSRV 
+* [`incompatible_msrv`] now recognizes types exceeding MSRV
   [#15296](https://github.com/rust-lang/rust-clippy/pull/15296)
-* [`incompatible_msrv`] now checks the right MSRV when in a `const` context 
+* [`incompatible_msrv`] now checks the right MSRV when in a `const` context
   [#15297](https://github.com/rust-lang/rust-clippy/pull/15297)
-* [`zero_ptr`] now lints in `const` context as well 
+* [`zero_ptr`] now lints in `const` context as well
   [#15152](https://github.com/rust-lang/rust-clippy/pull/15152)
 * [`map_identity`],[`flat_map_identity`] now recognizes `|[x, y]| [x, y]` as an identity function
   [#15229](https://github.com/rust-lang/rust-clippy/pull/15229)
-* [`exit`] no longer fails on the main function when using `--test` or `--all-targets` flag 
+* [`exit`] no longer fails on the main function when using `--test` or `--all-targets` flag
   [#15222](https://github.com/rust-lang/rust-clippy/pull/15222)
 
 ### False Positive Fixes
@@ -51,7 +51,7 @@
   [#15319](https://github.com/rust-lang/rust-clippy/pull/15319)
 * [`unused_async`] fixed FP on function with `todo!`
   [#15308](https://github.com/rust-lang/rust-clippy/pull/15308)
-* [`useless_attribute`] fixed FP when using `#[expect(redundant_imports)]` and similar lint attributes 
+* [`useless_attribute`] fixed FP when using `#[expect(redundant_imports)]` and similar lint attributes
   on `use` statements
   [#15318](https://github.com/rust-lang/rust-clippy/pull/15318)
 * [`pattern_type_mismatch`] fixed FP in external macro
@@ -64,7 +64,7 @@
   [#15314](https://github.com/rust-lang/rust-clippy/pull/15314)
 * [`ptr_as_ptr`] fixed wrong suggestions with turbo fish
   [#15289](https://github.com/rust-lang/rust-clippy/pull/15289)
-* [`range_plus_one`], [`range_minus_one`] fixed FP by restricting lint to cases where it is safe 
+* [`range_plus_one`], [`range_minus_one`] fixed FP by restricting lint to cases where it is safe
   to switch the range type
   [#14432](https://github.com/rust-lang/rust-clippy/pull/14432)
 * [`ptr_arg`] fixed FP with underscore binding to `&T` or `&mut T` argument
@@ -129,7 +129,7 @@
   [#15022](https://github.com/rust-lang/rust-clippy/pull/15022)
 * [`collapsible_else_if`] fixed FP on conditionally compiled stmt
   [#14906](https://github.com/rust-lang/rust-clippy/pull/14906)
-* [`missing_const_for_fn`] fixed FP by checking MSRV before emitting lint on function containing 
+* [`missing_const_for_fn`] fixed FP by checking MSRV before emitting lint on function containing
   non-`Sized` trait bounds
   [#15080](https://github.com/rust-lang/rust-clippy/pull/15080)
 * [`question_mark`] fixed FP when else branch of let-else contains `#[cfg]`
@@ -137,7 +137,7 @@
 
 ### ICE Fixes
 
-* [`single_match`] fixed ICE with deref patterns and string literals 
+* [`single_match`] fixed ICE with deref patterns and string literals
   [#15124](https://github.com/rust-lang/rust-clippy/pull/15124)
 * [`needless_doctest_main`] fixed panic when doctest is invalid
   [#15052](https://github.com/rust-lang/rust-clippy/pull/15052)
@@ -146,11 +146,11 @@
 
 ### Documentation Improvements
 
-* [`manual_is_variant_and`] improved documentation to include equality comparison patterns 
+* [`manual_is_variant_and`] improved documentation to include equality comparison patterns
   [#15239](https://github.com/rust-lang/rust-clippy/pull/15239)
 * [`uninlined_format_args`] improved documentation with example of how to fix a `{:?}` parameter
   [#15228](https://github.com/rust-lang/rust-clippy/pull/15228)
-* [`undocumented_unsafe_blocks`] improved documentation wording 
+* [`undocumented_unsafe_blocks`] improved documentation wording
   [#15213](https://github.com/rust-lang/rust-clippy/pull/15213)
 
 ## Rust 1.89
@@ -292,7 +292,7 @@
   [#14408](https://github.com/rust-lang/rust-clippy/pull/14408)
 * [`iter_kv_map`] now recognizes references on maps
   [#14596](https://github.com/rust-lang/rust-clippy/pull/14596)
-* [`empty_enum_variants_with_brackets`] no longer lints reachable enums or enums used 
+* [`empty_enum_variants_with_brackets`] no longer lints reachable enums or enums used
   as functions within same crate [#12971](https://github.com/rust-lang/rust-clippy/pull/12971)
 * [`needless_lifetimes`] now checks for lifetime uses in closures
   [#14608](https://github.com/rust-lang/rust-clippy/pull/14608)
@@ -928,50 +928,50 @@
 
 ### New Lints
 
-- [`infinite_loop`]
+* [`infinite_loop`]
   [#11829](https://github.com/rust-lang/rust-clippy/pull/11829)
-- [`ineffective_open_options`]
+* [`ineffective_open_options`]
   [#11902](https://github.com/rust-lang/rust-clippy/pull/11902)
-- [`uninhabited_references`]
+* [`uninhabited_references`]
   [#11878](https://github.com/rust-lang/rust-clippy/pull/11878)
-- [`repeat_vec_with_capacity`]
+* [`repeat_vec_with_capacity`]
   [#11597](https://github.com/rust-lang/rust-clippy/pull/11597)
-- [`test_attr_in_doctest`]
+* [`test_attr_in_doctest`]
   [#11872](https://github.com/rust-lang/rust-clippy/pull/11872)
-- [`option_map_or_err_ok`]
+* [`option_map_or_err_ok`]
   [#11864](https://github.com/rust-lang/rust-clippy/pull/11864)
-- [`join_absolute_paths`]
+* [`join_absolute_paths`]
   [#11453](https://github.com/rust-lang/rust-clippy/pull/11453)
-- [`impl_hash_borrow_with_str_and_bytes`]
+* [`impl_hash_borrow_with_str_and_bytes`]
   [#11781](https://github.com/rust-lang/rust-clippy/pull/11781)
-- [`iter_over_hash_type`]
+* [`iter_over_hash_type`]
   [#11791](https://github.com/rust-lang/rust-clippy/pull/11791)
 
 ### Moves and Deprecations
 
-- Renamed `blocks_in_if_conditions` to [`blocks_in_conditions`]
+* Renamed `blocks_in_if_conditions` to [`blocks_in_conditions`]
   [#11853](https://github.com/rust-lang/rust-clippy/pull/11853)
-- Moved [`implied_bounds_in_impls`] to `complexity` (Now warn-by-default)
+* Moved [`implied_bounds_in_impls`] to `complexity` (Now warn-by-default)
   [#11867](https://github.com/rust-lang/rust-clippy/pull/11867)
-- Moved [`if_same_then_else`] to `style` (Now warn-by-default)
+* Moved [`if_same_then_else`] to `style` (Now warn-by-default)
   [#11809](https://github.com/rust-lang/rust-clippy/pull/11809)
 
 ### Enhancements
 
-- [`missing_safety_doc`], [`unnecessary_safety_doc`], [`missing_panics_doc`], [`missing_errors_doc`]:
+* [`missing_safety_doc`], [`unnecessary_safety_doc`], [`missing_panics_doc`], [`missing_errors_doc`]:
   Added the [`check-private-items`] configuration to enable lints on private items
   [#11842](https://github.com/rust-lang/rust-clippy/pull/11842)
 
 ### ICE Fixes
 
-- [`impl_trait_in_params`]: No longer crashes when a function has generics but no function parameters
+* [`impl_trait_in_params`]: No longer crashes when a function has generics but no function parameters
   [#11804](https://github.com/rust-lang/rust-clippy/pull/11804)
-- [`unused_enumerate_index`]: No longer crashes on empty tuples
+* [`unused_enumerate_index`]: No longer crashes on empty tuples
   [#11756](https://github.com/rust-lang/rust-clippy/pull/11756)
 
 ### Others
 
-- Clippy now respects the `CARGO` environment value
+* Clippy now respects the `CARGO` environment value
   [#11944](https://github.com/rust-lang/rust-clippy/pull/11944)
 
 ## Rust 1.75
@@ -997,7 +997,6 @@
 * [`manual_hash_one`]
   [#11556](https://github.com/rust-lang/rust-clippy/pull/11556)
 
-
 ### Moves and Deprecations
 
 * Moved [`read_zero_byte_vec`] to `nursery` (Now allow-by-default)
@@ -1073,7 +1072,7 @@
 
 ### Enhancements
 
-* [`undocumented_unsafe_blocks`]: The config values [`accept-comment-above-statement`] and 
+* [`undocumented_unsafe_blocks`]: The config values [`accept-comment-above-statement`] and
   [`accept-comment-above-attributes`] are now `true` by default
   [#11170](https://github.com/rust-lang/rust-clippy/pull/11170)
 * [`explicit_iter_loop`]: Added [`enforce-iter-loop-reborrow`] to disable reborrow linting by default
@@ -2254,7 +2253,6 @@
 * [`explicit_auto_deref`]
   [#8355](https://github.com/rust-lang/rust-clippy/pull/8355)
 
-
 ### Moves and Deprecations
 
 * Moved [`format_push_string`] to `restriction` (now allow-by-default)
@@ -2455,10 +2453,10 @@
 * [`redundant_allocation`]: No longer lints on fat pointers that would become
   thin pointers [#8813](https://github.com/rust-lang/rust-clippy/pull/8813)
 * [`derive_partial_eq_without_eq`]:
-    * Handle differing predicates applied by `#[derive(PartialEq)]` and
+  * Handle differing predicates applied by `#[derive(PartialEq)]` and
       `#[derive(Eq)]`
       [#8869](https://github.com/rust-lang/rust-clippy/pull/8869)
-    * No longer lints on non-public types and better handles generics
+  * No longer lints on non-public types and better handles generics
       [#8950](https://github.com/rust-lang/rust-clippy/pull/8950)
 * [`empty_line_after_outer_attr`]: No longer lints empty lines in inner
   string values [#8892](https://github.com/rust-lang/rust-clippy/pull/8892)
@@ -2952,12 +2950,12 @@
   [#7957](https://github.com/rust-lang/rust-clippy/pull/7957)
 * [`needless_borrow`]
   [#7977](https://github.com/rust-lang/rust-clippy/pull/7977)
-    * Lint when a borrow is auto-dereffed more than once
-    * Lint in the trailing expression of a block for a match arm
+  * Lint when a borrow is auto-dereffed more than once
+  * Lint in the trailing expression of a block for a match arm
 * [`strlen_on_c_strings`]
   [8001](https://github.com/rust-lang/rust-clippy/pull/8001)
-    * Lint when used without a fully-qualified path
-    * Suggest removing the surrounding unsafe block when possible
+  * Lint when used without a fully-qualified path
+  * Suggest removing the surrounding unsafe block when possible
 * [`non_ascii_literal`]: Now also lints on `char`s, not just `string`s
   [#8034](https://github.com/rust-lang/rust-clippy/pull/8034)
 * [`single_char_pattern`]: Now also lints on `split_inclusive`, `split_once`,
@@ -3068,7 +3066,7 @@
   [#7813](https://github.com/rust-lang/rust-clippy/pull/7813)
 * New and improved issue templates
   [#8032](https://github.com/rust-lang/rust-clippy/pull/8032)
-* _Dev:_ Add `cargo dev lint` command, to run your modified Clippy version on a
+* *Dev:* Add `cargo dev lint` command, to run your modified Clippy version on a
   file [#7917](https://github.com/rust-lang/rust-clippy/pull/7917)
 
 ## Rust 1.58
@@ -3278,15 +3276,15 @@
   [#7566](https://github.com/rust-lang/rust-clippy/pull/7566)
 * [`option_if_let_else`]: Multiple fixes
   [#7573](https://github.com/rust-lang/rust-clippy/pull/7573)
-    * `break` and `continue` statements local to the would-be closure are
+  * `break` and `continue` statements local to the would-be closure are
       allowed
-    * Don't lint in const contexts
-    * Don't lint when yield expressions are used
-    * Don't lint when the captures made by the would-be closure conflict with
+  * Don't lint in const contexts
+  * Don't lint when yield expressions are used
+  * Don't lint when the captures made by the would-be closure conflict with
       the other branch
-    * Don't lint when a field of a local is used when the type could be
+  * Don't lint when a field of a local is used when the type could be
       potentially moved from
-    * In some cases, don't lint when scrutinee expression conflicts with the
+  * In some cases, don't lint when scrutinee expression conflicts with the
       captures of the would-be closure
 * [`redundant_allocation`]: No longer lints on `Box<Box<dyn T>>` which replaces
   wide pointers with thin pointers
@@ -3535,124 +3533,124 @@
 
 ### New Lints
 
-- [`ref_binding_to_reference`]
+* [`ref_binding_to_reference`]
   [#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
-- [`needless_bitwise_bool`]
+* [`needless_bitwise_bool`]
   [#7133](https://github.com/rust-lang/rust-clippy/pull/7133)
-- [`unused_async`] [#7225](https://github.com/rust-lang/rust-clippy/pull/7225)
-- [`manual_str_repeat`]
+* [`unused_async`] [#7225](https://github.com/rust-lang/rust-clippy/pull/7225)
+* [`manual_str_repeat`]
   [#7265](https://github.com/rust-lang/rust-clippy/pull/7265)
-- [`suspicious_splitn`]
+* [`suspicious_splitn`]
   [#7292](https://github.com/rust-lang/rust-clippy/pull/7292)
 
 ### Moves and Deprecations
 
-- Deprecate `pub_enum_variant_names` and `wrong_pub_self_convention` in favor of
+* Deprecate `pub_enum_variant_names` and `wrong_pub_self_convention` in favor of
   the new `avoid-breaking-exported-api` config option (see
   [Enhancements](#1-54-enhancements))
   [#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
-- Move [`inconsistent_struct_constructor`] to `pedantic`
+* Move [`inconsistent_struct_constructor`] to `pedantic`
   [#7193](https://github.com/rust-lang/rust-clippy/pull/7193)
-- Move [`needless_borrow`] to `style` (now warn-by-default)
+* Move [`needless_borrow`] to `style` (now warn-by-default)
   [#7254](https://github.com/rust-lang/rust-clippy/pull/7254)
-- Move [`suspicious_operation_groupings`] to `nursery`
+* Move [`suspicious_operation_groupings`] to `nursery`
   [#7266](https://github.com/rust-lang/rust-clippy/pull/7266)
-- Move [`semicolon_if_nothing_returned`] to `pedantic`
+* Move [`semicolon_if_nothing_returned`] to `pedantic`
   [#7268](https://github.com/rust-lang/rust-clippy/pull/7268)
 
 ### Enhancements <a name="1-54-enhancements"></a>
 
-- [`while_let_on_iterator`]: Now also lints in nested loops
+* [`while_let_on_iterator`]: Now also lints in nested loops
   [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
-- [`single_char_pattern`]: Now also lints on `strip_prefix` and `strip_suffix`
+* [`single_char_pattern`]: Now also lints on `strip_prefix` and `strip_suffix`
   [#7156](https://github.com/rust-lang/rust-clippy/pull/7156)
-- [`needless_collect`]: Now also lints on assignments with type annotations
+* [`needless_collect`]: Now also lints on assignments with type annotations
   [#7163](https://github.com/rust-lang/rust-clippy/pull/7163)
-- [`if_then_some_else_none`]: Now works with the MSRV config
+* [`if_then_some_else_none`]: Now works with the MSRV config
   [#7177](https://github.com/rust-lang/rust-clippy/pull/7177)
-- Add `avoid-breaking-exported-api` config option for the lints
+* Add `avoid-breaking-exported-api` config option for the lints
   [`enum_variant_names`], [`large_types_passed_by_value`],
   [`trivially_copy_pass_by_ref`], [`unnecessary_wraps`],
   [`upper_case_acronyms`], and [`wrong_self_convention`]. We recommend to set
   this configuration option to `false` before a major release (1.0/2.0/...) to
   clean up the API [#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
-- [`needless_collect`]: Now lints on even more data structures
+* [`needless_collect`]: Now lints on even more data structures
   [#7188](https://github.com/rust-lang/rust-clippy/pull/7188)
-- [`missing_docs_in_private_items`]: No longer sees `#[<name> = "<value>"]` like
+* [`missing_docs_in_private_items`]: No longer sees `#[<name> = "<value>"]` like
   attributes as sufficient documentation
   [#7281](https://github.com/rust-lang/rust-clippy/pull/7281)
-- [`needless_collect`], [`short_circuit_statement`], [`unnecessary_operation`]:
+* [`needless_collect`], [`short_circuit_statement`], [`unnecessary_operation`]:
   Now work as expected when used with `allow`
   [#7282](https://github.com/rust-lang/rust-clippy/pull/7282)
 
 ### False Positive Fixes
 
-- [`implicit_return`]: Now takes all diverging functions in account to avoid
+* [`implicit_return`]: Now takes all diverging functions in account to avoid
   false positives [#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
-- [`while_let_on_iterator`]: No longer lints when the iterator is a struct field
+* [`while_let_on_iterator`]: No longer lints when the iterator is a struct field
   and the struct is used in the loop
   [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
-- [`multiple_inherent_impl`]: No longer lints with generic arguments
+* [`multiple_inherent_impl`]: No longer lints with generic arguments
   [#7089](https://github.com/rust-lang/rust-clippy/pull/7089)
-- [`comparison_chain`]: No longer lints in a `const` context
+* [`comparison_chain`]: No longer lints in a `const` context
   [#7118](https://github.com/rust-lang/rust-clippy/pull/7118)
-- [`while_immutable_condition`]: Fix false positive where mutation in the loop
+* [`while_immutable_condition`]: Fix false positive where mutation in the loop
   variable wasn't picked up
   [#7144](https://github.com/rust-lang/rust-clippy/pull/7144)
-- [`default_trait_access`]: No longer lints in macros
+* [`default_trait_access`]: No longer lints in macros
   [#7150](https://github.com/rust-lang/rust-clippy/pull/7150)
-- [`needless_question_mark`]: No longer lints when the inner value is implicitly
+* [`needless_question_mark`]: No longer lints when the inner value is implicitly
   dereferenced [#7165](https://github.com/rust-lang/rust-clippy/pull/7165)
-- [`unused_unit`]: No longer lints when multiple macro contexts are involved
+* [`unused_unit`]: No longer lints when multiple macro contexts are involved
   [#7167](https://github.com/rust-lang/rust-clippy/pull/7167)
-- [`eval_order_dependence`]: Fix false positive in async context
+* [`eval_order_dependence`]: Fix false positive in async context
   [#7174](https://github.com/rust-lang/rust-clippy/pull/7174)
-- [`unnecessary_filter_map`]: No longer lints if the `filter_map` changes the
+* [`unnecessary_filter_map`]: No longer lints if the `filter_map` changes the
   type [#7175](https://github.com/rust-lang/rust-clippy/pull/7175)
-- [`wrong_self_convention`]: No longer lints in trait implementations of
+* [`wrong_self_convention`]: No longer lints in trait implementations of
   non-`Copy` types [#7182](https://github.com/rust-lang/rust-clippy/pull/7182)
-- [`suboptimal_flops`]: No longer lints on `powi(2)`
+* [`suboptimal_flops`]: No longer lints on `powi(2)`
   [#7201](https://github.com/rust-lang/rust-clippy/pull/7201)
-- [`wrong_self_convention`]: No longer lints if there is no implicit `self`
+* [`wrong_self_convention`]: No longer lints if there is no implicit `self`
   [#7215](https://github.com/rust-lang/rust-clippy/pull/7215)
-- [`option_if_let_else`]: No longer lints on `else if let` pattern
+* [`option_if_let_else`]: No longer lints on `else if let` pattern
   [#7216](https://github.com/rust-lang/rust-clippy/pull/7216)
-- [`use_self`], [`useless_conversion`]: Fix false positives when generic
+* [`use_self`], [`useless_conversion`]: Fix false positives when generic
   arguments are involved
   [#7223](https://github.com/rust-lang/rust-clippy/pull/7223)
-- [`manual_unwrap_or`]: Fix false positive with deref coercion
+* [`manual_unwrap_or`]: Fix false positive with deref coercion
   [#7233](https://github.com/rust-lang/rust-clippy/pull/7233)
-- [`similar_names`]: No longer lints on `wparam`/`lparam`
+* [`similar_names`]: No longer lints on `wparam`/`lparam`
   [#7255](https://github.com/rust-lang/rust-clippy/pull/7255)
-- [`redundant_closure`]: No longer lints on using the `vec![]` macro in a
+* [`redundant_closure`]: No longer lints on using the `vec![]` macro in a
   closure [#7263](https://github.com/rust-lang/rust-clippy/pull/7263)
 
 ### Suggestion Fixes/Improvements
 
-- [`implicit_return`]
+* [`implicit_return`]
   [#6951](https://github.com/rust-lang/rust-clippy/pull/6951)
-    - Fix suggestion for async functions
-    - Improve suggestion with macros
-    - Suggest to change `break` to `return` when appropriate
-- [`while_let_on_iterator`]: Now suggests `&mut iter` when necessary
+  * Fix suggestion for async functions
+  * Improve suggestion with macros
+  * Suggest to change `break` to `return` when appropriate
+* [`while_let_on_iterator`]: Now suggests `&mut iter` when necessary
   [#6966](https://github.com/rust-lang/rust-clippy/pull/6966)
-- [`match_single_binding`]: Improve suggestion when match scrutinee has side
+* [`match_single_binding`]: Improve suggestion when match scrutinee has side
   effects [#7095](https://github.com/rust-lang/rust-clippy/pull/7095)
-- [`needless_borrow`]: Now suggests to also change usage sites as needed
+* [`needless_borrow`]: Now suggests to also change usage sites as needed
   [#7105](https://github.com/rust-lang/rust-clippy/pull/7105)
-- [`write_with_newline`]: Improve suggestion when only `\n` is written to the
+* [`write_with_newline`]: Improve suggestion when only `\n` is written to the
   buffer [#7183](https://github.com/rust-lang/rust-clippy/pull/7183)
-- [`from_iter_instead_of_collect`]: The suggestion is now auto applicable also
+* [`from_iter_instead_of_collect`]: The suggestion is now auto applicable also
   when a `<_ as Trait>::_` is involved
   [#7264](https://github.com/rust-lang/rust-clippy/pull/7264)
-- [`not_unsafe_ptr_arg_deref`]: Improved error message
+* [`not_unsafe_ptr_arg_deref`]: Improved error message
   [#7294](https://github.com/rust-lang/rust-clippy/pull/7294)
 
 ### ICE Fixes
 
-- Fix ICE when running Clippy on `libstd`
+* Fix ICE when running Clippy on `libstd`
   [#7140](https://github.com/rust-lang/rust-clippy/pull/7140)
-- [`implicit_return`]
+* [`implicit_return`]
   [#7242](https://github.com/rust-lang/rust-clippy/pull/7242)
 
 ## Rust 1.53
@@ -3697,9 +3695,9 @@
   [#6828](https://github.com/rust-lang/rust-clippy/pull/6828)
 * [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]:
   [#6863](https://github.com/rust-lang/rust-clippy/pull/6863)
-    * Attempt to find a common path prefix in suggestion
-    * Don't lint on `Option` and `Result`
-    * Consider `Self` prefix
+  * Attempt to find a common path prefix in suggestion
+  * Don't lint on `Option` and `Result`
+  * Consider `Self` prefix
 * [`explicit_deref_methods`]: Also lint on chained `deref` calls
   [#6865](https://github.com/rust-lang/rust-clippy/pull/6865)
 * [`or_fun_call`]: Also lint on `unsafe` blocks
@@ -3959,6 +3957,7 @@
   [#6782](https://github.com/rust-lang/rust-clippy/pull/6782)
 
 ### Others
+
 * Running `cargo clippy` after `cargo check` now works as expected
   (`cargo clippy` and `cargo check` no longer shares the same build cache)
   [#6687](https://github.com/rust-lang/rust-clippy/pull/6687)
@@ -4174,7 +4173,6 @@
 * [`field_reassign_with_default`] No longer lint for private fields
   [#6537](https://github.com/rust-lang/rust-clippy/pull/6537)
 
-
 ### Suggestion Fixes/Improvements
 
 * [`vec_box`]: Provide correct type scope suggestion
@@ -4319,8 +4317,8 @@
 ### Documentation Improvements
 
 * Some doc improvements:
-    * [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090)
-    * [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
+  * [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090)
+  * [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162)
 * [`doc_markdown`]: Document problematic link text style
   [#6107](https://github.com/rust-lang/rust-clippy/pull/6107)
 
@@ -4703,7 +4701,6 @@
 * [`fn_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 * [`vtable_address_comparisons`] [#5294](https://github.com/rust-lang/rust-clippy/pull/5294)
 
-
 ### Moves and Deprecations
 
 * Deprecate [`replace_consts`] lint [#5380](https://github.com/rust-lang/rust-clippy/pull/5380)
@@ -4718,7 +4715,7 @@
 
 ### Enhancements
 
-* On _nightly_ you can now use `cargo clippy --fix -Z unstable-options` to
+* On *nightly* you can now use `cargo clippy --fix -Z unstable-options` to
   auto-fix lints that support this [#5363](https://github.com/rust-lang/rust-clippy/pull/5363)
 * Make [`redundant_clone`] also trigger on cases where the cloned value is not
   consumed. [#5304](https://github.com/rust-lang/rust-clippy/pull/5304)
@@ -4745,7 +4742,6 @@
 * [`redundant_pattern`] [#5287](https://github.com/rust-lang/rust-clippy/pull/5287)
 * [`inconsistent_digit_grouping`] [#5451](https://github.com/rust-lang/rust-clippy/pull/5451)
 
-
 ### Suggestion Improvements
 
 * Improved [`question_mark`] lint suggestion so that it doesn't add redundant `as_ref()` [#5481](https://github.com/rust-lang/rust-clippy/pull/5481)
@@ -4823,7 +4819,6 @@
 
 * Clippy now completely runs on GitHub Actions [#5190](https://github.com/rust-lang/rust-clippy/pull/5190)
 
-
 ## Rust 1.42
 
 Released 2020-03-12
@@ -4890,7 +4885,6 @@
 
 * Improve documentation of [`empty_enum`], [`replace_consts`], [`redundant_clone`], and [`iterator_step_by_zero`]
 
-
 ## Rust 1.41
 
 Released 2020-01-30
@@ -5106,7 +5100,6 @@
 * Fix ICE in [`suspicious_else_formatting`] [#3960](https://github.com/rust-lang/rust-clippy/pull/3960)
 * Fix ICE in [`decimal_literal_representation`] [#3931](https://github.com/rust-lang/rust-clippy/pull/3931)
 
-
 ## Rust 1.35
 
 Released 2019-05-20
@@ -5129,7 +5122,7 @@
 * Fix false positive in [`needless_continue`] pertaining to loop labels
 * Fix false positive for [`boxed_local`] pertaining to arguments moved into closures
 * Fix false positive for [`use_self`] in nested functions
-* Fix suggestion for [`expect_fun_call`] (https://github.com/rust-lang/rust-clippy/pull/3846)
+* Fix suggestion for [`expect_fun_call`] (<https://github.com/rust-lang/rust-clippy/pull/3846>)
 * Fix suggestion for [`explicit_counter_loop`] to deal with parenthesizing range variables
 * Fix suggestion for [`single_char_pattern`] to correctly escape single quotes
 * Avoid triggering [`redundant_closure`] in macros
@@ -5273,6 +5266,7 @@
 Released 2018-10-25
 
 [View all 88 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2018-08-02T16%3A54%3A12Z..2018-09-17T09%3A44%3A06Z+base%3Amaster)
+
 * Deprecate `assign_ops` lint
 * New lints: [`mistyped_literal_suffixes`], [`ptr_offset_with_cast`],
   [`needless_collect`], [`copy_iterator`]
@@ -5322,255 +5316,326 @@
 * Improve website header
 
 ## 0.0.212 (2018-07-10)
+
 * Rustup to *rustc 1.29.0-nightly (e06c87544 2018-07-06)*
 
 ## 0.0.211
+
 * Rustup to *rustc 1.28.0-nightly (e3bf634e0 2018-06-28)*
 
 ## 0.0.210
+
 * Rustup to *rustc 1.28.0-nightly (01cc982e9 2018-06-24)*
 
 ## 0.0.209
+
 * Rustup to *rustc 1.28.0-nightly (523097979 2018-06-18)*
 
 ## 0.0.208
+
 * Rustup to *rustc 1.28.0-nightly (86a8f1a63 2018-06-17)*
 
 ## 0.0.207
+
 * Rustup to *rustc 1.28.0-nightly (2a0062974 2018-06-09)*
 
 ## 0.0.206
+
 * Rustup to *rustc 1.28.0-nightly (5bf68db6e 2018-05-28)*
 
 ## 0.0.205
+
 * Rustup to *rustc 1.28.0-nightly (990d8aa74 2018-05-25)*
 * Rename `unused_lifetimes` to `extra_unused_lifetimes` because of naming conflict with new rustc lint
 
 ## 0.0.204
+
 * Rustup to *rustc 1.28.0-nightly (71e87be38 2018-05-22)*
 
 ## 0.0.203
+
 * Rustup to *rustc 1.28.0-nightly (a3085756e 2018-05-19)*
 * Clippy attributes are now of the form `clippy::cyclomatic_complexity` instead of `clippy(cyclomatic_complexity)`
 
 ## 0.0.202
+
 * Rustup to *rustc 1.28.0-nightly (952f344cd 2018-05-18)*
 
 ## 0.0.201
+
 * Rustup to *rustc 1.27.0-nightly (2f2a11dfc 2018-05-16)*
 
 ## 0.0.200
+
 * Rustup to *rustc 1.27.0-nightly (9fae15374 2018-05-13)*
 
 ## 0.0.199
+
 * Rustup to *rustc 1.27.0-nightly (ff2ac35db 2018-05-12)*
 
 ## 0.0.198
+
 * Rustup to *rustc 1.27.0-nightly (acd3871ba 2018-05-10)*
 
 ## 0.0.197
+
 * Rustup to *rustc 1.27.0-nightly (428ea5f6b 2018-05-06)*
 
 ## 0.0.196
+
 * Rustup to *rustc 1.27.0-nightly (e82261dfb 2018-05-03)*
 
 ## 0.0.195
+
 * Rustup to *rustc 1.27.0-nightly (ac3c2288f 2018-04-18)*
 
 ## 0.0.194
+
 * Rustup to *rustc 1.27.0-nightly (bd40cbbe1 2018-04-14)*
 * New lints: [`cast_ptr_alignment`], [`transmute_ptr_to_ptr`], [`write_literal`], [`write_with_newline`], [`writeln_empty_string`]
 
 ## 0.0.193
+
 * Rustup to *rustc 1.27.0-nightly (eeea94c11 2018-04-06)*
 
 ## 0.0.192
+
 * Rustup to *rustc 1.27.0-nightly (fb44b4c0e 2018-04-04)*
 * New lint: [`print_literal`]
 
 ## 0.0.191
+
 * Rustup to *rustc 1.26.0-nightly (ae544ee1c 2018-03-29)*
 * Lint audit; categorize lints as style, correctness, complexity, pedantic, nursery, restriction.
 
 ## 0.0.190
+
 * Fix a bunch of intermittent cargo bugs
 
 ## 0.0.189
+
 * Rustup to *rustc 1.26.0-nightly (5508b2714 2018-03-18)*
 
 ## 0.0.188
+
 * Rustup to *rustc 1.26.0-nightly (392645394 2018-03-15)*
 * New lint: [`while_immutable_condition`]
 
 ## 0.0.187
+
 * Rustup to *rustc 1.26.0-nightly (322d7f7b9 2018-02-25)*
 * New lints: [`redundant_field_names`], [`suspicious_arithmetic_impl`], [`suspicious_op_assign_impl`]
 
 ## 0.0.186
+
 * Rustup to *rustc 1.25.0-nightly (0c6091fbd 2018-02-04)*
 * Various false positive fixes
 
 ## 0.0.185
+
 * Rustup to *rustc 1.25.0-nightly (56733bc9f 2018-02-01)*
 * New lint: [`question_mark`]
 
 ## 0.0.184
+
 * Rustup to *rustc 1.25.0-nightly (90eb44a58 2018-01-29)*
 * New lints: [`double_comparisons`], [`empty_line_after_outer_attr`]
 
 ## 0.0.183
+
 * Rustup to *rustc 1.25.0-nightly (21882aad7 2018-01-28)*
 * New lint: [`misaligned_transmute`]
 
 ## 0.0.182
+
 * Rustup to *rustc 1.25.0-nightly (a0dcecff9 2018-01-24)*
 * New lint: [`decimal_literal_representation`]
 
 ## 0.0.181
+
 * Rustup to *rustc 1.25.0-nightly (97520ccb1 2018-01-21)*
 * New lints: [`else_if_without_else`], [`option_option`], [`unit_arg`], [`unnecessary_fold`]
 * Removed `unit_expr`
 * Various false positive fixes for [`needless_pass_by_value`]
 
 ## 0.0.180
+
 * Rustup to *rustc 1.25.0-nightly (3f92e8d89 2018-01-14)*
 
 ## 0.0.179
+
 * Rustup to *rustc 1.25.0-nightly (61452e506 2018-01-09)*
 
 ## 0.0.178
+
 * Rustup to *rustc 1.25.0-nightly (ee220daca 2018-01-07)*
 
 ## 0.0.177
+
 * Rustup to *rustc 1.24.0-nightly (250b49205 2017-12-21)*
 * New lint: [`match_as_ref`]
 
 ## 0.0.176
+
 * Rustup to *rustc 1.24.0-nightly (0077d128d 2017-12-14)*
 
 ## 0.0.175
+
 * Rustup to *rustc 1.24.0-nightly (bb42071f6 2017-12-01)*
 
 ## 0.0.174
+
 * Rustup to *rustc 1.23.0-nightly (63739ab7b 2017-11-21)*
 
 ## 0.0.173
+
 * Rustup to *rustc 1.23.0-nightly (33374fa9d 2017-11-20)*
 
 ## 0.0.172
+
 * Rustup to *rustc 1.23.0-nightly (d0f8e2913 2017-11-16)*
 
 ## 0.0.171
+
 * Rustup to *rustc 1.23.0-nightly (ff0f5de3b 2017-11-14)*
 
 ## 0.0.170
+
 * Rustup to *rustc 1.23.0-nightly (d6b06c63a 2017-11-09)*
 
 ## 0.0.169
+
 * Rustup to *rustc 1.23.0-nightly (3b82e4c74 2017-11-05)*
 * New lints: [`just_underscores_and_digits`], `result_map_unwrap_or_else`, [`transmute_bytes_to_str`]
 
 ## 0.0.168
+
 * Rustup to *rustc 1.23.0-nightly (f0fe716db 2017-10-30)*
 
 ## 0.0.167
+
 * Rustup to *rustc 1.23.0-nightly (90ef3372e 2017-10-29)*
 * New lints: `const_static_lifetime`, [`erasing_op`], [`fallible_impl_from`], [`println_empty_string`], [`useless_asref`]
 
 ## 0.0.166
+
 * Rustup to *rustc 1.22.0-nightly (b7960878b 2017-10-18)*
 * New lints: [`explicit_write`], `identity_conversion`, [`implicit_hasher`], `invalid_ref`, [`option_map_or_none`],
   [`range_minus_one`], [`range_plus_one`], [`transmute_int_to_bool`], [`transmute_int_to_char`],
   [`transmute_int_to_float`]
 
 ## 0.0.165
+
 * Rust upgrade to rustc 1.22.0-nightly (0e6f4cf51 2017-09-27)
 * New lint: [`mut_range_bound`]
 
 ## 0.0.164
+
 * Update to *rustc 1.22.0-nightly (6c476ce46 2017-09-25)*
 * New lint: [`int_plus_one`]
 
 ## 0.0.163
+
 * Update to *rustc 1.22.0-nightly (14039a42a 2017-09-22)*
 
 ## 0.0.162
+
 * Update to *rustc 1.22.0-nightly (0701b37d9 2017-09-18)*
 * New lint: [`chars_last_cmp`]
 * Improved suggestions for [`needless_borrow`], [`ptr_arg`],
 
 ## 0.0.161
+
 * Update to *rustc 1.22.0-nightly (539f2083d 2017-09-13)*
 
 ## 0.0.160
+
 * Update to *rustc 1.22.0-nightly (dd08c3070 2017-09-12)*
 
 ## 0.0.159
+
 * Update to *rustc 1.22.0-nightly (eba374fb2 2017-09-11)*
 * New lint: [`clone_on_ref_ptr`]
 
 ## 0.0.158
+
 * New lint: [`manual_memcpy`]
 * [`cast_lossless`] no longer has redundant parentheses in its suggestions
 * Update to *rustc 1.22.0-nightly (dead08cb3 2017-09-08)*
 
 ## 0.0.157 - 2017-09-04
+
 * Update to *rustc 1.22.0-nightly (981ce7d8d 2017-09-03)*
 * New lint: `unit_expr`
 
 ## 0.0.156 - 2017-09-03
+
 * Update to *rustc 1.22.0-nightly (744dd6c1d 2017-09-02)*
 
 ## 0.0.155
+
 * Update to *rustc 1.21.0-nightly (c11f689d2 2017-08-29)*
 * New lint: [`infinite_iter`], [`maybe_infinite_iter`], [`cast_lossless`]
 
 ## 0.0.154
+
 * Update to *rustc 1.21.0-nightly (2c0558f63 2017-08-24)*
 * Fix [`use_self`] triggering inside derives
 * Add support for linting an entire workspace with `cargo clippy --all`
 * New lint: [`naive_bytecount`]
 
 ## 0.0.153
+
 * Update to *rustc 1.21.0-nightly (8c303ed87 2017-08-20)*
 * New lint: [`use_self`]
 
 ## 0.0.152
+
 * Update to *rustc 1.21.0-nightly (df511d554 2017-08-14)*
 
 ## 0.0.151
+
 * Update to *rustc 1.21.0-nightly (13d94d5fa 2017-08-10)*
 
 ## 0.0.150
+
 * Update to *rustc 1.21.0-nightly (215e0b10e 2017-08-08)*
 
 ## 0.0.148
+
 * Update to *rustc 1.21.0-nightly (37c7d0ebb 2017-07-31)*
 * New lints: [`unreadable_literal`], [`inconsistent_digit_grouping`], [`large_digit_groups`]
 
 ## 0.0.147
+
 * Update to *rustc 1.21.0-nightly (aac223f4f 2017-07-30)*
 
 ## 0.0.146
+
 * Update to *rustc 1.21.0-nightly (52a330969 2017-07-27)*
 * Fixes false positives in `inline_always`
 * Fixes false negatives in `panic_params`
 
 ## 0.0.145
+
 * Update to *rustc 1.20.0-nightly (afe145d22 2017-07-23)*
 
 ## 0.0.144
+
 * Update to *rustc 1.20.0-nightly (086eaa78e 2017-07-15)*
 
 ## 0.0.143
+
 * Update to *rustc 1.20.0-nightly (d84693b93 2017-07-09)*
 * Fix `cargo clippy` crashing on `dylib` projects
 * Fix false positives around `nested_while_let` and `never_loop`
 
 ## 0.0.142
+
 * Update to *rustc 1.20.0-nightly (067971139 2017-07-02)*
 
 ## 0.0.141
+
 * Rewrite of the `doc_markdown` lint.
 * Deprecated [`range_step_by_zero`]
 * New lint: [`iterator_step_by_zero`]
@@ -5578,151 +5643,195 @@
 * Update to *rustc 1.20.0-nightly (69c65d296 2017-06-28)*
 
 ## 0.0.140 - 2017-06-16
+
 * Update to *rustc 1.19.0-nightly (258ae6dd9 2017-06-15)*
 
 ## 0.0.139 — 2017-06-10
+
 * Update to *rustc 1.19.0-nightly (4bf5c99af 2017-06-10)*
 * Fix bugs with for loop desugaring
 * Check for [`AsRef`]/[`AsMut`] arguments in [`wrong_self_convention`]
 
 ## 0.0.138 — 2017-06-05
+
 * Update to *rustc 1.19.0-nightly (0418fa9d3 2017-06-04)*
 
 ## 0.0.137 — 2017-06-05
+
 * Update to *rustc 1.19.0-nightly (6684d176c 2017-06-03)*
 
 ## 0.0.136 — 2017—05—26
+
 * Update to *rustc 1.19.0-nightly (557967766 2017-05-26)*
 
 ## 0.0.135 — 2017—05—24
+
 * Update to *rustc 1.19.0-nightly (5b13bff52 2017-05-23)*
 
 ## 0.0.134 — 2017—05—19
+
 * Update to *rustc 1.19.0-nightly (0ed1ec9f9 2017-05-18)*
 
 ## 0.0.133 — 2017—05—14
+
 * Update to *rustc 1.19.0-nightly (826d8f385 2017-05-13)*
 
 ## 0.0.132 — 2017—05—05
+
 * Fix various bugs and some ices
 
 ## 0.0.131 — 2017—05—04
+
 * Update to *rustc 1.19.0-nightly (2d4ed8e0c 2017-05-03)*
 
 ## 0.0.130 — 2017—05—03
+
 * Update to *rustc 1.19.0-nightly (6a5fc9eec 2017-05-02)*
 
 ## 0.0.129 — 2017-05-01
+
 * Update to *rustc 1.19.0-nightly (06fb4d256 2017-04-30)*
 
 ## 0.0.128 — 2017-04-28
+
 * Update to *rustc 1.18.0-nightly (94e884b63 2017-04-27)*
 
 ## 0.0.127 — 2017-04-27
+
 * Update to *rustc 1.18.0-nightly (036983201 2017-04-26)*
 * New lint: [`needless_continue`]
 
 ## 0.0.126 — 2017-04-24
+
 * Update to *rustc 1.18.0-nightly (2bd4b5c6d 2017-04-23)*
 
 ## 0.0.125 — 2017-04-19
+
 * Update to *rustc 1.18.0-nightly (9f2abadca 2017-04-18)*
 
 ## 0.0.124 — 2017-04-16
+
 * Update to *rustc 1.18.0-nightly (d5cf1cb64 2017-04-15)*
 
 ## 0.0.123 — 2017-04-07
+
 * Fix various false positives
 
 ## 0.0.122 — 2017-04-07
+
 * Rustup to *rustc 1.18.0-nightly (91ae22a01 2017-04-05)*
 * New lint: [`op_ref`]
 
 ## 0.0.121 — 2017-03-21
+
 * Rustup to *rustc 1.17.0-nightly (134c4a0f0 2017-03-20)*
 
 ## 0.0.120 — 2017-03-17
+
 * Rustup to *rustc 1.17.0-nightly (0aeb9c129 2017-03-15)*
 
 ## 0.0.119 — 2017-03-13
+
 * Rustup to *rustc 1.17.0-nightly (824c9ebbd 2017-03-12)*
 
 ## 0.0.118 — 2017-03-05
+
 * Rustup to *rustc 1.17.0-nightly (b1e31766d 2017-03-03)*
 
 ## 0.0.117 — 2017-03-01
+
 * Rustup to *rustc 1.17.0-nightly (be760566c 2017-02-28)*
 
 ## 0.0.116 — 2017-02-28
+
 * Fix `cargo clippy` on 64 bit windows systems
 
 ## 0.0.115 — 2017-02-27
+
 * Rustup to *rustc 1.17.0-nightly (60a0edc6c 2017-02-26)*
 * New lints: [`zero_ptr`], [`never_loop`], [`mut_from_ref`]
 
 ## 0.0.114 — 2017-02-08
+
 * Rustup to *rustc 1.17.0-nightly (c49d10207 2017-02-07)*
 * Tests are now ui tests (testing the exact output of rustc)
 
 ## 0.0.113 — 2017-02-04
+
 * Rustup to *rustc 1.16.0-nightly (eedaa94e3 2017-02-02)*
 * New lint: [`large_enum_variant`]
 * `explicit_into_iter_loop` provides suggestions
 
 ## 0.0.112 — 2017-01-27
+
 * Rustup to *rustc 1.16.0-nightly (df8debf6d 2017-01-25)*
 
 ## 0.0.111 — 2017-01-21
+
 * Rustup to *rustc 1.16.0-nightly (a52da95ce 2017-01-20)*
 
 ## 0.0.110 — 2017-01-20
+
 * Add badges and categories to `Cargo.toml`
 
 ## 0.0.109 — 2017-01-19
+
 * Update to *rustc 1.16.0-nightly (c07a6ae77 2017-01-17)*
 
 ## 0.0.108 — 2017-01-12
+
 * Update to *rustc 1.16.0-nightly (2782e8f8f 2017-01-12)*
 
 ## 0.0.107 — 2017-01-11
+
 * Update regex dependency
 * Fix FP when matching `&&mut` by `&ref`
 * Reintroduce `for (_, x) in &mut hash_map` -> `for x in hash_map.values_mut()`
 * New lints: [`unused_io_amount`], [`forget_ref`], [`short_circuit_statement`]
 
 ## 0.0.106 — 2017-01-04
+
 * Fix FP introduced by rustup in [`wrong_self_convention`]
 
 ## 0.0.105 — 2017-01-04
+
 * Update to *rustc 1.16.0-nightly (468227129 2017-01-03)*
 * New lints: [`deref_addrof`], [`double_parens`], [`pub_enum_variant_names`]
 * Fix suggestion in [`new_without_default`]
 * FP fix in [`absurd_extreme_comparisons`]
 
 ## 0.0.104 — 2016-12-15
+
 * Update to *rustc 1.15.0-nightly (8f02c429a 2016-12-15)*
 
 ## 0.0.103 — 2016-11-25
+
 * Update to *rustc 1.15.0-nightly (d5814b03e 2016-11-23)*
 
 ## 0.0.102 — 2016-11-24
+
 * Update to *rustc 1.15.0-nightly (3bf2be9ce 2016-11-22)*
 
 ## 0.0.101 — 2016-11-23
+
 * Update to *rustc 1.15.0-nightly (7b3eeea22 2016-11-21)*
 * New lint: [`string_extend_chars`]
 
 ## 0.0.100 — 2016-11-20
+
 * Update to *rustc 1.15.0-nightly (ac635aa95 2016-11-18)*
 
 ## 0.0.99 — 2016-11-18
+
 * Update to rustc 1.15.0-nightly (0ed951993 2016-11-14)
 * New lint: [`get_unwrap`]
 
 ## 0.0.98 — 2016-11-08
+
 * Fixes an issue due to a change in how cargo handles `--sysroot`, which broke `cargo clippy`
 
 ## 0.0.97 — 2016-11-03
+
 * For convenience, `cargo clippy` defines a `cargo-clippy` feature. This was
   previously added for a short time under the name `clippy` but removed for
   compatibility.
@@ -5731,34 +5840,43 @@
 * New lints: [`if_let_redundant_pattern_matching`], [`partialeq_ne_impl`]
 
 ## 0.0.96 — 2016-10-22
+
 * Rustup to *rustc 1.14.0-nightly (f09420685 2016-10-20)*
 * New lint: [`iter_skip_next`]
 
 ## 0.0.95 — 2016-10-06
+
 * Rustup to *rustc 1.14.0-nightly (3210fd5c2 2016-10-05)*
 
 ## 0.0.94 — 2016-10-04
+
 * Fixes bustage on Windows due to forbidden directory name
 
 ## 0.0.93 — 2016-10-03
+
 * Rustup to *rustc 1.14.0-nightly (144af3e97 2016-10-02)*
 * `option_map_unwrap_or` and `option_map_unwrap_or_else` are now
   allowed by default.
 * New lint: [`explicit_into_iter_loop`]
 
 ## 0.0.92 — 2016-09-30
+
 * Rustup to *rustc 1.14.0-nightly (289f3a4ca 2016-09-29)*
 
 ## 0.0.91 — 2016-09-28
+
 * Rustup to *rustc 1.13.0-nightly (d0623cf7b 2016-09-26)*
 
 ## 0.0.90 — 2016-09-09
+
 * Rustup to *rustc 1.13.0-nightly (f1f40f850 2016-09-09)*
 
 ## 0.0.89 — 2016-09-06
+
 * Rustup to *rustc 1.13.0-nightly (cbe4de78e 2016-09-05)*
 
 ## 0.0.88 — 2016-09-04
+
 * Rustup to *rustc 1.13.0-nightly (70598e04f 2016-09-03)*
 * The following lints are not new but were only usable through the `clippy`
   lint groups: [`filter_next`], `for_loop_over_option`,
@@ -5767,30 +5885,37 @@
   through `cargo clippy`.
 
 ## 0.0.87 — 2016-08-31
+
 * Rustup to *rustc 1.13.0-nightly (eac41469d 2016-08-30)*
 * New lints: [`builtin_type_shadow`]
 * Fix FP in [`zero_prefixed_literal`] and `0b`/`0o`
 
 ## 0.0.86 — 2016-08-28
+
 * Rustup to *rustc 1.13.0-nightly (a23064af5 2016-08-27)*
 * New lints: [`missing_docs_in_private_items`], [`zero_prefixed_literal`]
 
 ## 0.0.85 — 2016-08-19
+
 * Fix ICE with [`useless_attribute`]
 * [`useless_attribute`] ignores `unused_imports` on `use` statements
 
 ## 0.0.84 — 2016-08-18
+
 * Rustup to *rustc 1.13.0-nightly (aef6971ca 2016-08-17)*
 
 ## 0.0.83 — 2016-08-17
+
 * Rustup to *rustc 1.12.0-nightly (1bf5fa326 2016-08-16)*
 * New lints: [`print_with_newline`], [`useless_attribute`]
 
 ## 0.0.82 — 2016-08-17
+
 * Rustup to *rustc 1.12.0-nightly (197be89f3 2016-08-15)*
 * New lint: [`module_inception`]
 
 ## 0.0.81 — 2016-08-14
+
 * Rustup to *rustc 1.12.0-nightly (1deb02ea6 2016-08-12)*
 * New lints: [`eval_order_dependence`], [`mixed_case_hex_literals`], [`unseparated_literal_suffix`]
 * False positive fix in [`too_many_arguments`]
@@ -5800,14 +5925,17 @@
 * Doc improvements
 
 ## 0.0.80 — 2016-07-31
+
 * Rustup to *rustc 1.12.0-nightly (1225e122f 2016-07-30)*
 * New lints: [`misrefactored_assign_op`], [`serde_api_misuse`]
 
 ## 0.0.79 — 2016-07-10
+
 * Rustup to *rustc 1.12.0-nightly (f93aaf84c 2016-07-09)*
 * Major suggestions refactoring
 
 ## 0.0.78 — 2016-07-02
+
 * Rustup to *rustc 1.11.0-nightly (01411937f 2016-07-01)*
 * New lints: [`wrong_transmute`], [`double_neg`], [`filter_map`]
 * For compatibility, `cargo clippy` does not defines the `clippy` feature
@@ -5815,118 +5943,148 @@
 * [`collapsible_if`] now considers `if let`
 
 ## 0.0.77 — 2016-06-21
+
 * Rustup to *rustc 1.11.0-nightly (5522e678b 2016-06-20)*
 * New lints: `stutter` and [`iter_nth`]
 
 ## 0.0.76 — 2016-06-10
+
 * Rustup to *rustc 1.11.0-nightly (7d2f75a95 2016-06-09)*
 * `cargo clippy` now automatically defines the `clippy` feature
 * New lint: [`not_unsafe_ptr_arg_deref`]
 
 ## 0.0.75 — 2016-06-08
+
 * Rustup to *rustc 1.11.0-nightly (763f9234b 2016-06-06)*
 
 ## 0.0.74 — 2016-06-07
+
 * Fix bug with `cargo-clippy` JSON parsing
 * Add the `CLIPPY_DISABLE_DOCS_LINKS` environment variable to deactivate the
   “for further information visit *lint-link*” message.
 
 ## 0.0.73 — 2016-06-05
+
 * Fix false positives in [`useless_let_if_seq`]
 
 ## 0.0.72 — 2016-06-04
+
 * Fix false positives in [`useless_let_if_seq`]
 
 ## 0.0.71 — 2016-05-31
+
 * Rustup to *rustc 1.11.0-nightly (a967611d8 2016-05-30)*
 * New lint: [`useless_let_if_seq`]
 
 ## 0.0.70 — 2016-05-28
+
 * Rustup to *rustc 1.10.0-nightly (7bddce693 2016-05-27)*
 * [`invalid_regex`] and [`trivial_regex`] can now warn on `RegexSet::new`,
   `RegexBuilder::new` and byte regexes
 
 ## 0.0.69 — 2016-05-20
+
 * Rustup to *rustc 1.10.0-nightly (476fe6eef 2016-05-21)*
 * [`used_underscore_binding`] has been made `Allow` temporarily
 
 ## 0.0.68 — 2016-05-17
+
 * Rustup to *rustc 1.10.0-nightly (cd6a40017 2016-05-16)*
 * New lint: [`unnecessary_operation`]
 
 ## 0.0.67 — 2016-05-12
+
 * Rustup to *rustc 1.10.0-nightly (22ac88f1a 2016-05-11)*
 
 ## 0.0.66 — 2016-05-11
+
 * New `cargo clippy` subcommand
 * New lints: [`assign_op_pattern`], [`assign_ops`], [`needless_borrow`]
 
 ## 0.0.65 — 2016-05-08
+
 * Rustup to *rustc 1.10.0-nightly (62e2b2fb7 2016-05-06)*
 * New lints: [`float_arithmetic`], [`integer_arithmetic`]
 
 ## 0.0.64 — 2016-04-26
+
 * Rustup to *rustc 1.10.0-nightly (645dd013a 2016-04-24)*
 * New lints: `temporary_cstring_as_ptr`, [`unsafe_removed_from_name`], and [`mem_forget`]
 
 ## 0.0.63 — 2016-04-08
+
 * Rustup to *rustc 1.9.0-nightly (7979dd608 2016-04-07)*
 
 ## 0.0.62 — 2016-04-07
+
 * Rustup to *rustc 1.9.0-nightly (bf5da36f1 2016-04-06)*
 
 ## 0.0.61 — 2016-04-03
+
 * Rustup to *rustc 1.9.0-nightly (5ab11d72c 2016-04-02)*
 * New lint: [`invalid_upcast_comparisons`]
 
 ## 0.0.60 — 2016-04-01
+
 * Rustup to *rustc 1.9.0-nightly (e1195c24b 2016-03-31)*
 
 ## 0.0.59 — 2016-03-31
+
 * Rustup to *rustc 1.9.0-nightly (30a3849f2 2016-03-30)*
 * New lints: [`logic_bug`], [`nonminimal_bool`]
 * Fixed: [`match_same_arms`] now ignores arms with guards
 * Improved: [`useless_vec`] now warns on `for … in vec![…]`
 
 ## 0.0.58 — 2016-03-27
+
 * Rustup to *rustc 1.9.0-nightly (d5a91e695 2016-03-26)*
 * New lint: [`doc_markdown`]
 
 ## 0.0.57 — 2016-03-27
+
 * Update to *rustc 1.9.0-nightly (a1e29daf1 2016-03-25)*
 * Deprecated lints: [`str_to_string`], [`string_to_string`], [`unstable_as_slice`], [`unstable_as_mut_slice`]
 * New lint: [`crosspointer_transmute`]
 
 ## 0.0.56 — 2016-03-23
+
 * Update to *rustc 1.9.0-nightly (0dcc413e4 2016-03-22)*
 * New lints: [`many_single_char_names`] and [`similar_names`]
 
 ## 0.0.55 — 2016-03-21
+
 * Update to *rustc 1.9.0-nightly (02310fd31 2016-03-19)*
 
 ## 0.0.54 — 2016-03-16
+
 * Update to *rustc 1.9.0-nightly (c66d2380a 2016-03-15)*
 
 ## 0.0.53 — 2016-03-15
+
 * Add a [configuration file]
 
 ## ~~0.0.52~~
 
 ## 0.0.51 — 2016-03-13
+
 * Add `str` to types considered by [`len_zero`]
 * New lints: [`indexing_slicing`]
 
 ## 0.0.50 — 2016-03-11
+
 * Update to *rustc 1.9.0-nightly (c9629d61c 2016-03-10)*
 
 ## 0.0.49 — 2016-03-09
+
 * Update to *rustc 1.9.0-nightly (eabfc160f 2016-03-08)*
 * New lints: [`overflow_check_conditional`], `unused_label`, [`new_without_default`]
 
 ## 0.0.48 — 2016-03-07
+
 * Fixed: ICE in [`needless_range_loop`] with globals
 
 ## 0.0.47 — 2016-03-07
+
 * Update to *rustc 1.9.0-nightly (998a6720b 2016-03-07)*
 * New lint: [`redundant_closure_call`]
 
@@ -6573,6 +6731,7 @@
 [`renamed_function_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params
 [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 [`repeat_vec_with_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity
+[`replace_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_box
 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
 [`repr_packed_without_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#repr_packed_without_abi
 [`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization
@@ -6738,6 +6897,7 @@
 [`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max
 [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
+[`unnecessary_option_map_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_option_map_or_else
 [`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings
 [`unnecessary_result_map_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_result_map_or_else
 [`unnecessary_safety_comment`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_comment
@@ -6798,6 +6958,7 @@
 [`vec_resize_to_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_resize_to_zero
 [`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
 [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
+[`volatile_composites`]: https://rust-lang.github.io/rust-clippy/master/index.html#volatile_composites
 [`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
 [`waker_clone_wake`]: https://rust-lang.github.io/rust-clippy/master/index.html#waker_clone_wake
 [`while_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_float
@@ -6874,6 +7035,7 @@
 [`excessive-nesting-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#excessive-nesting-threshold
 [`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold
 [`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability
+[`inherent-impl-lint-scope`]: https://doc.rust-lang.org/clippy/lint_configuration.html#inherent-impl-lint-scope
 [`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold
 [`lint-commented-code`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-commented-code
 [`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold
@@ -6891,6 +7053,7 @@
 [`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv
 [`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit
 [`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior
+[`recursive-self-in-type-definitions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#recursive-self-in-type-definitions
 [`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline
 [`semicolon-outside-block-ignore-multiline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-outside-block-ignore-multiline
 [`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index 2b89e94..d9a5f04 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -759,8 +759,7 @@
 Here are some pointers to things you are likely going to need for every lint:
 
 * [Clippy utils][utils] - Various helper functions. Maybe the function you need
-  is already in here ([`is_type_diagnostic_item`], [`implements_trait`],
-  [`snippet`], etc)
+  is already in here ([`implements_trait`], [`snippet`], etc)
 * [Clippy diagnostics][diagnostics]
 * [Let chains][let-chains]
 * [`from_expansion`][from_expansion] and
@@ -790,7 +789,6 @@
 don't hesitate to ask on [Zulip] or in the issue/PR.
 
 [utils]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/index.html
-[`is_type_diagnostic_item`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.is_type_diagnostic_item.html
 [`implements_trait`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.implements_trait.html
 [`snippet`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/source/fn.snippet.html
 [let-chains]: https://github.com/rust-lang/rust/pull/94927
diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
index 3bec3ce..b5958f8 100644
--- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md
+++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
@@ -68,7 +68,7 @@
         // Check our expr is calling a method
         if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind
             // Check the name of this method is `some_method`
-            && path.ident.name.as_str() == "some_method"
+            && path.ident.name == sym::some_method
             // Optionally, check the type of the self argument.
             // - See "Checking for a specific type"
         {
@@ -85,9 +85,8 @@
 arguments have to be checked separately.
 
 ```rust
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use clippy_utils::paths;
-use rustc_span::symbol::sym;
+use clippy_utils::{paths, sym};
+use clippy_utils::res::MaybeDef;
 use rustc_hir::LangItem;
 
 impl LateLintPass<'_> for MyStructLint {
@@ -97,12 +96,12 @@
 
         // 1. Using diagnostic items
         // The last argument is the diagnostic item to check for
-        if is_type_diagnostic_item(cx, ty, sym::Option) {
+        if ty.is_diag_item(cx, sym::Option) {
             // The type is an `Option`
         }
 
         // 2. Using lang items
-        if is_type_lang_item(cx, ty, LangItem::RangeFull) {
+        if ty.is_lang_item(cx, LangItem::RangeFull) {
             // The type is a full range like `.drain(..)`
         }
 
@@ -123,27 +122,29 @@
 diagnostic item, lang item or neither.
 
 ```rust
+use clippy_utils::sym;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::is_trait_method;
-use rustc_span::symbol::sym;
 
 impl LateLintPass<'_> for MyStructLint {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        // 1. Using diagnostic items with the expression
-        // we use `is_trait_method` function from Clippy's utils
-        if is_trait_method(cx, expr, sym::Iterator) {
-            // method call in `expr` belongs to `Iterator` trait
+
+        // 1. Get the `DefId` of the trait.
+        // via lang items
+        let trait_id = cx.tcx.lang_items().drop_trait();
+        // via diagnostic items
+        let trait_id = cx.tcx.get_diagnostic_item(sym::Eq);
+
+        // 2. Check for the trait implementation via the `implements_trait` util.
+        let ty = cx.typeck_results().expr_ty(expr);
+        if trait_id.is_some_and(|id| implements_trait(cx, ty, id, &[])) {
+            // `ty` implements the trait.
         }
 
-        // 2. Using lang items with the expression type
-        let ty = cx.typeck_results().expr_ty(expr);
-        if cx.tcx.lang_items()
-            // we are looking for the `DefId` of `Drop` trait in lang items
-            .drop_trait()
-            // then we use it with our type `ty` by calling `implements_trait` from Clippy's utils
-            .is_some_and(|id| implements_trait(cx, ty, id, &[])) {
-                // `expr` implements `Drop` trait
-            }
+        // 3. If the trait requires additional generic arguments
+        let trait_id = cx.tcx.lang_items().eq_trait();
+        if trait_id.is_some_and(|id| implements_trait(cx, ty, id, &[ty])) {
+            // `ty` implements `PartialEq<Self>`
+        }
     }
 }
 ```
@@ -173,7 +174,7 @@
             // We can also check it has a parameter `self`
             && signature.decl.implicit_self.has_implicit_self()
             // We can go further and even check if its return type is `String`
-            && is_type_lang_item(cx, return_ty(cx, impl_item.hir_id), LangItem::String)
+            && return_ty(cx, impl_item.hir_id).is_lang_item(cx, LangItem::String)
         {
             // ...
         }
diff --git a/src/tools/clippy/book/src/development/macro_expansions.md b/src/tools/clippy/book/src/development/macro_expansions.md
index ed54713..63a96dc 100644
--- a/src/tools/clippy/book/src/development/macro_expansions.md
+++ b/src/tools/clippy/book/src/development/macro_expansions.md
@@ -37,7 +37,7 @@
 
 Several functions are available for working with macros.
 
-### The `Span.from_expansion` method
+### The `Span::from_expansion` method
 
 We could utilize a `span`'s [`from_expansion`] method, which
 detects if the `span` is from a macro expansion / desugaring.
@@ -50,7 +50,7 @@
 }
 ```
 
-### `Span.ctxt` method
+### `Span::ctxt` method
 
 The `span`'s context, given by the method [`ctxt`] and returning [SyntaxContext],
 represents if the span is from a macro expansion and, if it is, which
diff --git a/src/tools/clippy/book/src/development/method_checking.md b/src/tools/clippy/book/src/development/method_checking.md
index b312602..cca6d6a 100644
--- a/src/tools/clippy/book/src/development/method_checking.md
+++ b/src/tools/clippy/book/src/development/method_checking.md
@@ -15,20 +15,20 @@
 ```rust
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_span::sym;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
+use clippy_utils::sym;
 
 impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         // Check our expr is calling a method with pattern matching
         if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind
             // Check if the name of this method is `our_fancy_method`
-            && path.ident.name.as_str() == "our_fancy_method"
+            && path.ident.name == sym::our_fancy_method
             // We can check the type of the self argument whenever necessary.
             // (It's necessary if we want to check that method is specifically belonging to a specific trait,
             // for example, a `map` method could belong to user-defined trait instead of to `Iterator`)
             // See the next section for more information.
-            && is_trait_method(cx, self_arg, sym::OurFancyTrait)
+            && cx.ty_based_def(self_arg).opt_parent(cx).is_diag_item(cx, sym::OurFancyTrait)
         {
             println!("`expr` is a method call for `our_fancy_method`");
         }
@@ -41,6 +41,10 @@
 Lints](defining_lints.md#lint-types), the `methods` lint type is full of pattern
 matching with `MethodCall` in case the reader wishes to explore more.
 
+New symbols such as `our_fancy_method` need to be added to the `clippy_utils::sym` module.
+This module extends the list of symbols already provided by the compiler crates
+in `rustc_span::sym`.
+
 ## Checking if a `impl` block implements a method
 
 While sometimes we want to check whether a method is being called or not, other
@@ -56,11 +60,10 @@
 `our_fancy_method` on a type:
 
 ```rust
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::return_ty;
+use clippy_utils::{return_ty, sym};
+use clippy_utils::res::MaybeDef;
 use rustc_hir::{ImplItem, ImplItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_span::symbol::sym;
 
 impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
@@ -71,7 +74,7 @@
             // We can also check it has a parameter `self`
             && signature.decl.implicit_self.has_implicit_self()
             // We can go even further and even check if its return type is `String`
-            && is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::String)
+            && return_ty(cx, impl_item.hir_id).is_diag_item(cx, sym::String)
         {
             println!("`our_fancy_method` is implemented!");
         }
diff --git a/src/tools/clippy/book/src/development/trait_checking.md b/src/tools/clippy/book/src/development/trait_checking.md
index c6f6f6b..714607e 100644
--- a/src/tools/clippy/book/src/development/trait_checking.md
+++ b/src/tools/clippy/book/src/development/trait_checking.md
@@ -17,10 +17,10 @@
 the symbol of the trait in question:
 
 ```rust
+use clippy_utils::sym;
 use clippy_utils::ty::implements_trait;
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_span::symbol::sym;
 
 impl LateLintPass<'_> for CheckIteratorTraitLint {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
@@ -53,7 +53,7 @@
 we can check that the `Ty` of the `expr` implements the trait:
 
 ```rust
-use clippy_utils::implements_trait;
+use clippy_utils::ty::implements_trait;
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 
@@ -79,7 +79,8 @@
 Below, we check if the given `expr` implements [`core::iter::Step`](https://doc.rust-lang.org/std/iter/trait.Step.html):
 
 ```rust
-use clippy_utils::{implements_trait, paths};
+use clippy_utils::paths;
+use clippy_utils::ty::implements_trait;
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 
@@ -124,8 +125,8 @@
 ```rust
 
 use rustc_middle::ty::Ty;
+use clippy_utils::sym;
 use clippy_utils::ty::implements_trait;
-use rustc_span::symbol::sym;
 
 let ty = todo!("Get the `Foo` type to check for a trait implementation");
 let borrow_id = cx.tcx.get_diagnostic_item(sym::Borrow).unwrap(); // avoid unwrap in real code
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index b2ba196..b9ecff1 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -671,6 +671,16 @@
 * [`mutable_key_type`](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type)
 
 
+## `inherent-impl-lint-scope`
+Sets the scope ("crate", "file", or "module") in which duplicate inherent `impl` blocks for the same type are linted.
+
+**Default Value:** `"crate"`
+
+---
+**Affected lints:**
+* [`multiple_inherent_impl`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl)
+
+
 ## `large-error-threshold`
 The maximum size of the `Err`-variant in a `Result` returned from a function
 
@@ -927,6 +937,16 @@
 * [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields)
 
 
+## `recursive-self-in-type-definitions`
+Whether the type itself in a struct or enum should be replaced with `Self` when encountering recursive types.
+
+**Default Value:** `true`
+
+---
+**Affected lints:**
+* [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self)
+
+
 ## `semicolon-inside-block-ignore-singleline`
 Whether to lint only if it's multiline.
 
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 9ad4346..9993765 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -1,9 +1,9 @@
 use crate::ClippyConfiguration;
 use crate::types::{
-    DisallowedPath, DisallowedPathWithoutReplacement, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour,
-    Rename, SourceItemOrdering, SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings,
-    SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
-    SourceItemOrderingWithinModuleItemGroupings,
+    DisallowedPath, DisallowedPathWithoutReplacement, InherentImplLintScope, MacroMatcher, MatchLintBehaviour,
+    PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory,
+    SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind,
+    SourceItemOrderingTraitAssocItemKinds, SourceItemOrderingWithinModuleItemGroupings,
 };
 use clippy_utils::msrvs::Msrv;
 use itertools::Itertools;
@@ -248,7 +248,7 @@ fn default() -> Self {
 
         #[derive(Deserialize)]
         #[serde(field_identifier, rename_all = "kebab-case")]
-        #[allow(non_camel_case_types)]
+        #[expect(non_camel_case_types)]
         enum Field { $($name,)* third_party, }
 
         struct ConfVisitor<'a>(&'a SourceFile);
@@ -663,6 +663,9 @@ fn span_from_toml_range(file: &SourceFile, span: Range<usize>) -> Span {
     /// A list of paths to types that should be treated as if they do not contain interior mutability
     #[lints(borrow_interior_mutable_const, declare_interior_mutable_const, ifs_same_cond, mutable_key_type)]
     ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()]),
+    /// Sets the scope ("crate", "file", or "module") in which duplicate inherent `impl` blocks for the same type are linted.
+    #[lints(multiple_inherent_impl)]
+    inherent_impl_lint_scope: InherentImplLintScope = InherentImplLintScope::Crate,
     /// The maximum size of the `Err`-variant in a `Result` returned from a function
     #[lints(result_large_err)]
     large_error_threshold: u64 = 128,
@@ -809,6 +812,9 @@ fn span_from_toml_range(file: &SourceFile, span: Range<usize>) -> Span {
     /// exported visibility, or whether they are marked as "pub".
     #[lints(pub_underscore_fields)]
     pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported,
+    /// Whether the type itself in a struct or enum should be replaced with `Self` when encountering recursive types.
+    #[lints(use_self)]
+    recursive_self_in_type_definitions: bool = true,
     /// Whether to lint only if it's multiline.
     #[lints(semicolon_inside_block)]
     semicolon_inside_block_ignore_singleline: bool = false,
@@ -1213,7 +1219,7 @@ fn configs_are_tested() {
 
         for entry in toml_files {
             let file = fs::read_to_string(entry.path()).unwrap();
-            #[allow(clippy::zero_sized_map_values)]
+            #[expect(clippy::zero_sized_map_values)]
             if let Ok(map) = toml::from_str::<HashMap<String, IgnoredAny>>(&file) {
                 for name in map.keys() {
                     names.remove(name.as_str());
diff --git a/src/tools/clippy/clippy_config/src/types.rs b/src/tools/clippy/clippy_config/src/types.rs
index f64eefa..8d9326a 100644
--- a/src/tools/clippy/clippy_config/src/types.rs
+++ b/src/tools/clippy/clippy_config/src/types.rs
@@ -131,7 +131,7 @@ fn allow_invalid(&self) -> bool {
 }
 
 /// Creates a map of disallowed items to the reason they were disallowed.
-#[allow(clippy::type_complexity)]
+#[expect(clippy::type_complexity)]
 pub fn create_disallowed_map<const REPLACEMENT_ALLOWED: bool>(
     tcx: TyCtxt<'_>,
     disallowed_paths: &'static [DisallowedPath<REPLACEMENT_ALLOWED>],
@@ -698,3 +698,11 @@ pub enum PubUnderscoreFieldsBehaviour {
     PubliclyExported,
     AllPubFields,
 }
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
+#[serde(rename_all = "lowercase")]
+pub enum InherentImplLintScope {
+    Crate,
+    File,
+    Module,
+}
diff --git a/src/tools/clippy/clippy_dev/src/dogfood.rs b/src/tools/clippy/clippy_dev/src/dogfood.rs
index d0fca95..9eb323e 100644
--- a/src/tools/clippy/clippy_dev/src/dogfood.rs
+++ b/src/tools/clippy/clippy_dev/src/dogfood.rs
@@ -4,7 +4,7 @@
 /// # Panics
 ///
 /// Panics if unable to run the dogfood test
-#[allow(clippy::fn_params_excessive_bools)]
+#[expect(clippy::fn_params_excessive_bools)]
 pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool, allow_no_vcs: bool) {
     run_exit_on_err(
         "cargo test",
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 5fef231..1b6a590b 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -192,7 +192,7 @@ enum DevCommand {
         /// Which lint's page to load initially (optional)
         lint: Option<String>,
     },
-    #[allow(clippy::doc_markdown)]
+    #[expect(clippy::doc_markdown)]
     /// Manually run clippy on a file or package
     ///
     /// ## Examples
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 4121daa..a14afd8 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -443,7 +443,6 @@ pub(super) fn check(cx: &{context_import}{pass_lifetimes}) {{
     Ok(())
 }
 
-#[allow(clippy::too_many_lines)]
 fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> {
     let lint_name_upper = lint.name.to_uppercase();
 
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index 36498ad..b8bf8b2 100644
--- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -167,7 +167,7 @@
 impl_lint_pass!(ArbitrarySourceItemOrdering => [ARBITRARY_SOURCE_ITEM_ORDERING]);
 
 #[derive(Debug)]
-#[allow(clippy::struct_excessive_bools)] // Bools are cached feature flags.
+#[expect(clippy::struct_excessive_bools, reason = "Bools are cached feature flags")]
 pub struct ArbitrarySourceItemOrdering {
     assoc_types_order: SourceItemOrderingTraitAssocItemKinds,
     enable_ordering_for_enum: bool,
diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
index 085029a..acfdfa6 100644
--- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
+++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::ty::implements_trait;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
@@ -46,7 +47,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             && let ExprKind::Path(QPath::TypeRelative(func_ty, func_name)) = func.kind
             && func_name.ident.name == sym::new
             && !expr.span.from_expansion()
-            && is_type_diagnostic_item(cx, cx.typeck_results().node_type(func_ty.hir_id), sym::Arc)
+            && cx.typeck_results().node_type(func_ty.hir_id).is_diag_item(cx, sym::Arc)
             && let arg_ty = cx.typeck_results().expr_ty(arg)
             // make sure that the type is not and does not contain any type parameters
             && arg_ty.walk().all(|arg| {
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
index 08253b0..cc62306 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -1,9 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_node};
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
+use clippy_utils::sym;
+use clippy_utils::ty::{has_debug_impl, is_copy};
 use clippy_utils::usage::local_used_after_expr;
-use clippy_utils::{path_res, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{Expr, ExprKind, Node};
@@ -55,13 +56,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             && let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind
             && let result_type_with_refs = cx.typeck_results().expr_ty(recv)
             && let result_type = result_type_with_refs.peel_refs()
-            && is_type_diagnostic_item(cx, result_type, sym::Result)
+            && result_type.is_diag_item(cx, sym::Result)
             && let ty::Adt(_, args) = result_type.kind()
         {
             if !is_copy(cx, result_type) {
                 if result_type_with_refs != result_type {
                     return;
-                } else if let Res::Local(binding_id) = path_res(cx, recv)
+                } else if let Res::Local(binding_id) = *recv.basic_res()
                     && local_used_after_expr(cx, binding_id, recv)
                 {
                     return;
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 52287be..efce23d 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -2,8 +2,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir};
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local, sym};
+use clippy_utils::{is_in_test, last_path_segment, local_is_initialized, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -68,15 +69,15 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if let ExprKind::Assign(lhs, rhs, _) = e.kind
             && let typeck = cx.typeck_results()
-            && let (call_kind, fn_name, fn_id, fn_arg, fn_gen_args) = match rhs.kind {
+            && let (call_kind, fn_name, fn_def, fn_arg, fn_gen_args) = match rhs.kind {
                 ExprKind::Call(f, [arg])
                     if let ExprKind::Path(fn_path) = &f.kind
-                        && let Some(id) = typeck.qpath_res(fn_path, f.hir_id).opt_def_id() =>
+                        && let Some(def) = typeck.qpath_res(fn_path, f.hir_id).opt_def(cx) =>
                 {
-                    (CallKind::Ufcs, last_path_segment(fn_path).ident.name, id, arg, typeck.node_args(f.hir_id))
+                    (CallKind::Ufcs, last_path_segment(fn_path).ident.name, def, arg, typeck.node_args(f.hir_id))
                 },
-                ExprKind::MethodCall(name, recv, [], _) if let Some(id) = typeck.type_dependent_def_id(rhs.hir_id) => {
-                    (CallKind::Method, name.ident.name, id, recv, typeck.node_args(rhs.hir_id))
+                ExprKind::MethodCall(name, recv, [], _) if let Some(def) = typeck.type_dependent_def(rhs.hir_id) => {
+                    (CallKind::Method, name.ident.name, def, recv, typeck.node_args(rhs.hir_id))
                 },
                 _ => return,
             }
@@ -84,20 +85,20 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             // Don't lint in macros.
             && ctxt.is_root()
             && let which_trait = match fn_name {
-                sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone,
+                sym::clone if fn_def.assoc_fn_parent(cx).is_diag_item(cx, sym::Clone) => CloneTrait::Clone,
                 sym::to_owned
-                    if is_diag_trait_item(cx, fn_id, sym::ToOwned)
+                    if fn_def.assoc_fn_parent(cx).is_diag_item(cx, sym::ToOwned)
                         && self.msrv.meets(cx, msrvs::CLONE_INTO) =>
                 {
                     CloneTrait::ToOwned
                 },
                 _ => return,
             }
-            && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.typing_env(), fn_id, fn_gen_args)
+            && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.typing_env(), fn_def.1, fn_gen_args)
             // TODO: This check currently bails if the local variable has no initializer.
             // That is overly conservative - the lint should fire even if there was no initializer,
             // but the variable has been initialized before `lhs` was evaluated.
-            && path_to_local(lhs).is_none_or(|lhs| local_is_initialized(cx, lhs))
+            && lhs.res_local_id().is_none_or(|lhs| local_is_initialized(cx, lhs))
             && let Some(resolved_impl) = cx.tcx.impl_of_assoc(resolved_fn.def_id())
             // Derived forms don't implement `clone_from`/`clone_into`.
             // See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 64aeb27..f398560 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -2,9 +2,10 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::higher::has_let_expr;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::ty::implements_trait;
 use clippy_utils::{eq_expr_value, sym};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -431,9 +432,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio
         },
         ExprKind::MethodCall(path, receiver, args, _) => {
             let type_of_receiver = cx.typeck_results().expr_ty(receiver);
-            if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
-                && !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
-            {
+            if !type_of_receiver.is_diag_item(cx, sym::Option) && !type_of_receiver.is_diag_item(cx, sym::Result) {
                 return None;
             }
             METHODS_WITH_NEGATION
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 3b86184..6f51f23 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_default_equivalent;
 use clippy_utils::macros::macro_backtrace;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::ty::expr_sig;
-use clippy_utils::{is_default_equivalent, path_def_id};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
-use rustc_hir::{AmbigArg, Block, Expr, ExprKind, HirId, LetStmt, Node, QPath, Ty, TyKind};
+use rustc_hir::{AmbigArg, Block, Expr, ExprKind, HirId, LangItem, LetStmt, Node, QPath, Ty, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
 use rustc_span::{Span, sym};
@@ -44,7 +45,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
             // And that method is `new`
             && seg.ident.name == sym::new
             // And the call is that of a `Box` method
-            && path_def_id(cx, ty).is_some_and(|id| Some(id) == cx.tcx.lang_items().owned_box())
+            && ty.basic_res().is_lang_item(cx, LangItem::OwnedBox)
             // And the single argument to the call is another function call
             // This is the `T::default()` (or default equivalent) of `Box::new(T::default())`
             && let ExprKind::Call(arg_path, _) = arg.kind
diff --git a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
index ff53207..be1f406 100644
--- a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{expr_or_init, is_path_diagnostic_item, std_or_core, sym};
+use clippy_utils::{expr_or_init, std_or_core, sym};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, Ty, TyKind};
@@ -53,7 +54,7 @@ fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) ->
 
 fn is_align_of_call(cx: &LateContext<'_>, fun: &Expr<'_>, to: &Ty<'_>) -> bool {
     if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind
-        && is_path_diagnostic_item(cx, fun, sym::mem_align_of)
+        && fun.basic_res().is_diag_item(cx, sym::mem_align_of)
         && let Some(args) = path.segments.last().and_then(|seg| seg.args)
         && let [GenericArg::Type(generic_ty)] = args.args
     {
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index c88a053..7bfe920 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::numeric_literal::NumericLiteral;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::{SpanRangeExt, snippet_opt};
 use clippy_utils::visitors::{Visitable, for_each_expr_without_closures};
-use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local};
+use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias};
 use rustc_ast::{LitFloatType, LitIntType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -167,11 +168,11 @@ fn is_in_allowed_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
                 sym::assert_ne_macro,
                 sym::debug_assert_ne_macro,
             ];
-            matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if 
+            matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if
                 cx.tcx.get_diagnostic_name(def_id).is_some_and(|sym| ALLOWED_MACROS.contains(&sym)))
         }
 
-        if let Some(id) = path_to_local(cast_expr)
+        if let Some(id) = cast_expr.res_local_id()
             && !cx.tcx.hir_span(id).eq_ctxt(cast_expr.span)
         {
             // Binding context is different than the identifiers context.
diff --git a/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs b/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs
index 72ab292..35b799a 100644
--- a/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs
+++ b/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs
@@ -1,9 +1,10 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::visitors::is_const_evaluatable;
-use clippy_utils::{is_in_const_context, is_mutable, is_trait_method};
+use clippy_utils::{is_in_const_context, is_mutable};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -73,7 +74,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
 
             // check for clones
             && let ExprKind::MethodCall(_, val, _, _) = item.kind
-            && is_trait_method(cx, item, sym::Clone)
+            && cx.ty_based_def(item).opt_parent(cx).is_diag_item(cx, sym::Clone)
 
             // check for immutability or purity
             && (!is_mutable(cx, val) || is_const_evaluatable(cx, val))
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index c0f30e4..595625c 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -1,7 +1,7 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::{IntoSpan, SpanRangeExt};
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_expr_without_closures;
 use clippy_utils::{LimitStack, get_async_fn_body, sym};
 use core::ops::ControlFlow;
@@ -93,7 +93,7 @@ fn check<'tcx>(
         });
 
         let ret_ty = cx.typeck_results().node_type(expr.hir_id);
-        let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::Result) {
+        let ret_adjust = if ret_ty.is_diag_item(cx, sym::Result) {
             returns
         } else {
             #[expect(clippy::integer_division)]
diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
index 1279be3..fd84ce7 100644
--- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
+++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
+use clippy_utils::get_enclosing_block;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::visitors::{Visitable, for_each_expr};
-use clippy_utils::{get_enclosing_block, path_to_local_id};
 use core::ops::ControlFlow;
 use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -59,7 +59,7 @@ fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
 fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
     let ty = cx.typeck_results().pat_ty(local.pat);
     matches!(
-        get_type_diagnostic_name(cx, ty),
+        ty.opt_diag_name(cx),
         Some(
             sym::BTreeMap
                 | sym::BTreeSet
@@ -71,7 +71,7 @@ fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
                 | sym::Vec
                 | sym::VecDeque
         )
-    ) || is_type_lang_item(cx, ty, LangItem::String)
+    ) || ty.is_lang_item(cx, LangItem::String)
 }
 
 fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirId, block: T) -> bool {
@@ -81,7 +81,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
     // Inspect all expressions and sub-expressions in the block.
     for_each_expr(cx, block, |expr| {
         // Ignore expressions that are not simply `id`.
-        if !path_to_local_id(expr, id) {
+        if expr.res_local_id() != Some(id) {
             return ControlFlow::Continue(());
         }
 
@@ -93,7 +93,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
         // id = ...; // Not reading `id`.
         if let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id)
             && let ExprKind::Assign(lhs, ..) = parent.kind
-            && path_to_local_id(lhs, id)
+            && lhs.res_local_id() == Some(id)
         {
             return ControlFlow::Continue(());
         }
@@ -107,7 +107,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
         // have side effects, so consider them a read.
         if let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id)
             && let ExprKind::MethodCall(_, receiver, args, _) = parent.kind
-            && path_to_local_id(receiver, id)
+            && receiver.res_local_id() == Some(id)
             && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
             && !method_def_id.is_local()
         {
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 0ec0aaa..375d179 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -488,6 +488,7 @@
     crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
     crate::methods::UNNECESSARY_MAP_OR_INFO,
     crate::methods::UNNECESSARY_MIN_OR_MAX_INFO,
+    crate::methods::UNNECESSARY_OPTION_MAP_OR_ELSE_INFO,
     crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO,
     crate::methods::UNNECESSARY_SORT_BY_INFO,
     crate::methods::UNNECESSARY_TO_OWNED_INFO,
@@ -655,6 +656,7 @@
     crate::regex::REGEX_CREATION_IN_LOOPS_INFO,
     crate::regex::TRIVIAL_REGEX_INFO,
     crate::repeat_vec_with_capacity::REPEAT_VEC_WITH_CAPACITY_INFO,
+    crate::replace_box::REPLACE_BOX_INFO,
     crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO,
     crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
     crate::returns::LET_AND_RETURN_INFO,
@@ -780,6 +782,7 @@
     crate::visibility::NEEDLESS_PUB_SELF_INFO,
     crate::visibility::PUB_WITHOUT_SHORTHAND_INFO,
     crate::visibility::PUB_WITH_SHORTHAND_INFO,
+    crate::volatile_composites::VOLATILE_COMPOSITES_INFO,
     crate::wildcard_imports::ENUM_GLOB_USE_INFO,
     crate::wildcard_imports::WILDCARD_IMPORTS_INFO,
     crate::write::PRINTLN_EMPTY_STRING_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 2147f72..f087a89 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -7,7 +7,6 @@ macro_rules! declare_with_version {
         $e:expr,
     )*]) => {
         pub static $name: &[(&str, &str)] = &[$($e),*];
-        #[allow(unused)]
         pub static $name_version: &[&str] = &[$($version),*];
     };
 }
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 9ebb8e6..de13620 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
 use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop, peel_and_count_ty_refs};
 use clippy_utils::{
     DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, is_block_like, is_from_proc_macro, is_lint_allowed,
-    path_to_local,
 };
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_data_structures::fx::FxIndexMap;
@@ -239,7 +239,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             return;
         }
 
-        if let Some(local) = path_to_local(expr) {
+        if let Some(local) = expr.res_local_id() {
             self.check_local_usage(cx, expr, local);
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs b/src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs
index 274c699..2bd5e2c 100644
--- a/src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/derive/derive_ord_xor_partial_ord.rs
@@ -28,7 +28,7 @@ pub(super) fn check<'tcx>(
                 return;
             }
 
-            let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
+            let trait_ref = cx.tcx.impl_trait_ref(impl_id);
 
             // Only care about `impl PartialOrd<Foo> for Foo`
             // For `impl PartialOrd<B> for A, input_types is [A, B]
diff --git a/src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs b/src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs
index afc02ce..dc3fbe5 100644
--- a/src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs
+++ b/src/tools/clippy/clippy_lints/src/derive/derived_hash_with_manual_eq.rs
@@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(
                 return;
             }
 
-            let trait_ref = cx.tcx.impl_trait_ref(impl_id).expect("must be a trait implementation");
+            let trait_ref = cx.tcx.impl_trait_ref(impl_id);
 
             // Only care about `impl PartialEq<Foo> for Foo`
             // For `impl PartialEq<B> for A, input_types is [A, B]
diff --git a/src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs
index dfb723b..b2bc640 100644
--- a/src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/derive/expl_impl_clone_on_copy.rs
@@ -1,4 +1,5 @@
-use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::fulfill_or_allowed;
 use clippy_utils::ty::{implements_trait, is_copy};
 use rustc_hir::{self as hir, HirId, Item};
 use rustc_lint::LateContext;
@@ -60,14 +61,16 @@ pub(super) fn check<'tcx>(
         return;
     }
 
-    span_lint_hir_and_then(
+    if fulfill_or_allowed(cx, EXPL_IMPL_CLONE_ON_COPY, [adt_hir_id]) {
+        return;
+    }
+
+    span_lint_and_help(
         cx,
         EXPL_IMPL_CLONE_ON_COPY,
-        adt_hir_id,
         item.span,
         "you are implementing `Clone` explicitly on a `Copy` type",
-        |diag| {
-            diag.span_help(item.span, "consider deriving `Clone` or removing `Copy`");
-        },
+        None,
+        "consider deriving `Clone` or removing `Copy`",
     );
 }
diff --git a/src/tools/clippy/clippy_lints/src/derive/mod.rs b/src/tools/clippy/clippy_lints/src/derive/mod.rs
index 06efc27..eafe7c4 100644
--- a/src/tools/clippy/clippy_lints/src/derive/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/derive/mod.rs
@@ -1,4 +1,4 @@
-use clippy_utils::path_res;
+use clippy_utils::res::MaybeResPath;
 use rustc_hir::def::Res;
 use rustc_hir::{Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -199,7 +199,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             self_ty,
             ..
         }) = item.kind
-            && let Res::Def(_, def_id) = path_res(cx, self_ty)
+            && let Res::Def(_, def_id) = *self_ty.basic_res()
             && let Some(local_def_id) = def_id.as_local()
         {
             let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
index 3033ac0..b164a9a 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -1,7 +1,8 @@
 use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
-use clippy_utils::ty::{get_type_diagnostic_name, implements_trait_with_env, is_type_diagnostic_item};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::ty::implements_trait_with_env;
 use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{fulfill_or_allowed, is_doc_hidden, is_inside_always_const_context, method_chain_args, return_ty};
 use rustc_hir::{BodyId, FnSig, OwnerId, Safety};
@@ -62,7 +63,7 @@ pub fn check(
         );
     }
     if !headers.errors {
-        if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) {
+        if return_ty(cx, owner_id).is_diag_item(cx, sym::Result) {
             span_lint(
                 cx,
                 MISSING_ERRORS_DOC,
@@ -83,7 +84,7 @@ pub fn check(
                 &[],
             )
             && let ty::Coroutine(_, subs) = ret_ty.kind()
-            && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result)
+            && subs.as_coroutine().return_ty().is_diag_item(cx, sym::Result)
         {
             span_lint(
                 cx,
@@ -119,10 +120,7 @@ fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option<Span> {
         if let Some(arglists) =
             method_chain_args(expr, &[sym::unwrap]).or_else(|| method_chain_args(expr, &[sym::expect]))
             && let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs()
-            && matches!(
-                get_type_diagnostic_name(cx, receiver_ty),
-                Some(sym::Option | sym::Result)
-            )
+            && matches!(receiver_ty.opt_diag_name(cx), Some(sym::Option | sym::Result))
             && !fulfill_or_allowed(cx, MISSING_PANICS_DOC, [expr.hir_id])
             && panic_span.is_none()
         {
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index cfdf9ca..2a3fb82 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -970,7 +970,7 @@ fn check_for_code_clusters<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a
 /// This walks the "events" (think sections of markdown) produced by `pulldown_cmark`,
 /// so lints here will generally access that information.
 /// Returns documentation headers -- whether a "Safety", "Errors", "Panic" section was found
-#[allow(clippy::too_many_lines)] // Only a big match statement
+#[expect(clippy::too_many_lines, reason = "big match statement")]
 fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>(
     cx: &LateContext<'_>,
     valid_idents: &FxHashSet<String>,
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index 5c360ce..3bb8c48 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_must_use_func_call;
-use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::ty::{is_copy, is_must_use_ty};
 use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -97,7 +98,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 sym::mem_forget if arg_ty.is_ref() => return,
                 sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return,
                 sym::mem_forget if is_copy => return,
-                sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => return,
+                sym::mem_drop if arg_ty.is_lang_item(cx, LangItem::ManuallyDrop) => return,
                 sym::mem_drop
                     if !(arg_ty.needs_drop(cx.tcx, cx.typing_env())
                         || is_must_use_func_call(cx, arg)
diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
index 3018e1f..3d8650f 100644
--- a/src/tools/clippy/clippy_lints/src/error_impl_error.rs
+++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_hir_and_then};
-use clippy_utils::path_res;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::ty::implements_trait;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{Item, ItemKind};
@@ -55,7 +55,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
                 if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_ref.trait_def_id())
                     && let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
                     && error_def_id == trait_def_id
-                    && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
+                    && let Some(def_id) = imp.self_ty.basic_res().opt_def_id().and_then(DefId::as_local)
                     && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
                     && ident.name == sym::Error
                     && is_visible_outside_module(cx, def_id) =>
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 752f39b..21385ee 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -1,11 +1,9 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::higher::VecArgs;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::{snippet_opt, snippet_with_applicability};
-use clippy_utils::ty::get_type_diagnostic_name;
 use clippy_utils::usage::{local_used_after_expr, local_used_in};
-use clippy_utils::{
-    get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id,
-};
+use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate};
 use rustc_abi::ExternAbi;
 use rustc_errors::Applicability;
 use rustc_hir::attrs::AttributeKind;
@@ -86,7 +84,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
     }
 }
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx>>, expr: &Expr<'tcx>) {
     let body = if let ExprKind::Closure(c) = expr.kind
         && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(())))
@@ -144,7 +142,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
         {
             let callee_ty_raw = typeck.expr_ty(callee);
             let callee_ty = callee_ty_raw.peel_refs();
-            if matches!(get_type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc))
+            if matches!(callee_ty.opt_diag_name(cx), Some(sym::Arc | sym::Rc))
                 || !check_inputs(typeck, body.params, None, args)
             {
                 return;
@@ -218,7 +216,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                     "redundant closure",
                     |diag| {
                         if let Some(mut snippet) = snippet_opt(cx, callee.span) {
-                            if path_to_local(callee).is_some_and(|l| {
+                            if callee.res_local_id().is_some_and(|l| {
                                 // FIXME: Do we really need this `local_used_in` check?
                                 // Isn't it checking something like... `callee(callee)`?
                                 // If somehow this check is needed, add some test for it,
@@ -307,7 +305,7 @@ fn check_inputs(
             matches!(
                 p.pat.kind,
                 PatKind::Binding(BindingMode::NONE, id, _, None)
-                if path_to_local_id(arg, id)
+                if arg.res_local_id() == Some(id)
             )
             // Only allow adjustments which change regions (i.e. re-borrowing).
             && typeck
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 085ee44..c59ffa1 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_expn_of, path_def_id, sym};
+use clippy_utils::{is_expn_of, is_in_test, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
@@ -59,7 +60,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind)
             && let ExprKind::Call(write_recv_path, []) = write_recv.kind
             && write_fun.ident.name == sym::write_fmt
-            && let Some(def_id) = path_def_id(cx, write_recv_path)
+            && let Some(def_id) = write_recv_path.basic_res().opt_def_id()
         {
             // match calls to std::io::stdout() / std::io::stderr ()
             let (dest_name, prefix) = match cx.tcx.get_diagnostic_name(def_id) {
@@ -71,6 +72,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 return;
             };
 
+            // Performing an explicit write in a test circumvent's libtest's capture of stdio and stdout.
+            if is_in_test(cx.tcx, expr.hir_id) {
+                return;
+            }
+
             // ordering is important here, since `writeln!` uses `write!` internally
             let calling_macro = if is_expn_of(write_call.span, sym::writeln).is_some() {
                 Some("writeln")
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index fdfcbb5..c42998f 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use clippy_utils::method_chain_args;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
@@ -52,11 +52,9 @@
 impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         // check for `impl From<???> for ..`
-        if let hir::ItemKind::Impl(_) = &item.kind
-            && let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
-            && cx
-                .tcx
-                .is_diagnostic_item(sym::From, impl_trait_ref.skip_binder().def_id)
+        if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = &item.kind
+            && let impl_trait_id = cx.tcx.impl_trait_id(item.owner_id)
+            && cx.tcx.is_diagnostic_item(sym::From, impl_trait_id)
         {
             lint_impl_body(cx, item.owner_id, item.span);
         }
@@ -84,9 +82,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             // check for `unwrap`
             if let Some(arglists) = method_chain_args(expr, &[sym::unwrap]) {
                 let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
-                if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
-                    || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
-                {
+                if receiver_ty.is_diag_item(self.lcx, sym::Option) || receiver_ty.is_diag_item(self.lcx, sym::Result) {
                     self.result.push(expr.span);
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 407a3f1..5f022ba 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -1,9 +1,10 @@
 use clippy_utils::consts::Constant::{F32, F64, Int};
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::{
-    eq_expr_value, get_parent_expr, has_ambiguous_literal_in_expr, higher, is_in_const_context,
-    is_inherent_method_call, is_no_std_crate, numeric_literal, peel_blocks, sugg, sym,
+    eq_expr_value, get_parent_expr, has_ambiguous_literal_in_expr, higher, is_in_const_context, is_no_std_crate,
+    numeric_literal, peel_blocks, sugg, sym,
 };
 use rustc_ast::ast;
 use rustc_errors::Applicability;
@@ -737,7 +738,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
             let recv_ty = cx.typeck_results().expr_ty(receiver);
 
-            if recv_ty.is_floating_point() && !is_no_std_crate(cx) && is_inherent_method_call(cx, expr) {
+            if recv_ty.is_floating_point() && !is_no_std_crate(cx) && cx.ty_based_def(expr).opt_parent(cx).is_impl(cx) {
                 match path.ident.name {
                     sym::ln => check_ln1p(cx, expr, receiver),
                     sym::log => check_log_base(cx, expr, receiver, args),
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index 94e6676..098bf4b 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -39,7 +39,6 @@
     "useless use of `format!`"
 }
 
-#[allow(clippy::module_name_repetitions)]
 pub struct UselessFormat {
     format_args: FormatArgsStorage,
 }
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 3359aa6..011cbf8 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -9,9 +9,10 @@
     root_macro_call_first_node,
 };
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::{SpanRangeExt, snippet};
-use clippy_utils::ty::{implements_trait, is_type_lang_item};
-use clippy_utils::{is_diag_trait_item, is_from_proc_macro, is_in_test, trait_ref_of_method};
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{is_from_proc_macro, is_in_test, trait_ref_of_method};
 use itertools::Itertools;
 use rustc_ast::{
     FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions,
@@ -237,7 +238,7 @@
     POINTER_FORMAT,
 ]);
 
-#[allow(clippy::struct_field_names)]
+#[expect(clippy::struct_field_names)]
 pub struct FormatArgs<'tcx> {
     format_args: FormatArgsStorage,
     msrv: Msrv,
@@ -344,7 +345,7 @@ fn check_unused_format_specifier(&self, placeholder: &FormatPlaceholder, arg: &E
         if let Some(placeholder_span) = placeholder.span
             && *options != FormatOptions::default()
             && let ty = self.cx.typeck_results().expr_ty(arg).peel_refs()
-            && is_type_lang_item(self.cx, ty, LangItem::FormatArguments)
+            && ty.is_lang_item(self.cx, LangItem::FormatArguments)
         {
             span_lint_and_then(
                 self.cx,
@@ -497,8 +498,11 @@ fn check_to_string_in_format_args(&self, name: Symbol, value: &Expr<'_>) {
         let cx = self.cx;
         if !value.span.from_expansion()
             && let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind
-            && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id)
-            && is_diag_trait_item(cx, method_def_id, sym::ToString)
+            && cx
+                .typeck_results()
+                .type_dependent_def_id(value.hir_id)
+                .opt_parent(cx)
+                .is_diag_item(cx, sym::ToString)
             && let receiver_ty = cx.typeck_results().expr_ty(receiver)
             && let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display)
             && let (n_needed_derefs, target) =
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index 416aea5..903d43e 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, is_format_macro, root_macro_call_first_node};
-use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators, sym};
+use clippy_utils::res::{MaybeDef, MaybeResPath};
+use clippy_utils::{get_parent_as_impl, peel_ref_operators, sym};
 use rustc_ast::{FormatArgsPiece, FormatTrait};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath};
@@ -157,8 +158,12 @@ fn check_to_string_in_display(&self) {
             && path.ident.name == sym::to_string
             // Is the method a part of the ToString trait? (i.e. not to_string() implemented
             // separately)
-            && let Some(expr_def_id) = self.cx.typeck_results().type_dependent_def_id(self.expr.hir_id)
-            && is_diag_trait_item(self.cx, expr_def_id, sym::ToString)
+            && self
+                .cx
+                .typeck_results()
+                .type_dependent_def_id(self.expr.hir_id)
+                .opt_parent(self.cx)
+                .is_diag_item(self.cx, sym::ToString)
             // Is the method is called on self
             && let ExprKind::Path(QPath::Resolved(_, path)) = self_arg.kind
             && let [segment] = path.segments
@@ -210,7 +215,7 @@ fn check_format_arg_self(&self, arg: &Expr<'_>) {
         // Since the argument to fmt is itself a reference: &self
         let reference = peel_ref_operators(self.cx, arg);
         // Is the reference self?
-        if path_to_local(reference).map(|x| self.cx.tcx.hir_name(x)) == Some(kw::SelfLower) {
+        if reference.res_local_id().map(|x| self.cx.tcx.hir_name(x)) == Some(kw::SelfLower) {
             let FormatTraitNames { name, .. } = self.format_trait_impl;
             span_lint(
                 self.cx,
diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs
index b64d608..a23ba9a 100644
--- a/src/tools/clippy/clippy_lints/src/format_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher;
-use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::res::MaybeDef;
 use rustc_hir::{AssignOpKind, Expr, ExprKind, LangItem, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -41,7 +41,10 @@
 declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]);
 
 fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String)
+    cx.typeck_results()
+        .expr_ty(e)
+        .peel_refs()
+        .is_lang_item(cx, LangItem::String)
 }
 fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     let e = e.peel_blocks().peel_borrows();
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index e3bb5ee..ed55f90 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -4,7 +4,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::span_is_local;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::path_def_id;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::SpanRangeExt;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_path};
@@ -76,8 +76,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             // `impl Into<target_ty> for self_ty`
             && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
             && span_is_local(item.span)
-            && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
-            .map(ty::EarlyBinder::instantiate_identity)
+            && let middle_trait_ref = cx.tcx.impl_trait_ref(item.owner_id).instantiate_identity()
             && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
             && !matches!(middle_trait_ref.args.type_at(1).kind(), ty::Alias(ty::Opaque, _))
             && self.msrv.meets(cx, msrvs::RE_REBALANCING_COHERENCE)
@@ -90,7 +89,12 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                 |diag| {
                     // If the target type is likely foreign mention the orphan rules as it's a common source of
                     // confusion
-                    if path_def_id(cx, target_ty.peel_refs()).is_none_or(|id| !id.is_local()) {
+                    if target_ty
+                        .peel_refs()
+                        .basic_res()
+                        .opt_def_id()
+                        .is_none_or(|id| !id.is_local())
+                    {
                         diag.help(
                             "`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\
                             https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence"
diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
index 5e2e2c9..0e6eeb7 100644
--- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::res::MaybeResPath;
+use clippy_utils::sym;
 use clippy_utils::ty::is_c_void;
-use clippy_utils::{path_def_id, sym};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
@@ -41,7 +42,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
             && seg.ident.name == sym::from_raw
-            && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
+            && let Some(type_str) = ty.basic_res().opt_def_id().and_then(|id| def_id_matches_type(cx, id))
             && let arg_kind = cx.typeck_results().expr_ty(arg).kind()
             && let ty::RawPtr(ty, _) = arg_kind
             && is_c_void(cx, *ty)
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index d5873b3..df8a35d 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{is_in_const_context, is_integer_literal, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def};
@@ -89,5 +89,5 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
 
 /// Checks if a Ty is `String` or `&str`
 fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    is_type_lang_item(cx, ty, LangItem::String) || ty.peel_refs().is_str()
+    ty.is_lang_item(cx, LangItem::String) || ty.peel_refs().is_str()
 }
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index 8de68bf..68532de 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -132,7 +132,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
 }
 
 // FIXME: needs to be an EARLY LINT. all attribute lints should be
-#[allow(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments)]
 fn check_needless_must_use(
     cx: &LateContext<'_>,
     decl: &hir::FnDecl<'_>,
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 72f8795..c6b0e7c 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -1,12 +1,13 @@
+use clippy_utils::res::MaybeResPath;
 use rustc_hir::{self as hir, HirId, HirIdSet, intravisit};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::def_id::LocalDefId;
 
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::iter_input_pats;
 use clippy_utils::ty::is_unsafe_fn;
 use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{iter_input_pats, path_to_local};
 
 use core::ops::ControlFlow;
 
@@ -87,7 +88,7 @@ fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option<HirId> {
 }
 
 fn check_arg(cx: &LateContext<'_>, raw_ptrs: &HirIdSet, arg: &hir::Expr<'_>) {
-    if path_to_local(arg).is_some_and(|id| raw_ptrs.contains(&id)) {
+    if arg.res_local_id().is_some_and(|id| raw_ptrs.contains(&id)) {
         span_lint(
             cx,
             NOT_UNSAFE_PTR_ARG_DEREF,
diff --git a/src/tools/clippy/clippy_lints/src/functions/ref_option.rs b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
index 5dc1b72..cc9dc47 100644
--- a/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
@@ -62,7 +62,7 @@ fn check_fn_sig<'a>(cx: &LateContext<'a>, decl: &FnDecl<'a>, span: Span, sig: ty
     }
 }
 
-#[allow(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments)]
 pub(crate) fn check_fn<'a>(
     cx: &LateContext<'a>,
     kind: FnKind<'a>,
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 1f2fce6..fb80cc1 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -1,4 +1,5 @@
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use rustc_errors::Diag;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LintContext};
@@ -6,7 +7,7 @@
 use rustc_span::{Span, sym};
 
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
-use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_type_diagnostic_item};
+use clippy_utils::ty::{AdtVariantInfo, approx_ty_size};
 use clippy_utils::{is_no_std_crate, trait_ref_of_method};
 
 use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};
@@ -24,7 +25,7 @@ fn result_err_ty<'tcx>(
         && let ty = cx
             .tcx
             .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(id).instantiate_identity().output())
-        && is_type_diagnostic_item(cx, ty, sym::Result)
+        && ty.is_diag_item(cx, sym::Result)
         && let ty::Adt(_, args) = ty.kind()
     {
         let err_ty = args.type_at(1);
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
index a99118f..eed2d5d 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::visitors::for_each_expr_without_closures;
 use clippy_utils::{eq_expr_value, higher, sym};
 use core::ops::ControlFlow;
@@ -95,7 +95,7 @@ fn mutex_lock_call<'tcx>(
     if let ExprKind::MethodCall(path, self_arg, [], _) = &expr.kind
         && path.ident.name == sym::lock
         && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
-        && is_type_diagnostic_item(cx, ty, sym::Mutex)
+        && ty.is_diag_item(cx, sym::Mutex)
         && op_mutex.is_none_or(|op| eq_expr_value(cx, self_arg, op))
     {
         ControlFlow::Break(self_arg)
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index f9fee29..dfc8411 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -2,11 +2,11 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, is_res_lang_ctor,
-    path_res, peel_blocks, sym,
+    contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, peel_blocks, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -73,8 +73,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
             && !expr.span.from_expansion()
             && !then_expr.span.from_expansion()
-            && is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome)
-            && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
+            && then_call.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome)
+            && peel_blocks(els).res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone)
             && !is_else_clause(cx.tcx, expr)
             && !is_in_const_context(cx)
             && self.msrv.meets(cx, msrvs::BOOL_THEN)
diff --git a/src/tools/clippy/clippy_lints/src/ifs/branches_sharing_code.rs b/src/tools/clippy/clippy_lints/src/ifs/branches_sharing_code.rs
index eb1025f..b3f597c 100644
--- a/src/tools/clippy/clippy_lints/src/ifs/branches_sharing_code.rs
+++ b/src/tools/clippy/clippy_lints/src/ifs/branches_sharing_code.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet};
 use clippy_utils::ty::needs_ordered_drop;
 use clippy_utils::visitors::for_each_expr_without_closures;
 use clippy_utils::{
     ContainsName, HirEqInterExpr, SpanlessEq, capture_local_usage, get_enclosing_block, hash_expr, hash_stmt,
-    path_to_local,
 };
 use core::iter;
 use core::ops::ControlFlow;
@@ -149,7 +149,7 @@ fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool {
 /// Checks if the statement modifies or moves any of the given locals.
 fn modifies_any_local<'tcx>(cx: &LateContext<'tcx>, s: &'tcx Stmt<'_>, locals: &HirIdSet) -> bool {
     for_each_expr_without_closures(s, |e| {
-        if let Some(id) = path_to_local(e)
+        if let Some(id) = e.res_local_id()
             && locals.contains(&id)
             && !capture_local_usage(cx, e).is_imm_ref()
         {
@@ -198,7 +198,7 @@ fn scan_block_for_eq<'tcx>(
     let mut cond_locals = HirIdSet::default();
     for &cond in conds {
         let _: Option<!> = for_each_expr_without_closures(cond, |e| {
-            if let Some(id) = path_to_local(e) {
+            if let Some(id) = e.res_local_id() {
                 cond_locals.insert(id);
             }
             ControlFlow::Continue(())
diff --git a/src/tools/clippy/clippy_lints/src/ifs/ifs_same_cond.rs b/src/tools/clippy/clippy_lints/src/ifs/ifs_same_cond.rs
index ca76fc2..3ea9413 100644
--- a/src/tools/clippy/clippy_lints/src/ifs/ifs_same_cond.rs
+++ b/src/tools/clippy/clippy_lints/src/ifs/ifs_same_cond.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::ty::InteriorMut;
-use clippy_utils::{SpanlessEq, eq_expr_value, find_binding_init, hash_expr, path_to_local, search_same};
+use clippy_utils::{SpanlessEq, eq_expr_value, find_binding_init, hash_expr, search_same};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
 
@@ -16,7 +17,7 @@ fn method_caller_is_mutable<'tcx>(
     interior_mut.is_interior_mut_ty(cx, caller_ty)
         || caller_ty.is_mutable_ptr()
         // `find_binding_init` will return the binding iff its not mutable
-        || path_to_local(caller_expr)
+        || caller_expr.res_local_id()
             .and_then(|hid| find_binding_init(cx, hid))
             .is_none()
 }
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index b3c90f3..d2bc0b6 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -1,6 +1,7 @@
 use std::borrow::Cow;
 use std::collections::BTreeMap;
 
+use clippy_utils::res::MaybeDef;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir::intravisit::{Visitor, VisitorExt, walk_body, walk_expr, walk_ty};
 use rustc_hir::{self as hir, AmbigArg, Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
@@ -14,7 +15,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet};
 use clippy_utils::sym;
-use clippy_utils::ty::is_type_diagnostic_item;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -227,14 +227,14 @@ fn new(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Option<Self> {
 
             let ty = lower_ty(cx.tcx, hir_ty);
 
-            if is_type_diagnostic_item(cx, ty, sym::HashMap) && params_len == 2 {
+            if ty.is_diag_item(cx, sym::HashMap) && params_len == 2 {
                 Some(ImplicitHasherType::HashMap(
                     hir_ty.span,
                     ty,
                     snippet(cx, params[0].span, "K"),
                     snippet(cx, params[1].span, "V"),
                 ))
-            } else if is_type_diagnostic_item(cx, ty, sym::HashSet) && params_len == 1 {
+            } else if ty.is_diag_item(cx, sym::HashSet) && params_len == 1 {
                 Some(ImplicitHasherType::HashSet(
                     hir_ty.span,
                     ty,
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index c634c12..7b6f872 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -112,7 +112,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     }
 }
 
-#[allow(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments)]
 fn check_manual_check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &Expr<'tcx>,
@@ -165,7 +165,7 @@ fn check_manual_check<'tcx>(
     }
 }
 
-#[allow(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments)]
 fn check_gt(
     cx: &LateContext<'_>,
     condition_span: Span,
@@ -196,7 +196,7 @@ fn is_side_effect_free(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     eq_expr_value(cx, expr, expr)
 }
 
-#[allow(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments)]
 fn check_subtraction(
     cx: &LateContext<'_>,
     condition_span: Span,
@@ -339,8 +339,7 @@ fn check_with_condition<'tcx>(
             ExprKind::Path(QPath::TypeRelative(_, name)) => {
                 if name.ident.name == sym::MIN
                     && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id)
-                    && let Some(impl_id) = cx.tcx.impl_of_assoc(const_id)
-                    && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl
+                    && let Some(impl_id) = cx.tcx.inherent_impl_of_assoc(const_id)
                     && cx.tcx.type_of(impl_id).instantiate_identity().is_integral()
                 {
                     print_lint_and_sugg(cx, var_name, expr);
@@ -350,8 +349,7 @@ fn check_with_condition<'tcx>(
                 if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind
                     && name.ident.name == sym::min_value
                     && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id)
-                    && let Some(impl_id) = cx.tcx.impl_of_assoc(func_id)
-                    && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl
+                    && let Some(impl_id) = cx.tcx.inherent_impl_of_assoc(func_id)
                     && cx.tcx.type_of(impl_id).instantiate_identity().is_integral()
                 {
                     print_lint_and_sugg(cx, var_name, expr);
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 8f9f71a..919702c 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -2,9 +2,10 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLet;
+use clippy_utils::is_lint_allowed;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::ty::is_copy;
-use clippy_utils::{is_lint_allowed, path_to_local};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -225,7 +226,7 @@ fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-        if let Some(local_id) = path_to_local(expr) {
+        if let Some(local_id) = expr.res_local_id() {
             let Self {
                 cx,
                 ref mut slice_lint_info,
diff --git a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
index a159f61..bc57d9e 100644
--- a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{peel_blocks, peel_hir_expr_while, sym};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
@@ -47,7 +47,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::MethodCall(name, recv, [_], _) = expr.kind
             && name.ident.name == sym::open
             && !expr.span.from_expansion()
-            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::FsOpenOptions)
+            && cx
+                .typeck_results()
+                .expr_ty(recv)
+                .peel_refs()
+                .is_diag_item(cx, sym::FsOpenOptions)
         {
             let mut append = false;
             let mut write = None;
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index bf3eafe..f193f06 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::ty::implements_trait;
 use clippy_utils::{higher, sym};
 use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -235,7 +236,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
             } else if method.ident.name == sym::collect {
                 let ty = cx.typeck_results().expr_ty(expr);
                 if matches!(
-                    get_type_diagnostic_name(cx, ty),
+                    ty.opt_diag_name(cx),
                     Some(
                         sym::BinaryHeap
                             | sym::BTreeMap
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index 309d2df..a08efbc 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -1,17 +1,23 @@
+use clippy_config::Conf;
+use clippy_config::types::InherentImplLintScope;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_lint_allowed;
+use clippy_utils::fulfill_or_allowed;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::{LocalDefId, LocalModDefId};
 use rustc_hir::{Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-use rustc_span::Span;
+use rustc_session::impl_lint_pass;
+use rustc_span::{FileName, Span};
 use std::collections::hash_map::Entry;
 
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for multiple inherent implementations of a struct
     ///
+    /// The config option controls the scope in which multiple inherent `impl` blocks for the same
+    /// struct are linted, allowing values of `module` (only within the same module), `file`
+    /// (within the same file), or `crate` (anywhere in the crate, default).
+    ///
     /// ### Why restrict this?
     /// Splitting the implementation of a type makes the code harder to navigate.
     ///
@@ -41,7 +47,26 @@
     "Multiple inherent impl that could be grouped"
 }
 
-declare_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
+impl_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
+
+pub struct MultipleInherentImpl {
+    scope: InherentImplLintScope,
+}
+
+impl MultipleInherentImpl {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            scope: conf.inherent_impl_lint_scope,
+        }
+    }
+}
+
+#[derive(Hash, Eq, PartialEq, Clone)]
+enum Criterion {
+    Module(LocalModDefId),
+    File(FileName),
+    Crate,
+}
 
 impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
     fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
@@ -55,18 +80,27 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
 
         for (&id, impl_ids) in &impls.inherent_impls {
             if impl_ids.len() < 2
-            // Check for `#[allow]` on the type definition
-            || is_lint_allowed(
+            // Check for `#[expect]` or `#[allow]` on the type definition
+            || fulfill_or_allowed(
                 cx,
                 MULTIPLE_INHERENT_IMPL,
-                cx.tcx.local_def_id_to_hir_id(id),
+                [cx.tcx.local_def_id_to_hir_id(id)],
             ) {
                 continue;
             }
 
             for impl_id in impl_ids.iter().map(|id| id.expect_local()) {
                 let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity();
-                match type_map.entry(impl_ty) {
+                let hir_id = cx.tcx.local_def_id_to_hir_id(impl_id);
+                let criterion = match self.scope {
+                    InherentImplLintScope::Module => Criterion::Module(cx.tcx.parent_module(hir_id)),
+                    InherentImplLintScope::File => {
+                        let span = cx.tcx.hir_span(hir_id);
+                        Criterion::File(cx.tcx.sess.source_map().lookup_source_file(span.lo()).name.clone())
+                    },
+                    InherentImplLintScope::Crate => Criterion::Crate,
+                };
+                match type_map.entry((impl_ty, criterion)) {
                     Entry::Vacant(e) => {
                         // Store the id for the first impl block of this type. The span is retrieved lazily.
                         e.insert(IdOrSpan::Id(impl_id));
@@ -97,7 +131,6 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
             // Switching to the next type definition, no need to keep the current entries around.
             type_map.clear();
         }
-
         // `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first.
         lint_spans.sort_by_key(|x| x.0.lo());
         for (span, first_span) in lint_spans {
@@ -125,7 +158,7 @@ fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
     {
         (!span.from_expansion()
             && impl_item.generics.params.is_empty()
-            && !is_lint_allowed(cx, MULTIPLE_INHERENT_IMPL, id))
+            && !fulfill_or_allowed(cx, MULTIPLE_INHERENT_IMPL, [id]))
         .then_some(span)
     } else {
         None
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 7f2e253..e569a5c 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{implements_trait, is_type_lang_item};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::ty::implements_trait;
 use clippy_utils::{return_ty, trait_ref_of_method};
 use rustc_abi::ExternAbi;
 use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
@@ -104,7 +105,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<
             && impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
             && !impl_item.span.from_expansion()
             // Check if return type is String
-            && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
+            && return_ty(cx, impl_item.owner_id).is_lang_item(cx, LangItem::String)
             // Filters instances of to_string which are required by a trait
             && trait_ref_of_method(cx, impl_item.owner_id).is_none()
         {
diff --git a/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs
index b1cb6da..6bb46ac3 100644
--- a/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_over_hash_type.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::higher::ForLoop;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -55,9 +55,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>) {
         if let Some(for_loop) = ForLoop::hir(expr)
             && !for_loop.body.span.from_expansion()
             && let ty = cx.typeck_results().expr_ty(for_loop.arg).peel_refs()
-            && hash_iter_tys
-                .into_iter()
-                .any(|sym| is_type_diagnostic_item(cx, ty, sym))
+            && hash_iter_tys.into_iter().any(|sym| ty.is_diag_item(cx, sym))
         {
             span_lint(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
index 42c6365..8a5d972 100644
--- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
@@ -113,35 +113,18 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
             // since this would only require removing a `use` import (which is already linted).
             && !is_numeric_const_path_canonical(path, [*mod_name, *name])
         {
-            (
-                vec![(expr.span, format!("{mod_name}::{name}"))],
-                "usage of a legacy numeric constant",
-            )
+            (format!("{mod_name}::{name}"), "usage of a legacy numeric constant")
         // `<integer>::xxx_value` check
         } else if let ExprKind::Call(func, []) = &expr.kind
             && let ExprKind::Path(qpath) = &func.kind
             && let QPath::TypeRelative(ty, last_segment) = qpath
             && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
             && is_integer_method(cx, def_id)
+            && let Some(mod_name) = ty.span.get_source_text(cx)
+            && ty.span.eq_ctxt(last_segment.ident.span)
         {
-            let mut sugg = vec![
-                // Replace the function name up to the end by the constant name
-                (
-                    last_segment.ident.span.to(expr.span.shrink_to_hi()),
-                    last_segment.ident.name.as_str()[..=2].to_ascii_uppercase(),
-                ),
-            ];
-            let before_span = expr.span.shrink_to_lo().until(ty.span);
-            if !before_span.is_empty() {
-                // Remove everything before the type name
-                sugg.push((before_span, String::new()));
-            }
-            // Use `::` between the type name and the constant
-            let between_span = ty.span.shrink_to_hi().until(last_segment.ident.span);
-            if !between_span.check_source_text(cx, |s| s == "::") {
-                sugg.push((between_span, String::from("::")));
-            }
-            (sugg, "usage of a legacy numeric method")
+            let name = last_segment.ident.name.as_str()[..=2].to_ascii_uppercase();
+            (format!("{mod_name}::{name}"), "usage of a legacy numeric method")
         } else {
             return;
         };
@@ -151,7 +134,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
             && !is_from_proc_macro(cx, expr)
         {
             span_lint_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.span, msg, |diag| {
-                diag.multipart_suggestion_verbose(
+                diag.span_suggestion_verbose(
+                    expr.span,
                     "use the associated constant instead",
                     sugg,
                     Applicability::MaybeIncorrect,
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 28a0fbc..04a8e47 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::{SpanRangeExt, snippet_with_context};
 use clippy_utils::sugg::{Sugg, has_enclosing_paren};
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{
-    fulfill_or_allowed, get_parent_as_impl, is_trait_method, parent_item_name, peel_ref_operators, sym,
-};
+use clippy_utils::{fulfill_or_allowed, get_parent_as_impl, parent_item_name, peel_ref_operators, sym};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -204,7 +203,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         }
 
         if let ExprKind::MethodCall(method, lhs_expr, [rhs_expr], _) = expr.kind
-            && is_trait_method(cx, expr, sym::PartialEq)
+            && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::PartialEq)
             && !expr.span.from_expansion()
         {
             check_empty_expr(
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index e480c8f..2dbf55a 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::path_to_local_id;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::is_local_used;
 use rustc_errors::Applicability;
@@ -145,7 +145,7 @@ fn check_assign<'tcx>(
         && let Some(expr) = block.stmts.iter().last()
         && let hir::StmtKind::Semi(expr) = expr.kind
         && let hir::ExprKind::Assign(var, value, _) = expr.kind
-        && path_to_local_id(var, decl)
+        && var.res_local_id() == Some(decl)
     {
         if block
             .stmts
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index dcc2d98..a4ad942 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -318,6 +318,7 @@
 mod reference;
 mod regex;
 mod repeat_vec_with_capacity;
+mod replace_box;
 mod reserve_after_initialization;
 mod return_self_not_must_use;
 mod returns;
@@ -394,6 +395,7 @@
 mod vec;
 mod vec_init_then_push;
 mod visibility;
+mod volatile_composites;
 mod wildcard_imports;
 mod write;
 mod zero_div_zero;
@@ -581,7 +583,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
     store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
     store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit));
-    store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
+    store.register_late_pass(move |_| Box::new(inherent_impl::MultipleInherentImpl::new(conf)));
     store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
     store.register_late_pass(move |_| Box::new(unwrap::Unwrap::new(conf)));
     store.register_late_pass(move |_| Box::new(indexing_slicing::IndexingSlicing::new(conf)));
@@ -612,7 +614,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements));
     store.register_early_pass(|| Box::new(precedence::Precedence));
     store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
-    store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue));
+    store.register_late_pass(|_| Box::new(needless_continue::NeedlessContinue));
     store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
     store.register_late_pass(|_| Box::new(create_dir::CreateDir));
     store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
@@ -758,7 +760,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(conf)));
     store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit));
     store.register_late_pass(move |_| Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new(conf)));
-    store.register_late_pass(|_| Box::new(non_canonical_impls::NonCanonicalImpls));
+    store.register_late_pass(|tcx| Box::new(non_canonical_impls::NonCanonicalImpls::new(tcx)));
     store.register_late_pass(move |_| Box::new(single_call_fn::SingleCallFn::new(conf)));
     store.register_early_pass(move || Box::new(raw_strings::RawStrings::new(conf)));
     store.register_late_pass(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(conf)));
@@ -825,5 +827,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
     store.register_late_pass(|_| Box::new(infallible_try_from::InfallibleTryFrom));
     store.register_late_pass(|_| Box::new(coerce_container_to_any::CoerceContainerToAny));
     store.register_late_pass(|_| Box::new(toplevel_ref_arg::ToplevelRefArg));
+    store.register_late_pass(|_| Box::new(volatile_composites::VolatileComposites));
+    store.register_late_pass(|_| Box::new(replace_box::ReplaceBox));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index d8b186b..519ec22 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -184,7 +184,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
     }
 }
 
-#[allow(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments)]
 fn check_fn_inner<'tcx>(
     cx: &LateContext<'tcx>,
     sig: &'tcx FnSig<'_>,
@@ -540,7 +540,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
     false
 }
 
-#[allow(clippy::struct_excessive_bools)]
+#[expect(clippy::struct_excessive_bools)]
 struct Usage {
     lifetime: Lifetime,
     in_where_predicate: bool,
diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
index 14ccb6f..65e922a 100644
--- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
@@ -1,8 +1,8 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id, sym};
+use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
+use clippy_utils::sym;
 use rustc_errors::Applicability;
 use rustc_hir::{Body, Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -73,10 +73,13 @@ pub fn new(conf: &Conf) -> Self {
 impl LateLintPass<'_> for LinesFilterMapOk {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind
-            && is_trait_method(cx, expr, sym::Iterator)
+            && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
             && let fm_method_name = fm_method.ident.name
             && matches!(fm_method_name, sym::filter_map | sym::flat_map | sym::flatten)
-            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines)
+            && cx
+                .typeck_results()
+                .expr_ty_adjusted(fm_receiver)
+                .is_diag_item(cx, sym::IoLines)
             && should_lint(cx, fm_args, fm_method_name)
             && self.msrv.meets(cx, msrvs::MAP_WHILE)
         {
@@ -117,10 +120,15 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_name: Symbol) ->
                         params: [param], value, ..
                     } = cx.tcx.hir_body(*body)
                         && let ExprKind::MethodCall(method, receiver, [], _) = value.kind
-                        && path_to_local_id(receiver, param.pat.hir_id)
-                        && let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
                     {
-                        is_diag_item_method(cx, method_did, sym::Result) && method.ident.name == sym::ok
+                        method.ident.name == sym::ok
+                            && receiver.res_local_id() == Some(param.pat.hir_id)
+                            && cx
+                                .typeck_results()
+                                .type_dependent_def_id(value.hir_id)
+                                .opt_parent(cx)
+                                .opt_impl_ty(cx)
+                                .is_diag_item(cx, sym::Result)
                     } else {
                         false
                     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs b/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs
index a702e60..7acf2a5 100644
--- a/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs
@@ -1,9 +1,9 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{eq_expr_value, higher, path_to_local_id, sym};
+use clippy_utils::{eq_expr_value, higher, sym};
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::{Expr, ExprKind, LangItem, Node, Pat, PatKind};
 use rustc_lint::LateContext;
@@ -49,7 +49,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr
         {
             // Destructured iterator element `(idx, _)`, look for uses of the binding
             for_each_expr(cx, body, |expr| {
-                if path_to_local_id(expr, binding_id) {
+                if expr.res_local_id() == Some(binding_id) {
                     check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv);
                 }
                 CONTINUE
@@ -58,7 +58,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr
             // Bound as a tuple, look for `tup.0`
             for_each_expr(cx, body, |expr| {
                 if let ExprKind::Field(e, field) = expr.kind
-                    && path_to_local_id(e, binding_id)
+                    && e.res_local_id() == Some(binding_id)
                     && field.name == sym::integer(0)
                 {
                     check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv);
@@ -81,7 +81,7 @@ fn check_index_usage<'tcx>(
         return;
     };
 
-    let is_string_like = |ty: Ty<'_>| ty.is_str() || is_type_lang_item(cx, ty, LangItem::String);
+    let is_string_like = |ty: Ty<'_>| ty.is_str() || ty.is_lang_item(cx, LangItem::String);
     let message = match parent_expr.kind {
         ExprKind::MethodCall(segment, recv, ..)
             // We currently only lint `str` methods (which `String` can deref to), so a `.is_str()` check is sufficient here
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs
index 4aa1c2e..daca78e 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs
@@ -1,6 +1,6 @@
 use super::EXPLICIT_INTO_ITER_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
@@ -43,7 +43,11 @@ fn display(self) -> &'static str {
 }
 
 pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>) {
-    if !is_trait_method(cx, call_expr, sym::IntoIterator) {
+    if !cx
+        .ty_based_def(call_expr)
+        .opt_parent(cx)
+        .is_diag_item(cx, sym::IntoIterator)
+    {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index af475c4..40d1d36 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -1,10 +1,11 @@
 use super::EXPLICIT_ITER_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::sym;
 use clippy_utils::ty::{
-    implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection,
+    implements_trait, implements_trait_with_env, is_copy, make_normalized_projection,
     make_normalized_projection_with_regions, normalize_with_regions,
 };
 use rustc_errors::Applicability;
@@ -127,8 +128,7 @@ fn is_ref_iterable<'tcx>(
         let self_ty = typeck.expr_ty(self_arg);
         let self_is_copy = is_copy(cx, self_ty);
 
-        if is_type_lang_item(cx, self_ty.peel_refs(), rustc_hir::LangItem::OwnedBox)
-            && !msrv.meets(cx, msrvs::BOX_INTO_ITER)
+        if self_ty.peel_refs().is_lang_item(cx, rustc_hir::LangItem::OwnedBox) && !msrv.meets(cx, msrvs::BOX_INTO_ITER)
         {
             return None;
         }
diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
index e314bc2..c6b650a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
@@ -1,7 +1,7 @@
 use super::FOR_KV_MAP;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{pat_is_wild, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
@@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
             _ => arg,
         };
 
-        if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) {
+        if ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap) {
             span_lint_and_then(
                 cx,
                 FOR_KV_MAP,
diff --git a/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs b/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs
index b8a2638..8a4644c 100644
--- a/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/iter_next_loop.rs
@@ -1,12 +1,12 @@
 use super::ITER_NEXT_LOOP;
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_span::sym;
 
 pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) {
-    if is_trait_method(cx, arg, sym::Iterator) {
+    if cx.ty_based_def(arg).opt_parent(cx).is_diag_item(cx, sym::Iterator) {
         span_lint(
             cx,
             ITER_NEXT_LOOP,
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
index f99989e..c38cf83 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
@@ -1,12 +1,12 @@
 use super::MANUAL_FIND;
 use super::utils::make_iterator_snippet;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::usage::contains_return_break_continue_macro;
-use clippy_utils::{higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt};
+use clippy_utils::{higher, peel_blocks_with_stmt};
 use rustc_errors::Applicability;
-use rustc_hir::def::Res;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::LateContext;
@@ -34,8 +34,8 @@ pub(super) fn check<'tcx>(
         && let StmtKind::Semi(semi) = stmt.kind
         && let ExprKind::Ret(Some(ret_value)) = semi.kind
         && let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind
-        && is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome)
-        && path_res(cx, inner_ret) == Res::Local(binding_id)
+        && ctor.res(cx).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
+        && inner_ret.res_local_id() == Some(binding_id)
         && !contains_return_break_continue_macro(cond)
         && let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr)
     {
@@ -150,7 +150,7 @@ fn extract<'tcx>(block: &Block<'tcx>) -> Option<(&'tcx Stmt<'tcx>, &'tcx Expr<'t
         && let Some((_, Node::Block(block))) = parent_iter.next()
         && let Some((last_stmt, last_ret)) = extract(block)
         && last_stmt.hir_id == node_hir
-        && is_res_lang_ctor(cx, path_res(cx, last_ret), LangItem::OptionNone)
+        && last_ret.res(cx).ctor_parent(cx).is_lang_item(cx, LangItem::OptionNone)
         && let Some((_, Node::Expr(_block))) = parent_iter.next()
         // This includes the function header
         && let Some((_, func)) = parent_iter.next()
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index ddb8bb5..96de118 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -2,9 +2,10 @@
 use super::utils::make_iterator_snippet;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_applicability};
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{higher, is_refutable, path_to_local_id, peel_blocks_with_stmt, span_contains_comment};
+use clippy_utils::{higher, is_refutable, peel_blocks_with_stmt, span_contains_comment};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, Pat, PatKind};
@@ -27,7 +28,7 @@ pub(super) fn check<'tcx>(
             = higher::IfLet::hir(cx, inner_expr)
         // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
         && let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind
-        && path_to_local_id(let_expr, pat_hir_id)
+        && let_expr.res_local_id() == Some(pat_hir_id)
         // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
         && let PatKind::TupleStruct(ref qpath, [inner_pat], _) = let_pat.kind
         && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id)
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index d9c4b52..a2da43c 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -1,10 +1,11 @@
 use super::{IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY};
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::snippet;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_copy;
 use clippy_utils::usage::local_used_in;
-use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg};
+use clippy_utils::{get_enclosing_block, higher, sugg};
 use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::walk_block;
@@ -67,7 +68,7 @@ pub(super) fn check<'tcx>(
                             && !local_used_in(cx, canonical_id, base_left)
                             && !local_used_in(cx, canonical_id, base_right)
 							// Source and destination must be different
-                            && path_to_local(base_left) != path_to_local(base_right)
+                            && base_left.res_local_id() != base_right.res_local_id()
                     {
                         Some((
                             ty,
@@ -128,7 +129,7 @@ fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> {
     let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
         if let ExprKind::MethodCall(method, recv, [], _) = end.kind
             && method.ident.name == sym::len
-            && path_to_local(recv) == path_to_local(base)
+            && recv.res_local_id() == base.res_local_id()
         {
             if sugg.to_string() == end_str {
                 sugg::EMPTY.into()
@@ -364,7 +365,7 @@ fn get_details_from_idx<'tcx>(
     starts: &[Start<'tcx>],
 ) -> Option<(StartKind<'tcx>, Offset)> {
     fn get_start<'tcx>(e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option<StartKind<'tcx>> {
-        let id = path_to_local(e)?;
+        let id = e.res_local_id()?;
         starts.iter().find(|start| start.id == id).map(|start| start.kind)
     }
 
@@ -425,7 +426,7 @@ fn get_assignments<'a, 'tcx>(
         .chain(*expr)
         .filter(move |e| {
             if let ExprKind::AssignOp(_, place, _) = e.kind {
-                path_to_local(place).is_some_and(|id| {
+                place.res_local_id().is_some_and(|id| {
                     !loop_counters
                         .iter()
                         // skip the first item which should be `StartKind::Range`
diff --git a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
index 8a2d003..d5dbcbe 100644
--- a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
@@ -1,7 +1,7 @@
 use super::MISSING_SPIN_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::std_or_core;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -40,7 +40,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
         && let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind
         && [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name)
         && let callee_ty = cx.typeck_results().expr_ty(callee)
-        && is_type_diagnostic_item(cx, callee_ty, sym::AtomicBool)
+        && callee_ty.is_diag_item(cx, sym::AtomicBool)
         && let Some(std_or_core) = std_or_core(cx)
     {
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 01c36b8..a064a59 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -861,6 +861,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // check for `loop { if let {} else break }` that could be `while let`
         // (also matches an explicit "match" instead of "if let")
         // (even if the "match" or "if let" is used for declaration)
+        // (also matches on `let {} else break`)
         if let ExprKind::Loop(block, label, LoopSource::Loop, _) = expr.kind {
             // also check for empty `loop {}` statements, skipping those in #[panic_handler]
             empty_loop::check(cx, expr, block);
@@ -870,7 +871,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
         while_let_on_iterator::check(cx, expr);
 
-        if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
+        if let Some(higher::While {
+            condition, body, span, ..
+        }) = higher::While::hir(expr)
+        {
             while_immutable_condition::check(cx, condition, body);
             while_float::check(cx, condition);
             missing_spin_loop::check(cx, condition, body);
@@ -880,7 +884,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 }
 
 impl Loops {
-    #[allow(clippy::too_many_arguments)]
+    #[expect(clippy::too_many_arguments)]
     fn check_for_loop<'tcx>(
         &self,
         cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index 70ca452..daeda22 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -1,6 +1,7 @@
 use super::MUT_RANGE_BOUND;
 use clippy_utils::diagnostics::span_lint_and_note;
-use clippy_utils::{get_enclosing_block, higher, path_to_local};
+use clippy_utils::res::MaybeResPath;
+use clippy_utils::{get_enclosing_block, higher};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Node, PatKind};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
@@ -39,7 +40,7 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option<Span>) {
 }
 
 fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId> {
-    if let Some(hir_id) = path_to_local(bound)
+    if let Some(hir_id) = bound.res_local_id()
         && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
         && let PatKind::Binding(BindingMode::MUT, ..) = pat.kind
     {
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 544c3c3..528cc64 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -240,7 +240,7 @@ fn is_label_for_block(cx: &LateContext<'_>, dest: &Destination) -> bool {
         .is_ok_and(|hir_id| matches!(cx.tcx.hir_node(hir_id), Node::Block(_)))
 }
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 fn never_loop_expr<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &Expr<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index e792edb..4135c63 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -1,9 +1,10 @@
 use super::SAME_ITEM_PUSH;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::Msrv;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{msrvs, path_to_local, std_or_core, sym};
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{msrvs, std_or_core, sym};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -125,7 +126,7 @@ fn should_lint(&self) -> bool {
         if !self.non_deterministic_expr
             && !self.multiple_pushes
             && let Some((vec, _, _)) = self.vec_push
-            && let Some(hir_id) = path_to_local(vec)
+            && let Some(hir_id) = vec.res_local_id()
         {
             !self.used_locals.contains(&hir_id)
         } else {
@@ -141,7 +142,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::If(..) => self.non_deterministic_expr = true,
             ExprKind::Block(block, _) => self.visit_block(block),
             _ => {
-                if let Some(hir_id) = path_to_local(expr) {
+                if let Some(hir_id) = expr.res_local_id() {
                     self.used_locals.insert(hir_id);
                 }
                 walk_expr(self, expr);
@@ -186,7 +187,7 @@ fn get_vec_push<'tcx>(
             && let ExprKind::MethodCall(path, self_expr, [pushed_item], _) = &semi_stmt.kind
             // Check that the method being called is push() on a Vec
             && path.ident.name == sym::push
-            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec)
+            && cx.typeck_results().expr_ty(self_expr).is_diag_item(cx, sym::Vec)
     {
         return Some((self_expr, pushed_item, semi_stmt.span.ctxt()));
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
index 13b93d2..b893b0b 100644
--- a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
@@ -1,7 +1,7 @@
 use super::UNUSED_ENUMERATE_INDEX;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{pat_is_wild, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::def::DefKind;
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_
         && let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind
         && let ty = cx.typeck_results().expr_ty(arg)
         && pat_is_wild(cx, &index.kind, body)
-        && is_type_diagnostic_item(cx, ty, sym::Enumerate)
+        && ty.is_diag_item(cx, sym::Enumerate)
         && let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id)
         && cx.tcx.is_diagnostic_item(sym::enumerate_method, call_id)
     {
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 2f6950b..56d535c 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -1,5 +1,6 @@
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::ty::{has_iter_method, implements_trait};
-use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg};
+use clippy_utils::{get_parent_expr, is_integer_const, sugg};
 use rustc_ast::ast::{LitIntType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_expr, walk_local};
@@ -47,7 +48,7 @@ pub(super) fn into_results(self) -> impl Iterator<Item = HirId> {
 impl<'tcx> Visitor<'tcx> for IncrementVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // If node is a variable
-        if let Some(def_id) = path_to_local(expr) {
+        if let Some(def_id) = expr.res_local_id() {
             if let Some(parent) = get_parent_expr(self.cx, expr) {
                 let state = self.states.entry(def_id).or_insert(IncrementVisitorVarState::Initial);
                 if *state == IncrementVisitorVarState::IncrOnce {
@@ -175,7 +176,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         }
 
         // If node is the desired variable, see how it's used
-        if path_to_local_id(expr, self.var_id) {
+        if expr.res_local_id() == Some(self.var_id) {
             if self.past_loop {
                 self.state = InitializeVisitorState::DontWarn;
                 return;
@@ -255,7 +256,7 @@ fn is_conditional(expr: &Expr<'_>) -> bool {
 
 /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the
 /// actual `Iterator` that the loop uses.
-pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String {
+pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applicability: &mut Applicability) -> String {
     let impls_iterator = cx
         .tcx
         .get_diagnostic_item(sym::Iterator)
@@ -263,7 +264,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
     if impls_iterator {
         format!(
             "{}",
-            sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_paren()
+            sugg::Sugg::hir_with_applicability(cx, arg, "_", applicability).maybe_paren()
         )
     } else {
         // (&x).into_iter() ==> x.iter()
@@ -281,12 +282,12 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
                 };
                 format!(
                     "{}.{method_name}()",
-                    sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_paren(),
+                    sugg::Sugg::hir_with_applicability(cx, caller, "_", applicability).maybe_paren(),
                 )
             },
             _ => format!(
                 "{}.into_iter()",
-                sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_paren()
+                sugg::Sugg::hir_with_applicability(cx, arg, "_", applicability).maybe_paren()
             ),
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
index 845edb9..d4285db 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
@@ -10,19 +10,19 @@
 use rustc_lint::LateContext;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
-    let (init, let_info) = match (loop_block.stmts, loop_block.expr) {
+    let (init, let_info, els) = match (loop_block.stmts, loop_block.expr) {
         ([stmt, ..], _) => match stmt.kind {
             StmtKind::Let(LetStmt {
                 init: Some(e),
-                els: None,
+                els,
                 pat,
                 ty,
                 ..
-            }) => (*e, Some((*pat, *ty))),
-            StmtKind::Semi(e) | StmtKind::Expr(e) => (e, None),
+            }) => (*e, Some((*pat, *ty)), *els),
+            StmtKind::Semi(e) | StmtKind::Expr(e) => (e, None, None),
             _ => return,
         },
-        ([], Some(e)) => (e, None),
+        ([], Some(e)) => (e, None, None),
         _ => return,
     };
     let has_trailing_exprs = loop_block.stmts.len() + usize::from(loop_block.expr.is_some()) > 1;
@@ -38,14 +38,26 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_blo
             if_let.let_expr,
             has_trailing_exprs,
             let_info,
-            if_let.if_then,
+            Some(if_let.if_then),
         );
+    } else if els.and_then(|x| x.expr).is_some_and(is_simple_break_expr)
+        && let Some((pat, _)) = let_info
+    {
+        could_be_while_let(cx, expr, pat, init, has_trailing_exprs, let_info, None);
     } else if let ExprKind::Match(scrutinee, [arm1, arm2], MatchSource::Normal) = init.kind
         && arm1.guard.is_none()
         && arm2.guard.is_none()
         && is_simple_break_expr(arm2.body)
     {
-        could_be_while_let(cx, expr, arm1.pat, scrutinee, has_trailing_exprs, let_info, arm1.body);
+        could_be_while_let(
+            cx,
+            expr,
+            arm1.pat,
+            scrutinee,
+            has_trailing_exprs,
+            let_info,
+            Some(arm1.body),
+        );
     }
 }
 
@@ -70,7 +82,7 @@ fn could_be_while_let<'tcx>(
     let_expr: &'tcx Expr<'_>,
     has_trailing_exprs: bool,
     let_info: Option<(&Pat<'_>, Option<&Ty<'_>>)>,
-    inner_expr: &Expr<'_>,
+    inner_expr: Option<&Expr<'_>>,
 ) {
     if has_trailing_exprs
         && (needs_ordered_drop(cx, cx.typeck_results().expr_ty(let_expr))
@@ -85,7 +97,7 @@ fn could_be_while_let<'tcx>(
     // 1) it was ugly with big bodies;
     // 2) it was not indented properly;
     // 3) it wasn’t very smart (see #675).
-    let inner_content = if let Some((pat, ty)) = let_info
+    let inner_content = if let Some(((pat, ty), inner_expr)) = let_info.zip(inner_expr)
         // Prevent trivial reassignments such as `let x = x;` or `let _ = …;`, but
         // keep them if the type has been explicitly specified.
         && (!is_trivial_assignment(pat, peel_blocks(inner_expr)) || ty.is_some())
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index 6000ff7..3ea6ba3 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -2,9 +2,10 @@
 
 use super::WHILE_LET_ON_ITERATOR;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::visitors::is_res_used;
-use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable, is_res_lang_ctor, is_trait_method};
+use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::{Visitor, walk_expr};
@@ -19,11 +20,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     if let Some(higher::WhileLet { if_then, let_pat, let_expr, label, .. }) = higher::WhileLet::hir(expr)
         // check for `Some(..)` pattern
         && let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind
-        && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
+        && cx.qpath_res(pat_path, let_pat.hir_id).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
         // check for call to `Iterator::next`
         && let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind
         && method_name.ident.name == sym::next
-        && is_trait_method(cx, let_expr, sym::Iterator)
+        && cx.ty_based_def(let_expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr)
         // get the loop containing the match expression
         && !uses_iter(cx, &iter_expr_struct, if_then)
diff --git a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
index 5814b68..22de5e8 100644
--- a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
@@ -2,9 +2,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::If;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::HasSession as _;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs};
+use clippy_utils::ty::peel_and_count_ty_refs;
 use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
@@ -104,7 +105,7 @@ impl ManualAbsDiff {
     fn are_ty_eligible<'tcx>(&self, cx: &LateContext<'tcx>, a: &Expr<'_>, b: &Expr<'_>) -> Option<(Ty<'tcx>, usize)> {
         let is_int = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) && self.msrv.meets(cx, msrvs::ABS_DIFF);
         let is_duration =
-            |ty| is_type_diagnostic_item(cx, ty, sym::Duration) && self.msrv.meets(cx, msrvs::DURATION_ABS_DIFF);
+            |ty: Ty<'_>| ty.is_diag_item(cx, sym::Duration) && self.msrv.meets(cx, msrvs::DURATION_ABS_DIFF);
 
         let a_ty = cx.typeck_results().expr_ty(a).peel_refs();
         let (b_ty, b_n_refs, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(b));
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 76cb228..c34e0d3 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{is_panic, root_macro_call};
+use clippy_utils::source::{indent_of, reindent_multiline};
 use clippy_utils::{higher, is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -50,32 +51,32 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
             // Should this have a config value?
             && !is_else_clause(cx.tcx, expr)
         {
-            let mut applicability = Applicability::MachineApplicable;
-            let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
-            if !comments.is_empty() {
-                comments += "\n";
-            }
-            let cond_sugg = !sugg::Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "..", &mut applicability);
-            let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" };
-            let sugg = format!("assert!({cond_sugg}, {format_args_snip}){semicolon}");
-            // we show to the user the suggestion without the comments, but when applying the fix, include the
-            // comments in the block
             span_lint_and_then(
                 cx,
                 MANUAL_ASSERT,
                 expr.span,
                 "only a `panic!` in `if`-then statement",
                 |diag| {
-                    // comments can be noisy, do not show them to the user
+                    let mut applicability = Applicability::MachineApplicable;
+                    let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
                     if !comments.is_empty() {
-                        diag.tool_only_span_suggestion(
-                            expr.span.shrink_to_lo(),
-                            "add comments back",
-                            comments,
-                            applicability,
-                        );
+                        comments += "\n";
                     }
-                    diag.span_suggestion(expr.span, "try instead", sugg, applicability);
+                    let cond_sugg = !sugg::Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "..", &mut applicability);
+                    let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" };
+
+                    let indent = indent_of(cx, expr.span);
+                    let full_sugg = reindent_multiline(
+                        format!("{comments}assert!({cond_sugg}, {format_args_snip}){semicolon}").as_str(),
+                        true,
+                        indent,
+                    );
+                    diag.span_suggestion_verbose(
+                        expr.span,
+                        "replace `if`-then-`panic!` with `assert!`",
+                        full_sugg,
+                        applicability,
+                    );
                 },
             );
         }
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index 42fe386..54387e3 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -3,13 +3,11 @@
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::higher::If;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::visitors::is_const_evaluatable;
-use clippy_utils::{
-    MaybePath, eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id,
-    peel_blocks, peel_blocks_with_stmt, sym,
-};
+use clippy_utils::{eq_expr_value, is_in_const_context, peel_blocks, peel_blocks_with_stmt, sym};
 use itertools::Itertools;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir::def::Res;
@@ -292,10 +290,12 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx
 /// # ;
 /// ```
 fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<ClampSuggestion<'tcx>> {
-    if let ExprKind::MethodCall(seg_second, receiver, [arg_second], _) = &expr.kind
-        && (cx.typeck_results().expr_ty_adjusted(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord))
+    if let ExprKind::MethodCall(seg_second, receiver, [arg_second], _) = expr.kind
+        && (cx.typeck_results().expr_ty_adjusted(receiver).is_floating_point()
+            || cx.ty_based_def(expr).assoc_fn_parent(cx).is_diag_item(cx, sym::Ord))
         && let ExprKind::MethodCall(seg_first, input, [arg_first], _) = &receiver.kind
-        && (cx.typeck_results().expr_ty_adjusted(input).is_floating_point() || is_trait_method(cx, receiver, sym::Ord))
+        && (cx.typeck_results().expr_ty_adjusted(input).is_floating_point()
+            || cx.ty_based_def(receiver).assoc_fn_parent(cx).is_diag_item(cx, sym::Ord))
     {
         let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point();
         let (min, max) = match (seg_first.ident.name, seg_second.ident.name) {
@@ -331,18 +331,18 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
     fn segment<'tcx>(cx: &LateContext<'_>, func: &Expr<'tcx>) -> Option<FunctionType<'tcx>> {
         match func.kind {
             ExprKind::Path(QPath::Resolved(None, path)) => {
-                let id = path.res.opt_def_id()?;
-                match cx.tcx.get_diagnostic_name(id) {
+                let def = path.res.opt_def(cx)?;
+                match cx.tcx.get_diagnostic_name(def.1) {
                     Some(sym::cmp_min) => Some(FunctionType::CmpMin),
                     Some(sym::cmp_max) => Some(FunctionType::CmpMax),
-                    _ if is_diag_trait_item(cx, id, sym::Ord) => {
+                    _ if def.assoc_fn_parent(cx).is_diag_item(cx, sym::Ord) => {
                         Some(FunctionType::OrdOrFloat(path.segments.last().expect("infallible")))
                     },
                     _ => None,
                 }
             },
             ExprKind::Path(QPath::TypeRelative(ty, seg)) => {
-                matches!(path_res(cx, ty), Res::PrimTy(PrimTy::Float(_))).then(|| FunctionType::OrdOrFloat(seg))
+                matches!(ty.basic_res(), Res::PrimTy(PrimTy::Float(_))).then(|| FunctionType::OrdOrFloat(seg))
             },
             _ => None,
         }
@@ -435,7 +435,7 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt
         let first = BinaryOp::new(first)?;
         let second = BinaryOp::new(second)?;
         if let PatKind::Binding(_, binding, _, None) = &last_arm.pat.kind
-            && path_to_local_id(peel_blocks_with_stmt(last_arm.body), *binding)
+            && peel_blocks_with_stmt(last_arm.body).res_local_id() == Some(*binding)
             && last_arm.guard.is_none()
         {
             // Proceed as normal
@@ -516,7 +516,7 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) ->
                     },
                     span: first_expr.span.to(second_expr.span),
                     make_assignment: Some(maybe_input_first_path),
-                    hir_with_ignore_attr: Some(first_expr.hir_id()),
+                    hir_with_ignore_attr: Some(first_expr.hir_id),
                 })
             } else {
                 None
@@ -655,8 +655,8 @@ fn check<'tcx>(
                 let (min, max) = (second_expr, first_expr);
                 let refers_to_input = match input_hir_ids {
                     Some((first_hir_id, second_hir_id)) => {
-                        path_to_local_id(peel_blocks(first_bin.left), first_hir_id)
-                            && path_to_local_id(peel_blocks(second_bin.left), second_hir_id)
+                        peel_blocks(first_bin.left).res_local_id() == Some(first_hir_id)
+                            && peel_blocks(second_bin.left).res_local_id() == Some(second_hir_id)
                     },
                     None => eq_expr_value(cx, first_bin.left, second_bin.left),
                 };
diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
index ed0cce7..ee53174 100644
--- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
@@ -1,7 +1,6 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg::{Sugg, has_enclosing_paren};
 use clippy_utils::{SpanlessEq, sym};
 use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp};
@@ -165,6 +164,7 @@ fn build_suggestion(
     applicability: &mut Applicability,
 ) {
     let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_paren();
+    let rhs_ty = cx.typeck_results().expr_ty(rhs);
     let type_suffix = if cx.typeck_results().expr_ty(lhs).is_numeric()
         && matches!(
             lhs.kind,
@@ -182,7 +182,7 @@ fn build_suggestion(
                 }
             )
         ) {
-        format!("_{}", cx.typeck_results().expr_ty(rhs))
+        format!("_{rhs_ty}")
     } else {
         String::new()
     };
@@ -199,9 +199,12 @@ fn build_suggestion(
     } else {
         format!("{dividend_sugg_str}{type_suffix}")
     };
-    let divisor_snippet = snippet_with_context(cx, rhs.span, expr.span.ctxt(), "..", applicability);
 
-    let sugg = format!("{suggestion_before_div_ceil}.div_ceil({})", divisor_snippet.0);
+    // Dereference the RHS if it is a reference type
+    let divisor_snippet = match Sugg::hir_with_context(cx, rhs, expr.span.ctxt(), "_", applicability) {
+        sugg if rhs_ty.is_ref() => sugg.deref(),
+        sugg => sugg,
+    };
 
     span_lint_and_sugg(
         cx,
@@ -209,7 +212,7 @@ fn build_suggestion(
         expr.span,
         "manually reimplementing `div_ceil`",
         "consider using `.div_ceil()`",
-        sugg,
+        format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})"),
         *applicability,
     );
 }
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 60782f4..a81c4dc 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -1,9 +1,10 @@
 use clippy_config::Conf;
 use clippy_utils::consts::ConstEvalCtxt;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{is_from_proc_macro, path_to_local};
 use rustc_errors::Applicability;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -138,7 +139,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             // Checking all possible scenarios using a function would be a hopeless task, as we have
             // 16 possible alignments of constants/operands. For now, let's use `partition`.
             && let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
-            && exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2
+            && exprs.iter_mut().partition_in_place(|i| i.res_local_id().is_some()) == 2
             && !expr.span.in_external_macro(cx.sess().source_map())
             && (
                 is_not_const(cx.tcx, cx.tcx.hir_enclosing_body_owner(expr.hir_id).into())
@@ -149,7 +150,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             && let ctxt = expr.span.ctxt()
             && let Some(const_1) = ecx.eval_local(const_1, ctxt)
             && let Some(const_2) = ecx.eval_local(const_2, ctxt)
-            && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
+            && first.res_local_id().is_some_and(|f| second.res_local_id().is_some_and(|s| f == s))
             // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
             // case somebody does that for some reason
             && (const_1.is_pos_infinity() && const_2.is_neg_infinity()
diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
index b3ee45c..ccb8d42 100644
--- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
@@ -1,9 +1,10 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
 use clippy_utils::source::SpanRangeExt;
+use clippy_utils::sym;
 use clippy_utils::visitors::{is_local_used, local_used_once};
-use clippy_utils::{is_trait_method, path_to_local_id, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{BindingMode, ExprKind, LetStmt, Node, PatKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -81,8 +82,8 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) {
             && !hash_expr.span.from_expansion()
             && let ExprKind::MethodCall(seg, hashed_value, [ref_to_hasher], _) = hash_expr.kind
             && seg.ident.name == sym::hash
-            && is_trait_method(cx, hash_expr, sym::Hash)
-            && path_to_local_id(ref_to_hasher.peel_borrows(), hasher)
+            && cx.ty_based_def(hash_expr).opt_parent(cx).is_diag_item(cx, sym::Hash)
+            && ref_to_hasher.peel_borrows().res_local_id() == Some(hasher)
 
             && let maybe_finish_stmt = stmts.next()
             // There should be no more statements referencing `hasher`
diff --git a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
index f7d9ec1..25057b4 100644
--- a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
@@ -1,8 +1,8 @@
 use crate::manual_ignore_case_cmp::MatchType::{Literal, ToAscii};
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sym;
-use clippy_utils::ty::{get_type_diagnostic_name, is_type_diagnostic_item, is_type_lang_item};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::ExprKind::{Binary, Lit, MethodCall};
@@ -58,7 +58,7 @@ fn get_ascii_type<'a>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'_>) -> Op
         if needs_ref_to_cmp(cx, ty)
             || ty.is_str()
             || ty.is_slice()
-            || matches!(get_type_diagnostic_name(cx, ty), Some(sym::OsStr | sym::OsString))
+            || matches!(ty.opt_diag_name(cx), Some(sym::OsStr | sym::OsString))
         {
             return Some((expr.span, ToAscii(is_lower, ty_raw)));
         }
@@ -72,8 +72,8 @@ fn get_ascii_type<'a>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'_>) -> Op
 fn needs_ref_to_cmp(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     ty.is_char()
         || *ty.kind() == ty::Uint(UintTy::U8)
-        || is_type_diagnostic_item(cx, ty, sym::Vec)
-        || is_type_lang_item(cx, ty, LangItem::String)
+        || ty.is_diag_item(cx, sym::Vec)
+        || ty.is_lang_item(cx, LangItem::String)
 }
 
 impl LateLintPass<'_> for ManualIgnoreCaseCmp {
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index 2eebb24..8c6abbe 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -2,8 +2,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators, sym};
+use clippy_utils::{higher, is_in_const_context, peel_ref_operators, sym};
 use rustc_ast::LitKind::{Byte, Char};
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
@@ -125,7 +126,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 }
 
 fn get_ty_sugg<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'_>) -> Option<(Span, Ty<'tcx>)> {
-    let local_hid = path_to_local(arg)?;
+    let local_hid = arg.res_local_id()?;
     if let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid)
         // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given
         && ty_span == span
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 2705ef2..298bf10 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -2,16 +2,14 @@
 use clippy_config::types::MatchLintBehaviour;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLetOrMatch;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{
-    MaybePath, is_lint_allowed, is_never_expr, is_wild, msrvs, pat_and_expr_can_be_question_mark, path_res, peel_blocks,
-};
+use clippy_utils::{is_lint_allowed, is_never_expr, is_wild, msrvs, pat_and_expr_can_be_question_mark, peel_blocks};
 use rustc_ast::BindingMode;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorOf, DefKind, Res};
-use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{Arm, Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_span::Span;
 use rustc_span::symbol::{Symbol, sym};
@@ -131,39 +129,25 @@ fn is_arms_disjointed(cx: &LateContext<'_>, arm1: &Arm<'_>, arm2: &Arm<'_>) -> b
 
 /// Returns `true` if the given pattern is a variant of an enum.
 pub fn is_enum_variant(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
-    struct Pat<'hir>(&'hir rustc_hir::Pat<'hir>);
-
-    impl<'hir> MaybePath<'hir> for Pat<'hir> {
-        fn qpath_opt(&self) -> Option<&QPath<'hir>> {
-            match self.0.kind {
-                PatKind::Struct(ref qpath, fields, _)
-                    if fields
-                        .iter()
-                        .all(|field| is_wild(field.pat) || matches!(field.pat.kind, PatKind::Binding(..))) =>
-                {
-                    Some(qpath)
-                },
-                PatKind::TupleStruct(ref qpath, pats, _)
-                    if pats
-                        .iter()
-                        .all(|pat| is_wild(pat) || matches!(pat.kind, PatKind::Binding(..))) =>
-                {
-                    Some(qpath)
-                },
-                PatKind::Expr(&PatExpr {
-                    kind: PatExprKind::Path(ref qpath),
-                    ..
-                }) => Some(qpath),
-                _ => None,
-            }
-        }
-
-        fn hir_id(&self) -> HirId {
-            self.0.hir_id
-        }
-    }
-
-    let res = path_res(cx, &Pat(pat));
+    let path = match pat.kind {
+        PatKind::Struct(ref qpath, fields, _)
+            if fields
+                .iter()
+                .all(|field| is_wild(field.pat) || matches!(field.pat.kind, PatKind::Binding(..))) =>
+        {
+            (qpath, pat.hir_id)
+        },
+        PatKind::TupleStruct(ref qpath, pats, _)
+            if pats
+                .iter()
+                .all(|pat| is_wild(pat) || matches!(pat.kind, PatKind::Binding(..))) =>
+        {
+            (qpath, pat.hir_id)
+        },
+        PatKind::Expr(e) if let Some((qpath, id)) = e.opt_qpath() => (qpath, id),
+        _ => return false,
+    };
+    let res = path.res(cx);
     matches!(
         res,
         Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(CtorOf::Variant, _), _)
@@ -384,7 +368,7 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo
         }
         let ty = typeck_results.pat_ty(pat);
         // Option and Result are allowed, everything else isn't.
-        if !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) {
+        if !(ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result)) {
             has_disallowed = true;
         }
     });
diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
index f54ccf2..e78f6af 100644
--- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
@@ -1,7 +1,8 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::{is_trait_method, peel_hir_expr_refs};
+use clippy_utils::peel_hir_expr_refs;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind, Mutability, QPath};
@@ -52,7 +53,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
             && path.ident.name == sym::to_string
             && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind
             && let Res::Def(DefKind::Const, receiver_def_id) = path.res
-            && is_trait_method(cx, target, sym::ToString)
+            && cx.ty_based_def(target).opt_parent(cx).is_diag_item(cx, sym::ToString)
             && cx.tcx.is_diagnostic_item(sym::path_main_separator, receiver_def_id)
             && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind()
             && ty.is_str()
diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
index b036e78..63f6d89 100644
--- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
@@ -1,6 +1,7 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::msrvs::Msrv;
+use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
 use clippy_utils::{is_none_pattern, msrvs, peel_hir_expr_refs, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -189,7 +190,7 @@ fn check_arms(cx: &LateContext<'_>, none_arm: &Arm<'_>, some_arm: &Arm<'_>) -> b
 
 fn returns_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match expr.kind {
-        ExprKind::Path(_) => clippy_utils::is_path_diagnostic_item(cx, expr, sym::default_fn),
+        ExprKind::Path(_) => expr.res(cx).is_diag_item(cx, sym::default_fn),
         ExprKind::Closure(cl) => is_empty_slice(cx, cx.tcx.hir_body(cl.body).value),
         _ => false,
     }
@@ -214,11 +215,11 @@ fn is_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
             _ => false,
         },
         ExprKind::Array([]) => true,
-        ExprKind::Call(def, []) => clippy_utils::is_path_diagnostic_item(cx, def, sym::default_fn),
+        ExprKind::Call(def, []) => def.res(cx).is_diag_item(cx, sym::default_fn),
         _ => false,
     }
 }
 
 fn is_slice_from_ref(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    clippy_utils::is_path_diagnostic_item(cx, expr, sym::slice_from_ref)
+    expr.basic_res().is_diag_item(cx, sym::slice_from_ref)
 }
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index 1e91a42..d993ed4 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -1,9 +1,10 @@
 use clippy_config::Conf;
 use clippy_utils::consts::{ConstEvalCtxt, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_in_const_context;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::{is_in_const_context, path_to_local};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -64,7 +65,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             && let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind
             && rem2_op.node == BinOpKind::Rem
             && const1 == const2
-            && let Some(hir_id) = path_to_local(rem2_lhs)
+            && let Some(hir_id) = rem2_lhs.res_local_id()
             && let Some(const3) = check_for_unsigned_int_constant(cx, ctxt, rem2_rhs)
             // Also ensures the const is nonzero since zero can't be a divisor
             && const2 == const3
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 7fb8876..674f0da 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -2,8 +2,8 @@
 use clippy_utils::SpanlessEq;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::ExprKind::Assign;
@@ -189,7 +189,7 @@ fn check_to_owned(
         && let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
         && cx.tcx.is_diagnostic_item(sym::str_chars, chars_expr_def_id)
         && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
-        && is_type_lang_item(cx, ty, hir::LangItem::String)
+        && ty.is_lang_item(cx, hir::LangItem::String)
         && SpanlessEq::new(cx).eq_expr(left_expr, str_expr)
         && let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind
         && let hir::ExprKind::Closure(closure) = closure_expr.kind
@@ -250,7 +250,7 @@ fn match_acceptable_sym(cx: &LateContext<'_>, collect_def_id: DefId) -> bool {
 
 fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Msrv) -> bool {
     let ty = cx.typeck_results().expr_ty(expr).peel_refs();
-    let required = match get_type_diagnostic_name(cx, ty) {
+    let required = match ty.opt_diag_name(cx) {
         Some(sym::BinaryHeap) => msrvs::BINARY_HEAP_RETAIN,
         Some(sym::BTreeSet) => msrvs::BTREE_SET_RETAIN,
         Some(sym::BTreeMap) => msrvs::BTREE_MAP_RETAIN,
@@ -264,7 +264,7 @@ fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Msrv)
 
 fn match_map_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr).peel_refs();
-    matches!(get_type_diagnostic_name(cx, ty), Some(sym::BTreeMap | sym::HashMap))
+    matches!(ty.opt_diag_name(cx), Some(sym::BTreeMap | sym::HashMap))
 }
 
 fn make_span_lint_and_sugg(cx: &LateContext<'_>, span: Span, sugg: String) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_rotate.rs b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
index 22e3407..e8db446 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rotate.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
@@ -56,20 +56,14 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     }
 }
 
-fn parse_shift<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'tcx>,
-) -> Option<(ShiftDirection, u128, &'tcx Expr<'tcx>)> {
+fn parse_shift<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(ShiftDirection, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
     if let ExprKind::Binary(op, l, r) = expr.kind {
         let dir = match op.node {
             BinOpKind::Shl => ShiftDirection::Left,
             BinOpKind::Shr => ShiftDirection::Right,
             _ => return None,
         };
-        let const_expr = ConstEvalCtxt::new(cx).eval_local(r, expr.span.ctxt())?;
-        if let Constant::Int(shift) = const_expr {
-            return Some((dir, shift, l));
-        }
+        return Some((dir, l, r));
     }
     None
 }
@@ -78,40 +72,62 @@ impl LateLintPass<'_> for ManualRotate {
     fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         if let ExprKind::Binary(op, l, r) = expr.kind
             && let BinOpKind::Add | BinOpKind::BitOr = op.node
-            && let Some((l_shift_dir, l_amount, l_expr)) = parse_shift(cx, l)
-            && let Some((r_shift_dir, r_amount, r_expr)) = parse_shift(cx, r)
-        {
-            if l_shift_dir == r_shift_dir {
-                return;
-            }
-            if !clippy_utils::eq_expr_value(cx, l_expr, r_expr) {
-                return;
-            }
-            let Some(bit_width) = (match cx.typeck_results().expr_ty(expr).kind() {
+            && let Some((l_shift_dir, l_expr, l_amount)) = parse_shift(l)
+            && let Some((r_shift_dir, r_expr, r_amount)) = parse_shift(r)
+            && l_shift_dir != r_shift_dir
+            && clippy_utils::eq_expr_value(cx, l_expr, r_expr)
+            && let Some(bit_width) = match cx.typeck_results().expr_ty(expr).kind() {
                 ty::Int(itype) => itype.bit_width(),
                 ty::Uint(itype) => itype.bit_width(),
                 _ => return,
-            }) else {
-                return;
-            };
-            if l_amount + r_amount == u128::from(bit_width) {
-                let (shift_function, amount) = if l_amount < r_amount {
+            }
+        {
+            let const_eval = ConstEvalCtxt::new(cx);
+
+            let ctxt = expr.span.ctxt();
+            let (shift_function, amount) = if let Some(Constant::Int(l_amount_val)) =
+                const_eval.eval_local(l_amount, ctxt)
+                && let Some(Constant::Int(r_amount_val)) = const_eval.eval_local(r_amount, ctxt)
+                && l_amount_val + r_amount_val == u128::from(bit_width)
+            {
+                if l_amount_val < r_amount_val {
                     (l_shift_dir, l_amount)
                 } else {
                     (r_shift_dir, r_amount)
+                }
+            } else {
+                let (amount1, binop, minuend, amount2, shift_direction) = match (l_amount.kind, r_amount.kind) {
+                    (_, ExprKind::Binary(binop, minuend, other)) => (l_amount, binop, minuend, other, l_shift_dir),
+                    (ExprKind::Binary(binop, minuend, other), _) => (r_amount, binop, minuend, other, r_shift_dir),
+                    _ => return,
                 };
-                let mut applicability = Applicability::MachineApplicable;
-                let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_paren();
-                span_lint_and_sugg(
-                    cx,
-                    MANUAL_ROTATE,
-                    expr.span,
-                    "there is no need to manually implement bit rotation",
-                    "this expression can be rewritten as",
-                    format!("{expr_sugg}.{shift_function}({amount})"),
-                    Applicability::MachineApplicable,
-                );
-            }
+
+                if let Some(Constant::Int(minuend)) = const_eval.eval_local(minuend, ctxt)
+                    && clippy_utils::eq_expr_value(cx, amount1, amount2)
+                    // (x << s) | (x >> bit_width - s)
+                    && ((binop.node == BinOpKind::Sub && u128::from(bit_width) == minuend)
+                        // (x << s) | (x >> (bit_width - 1) ^ s)
+                        || (binop.node == BinOpKind::BitXor && u128::from(bit_width).checked_sub(minuend) == Some(1)))
+                {
+                    // NOTE: we take these from the side that _doesn't_ have the binop, since it's probably simpler
+                    (shift_direction, amount1)
+                } else {
+                    return;
+                }
+            };
+
+            let mut applicability = Applicability::MachineApplicable;
+            let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_paren();
+            let amount = sugg::Sugg::hir_with_applicability(cx, amount, "_", &mut applicability);
+            span_lint_and_sugg(
+                cx,
+                MANUAL_ROTATE,
+                expr.span,
+                "there is no need to manually implement bit rotation",
+                "this expression can be rewritten as",
+                format!("{expr_sugg}.{shift_function}({amount})"),
+                Applicability::MachineApplicable,
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 39e5289..681dc2a 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{iter_input_pats, method_chain_args};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -205,9 +205,9 @@ fn lint_map_unit_fn(
 ) {
     let var_arg = &map_args.0;
 
-    let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
+    let (map_type, variant, lint) = if cx.typeck_results().expr_ty(var_arg).is_diag_item(cx, sym::Option) {
         ("Option", "Some", OPTION_MAP_UNIT_FN)
-    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Result) {
+    } else if cx.typeck_results().expr_ty(var_arg).is_diag_item(cx, sym::Result) {
         ("Result", "Ok", RESULT_MAP_UNIT_FN)
     } else {
         return;
diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
index e0cb5d1..fb83f7c 100644
--- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{higher, is_res_lang_ctor, sym};
+use clippy_utils::{higher, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -57,8 +57,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind //check is expr.ok() has type Result<T,E>.ok(, _)
             && let PatKind::TupleStruct(ref pat_path, [ok_pat], _)  = let_pat.kind //get operation
             && ok_path.ident.name == sym::ok
-            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
-            && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
+            && cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result)
+            && cx.qpath_res(pat_path, let_pat.hir_id).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
             && let ctxt = expr.span.ctxt()
             && let_expr.span.ctxt() == ctxt
             && let_pat.span.ctxt() == ctxt
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index aaf559f..79f737f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -1,18 +1,17 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::higher::IfLetOrMatch;
 use clippy_utils::msrvs::Msrv;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{
-    SpanlessEq, get_ref_operators, is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt,
-    peel_ref_operators,
-};
+use clippy_utils::{SpanlessEq, get_ref_operators, is_unit_expr, peel_blocks_with_stmt, peel_ref_operators};
 use rustc_ast::BorrowKind;
 use rustc_errors::MultiSpan;
 use rustc_hir::LangItem::OptionNone;
 use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatExpr, PatExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::Span;
+use rustc_span::symbol::Ident;
 
 use super::{COLLAPSIBLE_MATCH, pat_contains_disallowed_or};
 
@@ -35,7 +34,7 @@ pub(super) fn check_if_let<'tcx>(
     check_arm(cx, false, pat, let_expr, body, None, else_expr, msrv);
 }
 
-#[allow(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments)]
 fn check_arm<'tcx>(
     cx: &LateContext<'tcx>,
     outer_is_match: bool,
@@ -50,26 +49,28 @@ fn check_arm<'tcx>(
     if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr)
         && let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
             IfLetOrMatch::IfLet(scrutinee, pat, _, els, _) => Some((scrutinee, pat, els)),
-            IfLetOrMatch::Match(scrutinee, arms, ..) => if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none())
-                // if there are more than two arms, collapsing would be non-trivial
-                // one of the arms must be "wild-like"
-                && let Some(wild_idx) = arms.iter().rposition(|a| arm_is_wild_like(cx, a))
-            {
-                let (then, els) = (&arms[1 - wild_idx], &arms[wild_idx]);
-                Some((scrutinee, then.pat, Some(els.body)))
-            } else {
-                None
+            IfLetOrMatch::Match(scrutinee, arms, ..) => {
+                if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none())
+                    // if there are more than two arms, collapsing would be non-trivial
+                    // one of the arms must be "wild-like"
+                    && let Some(wild_idx) = arms.iter().rposition(|a| arm_is_wild_like(cx, a))
+                {
+                    let (then, els) = (&arms[1 - wild_idx], &arms[wild_idx]);
+                    Some((scrutinee, then.pat, Some(els.body)))
+                } else {
+                    None
+                }
             },
         }
         && outer_pat.span.eq_ctxt(inner_scrutinee.span)
         // match expression must be a local binding
         // match <local> { .. }
-        && let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee))
+        && let Some(binding_id) = peel_ref_operators(cx, inner_scrutinee).res_local_id()
         && !pat_contains_disallowed_or(cx, inner_then_pat, msrv)
         // the binding must come from the pattern of the containing match arm
         // ..<local>.. => match <local> { .. }
-        && let (Some(binding_span), is_innermost_parent_pat_struct)
-            = find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id)
+        && let (Some((binding_ident, binding_span)), is_innermost_parent_pat_struct) =
+            find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id)
         // the "else" branches must be equal
         && match (outer_else_body, inner_else_body) {
             (None, None) => true,
@@ -77,9 +78,7 @@ fn check_arm<'tcx>(
             (Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
         }
         // the binding must not be used in the if guard
-        && outer_guard.is_none_or(
-            |e| !is_local_used(cx, e, binding_id)
-        )
+        && outer_guard.is_none_or(|e| !is_local_used(cx, e, binding_id))
         // ...or anywhere in the inner expression
         && match inner {
             IfLetOrMatch::IfLet(_, _, body, els, _) => {
@@ -103,7 +102,7 @@ fn check_arm<'tcx>(
         // collapsing patterns need an explicit field name in struct pattern matching
         // ex: Struct {x: Some(1)}
         let replace_msg = if is_innermost_parent_pat_struct {
-            format!(", prefixed by `{}`:", snippet(cx, binding_span, "their field name"))
+            format!(", prefixed by `{binding_ident}: `")
         } else {
             String::new()
         };
@@ -135,21 +134,24 @@ fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
             kind: PatExprKind::Path(qpath),
             hir_id,
             ..
-        }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
+        }) => cx
+            .qpath_res(qpath, *hir_id)
+            .ctor_parent(cx)
+            .is_lang_item(cx, OptionNone),
         _ => false,
     }
 }
 
-fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: HirId) -> (Option<Span>, bool) {
-    let mut span = None;
+fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: HirId) -> (Option<(Ident, Span)>, bool) {
+    let mut binding = None;
     let mut is_innermost_parent_pat_struct = false;
-    pat.walk_short(|p| match &p.kind {
+    pat.walk_short(|p| match p.kind {
         // ignore OR patterns
         PatKind::Or(_) => false,
-        PatKind::Binding(_bm, _, _ident, _) => {
+        PatKind::Binding(_bm, _, ident, _) => {
             let found = p.hir_id == hir_id;
             if found {
-                span = Some(p.span);
+                binding = Some((ident, p.span));
             }
             !found
         },
@@ -158,7 +160,7 @@ fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: Hi
             true
         },
     });
-    (span, is_innermost_parent_pat_struct)
+    (binding, is_innermost_parent_pat_struct)
 }
 
 /// Builds a chain of reference-manipulation method calls (e.g., `.as_ref()`, `.as_mut()`,
diff --git a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
index 93d7683..be4b4f3 100644
--- a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs};
+use clippy_utils::{peel_blocks, strip_pat_refs};
 use rustc_errors::Applicability;
 use rustc_hir::{ExprKind, LetStmt, MatchSource, PatKind, QPath};
 use rustc_lint::LateContext;
@@ -17,7 +18,7 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
         && args.len() == 1
         && let PatKind::Binding(binding, arg, ..) = strip_pat_refs(&args[0]).kind
         && let body = peel_blocks(arms[0].body)
-        && path_to_local_id(body, arg)
+        && body.res_local_id() == Some(arg)
     {
         let mut applicability = Applicability::MachineApplicable;
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
index abf723f..d722405 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
 use clippy_utils::visitors::contains_unsafe_block;
-use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id};
 
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind};
@@ -66,15 +65,15 @@ fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr:
         && let ExprKind::Call(callee, [arg]) = inner_expr.kind
     {
         return ctxt == expr.span.ctxt()
-            && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome)
-            && path_to_local_id(arg, target);
+            && callee.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome)
+            && arg.res_local_id() == Some(target);
     }
     false
 }
 
 fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
-        return is_res_lang_ctor(cx, path_res(cx, inner_expr), OptionNone);
+        return inner_expr.res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone);
     }
     false
 }
@@ -98,7 +97,7 @@ pub(super) fn check_match<'tcx>(
     expr: &'tcx Expr<'_>,
 ) {
     let ty = cx.typeck_results().expr_ty(expr);
-    if is_type_diagnostic_item(cx, ty, sym::Option)
+    if ty.is_diag_item(cx, sym::Option)
         && let [first_arm, second_arm] = arms
         && first_arm.guard.is_none()
         && second_arm.guard.is_none()
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
index de57d1e..f111da6 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
@@ -2,8 +2,7 @@
 use super::manual_utils::{SomeExpr, check_with};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 
-use clippy_utils::{is_res_lang_ctor, path_res};
-
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use rustc_hir::LangItem::OptionSome;
 use rustc_hir::{Arm, Block, BlockCheckMode, Expr, ExprKind, Pat, UnsafeSource};
 use rustc_lint::LateContext;
@@ -91,7 +90,7 @@ fn get_some_expr_internal<'tcx>(
         // TODO: Allow more complex expressions.
         match expr.kind {
             ExprKind::Call(callee, [arg])
-                if ctxt == expr.span.ctxt() && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome) =>
+                if ctxt == expr.span.ctxt() && callee.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome) =>
             {
                 Some(SomeExpr::new_no_negated(arg, needs_unsafe_block))
             },
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
index a8490d6..c929341 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::{indent_of, reindent_multiline};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{option_arg_ty, peel_and_count_ty_refs};
-use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res, peel_blocks, span_contains_comment};
+use clippy_utils::{get_parent_expr, peel_blocks, span_contains_comment};
 use rustc_ast::{BindingMode, Mutability};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr};
@@ -72,7 +73,10 @@ fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool
             true
         },
         PatKind::TupleStruct(qpath, ..) => {
-            is_res_lang_ctor(cx, cx.qpath_res(&qpath, pat.hir_id), ResultErr) == must_match_err
+            cx.qpath_res(&qpath, pat.hir_id)
+                .ctor_parent(cx)
+                .is_lang_item(cx, ResultErr)
+                == must_match_err
         },
         PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) => {
             is_variant_or_wildcard(cx, pat, can_be_wild, must_match_err)
@@ -103,7 +107,7 @@ fn is_ok_or_err<'hir>(cx: &LateContext<'_>, pat: &Pat<'hir>) -> Option<(bool, &'
 /// Check if `expr` contains `Some(ident)`, possibly as a block
 fn is_some_ident<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, ident: &Ident, ty: Ty<'tcx>) -> bool {
     if let ExprKind::Call(body_callee, [body_arg]) = peel_blocks(expr).kind
-        && is_res_lang_ctor(cx, path_res(cx, body_callee), OptionSome)
+        && body_callee.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome)
         && cx.typeck_results().expr_ty(body_arg) == ty
         && let ExprKind::Path(QPath::Resolved(
             _,
@@ -120,7 +124,7 @@ fn is_some_ident<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, ident: &Ident, t
 
 /// Check if `expr` is `None`, possibly as a block
 fn is_none(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    is_res_lang_ctor(cx, path_res(cx, peel_blocks(expr)), OptionNone)
+    peel_blocks(expr).res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone)
 }
 
 /// Suggest replacing `expr` by `scrutinee.METHOD()`, where `METHOD` is either `ok` or
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index ac9e518..e00d0c7 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -1,4 +1,5 @@
 use clippy_utils::consts::ConstEvalCtxt;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::{SpanRangeExt as _, indent_of, reindent_multiline};
 use rustc_ast::{BindingMode, ByRef};
 use rustc_errors::Applicability;
@@ -10,8 +11,8 @@
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{expr_type_is_certain, get_type_diagnostic_name, implements_trait};
-use clippy_utils::{is_default_equivalent, is_lint_allowed, path_res, peel_blocks, span_contains_comment};
+use clippy_utils::ty::{expr_type_is_certain, implements_trait};
+use clippy_utils::{is_default_equivalent, is_lint_allowed, peel_blocks, span_contains_comment};
 
 use super::{MANUAL_UNWRAP_OR, MANUAL_UNWRAP_OR_DEFAULT};
 
@@ -31,7 +32,7 @@ fn get_some(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<HirId> {
     }
 }
 
-fn get_none<'tcx>(cx: &LateContext<'_>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+fn get_none<'tcx>(cx: &LateContext<'_>, arm: &Arm<'tcx>, allow_wildcard: bool) -> Option<&'tcx Expr<'tcx>> {
     if let PatKind::Expr(PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. }) = arm.pat.kind
         && let Some(def_id) = path.res.opt_def_id()
         // Since it comes from a pattern binding, we need to get the parent to actually match
@@ -48,7 +49,9 @@ fn get_none<'tcx>(cx: &LateContext<'_>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'t
         && cx.tcx.lang_items().get(LangItem::ResultErr) == Some(def_id)
     {
         Some(arm.body)
-    } else if let PatKind::Wild = arm.pat.kind {
+    } else if let PatKind::Wild = arm.pat.kind
+        && allow_wildcard
+    {
         // We consider that the `Some` check will filter it out if it's not right.
         Some(arm.body)
     } else {
@@ -62,11 +65,11 @@ fn get_some_and_none_bodies<'tcx>(
     arm2: &'tcx Arm<'tcx>,
 ) -> Option<((&'tcx Expr<'tcx>, HirId), &'tcx Expr<'tcx>)> {
     if let Some(binding_id) = get_some(cx, arm1.pat)
-        && let Some(body_none) = get_none(cx, arm2)
+        && let Some(body_none) = get_none(cx, arm2, true)
     {
         Some(((arm1.body, binding_id), body_none))
-    } else if let Some(binding_id) = get_some(cx, arm2.pat)
-        && let Some(body_none) = get_none(cx, arm1)
+    } else if let Some(body_none) = get_none(cx, arm1, false)
+        && let Some(binding_id) = get_some(cx, arm2.pat)
     {
         Some(((arm2.body, binding_id), body_none))
     } else {
@@ -114,7 +117,8 @@ fn handle(
             && is_default_equivalent(cx, peel_blocks(body_none))
         {
             // We now check if the condition is a None variant, in which case we need to specify the type
-            if path_res(cx, condition)
+            if condition
+                .res(cx)
                 .opt_def_id()
                 .is_some_and(|id| Some(cx.tcx.parent(id)) == cx.tcx.lang_items().option_none_variant())
             {
@@ -174,7 +178,7 @@ fn handle(
 }
 
 fn find_type_name<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'static str> {
-    match get_type_diagnostic_name(cx, ty)? {
+    match ty.opt_diag_name(cx)? {
         sym::Option => Some("Option"),
         sym::Result => Some("Result"),
         _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index d4bfdb7..235cb9e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -1,11 +1,12 @@
 use crate::map_unit_fn::OPTION_MAP_UNIT_FN;
 use crate::matches::MATCH_AS_REF;
+use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_copy, is_type_diagnostic_item, is_unsafe_fn, peel_and_count_ty_refs};
+use clippy_utils::ty::{is_copy, is_unsafe_fn, peel_and_count_ty_refs};
 use clippy_utils::{
-    CaptureKind, can_move_expr_to_closure, expr_requires_coercion, is_else_clause, is_lint_allowed, is_res_lang_ctor,
-    path_res, path_to_local_id, peel_blocks, peel_hir_expr_refs, peel_hir_expr_while,
+    CaptureKind, can_move_expr_to_closure, expr_requires_coercion, is_else_clause, is_lint_allowed, peel_blocks,
+    peel_hir_expr_refs, peel_hir_expr_while,
 };
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_errors::Applicability;
@@ -33,8 +34,7 @@ pub(super) fn check_with<'tcx, F>(
     let (scrutinee_ty, ty_ref_count, ty_mutability) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(scrutinee));
     let ty_mutability = ty_mutability.unwrap_or(Mutability::Mut);
 
-    if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::Option)
-        && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Option))
+    if !(scrutinee_ty.is_diag_item(cx, sym::Option) && cx.typeck_results().expr_ty(expr).is_diag_item(cx, sym::Option))
     {
         return None;
     }
@@ -138,7 +138,7 @@ pub(super) fn check_with<'tcx, F>(
         {
             snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
         } else {
-            if path_to_local_id(some_expr.expr, id)
+            if some_expr.expr.res_local_id() == Some(id)
                 && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
                 && binding_ref.is_some()
             {
@@ -190,7 +190,7 @@ pub struct SuggInfo<'a> {
 fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     match expr.kind {
         ExprKind::Call(func, [arg])
-            if path_to_local_id(arg, binding)
+            if arg.res_local_id() == Some(binding)
                 && cx.typeck_results().expr_adjustments(arg).is_empty()
                 && !is_unsafe_fn(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
         {
@@ -259,9 +259,19 @@ fn f<'tcx>(
                 kind: PatExprKind::Path(qpath),
                 hir_id,
                 ..
-            }) if is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone) => Some(OptionPat::None),
+            }) if cx
+                .qpath_res(qpath, *hir_id)
+                .ctor_parent(cx)
+                .is_lang_item(cx, OptionNone) =>
+            {
+                Some(OptionPat::None)
+            },
             PatKind::TupleStruct(ref qpath, [pattern], _)
-                if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionSome) && pat.span.ctxt() == ctxt =>
+                if cx
+                    .qpath_res(qpath, pat.hir_id)
+                    .ctor_parent(cx)
+                    .is_lang_item(cx, OptionSome)
+                    && pat.span.ctxt() == ctxt =>
             {
                 Some(OptionPat::Some { pattern, ref_count })
             },
@@ -273,5 +283,5 @@ fn f<'tcx>(
 
 // Checks for the `None` value.
 fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    is_res_lang_ctor(cx, path_res(cx, peel_blocks(expr)), OptionNone)
+    peel_blocks(expr).res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone)
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
index 1cb4b51..156118b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_none_arm, is_res_lang_ctor, path_res, peel_blocks};
+use clippy_utils::{is_none_arm, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
 use rustc_lint::LateContext;
@@ -58,10 +59,13 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
 // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
 fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
     if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind
-        && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome)
+        && cx
+            .qpath_res(qpath, arm.pat.hir_id)
+            .ctor_parent(cx)
+            .is_lang_item(cx, LangItem::OptionSome)
         && let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., ident, _) = first_pat.kind
         && let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind
-        && is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome)
+        && e.res(cx).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
         && let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind
         && path2.segments.len() == 1
         && ident.name == path2.segments[0].ident.name
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
index 5816da5..b5f631e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
@@ -1,17 +1,18 @@
+//! Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
+
 use super::REDUNDANT_PATTERN_MATCHING;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, Attribute, BorrowKind, Expr, ExprKind, Pat, PatKind, QPath};
+use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Pat, PatKind, QPath};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
 use rustc_span::source_map::Spanned;
 
 use super::MATCH_LIKE_MATCHES_MACRO;
 
-/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
 pub(crate) fn check_if_let<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
@@ -20,16 +21,42 @@ pub(crate) fn check_if_let<'tcx>(
     then_expr: &'tcx Expr<'_>,
     else_expr: &'tcx Expr<'_>,
 ) {
-    find_matches_sugg(
-        cx,
-        let_expr,
-        IntoIterator::into_iter([
-            (&[][..], Some(let_pat), then_expr, None),
-            (&[][..], None, else_expr, None),
-        ]),
-        expr,
-        true,
-    );
+    if !span_contains_comment(cx.sess().source_map(), expr.span)
+        && cx.typeck_results().expr_ty(expr).is_bool()
+        && let Some(b0) = find_bool_lit(then_expr)
+        && let Some(b1) = find_bool_lit(else_expr)
+        && b0 != b1
+    {
+        if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, let_pat.hir_id) && is_some_wild(let_pat.kind) {
+            return;
+        }
+
+        // The suggestion may be incorrect, because some arms can have `cfg` attributes
+        // evaluated into `false` and so such arms will be stripped before.
+        let mut applicability = Applicability::MaybeIncorrect;
+        let pat = snippet_with_applicability(cx, let_pat.span, "..", &mut applicability);
+
+        // strip potential borrows (#6503), but only if the type is a reference
+        let mut ex_new = let_expr;
+        if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = let_expr.kind
+            && let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind()
+        {
+            ex_new = ex_inner;
+        }
+        span_lint_and_sugg(
+            cx,
+            MATCH_LIKE_MATCHES_MACRO,
+            expr.span,
+            "if let .. else expression looks like `matches!` macro",
+            "try",
+            format!(
+                "{}matches!({}, {pat})",
+                if b0 { "" } else { "!" },
+                snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
+            ),
+            applicability,
+        );
+    }
 }
 
 pub(super) fn check_match<'tcx>(
@@ -38,55 +65,80 @@ pub(super) fn check_match<'tcx>(
     scrutinee: &'tcx Expr<'_>,
     arms: &'tcx [Arm<'tcx>],
 ) -> bool {
-    find_matches_sugg(
-        cx,
-        scrutinee,
-        arms.iter()
-            .map(|arm| (cx.tcx.hir_attrs(arm.hir_id), Some(arm.pat), arm.body, arm.guard)),
-        e,
-        false,
-    )
-}
-
-/// Lint a `match` or `if let` for replacement by `matches!`
-fn find_matches_sugg<'a, 'b, I>(
-    cx: &LateContext<'_>,
-    ex: &Expr<'_>,
-    mut iter: I,
-    expr: &Expr<'_>,
-    is_if_let: bool,
-) -> bool
-where
-    'b: 'a,
-    I: Clone
-        + DoubleEndedIterator
-        + ExactSizeIterator
-        + Iterator<Item = (&'a [Attribute], Option<&'a Pat<'b>>, &'a Expr<'b>, Option<&'a Expr<'b>>)>,
-{
-    if !span_contains_comment(cx.sess().source_map(), expr.span)
-        && iter.len() >= 2
-        && cx.typeck_results().expr_ty(expr).is_bool()
-        && let Some((_, last_pat_opt, last_expr, _)) = iter.next_back()
-        && let iter_without_last = iter.clone()
-        && let Some((first_attrs, _, first_expr, first_guard)) = iter.next()
-        && let Some(b0) = find_bool_lit(&first_expr.kind)
-        && let Some(b1) = find_bool_lit(&last_expr.kind)
+    if let Some((last_arm, arms_without_last)) = arms.split_last()
+        && let Some((first_arm, middle_arms)) = arms_without_last.split_first()
+        && !span_contains_comment(cx.sess().source_map(), e.span)
+        && cx.typeck_results().expr_ty(e).is_bool()
+        && let Some(b0) = find_bool_lit(first_arm.body)
+        && let Some(b1) = find_bool_lit(last_arm.body)
         && b0 != b1
-        && (first_guard.is_none() || iter.len() == 0)
-        && first_attrs.is_empty()
-        && iter.all(|arm| find_bool_lit(&arm.2.kind).is_some_and(|b| b == b0) && arm.3.is_none() && arm.0.is_empty())
+        // We handle two cases:
+        && (
+            // - There are no middle arms, i.e., 2 arms in total
+            //
+            // In that case, the first arm may or may not have a guard, because this:
+            // ```rs
+            // match e {
+            //     Either::Left $(if $guard)|+ => true, // or `false`, but then we'll need `!matches!(..)`
+            //     _ => false,
+            // }
+            // ```
+            // can always become this:
+            // ```rs
+            // matches!(e, Either::Left $(if $guard)|+)
+            // ```
+            middle_arms.is_empty()
+
+            // - (added in #6216) There are middle arms
+            //
+            // In that case, neither they nor the first arm may have guards
+            // -- otherwise, they couldn't be combined into an or-pattern in `matches!`
+            //
+            // This:
+            // ```rs
+            // match e {
+            //     Either3::First => true,
+            //     Either3::Second => true,
+            //     _ /* matches `Either3::Third` */ => false,
+            // }
+            // ```
+            // can become this:
+            // ```rs
+            // matches!(e, Either3::First | Either3::Second)
+            // ```
+            //
+            // But this:
+            // ```rs
+            // match e {
+            //     Either3::First if X => true,
+            //     Either3::Second => true,
+            //     _ => false,
+            // }
+            // ```
+            // cannot be transformed.
+            //
+            // We set an additional constraint of all of them needing to return the same bool,
+            // so we don't lint things like:
+            // ```rs
+            // match e {
+            //     Either3::First => true,
+            //     Either3::Second => false,
+            //     _ => false,
+            // }
+            // ```
+            // This is not *strictly* necessary, but it simplifies the logic a bit
+            || arms_without_last.iter().all(|arm| {
+                cx.tcx.hir_attrs(arm.hir_id).is_empty() && arm.guard.is_none() && find_bool_lit(arm.body) == Some(b0)
+            })
+        )
     {
-        if let Some(last_pat) = last_pat_opt
-            && !is_wild(last_pat)
-        {
+        if !is_wild(last_arm.pat) {
             return false;
         }
 
-        for arm in iter_without_last.clone() {
-            if let Some(pat) = arm.1
-                && !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id)
-                && is_some(pat.kind)
-            {
+        for arm in arms_without_last {
+            let pat = arm.pat;
+            if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) && is_some_wild(pat.kind) {
                 return false;
             }
         }
@@ -96,14 +148,12 @@ fn find_matches_sugg<'a, 'b, I>(
         let mut applicability = Applicability::MaybeIncorrect;
         let pat = {
             use itertools::Itertools as _;
-            iter_without_last
-                .filter_map(|arm| {
-                    let pat_span = arm.1?.span;
-                    Some(snippet_with_applicability(cx, pat_span, "..", &mut applicability))
-                })
+            arms_without_last
+                .iter()
+                .map(|arm| snippet_with_applicability(cx, arm.pat.span, "..", &mut applicability))
                 .join(" | ")
         };
-        let pat_and_guard = if let Some(g) = first_guard {
+        let pat_and_guard = if let Some(g) = first_arm.guard {
             format!(
                 "{pat} if {}",
                 snippet_with_applicability(cx, g.span, "..", &mut applicability)
@@ -113,8 +163,8 @@ fn find_matches_sugg<'a, 'b, I>(
         };
 
         // strip potential borrows (#6503), but only if the type is a reference
-        let mut ex_new = ex;
-        if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind
+        let mut ex_new = scrutinee;
+        if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = scrutinee.kind
             && let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind()
         {
             ex_new = ex_inner;
@@ -122,11 +172,8 @@ fn find_matches_sugg<'a, 'b, I>(
         span_lint_and_sugg(
             cx,
             MATCH_LIKE_MATCHES_MACRO,
-            expr.span,
-            format!(
-                "{} expression looks like `matches!` macro",
-                if is_if_let { "if let .. else" } else { "match" }
-            ),
+            e.span,
+            "match expression looks like `matches!` macro",
             "try",
             format!(
                 "{}matches!({}, {pat_and_guard})",
@@ -142,11 +189,11 @@ fn find_matches_sugg<'a, 'b, I>(
 }
 
 /// Extract a `bool` or `{ bool }`
-fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> {
-    match ex {
+fn find_bool_lit(ex: &Expr<'_>) -> Option<bool> {
+    match ex.kind {
         ExprKind::Lit(Spanned {
             node: LitKind::Bool(b), ..
-        }) => Some(*b),
+        }) => Some(b),
         ExprKind::Block(
             rustc_hir::Block {
                 stmts: [],
@@ -168,8 +215,9 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> {
     }
 }
 
-fn is_some(path_kind: PatKind<'_>) -> bool {
-    match path_kind {
+/// Checks whether a pattern is `Some(_)`
+fn is_some_wild(pat_kind: PatKind<'_>) -> bool {
+    match pat_kind {
         PatKind::TupleStruct(QPath::Resolved(_, path), [first, ..], _) if is_wild(first) => {
             let name = path.segments[0].ident;
             name.name == rustc_span::sym::Some
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 818e504..be91442 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{SpanlessEq, fulfill_or_allowed, hash_expr, is_lint_allowed, path_to_local, search_same};
+use clippy_utils::{SpanlessEq, fulfill_or_allowed, hash_expr, is_lint_allowed, search_same};
 use core::cmp::Ordering;
 use core::{iter, slice};
 use itertools::Itertools;
@@ -61,8 +62,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
         let check_eq_with_pat = |expr_a: &Expr<'_>, expr_b: &Expr<'_>| {
             let mut local_map: HirIdMap<HirId> = HirIdMap::default();
             let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
-                if let Some(a_id) = path_to_local(a)
-                    && let Some(b_id) = path_to_local(b)
+                if let Some(a_id) = a.res_local_id()
+                    && let Some(b_id) = b.res_local_id()
                     && let entry = match local_map.entry(a_id) {
                         HirIdMapEntry::Vacant(entry) => entry,
                         // check if using the same bindings as before
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
index eb8b16e..3f8f2dc 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -1,8 +1,8 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::sym;
-use clippy_utils::ty::is_type_lang_item;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_expr};
@@ -58,7 +58,7 @@ fn case_altered(&self, segment_ident: Symbol, receiver: &Expr<'_>) -> ControlFlo
         if let Some(case_method) = get_case_method(segment_ident) {
             let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
 
-            if is_type_lang_item(self.cx, ty, LangItem::String) || ty.kind() == &ty::Str {
+            if ty.is_lang_item(self.cx, LangItem::String) || ty.kind() == &ty::Str {
                 return ControlFlow::Break(case_method);
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 70a03ff..ac5da32 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns};
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -16,8 +16,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
     let ty = cx.typeck_results().expr_ty(ex).peel_refs();
     let adt_def = match ty.kind() {
         ty::Adt(adt_def, _)
-            if adt_def.is_enum()
-                && !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) =>
+            if adt_def.is_enum() && !(ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result)) =>
         {
             adt_def
         },
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
index 8ce8453..e38ba80 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_note;
 use clippy_utils::macros::{is_panic, root_macro_call};
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{is_in_const_context, is_wild, peel_blocks_with_stmt};
 use rustc_hir::{Arm, Expr, PatKind};
@@ -16,7 +16,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
     }
 
     let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
-    if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
+    if ex_ty.is_diag_item(cx, sym::Result) {
         for arm in arms {
             if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
                 let path_str = rustc_hir_pretty::qpath_to_string(&cx.tcx, path);
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index 3a2097c..c9b6821 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -1,10 +1,10 @@
 use super::NEEDLESS_MATCH;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_type_diagnostic_item, same_type_modulo_regions};
+use clippy_utils::ty::same_type_modulo_regions;
 use clippy_utils::{
-    SpanlessEq, eq_expr_value, get_parent_expr_for_hir, higher, is_else_clause, is_res_lang_ctor, over, path_res,
-    peel_blocks_with_stmt,
+    SpanlessEq, eq_expr_value, get_parent_expr_for_hir, higher, is_else_clause, over, peel_blocks_with_stmt,
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
@@ -104,8 +104,8 @@ fn check_if_let_inner(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool
                 return false;
             }
             let let_expr_ty = cx.typeck_results().expr_ty(if_let.let_expr);
-            if is_type_diagnostic_item(cx, let_expr_ty, sym::Option) {
-                return is_res_lang_ctor(cx, path_res(cx, else_expr), OptionNone)
+            if let_expr_ty.is_diag_item(cx, sym::Option) {
+                return else_expr.res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone)
                     || eq_expr_value(cx, if_let.let_expr, else_expr);
             }
             return eq_expr_value(cx, if_let.let_expr, else_expr);
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 7c6d45e..d39e315 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -1,9 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::msrvs::Msrv;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used};
-use clippy_utils::{is_in_const_context, path_to_local, sym};
+use clippy_utils::{is_in_const_context, sym};
 use rustc_ast::{BorrowKind, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -164,7 +165,7 @@ fn get_pat_binding<'tcx>(
     guard_expr: &Expr<'_>,
     outer_arm: &Arm<'tcx>,
 ) -> Option<PatBindingInfo> {
-    if let Some(local) = path_to_local(guard_expr)
+    if let Some(local) = guard_expr.res_local_id()
         && !is_local_used(cx, outer_arm.body, local)
     {
         let mut span = None;
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 9d01157..2ca76a1 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -1,10 +1,11 @@
 use super::REDUNDANT_PATTERN_MATCHING;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::walk_span_to_context;
 use clippy_utils::sugg::{Sugg, make_unop};
-use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
+use clippy_utils::ty::needs_ordered_drop;
 use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures};
-use clippy_utils::{higher, is_expn_of, is_trait_method, sym};
+use clippy_utils::{higher, is_expn_of, sym};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
@@ -216,7 +217,7 @@ fn find_method_sugg_for_if_let<'tcx>(
     if keyword == "while"
         && let ExprKind::MethodCall(method_path, _, [], _) = let_expr.kind
         && method_path.ident.name == sym::next
-        && is_trait_method(cx, let_expr, sym::Iterator)
+        && cx.ty_based_def(let_expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
     {
         return;
     }
@@ -460,7 +461,7 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte
         Item::Diag(expected_ty, expected_variant) => {
             let ty = cx.typeck_results().pat_ty(pat);
 
-            if is_type_diagnostic_item(cx, ty, expected_ty) {
+            if ty.is_diag_item(cx, expected_ty) {
                 let variant = ty
                     .ty_adt_def()
                     .expect("struct pattern type is not an ADT")
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 02f8751..44c4d7a 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -224,7 +224,7 @@ enum PatState<'a> {
     /// A std enum we know won't be extended. Tracks the states of each variant separately.
     ///
     /// This is not used for `Option` since it uses the current pattern to track its state.
-    StdEnum(&'a mut [PatState<'a>]),
+    StdEnum(&'a mut [Self]),
     /// Either the initial state for a pattern or a non-std enum. There is currently no need to
     /// distinguish these cases.
     ///
diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
index af90cb5..7358628 100644
--- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::get_parent_expr;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::option_arg_ty;
-use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::ResultErr;
 use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
@@ -25,7 +26,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
         && let ExprKind::Path(ref match_fun_path) = match_fun.kind
         && matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..))
         && let ExprKind::Call(err_fun, [err_arg]) = try_arg.kind
-        && is_res_lang_ctor(cx, path_res(cx, err_fun), ResultErr)
+        && err_fun.res(cx).ctor_parent(cx).is_lang_item(cx, ResultErr)
         && let Some(return_ty) = find_return_type(cx, &expr.kind)
     {
         let (prefix, suffix, err_ty) = if let Some(ty) = result_error_type(cx, return_ty) {
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 95ecef5..ac3cbae 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -1,12 +1,11 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_non_aggregate_primitive_type;
-use clippy_utils::{
-    is_default_equivalent, is_expr_used_or_unified, is_res_lang_ctor, path_res, peel_ref_operators, std_or_core,
-};
+use clippy_utils::{is_default_equivalent, is_expr_used_or_unified, peel_ref_operators, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind};
@@ -129,7 +128,7 @@
     [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_OPTION_WITH_SOME, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]);
 
 fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) -> bool {
-    if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) {
+    if src.res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone) {
         // Since this is a late pass (already type-checked),
         // and we already know that the second argument is an
         // `Option`, we do not need to check the first
@@ -163,7 +162,7 @@ fn check_replace_option_with_some(
     msrv: Msrv,
 ) -> bool {
     if let ExprKind::Call(src_func, [src_arg]) = src.kind
-        && is_res_lang_ctor(cx, path_res(cx, src_func), OptionSome)
+        && src_func.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome)
         && msrv.meets(cx, msrvs::OPTION_REPLACE)
     {
         // We do not have to check for a `const` context here, because `core::mem::replace()` and
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
index 0498f31..77ac181 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{path_to_local_id, peel_blocks, peel_ref_operators, strip_pat_refs};
+use clippy_utils::{peel_blocks, peel_ref_operators, strip_pat_refs};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
 use rustc_lint::LateContext;
@@ -23,10 +23,14 @@ pub(super) fn check<'tcx>(
         && let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind
         && let ExprKind::Binary(ref op, l, r) = body.value.kind
         && op.node == BinOpKind::Eq
-        && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv).peel_refs(), sym::SliceIter)
+        && cx
+            .typeck_results()
+            .expr_ty(filter_recv)
+            .peel_refs()
+            .is_diag_item(cx, sym::SliceIter)
         && let operand_is_arg = (|expr| {
             let expr = peel_ref_operators(cx, peel_blocks(expr));
-            path_to_local_id(expr, arg_id)
+            expr.res_local_id() == Some(arg_id)
         })
         && let needle = if operand_is_arg(l) {
             r
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
index b8cc5dd..baea492 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_count_to_len.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_lang_item;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(
         && let Some(impl_id) = cx.tcx.impl_of_assoc(bytes_id)
         && cx.tcx.type_of(impl_id).instantiate_identity().is_str()
         && let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs()
-        && (ty.is_str() || is_type_lang_item(cx, ty, hir::LangItem::String))
+        && (ty.is_str() || ty.is_lang_item(cx, hir::LangItem::String))
     {
         let mut applicability = Applicability::MachineApplicable;
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
index 02fc0917..40d521d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sym;
-use clippy_utils::ty::is_type_lang_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, LangItem};
 use rustc_lint::LateContext;
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
     let ty = cx.typeck_results().expr_ty(recv).peel_refs();
     let caller_type = if ty.is_str() {
         "str"
-    } else if is_type_lang_item(cx, ty, LangItem::String) {
+    } else if ty.is_lang_item(cx, LangItem::String) {
         "String"
     } else {
         return;
diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
index 6f9702f..b4b10e9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
 use clippy_utils::sym;
-use clippy_utils::ty::is_type_lang_item;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem};
@@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(
             || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit()))
         && !ext_str.chars().skip(1).all(|c| c.is_ascii_digit())
         && let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs()
-        && (recv_ty.is_str() || is_type_lang_item(cx, recv_ty, LangItem::String))
+        && (recv_ty.is_str() || recv_ty.is_lang_item(cx, LangItem::String))
     {
         span_lint_and_then(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
index de27a45..4b0fc7e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::method_chain_args;
+use clippy_utils::res::MaybeQPath;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{method_chain_args, path_def_id};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, Lint};
@@ -17,7 +18,7 @@ pub(super) fn check(
 ) -> bool {
     if let Some(args) = method_chain_args(info.chain, chain_methods)
         && let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind
-        && let Some(id) = path_def_id(cx, fun).map(|ctor_id| cx.tcx.parent(ctor_id))
+        && let Some(id) = fun.res(cx).opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id))
         && Some(id) == cx.tcx.lang_items().option_some_variant()
     {
         let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs
index 6e24cab..67def87 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clear_with_drain.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_range_full;
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
+use clippy_utils::res::MaybeDef;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, QPath};
 use rustc_lint::LateContext;
@@ -29,9 +29,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span
 
 fn match_acceptable_type(cx: &LateContext<'_>, expr: &Expr<'_>, types: &[rustc_span::Symbol]) -> bool {
     let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
-    types.iter().any(|&ty| is_type_diagnostic_item(cx, expr_ty, ty))
+    types.iter().any(|&ty| expr_ty.is_diag_item(cx, ty))
     // String type is a lang item but not a diagnostic item for now so we need a separate check
-        || is_type_lang_item(cx, expr_ty, LangItem::String)
+        || expr_ty.is_lang_item(cx, LangItem::String)
 }
 
 fn suggest(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index 0a456d1..2a0ae14 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -4,27 +4,14 @@
 use rustc_errors::Applicability;
 use rustc_hir::{BindingMode, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
 use rustc_lint::LateContext;
+use rustc_middle::ty;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
-use rustc_middle::ty::{self};
-use rustc_span::symbol::{Symbol, sym};
 
 use super::CLONE_ON_COPY;
 
 /// Checks for the `CLONE_ON_COPY` lint.
-#[allow(clippy::too_many_lines)]
-pub(super) fn check(
-    cx: &LateContext<'_>,
-    expr: &Expr<'_>,
-    method_name: Symbol,
-    receiver: &Expr<'_>,
-    args: &[Expr<'_>],
-) {
-    let arg = if method_name == sym::clone && args.is_empty() {
-        receiver
-    } else {
-        return;
-    };
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
     if cx
         .typeck_results()
         .type_dependent_def_id(expr.hir_id)
@@ -34,10 +21,10 @@ pub(super) fn check(
     {
         return;
     }
-    let arg_adjustments = cx.typeck_results().expr_adjustments(arg);
+    let arg_adjustments = cx.typeck_results().expr_adjustments(receiver);
     let arg_ty = arg_adjustments
         .last()
-        .map_or_else(|| cx.typeck_results().expr_ty(arg), |a| a.target);
+        .map_or_else(|| cx.typeck_results().expr_ty(receiver), |a| a.target);
 
     let ty = cx.typeck_results().expr_ty(expr);
     if let ty::Ref(_, inner, _) = arg_ty.kind()
@@ -76,7 +63,7 @@ pub(super) fn check(
         };
 
         let mut app = Applicability::MachineApplicable;
-        let snip = snippet_with_context(cx, arg.span, expr.span.ctxt(), "_", &mut app).0;
+        let snip = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "_", &mut app).0;
 
         let deref_count = arg_adjustments
             .iter()
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
index 65583c6..238e1fe 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -3,21 +3,12 @@
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_middle::ty;
-use rustc_span::symbol::{Symbol, sym};
+use rustc_middle::ty::{self, IsSuggestable};
+use rustc_span::symbol::sym;
 
 use super::CLONE_ON_REF_PTR;
 
-pub(super) fn check(
-    cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    method_name: Symbol,
-    receiver: &hir::Expr<'_>,
-    args: &[hir::Expr<'_>],
-) {
-    if !(args.is_empty() && method_name == sym::clone) {
-        return;
-    }
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>) {
     let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
 
     if let ty::Adt(adt, subst) = obj_ty.kind()
@@ -39,12 +30,22 @@ pub(super) fn check(
                 // Sometimes unnecessary ::<_> after Rc/Arc/Weak
                 let mut app = Applicability::Unspecified;
                 let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0;
-                diag.span_suggestion(
-                    expr.span,
-                    "try",
-                    format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
-                    app,
-                );
+                let generic = subst.type_at(0);
+                if generic.is_suggestable(cx.tcx, true) {
+                    diag.span_suggestion(
+                        expr.span,
+                        "try",
+                        format!("{caller_type}::<{generic}>::clone(&{snippet})"),
+                        app,
+                    );
+                } else {
+                    diag.span_suggestion(
+                        expr.span,
+                        "try",
+                        format!("{caller_type}::</* generic */>::clone(&{snippet})"),
+                        Applicability::HasPlaceholders,
+                    );
+                }
             },
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
index f50fb62..d80d6f7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::ty::{get_iterator_item_ty, is_copy};
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
@@ -19,7 +19,9 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span,
         {
             subst.type_at(0)
         },
-        _ if is_trait_method(cx, expr, sym::Iterator) && msrv.meets(cx, msrvs::ITERATOR_COPIED) => {
+        _ if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
+            && msrv.meets(cx, msrvs::ITERATOR_COPIED) =>
+        {
             match get_iterator_item_ty(cx, recv_ty) {
                 // <T as Iterator>::Item
                 Some(ty) => ty,
diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
index 578865c..8ba8264 100644
--- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::ty::{has_non_owning_mutable_access, implements_trait};
-use clippy_utils::{is_mutable, is_trait_method, path_to_local_with_projections, sym};
+use clippy_utils::{is_mutable, path_to_local_with_projections, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Node, PatKind};
 use rustc_lint::LateContext;
@@ -13,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp
     let typeck = cx.typeck_results();
 
     // if the "last" method is that of Iterator
-    if is_trait_method(cx, expr, sym::Iterator)
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         // if self implements DoubleEndedIterator
         && let Some(deiter_id) = cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator)
         && let self_type = cx.typeck_results().expr_ty(self_expr)
diff --git a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs
index cbf713a..9b0c290 100644
--- a/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/drain_collect.rs
@@ -1,7 +1,7 @@
 use crate::methods::DRAIN_COLLECT;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{is_range_full, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, Path, QPath};
@@ -35,8 +35,8 @@ fn check_vec(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>
 
 /// Checks `std::string::String`
 fn check_string(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool {
-    is_type_lang_item(cx, expr, LangItem::String)
-        && is_type_lang_item(cx, recv, LangItem::String)
+    expr.is_lang_item(cx, LangItem::String)
+        && recv.is_lang_item(cx, LangItem::String)
         && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path)))
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
index 91ddaca..6e9aebc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
@@ -1,7 +1,8 @@
 use super::ERR_EXPECT;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::ty::has_debug_impl;
 use rustc_errors::Applicability;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
@@ -16,7 +17,7 @@ pub(super) fn check(
     err_span: Span,
     msrv: Msrv,
 ) {
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
+    if cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result)
         // Grabs the `Result<T, E>` type
         && let result_type = cx.typeck_results().expr_ty(recv)
         // Tests if the T type in a `Result<T, E>` is not None
@@ -40,7 +41,7 @@ pub(super) fn check(
 /// Given a `Result<T, E>` type, return its data (`T`).
 fn get_data_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
     match ty.kind() {
-        ty::Adt(_, args) if is_type_diagnostic_item(cx, ty, sym::Result) => args.types().next(),
+        ty::Adt(_, args) if ty.is_diag_item(cx, sym::Result) => args.types().next(),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index 818e26f..288f966 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -1,14 +1,14 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span, root_macro_call_first_node};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{contains_return, is_inside_always_const_context, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
+use rustc_span::Span;
 use rustc_span::symbol::sym;
-use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 use std::ops::ControlFlow;
 
@@ -20,20 +20,15 @@ pub(super) fn check<'tcx>(
     format_args_storage: &FormatArgsStorage,
     expr: &hir::Expr<'_>,
     method_span: Span,
-    name: Symbol,
     receiver: &'tcx hir::Expr<'tcx>,
-    args: &'tcx [hir::Expr<'tcx>],
+    arg: &'tcx hir::Expr<'tcx>,
 ) {
-    if name == sym::expect
-        && let [arg] = args
-        && let arg_root = get_arg_root(cx, arg)
-        && contains_call(cx, arg_root)
-        && !contains_return(arg_root)
-    {
+    let arg_root = get_arg_root(cx, arg);
+    if contains_call(cx, arg_root) && !contains_return(arg_root) {
         let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver);
-        let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) {
+        let closure_args = if receiver_type.is_diag_item(cx, sym::Option) {
             "||"
-        } else if is_type_diagnostic_item(cx, receiver_type, sym::Result) {
+        } else if receiver_type.is_diag_item(cx, sym::Result) {
             "|_|"
         } else {
             return;
@@ -54,7 +49,7 @@ pub(super) fn check<'tcx>(
                     cx,
                     EXPECT_FUN_CALL,
                     span_replace_word,
-                    format!("function call inside of `{name}`"),
+                    "function call inside of `expect`",
                     "try",
                     format!("unwrap_or_else({closure_args} panic!({sugg}))"),
                     applicability,
@@ -69,7 +64,7 @@ pub(super) fn check<'tcx>(
             cx,
             EXPECT_FUN_CALL,
             span_replace_word,
-            format!("function call inside of `{name}`"),
+            "function call inside of `expect`",
             "try",
             format!("unwrap_or_else({closure_args} panic!(\"{{}}\", {arg_root_snippet}))"),
             applicability,
@@ -88,7 +83,7 @@ fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Ex
                 if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && {
                     let arg_type = cx.typeck_results().expr_ty(receiver);
                     let base_type = arg_type.peel_refs();
-                    base_type.is_str() || is_type_lang_item(cx, base_type, hir::LangItem::String)
+                    base_type.is_str() || base_type.is_lang_item(cx, hir::LangItem::String)
                 } {
                     receiver
                 } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
index db60061..829c122 100644
--- a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sym;
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem};
 use rustc_lint::LateContext;
@@ -10,7 +10,7 @@
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
     let ty = cx.typeck_results().expr_ty(recv).peel_refs();
-    if is_type_diagnostic_item(cx, ty, sym::Vec)
+    if ty.is_diag_item(cx, sym::Vec)
         //check source object
         && let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind
         && src_method.ident.name == sym::drain
@@ -18,10 +18,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
         //check if actual src type is mutable for code suggestion
         && let immutable = src_ty.is_mutable_ptr()
         && let src_ty = src_ty.peel_refs()
-        && is_type_diagnostic_item(cx, src_ty, sym::Vec)
+        && src_ty.is_diag_item(cx, sym::Vec)
         //check drain range
         && let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs()
-        && is_type_lang_item(cx, src_ty_range, LangItem::RangeFull)
+        && src_ty_range.is_lang_item(cx, LangItem::RangeFull)
     {
         let mut applicability = Applicability::MachineApplicable;
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
index 35008c3..a964cbf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_parent_expr;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::{Span, sym};
@@ -10,7 +10,7 @@
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     let ty = cx.typeck_results().expr_ty(recv);
 
-    if !is_type_diagnostic_item(cx, ty, sym::FileType) {
+    if !ty.is_diag_item(cx, sym::FileType) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 2da0f83..26b1984 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::macros::{is_panic, matching_root_macro_call, root_macro_call};
+use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
 use clippy_utils::source::{indent_of, reindent_multiline, snippet};
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{SpanlessEq, higher, is_trait_method, path_to_local_id, peel_blocks, sym};
+use clippy_utils::{SpanlessEq, higher, peel_blocks, sym};
 use hir::{Body, HirId, MatchSource, Pat};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -134,16 +134,16 @@ pub fn check_map_call(
                         _ => map_arg,
                     }
                     // .map(|y| y[.acceptable_method()].unwrap())
-                    && let simple_equal = (path_to_local_id(receiver, filter_param_id)
-                        && path_to_local_id(map_arg_peeled, map_param_id))
+                    && let simple_equal = (receiver.res_local_id() == Some(filter_param_id)
+                        && map_arg_peeled.res_local_id() == Some(map_param_id))
                     && let eq_fallback = (|a: &Expr<'_>, b: &Expr<'_>| {
                         // in `filter(|x| ..)`, replace `*x` with `x`
                         let a_path = if !is_filter_param_ref
                             && let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind
                         { expr_path } else { a };
                         // let the filter closure arg and the map closure arg be equal
-                        path_to_local_id(a_path, filter_param_id)
-                            && path_to_local_id(b, map_param_id)
+                        a_path.res_local_id() == Some(filter_param_id)
+                            && b.res_local_id() == Some(map_param_id)
                             && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
                     })
                     && (simple_equal
@@ -166,7 +166,7 @@ pub fn check_map_call(
                 let expr_uses_local = |pat: &Pat<'_>, expr: &Expr<'_>| {
                     if let PatKind::TupleStruct(QPath::Resolved(_, path), [subpat], _) = pat.kind
                         && let PatKind::Binding(_, local_id, ident, _) = subpat.kind
-                        && path_to_local_id(expr.peel_blocks(), local_id)
+                        && expr.peel_blocks().res_local_id() == Some(local_id)
                         && let Some(local_variant_def_id) = path.res.opt_def_id()
                         && local_variant_def_id == variant_def_id
                     {
@@ -204,7 +204,7 @@ pub fn check_map_call(
                         _ => return None,
                     };
 
-                if path_to_local_id(scrutinee, map_param_id)
+                if scrutinee.res_local_id() == Some(map_param_id)
                     // else branch should be a `panic!` or `unreachable!` macro call
                     && let Some(mac) = root_macro_call(else_.peel_blocks().span)
                     && (is_panic(cx, mac.def_id) || cx.tcx.opt_item_name(mac.def_id) == Some(sym::unreachable))
@@ -247,7 +247,7 @@ fn hir(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, filter_param_id: HirId) -
         } else if matching_root_macro_call(cx, expr.span, sym::matches_macro).is_some()
             // we know for a fact that the wildcard pattern is the second arm
             && let ExprKind::Match(scrutinee, [arm, _], _) = expr.kind
-            && path_to_local_id(scrutinee, filter_param_id)
+            && scrutinee.res_local_id() == Some(filter_param_id)
             && let PatKind::TupleStruct(QPath::Resolved(_, path), ..) = arm.pat.kind
             && let Some(variant_def_id) = path.res.opt_def_id()
         {
@@ -266,8 +266,8 @@ fn is_filter_some_map_unwrap(
     filter_arg: &Expr<'_>,
     map_arg: &Expr<'_>,
 ) -> bool {
-    let iterator = is_trait_method(cx, expr, sym::Iterator);
-    let option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(filter_recv), sym::Option);
+    let iterator = cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator);
+    let option = cx.typeck_results().expr_ty(filter_recv).is_diag_item(cx, sym::Option);
 
     (iterator || option) && is_option_filter_map(cx, filter_arg, map_arg)
 }
@@ -275,12 +275,12 @@ fn is_filter_some_map_unwrap(
 /// is `filter(|x| x.is_ok()).map(|x| x.unwrap())`
 fn is_filter_ok_map_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool {
     // result has no filter, so we only check for iterators
-    let iterator = is_trait_method(cx, expr, sym::Iterator);
+    let iterator = cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator);
     iterator && is_ok_filter_map(cx, filter_arg, map_arg)
 }
 
 /// lint use of `filter().map()` or `find().map()` for `Iterators`
-#[allow(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments)]
 pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &Expr<'_>,
@@ -398,7 +398,7 @@ fn is_find_or_filter<'a>(
     filter_arg: &Expr<'_>,
     map_arg: &Expr<'_>,
 ) -> Option<(Ident, CheckResult<'a>)> {
-    if is_trait_method(cx, map_recv, sym::Iterator)
+    if cx.ty_based_def(map_recv).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         // filter(|x| ...is_some())...
         && let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind
         && let filter_body = cx.tcx.hir_body(filter_body_id)
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 94944bd..b803d1a 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,10 +1,9 @@
 use super::FILTER_MAP_BOOL_THEN;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::{SpanRangeExt, snippet_with_context};
 use clippy_utils::ty::is_copy;
-use clippy_utils::{
-    CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, is_trait_method, peel_blocks,
-};
+use clippy_utils::{CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, peel_blocks};
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -16,7 +15,7 @@
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) {
     if !expr.span.in_external_macro(cx.sess().source_map())
-        && is_trait_method(cx, expr, sym::Iterator)
+        && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && let ExprKind::Closure(closure) = arg.kind
         && let body = cx.tcx.hir_body(closure.body)
         && let value = peel_blocks(body.value)
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
index b04d761..c6e3071 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_expr_identity_function, is_expr_untyped_identity_function, is_trait_method};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
+use clippy_utils::{is_expr_identity_function, is_expr_untyped_identity_function};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::ExprKind;
@@ -19,7 +20,7 @@ fn is_identity(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Applicabili
 }
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) {
-    if is_trait_method(cx, expr, sym::Iterator)
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && let Some(applicability) = is_identity(cx, filter_map_arg)
     {
         // check if the iterator is from an empty array, see issue #12653
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
index 9f3c346..698025d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::is_trait_method;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(
     arg: &'tcx hir::Expr<'_>,
     msrv: Msrv,
 ) {
-    if is_trait_method(cx, expr, sym::Iterator) {
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) {
         if !msrv.meets(cx, msrvs::ITERATOR_FIND_MAP) {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
index 0c2ecfb..043adb8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
+use clippy_utils::is_expr_untyped_identity_function;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -14,7 +15,9 @@ pub(super) fn check<'tcx>(
     flat_map_arg: &'tcx hir::Expr<'_>,
     flat_map_span: Span,
 ) {
-    if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, flat_map_arg) {
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
+        && is_expr_untyped_identity_function(cx, flat_map_arg)
+    {
         span_lint_and_sugg(
             cx,
             FLAT_MAP_IDENTITY,
diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
index 3242dca..fb0e8f9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -7,10 +7,9 @@
 use rustc_span::{Span, sym};
 
 use super::FLAT_MAP_OPTION;
-use clippy_utils::ty::is_type_diagnostic_item;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) {
-    if !is_trait_method(cx, expr, sym::Iterator) {
+    if !cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) {
         return;
     }
     let arg_ty = cx.typeck_results().expr_ty_adjusted(arg);
@@ -19,7 +18,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg
         _ if arg_ty.is_fn() => arg_ty.fn_sig(cx.tcx),
         _ => return,
     };
-    if !is_type_diagnostic_item(cx, sig.output().skip_binder(), sym::Option) {
+    if !sig.output().skip_binder().is_diag_item(cx, sym::Option) {
         return;
     }
     span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
index 1b28596..7b2fe00 100644
--- a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
@@ -1,7 +1,7 @@
 use super::FORMAT_COLLECT;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{is_format_macro, root_macro_call_first_node};
-use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::res::MaybeDef;
 use rustc_hir::{Expr, ExprKind, LangItem};
 use rustc_lint::LateContext;
 use rustc_span::Span;
@@ -17,7 +17,7 @@ fn peel_non_expn_blocks<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>
 }
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) {
-    if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String)
+    if cx.typeck_results().expr_ty(expr).is_lang_item(cx, LangItem::String)
         && let ExprKind::Closure(closure) = map_arg.kind
         && let body = cx.tcx.hir_body(closure.body)
         && let Some(value) = peel_non_expn_blocks(body.value)
diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index d664eaa..11671f3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -1,9 +1,10 @@
 use std::fmt::Write as _;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sugg;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_path_diagnostic_item, sugg};
 use rustc_ast::join_path_idents;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -15,7 +16,7 @@
 use super::FROM_ITER_INSTEAD_OF_COLLECT;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>], func: &Expr<'_>) {
-    if is_path_diagnostic_item(cx, func, sym::from_iter_fn)
+    if func.res(cx).is_diag_item(cx, sym::from_iter_fn)
         && let arg_ty = cx.typeck_results().expr_ty(&args[0])
         && let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
         && implements_trait(cx, arg_ty, iter_id, &[])
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
index 2e1d71c..88e9f2f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_ast::LitKind;
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::Applicability;
@@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(
                 format!("{slice_name}.first()"),
                 app,
             );
-        } else if is_type_diagnostic_item(cx, identity, sym::VecDeque) {
+        } else if identity.is_diag_item(cx, sym::VecDeque) {
             let mut app = Applicability::MachineApplicable;
             let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
             span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
index 9daad1a..d273558 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
@@ -2,7 +2,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -22,16 +21,17 @@ pub(super) fn check<'tcx>(
     let expr_ty = cx.typeck_results().expr_ty(recv);
     let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() {
         "slice"
-    } else if is_type_diagnostic_item(cx, expr_ty, sym::Vec) {
-        "Vec"
-    } else if is_type_diagnostic_item(cx, expr_ty, sym::VecDeque) {
-        "VecDeque"
-    } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::HashMap) {
-        "HashMap"
-    } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::BTreeMap) {
-        "BTreeMap"
     } else {
-        return; // caller is not a type that we want to lint
+        match expr_ty
+            .ty_adt_def()
+            .and_then(|def| cx.tcx.get_diagnostic_name(def.did()))
+        {
+            Some(sym::Vec) => "Vec",
+            Some(sym::VecDeque) => "VecDeque",
+            Some(sym::HashMap) if !is_mut => "HashMap",
+            Some(sym::BTreeMap) if !is_mut => "BTreeMap",
+            _ => return, // caller is not a type that we want to lint
+        }
     };
 
     let mut span = expr.span;
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 0ba8491..57c0ba2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_context;
+use clippy_utils::sym;
 use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs};
-use clippy_utils::{is_diag_item_method, is_diag_trait_item, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -10,12 +11,12 @@
 use super::IMPLICIT_CLONE;
 
 pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
-    if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
-        && is_clone_like(cx, method_name, method_def_id)
+    if let Some(method_parent_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id).opt_parent(cx)
+        && is_clone_like(cx, method_name, method_parent_id)
         && let return_type = cx.typeck_results().expr_ty(expr)
         && let input_type = cx.typeck_results().expr_ty(recv)
         && let (input_type, ref_count, _) = peel_and_count_ty_refs(input_type)
-        && !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned))
+        && !(ref_count > 0 && method_parent_id.is_diag_item(cx, sym::ToOwned))
         && let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()))
         && return_type == input_type
         && let Some(clone_trait) = cx.tcx.lang_items().clone_trait()
@@ -40,19 +41,15 @@ pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, re
 }
 
 /// Returns true if the named method can be used to clone the receiver.
-pub fn is_clone_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: hir::def_id::DefId) -> bool {
+pub fn is_clone_like(cx: &LateContext<'_>, method_name: Symbol, method_parent_id: hir::def_id::DefId) -> bool {
     match method_name {
-        sym::to_os_string => is_diag_item_method(cx, method_def_id, sym::OsStr),
-        sym::to_owned => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
-        sym::to_path_buf => is_diag_item_method(cx, method_def_id, sym::Path),
-        sym::to_string => is_diag_trait_item(cx, method_def_id, sym::ToString),
-        sym::to_vec => cx
-            .tcx
-            .impl_of_assoc(method_def_id)
-            .filter(|&impl_did| {
-                cx.tcx.type_of(impl_did).instantiate_identity().is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none()
-            })
-            .is_some(),
+        sym::to_os_string => method_parent_id.opt_impl_ty(cx).is_diag_item(cx, sym::OsStr),
+        sym::to_owned => method_parent_id.is_diag_item(cx, sym::ToOwned),
+        sym::to_path_buf => method_parent_id.opt_impl_ty(cx).is_diag_item(cx, sym::Path),
+        sym::to_string => method_parent_id.is_diag_item(cx, sym::ToString),
+        sym::to_vec => method_parent_id
+            .opt_impl_ty(cx)
+            .is_some_and(|ty| ty.instantiate_identity().is_slice()),
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index ab21515f..7a49a5f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -1,27 +1,18 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_type_lang_item, peel_and_count_ty_refs};
+use clippy_utils::ty::peel_and_count_ty_refs;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::symbol::{Symbol, sym};
+use rustc_span::symbol::sym;
 
 use super::INEFFICIENT_TO_STRING;
 
-/// Checks for the `INEFFICIENT_TO_STRING` lint
-pub fn check(
-    cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    method_name: Symbol,
-    receiver: &hir::Expr<'_>,
-    args: &[hir::Expr<'_>],
-    msrv: Msrv,
-) {
-    if args.is_empty()
-        && method_name == sym::to_string
-        && let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, msrv: Msrv) {
+    if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
         && cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did)
         && let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id)
         && let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver)
@@ -61,7 +52,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
         return true;
     }
 
-    if is_type_lang_item(cx, ty, hir::LangItem::String) {
+    if ty.is_lang_item(cx, hir::LangItem::String) {
         return true;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs
index 3706f3b..194ddf4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::{Span, sym};
@@ -8,7 +8,7 @@
 
 /// lint use of `inspect().for_each()` for `Iterators`
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, inspect_span: Span) {
-    if is_trait_method(cx, expr, sym::Iterator) {
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) {
         let msg = "called `inspect(..).for_each(..)` on an `Iterator`";
         let hint = "move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)`";
         span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
index bedeb63..c4b116a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::ty::has_iter_method;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -10,17 +10,10 @@
 
 use super::INTO_ITER_ON_REF;
 
-pub(super) fn check(
-    cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
-    method_span: Span,
-    method_name: Symbol,
-    receiver: &hir::Expr<'_>,
-) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Span, receiver: &hir::Expr<'_>) {
     let self_ty = cx.typeck_results().expr_ty_adjusted(receiver);
     if let ty::Ref(..) = self_ty.kind()
-        && method_name == sym::into_iter
-        && is_trait_method(cx, expr, sym::IntoIterator)
+        && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::IntoIterator)
         && let Some((kind, method_name)) = ty_has_iter_method(cx, self_ty)
     {
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs b/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs
index 9276261..b081e80 100644
--- a/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::{expr_or_init, is_path_diagnostic_item, sym};
+use clippy_utils::res::{MaybeDef, MaybeQPath};
+use clippy_utils::{expr_or_init, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
@@ -10,7 +11,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, path: &Expr<'_>, args
         && !expr.span.from_expansion()
         && !error_kind.span.from_expansion()
         && let ExprKind::Path(QPath::TypeRelative(_, new_segment)) = path.kind
-        && is_path_diagnostic_item(cx, path, sym::io_error_new)
+        && path.ty_rel_def(cx).is_diag_item(cx, sym::io_error_new)
         && let ExprKind::Path(QPath::Resolved(_, init_path)) = &expr_or_init(cx, error_kind).kind
         && let [.., error_kind_ty, error_kind_variant] = init_path.segments
         && cx.tcx.is_diagnostic_item(sym::io_errorkind, error_kind_ty.res.def_id())
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
index 545bef1..add01b6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
@@ -1,7 +1,8 @@
 use clippy_utils::consts::ConstEvalCtxt;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::macros::{is_assert_macro, root_macro_call};
-use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context, path_to_local};
+use clippy_utils::res::MaybeResPath;
+use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context};
 use rustc_hir::{Expr, HirId};
 use rustc_lint::{LateContext, LintContext};
 use rustc_span::sym;
@@ -45,7 +46,8 @@ fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool {
 /// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization
 /// value depends on a `#[cfg(…)]` directive.
 fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
-    while let Some(init) = path_to_local(expr)
+    while let Some(init) = expr
+        .res_local_id()
         .and_then(|id| find_binding_init(cx, id))
         .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())
         .filter(|init| !is_under_cfg(cx, init.hir_id))
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
index b4ab313..b1a0b65 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
@@ -1,6 +1,7 @@
 use crate::methods::utils::derefs_to_slice;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::{get_iterator_item_ty, is_type_diagnostic_item};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::ty::get_iterator_item_ty;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -16,7 +17,7 @@ pub(super) fn check<'tcx>(
     recv: &'tcx hir::Expr<'_>,
 ) {
     let expr_ty = cx.typeck_results().expr_ty(expr);
-    if is_type_diagnostic_item(cx, expr_ty, sym::Vec)
+    if expr_ty.is_diag_item(cx, sym::Vec)
         && let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv))
         && let ty::Adt(_, args) = expr_ty.kind()
         && let Some(iter_item_ty) = get_iterator_item_ty(cx, cx.typeck_results().expr_ty(recv))
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
index 6b64cc8..ea2508c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
@@ -1,7 +1,7 @@
 use super::utils::derefs_to_slice;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -13,21 +13,21 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
     let ty = cx.typeck_results().expr_ty(recv);
     let caller_type = if derefs_to_slice(cx, recv, ty).is_some() {
         "slice"
-    } else if is_type_diagnostic_item(cx, ty, sym::Vec) {
+    } else if ty.is_diag_item(cx, sym::Vec) {
         "Vec"
-    } else if is_type_diagnostic_item(cx, ty, sym::VecDeque) {
+    } else if ty.is_diag_item(cx, sym::VecDeque) {
         "VecDeque"
-    } else if is_type_diagnostic_item(cx, ty, sym::HashSet) {
+    } else if ty.is_diag_item(cx, sym::HashSet) {
         "HashSet"
-    } else if is_type_diagnostic_item(cx, ty, sym::HashMap) {
+    } else if ty.is_diag_item(cx, sym::HashMap) {
         "HashMap"
-    } else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) {
+    } else if ty.is_diag_item(cx, sym::BTreeMap) {
         "BTreeMap"
-    } else if is_type_diagnostic_item(cx, ty, sym::BTreeSet) {
+    } else if ty.is_diag_item(cx, sym::BTreeSet) {
         "BTreeSet"
-    } else if is_type_diagnostic_item(cx, ty, sym::LinkedList) {
+    } else if ty.is_diag_item(cx, sym::LinkedList) {
         "LinkedList"
-    } else if is_type_diagnostic_item(cx, ty, sym::BinaryHeap) {
+    } else if ty.is_diag_item(cx, sym::BinaryHeap) {
         "BinaryHeap"
     } else {
         return;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
index adeff37..8d95b70 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
@@ -1,3 +1,4 @@
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::ty::get_iterator_item_ty;
 use hir::ExprKind;
 use rustc_lint::{LateContext, LintContext};
@@ -6,7 +7,7 @@
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, reindent_multiline};
-use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_comment, sym};
+use clippy_utils::{get_parent_expr, peel_blocks, span_contains_comment, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::QPath;
@@ -107,7 +108,7 @@ fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
     if let Some(expr) = get_parent_expr(cx, expr)
         && let ExprKind::MethodCall(path, _, [_], _) = expr.kind
         && path.ident.name == sym::map
-        && is_trait_method(cx, expr, sym::Iterator)
+        && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
     {
         return true;
     }
@@ -141,7 +142,7 @@ fn expression_type(
     filter_arg: &hir::Expr<'_>,
     filter_span: Span,
 ) -> Option<FilterType> {
-    if !is_trait_method(cx, expr, sym::Iterator)
+    if !cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         || parent_is_map(cx, expr)
         || span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi()))
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index cbb1b45..2d6bc36 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -1,8 +1,8 @@
 use super::ITER_KV_MAP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{pat_is_wild, sym};
 use rustc_hir::{Body, Expr, ExprKind, PatKind};
 use rustc_lint::LateContext;
@@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(
             _ => return,
         }
         && let ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs()
-        && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap))
+        && (ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap))
     {
         let mut applicability = rustc_errors::Applicability::MachineApplicable;
         let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
index fd4650e..01f35ff 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
@@ -1,7 +1,7 @@
 use super::utils::derefs_to_slice;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{get_parent_expr, higher};
 use rustc_ast::ast;
 use rustc_errors::Applicability;
@@ -75,6 +75,6 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
 }
 
 fn is_vec_or_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool {
-    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec)
+    cx.typeck_results().expr_ty(expr).is_diag_item(cx, sym::Vec)
         || matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _))
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
index 1fdbd81..6d1ee32 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::sym;
-use clippy_utils::ty::get_type_diagnostic_name;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(
     iter_span: Span,
     nth_span: Span,
 ) -> bool {
-    let caller_type = match get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(iter_recv).peel_refs()) {
+    let caller_type = match cx.typeck_results().expr_ty(iter_recv).peel_refs().opt_diag_name(cx) {
         Some(sym::Vec) => "`Vec`",
         Some(sym::VecDeque) => "`VecDeque`",
         _ if cx.typeck_results().expr_ty_adjusted(iter_recv).peel_refs().is_slice() => "slice",
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
index 0f8abd0..e0107b7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
@@ -1,7 +1,8 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_lang_item_or_ctor;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_lang_item_or_ctor, is_trait_method};
 use hir::{LangItem, OwnerNode};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -13,7 +14,7 @@
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
     if let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir_get_parent_item(expr.hir_id))
         && let def_id = item.owner_id.to_def_id()
-        && is_trait_method(cx, expr, sym::Iterator)
+        && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval_local(arg, expr.span.ctxt())
         && !is_lang_item_or_ctor(cx, def_id, LangItem::IteratorNext)
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
index 83e5655..8183c30 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
@@ -1,9 +1,10 @@
 use std::iter::once;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{ExprFnSig, expr_sig, ty_sig};
-use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core, sym};
+use clippy_utils::{get_expr_use_or_unification_node, std_or_core, sym};
 
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -67,8 +68,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method
     let item = match recv.kind {
         ExprKind::Array([]) => None,
         ExprKind::Array([e]) => Some(e),
-        ExprKind::Path(ref p) if is_res_lang_ctor(cx, cx.qpath_res(p, recv.hir_id), OptionNone) => None,
-        ExprKind::Call(f, [arg]) if is_res_lang_ctor(cx, path_res(cx, f), OptionSome) => Some(arg),
+        ExprKind::Path(ref p)
+            if cx
+                .qpath_res(p, recv.hir_id)
+                .ctor_parent(cx)
+                .is_lang_item(cx, OptionNone) =>
+        {
+            None
+        },
+        ExprKind::Call(f, [arg]) if f.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome) => Some(arg),
         _ => return,
     };
     let iter_type = match method_name {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs
index fa8f9d6..8cff3bd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::expr_or_init;
 use clippy_utils::higher::VecArgs;
-use clippy_utils::{expr_or_init, is_trait_method};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -58,7 +59,7 @@ fn check<'tcx>(
     message: &'static str,
     note: &'static str,
 ) {
-    if is_trait_method(cx, expr, sym::Iterator)
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && let Some(len) = get_iterator_length(cx, recv)
         && let Some(skipped) = expr_as_u128(cx, arg)
         && skipped > len
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
index fedb7c2..661188c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
 use clippy_utils::source::snippet;
-use clippy_utils::{is_trait_method, path_to_local};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::{BindingMode, Node, PatKind};
@@ -11,20 +11,20 @@
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
     // lint if caller of skip is an Iterator
-    if is_trait_method(cx, expr, sym::Iterator) {
-        let mut application = Applicability::MachineApplicable;
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) {
+        let mut applicability = Applicability::MachineApplicable;
         span_lint_and_then(
             cx,
             ITER_SKIP_NEXT,
             expr.span.trim_start(recv.span).unwrap(),
             "called `skip(..).next()` on an iterator",
             |diag| {
-                if let Some(id) = path_to_local(recv)
+                if let Some(id) = recv.res_local_id()
                     && let Node::Pat(pat) = cx.tcx.hir_node(id)
                     && let PatKind::Binding(ann, _, _, _) = pat.kind
                     && ann != BindingMode::MUT
                 {
-                    application = Applicability::Unspecified;
+                    applicability = Applicability::Unspecified;
                     diag.span_help(
                         pat.span,
                         format!("for this change `{}` has to be mutable", snippet(cx, pat.span, "..")),
@@ -35,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
                     expr.span.trim_start(recv.span).unwrap(),
                     "use `nth` instead",
                     format!(".nth({})", snippet(cx, arg.span, "..")),
-                    application,
+                    applicability,
                 );
             },
         );
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
index 663e344..cae31e7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
@@ -1,6 +1,7 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{is_from_proc_macro, is_trait_method};
+use clippy_utils::is_from_proc_macro;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -10,7 +11,7 @@
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg_expr: &Expr<'_>) {
     if !expr.span.from_expansion()
-        && is_trait_method(cx, expr, sym::Iterator)
+        && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && let Some(arg) = ConstEvalCtxt::new(cx)
             .eval_local(arg_expr, expr.span.ctxt())
             .and_then(|constant| {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
index 90d5d9d..11dde24 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
@@ -1,6 +1,6 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::sym;
@@ -8,7 +8,7 @@
 use super::ITERATOR_STEP_BY_ZERO;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
-    if is_trait_method(cx, expr, sym::Iterator)
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg)
     {
         span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs
index 2ad0707..e84b745 100644
--- a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::expr_or_init;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -13,7 +13,7 @@
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_arg: &'tcx Expr<'tcx>, expr_span: Span) {
     let ty = cx.typeck_results().expr_ty(recv).peel_refs();
-    if (is_type_diagnostic_item(cx, ty, sym::Path) || is_type_diagnostic_item(cx, ty, sym::PathBuf))
+    if (ty.is_diag_item(cx, sym::Path) || ty.is_diag_item(cx, sym::PathBuf))
         && let ExprKind::Lit(spanned) = expr_or_init(cx, join_arg).kind
         && let LitKind::Str(symbol, _) = spanned.node
         && let sym_str = symbol.as_str()
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
index bc96815..1a5b180 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
@@ -1,9 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::{IntoSpan, SpanRangeExt};
 use clippy_utils::ty::get_field_by_name;
 use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
-use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, sym};
+use clippy_utils::{ExprUseNode, expr_use_ctxt, sym};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind};
@@ -18,9 +19,10 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
     if let ExprKind::Closure(c) = arg.kind
         && matches!(c.kind, ClosureKind::Closure)
         && let typeck = cx.typeck_results()
-        && let Some(fn_id) = typeck.type_dependent_def_id(expr.hir_id)
-        && (is_diag_trait_item(cx, fn_id, sym::Iterator)
-            || ((is_diag_item_method(cx, fn_id, sym::Option) || is_diag_item_method(cx, fn_id, sym::Result))
+        && let Some(fn_def) = typeck.type_dependent_def(expr.hir_id)
+        && (fn_def.opt_parent(cx).is_diag_item(cx, sym::Iterator)
+            || ((fn_def.opt_parent(cx).opt_impl_ty(cx).is_diag_item(cx, sym::Option)
+                || fn_def.opt_parent(cx).opt_impl_ty(cx).is_diag_item(cx, sym::Result))
                 && msrv.meets(cx, msrvs::OPTION_RESULT_INSPECT)))
         && let body = cx.tcx.hir_body(c.body)
         && let [param] = body.params
@@ -29,7 +31,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
         && let ExprKind::Block(block, _) = body.value.kind
         && let Some(final_expr) = block.expr
         && !block.stmts.is_empty()
-        && path_to_local_id(final_expr, arg_id)
+        && final_expr.res_local_id() == Some(arg_id)
         && typeck.expr_adjustments(final_expr).is_empty()
     {
         let mut requires_copy = false;
@@ -46,7 +48,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
             if let ExprKind::Closure(c) = e.kind {
                 // Nested closures don't need to treat returns specially.
                 let _: Option<!> = for_each_expr(cx, cx.tcx.hir_body(c.body).value, |e| {
-                    if path_to_local_id(e, arg_id) {
+                    if e.res_local_id() == Some(arg_id) {
                         let (kind, same_ctxt) = check_use(cx, e);
                         match (kind, same_ctxt && e.span.ctxt() == ctxt) {
                             (_, false) | (UseKind::Deref | UseKind::Return(..), true) => {
@@ -64,7 +66,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
                 });
             } else if matches!(e.kind, ExprKind::Ret(_)) {
                 ret_count += 1;
-            } else if path_to_local_id(e, arg_id) {
+            } else if e.res_local_id() == Some(arg_id) {
                 let (kind, same_ctxt) = check_use(cx, e);
                 match (kind, same_ctxt && e.span.ctxt() == ctxt) {
                     (UseKind::Return(..), false) => {
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs
index 93325ca..8f65858 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{get_parent_expr, sym};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
@@ -30,8 +30,8 @@ pub(super) fn check(
     }
 
     // 2. the caller of `map()` is neither `Option` nor `Result`
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(map_recv), sym::Option);
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(map_recv), sym::Result);
+    let is_option = cx.typeck_results().expr_ty(map_recv).is_diag_item(cx, sym::Option);
+    let is_result = cx.typeck_results().expr_ty(map_recv).is_diag_item(cx, sym::Result);
     if !is_option && !is_result {
         return;
     }
@@ -208,7 +208,7 @@ pub(super) fn check_map(cx: &LateContext<'_>, expr: &Expr<'_>) {
                     && cx.tcx.is_diagnostic_item(flavor.symbol(), adt.did())
                     && args.type_at(0).is_bool()
                     && let ExprKind::MethodCall(_, recv, [map_expr], _) = expr2.kind
-                    && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), flavor.symbol())
+                    && cx.typeck_results().expr_ty(recv).is_diag_item(cx, flavor.symbol())
                     && let Ok(map_func) = MapFunc::try_from(map_expr)
                 {
                     return emit_lint(cx, parent_expr.span, op, flavor, bool_cst, map_func, recv);
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs
index 9a03559..b064f97 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::ty::implements_trait;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
@@ -20,8 +20,8 @@ pub(super) fn check<'tcx>(
         .tcx
         .get_diagnostic_item(sym::DoubleEndedIterator)
         .is_some_and(|double_ended_iterator| implements_trait(cx, rev_recv_ty, double_ended_iterator, &[]))
-        && is_trait_method(cx, rev_call, sym::Iterator)
-        && is_trait_method(cx, expr, sym::Iterator)
+        && cx.ty_based_def(rev_call).opt_parent(cx).is_diag_item(cx, sym::Iterator)
+        && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
     {
         span_lint_and_sugg(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
index 077957f..a8e30e4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
 use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{ResultErr, ResultOk};
 use rustc_hir::{Expr, ExprKind, PatKind};
@@ -19,9 +18,13 @@ pub(super) fn check<'tcx>(
 ) {
     if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
-        && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Option)
+        && cx
+            .tcx
+            .type_of(impl_id)
+            .instantiate_identity()
+            .is_diag_item(cx, sym::Option)
         && let ExprKind::Call(err_path, [err_arg]) = or_expr.kind
-        && is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr)
+        && err_path.res(cx).ctor_parent(cx).is_lang_item(cx, ResultErr)
         && is_ok_wrapping(cx, map_expr)
         && let Some(recv_snippet) = recv.span.get_source_text(cx)
         && let Some(err_arg_snippet) = err_arg.span.get_source_text(cx)
@@ -42,14 +45,21 @@ pub(super) fn check<'tcx>(
 
 fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
     match map_expr.kind {
-        ExprKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, map_expr.hir_id), ResultOk) => true,
+        ExprKind::Path(ref qpath)
+            if cx
+                .qpath_res(qpath, map_expr.hir_id)
+                .ctor_parent(cx)
+                .is_lang_item(cx, ResultOk) =>
+        {
+            true
+        },
         ExprKind::Closure(closure) => {
             let body = cx.tcx.hir_body(closure.body);
             if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind
                 && let ExprKind::Call(callee, [ok_arg]) = body.value.kind
-                && is_res_lang_ctor(cx, path_res(cx, callee), ResultOk)
+                && callee.res(cx).ctor_parent(cx).is_lang_item(cx, ResultOk)
             {
-                path_to_local_id(ok_arg, param_id)
+                ok_arg.res_local_id() == Some(param_id)
             } else {
                 false
             }
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_repeat_n.rs b/src/tools/clippy/clippy_lints/src/methods/manual_repeat_n.rs
index 83b57cc..1a7628e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_repeat_n.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_repeat_n.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::{snippet, snippet_with_context};
-use clippy_utils::{expr_use_ctxt, fn_def_id, is_trait_method, std_or_core};
+use clippy_utils::{expr_use_ctxt, fn_def_id, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -17,7 +18,7 @@ pub(super) fn check<'tcx>(
     msrv: Msrv,
 ) {
     if !expr.span.from_expansion()
-        && is_trait_method(cx, expr, sym::Iterator)
+        && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && let ExprKind::Call(_, [repeat_arg]) = repeat_expr.kind
         && let Some(def_id) = fn_def_id(cx, repeat_expr)
         && cx.tcx.is_diagnostic_item(sym::iter_repeat, def_id)
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index c785b23b..2196ce9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{path_res, sym};
+use clippy_utils::sym;
 use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -83,7 +84,7 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
 
     // `T::MAX` and `T::MIN` constants
     if let hir::ExprKind::Path(hir::QPath::TypeRelative(base, seg)) = expr.kind
-        && let Res::PrimTy(_) = path_res(cx, base)
+        && matches!(base.basic_res(), Res::PrimTy(_))
     {
         match seg.ident.name {
             sym::MAX => return Some(MinMax::Max),
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
index a811dd1..4fe14f8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
@@ -1,8 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_path_diagnostic_item;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem};
@@ -35,14 +34,14 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
         }
     } else {
         let ty = cx.typeck_results().expr_ty(e);
-        if is_type_lang_item(cx, ty, LangItem::String)
-            || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).is_some_and(Ty::is_str))
-            || (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).is_some_and(Ty::is_str))
+        if ty.is_lang_item(cx, LangItem::String)
+            || (ty.is_lang_item(cx, LangItem::OwnedBox) && get_ty_param(ty).is_some_and(Ty::is_str))
+            || (ty.is_diag_item(cx, sym::Cow) && get_ty_param(ty).is_some_and(Ty::is_str))
         {
             Some(RepeatKind::String)
         } else {
             let ty = ty.peel_refs();
-            (ty.is_str() || is_type_lang_item(cx, ty, LangItem::String)).then_some(RepeatKind::String)
+            (ty.is_str() || ty.is_lang_item(cx, LangItem::String)).then_some(RepeatKind::String)
         }
     }
 }
@@ -55,8 +54,11 @@ pub(super) fn check(
     take_arg: &Expr<'_>,
 ) {
     if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind
-        && is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat)
-        && is_type_lang_item(cx, cx.typeck_results().expr_ty(collect_expr), LangItem::String)
+        && repeat_fn.basic_res().is_diag_item(cx, sym::iter_repeat)
+        && cx
+            .typeck_results()
+            .expr_ty(collect_expr)
+            .is_lang_item(cx, LangItem::String)
         && let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id)
         && let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
         && cx.tcx.trait_of_assoc(take_id) == Some(iter_trait_id)
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
index 23dba47..f2e127b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_from_proc_macro, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind};
@@ -20,7 +21,7 @@ pub(super) fn check<'tcx>(
     msrv: Msrv,
 ) {
     if !fold_span.in_external_macro(cx.sess().source_map())
-        && is_trait_method(cx, expr, sym::Iterator)
+        && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && let init_ty = cx.typeck_results().expr_ty(init)
         && let Some(try_trait) = cx.tcx.lang_items().try_trait()
         && implements_trait(cx, init_ty, try_trait, &[])
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_all_any_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_all_any_identity.rs
index ac11baa..ad950f7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_all_any_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_all_any_identity.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_expr_identity_function;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{is_expr_identity_function, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -8,7 +9,7 @@
 
 use super::MAP_ALL_ANY_IDENTITY;
 
-#[allow(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments)]
 pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &Expr<'_>,
@@ -19,8 +20,8 @@ pub(super) fn check(
     any_arg: &Expr<'_>,
     method: &str,
 ) {
-    if is_trait_method(cx, expr, sym::Iterator)
-        && is_trait_method(cx, recv, sym::Iterator)
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
+        && cx.ty_based_def(recv).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && is_expr_identity_function(cx, any_arg)
         && let map_any_call_span = map_call_span.with_hi(any_call_span.hi())
         && let Some(map_arg) = map_arg.span.get_source_text(cx)
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index 748be9b..1bc29c9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::peel_blocks;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_copy, is_type_diagnostic_item, should_call_clone_as_function};
-use clippy_utils::{is_diag_trait_item, peel_blocks};
+use clippy_utils::ty::{is_copy, should_call_clone_as_function};
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, LangItem};
@@ -18,14 +19,13 @@
 // If this `map` is called on an `Option` or a `Result` and the previous call is `as_ref`, we don't
 // run this lint because it would overlap with `useless_asref` which provides a better suggestion
 // in this case.
-fn should_run_lint(cx: &LateContext<'_>, e: &hir::Expr<'_>, method_id: DefId) -> bool {
-    if is_diag_trait_item(cx, method_id, sym::Iterator) {
+fn should_run_lint(cx: &LateContext<'_>, e: &hir::Expr<'_>, method_parent_id: DefId) -> bool {
+    if method_parent_id.is_diag_item(cx, sym::Iterator) {
         return true;
     }
     // We check if it's an `Option` or a `Result`.
-    if let Some(id) = cx.tcx.impl_of_assoc(method_id) {
-        let identity = cx.tcx.type_of(id).instantiate_identity();
-        if !is_type_diagnostic_item(cx, identity, sym::Option) && !is_type_diagnostic_item(cx, identity, sym::Result) {
+    if let Some(ty) = method_parent_id.opt_impl_ty(cx) {
+        if !ty.is_diag_item(cx, sym::Option) && !ty.is_diag_item(cx, sym::Result) {
             return false;
         }
     } else {
@@ -42,8 +42,8 @@ fn should_run_lint(cx: &LateContext<'_>, e: &hir::Expr<'_>, method_id: DefId) ->
 }
 
 pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, msrv: Msrv) {
-    if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
-        && should_run_lint(cx, e, method_id)
+    if let Some(parent_id) = cx.typeck_results().type_dependent_def_id(e.hir_id).opt_parent(cx)
+        && should_run_lint(cx, e, parent_id)
     {
         match arg.kind {
             hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs b/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
index e944eac..1112fbc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_collect_result_unit.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -12,7 +12,7 @@
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr<'_>, map_fn: &hir::Expr<'_>) {
     // return of collect `Result<(),_>`
     let collect_ret_ty = cx.typeck_results().expr_ty(expr);
-    if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result)
+    if collect_ret_ty.is_diag_item(cx, sym::Result)
         && let ty::Adt(_, args) = collect_ret_ty.kind()
         && let Some(result_t) = args.types().next()
         && result_t.is_unit()
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
index 41beda9..f7da24b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_err_ignore.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::sym;
@@ -9,7 +9,11 @@
 pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, arg: &Expr<'_>) {
     if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
-        && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Result)
+        && cx
+            .tcx
+            .type_of(impl_id)
+            .instantiate_identity()
+            .is_diag_item(cx, sym::Result)
         && let ExprKind::Closure(&Closure {
             capture_clause: CaptureBy::Ref,
             body,
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
index 750f933..e4ae14b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_trait_method, span_contains_comment};
+use clippy_utils::span_contains_comment;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -40,7 +40,7 @@ fn try_get_caller_ty_name_and_method_name(
     caller_expr: &Expr<'_>,
     map_arg: &Expr<'_>,
 ) -> Option<(&'static str, &'static str)> {
-    if is_trait_method(cx, expr, sym::Iterator) {
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) {
         if is_map_to_option(cx, map_arg) {
             // `(...).map(...)` has type `impl Iterator<Item=Option<...>>
             Some(("Iterator", "filter_map"))
@@ -69,7 +69,7 @@ fn is_map_to_option(cx: &LateContext<'_>, map_arg: &Expr<'_>) -> bool {
                 _ => map_closure_ty.fn_sig(cx.tcx),
             };
             let map_closure_return_ty = cx.tcx.instantiate_bound_regions_with_erased(map_closure_sig.output());
-            is_type_diagnostic_item(cx, map_closure_return_ty, sym::Option)
+            map_closure_return_ty.is_diag_item(cx, sym::Option)
         },
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
index 6190c43..fa39452 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
-use clippy_utils::{is_expr_untyped_identity_function, is_mutable, is_trait_method, path_to_local_with_projections};
+use clippy_utils::ty::is_copy;
+use clippy_utils::{is_expr_untyped_identity_function, is_mutable, path_to_local_with_projections};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, ExprKind, Node, PatKind};
 use rustc_lint::{LateContext, LintContext};
@@ -21,9 +22,9 @@ pub(super) fn check(
 ) {
     let caller_ty = cx.typeck_results().expr_ty(caller);
 
-    if (is_trait_method(cx, expr, sym::Iterator)
-        || is_type_diagnostic_item(cx, caller_ty, sym::Result)
-        || is_type_diagnostic_item(cx, caller_ty, sym::Option))
+    if (cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
+        || caller_ty.is_diag_item(cx, sym::Result)
+        || caller_ty.is_diag_item(cx, sym::Option))
         && is_expr_untyped_identity_function(cx, map_arg)
         && let Some(call_span) = expr.span.trim_start(caller.span)
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
index df5a0de..62bdc4a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::usage::mutated_variables;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -22,8 +22,8 @@ pub(super) fn check<'tcx>(
     msrv: Msrv,
 ) -> bool {
     // lint if the caller of `map()` is an `Option` or a `Result`.
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
+    let is_option = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option);
+    let is_result = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result);
 
     if is_result && !msrv.meets(cx, msrvs::RESULT_MAP_OR_ELSE) {
         return false;
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index b0b4e5e..c9066be 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -133,6 +133,7 @@
 mod unnecessary_literal_unwrap;
 mod unnecessary_map_or;
 mod unnecessary_min_or_max;
+mod unnecessary_option_map_or_else;
 mod unnecessary_result_map_or_else;
 mod unnecessary_sort_by;
 mod unnecessary_to_owned;
@@ -151,7 +152,8 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::macros::FormatArgsStorage;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::{contains_return, is_trait_method, iter_input_pats, peel_blocks, sym};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
+use clippy_utils::{contains_return, iter_input_pats, peel_blocks, sym};
 pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::{self as hir, Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
@@ -4639,6 +4641,30 @@
     "detects redundant calls to `Iterator::cloned`"
 }
 
+declare_clippy_lint! {
+    /// Checks for usage of `.map_or_else()` "map closure" for `Option` type.
+    ///
+    /// ### Why is this bad?
+    /// This can be written more concisely by using `unwrap_or_else()`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let k = 10;
+    /// let x: Option<u32> = Some(4);
+    /// let y = x.map_or_else(|| 2 * k, |n| n);
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let k = 10;
+    /// let x: Option<u32> = Some(4);
+    /// let y = x.unwrap_or_else(|| 2 * k);
+    /// ```
+    #[clippy::version = "1.88.0"]
+    pub UNNECESSARY_OPTION_MAP_OR_ELSE,
+    suspicious,
+    "making no use of the \"map closure\" when calling `.map_or_else(|| 2 * k, |n| n)`"
+}
+
 #[expect(clippy::struct_excessive_bools)]
 pub struct Methods {
     avoid_breaking_exported_api: bool,
@@ -4820,6 +4846,7 @@ pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
     SWAP_WITH_TEMPORARY,
     IP_CONSTANT,
     REDUNDANT_ITER_CLONED,
+    UNNECESSARY_OPTION_MAP_OR_ELSE,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4842,8 +4869,6 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             return;
         }
 
-        self.check_methods(cx, expr);
-
         match expr.kind {
             ExprKind::Call(func, args) => {
                 from_iter_instead_of_collect::check(cx, expr, args, func);
@@ -4854,24 +4879,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 swap_with_temporary::check(cx, expr, func, args);
                 ip_constant::check(cx, expr, func, args);
             },
-            ExprKind::MethodCall(method_call, receiver, args, _) => {
-                let method_span = method_call.ident.span;
-                or_fun_call::check(cx, expr, method_span, method_call.ident.name, receiver, args, self.msrv);
-                expect_fun_call::check(
-                    cx,
-                    &self.format_args,
-                    expr,
-                    method_span,
-                    method_call.ident.name,
-                    receiver,
-                    args,
-                );
-                clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
-                clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
-                inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
-                single_char_add_str::check(cx, expr, receiver, args);
-                into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
-                unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
+            ExprKind::MethodCall(..) => {
+                self.check_methods(cx, expr);
             },
             ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
                 let mut info = BinaryExprInfo {
@@ -4886,7 +4895,6 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         }
     }
 
-    #[allow(clippy::too_many_lines)]
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
         if impl_item.span.in_external_macro(cx.sess().source_map()) {
             return;
@@ -4958,7 +4966,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
 }
 
 impl Methods {
-    #[allow(clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // Handle method calls whose receiver and arguments may not come from expansion
         if let Some((name, recv, args, span, call_span)) = method_call(expr) {
@@ -5044,7 +5052,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv);
                     option_as_ref_cloned::check(cx, recv, span);
                 },
-                (sym::collect, []) if is_trait_method(cx, expr, sym::Iterator) => {
+                (sym::collect, []) if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) => {
                     needless_collect::check(cx, span, expr, recv, call_span);
                     match method_call(recv) {
                         Some((name @ (sym::cloned | sym::copied), recv2, [], _, _)) => {
@@ -5065,17 +5073,26 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         _ => {},
                     }
                 },
-                (sym::count, []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
-                    Some((sym::cloned, recv2, [], _, _)) => {
-                        iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned, false);
-                    },
-                    Some((name2 @ (sym::into_iter | sym::iter | sym::iter_mut), recv2, [], _, _)) => {
-                        iter_count::check(cx, expr, recv2, name2);
-                    },
-                    Some((sym::map, _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
-                    Some((sym::filter, recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
-                    Some((sym::bytes, recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
-                    _ => {},
+                (sym::count, []) if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) => {
+                    match method_call(recv) {
+                        Some((sym::cloned, recv2, [], _, _)) => {
+                            iter_overeager_cloned::check(
+                                cx,
+                                expr,
+                                recv,
+                                recv2,
+                                iter_overeager_cloned::Op::RmCloned,
+                                false,
+                            );
+                        },
+                        Some((name2 @ (sym::into_iter | sym::iter | sym::iter_mut), recv2, [], _, _)) => {
+                            iter_count::check(cx, expr, recv2, name2);
+                        },
+                        Some((sym::map, _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
+                        Some((sym::filter, recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
+                        Some((sym::bytes, recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
+                        _ => {},
+                    }
                 },
                 (sym::min | sym::max, [arg]) => {
                     unnecessary_min_or_max::check(cx, expr, name, recv, arg);
@@ -5294,6 +5311,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 },
                 (sym::map_or_else, [def, map]) => {
                     result_map_or_else_none::check(cx, expr, recv, def, map);
+                    unnecessary_option_map_or_else::check(cx, expr, recv, def, map);
                     unnecessary_result_map_or_else::check(cx, expr, recv, def, map);
                 },
                 (sym::next, []) => {
@@ -5457,7 +5475,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     }
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
                 },
-                (sym::try_into, []) if is_trait_method(cx, expr, sym::TryInto) => {
+                (sym::try_into, []) if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::TryInto) => {
                     unnecessary_fallible_conversions::check_method(cx, expr);
                 },
                 (sym::to_owned, []) => {
@@ -5502,7 +5520,14 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                             option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv);
                         },
                         Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => {
-                            obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, name);
+                            obfuscated_if_else::check(
+                                cx,
+                                expr,
+                                t_recv,
+                                t_arg,
+                                then_method,
+                                obfuscated_if_else::Unwrap::Or(u_arg),
+                            );
                         },
                         _ => {},
                     }
@@ -5519,9 +5544,8 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                                 expr,
                                 t_recv,
                                 t_arg,
-                                None,
                                 then_method,
-                                sym::unwrap_or_default,
+                                obfuscated_if_else::Unwrap::OrDefault,
                             );
                         },
                         _ => {},
@@ -5538,9 +5562,8 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                                 expr,
                                 t_recv,
                                 t_arg,
-                                Some(u_arg),
                                 then_method,
-                                sym::unwrap_or_else,
+                                obfuscated_if_else::Unwrap::OrElse(u_arg),
                             );
                         },
                         _ => {
@@ -5567,8 +5590,18 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         }
         // Handle method calls whose receiver and arguments may come from expansion
         if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind {
+            let method_span = path.ident.span;
+
+            // Those methods do their own method name checking as they deal with multiple methods.
+            or_fun_call::check(cx, expr, method_span, path.ident.name, recv, args, self.msrv);
+            unnecessary_to_owned::check(cx, expr, path.ident.name, recv, args, self.msrv);
+
             match (path.ident.name, args) {
-                (sym::expect, [_]) => {
+                (sym::clone, []) => {
+                    clone_on_ref_ptr::check(cx, expr, recv);
+                    clone_on_copy::check(cx, expr, recv);
+                },
+                (sym::expect, [arg]) => {
                     unwrap_expect_used::check(
                         cx,
                         expr,
@@ -5578,6 +5611,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         self.allow_expect_in_tests,
                         unwrap_expect_used::Variant::Expect,
                     );
+                    expect_fun_call::check(cx, &self.format_args, expr, method_span, recv, arg);
                 },
                 (sym::expect_err, [_]) => {
                     unwrap_expect_used::check(
@@ -5590,6 +5624,15 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         unwrap_expect_used::Variant::Expect,
                     );
                 },
+                (sym::insert_str | sym::push_str, _) => {
+                    single_char_add_str::check(cx, expr, recv, args);
+                },
+                (sym::into_iter, []) => {
+                    into_iter_on_ref::check(cx, expr, method_span, recv);
+                },
+                (sym::to_string, []) => {
+                    inefficient_to_string::check(cx, expr, recv, self.msrv);
+                },
                 (sym::unwrap, []) => {
                     unwrap_expect_used::check(
                         cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
index 9d2c5e6..c9264e7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::expr_custom_deref_adjustment;
-use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::ty::peel_and_count_ty_refs;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability};
 use rustc_lint::LateContext;
@@ -13,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'
         && let (_, _, Some(Mutability::Mut)) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(recv))
         && let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
-        && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Mutex)
+        && cx.tcx.type_of(impl_id).is_diag_item(cx, sym::Mutex)
     {
         span_lint_and_sugg(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs b/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs
index 635d063..22baad4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_lang_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, LangItem};
 use rustc_lint::LateContext;
@@ -10,7 +10,7 @@
 
 pub fn check(cx: &LateContext<'_>, prev_method: Symbol, method: Symbol, prev_recv: &Expr<'_>, span: Span) {
     let ty1 = cx.typeck_results().expr_ty_adjusted(prev_recv).peel_refs();
-    if is_type_lang_item(cx, ty1, LangItem::String) || ty1.is_str() {
+    if ty1.is_lang_item(cx, LangItem::String) || ty1.is_str() {
         let mut app = Applicability::MachineApplicable;
         let sugg = Sugg::hir_with_context(cx, prev_recv, span.ctxt(), "..", &mut app);
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
index 71c1576..948ed8a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
@@ -1,3 +1,4 @@
+use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
 use rustc_errors::Applicability;
 use rustc_hir::{Closure, Expr, ExprKind, HirId, StmtKind, UnOp};
 use rustc_lint::LateContext;
@@ -8,7 +9,7 @@
 use super::utils::get_last_chain_binding_hir_id;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{is_path_diagnostic_item, path_to_local_id, peel_blocks, sym};
+use clippy_utils::{peel_blocks, sym};
 
 fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> {
     while let ExprKind::AddrOf(_, _, e) = expr.kind {
@@ -32,7 +33,7 @@ fn handle_expr(
             // `is_ascii`, then only `.all()` should warn.
             if revert != is_all
                 && method.ident.name == sym::is_ascii
-                && path_to_local_id(receiver, first_param)
+                && receiver.res_local_id() == Some(first_param)
                 && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs()
                 && *char_arg_ty.kind() == ty::Char
                 && let Some(snippet) = before_chars.get_source_text(cx)
@@ -75,8 +76,8 @@ fn handle_expr(
             // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is
             // `is_ascii`, then only `.all()` should warn.
             if revert != is_all
-                && is_path_diagnostic_item(cx, fn_path, sym::char_is_ascii)
-                && path_to_local_id(peels_expr_ref(arg), first_param)
+                && fn_path.ty_rel_def(cx).is_diag_item(cx, sym::char_is_ascii)
+                && peels_expr_ref(arg).res_local_id() == Some(first_param)
                 && let Some(snippet) = before_chars.get_source_text(cx)
             {
                 span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 0075bf1..4f00510 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -2,15 +2,11 @@
 
 use super::NEEDLESS_COLLECT;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
+use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{
-    get_type_diagnostic_name, has_non_owning_mutable_access, make_normalized_projection, make_projection,
-};
-use clippy_utils::{
-    CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local,
-    path_to_local_id, sym,
-};
+use clippy_utils::ty::{has_non_owning_mutable_access, make_normalized_projection, make_projection};
+use clippy_utils::{CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, sym};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt};
@@ -98,7 +94,7 @@ pub(super) fn check<'tcx>(
             if let PatKind::Binding(BindingMode::NONE | BindingMode::MUT, id, _, None) = l.pat.kind
                 && let ty = cx.typeck_results().expr_ty(collect_expr)
                 && matches!(
-                    get_type_diagnostic_name(cx, ty),
+                    ty.opt_diag_name(cx),
                     Some(sym::Vec | sym::VecDeque | sym::BinaryHeap | sym::LinkedList)
                 )
                 && let iter_ty = cx.typeck_results().expr_ty(iter_expr)
@@ -339,14 +335,18 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind {
             if args.is_empty()
                 && method_name.ident.name == sym::collect
-                && is_trait_method(self.cx, expr, sym::Iterator)
+                && self
+                    .cx
+                    .ty_based_def(expr)
+                    .opt_parent(self.cx)
+                    .is_diag_item(self.cx, sym::Iterator)
             {
                 self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
                 self.visit_expr(recv);
                 return;
             }
 
-            if path_to_local_id(recv, self.target) {
+            if recv.res_local_id() == Some(self.target) {
                 if self
                     .illegal_mutable_capture_ids
                     .intersection(&self.current_mutably_captured_ids)
@@ -384,7 +384,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
                 return;
             }
 
-            if let Some(hir_id) = path_to_local(recv)
+            if let Some(hir_id) = recv.res_local_id()
                 && let Some(index) = self.hir_id_uses_map.remove(&hir_id)
             {
                 if self
@@ -402,7 +402,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
             }
         }
         // Check if the collection is used for anything else
-        if path_to_local_id(expr, self.target) {
+        if expr.res_local_id() == Some(self.target) {
             self.seen_other = true;
         } else {
             walk_expr(self, expr);
@@ -464,7 +464,7 @@ impl<'tcx> Visitor<'tcx> for UsedCountVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if path_to_local_id(expr, self.id) {
+        if expr.res_local_id() == Some(self.id) {
             self.count += 1;
         } else {
             walk_expr(self, expr);
@@ -549,13 +549,17 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow<()> {
             && (recv.hir_id == self.hir_id_of_expr
                 || self
                     .hir_id_of_let_binding
-                    .is_some_and(|hid| path_to_local_id(recv, hid)))
-            && !is_trait_method(self.cx, expr, sym::Iterator)
+                    .is_some_and(|hid| recv.res_local_id() == Some(hid)))
+            && !self
+                .cx
+                .ty_based_def(expr)
+                .opt_parent(self.cx)
+                .is_diag_item(self.cx, sym::Iterator)
         {
             return ControlFlow::Break(());
         } else if let ExprKind::Assign(place, value, _span) = &expr.kind
             && value.hir_id == self.hir_id_of_expr
-            && let Some(id) = path_to_local(place)
+            && let Some(id) = place.res_local_id()
         {
             // our iterator was directly assigned to a variable
             self.hir_id_of_let_binding = Some(id);
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
index d77d044..06e6a3c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::sym;
 use clippy_utils::usage::local_used_after_expr;
-use clippy_utils::{path_res, sym};
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_hir::def::Res;
@@ -15,9 +15,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name
     let typeck = cx.typeck_results();
     let outer_ty = typeck.expr_ty(expr);
 
-    if is_type_diagnostic_item(cx, outer_ty, sym::Option) && outer_ty == typeck.expr_ty(recv) {
+    if outer_ty.is_diag_item(cx, sym::Option) && outer_ty == typeck.expr_ty(recv) {
         if name == sym::as_deref_mut && recv.is_syntactic_place_expr() {
-            let Res::Local(binding_id) = path_res(cx, recv) else {
+            let Res::Local(binding_id) = *recv.basic_res() else {
                 return;
             };
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs b/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
index 1544a12..1622fdb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
 
 fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let expr_type = cx.typeck_results().expr_ty(expr);
-    is_type_diagnostic_item(cx, expr_type, sym::Option)
+    expr_type.is_diag_item(cx, sym::Option)
 }
 
 /// Returns the string of the function call that creates the temporary.
diff --git a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
index 32f32f1..9fa51f7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
@@ -1,6 +1,6 @@
 use clippy_utils::SpanlessEq;
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::res::MaybeDef;
 use rustc_ast::LitKind;
 use rustc_hir::{ExprKind, LangItem};
 use rustc_lint::LateContext;
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(
     arg2: &'tcx rustc_hir::Expr<'_>,
 ) {
     let ty = cx.typeck_results().expr_ty(expr).peel_refs();
-    if !(ty.is_str() || is_type_lang_item(cx, ty, LangItem::String)) {
+    if !(ty.is_str() || ty.is_lang_item(cx, LangItem::String)) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
index 604b486..b2466bb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
@@ -5,25 +5,24 @@
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{get_parent_expr, sym};
 use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_hir::ExprKind;
+use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_span::Symbol;
 
+#[expect(clippy::needless_pass_by_value)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
-    expr: &'tcx hir::Expr<'_>,
-    then_recv: &'tcx hir::Expr<'_>,
-    then_arg: &'tcx hir::Expr<'_>,
-    unwrap_arg: Option<&'tcx hir::Expr<'_>>,
+    expr: &'tcx Expr<'_>,
+    then_recv: &'tcx Expr<'_>,
+    then_arg: &'tcx Expr<'_>,
     then_method_name: Symbol,
-    unwrap_method_name: Symbol,
+    unwrap: Unwrap<'tcx>,
 ) {
     let recv_ty = cx.typeck_results().expr_ty(then_recv);
 
     if recv_ty.is_bool() {
         let then_eager = switch_to_eager_eval(cx, then_arg);
-        let unwrap_eager = unwrap_arg.is_none_or(|arg| switch_to_eager_eval(cx, arg));
+        let unwrap_eager = unwrap.arg().is_none_or(|arg| switch_to_eager_eval(cx, arg));
 
         let mut applicability = if then_eager && unwrap_eager {
             Applicability::MachineApplicable
@@ -40,18 +39,17 @@ pub(super) fn check<'tcx>(
             _ => return,
         };
 
-        // FIXME: Add `unwrap_or_else` and `unwrap_or_default` symbol
-        let els = match unwrap_method_name {
-            sym::unwrap_or => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability),
-            sym::unwrap_or_else if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => {
-                let body = cx.tcx.hir_body(closure.body);
-                snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
+        let els = match unwrap {
+            Unwrap::Or(arg) => snippet_with_applicability(cx, arg.span, "..", &mut applicability),
+            Unwrap::OrElse(arg) => match arg.kind {
+                ExprKind::Closure(closure) => {
+                    let body = cx.tcx.hir_body(closure.body);
+                    snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
+                },
+                ExprKind::Path(_) => snippet_with_applicability(cx, arg.span, "_", &mut applicability) + "()",
+                _ => return,
             },
-            sym::unwrap_or_else if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => {
-                snippet_with_applicability(cx, unwrap_arg.unwrap().span, "_", &mut applicability) + "()"
-            },
-            sym::unwrap_or_default => "Default::default()".into(),
-            _ => return,
+            Unwrap::OrDefault => "Default::default()".into(),
         };
 
         let sugg = format!(
@@ -83,3 +81,18 @@ pub(super) fn check<'tcx>(
         );
     }
 }
+
+pub(super) enum Unwrap<'tcx> {
+    Or(&'tcx Expr<'tcx>),
+    OrElse(&'tcx Expr<'tcx>),
+    OrDefault,
+}
+
+impl<'tcx> Unwrap<'tcx> {
+    fn arg(&self) -> Option<&'tcx Expr<'tcx>> {
+        match self {
+            Self::Or(a) | Self::OrElse(a) => Some(a),
+            Self::OrDefault => None,
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs b/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
index e10bc02..c9c1f48 100644
--- a/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/ok_expect.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::ty::has_debug_impl;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
@@ -9,7 +10,7 @@
 
 /// lint use of `ok().expect()` for `Result`s
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
+    if cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result)
         // lint if the caller of `ok()` is a `Result`
         && let result_type = cx.typeck_results().expr_ty(recv)
         && let Some(error_type) = get_error_type(cx, result_type)
@@ -29,7 +30,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
 /// Given a `Result<T, E>` type, return its error type (`E`).
 fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
     match ty.kind() {
-        ty::Adt(_, args) if is_type_diagnostic_item(cx, ty, sym::Result) => args.types().nth(1),
+        ty::Adt(_, args) if ty.is_diag_item(cx, sym::Result) => args.types().nth(1),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index 37a8e25..1b520a9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -1,7 +1,7 @@
+use clippy_utils::res::MaybeDef;
 use rustc_data_structures::fx::FxHashMap;
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{paths, sym};
 use rustc_ast::ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
@@ -13,7 +13,7 @@
 use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS};
 
 fn is_open_options(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    is_type_diagnostic_item(cx, ty, sym::FsOpenOptions) || paths::TOKIO_IO_OPEN_OPTIONS.matches_ty(cx, ty)
+    ty.is_diag_item(cx, sym::FsOpenOptions) || paths::TOKIO_IO_OPEN_OPTIONS.matches_ty(cx, ty)
 }
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
index 3c38dec..591f6aa 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::sym;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -11,7 +11,11 @@
 pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) {
     if let Some((method @ (sym::as_ref | sym::as_mut), as_ref_recv, [], as_ref_ident_span, _)) =
         method_call(cloned_recv)
-        && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(as_ref_recv).peel_refs(), sym::Option)
+        && cx
+            .typeck_results()
+            .expr_ty(as_ref_recv)
+            .peel_refs()
+            .is_diag_item(cx, sym::Option)
     {
         span_lint_and_sugg(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 906ead1..3d48907 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::peel_blocks;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{path_to_local_id, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -23,7 +23,7 @@ pub(super) fn check(
     let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
 
     let option_ty = cx.typeck_results().expr_ty(as_ref_recv);
-    if !is_type_diagnostic_item(cx, option_ty, sym::Option) {
+    if !option_ty.is_diag_item(cx, sym::Option) {
         return;
     }
 
@@ -51,7 +51,7 @@ pub(super) fn check(
 
             match &closure_expr.kind {
                 hir::ExprKind::MethodCall(_, receiver, [], _) => {
-                    if path_to_local_id(receiver, closure_body.params[0].pat.hir_id)
+                    if receiver.res_local_id() == Some(closure_body.params[0].pat.hir_id)
                         && let adj = cx
                             .typeck_results()
                             .expr_adjustments(receiver)
@@ -72,7 +72,7 @@ pub(super) fn check(
                     if let hir::ExprKind::Unary(hir::UnOp::Deref, inner1) = inner.kind
                         && let hir::ExprKind::Unary(hir::UnOp::Deref, inner2) = inner1.kind
                     {
-                        path_to_local_id(inner2, closure_body.params[0].pat.hir_id)
+                        inner2.res_local_id() == Some(closure_body.params[0].pat.hir_id)
                     } else {
                         false
                     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
index 1a273f7..342ffea 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_res_lang_ctor, path_def_id, path_res};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -37,8 +36,8 @@ pub(super) fn check<'tcx>(
     def_arg: &'tcx hir::Expr<'_>,
     map_arg: &'tcx hir::Expr<'_>,
 ) {
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
+    let is_option = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option);
+    let is_result = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result);
 
     // There are two variants of this `map_or` lint:
     // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
@@ -49,12 +48,12 @@ pub(super) fn check<'tcx>(
         return;
     }
 
-    if !is_res_lang_ctor(cx, path_res(cx, def_arg), OptionNone) {
+    if !def_arg.res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone) {
         // nothing to lint!
         return;
     }
 
-    let f_arg_is_some = is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome);
+    let f_arg_is_some = map_arg.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome);
 
     if is_option {
         let self_snippet = snippet(cx, recv.span, "..");
@@ -62,7 +61,7 @@ pub(super) fn check<'tcx>(
             && let arg_snippet = snippet(cx, fn_decl_span, "..")
             && let body = cx.tcx.hir_body(body)
             && let Some((func, [arg_char])) = reduce_unit_expression(body.value)
-            && let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id))
+            && let Some(id) = func.res(cx).opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id))
             && Some(id) == cx.tcx.lang_items().option_some_variant()
         {
             let func_snippet = snippet(cx, arg_char.span, "..");
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index 4ba8e01..32a9b4f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
+use clippy_utils::ty::is_copy;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -27,7 +28,7 @@ pub(super) fn check<'tcx>(
     msrv: Msrv,
 ) {
     // lint if the caller of `map()` is an `Option`
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) {
+    if cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option) {
         if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) {
             // Replacing `.map(<f>).unwrap_or(<a>)` with `.map_or(<a>, <f>)` can sometimes lead to
             // borrowck errors, see #10579 for one such instance.
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 04e4503..aed4a00 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -4,8 +4,9 @@
 use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
 use clippy_utils::higher::VecArgs;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item};
+use clippy_utils::ty::{expr_type_is_certain, implements_trait};
 use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{
     contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment, peel_blocks, sym,
@@ -113,7 +114,7 @@ fn check_unwrap_or_default(
     let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs();
 
     // Check MSRV, but only for `Result::unwrap_or_default`
-    if is_type_diagnostic_item(cx, receiver_ty, sym::Result) && !msrv.meets(cx, msrvs::RESULT_UNWRAP_OR_DEFAULT) {
+    if receiver_ty.is_diag_item(cx, sym::Result) && !msrv.meets(cx, msrvs::RESULT_UNWRAP_OR_DEFAULT) {
         return false;
     }
 
@@ -239,7 +240,7 @@ fn check_or_fn_call<'tcx>(
         && let self_ty = cx.typeck_results().expr_ty(self_expr)
         && let Some(&(_, fn_has_arguments, _, suffix)) = KNOW_TYPES
             .iter()
-            .find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0) && i.2.contains(&name))
+            .find(|&&i| self_ty.is_diag_item(cx, i.0) && i.2.contains(&name))
     {
         let ctxt = span.ctxt();
         let mut app = Applicability::HasPlaceholders;
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
index 1a760ea..07199b8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_then_unwrap.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_res_lang_ctor, path_res};
 use rustc_errors::Applicability;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Expr, ExprKind};
@@ -21,14 +20,14 @@ pub(super) fn check<'tcx>(
     let title;
     let or_arg_content: Span;
 
-    if is_type_diagnostic_item(cx, ty, sym::Option) {
+    if ty.is_diag_item(cx, sym::Option) {
         title = "found `.or(Some(…)).unwrap()`";
         if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::OptionSome) {
             or_arg_content = content;
         } else {
             return;
         }
-    } else if is_type_diagnostic_item(cx, ty, sym::Result) {
+    } else if ty.is_diag_item(cx, sym::Result) {
         title = "found `.or(Ok(…)).unwrap()`";
         if let Some(content) = get_content_if_ctor_matches(cx, or_arg, LangItem::ResultOk) {
             or_arg_content = content;
@@ -60,7 +59,7 @@ pub(super) fn check<'tcx>(
 
 fn get_content_if_ctor_matches(cx: &LateContext<'_>, expr: &Expr<'_>, item: LangItem) -> Option<Span> {
     if let ExprKind::Call(some_expr, [arg]) = expr.kind
-        && is_res_lang_ctor(cx, path_res(cx, some_expr), item)
+        && some_expr.res(cx).ctor_parent(cx).is_lang_item(cx, item)
     {
         Some(arg.span.source_callsite())
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
index 32752ef..18046ff 100644
--- a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -12,7 +12,11 @@
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
     if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
-        && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::PathBuf)
+        && cx
+            .tcx
+            .type_of(impl_id)
+            .instantiate_identity()
+            .is_diag_item(cx, sym::PathBuf)
         && let ExprKind::Lit(lit) = arg.kind
         && let LitKind::Str(ref path_lit, _) = lit.node
         && let pushed_path = Path::new(path_lit.as_str())
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs
index d3f513e..87d1aa6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs
@@ -1,8 +1,8 @@
 use super::PATH_ENDS_WITH_EXT;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_ast::{LitKind, StrStyle};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -23,7 +23,11 @@ pub(super) fn check(
     msrv: Msrv,
     allowed_dotfiles: &FxHashSet<&'static str>,
 ) {
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::Path)
+    if cx
+        .typeck_results()
+        .expr_ty(recv)
+        .peel_refs()
+        .is_diag_item(cx, sym::Path)
         && !path.span.from_expansion()
         && let ExprKind::Lit(lit) = path.kind
         && let LitKind::Str(path, StrStyle::Cooked) = lit.node
diff --git a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
index e13df18..de4207c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::{SpanRangeExt as _, snippet_with_applicability};
-use clippy_utils::{SpanlessEq, get_parent_expr, higher, is_integer_const, is_trait_method, sym};
+use clippy_utils::{SpanlessEq, get_parent_expr, higher, is_integer_const, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Node, Pat, PatKind, QPath};
 use rustc_lint::LateContext;
@@ -8,7 +9,7 @@
 use super::RANGE_ZIP_WITH_LEN;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, zip_arg: &'tcx Expr<'_>) {
-    if is_trait_method(cx, expr, sym::Iterator)
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         // range expression in `.zip()` call: `0..x.len()`
         && let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg)
         && is_integer_const(cx, start, 0)
@@ -82,7 +83,7 @@ fn for_loop_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Optio
 /// them to a closure, return the pattern of the closure.
 fn methods_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Pat<'tcx>> {
     if let Some(parent_expr) = get_parent_expr(cx, expr)
-        && is_trait_method(cx, expr, sym::Iterator)
+        && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && let ExprKind::MethodCall(method, recv, [arg], _) = parent_expr.kind
         && recv.hir_id == expr.hir_id
         && matches!(
diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
index 6738bbf..a6dfbad 100644
--- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
@@ -1,8 +1,8 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_local_use_after_expr;
 use clippy_utils::{get_parent_expr, sym};
 use rustc_ast::LitKind;
@@ -32,7 +32,7 @@ fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool {
 
 pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
     let recv_ty = cx.typeck_results().expr_ty(recv);
-    if is_type_diagnostic_item(cx, recv_ty, sym::Stdin)
+    if recv_ty.is_diag_item(cx, sym::Stdin)
         && let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind
         && let Res::Local(local_id) = path.res
     {
@@ -45,7 +45,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
                     if args.is_empty()
                         && segment.ident.name == sym::parse
                         && let parse_result_ty = cx.typeck_results().expr_ty(parent)
-                        && is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
+                        && parse_result_ty.is_diag_item(cx, sym::Result)
                         && let ty::Adt(_, substs) = parse_result_ty.kind()
                         && let Some(ok_ty) = substs[0].as_type()
                         && parse_fails_on_trailing_newline(ok_ty)
diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
index 40b6bec..a98a807 100644
--- a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
@@ -1,8 +1,8 @@
 use super::READONLY_WRITE_LOCK;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::mir::{enclosing_mir, visit_local_usage};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Node, PatKind};
 use rustc_lint::LateContext;
@@ -13,14 +13,17 @@ fn is_unwrap_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     if let ExprKind::MethodCall(path, receiver, [], _) = expr.kind
         && path.ident.name == sym::unwrap
     {
-        is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::Result)
+        cx.typeck_results()
+            .expr_ty(receiver)
+            .peel_refs()
+            .is_diag_item(cx, sym::Result)
     } else {
         false
     }
 }
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver: &Expr<'_>) {
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::RwLock)
+    if cx.typeck_results().expr_ty(receiver).peel_refs().is_diag_item(cx, sym::RwLock)
         && let Node::Expr(unwrap_call_expr) = cx.tcx.parent_hir_node(expr.hir_id)
         && is_unwrap_call(cx, unwrap_call_expr)
         && let parent = cx.tcx.parent_hir_node(unwrap_call_expr.hir_id)
diff --git a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
index 9111604..57a7254 100644
--- a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs
@@ -1,7 +1,7 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_lang_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, LangItem};
 use rustc_lint::LateContext;
@@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(
                 format!("{}.to_vec()", snippet(cx, recv.span, r#""...""#)),
                 Applicability::MachineApplicable,
             );
-        } else if is_type_lang_item(cx, ty, LangItem::String) {
+        } else if ty.is_lang_item(cx, LangItem::String) {
             span_lint_and_sugg(
                 cx,
                 REPEAT_ONCE,
diff --git a/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs
index af619c9..e2946c2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/result_map_or_else_none.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::peel_blocks;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -19,13 +19,13 @@ pub(super) fn check<'tcx>(
     map_arg: &'tcx hir::Expr<'_>,
 ) {
     // lint if the caller of `map_or_else()` is a `Result`
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
+    if cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result)
         // We check that it is mapped as `Some`.
-        && is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome)
+        && map_arg.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome)
         && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = def_arg.kind
         && let body = cx.tcx.hir_body(body)
         // And finally we check that we return a `None` in the "else case".
-        && is_res_lang_ctor(cx, path_res(cx, peel_blocks(body.value)), OptionNone)
+        && peel_blocks(body.value).res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone)
     {
         let msg = "called `map_or_else(|_| None, Some)` on a `Result` value";
         let self_snippet = snippet(cx, recv.span, "..");
diff --git a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
index 54f38a3..8f47306 100644
--- a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
@@ -1,3 +1,4 @@
+use clippy_utils::res::MaybeDef;
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Node};
 use rustc_lint::LateContext;
@@ -7,7 +8,6 @@
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability};
-use clippy_utils::ty::get_type_diagnostic_name;
 use clippy_utils::visitors::for_each_unconsumed_temporary;
 use clippy_utils::{peel_blocks, potential_return_of_enclosing_body};
 
@@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(
     }
 
     let recv_type = cx.typeck_results().expr_ty(recv);
-    if !matches!(get_type_diagnostic_name(cx, recv_type), Some(sym::Option | sym::Result)) {
+    if !matches!(recv_type.opt_diag_name(cx), Some(sym::Option | sym::Result)) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index 855babb..c9c75f3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::deref_closure_args;
-use clippy_utils::ty::is_type_lang_item;
-use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs, sym};
+use clippy_utils::{is_receiver_of_method_call, strip_pat_refs, sym};
 use hir::ExprKind;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -14,7 +14,7 @@
 
 /// lint searching an Iterator followed by `is_some()`
 /// or calling `find()` on a string followed by `is_some()` or `is_none()`
-#[allow(clippy::too_many_arguments, clippy::too_many_lines)]
+#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'_>,
     expr: &'tcx hir::Expr<'_>,
@@ -27,7 +27,11 @@ pub(super) fn check<'tcx>(
 ) {
     let option_check_method = if is_some { "is_some" } else { "is_none" };
     // lint if caller of search is an Iterator
-    if is_trait_method(cx, is_some_recv, sym::Iterator) {
+    if cx
+        .ty_based_def(is_some_recv)
+        .opt_parent(cx)
+        .is_diag_item(cx, sym::Iterator)
+    {
         let msg = format!("called `{option_check_method}()` after searching an `Iterator` with `{search_method}`");
         let search_snippet = snippet(cx, search_arg.span, "..");
         if search_snippet.lines().count() <= 1 {
@@ -109,7 +113,7 @@ pub(super) fn check<'tcx>(
     else if search_method == sym::find {
         let is_string_or_str_slice = |e| {
             let self_ty = cx.typeck_results().expr_ty(e).peel_refs();
-            if is_type_lang_item(cx, self_ty, hir::LangItem::String) {
+            if self_ty.is_lang_item(cx, hir::LangItem::String) {
                 true
             } else {
                 self_ty.is_str()
diff --git a/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs b/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs
index 9f0b6c3..2452c49 100644
--- a/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/skip_while_next.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::sym;
@@ -9,7 +9,7 @@
 /// lint use of `skip_while().next()` for `Iterators`
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
     // lint if caller of `.skip_while().next()` is an Iterator
-    if is_trait_method(cx, expr, sym::Iterator) {
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) {
         span_lint_and_help(
             cx,
             SKIP_WHILE_NEXT,
diff --git a/src/tools/clippy/clippy_lints/src/methods/sliced_string_as_bytes.rs b/src/tools/clippy/clippy_lints/src/methods/sliced_string_as_bytes.rs
index 6d4cfdb..4aff194 100644
--- a/src/tools/clippy/clippy_lints/src/methods/sliced_string_as_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/sliced_string_as_bytes.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_lang_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, is_range_literal};
 use rustc_lint::LateContext;
@@ -11,7 +11,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>) {
     if let ExprKind::Index(indexed, index, _) = recv.kind
         && is_range_literal(index)
         && let ty = cx.typeck_results().expr_ty(indexed).peel_refs()
-        && (ty.is_str() || is_type_lang_item(cx, ty, LangItem::String))
+        && (ty.is_str() || ty.is_lang_item(cx, LangItem::String))
     {
         let mut applicability = Applicability::MaybeIncorrect;
         let stringish = snippet_with_applicability(cx, indexed.span, "_", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 8daa5db..eee7fb0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -1,10 +1,11 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::usage::local_used_after_expr;
 use clippy_utils::visitors::{Descend, for_each_expr};
-use clippy_utils::{is_diag_item_method, path_to_local_id, paths, sym};
+use clippy_utils::{paths, sym};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::{
@@ -214,7 +215,7 @@ fn indirect_usage<'tcx>(
     {
         let mut path_to_binding = None;
         let _: Option<!> = for_each_expr(cx, init_expr, |e| {
-            if path_to_local_id(e, binding) {
+            if e.res_local_id() == Some(binding) {
                 path_to_binding = Some(e);
             }
             ControlFlow::Continue(Descend::from(path_to_binding.is_none()))
@@ -271,7 +272,6 @@ struct IterUsage {
     span: Span,
 }
 
-#[allow(clippy::too_many_lines)]
 fn parse_iter_usage<'tcx>(
     cx: &LateContext<'tcx>,
     ctxt: SyntaxContext,
@@ -351,7 +351,9 @@ fn parse_iter_usage<'tcx>(
                     && cx
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
-                        .is_some_and(|id| is_diag_item_method(cx, id, sym::Option)) =>
+                        .opt_parent(cx)
+                        .opt_impl_ty(cx)
+                        .is_diag_item(cx, sym::Option) =>
             {
                 (Some(UnwrapKind::Unwrap), e.span)
             },
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
index f11a41f..1fc0633 100644
--- a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{method_chain_args, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -10,7 +10,7 @@
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
     let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
-    if !is_type_lang_item(cx, obj_ty, hir::LangItem::String) {
+    if !obj_ty.is_lang_item(cx, hir::LangItem::String) {
         return;
     }
     if let Some(arglists) = method_chain_args(arg, &[sym::chars]) {
@@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
             } else {
                 ""
             }
-        } else if is_type_lang_item(cx, self_ty, hir::LangItem::String) {
+        } else if self_ty.is_lang_item(cx, hir::LangItem::String) {
             "&"
         } else {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
index f0f9d30..48e89c2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local};
 use itertools::Itertools;
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
@@ -19,14 +20,14 @@ pub(super) fn check<'tcx>(
     body: &Expr<'_>,
     msrv: Msrv,
 ) {
-    if is_trait_method(cx, expr, sym::Iterator)
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         && let PatKind::Binding(_, arg, _, _) = param.pat.kind
         && let ExprKind::Lit(lit_kind) = recv.kind
         && let LitKind::Str(val, _) = lit_kind.node
         && let ExprKind::Binary(kind, lhs, rhs) = body.kind
         && let BinOpKind::Eq = kind.node
-        && let Some(lhs_path) = path_to_local(lhs)
-        && let Some(rhs_path) = path_to_local(rhs)
+        && let Some(lhs_path) = lhs.res_local_id()
+        && let Some(rhs_path) = rhs.res_local_id()
         && let scrutinee = match (lhs_path == arg, rhs_path == arg) {
             (true, false) => rhs,
             (false, true) => lhs,
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
index c60a490..3e9c677 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use rustc_errors::{Applicability, Diag};
 use rustc_lint::LateContext;
 use rustc_span::{Span, sym};
@@ -10,7 +10,7 @@
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) {
     let ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
-    if is_type_diagnostic_item(cx, ty, sym::Command)
+    if ty.is_diag_item(cx, sym::Command)
         && let hir::ExprKind::Lit(lit) = &arg.kind
         && let ast::LitKind::Str(s, _) = &lit.node
         && let Some((arg1, arg2)) = s.as_str().split_once(' ')
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
index 788014d..ece97c1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::expr_or_init;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::usage::mutated_variables;
-use clippy_utils::{expr_or_init, is_trait_method};
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::sym;
@@ -8,7 +9,10 @@
 use super::SUSPICIOUS_MAP;
 
 pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) {
-    if is_trait_method(cx, count_recv, sym::Iterator)
+    if cx
+        .ty_based_def(count_recv)
+        .opt_parent(cx)
+        .is_diag_item(cx, sym::Iterator)
         && let hir::ExprKind::Closure(closure) = expr_or_init(cx, map_arg).kind
         && let closure_body = cx.tcx.hir_body(closure.body)
         && !cx.typeck_results().expr_ty(closure_body.value).is_unit()
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
index 9876681..be1481e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -10,8 +10,7 @@
 pub(super) fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) {
     if count <= 1
         && let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
-        && let Some(impl_id) = cx.tcx.impl_of_assoc(call_id)
-        && cx.tcx.impl_trait_ref(impl_id).is_none()
+        && let Some(impl_id) = cx.tcx.inherent_impl_of_assoc(call_id)
         && let self_ty = cx.tcx.type_of(impl_id).instantiate_identity()
         && (self_ty.is_slice() || self_ty.is_str())
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
index ffc237e..bcd1f11 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_diag_trait_item;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -11,10 +10,13 @@
 use super::SUSPICIOUS_TO_OWNED;
 
 pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -> bool {
-    if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
-        && is_diag_trait_item(cx, method_def_id, sym::ToOwned)
+    if cx
+        .typeck_results()
+        .type_dependent_def_id(expr.hir_id)
+        .opt_parent(cx)
+        .is_diag_item(cx, sym::ToOwned)
         && let input_type = cx.typeck_results().expr_ty(expr)
-        && is_type_diagnostic_item(cx, input_type, sym::Cow)
+        && input_type.is_diag_item(cx, sym::Cow)
     {
         let mut app = Applicability::MaybeIncorrect;
         let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
diff --git a/src/tools/clippy/clippy_lints/src/methods/unbuffered_bytes.rs b/src/tools/clippy/clippy_lints/src/methods/unbuffered_bytes.rs
index dd5566f..fdddd5e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unbuffered_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unbuffered_bytes.rs
@@ -1,6 +1,6 @@
 use super::UNBUFFERED_BYTES;
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::ty::implements_trait;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -8,7 +8,7 @@
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     // Lint if the `.bytes()` call is from the `Read` trait and the implementor is not buffered.
-    if is_trait_method(cx, expr, sym::IoRead)
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::IoRead)
         && let Some(buf_read) = cx.tcx.get_diagnostic_item(sym::IoBufRead)
         && let ty = cx.typeck_results().expr_ty_adjusted(recv)
         && !implements_trait(cx, ty, buf_read, &[])
diff --git a/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs b/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
index 6371fe6..5e247a5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/uninit_assumed_init.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_path_diagnostic_item;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::ty::is_uninit_value_valid_for_ty;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -10,7 +10,7 @@
 /// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter)
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if let hir::ExprKind::Call(callee, []) = recv.kind
-        && is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit)
+        && callee.ty_rel_def(cx).is_diag_item(cx, sym::maybe_uninit_uninit)
         && !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr))
     {
         span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/methods/unit_hash.rs b/src/tools/clippy/clippy_lints/src/methods/unit_hash.rs
index 3c7955b..9defd56 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unit_hash.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unit_hash.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
@@ -9,7 +9,7 @@
 use super::UNIT_HASH;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
-    if is_trait_method(cx, expr, sym::Hash) && cx.typeck_results().expr_ty(recv).is_unit() {
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Hash) && cx.typeck_results().expr_ty(recv).is_unit() {
         span_lint_and_then(
             cx,
             UNIT_HASH,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index d260e0e..d9d6420 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -1,9 +1,10 @@
 use super::utils::clone_or_copy_needed;
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath, MaybeTypeckRes};
+use clippy_utils::sym;
 use clippy_utils::ty::is_copy;
 use clippy_utils::usage::mutated_variables;
 use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
-use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id, sym};
 use core::ops::ControlFlow;
 use rustc_hir as hir;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -19,7 +20,7 @@ pub(super) fn check<'tcx>(
     arg: &'tcx hir::Expr<'tcx>,
     name: Symbol,
 ) {
-    if !is_trait_method(cx, expr, sym::Iterator) {
+    if !cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) {
         return;
     }
 
@@ -46,7 +47,7 @@ pub(super) fn check<'tcx>(
             // Check if the closure is .filter_map(|x| Some(x))
             if name == sym::filter_map
                 && let hir::ExprKind::Call(expr, args) = body.value.kind
-                && is_res_lang_ctor(cx, path_res(cx, expr), OptionSome)
+                && expr.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome)
                 && let hir::ExprKind::Path(_) = args[0].kind
             {
                 span_lint(
@@ -95,8 +96,8 @@ pub(super) fn check<'tcx>(
 fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tcx hir::Expr<'_>) -> (bool, bool) {
     match expr.kind {
         hir::ExprKind::Call(func, args) => {
-            if is_res_lang_ctor(cx, path_res(cx, func), OptionSome) {
-                if path_to_local_id(&args[0], arg_id) {
+            if func.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome) {
+                if args[0].res_local_id() == Some(arg_id) {
                     return (false, false);
                 }
                 return (true, false);
@@ -106,7 +107,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
         hir::ExprKind::MethodCall(segment, recv, [arg], _) => {
             if segment.ident.name == sym::then_some
                 && cx.typeck_results().expr_ty(recv).is_bool()
-                && path_to_local_id(arg, arg_id)
+                && arg.res_local_id() == Some(arg_id)
             {
                 (false, true)
             } else {
@@ -133,7 +134,12 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
             let else_check = check_expression(cx, arg_id, else_arm);
             (if_check.0 | else_check.0, if_check.1 | else_check.1)
         },
-        hir::ExprKind::Path(ref path) if is_res_lang_ctor(cx, cx.qpath_res(path, expr.hir_id), OptionNone) => {
+        hir::ExprKind::Path(ref path)
+            if cx
+                .qpath_res(path, expr.hir_id)
+                .ctor_parent(cx)
+                .is_lang_item(cx, OptionNone) =>
+        {
             (false, true)
         },
         _ => (true, true),
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 8e3cc9a..bd471e0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, strip_pat_refs};
+use clippy_utils::{peel_blocks, strip_pat_refs};
 use rustc_ast::ast;
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::Applicability;
@@ -74,8 +75,8 @@ fn check_fold_with_op(
         && let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind
         && let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind
 
-        && path_to_local_id(left_expr, first_arg_id)
-        && (replacement.has_args || path_to_local_id(right_expr, second_arg_id))
+        && left_expr.res_local_id() == Some(first_arg_id)
+        && (replacement.has_args || right_expr.res_local_id() == Some(second_arg_id))
     {
         let mut applicability = Applicability::MachineApplicable;
 
@@ -115,7 +116,7 @@ pub(super) fn check(
     fold_span: Span,
 ) {
     // Check that this is a call to Iterator::fold rather than just some function called fold
-    if !is_trait_method(cx, expr, sym::Iterator) {
+    if !cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs
index 39fce2c..10ea0c0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::ty::is_type_diagnostic_item;
 
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -11,11 +11,11 @@
 use super::UNNECESSARY_GET_THEN_CHECK;
 
 fn is_a_std_set_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    is_type_diagnostic_item(cx, ty, sym::HashSet) || is_type_diagnostic_item(cx, ty, sym::BTreeSet)
+    ty.is_diag_item(cx, sym::HashSet) || ty.is_diag_item(cx, sym::BTreeSet)
 }
 
 fn is_a_std_map_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap)
+    ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap)
 }
 
 pub(super) fn check(
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 20cf353..4142f9f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -1,10 +1,11 @@
 use super::utils::clone_or_copy_needed;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::ForLoop;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::{get_iterator_item_ty, implements_trait};
 use clippy_utils::visitors::for_each_expr_without_closures;
-use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local};
+use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr};
 use core::ops::ControlFlow;
 use itertools::Itertools;
 use rustc_errors::Applicability;
@@ -50,7 +51,7 @@ pub fn check_for_loop_iter(
 
         // check whether `expr` is mutable
         fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-            if let Some(hir_id) = path_to_local(expr)
+            if let Some(hir_id) = expr.res_local_id()
                 && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
             {
                 matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..))
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs
index efd1a71..3290bdd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_join.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::res::MaybeDef;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem};
@@ -20,8 +20,8 @@ pub(super) fn check<'tcx>(
     let collect_output_adjusted_type = cx.typeck_results().expr_ty_adjusted(join_self_arg);
     if let ty::Ref(_, ref_type, _) = collect_output_adjusted_type.kind()
         // the turbofish for collect is ::<Vec<String>>
-        && let ty::Slice(slice) = ref_type.kind()
-        && is_type_lang_item(cx, *slice, LangItem::String)
+        && let ty::Slice(slice) = *ref_type.kind()
+        && slice.is_lang_item(cx, LangItem::String)
         // the argument for join is ""
         && let ExprKind::Lit(spanned) = &join_arg.kind
         && let LitKind::Str(symbol, _) = spanned.node
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 71e606a..2869547 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage};
 use hir::FnRetTy;
 use rustc_errors::Applicability;
@@ -19,8 +19,8 @@ pub(super) fn check<'tcx>(
     arg: &'tcx hir::Expr<'_>,
     simplify_using: &str,
 ) -> bool {
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
+    let is_option = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option);
+    let is_result = cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result);
     let is_bool = cx.typeck_results().expr_ty(recv).is_bool();
 
     if (is_option || is_result || is_bool)
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index cc44481..410e973 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res, sym};
+use clippy_utils::res::{MaybeDef, MaybeQPath};
+use clippy_utils::{last_path_segment, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, AmbigArg};
 use rustc_lint::LateContext;
@@ -37,21 +38,23 @@ pub(super) fn check(
     }
 
     let (constructor, call_args, ty) = if let hir::ExprKind::Call(call, call_args) = init.kind {
-        let Some(qpath) = call.qpath_opt() else { return };
+        let Some((qpath, hir_id)) = call.opt_qpath() else {
+            return;
+        };
 
         let args = last_path_segment(qpath).args.map(|args| args.args);
-        let res = cx.qpath_res(qpath, call.hir_id());
+        let res = cx.qpath_res(qpath, hir_id);
 
-        if is_res_lang_ctor(cx, res, hir::LangItem::OptionSome) {
+        if res.ctor_parent(cx).is_lang_item(cx, hir::LangItem::OptionSome) {
             (sym::Some, call_args, get_ty_from_args(args, 0))
-        } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultOk) {
+        } else if res.ctor_parent(cx).is_lang_item(cx, hir::LangItem::ResultOk) {
             (sym::Ok, call_args, get_ty_from_args(args, 0))
-        } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultErr) {
+        } else if res.ctor_parent(cx).is_lang_item(cx, hir::LangItem::ResultErr) {
             (sym::Err, call_args, get_ty_from_args(args, 1))
         } else {
             return;
         }
-    } else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) {
+    } else if init.res(cx).ctor_parent(cx).is_lang_item(cx, hir::LangItem::OptionNone) {
         let call_args: &[hir::Expr<'_>] = &[];
         (sym::None, call_args, None)
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
index 1f5e3de..0c01be4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
@@ -3,10 +3,11 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::sugg::{Sugg, make_binop};
-use clippy_utils::ty::{get_type_diagnostic_name, implements_trait, is_copy};
+use clippy_utils::ty::{implements_trait, is_copy};
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{get_parent_expr, is_from_proc_macro, path_to_local_id};
+use clippy_utils::{get_parent_expr, is_from_proc_macro};
 use rustc_ast::LitKind::Bool;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind};
@@ -54,7 +55,7 @@ pub(super) fn check<'a>(
         return;
     };
 
-    let variant = match get_type_diagnostic_name(cx, recv_ty) {
+    let variant = match recv_ty.opt_diag_name(cx) {
         Some(sym::Option) => Variant::Some,
         Some(sym::Result) => Variant::Ok,
         Some(_) | None => return,
@@ -75,11 +76,11 @@ pub(super) fn check<'a>(
             // .map_or(true, |x| x != y)
             // .map_or(true, |x| y != x) - swapped comparison
             && ((BinOpKind::Eq == op.node && !def_bool) || (BinOpKind::Ne == op.node && def_bool))
-            && let non_binding_location = if path_to_local_id(l, hir_id) { r } else { l }
+            && let non_binding_location = if l.res_local_id() == Some(hir_id) { r } else { l }
             && switch_to_eager_eval(cx, non_binding_location)
-            // xor, because if its both then that's a strange edge case and
+            // if its both then that's a strange edge case and
             // we can just ignore it, since by default clippy will error on this
-            && (path_to_local_id(l, hir_id) ^ path_to_local_id(r, hir_id))
+            && (l.res_local_id() == Some(hir_id)) != (r.res_local_id() == Some(hir_id))
             && !is_local_used(cx, non_binding_location, hir_id)
             && let typeck_results = cx.typeck_results()
             && let l_ty = typeck_results.expr_ty(l)
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_option_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_option_map_or_else.rs
new file mode 100644
index 0000000..265619e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_option_map_or_else.rs
@@ -0,0 +1,111 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{expr_or_init, find_binding_init, peel_blocks};
+use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{Body, BodyId, Closure, Expr, ExprKind, HirId, QPath};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+
+use super::UNNECESSARY_OPTION_MAP_OR_ELSE;
+use super::utils::get_last_chain_binding_hir_id;
+
+fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) {
+    let msg = "unused \"map closure\" when calling `Option::map_or_else` value";
+    let mut applicability = Applicability::MachineApplicable;
+    let self_snippet = snippet_with_applicability(cx, recv.span, "_", &mut applicability);
+    let err_snippet = snippet_with_applicability(cx, def_arg.span, "..", &mut applicability);
+    span_lint_and_sugg(
+        cx,
+        UNNECESSARY_OPTION_MAP_OR_ELSE,
+        expr.span,
+        msg,
+        "consider using `unwrap_or_else`",
+        format!("{self_snippet}.unwrap_or_else({err_snippet})"),
+        Applicability::MachineApplicable,
+    );
+}
+
+fn handle_qpath(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    recv: &Expr<'_>,
+    def_arg: &Expr<'_>,
+    expected_hir_id: HirId,
+    qpath: QPath<'_>,
+) {
+    if let QPath::Resolved(_, path) = qpath
+        && let Res::Local(hir_id) = path.res
+        && expected_hir_id == hir_id
+    {
+        emit_lint(cx, expr, recv, def_arg);
+    }
+}
+
+fn handle_closure(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, body_id: BodyId) {
+    let body = cx.tcx.hir_body(body_id);
+    handle_fn_body(cx, expr, recv, def_arg, body);
+}
+
+fn handle_fn_body(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, body: &Body<'_>) {
+    if let Some(first_param) = body.params.first() {
+        let body_expr = peel_blocks(body.value);
+        match body_expr.kind {
+            ExprKind::Path(qpath) => {
+                handle_qpath(cx, expr, recv, def_arg, first_param.pat.hir_id, qpath);
+            },
+            // If this is a block (that wasn't peeled off), then it means there are statements.
+            ExprKind::Block(block, _) => {
+                if let Some(block_expr) = block.expr
+                        // First we ensure that this is a "binding chain" (each statement is a binding
+                        // of the previous one) and that it is a binding of the closure argument.
+                        && let Some(last_chain_binding_id) =
+                            get_last_chain_binding_hir_id(first_param.pat.hir_id, block.stmts)
+                        && let ExprKind::Path(qpath) = block_expr.kind
+                {
+                    handle_qpath(cx, expr, recv, def_arg, last_chain_binding_id, qpath);
+                }
+            },
+            _ => {},
+        }
+    }
+}
+
+/// lint use of `_.map_or_else(|err| err, |n| n)` for `Option`s.
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, map_arg: &Expr<'_>) {
+    // lint if the caller of `map_or_else()` is an `Option`
+    if !cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option) {
+        return;
+    }
+    match map_arg.kind {
+        // If the second argument is a closure, we can check its body.
+        ExprKind::Closure(&Closure { body, .. }) => {
+            handle_closure(cx, expr, recv, def_arg, body);
+        },
+        ExprKind::Path(qpath) => {
+            let res = cx.qpath_res(&qpath, map_arg.hir_id);
+            match res {
+                // Case 1: Local variable (could be a closure)
+                Res::Local(hir_id) => {
+                    if let Some(init_expr) = find_binding_init(cx, hir_id) {
+                        let origin = expr_or_init(cx, init_expr);
+                        if let ExprKind::Closure(&Closure { body, .. }) = origin.kind {
+                            handle_closure(cx, expr, recv, def_arg, body);
+                        }
+                    }
+                },
+                // Case 2: Function definition
+                Res::Def(DefKind::Fn, def_id) => {
+                    if let Some(local_def_id) = def_id.as_local()
+                        && let Some(body) = cx.tcx.hir_maybe_body_owned_by(local_def_id)
+                    {
+                        handle_fn_body(cx, expr, recv, def_arg, body);
+                    }
+                },
+                _ => (),
+            }
+        },
+        _ => (),
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
index f84d0d6..1f6bb60 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_result_map_or_else.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::peel_blocks;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath};
@@ -51,7 +51,7 @@ pub(super) fn check<'tcx>(
     map_arg: &'tcx Expr<'_>,
 ) {
     // lint if the caller of `map_or_else()` is a `Result`
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
+    if cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result)
         && let ExprKind::Closure(&Closure { body, .. }) = map_arg.kind
         && let body = cx.tcx.hir_body(body)
         && let Some(first_param) = body.params.first()
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
index fa9d533..7cc8c79 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
+use clippy_utils::std_or_core;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_trait_method, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
 use rustc_lint::LateContext;
@@ -138,7 +139,10 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
         ] = &closure_body.params
         && let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind
         && method_path.ident.name == sym::cmp
-        && is_trait_method(cx, closure_body.value, sym::Ord)
+        && cx
+            .ty_based_def(closure_body.value)
+            .opt_parent(cx)
+            .is_diag_item(cx, sym::Ord)
     {
         let (closure_body, closure_arg, reverse) = if mirrored_exprs(left_expr, left_ident, right_expr, right_ident) {
             (
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 640931a..a6a39cb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -2,14 +2,11 @@
 use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::{SpanRangeExt, snippet};
-use clippy_utils::ty::{
-    get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_and_count_ty_refs,
-};
+use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_and_count_ty_refs};
 use clippy_utils::visitors::find_all_ret_expressions;
-use clippy_utils::{
-    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, is_expr_temporary_value, return_ty, sym,
-};
+use clippy_utils::{fn_def_id, get_parent_expr, is_expr_temporary_value, return_ty, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -35,12 +32,12 @@ pub fn check<'tcx>(
     args: &'tcx [Expr<'_>],
     msrv: Msrv,
 ) {
-    if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+    if let Some(method_parent_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id).opt_parent(cx)
         && args.is_empty()
     {
-        if is_cloned_or_copied(cx, method_name, method_def_id) {
+        if is_cloned_or_copied(cx, method_name, method_parent_id) {
             unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
-        } else if is_to_owned_like(cx, expr, method_name, method_def_id) {
+        } else if is_to_owned_like(cx, expr, method_name, method_parent_id) {
             if check_split_call_arg(cx, expr, method_name, receiver) {
                 return;
             }
@@ -48,7 +45,7 @@ pub fn check<'tcx>(
             // `check_addr_of_expr` and `check_into_iter_call_arg` determine whether the call is unnecessary
             // based on its context, that is, whether it is a referent in an `AddrOf` expression, an
             // argument in a `into_iter` call, or an argument in the call of some other function.
-            if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) {
+            if check_addr_of_expr(cx, expr, method_name, method_parent_id, receiver) {
                 return;
             }
             if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) {
@@ -66,12 +63,12 @@ pub fn check<'tcx>(
 
 /// Checks whether `expr` is a referent in an `AddrOf` expression and, if so, determines whether its
 /// call of a `to_owned`-like function is unnecessary.
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 fn check_addr_of_expr(
     cx: &LateContext<'_>,
     expr: &Expr<'_>,
     method_name: Symbol,
-    method_def_id: DefId,
+    method_parent_id: DefId,
     receiver: &Expr<'_>,
 ) -> bool {
     if let Some(parent) = get_parent_expr(cx, expr)
@@ -133,7 +130,7 @@ fn check_addr_of_expr(
         // `redundant_clone`, but copyable arrays are not.
         && (*referent_ty != receiver_ty
             || (matches!(referent_ty.kind(), ty::Array(..)) && is_copy(cx, *referent_ty))
-            || is_cow_into_owned(cx, method_name, method_def_id))
+            || is_cow_into_owned(cx, method_name, method_parent_id))
         && let Some(receiver_snippet) = receiver.span.get_source_text(cx)
     {
         if receiver_ty == target_ty && n_target_refs >= n_receiver_refs {
@@ -159,7 +156,7 @@ fn check_addr_of_expr(
             // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow)
             // but that's ok for Cow::into_owned specifically)
             && (cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() == target_ty
-                || is_cow_into_owned(cx, method_name, method_def_id))
+                || is_cow_into_owned(cx, method_name, method_parent_id))
         {
             if n_receiver_refs > 0 {
                 span_lint_and_sugg(
@@ -220,7 +217,7 @@ fn check_into_iter_call_arg(
         && let Some(item_ty) = get_iterator_item_ty(cx, parent_ty)
         && let Some(receiver_snippet) = receiver.span.get_source_text(cx)
         // If the receiver is a `Cow`, we can't remove the `into_owned` generally, see https://github.com/rust-lang/rust-clippy/issues/13624.
-        && !is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::Cow)
+        && !cx.typeck_results().expr_ty(receiver).is_diag_item(cx, sym::Cow)
         // Calling `iter()` on a temporary object can lead to false positives. #14242
         && !is_expr_temporary_value(cx, receiver)
     {
@@ -320,7 +317,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb
         // We may end-up here because of an expression like `x.to_string().split(…)` where the type of `x`
         // implements `AsRef<str>` but does not implement `Deref<Target = str>`. In this case, we have to
         // add `.as_ref()` to the suggestion.
-        let as_ref = if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String)
+        let as_ref = if cx.typeck_results().expr_ty(expr).is_lang_item(cx, LangItem::String)
             && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
             && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, sym::Target)
                 != Some(cx.tcx.types.str_)
@@ -615,21 +612,26 @@ fn has_lifetime(ty: Ty<'_>) -> bool {
 }
 
 /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`.
-fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
-    matches!(method_name, sym::cloned | sym::copied) && is_diag_trait_item(cx, method_def_id, sym::Iterator)
+fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_parent_id: DefId) -> bool {
+    matches!(method_name, sym::cloned | sym::copied) && method_parent_id.is_diag_item(cx, sym::Iterator)
 }
 
 /// Returns true if the named method can be used to convert the receiver to its "owned"
 /// representation.
-fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
-    is_cow_into_owned(cx, method_name, method_def_id)
-        || (method_name != sym::to_string && is_clone_like(cx, method_name, method_def_id))
-        || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
+fn is_to_owned_like<'a>(
+    cx: &LateContext<'a>,
+    call_expr: &Expr<'a>,
+    method_name: Symbol,
+    method_parent_id: DefId,
+) -> bool {
+    is_cow_into_owned(cx, method_name, method_parent_id)
+        || (method_name != sym::to_string && is_clone_like(cx, method_name, method_parent_id))
+        || is_to_string_on_string_like(cx, call_expr, method_name, method_parent_id)
 }
 
 /// Returns true if the named method is `Cow::into_owned`.
-fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
-    method_name == sym::into_owned && is_diag_item_method(cx, method_def_id, sym::Cow)
+fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_parent_id: DefId) -> bool {
+    method_name == sym::into_owned && method_parent_id.opt_impl_ty(cx).is_diag_item(cx, sym::Cow)
 }
 
 /// Returns true if the named method is `ToString::to_string` and it's called on a type that
@@ -638,9 +640,9 @@ fn is_to_string_on_string_like<'a>(
     cx: &LateContext<'_>,
     call_expr: &'a Expr<'a>,
     method_name: Symbol,
-    method_def_id: DefId,
+    method_parent_id: DefId,
 ) -> bool {
-    if method_name != sym::to_string || !is_diag_trait_item(cx, method_def_id, sym::ToString) {
+    if method_name != sym::to_string || !method_parent_id.is_diag_item(cx, sym::ToString) {
         return false;
     }
 
@@ -673,12 +675,12 @@ fn std_map_key<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
 }
 
 fn is_str_and_string(cx: &LateContext<'_>, arg_ty: Ty<'_>, original_arg_ty: Ty<'_>) -> bool {
-    original_arg_ty.is_str() && is_type_lang_item(cx, arg_ty, LangItem::String)
+    original_arg_ty.is_str() && arg_ty.is_lang_item(cx, LangItem::String)
 }
 
 fn is_slice_and_vec(cx: &LateContext<'_>, arg_ty: Ty<'_>, original_arg_ty: Ty<'_>) -> bool {
     (original_arg_ty.is_slice() || original_arg_ty.is_array() || original_arg_ty.is_array_slice())
-        && is_type_diagnostic_item(cx, arg_ty, sym::Vec)
+        && arg_ty.is_diag_item(cx, sym::Vec)
 }
 
 // This function will check the following:
diff --git a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
index af4ade3..a7d9b2e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::{SpanRangeExt, snippet};
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild};
+use clippy_utils::{expr_or_init, pat_is_wild};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind};
 use rustc_lint::LateContext;
@@ -40,9 +40,9 @@
 pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) {
     let recv_ty = cx.typeck_results().expr_ty(recv);
     // If we call a method on a `std::iter::Enumerate` instance
-    if is_type_diagnostic_item(cx, recv_ty, sym::Enumerate)
+    if recv_ty.is_diag_item(cx, sym::Enumerate)
         // If we are calling a method of the `Iterator` trait
-        && is_trait_method(cx, call_expr, sym::Iterator)
+        && cx.ty_based_def(call_expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
         // And the map argument is a closure
         && let ExprKind::Closure(closure) = closure_arg.kind
         && let closure_body = cx.tcx.hir_body(closure.body)
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
index 027215e..73a407b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::{is_never_like, is_type_diagnostic_item};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::ty::is_never_like;
 use clippy_utils::{is_in_test, is_inside_always_const_context, is_lint_allowed};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, Lint};
@@ -45,9 +46,9 @@ pub(super) fn check(
 ) {
     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 {
+    let (kind, none_value, none_prefix) = if ty.is_diag_item(cx, sym::Option) && !is_err {
         ("an `Option`", "None", "")
-    } else if is_type_diagnostic_item(cx, ty, sym::Result)
+    } else if ty.is_diag_item(cx, sym::Result)
         && let ty::Adt(_, substs) = ty.kind()
         && let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type()
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index e56f4b8..972304d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs, should_call_clone_as_function};
-use clippy_utils::{get_parent_expr, is_diag_trait_item, path_to_local_id, peel_blocks, strip_pat_refs};
+use clippy_utils::{get_parent_expr, peel_blocks, strip_pat_refs};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, LangItem};
 use rustc_lint::LateContext;
@@ -42,11 +43,11 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbol, recvr: &hir::Expr<'_>) {
     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
     // check if the call is to the actual `AsRef` or `AsMut` trait
-    let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else {
+    let Some(def) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else {
         return;
     };
 
-    if is_diag_trait_item(cx, def_id, sym::AsRef) || is_diag_trait_item(cx, def_id, sym::AsMut) {
+    if def.opt_parent(cx).is_diag_item(cx, sym::AsRef) || def.opt_parent(cx).is_diag_item(cx, sym::AsMut) {
         // check if the type after `as_ref` or `as_mut` is the same as before
         let rcv_ty = cx.typeck_results().expr_ty(recvr);
         let res_ty = cx.typeck_results().expr_ty(expr);
@@ -79,10 +80,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbo
                 applicability,
             );
         }
-    } else if let Some(impl_id) = cx.tcx.impl_of_assoc(def_id)
-        && let Some(adt) = cx.tcx.type_of(impl_id).instantiate_identity().ty_adt_def()
-        && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Option | sym::Result))
-    {
+    } else if matches!(
+        def.opt_parent(cx).opt_impl_ty(cx).opt_diag_name(cx),
+        Some(sym::Option | sym::Result)
+    ) {
         let rcv_ty = cx.typeck_results().expr_ty(recvr).peel_refs();
         let res_ty = cx.typeck_results().expr_ty(expr).peel_refs();
 
@@ -137,7 +138,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
                         // no autoderefs
                         && !cx.typeck_results().expr_adjustments(obj).iter()
                             .any(|a| matches!(a.kind, Adjust::Deref(Some(..))))
-                        && path_to_local_id(obj, local_id)
+                        && obj.res_local_id() == Some(local_id)
                     {
                         true
                     } else {
@@ -146,7 +147,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
                 },
                 hir::ExprKind::Call(call, [recv]) => {
                     if let hir::ExprKind::Path(qpath) = call.kind
-                        && path_to_local_id(recv, local_id)
+                        && recv.res_local_id() == Some(local_id)
                     {
                         check_qpath(cx, qpath, call.hir_id)
                     } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs b/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs
index 22df1f3..c6f5415 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::is_inside_always_const_context;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, QPath, UnsafeSource};
 use rustc_lint::LateContext;
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, func: &Expr<'
         && segment.ident.name == sym::new_unchecked
         && let [init_arg] = args
         && is_inside_always_const_context(cx.tcx, expr.hir_id)
-        && is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::NonZero)
+        && cx.typeck_results().node_type(ty.hir_id).is_diag_item(cx, sym::NonZero)
         && msrv.meets(cx, msrvs::CONST_UNWRAP)
     {
         let mut app = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index b0cc7a7..1e1b124 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -1,5 +1,5 @@
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{get_parent_expr, path_to_local_id, usage};
+use clippy_utils::res::{MaybeDef, MaybeResPath};
+use clippy_utils::{get_parent_expr, usage};
 use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, QPath, Stmt, StmtKind};
 use rustc_lint::LateContext;
@@ -20,7 +20,7 @@ fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
         match ty.kind() {
             ty::Slice(_) => true,
             ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => may_slice(cx, boxed),
-            ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec),
+            ty::Adt(..) => ty.is_diag_item(cx, sym::Vec),
             ty::Array(_, size) => size.try_to_target_usize(cx.tcx).is_some(),
             ty::Ref(_, inner, _) => may_slice(cx, *inner),
             _ => false,
@@ -130,7 +130,7 @@ impl<'tcx> CloneOrCopyVisitor<'_, 'tcx> {
     fn is_binding(&self, expr: &Expr<'tcx>) -> bool {
         self.binding_hir_ids
             .iter()
-            .any(|hir_id| path_to_local_id(expr, *hir_id))
+            .any(|&hir_id| expr.res_local_id() == Some(hir_id))
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
index bfb481f..5debaab 100644
--- a/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/vec_resize_to_zero.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use rustc_ast::LitKind;
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::Applicability;
@@ -19,7 +19,11 @@ pub(super) fn check<'tcx>(
 ) {
     if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
-        && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::Vec)
+        && cx
+            .tcx
+            .type_of(impl_id)
+            .instantiate_identity()
+            .is_diag_item(cx, sym::Vec)
         && let ExprKind::Lit(Spanned {
             node: LitKind::Int(Pu128(0), _),
             ..
diff --git a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
index 8ed6163..5727843 100644
--- a/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/verbose_file_reads.rs
@@ -1,6 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_trait_method;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
 use rustc_span::sym;
@@ -19,9 +18,13 @@ pub(super) fn check<'tcx>(
     recv: &'tcx Expr<'_>,
     (msg, help): (&'static str, &'static str),
 ) {
-    if is_trait_method(cx, expr, sym::IoRead)
+    if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::IoRead)
         && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _)))
-        && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(recv).peel_refs(), sym::File)
+        && cx
+            .typeck_results()
+            .expr_ty_adjusted(recv)
+            .peel_refs()
+            .is_diag_item(cx, sym::File)
     {
         #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
         span_lint_and_then(cx, VERBOSE_FILE_READS, expr.span, msg, |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs b/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs
index b5f34a9..3081d7f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
     if let Some(did) = ty.ty_adt_def()
         && cx.tcx.is_diagnostic_item(sym::Waker, did.did())
         && let ExprKind::MethodCall(_, waker_ref, &[], _) = recv.kind
-        && is_trait_method(cx, recv, sym::Clone)
+        && cx.ty_based_def(recv).opt_parent(cx).is_diag_item(cx, sym::Clone)
     {
         let mut applicability = Applicability::MachineApplicable;
         let snippet = snippet_with_applicability(cx, waker_ref.span.source_callsite(), "..", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 74b297c..12a6f34 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -81,7 +81,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
     }
 }
 
-#[allow(clippy::too_many_arguments)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     item_name: Symbol,
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index f9a7c56..ba62853 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -1,6 +1,7 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_trait_method, sym};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
+use clippy_utils::sym;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -78,7 +79,9 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
             }
         },
         ExprKind::MethodCall(path, receiver, args @ [_], _) => {
-            if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) {
+            if cx.typeck_results().expr_ty(receiver).is_floating_point()
+                || cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Ord)
+            {
                 match path.ident.name {
                     sym::max => fetch_const(cx, expr.span.ctxt(), Some(receiver), args, MinMax::Max),
                     sym::min => fetch_const(cx, expr.span.ctxt(), Some(receiver), args, MinMax::Min),
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index 8822b32..15b773c 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -1,9 +1,9 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
+use clippy_utils::sym;
 use clippy_utils::visitors::{Visitable, for_each_expr};
-use clippy_utils::{is_path_lang_item, sym};
 use rustc_ast::LitKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
@@ -112,11 +112,9 @@ fn should_lint<'tcx>(
         if let ExprKind::MethodCall(path, recv, ..) = &expr.kind {
             let recv_ty = typeck_results.expr_ty(recv).peel_refs();
 
-            if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) {
+            if path.ident.name == sym::debug_struct && recv_ty.is_diag_item(cx, sym::Formatter) {
                 has_debug_struct = true;
-            } else if path.ident.name == sym::finish_non_exhaustive
-                && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct)
-            {
+            } else if path.ident.name == sym::finish_non_exhaustive && recv_ty.is_diag_item(cx, sym::DebugStruct) {
                 has_finish_non_exhaustive = true;
             }
         }
@@ -137,7 +135,7 @@ fn as_field_call<'tcx>(
 ) -> Option<Symbol> {
     if let ExprKind::MethodCall(path, recv, [debug_field, _], _) = &expr.kind
         && let recv_ty = typeck_results.expr_ty(recv).peel_refs()
-        && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct)
+        && recv_ty.is_diag_item(cx, sym::DebugStruct)
         && path.ident.name == sym::field
         && let ExprKind::Lit(lit) = &debug_field.kind
         && let LitKind::Str(sym, ..) = lit.node
@@ -180,7 +178,9 @@ fn check_struct<'tcx>(
         .fields()
         .iter()
         .filter_map(|field| {
-            if field_accesses.contains(&field.ident.name) || is_path_lang_item(cx, field.ty, LangItem::PhantomData) {
+            if field_accesses.contains(&field.ident.name)
+                || field.ty.basic_res().is_lang_item(cx, LangItem::PhantomData)
+            {
                 None
             } else {
                 Some((field.span, "this field is unused"))
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 6323e72..bccc72c 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -167,7 +167,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
         let container_id = assoc_item.container_id(cx.tcx);
         let trait_def_id = match assoc_item.container {
             AssocContainer::Trait => Some(container_id),
-            AssocContainer::TraitImpl(_) => cx.tcx.impl_trait_ref(container_id).map(|t| t.skip_binder().def_id),
+            AssocContainer::TraitImpl(_) => Some(cx.tcx.impl_trait_id(container_id)),
             AssocContainer::InherentImpl => None,
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 3b44d4b..ddd4271 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::macros::root_macro_call_first_node;
-use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id, sym};
+use clippy_utils::res::MaybeResPath;
+use clippy_utils::{get_parent_expr, sym};
 use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -84,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // Find a write to a local variable.
         let var = if let ExprKind::Assign(lhs, ..) | ExprKind::AssignOp(_, lhs, _) = expr.kind
-            && let Some(var) = path_to_local(lhs)
+            && let Some(var) = lhs.res_local_id()
             && expr.span.desugaring_kind().is_none()
         {
             var
@@ -325,7 +326,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             return;
         }
 
-        if path_to_local_id(expr, self.var)
+        if expr.res_local_id() == Some(self.var)
             // Check that this is a read, not a write.
             && !is_in_assignment_position(self.cx, expr)
         {
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index fe2157c..2fef840 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -1,7 +1,12 @@
-use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::is_type_diagnostic_item;
-use rustc_hir::Expr;
-use rustc_lint::{LateContext, LateLintPass};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeDef;
+use clippy_utils::source::{IntoSpan, SpanRangeExt};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::ty_from_hir_ty;
+use rustc_errors::{Applicability, Diag};
+use rustc_hir::{self as hir, Expr, ExprKind, Item, ItemKind, LetStmt, QPath};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::mir::Mutability;
 use rustc_middle::ty::{self, IntTy, Ty, UintTy};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -88,24 +93,83 @@
 
 declare_lint_pass!(Mutex => [MUTEX_ATOMIC, MUTEX_INTEGER]);
 
+// NOTE: we don't use `check_expr` because that would make us lint every _use_ of such mutexes, not
+// just their definitions
 impl<'tcx> LateLintPass<'tcx> for Mutex {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let ty = cx.typeck_results().expr_ty(expr);
-        if let ty::Adt(_, subst) = ty.kind()
-            && is_type_diagnostic_item(cx, ty, sym::Mutex)
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        if !item.span.from_expansion()
+            && let ItemKind::Static(_, _, ty, body_id) = item.kind
         {
-            let mutex_param = subst.type_at(0);
-            if let Some(atomic_name) = get_atomic_name(mutex_param) {
-                let msg = format!(
-                    "consider using an `{atomic_name}` instead of a `Mutex` here; if you just want the locking \
-                         behavior and not the internal type, consider using `Mutex<()>`"
-                );
-                match *mutex_param.kind() {
-                    ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, msg),
-                    ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, msg),
-                    _ => span_lint(cx, MUTEX_ATOMIC, expr.span, msg),
+            let body = cx.tcx.hir_body(body_id);
+            let mid_ty = ty_from_hir_ty(cx, ty);
+            check_expr(cx, body.value.peel_blocks(), &TypeAscriptionKind::Required(ty), mid_ty);
+        }
+    }
+    fn check_local(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx LetStmt<'_>) {
+        if !stmt.span.from_expansion()
+            && let Some(init) = stmt.init
+        {
+            let mid_ty = cx.typeck_results().expr_ty(init);
+            check_expr(cx, init.peel_blocks(), &TypeAscriptionKind::Optional(stmt.ty), mid_ty);
+        }
+    }
+}
+
+/// Whether the type ascription `: Mutex<X>` (which we'll suggest replacing with `AtomicX`) is
+/// required
+enum TypeAscriptionKind<'tcx> {
+    /// Yes; for us, this is the case for statics
+    Required(&'tcx hir::Ty<'tcx>),
+    /// No; the ascription might've been necessary in an expression like:
+    /// ```ignore
+    /// let mutex: Mutex<u64> = Mutex::new(0);
+    /// ```
+    /// to specify the type of `0`, but since `AtomicX` already refers to a concrete type, we won't
+    /// need this ascription anymore.
+    Optional(Option<&'tcx hir::Ty<'tcx>>),
+}
+
+fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &TypeAscriptionKind<'tcx>, ty: Ty<'tcx>) {
+    if let ty::Adt(_, subst) = ty.kind()
+        && ty.is_diag_item(cx, sym::Mutex)
+        && let mutex_param = subst.type_at(0)
+        && let Some(atomic_name) = get_atomic_name(mutex_param)
+    {
+        let msg = "using a `Mutex` where an atomic would do";
+        let diag = |diag: &mut Diag<'_, _>| {
+            // if `expr = Mutex::new(arg)`, we can try emitting a suggestion
+            if let ExprKind::Call(qpath, [arg]) = expr.kind
+                && let ExprKind::Path(QPath::TypeRelative(_mutex, new)) = qpath.kind
+                && new.ident.name == sym::new
+            {
+                let mut applicability = Applicability::MaybeIncorrect;
+                let arg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability);
+                let mut suggs = vec![(expr.span, format!("std::sync::atomic::{atomic_name}::new({arg})"))];
+                match ty_ascription {
+                    TypeAscriptionKind::Required(ty_ascription) => {
+                        suggs.push((ty_ascription.span, format!("std::sync::atomic::{atomic_name}")));
+                    },
+                    TypeAscriptionKind::Optional(Some(ty_ascription)) => {
+                        // See https://github.com/rust-lang/rust-clippy/pull/15386 for why this is
+                        // required
+                        let colon_ascription = (cx.sess().source_map())
+                            .span_extend_to_prev_char_before(ty_ascription.span, ':', true)
+                            .with_leading_whitespace(cx)
+                            .into_span();
+                        suggs.push((colon_ascription, String::new()));
+                    },
+                    TypeAscriptionKind::Optional(None) => {}, // nothing to remove/replace
                 }
+                diag.multipart_suggestion("try", suggs, applicability);
+            } else {
+                diag.help(format!("consider using an `{atomic_name}` instead"));
             }
+            diag.help("if you just want the locking behavior and not the internal type, consider using `Mutex<()>`");
+        };
+        match *mutex_param.kind() {
+            ty::Uint(t) if t != UintTy::Usize => span_lint_and_then(cx, MUTEX_INTEGER, expr.span, msg, diag),
+            ty::Int(t) if t != IntTy::Isize => span_lint_and_then(cx, MUTEX_INTEGER, expr.span, msg, diag),
+            _ => span_lint_and_then(cx, MUTEX_ATOMIC, expr.span, msg, diag),
         }
     }
 }
@@ -135,7 +199,8 @@ fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> {
                 IntTy::I128 => None,
             }
         },
-        ty::RawPtr(_, _) => Some("AtomicPtr"),
+        // `AtomicPtr` only accepts `*mut T`
+        ty::RawPtr(_, Mutability::Mut) => Some("AtomicPtr"),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index b8601f7..55208ae 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -1,9 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::source::{indent_of, snippet, snippet_block};
-use rustc_ast::{Block, Label, ast};
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use clippy_utils::higher;
+use clippy_utils::source::{indent_of, snippet_block, snippet_with_context};
+use rustc_ast::Label;
+use rustc_errors::Applicability;
+use rustc_hir::{Block, Expr, ExprKind, LoopSource, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
-use rustc_span::Span;
+use rustc_span::{ExpnKind, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -127,9 +130,11 @@
 
 declare_lint_pass!(NeedlessContinue => [NEEDLESS_CONTINUE]);
 
-impl EarlyLintPass for NeedlessContinue {
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
-        if !expr.span.from_expansion() {
+impl<'tcx> LateLintPass<'tcx> for NeedlessContinue {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        // We cannot use `from_expansion` because for loops, while loops and while let loops are desugared
+        // into `loop` expressions.
+        if !matches!(expr.span.ctxt().outer_expn_data().kind, ExpnKind::Macro(..)) {
             check_and_warn(cx, expr);
         }
     }
@@ -188,19 +193,19 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
 ///
 /// - The expression is a `continue` node.
 /// - The expression node is a block with the first statement being a `continue`.
-fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&Label>) -> bool {
+fn needless_continue_in_else(else_expr: &Expr<'_>, label: Option<&Label>) -> bool {
     match else_expr.kind {
-        ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block, label),
-        ast::ExprKind::Continue(l) => compare_labels(label, l.as_ref()),
+        ExprKind::Block(else_block, _) => is_first_block_stmt_continue(else_block, label),
+        ExprKind::Continue(l) => compare_labels(label, l.label.as_ref()),
         _ => false,
     }
 }
 
-fn is_first_block_stmt_continue(block: &Block, label: Option<&Label>) -> bool {
+fn is_first_block_stmt_continue(block: &Block<'_>, label: Option<&Label>) -> bool {
     block.stmts.first().is_some_and(|stmt| match stmt.kind {
-        ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
-            if let ast::ExprKind::Continue(ref l) = e.kind {
-                compare_labels(label, l.as_ref())
+        StmtKind::Semi(e) | StmtKind::Expr(e) => {
+            if let ExprKind::Continue(l) = e.kind {
+                compare_labels(label, l.label.as_ref())
             } else {
                 false
             }
@@ -222,20 +227,34 @@ fn compare_labels(loop_label: Option<&Label>, continue_label: Option<&Label>) ->
 }
 
 /// If `expr` is a loop expression (while/while let/for/loop), calls `func` with
-/// the AST object representing the loop block of `expr`.
-fn with_loop_block<F>(expr: &ast::Expr, mut func: F)
+/// the HIR object representing the loop block of `expr`.
+fn with_loop_block<F>(expr: &Expr<'_>, mut func: F)
 where
-    F: FnMut(&Block, Option<&Label>),
+    F: FnMut(&Block<'_>, Option<&Label>),
 {
-    if let ast::ExprKind::While(_, loop_block, label)
-    | ast::ExprKind::ForLoop {
-        body: loop_block,
-        label,
-        ..
-    }
-    | ast::ExprKind::Loop(loop_block, label, ..) = &expr.kind
+    if let Some(higher::ForLoop { body, label, .. }) = higher::ForLoop::hir(expr)
+        && let ExprKind::Block(block, _) = &body.kind
     {
-        func(loop_block, label.as_ref());
+        func(block, label.as_ref());
+        return;
+    }
+
+    if let Some(higher::While { body, label, .. }) = higher::While::hir(expr)
+        && let ExprKind::Block(block, _) = &body.kind
+    {
+        func(block, label.as_ref());
+        return;
+    }
+
+    if let Some(higher::WhileLet { if_then, label, .. }) = higher::WhileLet::hir(expr)
+        && let ExprKind::Block(block, _) = &if_then.kind
+    {
+        func(block, label.as_ref());
+        return;
+    }
+
+    if let ExprKind::Loop(block, label, LoopSource::Loop, ..) = expr.kind {
+        func(block, label.as_ref());
     }
 }
 
@@ -247,17 +266,18 @@ fn with_loop_block<F>(expr: &ast::Expr, mut func: F)
 /// - The `if` condition expression,
 /// - The `then` block, and
 /// - The `else` expression.
-fn with_if_expr<F>(stmt: &ast::Stmt, mut func: F)
+fn with_if_expr<F>(expr: &Expr<'_>, mut func: F)
 where
-    F: FnMut(&ast::Expr, &ast::Expr, &Block, &ast::Expr),
+    F: FnMut(&Expr<'_>, &Expr<'_>, &Block<'_>, &Expr<'_>),
 {
-    match stmt.kind {
-        ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
-            if let ast::ExprKind::If(ref cond, ref if_block, Some(ref else_expr)) = e.kind {
-                func(e, cond, if_block, else_expr);
-            }
-        },
-        _ => {},
+    if let Some(higher::If {
+        cond,
+        then,
+        r#else: Some(r#else),
+    }) = higher::If::hir(expr)
+        && let ExprKind::Block(then, _) = then.kind
+    {
+        func(expr, cond, then, r#else);
     }
 }
 
@@ -269,20 +289,21 @@ enum LintType {
 }
 
 /// Data we pass around for construction of help messages.
-struct LintData<'a> {
+#[derive(Debug)]
+struct LintData<'hir> {
     /// The `if` expression encountered in the above loop.
-    if_expr: &'a ast::Expr,
+    if_expr: &'hir Expr<'hir>,
     /// The condition expression for the above `if`.
-    if_cond: &'a ast::Expr,
+    if_cond: &'hir Expr<'hir>,
     /// The `then` block of the `if` statement.
-    if_block: &'a Block,
+    if_block: &'hir Block<'hir>,
     /// The `else` block of the `if` statement.
     /// Note that we only work with `if` exprs that have an `else` branch.
-    else_expr: &'a ast::Expr,
+    else_expr: &'hir Expr<'hir>,
     /// The 0-based index of the `if` statement in the containing loop block.
-    stmt_idx: usize,
+    stmt_idx: Option<usize>,
     /// The statements of the loop block.
-    loop_block: &'a Block,
+    loop_block: &'hir Block<'hir>,
 }
 
 const MSG_REDUNDANT_CONTINUE_EXPRESSION: &str = "this `continue` expression is redundant";
@@ -299,7 +320,7 @@ struct LintData<'a> {
 
 const DROP_CONTINUE_EXPRESSION_MSG: &str = "consider dropping the `continue` expression";
 
-fn emit_warning(cx: &EarlyContext<'_>, data: &LintData<'_>, header: &str, typ: LintType) {
+fn emit_warning(cx: &LateContext<'_>, data: &LintData<'_>, header: &str, typ: LintType) {
     // snip    is the whole *help* message that appears after the warning.
     // message is the warning message.
     // expr    is the expression which the lint warning message refers to.
@@ -325,8 +346,15 @@ fn emit_warning(cx: &EarlyContext<'_>, data: &LintData<'_>, header: &str, typ: L
     );
 }
 
-fn suggestion_snippet_for_continue_inside_if(cx: &EarlyContext<'_>, data: &LintData<'_>) -> String {
-    let cond_code = snippet(cx, data.if_cond.span, "..");
+fn suggestion_snippet_for_continue_inside_if(cx: &LateContext<'_>, data: &LintData<'_>) -> String {
+    let mut applicability = Applicability::MachineApplicable;
+    let (cond_code, _) = snippet_with_context(
+        cx,
+        data.if_cond.span,
+        data.if_expr.span.ctxt(),
+        "..",
+        &mut applicability,
+    );
 
     let continue_code = snippet_block(cx, data.if_block.span, "..", Some(data.if_expr.span));
 
@@ -339,8 +367,15 @@ fn suggestion_snippet_for_continue_inside_if(cx: &EarlyContext<'_>, data: &LintD
     )
 }
 
-fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &LintData<'_>) -> String {
-    let cond_code = snippet(cx, data.if_cond.span, "..");
+fn suggestion_snippet_for_continue_inside_else(cx: &LateContext<'_>, data: &LintData<'_>) -> String {
+    let mut applicability = Applicability::MachineApplicable;
+    let (cond_code, _) = snippet_with_context(
+        cx,
+        data.if_cond.span,
+        data.if_expr.span.ctxt(),
+        "..",
+        &mut applicability,
+    );
 
     // Region B
     let block_code = erode_from_back(&snippet_block(cx, data.if_block.span, "..", Some(data.if_expr.span)));
@@ -352,18 +387,32 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin
     let indent = span_of_first_expr_in_block(data.if_block)
         .and_then(|span| indent_of(cx, span))
         .unwrap_or(0);
-    let to_annex = data.loop_block.stmts[data.stmt_idx + 1..]
-        .iter()
-        .map(|stmt| {
-            let span = cx.sess().source_map().stmt_span(stmt.span, data.loop_block.span);
+    let to_annex = if let Some(stmt_idx) = data.stmt_idx {
+        let mut lines = data.loop_block.stmts[stmt_idx + 1..]
+            .iter()
+            .map(|stmt| {
+                let span = cx.sess().source_map().stmt_span(stmt.span, data.loop_block.span);
+                let snip = snippet_block(cx, span, "..", None);
+                snip.lines()
+                    .map(|line| format!("{}{line}", " ".repeat(indent)))
+                    .collect::<Vec<_>>()
+                    .join("\n")
+            })
+            .collect::<Vec<_>>();
+        if let Some(expr) = data.loop_block.expr {
+            let span = expr.span;
             let snip = snippet_block(cx, span, "..", None);
-            snip.lines()
+            let expr_lines = snip
+                .lines()
                 .map(|line| format!("{}{line}", " ".repeat(indent)))
                 .collect::<Vec<_>>()
-                .join("\n")
-        })
-        .collect::<Vec<_>>()
-        .join("\n");
+                .join("\n");
+            lines.push(expr_lines);
+        }
+        lines.join("\n")
+    } else {
+        String::new()
+    };
 
     let indent_if = indent_of(cx, data.if_expr.span).unwrap_or(0);
     format!(
@@ -373,46 +422,53 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin
     )
 }
 
-fn check_last_stmt_in_expr<F>(inner_expr: &ast::Expr, func: &F)
+fn check_last_stmt_in_expr<F>(cx: &LateContext<'_>, inner_expr: &Expr<'_>, func: &F)
 where
     F: Fn(Option<&Label>, Span),
 {
-    match &inner_expr.kind {
-        ast::ExprKind::Continue(continue_label) => {
-            func(continue_label.as_ref(), inner_expr.span);
+    match inner_expr.kind {
+        ExprKind::Continue(continue_label) => {
+            func(continue_label.label.as_ref(), inner_expr.span);
         },
-        ast::ExprKind::If(_, then_block, else_block) => {
-            check_last_stmt_in_block(then_block, func);
+        ExprKind::If(_, then_block, else_block) if let ExprKind::Block(then_block, _) = then_block.kind => {
+            check_last_stmt_in_block(cx, then_block, func);
             if let Some(else_block) = else_block {
-                check_last_stmt_in_expr(else_block, func);
+                check_last_stmt_in_expr(cx, else_block, func);
             }
         },
-        ast::ExprKind::Match(_, arms, _) => {
+        ExprKind::Match(_, arms, _) => {
+            let match_ty = cx.typeck_results().expr_ty(inner_expr);
+            if !match_ty.is_unit() && !match_ty.is_never() {
+                return;
+            }
             for arm in arms {
-                if let Some(expr) = &arm.body {
-                    check_last_stmt_in_expr(expr, func);
-                }
+                check_last_stmt_in_expr(cx, arm.body, func);
             }
         },
-        ast::ExprKind::Block(b, _) => {
-            check_last_stmt_in_block(b, func);
+        ExprKind::Block(b, _) => {
+            check_last_stmt_in_block(cx, b, func);
         },
         _ => {},
     }
 }
 
-fn check_last_stmt_in_block<F>(b: &Block, func: &F)
+fn check_last_stmt_in_block<F>(cx: &LateContext<'_>, b: &Block<'_>, func: &F)
 where
     F: Fn(Option<&Label>, Span),
 {
+    if let Some(expr) = b.expr {
+        check_last_stmt_in_expr(cx, expr, func);
+        return;
+    }
+
     if let Some(last_stmt) = b.stmts.last()
-        && let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind
+        && let StmtKind::Expr(inner_expr) | StmtKind::Semi(inner_expr) = last_stmt.kind
     {
-        check_last_stmt_in_expr(inner_expr, func);
+        check_last_stmt_in_expr(cx, inner_expr, func);
     }
 }
 
-fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
+fn check_and_warn(cx: &LateContext<'_>, expr: &Expr<'_>) {
     with_loop_block(expr, |loop_block, label| {
         let p = |continue_label: Option<&Label>, span: Span| {
             if compare_labels(label, continue_label) {
@@ -427,16 +483,51 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
             }
         };
 
-        let stmts = &loop_block.stmts;
+        let stmts = loop_block.stmts;
         for (i, stmt) in stmts.iter().enumerate() {
             let mut maybe_emitted_in_if = false;
-            with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
+            if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind {
+                with_if_expr(expr, |if_expr, cond, then_block, else_expr| {
+                    let data = &LintData {
+                        if_expr,
+                        if_cond: cond,
+                        if_block: then_block,
+                        else_expr,
+                        stmt_idx: Some(i),
+                        loop_block,
+                    };
+
+                    maybe_emitted_in_if = true;
+                    if needless_continue_in_else(else_expr, label) {
+                        emit_warning(
+                            cx,
+                            data,
+                            DROP_ELSE_BLOCK_AND_MERGE_MSG,
+                            LintType::ContinueInsideElseBlock,
+                        );
+                    } else if is_first_block_stmt_continue(then_block, label) {
+                        emit_warning(cx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
+                    } else {
+                        maybe_emitted_in_if = false;
+                    }
+                });
+            }
+
+            if i == stmts.len() - 1 && loop_block.expr.is_none() && !maybe_emitted_in_if {
+                check_last_stmt_in_block(cx, loop_block, &p);
+            }
+        }
+
+        if let Some(expr) = loop_block.expr {
+            let mut maybe_emitted_in_if = false;
+
+            with_if_expr(expr, |if_expr, cond, then_block, else_expr| {
                 let data = &LintData {
                     if_expr,
                     if_cond: cond,
                     if_block: then_block,
                     else_expr,
-                    stmt_idx: i,
+                    stmt_idx: None,
                     loop_block,
                 };
 
@@ -455,8 +546,8 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
                 }
             });
 
-            if i == stmts.len() - 1 && !maybe_emitted_in_if {
-                check_last_stmt_in_block(loop_block, &p);
+            if !maybe_emitted_in_if {
+                check_last_stmt_in_block(cx, loop_block, &p);
             }
         }
     });
@@ -491,8 +582,12 @@ fn erode_from_back(s: &str) -> String {
     if ret.is_empty() { s.to_string() } else { ret }
 }
 
-fn span_of_first_expr_in_block(block: &Block) -> Option<Span> {
-    block.stmts.first().map(|stmt| stmt.span)
+fn span_of_first_expr_in_block(block: &Block<'_>) -> Option<Span> {
+    block
+        .stmts
+        .first()
+        .map(|stmt| stmt.span)
+        .or(block.expr.map(|expr| expr.span))
 }
 
 #[cfg(test)]
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 3a6ccc2..d03188f 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -1,3 +1,4 @@
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind, TyKind};
@@ -7,8 +8,8 @@
 
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::sym;
 use clippy_utils::ty::has_iter_method;
-use clippy_utils::{is_trait_method, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -65,7 +66,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
                 ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..)
             )
             && method_name.ident.name == sym::for_each
-            && is_trait_method(cx, expr, sym::Iterator)
+            && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
             // Checks the type of the `iter` method receiver is NOT a user defined type.
             && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some()
             // Skip the lint if the body is not block because this is simpler than `for` loop.
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index a914267..464a919 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::path_to_local;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::{SourceText, SpanRangeExt, snippet};
 use clippy_utils::ty::needs_ordered_drop;
 use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used};
@@ -116,7 +116,7 @@ fn from_expr(expr: &Expr<'_>, span: Span) -> Option<Self> {
             }
 
             Some(Self {
-                lhs_id: path_to_local(lhs)?,
+                lhs_id: lhs.res_local_id()?,
                 rhs_span: rhs.span.source_callsite(),
                 span,
             })
diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
index ad6313e..4bcd26c 100644
--- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
@@ -33,7 +33,7 @@
 }
 declare_lint_pass!(NeedlessMaybeSized => [NEEDLESS_MAYBE_SIZED]);
 
-#[allow(clippy::struct_field_names)]
+#[expect(clippy::struct_field_names)]
 struct Bound<'tcx> {
     /// The [`DefId`] of the type parameter the bound refers to
     param: DefId,
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index 7052e1d..3d2285e 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -364,7 +364,6 @@ fn is_in_unsafe_block(&self, item: HirId) -> bool {
 }
 
 impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
-    #[allow(clippy::if_same_then_else)]
     fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
         if let euv::Place {
             base:
@@ -398,7 +397,6 @@ fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
 
     fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {}
 
-    #[allow(clippy::if_same_then_else)]
     fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) {
         self.prev_bind = None;
         if let euv::Place {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 455d142..fb5f21a 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::{SpanRangeExt, snippet};
-use clippy_utils::ty::{
-    implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
-};
+use clippy_utils::ty::{implements_trait, implements_trait_with_env_from_iter, is_copy};
 use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
-use clippy_utils::{is_self, path_to_local_id, peel_hir_ty_options, strip_pat_refs, sym};
+use clippy_utils::{is_self, peel_hir_ty_options, strip_pat_refs, sym};
 use rustc_abi::ExternAbi;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir::intravisit::FnKind;
@@ -219,7 +218,7 @@ fn check_fn(
                         diag.span_help(span, "or consider marking this type as `Copy`");
                     }
 
-                    if is_type_diagnostic_item(cx, ty, sym::Vec)
+                    if ty.is_diag_item(cx, sym::Vec)
                         && let Some(clone_spans) = get_spans(cx, body, idx, &[(sym::clone, ".to_owned()")])
                         && let TyKind::Path(QPath::Resolved(_, path)) = input.kind
                         && let Some(elem_ty) = path
@@ -262,7 +261,7 @@ fn check_fn(
                         return;
                     }
 
-                    if is_type_lang_item(cx, ty, LangItem::String)
+                    if ty.is_lang_item(cx, LangItem::String)
                         && let Some(clone_spans) =
                             get_spans(cx, body, idx, &[(sym::clone, ".to_string()"), (sym::as_str, "")])
                     {
@@ -362,7 +361,7 @@ fn extract_clone_suggestions<'tcx>(
     let mut spans = Vec::new();
     for_each_expr_without_closures(body, |e| {
         if let ExprKind::MethodCall(seg, recv, [], _) = e.kind
-            && path_to_local_id(recv, id)
+            && recv.res_local_id() == Some(id)
         {
             if seg.ident.name == sym::capacity {
                 return ControlFlow::Break(());
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index 2a2160c..986a827 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::path_res;
+use clippy_utils::res::MaybeQPath;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath};
@@ -94,7 +94,7 @@ fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
 
 fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if let ExprKind::Call(path, [arg]) = expr.kind
-        && let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path)
+        && let Res::Def(DefKind::Ctor(..), ctor_id) = path.res(cx)
         && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
         && let variant = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) {
             "Some"
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 0d6666e..701923c 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -1,9 +1,8 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::{expr_type_is_certain, has_drop};
-use clippy_utils::{
-    in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks,
-};
+use clippy_utils::{in_automatically_derived, is_inside_always_const_context, is_lint_allowed, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{
@@ -109,7 +108,7 @@ fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx rustc_hir::Block
     }
 
     fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if let Some(def_id) = path_to_local(expr) {
+        if let Some(def_id) = expr.res_local_id() {
             self.underscore_bindings.swap_remove(&def_id);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
index e531f79..e11f775 100644
--- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
@@ -1,14 +1,13 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{
-    is_diag_trait_item, is_from_proc_macro, is_res_lang_ctor, last_path_segment, path_res, std_or_core,
-};
+use clippy_utils::{is_from_proc_macro, last_path_segment, std_or_core};
 use rustc_errors::Applicability;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::{Block, Body, Expr, ExprKind, ImplItem, ImplItemKind, Item, LangItem, Node, UnOp};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{Block, Body, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, LangItem, UnOp};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::{EarlyBinder, TraitRef};
-use rustc_session::declare_lint_pass;
+use rustc_middle::ty::{TyCtxt, TypeckResults};
+use rustc_session::impl_lint_pass;
 use rustc_span::sym;
 use rustc_span::symbol::kw;
 
@@ -109,33 +108,96 @@
     suspicious,
     "non-canonical implementation of `PartialOrd` on an `Ord` type"
 }
-declare_lint_pass!(NonCanonicalImpls => [NON_CANONICAL_CLONE_IMPL, NON_CANONICAL_PARTIAL_ORD_IMPL]);
+impl_lint_pass!(NonCanonicalImpls => [NON_CANONICAL_CLONE_IMPL, NON_CANONICAL_PARTIAL_ORD_IMPL]);
+
+#[expect(
+    clippy::struct_field_names,
+    reason = "`_trait` suffix is meaningful on its own, \
+              and creating an inner `StoredTraits` struct would just add a level of indirection"
+)]
+pub(crate) struct NonCanonicalImpls {
+    partial_ord_trait: Option<DefId>,
+    ord_trait: Option<DefId>,
+    clone_trait: Option<DefId>,
+    copy_trait: Option<DefId>,
+}
+
+impl NonCanonicalImpls {
+    pub(crate) fn new(tcx: TyCtxt<'_>) -> Self {
+        let lang_items = tcx.lang_items();
+        Self {
+            partial_ord_trait: lang_items.partial_ord_trait(),
+            ord_trait: tcx.get_diagnostic_item(sym::Ord),
+            clone_trait: lang_items.clone_trait(),
+            copy_trait: lang_items.copy_trait(),
+        }
+    }
+}
+
+/// The traits that this lint looks at
+enum Trait {
+    Clone,
+    PartialOrd,
+}
 
 impl LateLintPass<'_> for NonCanonicalImpls {
-    fn check_impl_item<'tcx>(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem<'tcx>) {
-        if let ImplItemKind::Fn(_, impl_item_id) = impl_item.kind
-            && let Node::Item(item) = cx.tcx.parent_hir_node(impl_item.hir_id())
-            && let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder)
-            && let trait_name = cx.tcx.get_diagnostic_name(trait_impl.def_id)
-            // NOTE: check this early to avoid expensive checks that come after this one
-            && matches!(trait_name, Some(sym::Clone | sym::PartialOrd))
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+        if let ItemKind::Impl(impl_) = item.kind
+            // Both `PartialOrd` and `Clone` have one required method, and `PartialOrd` can have 5 methods in total
+            && (1..=5).contains(&impl_.items.len())
+            && let Some(of_trait) = impl_.of_trait
+            && let Some(trait_did) = of_trait.trait_ref.trait_def_id()
+            // Check this early to hopefully bail out as soon as possible
+            && let trait_ = if Some(trait_did) == self.clone_trait {
+                Trait::Clone
+            } else if Some(trait_did) == self.partial_ord_trait {
+                Trait::PartialOrd
+            } else {
+                return;
+            }
             && !cx.tcx.is_automatically_derived(item.owner_id.to_def_id())
-            && let body = cx.tcx.hir_body(impl_item_id)
-            && let ExprKind::Block(block, ..) = body.value.kind
-            && !block.span.in_external_macro(cx.sess().source_map())
-            && !is_from_proc_macro(cx, impl_item)
         {
-            if trait_name == Some(sym::Clone)
-                && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy)
-                && implements_trait(cx, trait_impl.self_ty(), copy_def_id, &[])
-            {
-                check_clone_on_copy(cx, impl_item, block);
-            } else if trait_name == Some(sym::PartialOrd)
-                && impl_item.ident.name == sym::partial_cmp
-                && let Some(ord_def_id) = cx.tcx.get_diagnostic_item(sym::Ord)
-                && implements_trait(cx, trait_impl.self_ty(), ord_def_id, &[])
-            {
-                check_partial_ord_on_ord(cx, impl_item, item, &trait_impl, body, block);
+            let mut assoc_fns = impl_
+                .items
+                .iter()
+                .map(|id| cx.tcx.hir_impl_item(*id))
+                .filter_map(|assoc| {
+                    if let ImplItemKind::Fn(_, body_id) = assoc.kind
+                        && let body = cx.tcx.hir_body(body_id)
+                        && let ExprKind::Block(block, ..) = body.value.kind
+                        && !block.span.in_external_macro(cx.sess().source_map())
+                    {
+                        Some((assoc, body, block))
+                    } else {
+                        None
+                    }
+                });
+
+            let trait_impl = cx.tcx.impl_trait_ref(item.owner_id).skip_binder();
+
+            match trait_ {
+                Trait::Clone => {
+                    if let Some(copy_trait) = self.copy_trait
+                        && implements_trait(cx, trait_impl.self_ty(), copy_trait, &[])
+                    {
+                        for (assoc, _, block) in assoc_fns {
+                            check_clone_on_copy(cx, assoc, block);
+                        }
+                    }
+                },
+                Trait::PartialOrd => {
+                    // If `Self` and `Rhs` are not the same type, then a corresponding `Ord` impl is not possible,
+                    // since it doesn't have an `Rhs`
+                    if let [lhs, rhs] = trait_impl.args.as_slice()
+                        && lhs == rhs
+                        && let Some(ord_trait) = self.ord_trait
+                        && implements_trait(cx, trait_impl.self_ty(), ord_trait, &[])
+                        && let Some((assoc, body, block)) =
+                            assoc_fns.find(|(assoc, _, _)| assoc.ident.name == sym::partial_cmp)
+                    {
+                        check_partial_ord_on_ord(cx, assoc, item, body, block);
+                    }
+                },
             }
         }
     }
@@ -153,6 +215,10 @@ fn check_clone_on_copy(cx: &LateContext<'_>, impl_item: &ImplItem<'_>, block: &B
             return;
         }
 
+        if is_from_proc_macro(cx, impl_item) {
+            return;
+        }
+
         span_lint_and_sugg(
             cx,
             NON_CANONICAL_CLONE_IMPL,
@@ -164,7 +230,7 @@ fn check_clone_on_copy(cx: &LateContext<'_>, impl_item: &ImplItem<'_>, block: &B
         );
     }
 
-    if impl_item.ident.name == sym::clone_from {
+    if impl_item.ident.name == sym::clone_from && !is_from_proc_macro(cx, impl_item) {
         span_lint_and_sugg(
             cx,
             NON_CANONICAL_CLONE_IMPL,
@@ -181,7 +247,6 @@ fn check_partial_ord_on_ord<'tcx>(
     cx: &LateContext<'tcx>,
     impl_item: &ImplItem<'_>,
     item: &Item<'_>,
-    trait_impl: &TraitRef<'_>,
     body: &Body<'_>,
     block: &Block<'tcx>,
 ) {
@@ -206,12 +271,7 @@ fn check_partial_ord_on_ord<'tcx>(
         && expr_is_cmp(cx, ret, impl_item, &mut needs_fully_qualified)
     {
         return;
-    }
-    // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
-    // suggestion tons more complex.
-    else if let [lhs, rhs, ..] = trait_impl.args.as_slice()
-        && lhs != rhs
-    {
+    } else if is_from_proc_macro(cx, impl_item) {
         return;
     }
 
@@ -261,7 +321,7 @@ fn expr_is_cmp<'tcx>(
     impl_item: &ImplItem<'_>,
     needs_fully_qualified: &mut bool,
 ) -> bool {
-    let impl_item_did = impl_item.owner_id.def_id;
+    let typeck = cx.tcx.typeck(impl_item.owner_id.def_id);
     match expr.kind {
         ExprKind::Call(
             Expr {
@@ -271,16 +331,16 @@ fn expr_is_cmp<'tcx>(
             },
             [cmp_expr],
         ) => {
-            is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome)
-            // Fix #11178, allow `Self::cmp(self, ..)` too
-            && self_cmp_call(cx, cmp_expr, impl_item_did, needs_fully_qualified)
+            typeck.qpath_res(some_path, *some_hir_id).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
+                // Fix #11178, allow `Self::cmp(self, ..)`
+                && self_cmp_call(cx, typeck, cmp_expr, needs_fully_qualified)
         },
         ExprKind::MethodCall(_, recv, [], _) => {
-            cx.tcx
-                .typeck(impl_item_did)
-                .type_dependent_def_id(expr.hir_id)
-                .is_some_and(|def_id| is_diag_trait_item(cx, def_id, sym::Into))
-                && self_cmp_call(cx, recv, impl_item_did, needs_fully_qualified)
+            typeck
+                .type_dependent_def(expr.hir_id)
+                .assoc_parent(cx)
+                .is_diag_item(cx, sym::Into)
+                && self_cmp_call(cx, typeck, recv, needs_fully_qualified)
         },
         _ => false,
     }
@@ -289,12 +349,13 @@ fn expr_is_cmp<'tcx>(
 /// Returns whether this is any of `self.cmp(..)`, `Self::cmp(self, ..)` or `Ord::cmp(self, ..)`.
 fn self_cmp_call<'tcx>(
     cx: &LateContext<'tcx>,
+    typeck: &TypeckResults<'tcx>,
     cmp_expr: &'tcx Expr<'tcx>,
-    def_id: LocalDefId,
     needs_fully_qualified: &mut bool,
 ) -> bool {
     match cmp_expr.kind {
-        ExprKind::Call(path, [_, _]) => path_res(cx, path)
+        ExprKind::Call(path, [_, _]) => path
+            .res(typeck)
             .opt_def_id()
             .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)),
         ExprKind::MethodCall(_, recv, [_], ..) => {
@@ -309,11 +370,7 @@ fn self_cmp_call<'tcx>(
             // `else` branch, it must be a method named `cmp` that isn't `Ord::cmp`
             *needs_fully_qualified = true;
 
-            // It's a bit annoying but `typeck_results` only gives us the CURRENT body, which we
-            // have none, not of any `LocalDefId` we want, so we must call the query itself to avoid
-            // an immediate ICE
-            cx.tcx
-                .typeck(def_id)
+            typeck
                 .type_dependent_def_id(cmp_expr.hir_id)
                 .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id))
         },
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index b810bc0..fd5562f 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -87,7 +87,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             && let Some(trait_id) = of_trait.trait_ref.trait_def_id()
             && send_trait == trait_id
             && of_trait.polarity == ImplPolarity::Positive
-            && let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+            && let ty_trait_ref = cx.tcx.impl_trait_ref(item.owner_id)
             && let self_ty = ty_trait_ref.instantiate_identity().self_ty()
             && let ty::Adt(adt_def, impl_trait_args) = self_ty.kind()
         {
diff --git a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
index 7ecde40..61e4d41 100644
--- a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
+++ b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
@@ -2,8 +2,9 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_hir_and_then};
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::paths::{self, PathNS, find_crates, lookup_path_str};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{fn_def_id, is_no_std_crate, path_def_id, sym};
+use clippy_utils::{fn_def_id, is_no_std_crate, sym};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -188,7 +189,7 @@ impl LazyInfo {
     fn from_item(cx: &LateContext<'_>, item: &Item<'_>) -> Option<Self> {
         // Check if item is a `once_cell:sync::Lazy` static.
         if let ItemKind::Static(_, _, ty, body_id) = item.kind
-            && let Some(path_def_id) = path_def_id(cx, ty)
+            && let Some(path_def_id) = ty.basic_res().opt_def_id()
             && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
             && paths::ONCE_CELL_SYNC_LAZY.matches(cx, path_def_id)
         {
@@ -219,7 +220,7 @@ fn from_item(cx: &LateContext<'_>, item: &Item<'_>) -> Option<Self> {
     fn lint(&self, cx: &LateContext<'_>, sugg_map: &FxIndexMap<DefId, Option<String>>) {
         // Applicability might get adjusted to `Unspecified` later if any calls
         // in `calls_span_and_id` are not replaceable judging by the `sugg_map`.
-        let mut appl = Applicability::MachineApplicable;
+        let mut app = Applicability::MachineApplicable;
         let mut suggs = vec![(self.ty_span_no_args, "std::sync::LazyLock".to_string())];
 
         for (span, def_id) in &self.calls_span_and_id {
@@ -228,7 +229,7 @@ fn lint(&self, cx: &LateContext<'_>, sugg_map: &FxIndexMap<DefId, Option<String>
                 suggs.push((*span, sugg));
             } else {
                 // If NO suggested replacement, not machine applicable
-                appl = Applicability::Unspecified;
+                app = Applicability::Unspecified;
             }
         }
 
@@ -239,7 +240,7 @@ fn lint(&self, cx: &LateContext<'_>, sugg_map: &FxIndexMap<DefId, Option<String>
             self.ty_span_no_args,
             "this type has been superseded by `LazyLock` in the standard library",
             |diag| {
-                diag.multipart_suggestion("use `std::sync::LazyLock` instead", suggs, appl);
+                diag.multipart_suggestion("use `std::sync::LazyLock` instead", suggs, app);
             },
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index ec8c229..51644f7 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -1,13 +1,14 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{get_expr_use_or_unification_node, path_def_id, path_to_local, path_to_local_id};
+use clippy_utils::get_expr_use_or_unification_node;
+use clippy_utils::res::{MaybeQPath, MaybeResPath};
 use core::cell::Cell;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::HirIdMap;
-use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
+use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemImplKind, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, ConstKind, EarlyBinder, GenericArgKind, GenericArgsRef};
+use rustc_middle::ty::{self, ConstKind, GenericArgKind, GenericArgsRef};
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::symbol::{Ident, kw};
@@ -212,7 +213,7 @@ fn new(span: Span, idx: usize) -> Self {
 /// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the
 /// `DefId` of the function paired with the parameter's index.
 #[derive(Default)]
-#[allow(clippy::struct_field_names)]
+#[expect(clippy::struct_field_names)]
 struct Params {
     params: Vec<Param>,
     by_id: HirIdMap<usize>,
@@ -319,15 +320,14 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) {
             Node::ImplItem(&ImplItem {
                 kind: ImplItemKind::Fn(ref sig, _),
                 owner_id,
+                impl_kind,
                 ..
             }) => {
-                if let Node::Item(item) = cx.tcx.parent_hir_node(owner_id.into())
-                    && let Some(trait_ref) = cx
-                        .tcx
-                        .impl_trait_ref(item.owner_id)
-                        .map(EarlyBinder::instantiate_identity)
-                    && let Some(trait_item_id) = cx.tcx.trait_item_of(owner_id)
+                if let ImplItemImplKind::Trait { trait_item_def_id, .. } = impl_kind
+                    && let Ok(trait_item_id) = trait_item_def_id
                 {
+                    let impl_id = cx.tcx.parent(owner_id.into());
+                    let trait_ref = cx.tcx.impl_trait_ref(impl_id).instantiate_identity();
                     (
                         trait_item_id,
                         FnKind::ImplTraitFn(
@@ -358,7 +358,7 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) {
-        if let Some(id) = path_to_local(e)
+        if let Some(id) = e.res_local_id()
             && let Some(param) = self.params.get_by_id_mut(id)
         {
             let typeck = cx.typeck_results();
@@ -370,7 +370,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) {
                     Some((Node::Expr(parent), child_id)) => match parent.kind {
                         // Recursive call. Track which index the parameter is used in.
                         ExprKind::Call(callee, args)
-                            if path_def_id(cx, callee).is_some_and(|id| {
+                            if callee.res(cx).opt_def_id().is_some_and(|id| {
                                 id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id))
                             }) =>
                         {
@@ -395,7 +395,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) {
                         },
                         // Parameter update e.g. `x = x + 1`
                         ExprKind::Assign(lhs, rhs, _) | ExprKind::AssignOp(_, lhs, rhs)
-                            if rhs.hir_id == child_id && path_to_local_id(lhs, id) =>
+                            if rhs.hir_id == child_id && lhs.res_local_id() == Some(id) =>
                         {
                             return;
                         },
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index e062e55..0a6499e 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -2,7 +2,7 @@
 use clippy_config::Conf;
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary, sym};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_lint::{LateContext, LateLintPass};
@@ -108,9 +108,7 @@ fn has_specific_allowed_type_and_operation<'tcx>(
         rhs_ty: Ty<'tcx>,
     ) -> bool {
         let is_div_or_rem = matches!(op, hir::BinOpKind::Div | hir::BinOpKind::Rem);
-        let is_sat_or_wrap = |ty: Ty<'_>| {
-            is_type_diagnostic_item(cx, ty, sym::Saturating) || is_type_diagnostic_item(cx, ty, sym::Wrapping)
-        };
+        let is_sat_or_wrap = |ty: Ty<'_>| ty.is_diag_item(cx, sym::Saturating) || ty.is_diag_item(cx, sym::Wrapping);
 
         // If the RHS is `NonZero<u*>`, then division or module by zero will never occur.
         if Self::is_non_zero_u(cx, rhs_ty) && is_div_or_rem {
diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
index e87cfd1..d6af023 100644
--- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
@@ -47,7 +47,6 @@ fn check_compare<'a>(cx: &LateContext<'a>, bit_op: &Expr<'a>, cmp_op: BinOpKind,
     }
 }
 
-#[allow(clippy::too_many_lines)]
 fn check_bit_mask(
     cx: &LateContext<'_>,
     bit_op: BinOpKind,
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index 604f8f5..05358de 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::path_def_id;
+use clippy_utils::res::MaybeQPath;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{implements_trait, is_copy};
 use rustc_errors::Applicability;
@@ -47,11 +47,14 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
             (arg, arg.span)
         },
         ExprKind::Call(path, [arg])
-            if path_def_id(cx, path).is_some_and(|did| match cx.tcx.get_diagnostic_name(did) {
-                Some(sym::from_str_method) => true,
-                Some(sym::from_fn) => !is_copy(cx, typeck.expr_ty(expr)),
-                _ => false,
-            }) =>
+            if path
+                .res(cx)
+                .opt_def_id()
+                .is_some_and(|did| match cx.tcx.get_diagnostic_name(did) {
+                    Some(sym::from_str_method) => true,
+                    Some(sym::from_fn) => !is_copy(cx, typeck.expr_ty(expr)),
+                    _ => false,
+                }) =>
         {
             (arg, arg.span)
         },
diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
index d897b0e..4a1da7e 100644
--- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
@@ -1,8 +1,8 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sym;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -18,7 +18,11 @@ pub(crate) fn check<'tcx>(
 ) {
     if op == BinOpKind::Div
         && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind
-        && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
+        && cx
+            .typeck_results()
+            .expr_ty(self_arg)
+            .peel_refs()
+            .is_diag_item(cx, sym::Duration)
         && let Some(Constant::Int(divisor)) = ConstEvalCtxt::new(cx).eval_local(right, expr.span.ctxt())
     {
         let suggested_fn = match (method_path.ident.name, divisor) {
diff --git a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
index 7b98afa..1620312 100644
--- a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::symbol::sym;
@@ -16,7 +16,7 @@ pub(crate) fn check<'tcx>(
     if op == hir::BinOpKind::Div
         && cx.typeck_results().expr_ty(left).is_integral()
         && let right_ty = cx.typeck_results().expr_ty(right)
-        && (right_ty.is_integral() || is_type_diagnostic_item(cx, right_ty, sym::NonZero))
+        && (right_ty.is_integral() || right_ty.is_diag_item(cx, sym::NonZero))
     {
         #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
         span_lint_and_then(cx, INTEGER_DIVISION, expr.span, "integer division", |diag| {
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 3483f30..c32c74a 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
@@ -1,11 +1,12 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_copy;
 use clippy_utils::{
     CaptureKind, can_move_expr_to_closure, eager_or_lazy, expr_requires_coercion, higher, is_else_clause,
-    is_in_const_context, is_res_lang_ctor, peel_blocks, peel_hir_expr_while,
+    is_in_const_context, peel_blocks, peel_hir_expr_while,
 };
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -314,9 +315,9 @@ fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
 fn try_get_inner_pat_and_is_result<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<(&'tcx Pat<'tcx>, bool)> {
     if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind {
         let res = cx.qpath_res(qpath, pat.hir_id);
-        if is_res_lang_ctor(cx, res, OptionSome) {
+        if res.ctor_parent(cx).is_lang_item(cx, OptionSome) {
             return Some((inner_pat, false));
-        } else if is_res_lang_ctor(cx, res, ResultOk) {
+        } else if res.ctor_parent(cx).is_lang_item(cx, ResultOk) {
             return Some((inner_pat, true));
         }
     }
@@ -379,9 +380,14 @@ fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
             kind: PatExprKind::Path(qpath),
             hir_id,
             ..
-        }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
+        }) => cx
+            .qpath_res(qpath, *hir_id)
+            .ctor_parent(cx)
+            .is_lang_item(cx, OptionNone),
         PatKind::TupleStruct(ref qpath, [first_pat], _) => {
-            is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
+            cx.qpath_res(qpath, arm.pat.hir_id)
+                .ctor_parent(cx)
+                .is_lang_item(cx, ResultErr)
                 && matches!(first_pat.kind, PatKind::Wild)
         },
         PatKind::Wild => true,
diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
index ee1d594..57127e9 100644
--- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::visitors::{Descend, for_each_expr};
 use clippy_utils::{is_inside_always_const_context, return_ty};
 use core::ops::ControlFlow;
@@ -56,7 +56,7 @@ fn check_fn(
             return;
         }
         let owner = cx.tcx.local_def_id_to_hir_id(def_id).expect_owner();
-        if is_type_diagnostic_item(cx, return_ty(cx, owner), sym::Result) {
+        if return_ty(cx, owner).is_diag_item(cx, sym::Result) {
             lint_impl_body(cx, span, body);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
index 9b9024c..44217ac 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_res_lang_ctor, path_res, peel_hir_expr_refs, peel_ref_operators, sugg};
+use clippy_utils::res::{MaybeDef, MaybeQPath};
+use clippy_utils::{peel_hir_expr_refs, peel_ref_operators, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem};
 use rustc_lint::{LateContext, LateLintPass};
@@ -47,13 +47,21 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         }
 
         // If the expression is of type `Option`
-        let is_ty_option =
-            |expr: &Expr<'_>| is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr).peel_refs(), sym::Option);
+        let is_ty_option = |expr: &Expr<'_>| {
+            cx.typeck_results()
+                .expr_ty(expr)
+                .peel_refs()
+                .is_diag_item(cx, sym::Option)
+        };
 
         // If the expression is a literal `Option::None`
         let is_none_ctor = |expr: &Expr<'_>| {
             !expr.span.from_expansion()
-                && is_res_lang_ctor(cx, path_res(cx, peel_hir_expr_refs(expr).0), LangItem::OptionNone)
+                && peel_hir_expr_refs(expr)
+                    .0
+                    .res(cx)
+                    .ctor_parent(cx)
+                    .is_lang_item(cx, LangItem::OptionNone)
         };
 
         let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
index 4ce6827..a5e57d9 100644
--- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::{SpanRangeExt, snippet};
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{path_to_local_id, sym};
+use clippy_utils::sym;
 use rustc_ast::{LitKind, StrStyle};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -137,7 +137,7 @@ fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
             && let PatKind::Binding(BindingMode::MUT, id, name, None) = local.pat.kind
             && !local.span.in_external_macro(cx.sess().source_map())
             && let ty = cx.typeck_results().pat_ty(local.pat)
-            && is_type_diagnostic_item(cx, ty, sym::PathBuf)
+            && ty.is_diag_item(cx, sym::PathBuf)
         {
             self.searcher = Some(PathbufPushSearcher {
                 local_id: id,
@@ -158,7 +158,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             && let Res::Local(id) = path.res
             && !expr.span.in_external_macro(cx.sess().source_map())
             && let ty = cx.typeck_results().expr_ty(left)
-            && is_type_diagnostic_item(cx, ty, sym::PathBuf)
+            && ty.is_diag_item(cx, sym::PathBuf)
         {
             self.searcher = Some(PathbufPushSearcher {
                 local_id: id,
@@ -176,7 +176,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let Some(mut searcher) = self.searcher.take()
             && let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
             && let ExprKind::MethodCall(name, self_arg, [arg_expr], _) = expr.kind
-            && path_to_local_id(self_arg, searcher.local_id)
+            && self_arg.res_local_id() == Some(searcher.local_id)
             && name.ident.name == sym::push
         {
             searcher.err_span = searcher.err_span.to(stmt.span);
diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
index da56a78..68a34d4 100644
--- a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
+++ b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::sym;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_ast::ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -34,7 +34,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             && let ExprKind::Lit(lit) = &arg.kind
             && LitKind::Bool(false) == lit.node
             && path.ident.name == sym::set_readonly
-            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions)
+            && cx
+                .typeck_results()
+                .expr_ty(receiver)
+                .is_diag_item(cx, sym::FsPermissions)
         {
             span_lint_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 9eed464..8446b6f 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::visitors::contains_unsafe_block;
-use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core, sym};
+use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, std_or_core, sym};
 use hir::LifetimeKind;
 use rustc_abi::ExternAbi;
 use rustc_errors::{Applicability, MultiSpan};
@@ -561,7 +562,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             }
 
             // Check if this is local we care about
-            let Some(&args_idx) = path_to_local(e).and_then(|id| self.bindings.get(&id)) else {
+            let Some(&args_idx) = e.res_local_id().and_then(|id| self.bindings.get(&id)) else {
                 return walk_expr(self, e);
             };
             let args = &self.args[args_idx];
@@ -617,7 +618,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                         // Some methods exist on both `[T]` and `Vec<T>`, such as `len`, where the receiver type
                         // doesn't coerce to a slice and our adjusted type check below isn't enough,
                         // but it would still be valid to call with a slice
-                        if is_allowed_vec_method(self.cx, use_expr) {
+                        if is_allowed_vec_method(use_expr) {
                             return;
                         }
                     }
@@ -742,8 +743,10 @@ fn get_lifetimes<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Vec<(&'tcx Lifetime, Option<M
 
 fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     if let ExprKind::Call(pathexp, []) = expr.kind {
-        path_def_id(cx, pathexp)
-            .is_some_and(|id| matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut)))
+        matches!(
+            pathexp.basic_res().opt_diag_name(cx),
+            Some(sym::ptr_null | sym::ptr_null_mut)
+        )
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs
index 66c59cb..694d44d 100644
--- a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs
@@ -2,7 +2,7 @@
 use clippy_config::types::PubUnderscoreFieldsBehaviour;
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::is_path_lang_item;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use rustc_hir::{FieldDef, Item, ItemKind, LangItem};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -76,7 +76,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                 // We ignore fields that have `#[doc(hidden)]`.
                 && !is_doc_hidden(cx.tcx.hir_attrs(field.hir_id))
                 // We ignore fields that are `PhantomData`.
-                && !is_path_lang_item(cx, field.ty, LangItem::PhantomData)
+                && !field.ty.basic_res().is_lang_item(cx, LangItem::PhantomData)
             {
                 span_lint_hir_and_then(
                     cx,
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index d3a5a5dd..e67ea1f 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -4,14 +4,15 @@
 use clippy_config::types::MatchLintBehaviour;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item};
+use clippy_utils::ty::{implements_trait, is_copy};
 use clippy_utils::usage::local_used_after_expr;
 use clippy_utils::{
     eq_expr_value, fn_def_id_with_node_args, higher, is_else_clause, is_in_const_context, is_lint_allowed,
-    is_path_lang_item, is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id,
-    peel_blocks, peel_blocks_with_stmt, span_contains_cfg, span_contains_comment, sym,
+    pat_and_expr_can_be_question_mark, peel_blocks, peel_blocks_with_stmt, span_contains_cfg, span_contains_comment,
+    sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
@@ -205,7 +206,7 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_
         IfBlockType::IfIs(caller, caller_ty, call_sym, if_then) => {
             // If the block could be identified as `if x.is_none()/is_err()`,
             // we then only need to check the if_then return to see if it is none/err.
-            is_type_diagnostic_item(cx, caller_ty, smbl)
+            caller_ty.is_diag_item(cx, smbl)
                 && expr_return_none_or_err(smbl, cx, if_then, caller, None)
                 && match smbl {
                     sym::Option => call_sym == sym::is_none,
@@ -214,20 +215,20 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_
                 }
         },
         IfBlockType::IfLet(res, let_expr_ty, let_pat_sym, let_expr, if_then, if_else) => {
-            is_type_diagnostic_item(cx, let_expr_ty, smbl)
+            let_expr_ty.is_diag_item(cx, smbl)
                 && match smbl {
                     sym::Option => {
                         // We only need to check `if let Some(x) = option` not `if let None = option`,
                         // because the later one will be suggested as `if option.is_none()` thus causing conflict.
-                        is_res_lang_ctor(cx, res, OptionSome)
+                        res.ctor_parent(cx).is_lang_item(cx, OptionSome)
                             && if_else.is_some()
                             && expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, None)
                     },
                     sym::Result => {
-                        (is_res_lang_ctor(cx, res, ResultOk)
+                        (res.ctor_parent(cx).is_lang_item(cx, ResultOk)
                             && if_else.is_some()
                             && expr_return_none_or_err(smbl, cx, if_else.unwrap(), let_expr, Some(let_pat_sym)))
-                            || is_res_lang_ctor(cx, res, ResultErr)
+                            || res.ctor_parent(cx).is_lang_item(cx, ResultErr)
                                 && expr_return_none_or_err(smbl, cx, if_then, let_expr, Some(let_pat_sym))
                                 && if_else.is_none()
                     },
@@ -247,8 +248,11 @@ fn expr_return_none_or_err(
     match peel_blocks_with_stmt(expr).kind {
         ExprKind::Ret(Some(ret_expr)) => expr_return_none_or_err(smbl, cx, ret_expr, cond_expr, err_sym),
         ExprKind::Path(ref qpath) => match smbl {
-            sym::Option => is_res_lang_ctor(cx, cx.qpath_res(qpath, expr.hir_id), OptionNone),
-            sym::Result => path_to_local(expr).is_some() && path_to_local(expr) == path_to_local(cond_expr),
+            sym::Option => cx
+                .qpath_res(qpath, expr.hir_id)
+                .ctor_parent(cx)
+                .is_lang_item(cx, OptionNone),
+            sym::Result => expr.res_local_id().is_some() && expr.res_local_id() == cond_expr.res_local_id(),
             _ => false,
         },
         ExprKind::Call(call_expr, [arg]) => {
@@ -342,7 +346,10 @@ fn extract_ctor_call<'a, 'tcx>(
     pat: &'a Pat<'tcx>,
 ) -> Option<&'a Pat<'tcx>> {
     if let PatKind::TupleStruct(variant_path, [val_binding], _) = &pat.kind
-        && is_res_lang_ctor(cx, cx.qpath_res(variant_path, pat.hir_id), expected_ctor)
+        && cx
+            .qpath_res(variant_path, pat.hir_id)
+            .ctor_parent(cx)
+            .is_lang_item(cx, expected_ctor)
     {
         Some(val_binding)
     } else {
@@ -371,7 +378,7 @@ fn check_arm_is_some_or_ok<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &Ar
         // Extract out `val`
         && let Some(binding) = extract_binding_pat(val_binding)
         // Check body is just `=> val`
-        && path_to_local_id(peel_blocks(arm.body), binding)
+        && peel_blocks(arm.body).res_local_id() == Some(binding)
     {
         true
     } else {
@@ -393,7 +400,7 @@ fn check_arm_is_none_or_err<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &A
                 // check `=> return Err(...)`
                 && let ExprKind::Ret(Some(wrapped_ret_expr)) = arm_body.kind
                 && let ExprKind::Call(ok_ctor, [ret_expr]) = wrapped_ret_expr.kind
-                && is_res_lang_ctor(cx, path_res(cx, ok_ctor), ResultErr)
+                && ok_ctor.res(cx).ctor_parent(cx).is_lang_item(cx, ResultErr)
                 // check if `...` is `val` from binding or `val.into()`
                 && is_local_or_local_into(cx, ret_expr, ok_val)
             {
@@ -404,10 +411,10 @@ fn check_arm_is_none_or_err<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &A
         },
         TryMode::Option => {
             // Check the pat is `None`
-            if is_res_lang_ctor(cx, path_res(cx, arm.pat), OptionNone)
+            if arm.pat.res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone)
                 // Check `=> return None`
                 && let ExprKind::Ret(Some(ret_expr)) = arm_body.kind
-                && is_res_lang_ctor(cx, path_res(cx, ret_expr), OptionNone)
+                && ret_expr.res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone)
                 && !ret_expr.span.from_expansion()
             {
                 true
@@ -424,8 +431,10 @@ fn is_local_or_local_into(cx: &LateContext<'_>, expr: &Expr<'_>, val: HirId) ->
         .and_then(|(fn_def_id, _)| cx.tcx.trait_of_assoc(fn_def_id))
         .is_some_and(|trait_def_id| cx.tcx.is_diagnostic_item(sym::Into, trait_def_id));
     match expr.kind {
-        ExprKind::MethodCall(_, recv, [], _) | ExprKind::Call(_, [recv]) => is_into_call && path_to_local_id(recv, val),
-        _ => path_to_local_id(expr, val),
+        ExprKind::MethodCall(_, recv, [], _) | ExprKind::Call(_, [recv]) => {
+            is_into_call && recv.res_local_id() == Some(val)
+        },
+        _ => expr.res_local_id() == Some(val),
     }
 }
 
@@ -477,7 +486,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
             if_then,
             if_else,
         )
-        && ((is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id))
+        && ((is_early_return(sym::Option, cx, &if_block) && peel_blocks(if_then).res_local_id() == Some(bind_id))
             || is_early_return(sym::Result, cx, &if_block))
         && if_else
             .map(|e| eq_expr_value(cx, let_expr, peel_blocks(e)))
@@ -485,7 +494,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
             .is_none()
     {
         if !is_copy(cx, caller_ty)
-            && let Some(hir_id) = path_to_local(let_expr)
+            && let Some(hir_id) = let_expr.res_local_id()
             && local_used_after_expr(cx, hir_id, expr)
         {
             return;
@@ -521,11 +530,11 @@ fn inside_try_block(&self) -> bool {
     }
 }
 
-fn is_try_block(cx: &LateContext<'_>, bl: &Block<'_>) -> bool {
+fn is_try_block(bl: &Block<'_>) -> bool {
     if let Some(expr) = bl.expr
         && let ExprKind::Call(callee, [_]) = expr.kind
     {
-        is_path_lang_item(cx, callee, LangItem::TryTraitFromOutput)
+        callee.opt_lang_path() == Some(LangItem::TryTraitFromOutput)
     } else {
         false
     }
@@ -581,8 +590,8 @@ fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         }
     }
 
-    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
-        if is_try_block(cx, block) {
+    fn check_block(&mut self, _: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
+        if is_try_block(block) {
             *self
                 .try_block_depth_stack
                 .last_mut()
@@ -598,8 +607,8 @@ fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &Body<'tcx>) {
         self.try_block_depth_stack.pop();
     }
 
-    fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
-        if is_try_block(cx, block) {
+    fn check_block_post(&mut self, _: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
+        if is_try_block(block) {
             *self
                 .try_block_depth_stack
                 .last_mut()
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 0b2313c..e4c91b7 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -2,13 +2,11 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeQPath, MaybeResPath};
 use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{
-    expr_use_ctxt, fn_def_id, get_parent_expr, higher, is_in_const_context, is_integer_const, is_path_lang_item,
-    path_to_local,
-};
+use clippy_utils::{expr_use_ctxt, fn_def_id, get_parent_expr, higher, is_in_const_context, is_integer_const};
 use rustc_ast::Mutability;
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
@@ -321,7 +319,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R
             BinOpKind::Le => (true, Ordering::Less),
             _ => return None,
         };
-        if let Some(id) = path_to_local(l) {
+        if let Some(id) = l.res_local_id() {
             if let Some(c) = ConstEvalCtxt::new(cx).eval(r) {
                 return Some(RangeBounds {
                     val: c,
@@ -333,7 +331,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R
                     inc: inclusive,
                 });
             }
-        } else if let Some(id) = path_to_local(r)
+        } else if let Some(id) = r.res_local_id()
             && let Some(c) = ConstEvalCtxt::new(cx).eval(l)
         {
             return Some(RangeBounds {
@@ -370,7 +368,7 @@ fn can_switch_ranges<'tcx>(
     // Check if `expr` is the argument of a compiler-generated `IntoIter::into_iter(expr)`
     if let ExprKind::Call(func, [arg]) = parent_expr.kind
         && arg.hir_id == use_ctxt.child_id
-        && is_path_lang_item(cx, func, LangItem::IntoIterIntoIter)
+        && func.opt_lang_path() == Some(LangItem::IntoIterIntoIter)
     {
         return true;
     }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index de6766c..13c1b10 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::fn_has_unsatisfiable_preds;
 use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage};
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::ty::{has_drop, is_copy, is_type_lang_item, peel_and_count_ty_refs};
+use clippy_utils::ty::{has_drop, is_copy, peel_and_count_ty_refs};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, LangItem, def_id};
@@ -100,7 +101,7 @@ fn check_fn(
 
             let from_borrow = cx.tcx.lang_items().get(LangItem::CloneFn) == Some(fn_def_id)
                 || fn_name == Some(sym::to_owned_method)
-                || (fn_name == Some(sym::to_string_method) && is_type_lang_item(cx, arg_ty, LangItem::String));
+                || (fn_name == Some(sym::to_string_method) && arg_ty.is_lang_item(cx, LangItem::String));
 
             let from_deref = !from_borrow && matches!(fn_name, Some(sym::path_to_pathbuf | sym::os_str_to_os_string));
 
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index a358eff..f2cf809 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_parent_expr;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{is_type_lang_item, peel_and_count_ty_refs};
+use clippy_utils::ty::peel_and_count_ty_refs;
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
@@ -80,7 +81,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind
             && addressee.span.ctxt() == ctxt
             && let ExprKind::Index(indexed, range, _) = addressee.kind
-            && is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull)
+            && cx
+                .typeck_results()
+                .expr_ty_adjusted(range)
+                .is_lang_item(cx, LangItem::RangeFull)
         {
             let (expr_ty, expr_ref_count, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(expr));
             let (indexed_ty, indexed_ref_count, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(indexed));
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 89d9451..d1fc228 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -2,9 +2,10 @@
 
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::paths;
 use clippy_utils::paths::PathLookup;
+use clippy_utils::res::MaybeQPath;
 use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{path_def_id, paths};
 use rustc_ast::ast::{LitKind, StrStyle};
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{BorrowKind, Expr, ExprKind, OwnerId};
@@ -138,7 +139,7 @@ fn check_crate(&mut self, cx: &LateContext<'tcx>) {
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Call(fun, [arg]) = expr.kind
-            && let Some(def_id) = path_def_id(cx, fun)
+            && let Some(def_id) = fun.res(cx).opt_def_id()
             && let Some(regex_kind) = self.definitions.get(&def_id)
         {
             if let Some(&(loop_item_id, loop_span)) = self.loop_stack.last()
diff --git a/src/tools/clippy/clippy_lints/src/replace_box.rs b/src/tools/clippy/clippy_lints/src/replace_box.rs
new file mode 100644
index 0000000..4bbd180
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/replace_box.rs
@@ -0,0 +1,111 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{is_default_equivalent_call, local_is_initialized};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, LangItem, QPath};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects assignments of `Default::default()` or `Box::new(value)`
+    /// to a place of type `Box<T>`.
+    ///
+    /// ### Why is this bad?
+    /// This incurs an extra heap allocation compared to assigning the boxed
+    /// storage.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let mut b = Box::new(1u32);
+    /// b = Default::default();
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let mut b = Box::new(1u32);
+    /// *b = Default::default();
+    /// ```
+    #[clippy::version = "1.92.0"]
+    pub REPLACE_BOX,
+    perf,
+    "assigning a newly created box to `Box<T>` is inefficient"
+}
+declare_lint_pass!(ReplaceBox => [REPLACE_BOX]);
+
+impl LateLintPass<'_> for ReplaceBox {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+        if let ExprKind::Assign(lhs, rhs, _) = &expr.kind
+            && !lhs.span.from_expansion()
+            && !rhs.span.from_expansion()
+            && let lhs_ty = cx.typeck_results().expr_ty(lhs)
+            // No diagnostic for late-initialized locals
+            && lhs.res_local_id().is_none_or(|local| local_is_initialized(cx, local))
+            && let Some(inner_ty) = lhs_ty.boxed_ty()
+        {
+            if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
+                && implements_trait(cx, inner_ty, default_trait_id, &[])
+                && is_default_call(cx, rhs)
+            {
+                span_lint_and_then(
+                    cx,
+                    REPLACE_BOX,
+                    expr.span,
+                    "creating a new box with default content",
+                    |diag| {
+                        let mut app = Applicability::MachineApplicable;
+                        let suggestion = format!(
+                            "{} = Default::default()",
+                            Sugg::hir_with_applicability(cx, lhs, "_", &mut app).deref()
+                        );
+
+                        diag.note("this creates a needless allocation").span_suggestion(
+                            expr.span,
+                            "replace existing content with default instead",
+                            suggestion,
+                            app,
+                        );
+                    },
+                );
+            }
+
+            if inner_ty.is_sized(cx.tcx, cx.typing_env())
+                && let Some(rhs_inner) = get_box_new_payload(cx, rhs)
+            {
+                span_lint_and_then(cx, REPLACE_BOX, expr.span, "creating a new box", |diag| {
+                    let mut app = Applicability::MachineApplicable;
+                    let suggestion = format!(
+                        "{} = {}",
+                        Sugg::hir_with_applicability(cx, lhs, "_", &mut app).deref(),
+                        Sugg::hir_with_context(cx, rhs_inner, expr.span.ctxt(), "_", &mut app),
+                    );
+
+                    diag.note("this creates a needless allocation").span_suggestion(
+                        expr.span,
+                        "replace existing content with inner value instead",
+                        suggestion,
+                        app,
+                    );
+                });
+            }
+        }
+    }
+}
+
+fn is_default_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    matches!(expr.kind, ExprKind::Call(func, _args) if is_default_equivalent_call(cx, func, Some(expr)))
+}
+
+fn get_box_new_payload<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+    if let ExprKind::Call(box_new, [arg]) = expr.kind
+        && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_new.kind
+        && seg.ident.name == sym::new
+        && ty.basic_res().is_lang_item(cx, LangItem::OwnedBox)
+    {
+        Some(arg)
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
index 51adbbc..ce86a9c 100644
--- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::snippet;
-use clippy_utils::{is_from_proc_macro, path_to_local_id, sym};
+use clippy_utils::{is_from_proc_macro, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind};
@@ -125,7 +126,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let Some(searcher) = self.searcher.take() {
             if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
                 && let ExprKind::MethodCall(name, self_arg, [space_hint], _) = expr.kind
-                && path_to_local_id(self_arg, searcher.local_id)
+                && self_arg.res_local_id() == Some(searcher.local_id)
                 && name.ident.name == sym::reserve
                 && !is_from_proc_macro(cx, expr)
             {
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index b057396..83a226b 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -113,10 +113,9 @@ fn check_fn(
     ) {
         if matches!(kind, FnKind::Method(_, _))
             // We are only interested in methods, not in functions or associated functions.
-            && let Some(impl_def) = cx.tcx.impl_of_assoc(fn_def.to_def_id())
             // We don't want this method to be te implementation of a trait because the
             // `#[must_use]` should be put on the trait definition directly.
-            && cx.tcx.trait_id_of_impl(impl_def).is_none()
+            && cx.tcx.inherent_impl_of_assoc(fn_def.to_def_id()).is_some()
         {
             let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def);
             check_method(cx, decl, fn_def, span, hir_id.expect_owner());
diff --git a/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs b/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs
index e2002fb..f54a26a 100644
--- a/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs
+++ b/src/tools/clippy/clippy_lints/src/returns/let_and_return.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::sugg::has_enclosing_paren;
 use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{binary_expr_needs_parentheses, fn_def_id, path_to_local_id, span_contains_cfg};
+use clippy_utils::{binary_expr_needs_parentheses, fn_def_id, span_contains_cfg};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, PatKind, StmtKind};
@@ -21,7 +22,7 @@ pub(super) fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>)
         && cx.tcx.hir_attrs(local.hir_id).is_empty()
         && let Some(initexpr) = &local.init
         && let PatKind::Binding(_, local_id, _, _) = local.pat.kind
-        && path_to_local_id(retexpr, local_id)
+        && retexpr.res_local_id() == Some(local_id)
         && (cx.sess().edition() >= Edition::Edition2024 || !last_statement_borrows(cx, initexpr))
         && !initexpr.span.in_external_macro(cx.sess().source_map())
         && !retexpr.span.in_external_macro(cx.sess().source_map())
diff --git a/src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs b/src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs
index c05038c..c47a3ef 100644
--- a/src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/returns/needless_return_with_question_mark.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, path_res};
+use clippy_utils::res::{MaybeDef, MaybeQPath};
+use clippy_utils::{is_from_proc_macro, is_inside_let_else};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::ResultErr;
 use rustc_hir::{ExprKind, HirId, ItemKind, MatchSource, Node, OwnerNode, Stmt, StmtKind};
@@ -19,7 +20,7 @@ pub(super) fn check_stmt<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         && let ExprKind::Match(maybe_cons, _, MatchSource::TryDesugar(_)) = ret.kind
         && let ExprKind::Call(_, [maybe_result_err]) = maybe_cons.kind
         && let ExprKind::Call(maybe_constr, _) = maybe_result_err.kind
-        && is_res_lang_ctor(cx, path_res(cx, maybe_constr), ResultErr)
+        && maybe_constr.res(cx).ctor_parent(cx).is_lang_item(cx, ResultErr)
 
         // Ensure this is not the final stmt, otherwise removing it would cause a compile error
         && let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir_get_parent_item(expr.hir_id))
diff --git a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
index ff6e6ef..688da33 100644
--- a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
+++ b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
@@ -1,7 +1,7 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{SpanlessEq, higher, peel_hir_expr_while, sym};
 use rustc_hir::{Expr, ExprKind, UnOp};
@@ -103,7 +103,7 @@ fn try_parse_op_call<'tcx>(
         let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
         if value.span.eq_ctxt(expr.span) && path.ident.name == symbol {
             for sym in &[sym::HashSet, sym::BTreeSet] {
-                if is_type_diagnostic_item(cx, receiver_ty, *sym) {
+                if receiver_ty.is_diag_item(cx, *sym) {
                     return Some((OpExpr { receiver, value, span }, *sym));
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 1439986..7fdea6b 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -1,7 +1,7 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::path_to_local_id;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::{Descend, Visitable, for_each_expr};
 use rustc_data_structures::fx::FxHashMap;
@@ -202,7 +202,7 @@ pub fn is_local_used_except<'tcx>(
     for_each_expr(cx, visitable, |e| {
         if except.is_some_and(|it| it == e.hir_id) {
             ControlFlow::Continue(Descend::No)
-        } else if path_to_local_id(e, id) {
+        } else if e.res_local_id() == Some(id) {
             ControlFlow::Break(())
         } else {
             ControlFlow::Continue(Descend::Yes)
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index 9110f68..c4604fb 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::{indent_of, snippet};
-use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary, sym};
+use clippy_utils::{expr_or_init, get_attr, peel_hir_expr_unary, sym};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -276,7 +277,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                 && let hir::PatKind::Binding(_, hir_id, ident, _) = local.pat.kind
                 && !self.ap.apas.contains_key(&hir_id)
                 && {
-                    if let Some(local_hir_id) = path_to_local(expr) {
+                    if let Some(local_hir_id) = expr.res_local_id() {
                         local_hir_id == hir_id
                     } else {
                         true
@@ -301,7 +302,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                 modify_apa_params(&mut apa);
                 let _ = self.ap.apas.insert(hir_id, apa);
             } else {
-                let Some(hir_id) = path_to_local(expr) else {
+                let Some(hir_id) = expr.res_local_id() else {
                     return;
                 };
                 let Some(apa) = self.ap.apas.get_mut(&hir_id) else {
@@ -319,7 +320,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                         }
                     },
                     hir::StmtKind::Semi(semi_expr) => {
-                        if has_drop(semi_expr, apa.first_bind_ident, self.cx) {
+                        if has_drop(self.cx, semi_expr, apa.first_bind_ident) {
                             apa.has_expensive_expr_after_last_attr = false;
                             apa.last_stmt_span = DUMMY_SP;
                             return;
@@ -416,11 +417,11 @@ fn dummy_stmt_expr<'any>(expr: &'any hir::Expr<'any>) -> hir::Stmt<'any> {
     }
 }
 
-fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: Option<Ident>, lcx: &LateContext<'_>) -> bool {
+fn has_drop(cx: &LateContext<'_>, expr: &hir::Expr<'_>, first_bind_ident: Option<Ident>) -> bool {
     if let hir::ExprKind::Call(fun, [first_arg]) = expr.kind
         && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind
         && let Res::Def(DefKind::Fn, did) = fun_path.res
-        && lcx.tcx.is_diagnostic_item(sym::mem_drop, did)
+        && cx.tcx.is_diagnostic_item(sym::mem_drop, did)
     {
         let has_ident = |local_expr: &hir::Expr<'_>| {
             if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind
diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
index 8c34da0..595c75a 100644
--- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
+++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
@@ -40,8 +40,8 @@
 declare_lint_pass!(SingleCharLifetimeNames => [SINGLE_CHAR_LIFETIME_NAMES]);
 
 impl EarlyLintPass for SingleCharLifetimeNames {
-    fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam) {
-        if param.ident.span.in_external_macro(ctx.sess().source_map()) {
+    fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &GenericParam) {
+        if param.ident.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
@@ -51,7 +51,7 @@ fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam)
         {
             #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
             span_lint_and_then(
-                ctx,
+                cx,
                 SINGLE_CHAR_LIFETIME_NAMES,
                 param.ident.span,
                 "single-character lifetime names are likely uninformative",
diff --git a/src/tools/clippy/clippy_lints/src/single_option_map.rs b/src/tools/clippy/clippy_lints/src/single_option_map.rs
index cc497c9..4556d28 100644
--- a/src/tools/clippy/clippy_lints/src/single_option_map.rs
+++ b/src/tools/clippy/clippy_lints/src/single_option_map.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{path_res, peel_blocks};
+use clippy_utils::peel_blocks;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use rustc_hir::def::Res;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::FnKind;
@@ -55,10 +55,9 @@ fn check_fn(
             if let ExprKind::MethodCall(method_name, callee, args, _span) = func_body.kind
                 && method_name.ident.name == sym::map
                 && let callee_type = cx.typeck_results().expr_ty(callee)
-                && is_type_diagnostic_item(cx, callee_type, sym::Option)
+                && callee_type.is_diag_item(cx, sym::Option)
                 && let ExprKind::Path(_path) = callee.kind
-                && let Res::Local(_id) = path_res(cx, callee)
-                && matches!(path_res(cx, callee), Res::Local(_id))
+                && matches!(callee.basic_res(), Res::Local(_))
                 && !matches!(args[0].kind, ExprKind::Path(_))
             {
                 if let ExprKind::Closure(closure) = args[0].kind {
@@ -71,7 +70,7 @@ fn check_fn(
                     } else if let ExprKind::MethodCall(_segment, receiver, method_args, _span) = value.kind
                         && matches!(receiver.kind, ExprKind::Path(_))
                         && method_args.iter().all(|arg| matches!(arg.kind, ExprKind::Path(_)))
-                        && method_args.iter().all(|arg| matches!(path_res(cx, arg), Res::Local(_)))
+                        && method_args.iter().all(|arg| matches!(arg.basic_res(), Res::Local(_)))
                     {
                         return;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
index 606e852..bf304eb 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::path_def_id;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::ty::peel_and_count_ty_refs;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -57,8 +57,7 @@
 impl LateLintPass<'_> for SizeOfRef {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
         if let ExprKind::Call(path, [arg]) = expr.kind
-            && let Some(def_id) = path_def_id(cx, path)
-            && cx.tcx.is_diagnostic_item(sym::mem_size_of_val, def_id)
+            && path.basic_res().is_diag_item(cx, sym::mem_size_of_val)
             && let arg_ty = cx.typeck_results().expr_ty(arg)
             && peel_and_count_ty_refs(arg_ty).1 > 1
         {
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 f497d07..b25fa09 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -1,10 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::matching_root_macro_call;
+use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{
-    SpanlessEq, get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id,
-    span_contains_comment, sym,
-};
+use clippy_utils::{SpanlessEq, get_enclosing_block, is_integer_literal, span_contains_comment, sym};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt};
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind};
@@ -102,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)`
         if let ExprKind::Assign(left, right, _) = expr.kind
-            && let Some(local_id) = path_to_local(left)
+            && let Some(local_id) = left.res_local_id()
             && let Some(size_expr) = Self::as_vec_initializer(cx, right)
         {
             let vi = VecAllocation {
@@ -149,10 +147,10 @@ fn as_vec_initializer<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Opt
         }
 
         if let ExprKind::Call(func, [len_expr]) = expr.kind
-            && is_path_diagnostic_item(cx, func, sym::vec_with_capacity)
+            && func.ty_rel_def(cx).is_diag_item(cx, sym::vec_with_capacity)
         {
             Some(InitializedSize::Initialized(len_expr))
-        } else if matches!(expr.kind, ExprKind::Call(func, []) if is_path_diagnostic_item(cx, func, sym::vec_new)) {
+        } else if matches!(expr.kind, ExprKind::Call(func, []) if func.ty_rel_def(cx).is_diag_item(cx, sym::vec_new)) {
             Some(InitializedSize::Uninitialized)
         } else {
             None
@@ -246,7 +244,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
     fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
         if self.initialization_found
             && let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind
-            && path_to_local_id(self_arg, self.vec_alloc.local_id)
+            && self_arg.res_local_id() == Some(self.vec_alloc.local_id)
             && path.ident.name == sym::extend
             && self.is_repeat_take(extend_arg)
         {
@@ -258,7 +256,7 @@ fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
     fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'tcx>) {
         if self.initialization_found
             && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
-            && path_to_local_id(self_arg, self.vec_alloc.local_id)
+            && self_arg.res_local_id() == Some(self.vec_alloc.local_id)
             && path.ident.name == sym::resize
             // Check that is filled with 0
             && is_integer_literal(fill_arg, 0)
@@ -301,7 +299,7 @@ fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool {
     /// Returns `true` if given expression is `repeat(0)`
     fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool {
         if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind
-            && is_path_diagnostic_item(self.cx, fn_expr, sym::iter_repeat)
+            && fn_expr.basic_res().is_diag_item(self.cx, sym::iter_repeat)
             && is_integer_literal(repeat_arg, 0)
         {
             true
diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs
index f63e6b3..e5347bf 100644
--- a/src/tools/clippy/clippy_lints/src/string_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs
@@ -5,9 +5,10 @@
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::{snippet, str_literal_to_char_literal};
+use clippy_utils::sym;
 use clippy_utils::visitors::{Descend, for_each_expr};
-use clippy_utils::{path_to_local_id, sym};
 use itertools::Itertools;
 use rustc_ast::{BinOpKind, LitKind};
 use rustc_errors::Applicability;
@@ -146,12 +147,12 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<
         if for_each_expr(cx, body.value, |sub_expr| -> ControlFlow<(), Descend> {
             match sub_expr.kind {
                 ExprKind::Binary(op, left, right) if op.node == BinOpKind::Eq => {
-                    if path_to_local_id(left, binding)
+                    if left.res_local_id() == Some(binding)
                         && let Some(span) = get_char_span(cx, right)
                     {
                         set_char_spans.push(span);
                         ControlFlow::Continue(Descend::No)
-                    } else if path_to_local_id(right, binding)
+                    } else if right.res_local_id() == Some(binding)
                         && let Some(span) = get_char_span(cx, left)
                     {
                         set_char_spans.push(span);
@@ -164,7 +165,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<
                 ExprKind::Match(match_value, [arm, _], _) => {
                     if matching_root_macro_call(cx, sub_expr.span, sym::matches_macro).is_none()
                         || arm.guard.is_some()
-                        || !path_to_local_id(match_value, binding)
+                        || match_value.res_local_id() != Some(binding)
                     {
                         return ControlFlow::Break(());
                     }
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 57d5900..4730694 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -1,9 +1,8 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::{snippet, snippet_with_applicability};
-use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::{
-    SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, path_def_id,
-    peel_blocks, sym,
+    SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, peel_blocks, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
@@ -188,7 +187,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             },
             ExprKind::Index(target, _idx, _) => {
                 let e_ty = cx.typeck_results().expr_ty_adjusted(target).peel_refs();
-                if e_ty.is_str() || is_type_lang_item(cx, e_ty, LangItem::String) {
+                if e_ty.is_str() || e_ty.is_lang_item(cx, LangItem::String) {
                     span_lint(
                         cx,
                         STRING_SLICE,
@@ -203,7 +202,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 }
 
 fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String)
+    cx.typeck_results()
+        .expr_ty(e)
+        .peel_refs()
+        .is_lang_item(cx, LangItem::String)
 }
 
 fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
@@ -253,7 +255,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if let ExprKind::Call(fun, [bytes_arg]) = e.kind
             // Find `std::str::converts::from_utf8` or `std::primitive::str::from_utf8`
             && let Some(sym::str_from_utf8 | sym::str_inherent_from_utf8) =
-                path_def_id(cx, fun).and_then(|id| cx.tcx.get_diagnostic_name(id))
+                fun.res(cx).opt_diag_name(cx)
 
             // Find string::as_bytes
             && let ExprKind::AddrOf(BorrowKind::Ref, _, args) = bytes_arg.kind
diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
index 33856c7..58d692d 100644
--- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::is_expr_unsafe;
 use clippy_utils::{match_libc_symbol, sym};
 use rustc_errors::Applicability;
@@ -61,9 +61,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
             let mut app = Applicability::MachineApplicable;
             let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
-            let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) {
+            let method_name = if ty.is_diag_item(cx, sym::cstring_type) {
                 "as_bytes"
-            } else if is_type_lang_item(cx, ty, LangItem::CStr) {
+            } else if ty.is_lang_item(cx, LangItem::CStr) {
                 "to_bytes"
             } else {
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 76ab3cd..c3cb2c0 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -1,9 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::{snippet_indent, snippet_with_context};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
 
-use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, path_to_local, std_or_core};
+use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, std_or_core};
 use itertools::Itertools;
 
 use rustc_data_structures::fx::FxIndexSet;
@@ -85,7 +85,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
     }
 }
 
-#[allow(clippy::too_many_arguments)]
+#[expect(clippy::too_many_arguments)]
 fn generate_swap_warning<'tcx>(
     block: &'tcx Block<'tcx>,
     cx: &LateContext<'tcx>,
@@ -110,8 +110,8 @@ fn generate_swap_warning<'tcx>(
 
             if matches!(ty.kind(), ty::Slice(_))
                 || matches!(ty.kind(), ty::Array(_, _))
-                || is_type_diagnostic_item(cx, ty, sym::Vec)
-                || is_type_diagnostic_item(cx, ty, sym::VecDeque)
+                || ty.is_diag_item(cx, sym::Vec)
+                || ty.is_diag_item(cx, sym::VecDeque)
             {
                 let slice = Sugg::hir_with_applicability(cx, lhs1, "<slice>", &mut applicability);
 
@@ -361,7 +361,8 @@ fn snippet_index_binding(&mut self, expr: &'tcx Expr<'tcx>) -> String {
                 // - Variable declaration is outside the suggestion span
                 // - Variable is not used as an index or elsewhere later
                 if !self.suggest_span.contains(init.span)
-                    || path_to_local(expr)
+                    || expr
+                        .res_local_id()
                         .is_some_and(|hir_id| !self.suggest_span.contains(self.cx.tcx.hir_span(hir_id)))
                     || !self.is_used_other_than_swapping(first_segment.ident)
                 {
diff --git a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
index ff19635..339c97d 100644
--- a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::path_def_id;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp};
@@ -41,8 +41,7 @@
 impl LateLintPass<'_> for SwapPtrToRef {
     fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
         if let ExprKind::Call(fn_expr, [arg1, arg2]) = e.kind
-            && let Some(fn_id) = path_def_id(cx, fn_expr)
-            && cx.tcx.is_diagnostic_item(sym::mem_swap, fn_id)
+            && fn_expr.basic_res().is_diag_item(cx, sym::mem_swap)
             && let ctxt = e.span.ctxt()
             && let (from_ptr1, arg1_span) = is_ptr_to_ref(cx, arg1, ctxt)
             && let (from_ptr2, arg2_span) = is_ptr_to_ref(cx, arg2, ctxt)
diff --git a/src/tools/clippy/clippy_lints/src/time_subtraction.rs b/src/tools/clippy/clippy_lints/src/time_subtraction.rs
index fde8c3d..dbd4ec7 100644
--- a/src/tools/clippy/clippy_lints/src/time_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/time_subtraction.rs
@@ -1,8 +1,8 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_path_diagnostic_item, ty};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -96,16 +96,16 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
             let lhs_ty = typeck.expr_ty(lhs);
             let rhs_ty = typeck.expr_ty(rhs);
 
-            if ty::is_type_diagnostic_item(cx, lhs_ty, sym::Instant) {
+            if lhs_ty.is_diag_item(cx, sym::Instant) {
                 // Instant::now() - instant
                 if is_instant_now_call(cx, lhs)
-                    && ty::is_type_diagnostic_item(cx, rhs_ty, sym::Instant)
+                    && rhs_ty.is_diag_item(cx, sym::Instant)
                     && let Some(sugg) = Sugg::hir_opt(cx, rhs)
                 {
                     print_manual_instant_elapsed_sugg(cx, expr, sugg);
                 }
                 // instant - duration
-                else if ty::is_type_diagnostic_item(cx, rhs_ty, sym::Duration)
+                else if rhs_ty.is_diag_item(cx, sym::Duration)
                     && !expr.span.from_expansion()
                     && self.msrv.meets(cx, msrvs::TRY_FROM)
                 {
@@ -122,8 +122,8 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
                         print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr);
                     }
                 }
-            } else if ty::is_type_diagnostic_item(cx, lhs_ty, sym::Duration)
-                && ty::is_type_diagnostic_item(cx, rhs_ty, sym::Duration)
+            } else if lhs_ty.is_diag_item(cx, sym::Duration)
+                && rhs_ty.is_diag_item(cx, sym::Duration)
                 && !expr.span.from_expansion()
                 && self.msrv.meets(cx, msrvs::TRY_FROM)
             {
@@ -146,7 +146,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
 
 fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
     if let ExprKind::Call(fn_expr, []) = expr_block.kind
-        && is_path_diagnostic_item(cx, fn_expr, sym::instant_now)
+        && cx.ty_based_def(fn_expr).is_diag_item(cx, sym::instant_now)
     {
         true
     } else {
@@ -170,7 +170,7 @@ fn is_chained_time_subtraction(cx: &LateContext<'_>, lhs: &Expr<'_>) -> bool {
 
 /// Returns true if the type is Duration or Instant
 fn is_time_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    ty::is_type_diagnostic_item(cx, ty, sym::Duration) || ty::is_type_diagnostic_item(cx, ty, sym::Instant)
+    ty.is_diag_item(cx, sym::Duration) || ty.is_diag_item(cx, sym::Instant)
 }
 
 fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) {
@@ -194,7 +194,7 @@ fn print_unchecked_duration_subtraction_sugg(
     let typeck = cx.typeck_results();
     let left_ty = typeck.expr_ty(left_expr);
 
-    let lint_msg = if ty::is_type_diagnostic_item(cx, left_ty, sym::Instant) {
+    let lint_msg = if left_ty.is_diag_item(cx, sym::Instant) {
         "unchecked subtraction of a 'Duration' from an 'Instant'"
     } else {
         "unchecked subtraction between 'Duration' values"
diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
index 3e84754..71c4172 100644
--- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
@@ -1,8 +1,9 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_in_const_context, is_path_diagnostic_item, sym};
+use clippy_utils::{is_in_const_context, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -62,7 +63,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                     }
                 },
                 hir::ExprKind::Call(to_digits_call, [char_arg, radix_arg]) => {
-                    if is_path_diagnostic_item(cx, to_digits_call, sym::char_to_digit) {
+                    if to_digits_call.res(cx).is_diag_item(cx, sym::char_to_digit) {
                         Some((false, char_arg, radix_arg))
                     } else {
                         None
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 9182a55..352b852 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -238,7 +238,7 @@ fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<
         }
     }
 
-    #[allow(clippy::mutable_key_type)]
+    #[expect(clippy::mutable_key_type)]
     fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) {
         struct SpanlessTy<'cx, 'tcx> {
             ty: &'tcx Ty<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
index 7acf3be..e109b1c 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs
@@ -1,6 +1,7 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use clippy_utils::is_integer_literal;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
@@ -40,7 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
         },
         // Catching:
         // `std::mem::transmute(std::ptr::null::<i32>())`
-        ExprKind::Call(func1, []) if is_path_diagnostic_item(cx, func1, sym::ptr_null) => {
+        ExprKind::Call(func1, []) if func1.basic_res().is_diag_item(cx, sym::ptr_null) => {
             lint_expr(cx, expr);
             true
         },
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
index 544014b..1a6262f 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
@@ -1,6 +1,7 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
+use clippy_utils::is_integer_literal;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
@@ -35,7 +36,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
     // Catching:
     // `std::mem::transmute(std::ptr::null::<i32>())`
     if let ExprKind::Call(func1, []) = arg.kind
-        && is_path_diagnostic_item(cx, func1, sym::ptr_null)
+        && func1.basic_res().is_diag_item(cx, sym::ptr_null)
     {
         span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
         return true;
diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
index 3c21d19..5d0945b 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -1,8 +1,9 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::visitors::for_each_local_use_after_expr;
-use clippy_utils::{is_from_proc_macro, path_to_local};
 use itertools::Itertools;
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind, Node, PatKind};
@@ -152,7 +153,7 @@ fn all_bindings_are_for_conv<'tcx>(
     locals: &[&Expr<'_>],
     kind: ToType,
 ) -> bool {
-    let Some(locals) = locals.iter().map(|e| path_to_local(e)).collect::<Option<Vec<_>>>() else {
+    let Some(locals) = locals.iter().map(|e| e.res_local_id()).collect::<Option<Vec<_>>>() else {
         return false;
     };
     let local_parents = locals.iter().map(|l| cx.tcx.parent_hir_node(*l)).collect::<Vec<_>>();
diff --git a/src/tools/clippy/clippy_lints/src/types/box_collection.rs b/src/tools/clippy/clippy_lints/src/types/box_collection.rs
index 24fe4e0..985057c 100644
--- a/src/tools/clippy/clippy_lints/src/types/box_collection.rs
+++ b/src/tools/clippy/clippy_lints/src/types/box_collection.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{path_def_id, qpath_generic_tys};
+use clippy_utils::qpath_generic_tys;
+use clippy_utils::res::MaybeResPath;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, QPath};
 use rustc_lint::LateContext;
@@ -33,7 +34,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
 
 fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Symbol> {
     let param = qpath_generic_tys(qpath).next()?;
-    let id = path_def_id(cx, param)?;
+    let id = param.basic_res().opt_def_id()?;
     cx.tcx
         .get_diagnostic_name(id)
         .filter(|&name| {
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 515be5a..ccb027f 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -693,7 +693,7 @@ fn is_type_change_allowed(&self, context: CheckTyContext) -> bool {
     }
 }
 
-#[allow(clippy::struct_excessive_bools, clippy::struct_field_names)]
+#[expect(clippy::struct_excessive_bools)]
 #[derive(Clone, Copy, Default)]
 struct CheckTyContext {
     is_in_trait_impl: bool,
diff --git a/src/tools/clippy/clippy_lints/src/types/option_option.rs b/src/tools/clippy/clippy_lints/src/types/option_option.rs
index d12d14f..10df007 100644
--- a/src/tools/clippy/clippy_lints/src/types/option_option.rs
+++ b/src/tools/clippy/clippy_lints/src/types/option_option.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{path_def_id, qpath_generic_tys};
+use clippy_utils::qpath_generic_tys;
+use clippy_utils::res::MaybeResPath;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, QPath};
 use rustc_lint::LateContext;
@@ -10,7 +11,7 @@
 pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
     if cx.tcx.is_diagnostic_item(sym::Option, def_id)
         && let Some(arg) = qpath_generic_tys(qpath).next()
-        && path_def_id(cx, arg) == Some(def_id)
+        && arg.basic_res().opt_def_id() == Some(def_id)
     {
         span_lint(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/types/owned_cow.rs b/src/tools/clippy/clippy_lints/src/types/owned_cow.rs
index 8933994..0eef373 100644
--- a/src/tools/clippy/clippy_lints/src/types/owned_cow.rs
+++ b/src/tools/clippy/clippy_lints/src/types/owned_cow.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::snippet_opt;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
@@ -30,10 +31,10 @@ pub(super) fn check(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, def_id: DefId)
 }
 
 fn replacement(cx: &LateContext<'_>, cty: &hir::Ty<'_>) -> Option<(Span, String)> {
-    if clippy_utils::is_path_lang_item(cx, cty, hir::LangItem::String) {
+    if cty.basic_res().is_lang_item(cx, hir::LangItem::String) {
         return Some((cty.span, "str".into()));
     }
-    if clippy_utils::is_path_diagnostic_item(cx, cty, sym::Vec) {
+    if cty.basic_res().is_diag_item(cx, sym::Vec) {
         return if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = cty.kind
             && let [.., last_seg] = path.segments
             && let Some(args) = last_seg.args
@@ -45,7 +46,7 @@ fn replacement(cx: &LateContext<'_>, cty: &hir::Ty<'_>) -> Option<(Span, String)
             None
         };
     }
-    if clippy_utils::is_path_diagnostic_item(cx, cty, sym::cstring_type) {
+    if cty.basic_res().is_diag_item(cx, sym::cstring_type) {
         return Some((
             cty.span,
             (if clippy_utils::is_no_std_crate(cx) {
@@ -58,7 +59,7 @@ fn replacement(cx: &LateContext<'_>, cty: &hir::Ty<'_>) -> Option<(Span, String)
     }
     // Neither OsString nor PathBuf are available outside std
     for (diag, repl) in [(sym::OsString, "std::ffi::OsStr"), (sym::PathBuf, "std::path::Path")] {
-        if clippy_utils::is_path_diagnostic_item(cx, cty, diag) {
+        if cty.basic_res().is_diag_item(cx, diag) {
             return Some((cty.span, repl.into()));
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
index c4fd0fb..46d9feb 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::qpath_generic_tys;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{path_def_id, qpath_generic_tys};
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, QPath, TyKind};
@@ -28,8 +29,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
             let Some(ty) = qpath_generic_tys(qpath).next() else {
                 return false;
             };
-            let Some(id) = path_def_id(cx, ty) else { return false };
-            if !cx.tcx.is_diagnostic_item(sym::Vec, id) {
+            if !ty.basic_res().is_diag_item(cx, sym::Vec) {
                 return false;
             }
             let TyKind::Path(qpath) = &ty.kind else { return false };
@@ -70,8 +70,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                 },
             );
         } else if let Some(ty) = qpath_generic_tys(qpath).next() {
-            let Some(id) = path_def_id(cx, ty) else { return false };
-            if !cx.tcx.is_diagnostic_item(sym::Vec, id) {
+            if !ty.basic_res().is_diag_item(cx, sym::Vec) {
                 return false;
             }
             let TyKind::Path(qpath) = &ty.kind else { return false };
@@ -106,7 +105,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
 
 fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
     let ty = qpath_generic_tys(qpath).next()?;
-    let id = path_def_id(cx, ty)?;
+    let id = ty.basic_res().opt_def_id()?;
     let path = match cx.tcx.get_diagnostic_name(id) {
         Some(sym::OsString) => "std::ffi::OsStr",
         Some(sym::PathBuf) => "std::path::Path",
diff --git a/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs b/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
index 7b13deb..e3d5368 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{path_def_id, qpath_generic_tys};
+use clippy_utils::qpath_generic_tys;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, QPath};
 use rustc_lint::LateContext;
@@ -10,8 +11,7 @@
 pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
     if cx.tcx.is_diagnostic_item(sym::Rc, def_id)
         && let Some(arg) = qpath_generic_tys(qpath).next()
-        && let Some(id) = path_def_id(cx, arg)
-        && cx.tcx.is_diagnostic_item(sym::Mutex, id)
+        && arg.basic_res().is_diag_item(cx, sym::Mutex)
     {
         #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
         span_lint_and_then(cx, RC_MUTEX, hir_ty.span, "usage of `Rc<Mutex<_>>`", |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index 0ba51da..dbae2cc 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::qpath_generic_tys;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::{snippet, snippet_with_applicability};
-use clippy_utils::{path_def_id, qpath_generic_tys};
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, QPath, TyKind};
@@ -40,7 +41,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath:
     let Some(ty) = qpath_generic_tys(qpath).next() else {
         return false;
     };
-    let Some(id) = path_def_id(cx, ty) else { return false };
+    let Some(id) = ty.basic_res().opt_def_id() else {
+        return false;
+    };
     let (inner_sym, ty) = match cx.tcx.get_diagnostic_name(id) {
         Some(sym::Arc) => ("Arc", ty),
         Some(sym::Rc) => ("Rc", ty),
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index e843e16..e666318 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{expr_or_init, fn_def_id_with_node_args, path_def_id};
+use clippy_utils::res::MaybeQPath;
+use clippy_utils::{expr_or_init, fn_def_id_with_node_args};
 use rustc_ast::BinOpKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
@@ -317,7 +318,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow<()> {
         if let ExprKind::Call(f, _) = expr.kind
             && let ExprKind::Path(qpath) = f.kind
             && is_default_method_on_current_ty(self.cx.tcx, qpath, self.implemented_ty_id)
-            && let Some(method_def_id) = path_def_id(self.cx, f)
+            && let Some(method_def_id) = f.res(self.cx).opt_def_id()
             && let Some(trait_def_id) = self.cx.tcx.trait_of_assoc(method_def_id)
             && self.cx.tcx.is_diagnostic_item(sym::Default, trait_def_id)
         {
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 751e9b0..9afa9d6 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -7,8 +7,8 @@
 use clippy_utils::source::walk_span_to_context;
 use clippy_utils::visitors::{Descend, for_each_expr};
 use hir::HirId;
-use rustc_hir as hir;
-use rustc_hir::{Block, BlockCheckMode, Impl, ItemKind, Node, UnsafeSource};
+use rustc_errors::Applicability;
+use rustc_hir::{self as hir, Block, BlockCheckMode, FnSig, Impl, ItemKind, Node, UnsafeSource};
 use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
@@ -113,7 +113,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
             && !block.span.in_external_macro(cx.tcx.sess.source_map())
             && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
             && !is_unsafe_from_proc_macro(cx, block.span)
-            && !block_has_safety_comment(cx, block.span)
+            && !block_has_safety_comment(cx, block.span, self.accept_comment_above_attributes)
             && !block_parents_have_safety_comment(
                 self.accept_comment_above_statement,
                 self.accept_comment_above_attributes,
@@ -143,7 +143,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
         if let Some(tail) = block.expr
             && !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, tail.hir_id)
             && !tail.span.in_external_macro(cx.tcx.sess.source_map())
-            && let HasSafetyComment::Yes(pos) =
+            && let HasSafetyComment::Yes(pos, _) =
                 stmt_has_safety_comment(cx, tail.span, tail.hir_id, self.accept_comment_above_attributes)
             && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, tail, pos)
         {
@@ -168,7 +168,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &hir::Stmt<'tcx>) {
         };
         if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, stmt.hir_id)
             && !stmt.span.in_external_macro(cx.tcx.sess.source_map())
-            && let HasSafetyComment::Yes(pos) =
+            && let HasSafetyComment::Yes(pos, _) =
                 stmt_has_safety_comment(cx, stmt.span, stmt.hir_id, self.accept_comment_above_attributes)
             && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, expr, pos)
         {
@@ -191,8 +191,12 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
 
         let mk_spans = |pos: BytePos| {
             let source_map = cx.tcx.sess.source_map();
-            let span = Span::new(pos, pos, SyntaxContext::root(), None);
-            let help_span = source_map.span_extend_to_next_char(span, '\n', true);
+            let help_span = Span::new(
+                pos,
+                pos + BytePos(u32::try_from("SAFETY:".len()).unwrap()),
+                SyntaxContext::root(),
+                None,
+            );
             let span = if source_map.is_multiline(item.span) {
                 source_map.span_until_char(item.span, '\n')
             } else {
@@ -201,16 +205,16 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
             (span, help_span)
         };
 
-        let item_has_safety_comment = item_has_safety_comment(cx, item);
+        let item_has_safety_comment = item_has_safety_comment(cx, item, self.accept_comment_above_attributes);
         match item_has_safety_comment {
-            HasSafetyComment::Yes(pos) => check_has_safety_comment(cx, item, mk_spans(pos)),
+            HasSafetyComment::Yes(pos, is_doc) => check_has_safety_comment(cx, item, mk_spans(pos), is_doc),
             HasSafetyComment::No => check_has_no_safety_comment(cx, item),
             HasSafetyComment::Maybe => {},
         }
     }
 }
 
-fn check_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>, (span, help_span): (Span, Span)) {
+fn check_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>, (span, help_span): (Span, Span), is_doc: bool) {
     match &item.kind {
         ItemKind::Impl(Impl {
             of_trait: Some(of_trait),
@@ -252,6 +256,40 @@ fn check_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>, (span, h
                 }
             }
         },
+        // Unsafe functions with a SAFETY comment are suggested to change it to a `# Safety` comment
+        ItemKind::Fn {
+            sig: FnSig { header, .. },
+            ..
+        } if header.is_unsafe() => {
+            if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
+                span_lint_and_then(
+                    cx,
+                    UNNECESSARY_SAFETY_COMMENT,
+                    span,
+                    format!(
+                        "{} has unnecessary safety comment",
+                        cx.tcx.def_descr(item.owner_id.to_def_id()),
+                    ),
+                    |diag| {
+                        if is_doc {
+                            // If it's already within a doc comment, we try to suggest the change
+
+                            diag.span_suggestion(
+                                help_span,
+                                "consider changing it to a `# Safety` section",
+                                "# Safety",
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            diag.span_help(
+                                help_span,
+                                "consider changing the `safety` comment for a `# Safety` doc comment",
+                            );
+                        }
+                    },
+                );
+            }
+        },
         // Aside from unsafe impls and consts/statics with an unsafe block, items in general
         // do not have safety invariants that need to be documented, so lint those.
         _ => {
@@ -272,6 +310,7 @@ fn check_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>, (span, h
         },
     }
 }
+
 fn check_has_no_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) {
     if let ItemKind::Impl(Impl {
         of_trait: Some(of_trait),
@@ -407,21 +446,21 @@ fn block_parents_have_safety_comment(
     cx: &LateContext<'_>,
     id: HirId,
 ) -> bool {
-    let (span, hir_id) = match cx.tcx.parent_hir_node(id) {
-        Node::Expr(expr) if let Some(inner) = find_unsafe_block_parent_in_expr(cx, expr) => inner,
+    let span = match cx.tcx.parent_hir_node(id) {
+        Node::Expr(expr) if let Some((span, _)) = find_unsafe_block_parent_in_expr(cx, expr) => span,
         Node::Stmt(hir::Stmt {
             kind:
-                hir::StmtKind::Let(hir::LetStmt { span, hir_id, .. })
-                | hir::StmtKind::Expr(hir::Expr { span, hir_id, .. })
-                | hir::StmtKind::Semi(hir::Expr { span, hir_id, .. }),
+                hir::StmtKind::Let(hir::LetStmt { span, .. })
+                | hir::StmtKind::Expr(hir::Expr { span, .. })
+                | hir::StmtKind::Semi(hir::Expr { span, .. }),
             ..
         })
-        | Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id),
+        | Node::LetStmt(hir::LetStmt { span, .. }) => *span,
 
-        node if let Some((span, hir_id)) = span_and_hid_of_item_alike_node(&node)
+        node if let Some((span, _)) = span_and_hid_of_item_alike_node(&node)
             && is_const_or_static(&node) =>
         {
-            (span, hir_id)
+            span
         },
 
         _ => return false,
@@ -429,24 +468,7 @@ fn block_parents_have_safety_comment(
     // if unsafe block is part of a let/const/static statement,
     // and accept_comment_above_statement is set to true
     // we accept the safety comment in the line the precedes this statement.
-    accept_comment_above_statement
-        && span_with_attrs_has_safety_comment(cx, span, hir_id, accept_comment_above_attributes)
-}
-
-/// Extends `span` to also include its attributes, then checks if that span has a safety comment.
-fn span_with_attrs_has_safety_comment(
-    cx: &LateContext<'_>,
-    span: Span,
-    hir_id: HirId,
-    accept_comment_above_attributes: bool,
-) -> bool {
-    let span = if accept_comment_above_attributes {
-        include_attrs_in_span(cx, hir_id, span)
-    } else {
-        span
-    };
-
-    span_has_safety_comment(cx, span)
+    accept_comment_above_statement && span_has_safety_comment(cx, span, accept_comment_above_attributes)
 }
 
 /// Checks if an expression is "branchy", e.g. loop, match/if/etc.
@@ -458,7 +480,7 @@ fn is_branchy(expr: &hir::Expr<'_>) -> bool {
 }
 
 /// Checks if the lines immediately preceding the block contain a safety comment.
-fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
+fn block_has_safety_comment(cx: &LateContext<'_>, span: Span, accept_comment_above_attributes: bool) -> bool {
     // This intentionally ignores text before the start of a function so something like:
     // ```
     //     // SAFETY: reason
@@ -468,30 +490,25 @@ fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
     // attributes and doc comments.
 
     matches!(
-        span_from_macro_expansion_has_safety_comment(cx, span),
-        HasSafetyComment::Yes(_)
-    ) || span_has_safety_comment(cx, span)
+        span_from_macro_expansion_has_safety_comment(cx, span, accept_comment_above_attributes),
+        HasSafetyComment::Yes(_, _)
+    ) || span_has_safety_comment(cx, span, accept_comment_above_attributes)
 }
 
-fn include_attrs_in_span(cx: &LateContext<'_>, hir_id: HirId, span: Span) -> Span {
-    span.to(cx.tcx.hir_attrs(hir_id).iter().fold(span, |acc, attr| {
-        if attr.is_doc_comment().is_some() {
-            return acc;
-        }
-        acc.to(attr.span())
-    }))
-}
-
+#[derive(Debug)]
 enum HasSafetyComment {
-    Yes(BytePos),
+    Yes(BytePos, bool),
     No,
     Maybe,
 }
 
 /// Checks if the lines immediately preceding the item contain a safety comment.
-#[allow(clippy::collapsible_match)]
-fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSafetyComment {
-    match span_from_macro_expansion_has_safety_comment(cx, item.span) {
+fn item_has_safety_comment(
+    cx: &LateContext<'_>,
+    item: &hir::Item<'_>,
+    accept_comment_above_attributes: bool,
+) -> HasSafetyComment {
+    match span_from_macro_expansion_has_safety_comment(cx, item.span, accept_comment_above_attributes) {
         HasSafetyComment::Maybe => (),
         has_safety_comment => return has_safety_comment,
     }
@@ -536,29 +553,26 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
         return if comment_start_line.line >= unsafe_line.line {
             HasSafetyComment::No
         } else {
-            match text_has_safety_comment(
+            text_has_safety_comment(
                 src,
                 &unsafe_line.sf.lines()
                     [(comment_start_line.line + usize::from(!include_first_line_of_file))..=unsafe_line.line],
                 unsafe_line.sf.start_pos,
-            ) {
-                Some(b) => HasSafetyComment::Yes(b),
-                None => HasSafetyComment::No,
-            }
+                accept_comment_above_attributes,
+            )
         };
     }
     HasSafetyComment::Maybe
 }
 
 /// Checks if the lines immediately preceding the item contain a safety comment.
-#[allow(clippy::collapsible_match)]
 fn stmt_has_safety_comment(
     cx: &LateContext<'_>,
     span: Span,
     hir_id: HirId,
     accept_comment_above_attributes: bool,
 ) -> HasSafetyComment {
-    match span_from_macro_expansion_has_safety_comment(cx, span) {
+    match span_from_macro_expansion_has_safety_comment(cx, span, accept_comment_above_attributes) {
         HasSafetyComment::Maybe => (),
         has_safety_comment => return has_safety_comment,
     }
@@ -572,13 +586,6 @@ fn stmt_has_safety_comment(
         _ => return HasSafetyComment::Maybe,
     };
 
-    // if span_with_attrs_has_safety_comment(cx, span, hir_id, accept_comment_above_attrib
-    // }
-    let mut span = span;
-    if accept_comment_above_attributes {
-        span = include_attrs_in_span(cx, hir_id, span);
-    }
-
     let source_map = cx.sess().source_map();
     if let Some(comment_start) = comment_start
         && let Ok(unsafe_line) = source_map.lookup_line(span.lo())
@@ -589,14 +596,12 @@ fn stmt_has_safety_comment(
         return if comment_start_line.line >= unsafe_line.line {
             HasSafetyComment::No
         } else {
-            match text_has_safety_comment(
+            text_has_safety_comment(
                 src,
                 &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line],
                 unsafe_line.sf.start_pos,
-            ) {
-                Some(b) => HasSafetyComment::Yes(b),
-                None => HasSafetyComment::No,
-            }
+                accept_comment_above_attributes,
+            )
         };
     }
     HasSafetyComment::Maybe
@@ -649,7 +654,11 @@ fn comment_start_before_item_in_mod(
     })
 }
 
-fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span) -> HasSafetyComment {
+fn span_from_macro_expansion_has_safety_comment(
+    cx: &LateContext<'_>,
+    span: Span,
+    accept_comment_above_attributes: bool,
+) -> HasSafetyComment {
     let source_map = cx.sess().source_map();
     let ctxt = span.ctxt();
     if ctxt == SyntaxContext::root() {
@@ -665,14 +674,12 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span
         && let Some(src) = unsafe_line.sf.src.as_deref()
     {
         if macro_line.line < unsafe_line.line {
-            match text_has_safety_comment(
+            text_has_safety_comment(
                 src,
                 &unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line],
                 unsafe_line.sf.start_pos,
-            ) {
-                Some(b) => HasSafetyComment::Yes(b),
-                None => HasSafetyComment::No,
-            }
+                accept_comment_above_attributes,
+            )
         } else {
             HasSafetyComment::No
         }
@@ -715,7 +722,7 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
     None
 }
 
-fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
+fn span_has_safety_comment(cx: &LateContext<'_>, span: Span, accept_comment_above_attributes: bool) -> bool {
     let source_map = cx.sess().source_map();
     let ctxt = span.ctxt();
     if ctxt.is_root()
@@ -731,12 +738,15 @@ fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
             //     fn foo() { some_stuff; unsafe { stuff }; other_stuff; }
             //              ^-------------^
             body_line.line < unsafe_line.line
-                && text_has_safety_comment(
-                    src,
-                    &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line],
-                    unsafe_line.sf.start_pos,
+                && matches!(
+                    text_has_safety_comment(
+                        src,
+                        &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line],
+                        unsafe_line.sf.start_pos,
+                        accept_comment_above_attributes,
+                    ),
+                    HasSafetyComment::Yes(..)
                 )
-                .is_some()
         } else {
             // Problem getting source text. Pretend a comment was found.
             true
@@ -747,7 +757,15 @@ fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
 }
 
 /// Checks if the given text has a safety comment for the immediately proceeding line.
-fn text_has_safety_comment(src: &str, line_starts: &[RelativeBytePos], start_pos: BytePos) -> Option<BytePos> {
+///
+/// If `accept_comment_above_attributes` is true, it will ignore attributes inbetween blocks of
+/// comments
+fn text_has_safety_comment(
+    src: &str,
+    line_starts: &[RelativeBytePos],
+    start_pos: BytePos,
+    accept_comment_above_attributes: bool,
+) -> HasSafetyComment {
     let mut lines = line_starts
         .array_windows::<2>()
         .rev()
@@ -758,9 +776,12 @@ fn text_has_safety_comment(src: &str, line_starts: &[RelativeBytePos], start_pos
             let trimmed = text.trim_start();
             Some((start + (text.len() - trimmed.len()), trimmed))
         })
-        .filter(|(_, text)| !text.is_empty());
+        .filter(|(_, text)| !(text.is_empty() || (accept_comment_above_attributes && is_attribute(text))));
 
-    let (line_start, line) = lines.next()?;
+    let Some((line_start, line)) = lines.next() else {
+        return HasSafetyComment::No;
+    };
+
     let mut in_codeblock = false;
     // Check for a sequence of line comments.
     if line.starts_with("//") {
@@ -773,12 +794,17 @@ fn text_has_safety_comment(src: &str, line_starts: &[RelativeBytePos], start_pos
                 in_codeblock = !in_codeblock;
             }
 
-            if line.to_ascii_uppercase().contains("SAFETY:") && !in_codeblock {
-                return Some(start_pos + BytePos(u32::try_from(line_start).unwrap()));
+            if !in_codeblock && let Some(safety_pos) = line.to_ascii_uppercase().find("SAFETY:") {
+                return HasSafetyComment::Yes(
+                    start_pos
+                        + BytePos(u32::try_from(line_start).unwrap())
+                        + BytePos(u32::try_from(safety_pos).unwrap()),
+                    line.starts_with("///"),
+                );
             }
             match lines.next() {
                 Some((s, x)) if x.starts_with("//") => (line, line_start) = (x, s),
-                _ => return None,
+                _ => return HasSafetyComment::No,
             }
         }
     }
@@ -789,19 +815,30 @@ fn text_has_safety_comment(src: &str, line_starts: &[RelativeBytePos], start_pos
         if line.starts_with("/*") {
             let src = &src[line_start..line_starts.last().unwrap().to_usize()];
             let mut tokens = tokenize(src, FrontmatterAllowed::No);
-            return (src[..tokens.next().unwrap().len as usize]
-                .to_ascii_uppercase()
-                .contains("SAFETY:")
-                && tokens.all(|t| t.kind == TokenKind::Whitespace))
-            .then_some(start_pos + BytePos(u32::try_from(line_start).unwrap()));
+            let a = tokens.next();
+            if let Some(safety_pos) = src[..a.unwrap().len as usize].to_ascii_uppercase().find("SAFETY:")
+                && tokens.all(|t| t.kind == TokenKind::Whitespace)
+            {
+                return HasSafetyComment::Yes(
+                    start_pos
+                        + BytePos(u32::try_from(line_start).unwrap())
+                        + BytePos(u32::try_from(safety_pos).unwrap()),
+                    line.starts_with("/**"),
+                );
+            }
+            return HasSafetyComment::No;
         }
         match lines.next() {
             Some(x) => (line_start, line) = x,
-            None => return None,
+            None => return HasSafetyComment::No,
         }
     }
 }
 
+fn is_attribute(text: &str) -> bool {
+    (text.starts_with("#[") || text.starts_with("#![")) && text.trim_end().ends_with(']')
+}
+
 fn span_and_hid_of_item_alike_node(node: &Node<'_>) -> Option<(Span, HirId)> {
     match node {
         Node::Item(item) => Some((item.span, item.owner_id.into())),
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 51116b5..df06982 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
-use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
-use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, sym};
+use clippy_utils::res::{MaybeDef, MaybeResPath};
+use clippy_utils::ty::is_uninit_value_valid_for_ty;
+use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, peel_hir_expr_while, sym};
 use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
@@ -139,7 +140,7 @@ enum VecLocation<'tcx> {
 impl<'tcx> VecLocation<'tcx> {
     pub fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
         match self {
-            VecLocation::Local(hir_id) => path_to_local_id(expr, hir_id),
+            VecLocation::Local(hir_id) => expr.res_local_id() == Some(hir_id),
             VecLocation::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr),
         }
     }
@@ -183,7 +184,10 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt
 }
 
 fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool {
-    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec)
+    cx.typeck_results()
+        .expr_ty(self_expr)
+        .peel_refs()
+        .is_diag_item(cx, sym::Vec)
         && path.ident.name == sym::reserve
 }
 
@@ -205,10 +209,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
     match expr.kind {
         ExprKind::MethodCall(path, self_expr, [arg], _) => {
             let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
-            if is_type_diagnostic_item(cx, self_type, sym::Vec)
-                && path.ident.name == sym::set_len
-                && !is_integer_literal(arg, 0)
-            {
+            if self_type.is_diag_item(cx, sym::Vec) && path.ident.name == sym::set_len && !is_integer_literal(arg, 0) {
                 Some((self_expr, expr.span))
             } else {
                 None
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs b/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs
index 9f107fb..2603884 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::path_res;
+use clippy_utils::res::MaybeResPath;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -138,7 +138,7 @@ fn check_fn(
             return;
         };
 
-        if path_res(cx, inner_hir_ty) != Res::PrimTy(PrimTy::Str) {
+        if !matches!(inner_hir_ty.basic_res(), Res::PrimTy(PrimTy::Str)) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
index d3700d0..94b1a34 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::get_type_diagnostic_name;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -39,7 +39,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
             return;
         }
         if let hir::ExprKind::MethodCall(path, recv, [map_arg], ..) = expr.kind
-            && let Some(sym::Option | sym::Result) = get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(recv))
+            && let Some(sym::Option | sym::Result) = cx.typeck_results().expr_ty(recv).opt_diag_name(cx)
         {
             let (constructor_path, constructor_item) = if let hir::ExprKind::Call(constructor, [arg, ..]) = recv.kind
                 && let hir::ExprKind::Path(constructor_path) = constructor.kind
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
index 28f4884..0388450 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::res::MaybeDef;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
@@ -58,7 +58,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                 && let LitKind::Str(symbol, _) = spanned.node
                 && symbol.is_empty()
                 && let inner_expr_type = cx.typeck_results().expr_ty(inner_expr)
-                && is_type_lang_item(cx, inner_expr_type, LangItem::String)
+                && inner_expr_type.is_lang_item(cx, LangItem::String)
             {
                 span_lint_and_sugg(
                     cx,
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs
index 5792b6b..5159685 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_copy;
-use clippy_utils::{get_parent_expr, is_mutable, path_to_local};
+use clippy_utils::{get_parent_expr, is_mutable};
 use rustc_hir::{Expr, ExprField, ExprKind, Path, QPath, StructTailExpr, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -162,7 +163,7 @@ fn check_references(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>)
         && let parent_ty = cx.typeck_results().expr_ty_adjusted(parent)
         && parent_ty.is_any_ptr()
     {
-        if is_copy(cx, cx.typeck_results().expr_ty(expr_a)) && path_to_local(expr_b).is_some() {
+        if is_copy(cx, cx.typeck_results().expr_ty(expr_a)) && expr_b.res_local_id().is_some() {
             // When the type implements `Copy`, a reference to the new struct works on the
             // copy. Using the original would borrow it.
             return false;
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index 849c0b4..29747cf 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -2,9 +2,10 @@
 
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::res::{MaybeDef, MaybeQPath};
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::find_all_ret_expressions;
-use clippy_utils::{contains_return, is_res_lang_ctor, path_res, return_ty};
+use clippy_utils::{contains_return, return_ty};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionSome, ResultOk};
 use rustc_hir::intravisit::FnKind;
@@ -122,7 +123,7 @@ fn check_fn(
             if !ret_expr.span.from_expansion()
                 // Check if a function call.
                 && let ExprKind::Call(func, [arg]) = ret_expr.kind
-                && is_res_lang_ctor(cx, path_res(cx, func), lang_item)
+                && func.res(cx).ctor_parent(cx).is_lang_item(cx, lang_item)
                 // Make sure the function argument does not contain a return expression.
                 && !contains_return(arg)
             {
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index af3ad45..2884bbd 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
-use clippy_utils::{is_res_lang_ctor, paths, peel_blocks, sym};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::{paths, peel_blocks, sym};
 use hir::{ExprKind, HirId, PatKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -84,9 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
     /// get desugared to match.
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'tcx>) {
         let fn_def_id = block.hir_id.owner.to_def_id();
-        if let Some(impl_id) = cx.tcx.impl_of_assoc(fn_def_id)
-            && let Some(trait_id) = cx.tcx.trait_id_of_impl(impl_id)
-        {
+        if let Some(impl_id) = cx.tcx.trait_impl_of_assoc(fn_def_id) {
+            let trait_id = cx.tcx.impl_trait_id(impl_id);
             // We don't want to lint inside io::Read or io::Write implementations, as the author has more
             // information about their trait implementation than our lint, see https://github.com/rust-lang/rust-clippy/issues/4836
             if let Some(trait_name) = cx.tcx.get_diagnostic_name(trait_id)
@@ -136,7 +136,10 @@ fn non_consuming_err_arm<'a>(cx: &LateContext<'a>, arm: &hir::Arm<'a>) -> bool {
     }
 
     if let PatKind::TupleStruct(ref path, [inner_pat], _) = arm.pat.kind {
-        return is_res_lang_ctor(cx, cx.qpath_res(path, inner_pat.hir_id), hir::LangItem::ResultErr);
+        return cx
+            .qpath_res(path, inner_pat.hir_id)
+            .ctor_parent(cx)
+            .is_lang_item(cx, hir::LangItem::ResultErr);
     }
 
     false
@@ -203,7 +206,7 @@ fn is_ok_wild_or_dotdot_pattern<'a>(cx: &LateContext<'a>, pat: &hir::Pat<'a>) ->
 
     if let PatKind::TupleStruct(ref path, inner_pat, _) = pat.kind
         // we check against Result::Ok to avoid linting on Err(_) or something else.
-        && is_res_lang_ctor(cx, cx.qpath_res(path, pat.hir_id), hir::LangItem::ResultOk)
+        && cx.qpath_res(path, pat.hir_id).ctor_parent(cx).is_lang_item(cx, hir::LangItem::ResultOk)
     {
         if matches!(inner_pat, []) {
             return true;
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index 5224b62..668663e 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs};
-use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators, sym};
+use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
+use clippy_utils::ty::peel_and_count_ty_refs;
+use clippy_utils::{fn_def_id, peel_ref_operators, sym};
 use rustc_ast::Mutability;
 use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind};
@@ -49,7 +50,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
         // Don't lint `Peekable`s returned from a block
         if let Some(expr) = block.expr
             && let Some(ty) = cx.typeck_results().expr_ty_opt(peel_ref_operators(cx, expr))
-            && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
+            && ty.is_diag_item(cx, sym::IterPeekable)
         {
             return;
         }
@@ -62,7 +63,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
                 && !init.span.from_expansion()
                 && let Some(ty) = cx.typeck_results().expr_ty_opt(init)
                 && let (ty, _, None | Some(Mutability::Mut)) = peel_and_count_ty_refs(ty)
-                && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
+                && ty.is_diag_item(cx, sym::IterPeekable)
             {
                 let mut vis = PeekableVisitor::new(cx, binding);
 
@@ -116,7 +117,7 @@ fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
     }
 
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow<()> {
-        if path_to_local_id(ex, self.expected_hir_id) {
+        if ex.res_local_id() == Some(self.expected_hir_id) {
             for (_, node) in self.cx.tcx.hir_parent_iter(ex.hir_id) {
                 match node {
                     Node::Expr(expr) => {
@@ -160,7 +161,11 @@ fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow<()> {
 
                                 // foo.some_method() excluding Iterator methods
                                 if remaining_args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg))
-                                    && !is_trait_method(self.cx, expr, sym::Iterator)
+                                    && !self
+                                        .cx
+                                        .ty_based_def(expr)
+                                        .opt_parent(self.cx)
+                                        .is_diag_item(self.cx, sym::Iterator)
                                 {
                                     return ControlFlow::Break(());
                                 }
@@ -212,7 +217,7 @@ fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow<()> {
 fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
     if let Some(ty) = cx.typeck_results().expr_ty_opt(arg)
         && let (ty, _, None | Some(Mutability::Mut)) = peel_and_count_ty_refs(ty)
-        && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
+        && ty.is_diag_item(cx, sym::IterPeekable)
     {
         true
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
index f5ed10f..fe323a0 100644
--- a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::res::MaybeDef;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::sym;
-use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -37,7 +37,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
         if let StmtKind::Semi(expr) = stmt.kind
             && let ExprKind::MethodCall(ok_path, recv, [], ..) = expr.kind //check is expr.ok() has type Result<T,E>.ok(, _)
             && ok_path.ident.name == sym::ok
-            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
+            && cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result)
             && !stmt.span.in_external_macro(cx.sess().source_map())
         {
             let ctxt = expr.span.ctxt();
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index aee8028..99201a1 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -1,9 +1,9 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::msrvs::Msrv;
-use clippy_utils::ty::get_type_diagnostic_name;
+use clippy_utils::res::{MaybeDef, MaybeResPath};
 use clippy_utils::usage::is_potentially_local_place;
-use clippy_utils::{can_use_if_let_chains, higher, path_to_local, sym};
+use clippy_utils::{can_use_if_let_chains, higher, sym};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
 use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, UnOp};
@@ -147,7 +147,7 @@ fn collect_unwrap_info<'tcx>(
     is_entire_condition: bool,
 ) -> Vec<UnwrapInfo<'tcx>> {
     fn option_or_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<(UnwrappableKind, bool)> {
-        match (get_type_diagnostic_name(cx, ty)?, method_name) {
+        match (ty.opt_diag_name(cx)?, method_name) {
             (sym::Option, sym::is_some) => Some((UnwrappableKind::Option, true)),
             (sym::Option, sym::is_none) => Some((UnwrappableKind::Option, false)),
             (sym::Result, sym::is_ok) => Some((UnwrappableKind::Result, true)),
@@ -169,7 +169,7 @@ fn option_or_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol)
         },
         ExprKind::Unary(UnOp::Not, expr) => collect_unwrap_info(cx, if_expr, expr, branch, !invert, false),
         ExprKind::MethodCall(method_name, receiver, [], _)
-            if let Some(local_id) = path_to_local(receiver)
+            if let Some(local_id) = receiver.res_local_id()
                 && let ty = cx.typeck_results().expr_ty(receiver)
                 && let name = method_name.ident.name
                 && let Some((kind, unwrappable)) = option_or_result_call(cx, ty, name) =>
@@ -318,7 +318,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             // find `unwrap[_err]()` or `expect("...")` calls:
             if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind
                 && let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg)
-                && let Some(id) = path_to_local(self_arg)
+                && let Some(id) = self_arg.res_local_id()
                 && matches!(method_name.ident.name, sym::unwrap | sym::expect | sym::unwrap_err)
                 && let call_to_unwrap = matches!(method_name.ident.name, sym::unwrap | sym::expect)
                 && let Some(unwrappable) = self.unwrappables.iter()
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 9d5be92..eba6050 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -10,7 +10,7 @@
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
 use rustc_hir::{
     self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParamKind, HirId, Impl,
-    ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
+    ImplItemImplKind, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty as MiddleTy;
@@ -58,6 +58,7 @@
 pub struct UseSelf {
     msrv: Msrv,
     stack: Vec<StackItem>,
+    recursive_self_in_type_definitions: bool,
 }
 
 impl UseSelf {
@@ -65,6 +66,7 @@ pub fn new(conf: &'static Conf) -> Self {
         Self {
             msrv: conf.msrv,
             stack: Vec::new(),
+            recursive_self_in_type_definitions: conf.recursive_self_in_type_definitions,
         }
     }
 }
@@ -84,10 +86,10 @@ enum StackItem {
 
 impl<'tcx> LateLintPass<'tcx> for UseSelf {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
-        // We push the self types of `impl`s on a stack here. Only the top type on the stack is
-        // relevant for linting, since this is the self type of the `impl` we're currently in. To
-        // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that
-        // we're in an `impl` or nested item, that we don't want to lint
+        // We push the self types of items on a stack here. Only the top type on the stack is
+        // relevant for linting, since this is the self type of the item we're currently in. To
+        // avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal that
+        // we're in an item or nested item that we don't want to lint
         let stack_item = if let ItemKind::Impl(Impl { self_ty, generics, .. }) = item.kind
             && let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind
             && let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args
@@ -112,6 +114,15 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
                 impl_id: item.owner_id.def_id,
                 types_to_skip,
             }
+        } else if let ItemKind::Struct(..) | ItemKind::Enum(..) = item.kind
+            && self.recursive_self_in_type_definitions
+            && !item.span.from_expansion()
+            && !is_from_proc_macro(cx, item)
+        {
+            StackItem::Check {
+                impl_id: item.owner_id.def_id,
+                types_to_skip: FxHashSet::default(),
+            }
         } else {
             StackItem::NoCheck
         };
@@ -131,13 +142,14 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
         // We want to skip types in trait `impl`s that aren't declared as `Self` in the trait
         // declaration. The collection of those types is all this method implementation does.
         if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind
+            && let ImplItemImplKind::Trait { .. } = impl_item.impl_kind
             && let Some(&mut StackItem::Check {
                 impl_id,
                 ref mut types_to_skip,
                 ..
             }) = self.stack.last_mut()
-            && let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_id)
         {
+            let impl_trait_ref = cx.tcx.impl_trait_ref(impl_id);
             // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
             // `Self`.
             let self_ty = impl_trait_ref.instantiate_identity().self_ty();
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 1b13701..0cf5b94 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath, MaybeTypeckRes};
 use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::sugg::{DiagExt as _, Sugg};
-use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_modulo_regions};
-use clippy_utils::{
-    get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, sym,
-};
+use clippy_utils::ty::{is_copy, same_type_modulo_regions};
+use clippy_utils::{get_parent_expr, is_ty_alias, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Mutability, Node, PatKind};
@@ -133,7 +132,7 @@ fn into_iter_bound<'tcx>(
 /// Extracts the receiver of a `.into_iter()` method call.
 fn into_iter_call<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>) -> Option<&'hir Expr<'hir>> {
     if let ExprKind::MethodCall(name, recv, [], _) = expr.kind
-        && is_trait_method(cx, expr, sym::IntoIterator)
+        && cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::IntoIterator)
         && name.ident.name == sym::into_iter
     {
         Some(recv)
@@ -181,7 +180,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     path.ident.name,
                     sym::map | sym::map_err | sym::map_break | sym::map_continue
                 ) && has_eligible_receiver(cx, recv, e)
-                    && (is_trait_item(cx, arg, sym::Into) || is_trait_item(cx, arg, sym::From))
+                    && matches!(
+                        arg.res(cx).assoc_parent(cx).opt_diag_name(cx),
+                        Some(sym::Into | sym::From)
+                    )
                     && let ty::FnDef(_, args) = cx.typeck_results().expr_ty(arg).kind()
                     && let &[from_ty, to_ty] = args.into_type_list(cx.tcx).as_slice()
                     && same_type_modulo_regions(from_ty, to_ty)
@@ -204,7 +206,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             },
 
             ExprKind::MethodCall(name, recv, [], _) => {
-                if is_trait_method(cx, e, sym::Into) && name.ident.name == sym::into {
+                if cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::Into) && name.ident.name == sym::into {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
                     if same_type_modulo_regions(a, b) {
@@ -308,7 +310,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                         }
                     }
 
-                    if let Some(id) = path_to_local(recv)
+                    if let Some(id) = recv.res_local_id()
                         && let Node::Pat(pat) = cx.tcx.hir_node(id)
                         && let PatKind::Binding(ann, ..) = pat.kind
                         && ann != BindingMode::MUT
@@ -364,11 +366,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                         );
                     }
                 }
-                if is_trait_method(cx, e, sym::TryInto)
+                if cx.ty_based_def(e).opt_parent(cx).is_diag_item(cx, sym::TryInto)
                     && name.ident.name == sym::try_into
                     && let a = cx.typeck_results().expr_ty(e)
                     && let b = cx.typeck_results().expr_ty(recv)
-                    && is_type_diagnostic_item(cx, a, sym::Result)
+                    && a.is_diag_item(cx, sym::Result)
                     && let ty::Adt(_, args) = a.kind()
                     && let Some(a_type) = args.types().next()
                     && same_type_modulo_regions(a_type, b)
@@ -393,7 +395,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(arg);
                     if name == sym::try_from_fn
-                        && is_type_diagnostic_item(cx, a, sym::Result)
+                        && a.is_diag_item(cx, sym::Result)
                         && let ty::Adt(_, args) = a.kind()
                         && let Some(a_type) = args.types().next()
                         && same_type_modulo_regions(a_type, b)
@@ -439,13 +441,13 @@ fn check_expr_post(&mut self, _: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 }
 
 fn has_eligible_receiver(cx: &LateContext<'_>, recv: &Expr<'_>, expr: &Expr<'_>) -> bool {
-    if is_inherent_method_call(cx, expr) {
+    if cx.ty_based_def(expr).opt_parent(cx).is_impl(cx) {
         matches!(
-            get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(recv)),
+            cx.typeck_results().expr_ty(recv).opt_diag_name(cx),
             Some(sym::Option | sym::Result | sym::ControlFlow)
         )
     } else {
-        is_trait_method(cx, expr, sym::Iterator)
+        cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index ece2936..68e51da 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -1,4 +1,5 @@
-use clippy_utils::{MaybePath, get_attr, higher, path_def_id, sym};
+use clippy_utils::res::MaybeQPath;
+use clippy_utils::{get_attr, higher, sym};
 use itertools::Itertools;
 use rustc_ast::LitIntType;
 use rustc_ast::ast::{LitFloatType, LitKind};
@@ -205,7 +206,6 @@ struct PrintVisitor<'a, 'tcx> {
     first: Cell<bool>,
 }
 
-#[allow(clippy::unused_self)]
 impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     fn new(cx: &'a LateContext<'tcx>) -> Self {
         Self {
@@ -269,16 +269,16 @@ fn symbol(&self, symbol: &Binding<Symbol>) {
         chain!(self, "{symbol}.as_str() == {:?}", symbol.value.as_str());
     }
 
-    fn qpath<'p>(&self, qpath: &Binding<&QPath<'_>>, has_hir_id: &Binding<&impl MaybePath<'p>>) {
+    fn qpath(&self, qpath: &Binding<&QPath<'_>>, hir_id_binding: &str, hir_id: HirId) {
         if let QPath::LangItem(lang_item, ..) = *qpath.value {
             chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))");
-        } else if let Some(def_id) = self.cx.qpath_res(qpath.value, has_hir_id.value.hir_id()).opt_def_id()
+        } else if let Some(def_id) = self.cx.qpath_res(qpath.value, hir_id).opt_def_id()
             && !def_id.is_local()
         {
             bind!(self, def_id);
             chain!(
                 self,
-                "let Some({def_id}) = cx.qpath_res({qpath}, {has_hir_id}.hir_id).opt_def_id()"
+                "let Some({def_id}) = cx.qpath_res({qpath}, {hir_id_binding}.hir_id).opt_def_id()"
             );
             if let Some(name) = self.cx.tcx.get_diagnostic_name(def_id.value) {
                 chain!(self, "cx.tcx.is_diagnostic_item(sym::{name}, {def_id})");
@@ -292,14 +292,14 @@ fn qpath<'p>(&self, qpath: &Binding<&QPath<'_>>, has_hir_id: &Binding<&impl Mayb
         }
     }
 
-    fn maybe_path<'p>(&self, path: &Binding<&impl MaybePath<'p>>) {
-        if let Some(id) = path_def_id(self.cx, path.value)
+    fn maybe_path<'p>(&self, path: &Binding<impl MaybeQPath<'p>>) {
+        if let Some(id) = path.value.res(self.cx).opt_def_id()
             && !id.is_local()
         {
             if let Some(lang) = self.cx.tcx.lang_items().from_def_id(id) {
-                chain!(self, "is_path_lang_item(cx, {path}, LangItem::{}", lang.name());
+                chain!(self, "{path}.res(cx).is_lang_item(cx, LangItem::{}", lang.name());
             } else if let Some(name) = self.cx.tcx.get_diagnostic_name(id) {
-                chain!(self, "is_path_diagnostic_item(cx, {path}, sym::{name})");
+                chain!(self, "{path}.res(cx).is_diag_item(cx, sym::{name})");
             } else {
                 chain!(
                     self,
@@ -410,7 +410,7 @@ fn arm(&self, arm: &Binding<&hir::Arm<'_>>) {
         self.expr(field!(arm.body));
     }
 
-    #[allow(clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn expr(&self, expr: &Binding<&hir::Expr<'_>>) {
         if let Some(higher::While { condition, body, .. }) = higher::While::hir(expr.value) {
             bind!(self, condition, body);
@@ -672,7 +672,7 @@ macro_rules! kind {
                     StructTailExpr::None | StructTailExpr::DefaultFields(_) => None,
                 });
                 kind!("Struct({qpath}, {fields}, {base})");
-                self.qpath(qpath, expr);
+                self.qpath(qpath, &expr.name, expr.value.hir_id);
                 self.slice(fields, |field| {
                     self.ident(field!(field.ident));
                     self.expr(field!(field.expr));
@@ -758,7 +758,7 @@ macro_rules! kind {
                 let ignore = etc.is_some();
                 bind!(self, qpath, fields);
                 kind!("Struct(ref {qpath}, {fields}, {ignore})");
-                self.qpath(qpath, pat);
+                self.qpath(qpath, &pat.name, pat.value.hir_id);
                 self.slice(fields, |field| {
                     self.ident(field!(field.ident));
                     self.pat(field!(field.pat));
@@ -772,7 +772,7 @@ macro_rules! kind {
             PatKind::TupleStruct(ref qpath, fields, skip_pos) => {
                 bind!(self, qpath, fields);
                 kind!("TupleStruct(ref {qpath}, {fields}, {skip_pos:?})");
-                self.qpath(qpath, pat);
+                self.qpath(qpath, &pat.name, pat.value.hir_id);
                 self.slice(fields, |pat| self.pat(pat));
             },
             PatKind::Tuple(fields, skip_pos) => {
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 52b30dd..b87db83 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -10,7 +10,7 @@
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::is_copy;
 use clippy_utils::visitors::for_each_local_use_after_expr;
-use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment, sym};
+use clippy_utils::{get_parent_expr, higher, is_in_test, span_contains_comment, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -124,7 +124,7 @@ fn expr_usage_requires_vec(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) ->
                     if let Some(parent) = get_parent_expr(cx, expr)
                         && (adjusts_to_slice(cx, expr)
                             || matches!(parent.kind, ExprKind::Index(..))
-                            || is_allowed_vec_method(cx, parent))
+                            || is_allowed_vec_method(parent))
                     {
                         ControlFlow::Continue(())
                     } else {
@@ -304,11 +304,11 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 /// Checks if the given expression is a method call to a `Vec` method
 /// that also exists on slices. If this returns true, it means that
 /// this expression does not actually require a `Vec` and could just work with an array.
-pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+pub fn is_allowed_vec_method(e: &Expr<'_>) -> bool {
     if let ExprKind::MethodCall(path, _, [], _) = e.kind {
         matches!(path.ident.name, sym::as_ptr | sym::is_empty | sym::len)
     } else {
-        is_trait_method(cx, e, sym::IntoIterator)
+        false
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index 8d87353..5d07420 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
+use clippy_utils::res::MaybeResPath;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::for_each_local_use_after_expr;
-use clippy_utils::{get_parent_expr, path_to_local_id, sym};
+use clippy_utils::{get_parent_expr, sym};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -201,7 +202,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let Some(searcher) = self.searcher.take() {
             if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
                 && let ExprKind::MethodCall(name, self_arg, [_], _) = expr.kind
-                && path_to_local_id(self_arg, searcher.local_id)
+                && self_arg.res_local_id() == Some(searcher.local_id)
                 && name.ident.name == sym::push
             {
                 self.searcher = Some(VecPushSearcher {
diff --git a/src/tools/clippy/clippy_lints/src/volatile_composites.rs b/src/tools/clippy/clippy_lints/src/volatile_composites.rs
new file mode 100644
index 0000000..6402c3e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/volatile_composites.rs
@@ -0,0 +1,180 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::res::MaybeDef;
+use clippy_utils::sym;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::{self, Ty, TypeVisitableExt};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// This lint warns when volatile load/store operations
+    /// (`write_volatile`/`read_volatile`) are applied to composite types.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Volatile operations are typically used with memory mapped IO devices,
+    /// where the precise number and ordering of load and store instructions is
+    /// important because they can have side effects. This is well defined for
+    /// primitive types like `u32`, but less well defined for structures and
+    /// other composite types. In practice it's implementation defined, and the
+    /// behavior can be rustc-version dependent.
+    ///
+    /// As a result, code should only apply `write_volatile`/`read_volatile` to
+    /// primitive types to be fully well-defined.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// struct MyDevice {
+    ///     addr: usize,
+    ///     count: usize
+    /// }
+    ///
+    /// fn start_device(device: *mut MyDevice, addr: usize, count: usize) {
+    ///     unsafe {
+    ///         device.write_volatile(MyDevice { addr, count });
+    ///     }
+    /// }
+    /// ```
+    /// Instead, operate on each primtive field individually:
+    /// ```no_run
+    /// struct MyDevice {
+    ///     addr: usize,
+    ///     count: usize
+    /// }
+    ///
+    /// fn start_device(device: *mut MyDevice, addr: usize, count: usize) {
+    ///     unsafe {
+    ///         (&raw mut (*device).addr).write_volatile(addr);
+    ///         (&raw mut (*device).count).write_volatile(count);
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.92.0"]
+    pub VOLATILE_COMPOSITES,
+    nursery,
+    "warn about volatile read/write applied to composite types"
+}
+declare_lint_pass!(VolatileComposites => [VOLATILE_COMPOSITES]);
+
+/// Zero-sized types are intrinsically safe to use volatile on since they won't
+/// actually generate *any* loads or stores. But this is also used to skip zero-sized
+/// fields of `#[repr(transparent)]` structures.
+fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    cx.layout_of(ty).is_ok_and(|layout| layout.is_zst())
+}
+
+/// A thin raw pointer or reference.
+fn is_narrow_ptr<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    match ty.kind() {
+        ty::RawPtr(inner, _) | ty::Ref(_, inner, _) => inner.has_trivial_sizedness(cx.tcx, ty::SizedTraitKind::Sized),
+        _ => false,
+    }
+}
+
+/// Enum with some fixed representation and no data-carrying variants.
+fn is_enum_repr_c<'tcx>(_cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    ty.ty_adt_def().is_some_and(|adt_def| {
+        adt_def.is_enum() && adt_def.repr().inhibit_struct_field_reordering() && adt_def.is_payloadfree()
+    })
+}
+
+/// `#[repr(transparent)]` structures are also OK if the only non-zero
+/// sized field contains a volatile-safe type.
+fn is_struct_repr_transparent<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    if let ty::Adt(adt_def, args) = ty.kind()
+        && adt_def.is_struct()
+        && adt_def.repr().transparent()
+        && let [fieldty] = adt_def
+            .all_fields()
+            .filter_map(|field| {
+                let fty = field.ty(cx.tcx, args);
+                if is_zero_sized_ty(cx, fty) { None } else { Some(fty) }
+            })
+            .collect::<Vec<_>>()
+            .as_slice()
+    {
+        is_volatile_safe_ty(cx, *fieldty)
+    } else {
+        false
+    }
+}
+
+/// SIMD can be useful to get larger single loads/stores, though this is still
+/// pretty machine-dependent.
+fn is_simd_repr<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    if let ty::Adt(adt_def, _args) = ty.kind()
+        && adt_def.is_struct()
+        && adt_def.repr().simd()
+    {
+        let (_size, simdty) = ty.simd_size_and_type(cx.tcx);
+        is_volatile_safe_ty(cx, simdty)
+    } else {
+        false
+    }
+}
+
+/// Top-level predicate for whether a type is volatile-safe or not.
+fn is_volatile_safe_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    ty.is_primitive()
+        || is_narrow_ptr(cx, ty)
+        || is_zero_sized_ty(cx, ty)
+        || is_enum_repr_c(cx, ty)
+        || is_simd_repr(cx, ty)
+        || is_struct_repr_transparent(cx, ty)
+        // We can't know about a generic type, so just let it pass to avoid noise
+        || ty.has_non_region_param()
+}
+
+/// Print diagnostic for volatile read/write on non-volatile-safe types.
+fn report_volatile_safe<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty: Ty<'tcx>) {
+    if !is_volatile_safe_ty(cx, ty) {
+        span_lint(
+            cx,
+            VOLATILE_COMPOSITES,
+            expr.span,
+            format!("type `{ty}` is not volatile-compatible"),
+        );
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for VolatileComposites {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        // Check our expr is calling a method with pattern matching
+        match expr.kind {
+            // Look for method calls to `write_volatile`/`read_volatile`, which
+            // apply to both raw pointers and std::ptr::NonNull.
+            ExprKind::MethodCall(name, self_arg, _, _)
+                if matches!(name.ident.name, sym::read_volatile | sym::write_volatile) =>
+            {
+                let self_ty = cx.typeck_results().expr_ty(self_arg);
+                match self_ty.kind() {
+                    // Raw pointers
+                    ty::RawPtr(innerty, _) => report_volatile_safe(cx, expr, *innerty),
+                    // std::ptr::NonNull
+                    ty::Adt(_, args) if self_ty.is_diag_item(cx, sym::NonNull) => {
+                        report_volatile_safe(cx, expr, args.type_at(0));
+                    },
+                    _ => (),
+                }
+            },
+
+            // Also plain function calls to std::ptr::{read,write}_volatile
+            ExprKind::Call(func, [arg_ptr, ..]) => {
+                if let ExprKind::Path(ref qpath) = func.kind
+                    && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
+                    && matches!(
+                        cx.tcx.get_diagnostic_name(def_id),
+                        Some(sym::ptr_read_volatile | sym::ptr_write_volatile)
+                    )
+                    && let ty::RawPtr(ptrty, _) = cx.typeck_results().expr_ty_adjusted(arg_ptr).kind()
+                {
+                    report_volatile_safe(cx, expr, *ptrty);
+                }
+            },
+            _ => {},
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs
index cd6c11b..a835169 100644
--- a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::VecArgs;
-use clippy_utils::source::snippet;
+use clippy_utils::source::{snippet, snippet_indent};
 use rustc_ast::LitKind;
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::Applicability;
 use rustc_hir::{ConstArgKind, ExprKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::IsSuggestable;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -72,40 +73,60 @@ fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr:
     // check if expr is a call or has a call inside it
     if inner_expr.can_have_side_effects() {
         let parent_hir_node = cx.tcx.parent_hir_node(expr.hir_id);
+        let inner_expr_ty = cx.typeck_results().expr_ty(inner_expr);
         let return_type = cx.typeck_results().expr_ty(expr);
 
         let inner_expr = snippet(cx, inner_expr.span.source_callsite(), "..");
+        let indent = snippet_indent(cx, expr.span).unwrap_or_default();
         let vec = if is_vec { "vec!" } else { "" };
 
         let (span, sugg) = match parent_hir_node {
             Node::LetStmt(l) => (
                 l.span,
                 format!(
-                    "{inner_expr}; let {var_name}: {return_type} = {vec}[];",
+                    "{inner_expr};\n{indent}let {var_name}: {return_type} = {vec}[];",
                     var_name = snippet(cx, l.pat.span.source_callsite(), "..")
                 ),
             ),
             Node::Expr(x) if let ExprKind::Assign(l, _, _) = x.kind => (
                 x.span,
                 format!(
-                    "{inner_expr}; {var_name} = {vec}[] as {return_type}",
+                    "{inner_expr};\n{indent}{var_name} = {vec}[] as {return_type}",
                     var_name = snippet(cx, l.span.source_callsite(), "..")
                 ),
             ),
-            _ => (expr.span, format!("{{ {inner_expr}; {vec}[] as {return_type} }}")),
+            // NOTE: don't use the stmt span to avoid touching the trailing semicolon
+            Node::Stmt(_) => (expr.span, format!("{inner_expr};\n{indent}{vec}[] as {return_type}")),
+            _ => (
+                expr.span,
+                format!(
+                    "\
+{{
+{indent}    {inner_expr};
+{indent}    {vec}[] as {return_type}
+{indent}}}"
+                ),
+            ),
         };
+        let span = span.source_callsite();
         span_lint_and_then(
             cx,
             ZERO_REPEAT_SIDE_EFFECTS,
-            span.source_callsite(),
+            span,
             "expression with side effects as the initial value in a zero-sized array initializer",
             |diag| {
-                diag.span_suggestion_verbose(
-                    span.source_callsite(),
-                    "consider performing the side effect separately",
-                    sugg,
-                    Applicability::Unspecified,
-                );
+                if (!inner_expr_ty.is_never() || cx.tcx.features().never_type())
+                    && return_type.is_suggestable(cx.tcx, true)
+                {
+                    diag.span_suggestion_verbose(
+                        span,
+                        "consider performing the side effect separately",
+                        sugg,
+                        Applicability::Unspecified,
+                    );
+                } else {
+                    diag.help("consider performing the side effect separately");
+                }
             },
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index f1572fd..bf133d2 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{is_type_diagnostic_item, ty_from_hir_ty};
+use clippy_utils::res::MaybeDef;
+use clippy_utils::ty::ty_from_hir_ty;
 use rustc_hir::{self as hir, AmbigArg, HirId, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf as _;
@@ -48,7 +49,7 @@ fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx, Ambi
             && !in_trait_impl(cx, hir_ty.hir_id)
             // We don't care about infer vars
             && let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty())
-            && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap))
+            && (ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap))
             && let ty::Adt(_, args) = ty.kind()
             && let ty = args.type_at(1)
             // Ensure that no type information is missing, to avoid a delayed bug in the compiler if this is not the case.
diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
index a934d20..0319f3e 100644
--- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs
+++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
@@ -1,7 +1,7 @@
 use ControlFlow::{Break, Continue};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{fn_def_id, get_enclosing_block, path_to_local_id};
+use clippy_utils::res::{MaybeDef, MaybeResPath};
+use clippy_utils::{fn_def_id, get_enclosing_block};
 use rustc_ast::Mutability;
 use rustc_ast::visit::visit_opt;
 use rustc_errors::Applicability;
@@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::Call(..) | ExprKind::MethodCall(..) = expr.kind
             && let child_ty = cx.typeck_results().expr_ty(expr)
-            && is_type_diagnostic_item(cx, child_ty, sym::Child)
+            && child_ty.is_diag_item(cx, sym::Child)
         {
             match cx.tcx.parent_hir_node(expr.hir_id) {
                 Node::LetStmt(local)
@@ -168,7 +168,7 @@ fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result {
             return walk_expr(self, ex);
         }
 
-        if path_to_local_id(ex, self.local_id) {
+        if ex.res_local_id() == Some(self.local_id) {
             match self.cx.tcx.parent_hir_node(ex.hir_id) {
                 Node::Stmt(Stmt {
                     kind: StmtKind::Semi(_),
diff --git a/src/tools/clippy/clippy_lints_internal/Cargo.toml b/src/tools/clippy/clippy_lints_internal/Cargo.toml
index a8293a1..16b4532 100644
--- a/src/tools/clippy/clippy_lints_internal/Cargo.toml
+++ b/src/tools/clippy/clippy_lints_internal/Cargo.toml
@@ -6,6 +6,7 @@
 [dependencies]
 clippy_config = { path = "../clippy_config" }
 clippy_utils = { path = "../clippy_utils" }
+itertools = "0.12"
 regex = { version = "1.5" }
 rustc-semver = "1.1"
 
diff --git a/src/tools/clippy/clippy_lints_internal/src/internal_paths.rs b/src/tools/clippy/clippy_lints_internal/src/internal_paths.rs
index dc1e30a..95bdf27 100644
--- a/src/tools/clippy/clippy_lints_internal/src/internal_paths.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/internal_paths.rs
@@ -2,13 +2,18 @@
 use clippy_utils::{sym, type_path, value_path};
 
 // Paths inside rustc
+pub static APPLICABILITY: PathLookup = type_path!(rustc_errors::Applicability);
+pub static EARLY_CONTEXT: PathLookup = type_path!(rustc_lint::EarlyContext);
 pub static EARLY_LINT_PASS: PathLookup = type_path!(rustc_lint::passes::EarlyLintPass);
 pub static KW_MODULE: PathLookup = type_path!(rustc_span::symbol::kw);
+pub static LATE_CONTEXT: PathLookup = type_path!(rustc_lint::LateContext);
 pub static LINT: PathLookup = type_path!(rustc_lint_defs::Lint);
 pub static SYMBOL: PathLookup = type_path!(rustc_span::symbol::Symbol);
 pub static SYMBOL_AS_STR: PathLookup = value_path!(rustc_span::symbol::Symbol::as_str);
 pub static SYM_MODULE: PathLookup = type_path!(rustc_span::symbol::sym);
 pub static SYNTAX_CONTEXT: PathLookup = type_path!(rustc_span::hygiene::SyntaxContext);
+#[expect(clippy::unnecessary_def_path, reason = "for uniform checking in internal lint")]
+pub static TY_CTXT: PathLookup = type_path!(rustc_middle::ty::TyCtxt);
 
 // Paths in clippy itself
 pub static CLIPPY_SYM_MODULE: PathLookup = type_path!(clippy_utils::sym);
diff --git a/src/tools/clippy/clippy_lints_internal/src/lib.rs b/src/tools/clippy/clippy_lints_internal/src/lib.rs
index 43cde86..d686ba7 100644
--- a/src/tools/clippy/clippy_lints_internal/src/lib.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/lib.rs
@@ -41,6 +41,7 @@
 mod symbols;
 mod unnecessary_def_path;
 mod unsorted_clippy_utils_paths;
+mod unusual_names;
 
 use rustc_lint::{Lint, LintStore};
 
@@ -59,6 +60,7 @@
     symbols::SYMBOL_AS_STR,
     unnecessary_def_path::UNNECESSARY_DEF_PATH,
     unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS,
+    unusual_names::UNUSUAL_NAMES,
 ];
 
 pub fn register_lints(store: &mut LintStore) {
@@ -74,4 +76,5 @@ pub fn register_lints(store: &mut LintStore) {
     store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass));
     store.register_late_pass(|_| Box::new(msrv_attr_impl::MsrvAttrImpl));
     store.register_late_pass(|_| Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new()));
+    store.register_late_pass(|_| Box::new(unusual_names::UnusualNames));
 }
diff --git a/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
index 66aeb91..e529bc2 100644
--- a/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
@@ -26,10 +26,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
             items,
             ..
         }) = &item.kind
-            && let Some(trait_ref) = cx
-                .tcx
-                .impl_trait_ref(item.owner_id)
-                .map(EarlyBinder::instantiate_identity)
+            && let trait_ref = cx.tcx.impl_trait_ref(item.owner_id).instantiate_identity()
             && internal_paths::EARLY_LINT_PASS.matches(cx, trait_ref.def_id)
             && let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind()
             && self_ty_def.is_struct()
diff --git a/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs b/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
index 3a813b4..6308430 100644
--- a/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
@@ -25,9 +25,9 @@
 declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
 
 impl EarlyLintPass for ProduceIce {
-    fn check_fn(&mut self, ctx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
+    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span, _: NodeId) {
         if is_trigger_fn(fn_kind) {
-            ctx.sess()
+            cx.sess()
                 .dcx()
                 .span_delayed_bug(span, "Would you like some help with that?");
         }
diff --git a/src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs
index 8877f1f..f2e8d35 100644
--- a/src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs
@@ -1,7 +1,8 @@
 use crate::internal_paths;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::paths::{PathNS, lookup_path};
-use clippy_utils::{path_def_id, peel_ref_operators};
+use clippy_utils::peel_ref_operators;
+use clippy_utils::res::MaybeQPath;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -26,7 +27,7 @@
     ///
     /// Use instead:
     /// ```rust,ignore
-    /// is_type_diagnostic_item(cx, ty, sym::Vec)
+    /// ty.is_diag_item(cx, sym::Vec)
     /// ```
     pub clippy::UNNECESSARY_DEF_PATH,
     Warn,
@@ -53,7 +54,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             let path: Vec<Symbol> = segments
                 .iter()
                 .map(|segment| {
-                    if let Some(const_def_id) = path_def_id(cx, segment)
+                    if let Some(const_def_id) = segment.res(cx).opt_def_id()
                         && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(const_def_id)
                         && let Some(value) = value.to_u32().discard_err()
                     {
diff --git a/src/tools/clippy/clippy_lints_internal/src/unusual_names.rs b/src/tools/clippy/clippy_lints_internal/src/unusual_names.rs
new file mode 100644
index 0000000..e11a286
--- /dev/null
+++ b/src/tools/clippy/clippy_lints_internal/src/unusual_names.rs
@@ -0,0 +1,99 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::paths::PathLookup;
+use clippy_utils::sym;
+use itertools::Itertools;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, FnDecl, Pat, PatKind, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::kw;
+use rustc_span::{Span, Symbol};
+
+use crate::internal_paths::{APPLICABILITY, EARLY_CONTEXT, LATE_CONTEXT, TY_CTXT};
+
+declare_tool_lint! {
+    /// ### What it does
+    /// Checks if variables of some types use the usual name.
+    ///
+    /// ### Why is this bad?
+    /// Restricting the identifiers used for common things in
+    /// Clippy sources increases consistency.
+    ///
+    /// ### Example
+    /// Check that an `rustc_errors::Applicability` variable is
+    /// named either `app` or `applicability`, and not
+    /// `a` or `appl`.
+    pub clippy::UNUSUAL_NAMES,
+    Warn,
+    "commonly used concepts should use usual same variable name.",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(UnusualNames => [UNUSUAL_NAMES]);
+
+const USUAL_NAMES: [(&PathLookup, &str, &[Symbol]); 4] = [
+    (
+        &APPLICABILITY,
+        "rustc_errors::Applicability",
+        &[sym::app, sym::applicability],
+    ),
+    (&EARLY_CONTEXT, "rustc_lint::EarlyContext", &[sym::cx]),
+    (&LATE_CONTEXT, "rustc_lint::LateContext", &[sym::cx]),
+    (&TY_CTXT, "rustc_middle::ty::TyCtxt", &[sym::tcx]),
+];
+
+impl<'tcx> LateLintPass<'tcx> for UnusualNames {
+    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+        if let StmtKind::Let(let_stmt) = stmt.kind
+            && let Some(init_expr) = let_stmt.init
+        {
+            check_pat_name_for_ty(cx, let_stmt.pat, cx.typeck_results().expr_ty(init_expr), "variable");
+        }
+    }
+
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        kind: FnKind<'tcx>,
+        _decl: &'tcx FnDecl<'_>,
+        body: &'tcx Body<'_>,
+        _span: Span,
+        def_id: LocalDefId,
+    ) {
+        if matches!(kind, FnKind::Closure) {
+            return;
+        }
+        for (param, ty) in body
+            .params
+            .iter()
+            .zip(cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder().inputs())
+        {
+            check_pat_name_for_ty(cx, param.pat, *ty, "parameter");
+        }
+    }
+}
+
+fn check_pat_name_for_ty(cx: &LateContext<'_>, pat: &Pat<'_>, ty: Ty<'_>, kind: &str) {
+    if let PatKind::Binding(_, _, ident, _) = pat.kind {
+        let ty = ty.peel_refs();
+        for (usual_ty, ty_str, usual_names) in USUAL_NAMES {
+            if usual_ty.matches_ty(cx, ty)
+                && !usual_names.contains(&ident.name)
+                && ident.name != kw::SelfLower
+                && !ident.name.as_str().starts_with('_')
+            {
+                let usual_names = usual_names.iter().map(|name| format!("`{name}`")).join(" or ");
+                span_lint_and_help(
+                    cx,
+                    UNUSUAL_NAMES,
+                    ident.span,
+                    format!("unusual name for a {kind} of type `{ty_str}`"),
+                    None,
+                    format!("prefer using {usual_names}"),
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index 1f678a6..9d12b46 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2025-10-06
+nightly-2025-10-16
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index ad69e6e..b01e160 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -143,7 +143,7 @@ pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool {
     }
 }
 
-#[allow(clippy::too_many_lines)] // Just a big match statement
+#[expect(clippy::too_many_lines, reason = "big match statement")]
 pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
     use ExprKind::*;
     if !over(&l.attrs, &r.attrs, eq_attr) {
@@ -328,7 +328,7 @@ pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> b
     over(&l.attrs, &r.attrs, eq_attr) && eq_vis(&l.vis, &r.vis) && eq_kind(&l.kind, &r.kind)
 }
 
-#[expect(clippy::too_many_lines)] // Just a big match statement
+#[expect(clippy::too_many_lines, reason = "big match statement")]
 pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
     use ItemKind::*;
     match (l, r) {
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 948a720..ff3e7b9 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -490,17 +490,14 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) {
                     None => ident_search_pat(last.ident).1,
                 }
             } else {
-                // this shouldn't be possible, but sure
-                #[allow(
-                    clippy::collapsible_else_if,
-                    reason = "we want to keep these cases together, since they are both impossible"
-                )]
-                if qself_path.is_some() {
-                    // last `>` in `<Vec as IntoIterator>`
-                    Pat::Str(">")
-                } else {
-                    Pat::Str("")
-                }
+                // this shouldn't be possible
+                Pat::Str(
+                    if qself_path.is_some() {
+                        ">"  // last `>` in `<Vec as IntoIterator>`
+                    } else {
+                        ""
+                    }
+                )
             };
             (start, end)
         },
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 9ba7961..7b8c7f3 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -2,10 +2,11 @@
 //!
 //! This cannot use rustc's const eval, aka miri, as arbitrary HIR expressions cannot be lowered to
 //! executable MIR bodies, so we have to do this instead.
-#![allow(clippy::float_cmp)]
+#![expect(clippy::float_cmp)]
 
+use crate::res::MaybeDef;
 use crate::source::{SpanRangeExt, walk_span_to_context};
-use crate::{clip, is_direct_expn_of, paths, sext, sym, unsext};
+use crate::{clip, is_direct_expn_of, sext, sym, unsext};
 
 use rustc_abi::Size;
 use rustc_apfloat::Float;
@@ -50,15 +51,15 @@ pub enum Constant {
     /// `true` or `false`.
     Bool(bool),
     /// An array of constants.
-    Vec(Vec<Constant>),
+    Vec(Vec<Self>),
     /// Also an array, but with only one constant, repeated N times.
-    Repeat(Box<Constant>, u64),
+    Repeat(Box<Self>, u64),
     /// A tuple of constants.
-    Tuple(Vec<Constant>),
+    Tuple(Vec<Self>),
     /// A raw pointer.
     RawPtr(u128),
     /// A reference
-    Ref(Box<Constant>),
+    Ref(Box<Self>),
     /// A literal with syntax error.
     Err,
 }
@@ -805,10 +806,10 @@ fn fetch_path(&self, qpath: &QPath<'_>, id: HirId) -> Option<ConstValue> {
                                 | sym::i128_legacy_const_max
                         )
                     ) || self.tcx.opt_parent(did).is_some_and(|parent| {
-                        paths::F16_CONSTS.matches(&self.tcx, parent)
-                            || paths::F32_CONSTS.matches(&self.tcx, parent)
-                            || paths::F64_CONSTS.matches(&self.tcx, parent)
-                            || paths::F128_CONSTS.matches(&self.tcx, parent)
+                        parent.is_diag_item(&self.tcx, sym::f16_consts_mod)
+                            || parent.is_diag_item(&self.tcx, sym::f32_consts_mod)
+                            || parent.is_diag_item(&self.tcx, sym::f64_consts_mod)
+                            || parent.is_diag_item(&self.tcx, sym::f128_consts_mod)
                     })) =>
             {
                 did
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 6f1bc28..3383e66 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -3,7 +3,7 @@
 #![deny(clippy::missing_docs_in_private_items)]
 
 use crate::consts::{ConstEvalCtxt, Constant};
-use crate::ty::is_type_diagnostic_item;
+use crate::res::MaybeDef;
 use crate::{is_expn_of, sym};
 
 use rustc_ast::ast;
@@ -14,6 +14,7 @@
 
 /// The essential nodes of a desugared for loop as well as the entire span:
 /// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`.
+#[derive(Debug)]
 pub struct ForLoop<'tcx> {
     /// `for` loop item
     pub pat: &'tcx Pat<'tcx>,
@@ -212,7 +213,7 @@ pub struct Range<'a> {
 
 impl<'a> Range<'a> {
     /// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
-    #[allow(clippy::similar_names)]
+    #[expect(clippy::similar_names)]
     pub fn hir(expr: &'a Expr<'_>) -> Option<Range<'a>> {
         match expr.kind {
             ExprKind::Call(path, [arg1, arg2])
@@ -318,6 +319,7 @@ pub struct While<'hir> {
     pub body: &'hir Expr<'hir>,
     /// Span of the loop header
     pub span: Span,
+    pub label: Option<ast::Label>,
 }
 
 impl<'hir> While<'hir> {
@@ -333,13 +335,18 @@ pub const fn hir(expr: &Expr<'hir>) -> Option<Self> {
                     }),
                 ..
             },
-            _,
+            label,
             LoopSource::While,
             span,
         ) = expr.kind
             && !has_let_expr(condition)
         {
-            return Some(Self { condition, body, span });
+            return Some(Self {
+                condition,
+                body,
+                span,
+                label,
+            });
         }
         None
     }
@@ -446,7 +453,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
     if let ExprKind::Call(func, args) = expr.kind {
         match func.kind {
             ExprKind::Path(QPath::TypeRelative(ty, name))
-                if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) =>
+                if cx.typeck_results().node_type(ty.hir_id).is_diag_item(cx, sym::Vec) =>
             {
                 if name.ident.name == sym::new {
                     return Some(VecInitKind::New);
@@ -462,7 +469,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
             },
             ExprKind::Path(QPath::Resolved(_, path))
                 if cx.tcx.is_diagnostic_item(sym::default_fn, path.res.opt_def_id()?)
-                    && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) =>
+                    && cx.typeck_results().expr_ty(expr).is_diag_item(cx, sym::Vec) =>
             {
                 return Some(VecInitKind::Default);
             },
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 2218c5e..c894352 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -30,8 +30,10 @@
 extern crate rustc_attr_parsing;
 extern crate rustc_const_eval;
 extern crate rustc_data_structures;
-// The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate.
-#[allow(unused_extern_crates)]
+#[expect(
+    unused_extern_crates,
+    reason = "The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate."
+)]
 extern crate rustc_driver;
 extern crate rustc_errors;
 extern crate rustc_hir;
@@ -62,6 +64,7 @@
 pub mod numeric_literal;
 pub mod paths;
 pub mod qualify_min_const_fn;
+pub mod res;
 pub mod source;
 pub mod str_utils;
 pub mod sugg;
@@ -128,6 +131,7 @@
 use crate::consts::{ConstEvalCtxt, Constant};
 use crate::higher::Range;
 use crate::msrvs::Msrv;
+use crate::res::{MaybeDef, MaybeResPath};
 use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
 use crate::visitors::for_each_expr_without_closures;
 
@@ -169,7 +173,8 @@ fn check_attributes_post(&mut self, cx: &rustc_lint::EarlyContext<'_>, attrs: &[
 /// //   ^^^ input
 /// ```
 pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
-    while let Some(init) = path_to_local(expr)
+    while let Some(init) = expr
+        .res_local_id()
         .and_then(|id| find_binding_init(cx, id))
         .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())
     {
@@ -247,19 +252,6 @@ pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
     }
 }
 
-/// Checks if a `Res` refers to a constructor of a `LangItem`
-/// For example, use this to check whether a function call or a pattern is `Some(..)`.
-pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool {
-    if let Res::Def(DefKind::Ctor(..), id) = res
-        && let Some(lang_id) = cx.tcx.lang_items().get(lang_item)
-        && let Some(id) = cx.tcx.opt_parent(id)
-    {
-        id == lang_id
-    } else {
-        false
-    }
-}
-
 /// Checks if `{ctor_call_id}(...)` is `{enum_item}::{variant_name}(...)`.
 pub fn is_enum_variant_ctor(
     cx: &LateContext<'_>,
@@ -332,13 +324,17 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
 pub fn is_none_pattern(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
     matches!(pat.kind,
         PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
-            if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone))
+            if cx.qpath_res(qpath, pat.hir_id).ctor_parent(cx).is_lang_item(cx, OptionNone))
 }
 
 /// Checks if `arm` has the form `None => None`.
 pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     is_none_pattern(cx, arm.pat)
-        && matches!(peel_blocks(arm.body).kind, ExprKind::Path(qpath) if is_res_lang_ctor(cx, cx.qpath_res(&qpath, arm.body.hir_id), OptionNone))
+        && matches!(
+            peel_blocks(arm.body).kind,
+            ExprKind::Path(qpath)
+            if cx.qpath_res(&qpath, arm.body.hir_id).ctor_parent(cx).is_lang_item(cx, OptionNone)
+        )
 }
 
 /// Checks if the given `QPath` belongs to a type alias.
@@ -350,40 +346,6 @@ pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
     }
 }
 
-/// Checks if the given method call expression calls an inherent method.
-pub fn is_inherent_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
-        cx.tcx.trait_of_assoc(method_id).is_none()
-    } else {
-        false
-    }
-}
-
-/// Checks if a method is defined in an impl of a diagnostic item
-pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
-    if let Some(impl_did) = cx.tcx.impl_of_assoc(def_id)
-        && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
-    {
-        return cx.tcx.is_diagnostic_item(diag_item, adt.did());
-    }
-    false
-}
-
-/// Checks if a method is in a diagnostic item trait
-pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
-    if let Some(trait_did) = cx.tcx.trait_of_assoc(def_id) {
-        return cx.tcx.is_diagnostic_item(diag_item, trait_did);
-    }
-    false
-}
-
-/// Checks if the method call given in `expr` belongs to the given trait.
-pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
-    cx.typeck_results()
-        .type_dependent_def_id(expr.hir_id)
-        .is_some_and(|did| is_diag_trait_item(cx, did, diag_item))
-}
-
 /// Checks if the `def_id` belongs to a function that is part of a trait impl.
 pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
     if let Node::Item(item) = cx.tcx.parent_hir_node(cx.tcx.local_def_id_to_hir_id(def_id))
@@ -395,25 +357,6 @@ pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool
     }
 }
 
-/// Checks if the given expression is a path referring an item on the trait
-/// that is marked with the given diagnostic item.
-///
-/// For checking method call expressions instead of path expressions, use
-/// [`is_trait_method`].
-///
-/// For example, this can be used to find if an expression like `u64::default`
-/// refers to an item of the trait `Default`, which is associated with the
-/// `diag_item` of `sym::Default`.
-pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
-    if let ExprKind::Path(ref qpath) = expr.kind {
-        cx.qpath_res(qpath, expr.hir_id)
-            .opt_def_id()
-            .is_some_and(|def_id| is_diag_trait_item(cx, def_id, diag_item))
-    } else {
-        false
-    }
-}
-
 pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
     match *path {
         QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
@@ -433,38 +376,6 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tc
         })
 }
 
-/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
-/// it matches the given lang item.
-pub fn is_path_lang_item<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>, lang_item: LangItem) -> bool {
-    path_def_id(cx, maybe_path).is_some_and(|id| cx.tcx.lang_items().get(lang_item) == Some(id))
-}
-
-/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
-/// it matches the given diagnostic item.
-pub fn is_path_diagnostic_item<'tcx>(
-    cx: &LateContext<'_>,
-    maybe_path: &impl MaybePath<'tcx>,
-    diag_item: Symbol,
-) -> bool {
-    path_def_id(cx, maybe_path).is_some_and(|id| cx.tcx.is_diagnostic_item(diag_item, id))
-}
-
-/// If the expression is a path to a local, returns the canonical `HirId` of the local.
-pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
-    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind
-        && let Res::Local(id) = path.res
-    {
-        return Some(id);
-    }
-    None
-}
-
-/// Returns true if the expression is a path to a local with the specified `HirId`.
-/// Use this function to see if an expression matches a function argument or a match binding.
-pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool {
-    path_to_local(expr) == Some(id)
-}
-
 /// If the expression is a path to a local (with optional projections),
 /// returns the canonical `HirId` of the local.
 ///
@@ -482,56 +393,6 @@ pub fn path_to_local_with_projections(expr: &Expr<'_>) -> Option<HirId> {
     }
 }
 
-pub trait MaybePath<'hir> {
-    fn hir_id(&self) -> HirId;
-    fn qpath_opt(&self) -> Option<&QPath<'hir>>;
-}
-
-macro_rules! maybe_path {
-    ($ty:ident, $kind:ident) => {
-        impl<'hir> MaybePath<'hir> for hir::$ty<'hir> {
-            fn hir_id(&self) -> HirId {
-                self.hir_id
-            }
-            fn qpath_opt(&self) -> Option<&QPath<'hir>> {
-                match &self.kind {
-                    hir::$kind::Path(qpath) => Some(qpath),
-                    _ => None,
-                }
-            }
-        }
-    };
-}
-maybe_path!(Expr, ExprKind);
-impl<'hir> MaybePath<'hir> for Pat<'hir> {
-    fn hir_id(&self) -> HirId {
-        self.hir_id
-    }
-    fn qpath_opt(&self) -> Option<&QPath<'hir>> {
-        match &self.kind {
-            PatKind::Expr(PatExpr {
-                kind: PatExprKind::Path(qpath),
-                ..
-            }) => Some(qpath),
-            _ => None,
-        }
-    }
-}
-maybe_path!(Ty, TyKind);
-
-/// If `maybe_path` is a path node, resolves it, otherwise returns `Res::Err`
-pub fn path_res<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Res {
-    match maybe_path.qpath_opt() {
-        None => Res::Err,
-        Some(qpath) => cx.qpath_res(qpath, maybe_path.hir_id()),
-    }
-}
-
-/// If `maybe_path` is a path node which resolves to an item, retrieves the item ID
-pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Option<DefId> {
-    path_res(cx, maybe_path).opt_def_id()
-}
-
 /// Gets the `hir::TraitRef` of the trait the given method is implemented for.
 ///
 /// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
@@ -658,9 +519,9 @@ pub fn is_default_equivalent_call(
     whole_call_expr: Option<&Expr<'_>>,
 ) -> bool {
     if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind
-        && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id()
-        && (is_diag_trait_item(cx, repl_def_id, sym::Default)
-            || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath))
+        && let Some(repl_def) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def(cx)
+        && (repl_def.assoc_fn_parent(cx).is_diag_item(cx, sym::Default)
+            || is_default_equivalent_ctor(cx, repl_def.1, repl_func_qpath))
     {
         return true;
     }
@@ -769,7 +630,10 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
         },
         ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func, Some(e)),
         ExprKind::Call(from_func, [arg]) => is_default_equivalent_from(cx, from_func, arg),
-        ExprKind::Path(qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, e.hir_id), OptionNone),
+        ExprKind::Path(qpath) => cx
+            .qpath_res(qpath, e.hir_id)
+            .ctor_parent(cx)
+            .is_lang_item(cx, OptionNone),
         ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
         ExprKind::Block(Block { stmts: [], expr, .. }, _) => expr.is_some_and(|e| is_default_equivalent(cx, e)),
         _ => false,
@@ -784,14 +648,14 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
             ExprKind::Lit(hir::Lit {
                 node: LitKind::Str(sym, _),
                 ..
-            }) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
-            ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
+            }) => return sym.is_empty() && ty.basic_res().is_lang_item(cx, LangItem::String),
+            ExprKind::Array([]) => return ty.basic_res().is_diag_item(cx, sym::Vec),
             ExprKind::Repeat(_, len) => {
                 if let ConstArgKind::Anon(anon_const) = len.kind
                     && let ExprKind::Lit(const_lit) = cx.tcx.hir_body(anon_const.body).value.kind
                     && let LitKind::Int(v, _) = const_lit.node
                 {
-                    return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
+                    return v == 0 && ty.basic_res().is_diag_item(cx, sym::Vec);
                 }
             },
             _ => (),
@@ -1670,9 +1534,12 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc
     fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
         if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind
             && ddpos.as_opt_usize().is_none()
-            && is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultOk)
+            && cx
+                .qpath_res(path, arm.pat.hir_id)
+                .ctor_parent(cx)
+                .is_lang_item(cx, ResultOk)
             && let PatKind::Binding(_, hir_id, _, None) = pat[0].kind
-            && path_to_local_id(arm.body, hir_id)
+            && arm.body.res_local_id() == Some(hir_id)
         {
             return true;
         }
@@ -1681,7 +1548,9 @@ fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 
     fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
         if let PatKind::TupleStruct(ref path, _, _) = arm.pat.kind {
-            is_res_lang_ctor(cx, cx.qpath_res(path, arm.pat.hir_id), ResultErr)
+            cx.qpath_res(path, arm.pat.hir_id)
+                .ctor_parent(cx)
+                .is_lang_item(cx, ResultErr)
         } else {
             false
         }
@@ -1975,7 +1844,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<
 
     match (pat.kind, expr.kind) {
         (PatKind::Binding(_, id, _, _), _) if by_hir => {
-            path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty()
+            expr.res_local_id() == Some(id) && cx.typeck_results().expr_adjustments(expr).is_empty()
         },
         (PatKind::Binding(_, _, ident, _), ExprKind::Path(QPath::Resolved(_, path))) => {
             matches!(path.segments, [ segment] if segment.ident.name == ident.name)
@@ -2048,7 +1917,7 @@ pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>)
 pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match expr.kind {
         ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir_body(body)),
-        _ => path_def_id(cx, expr).is_some_and(|id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)),
+        _ => expr.basic_res().is_diag_item(cx, sym::convert_identity),
     }
 }
 
@@ -2812,7 +2681,6 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'tcx>) -> ExprUseCtx
             moved_before_use,
             same_ctxt,
         },
-        #[allow(unreachable_patterns)]
         Some(ControlFlow::Break(_)) => unreachable!("type of node is ControlFlow<!>"),
         None => ExprUseCtxt {
             node: Node::Crate(cx.tcx.hir_root_module()),
@@ -2916,12 +2784,18 @@ pub fn pat_and_expr_can_be_question_mark<'a, 'hir>(
     else_body: &Expr<'_>,
 ) -> Option<&'a Pat<'hir>> {
     if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind
-        && is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome)
+        && cx
+            .qpath_res(&pat_path, pat.hir_id)
+            .ctor_parent(cx)
+            .is_lang_item(cx, OptionSome)
         && !is_refutable(cx, inner_pat)
         && let else_body = peel_blocks(else_body)
         && let ExprKind::Ret(Some(ret_val)) = else_body.kind
         && let ExprKind::Path(ret_path) = ret_val.kind
-        && is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone)
+        && cx
+            .qpath_res(&ret_path, ret_val.hir_id)
+            .ctor_parent(cx)
+            .is_lang_item(cx, OptionNone)
     {
         Some(inner_pat)
     } else {
@@ -3495,7 +3369,7 @@ pub fn expr_requires_coercion<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -
 /// Returns `true` if `expr` designates a mutable static, a mutable local binding, or an expression
 /// that can be owned.
 pub fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    if let Some(hir_id) = path_to_local(expr)
+    if let Some(hir_id) = expr.res_local_id()
         && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
     {
         matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..))
diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs
index 9ba644f..a066427 100644
--- a/src/tools/clippy/clippy_utils/src/mir/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs
@@ -134,7 +134,7 @@ pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option<bool> {
 }
 
 /// Returns the `mir::Body` containing the node associated with `hir_id`.
-#[allow(clippy::module_name_repetitions)]
+#[expect(clippy::module_name_repetitions)]
 pub fn enclosing_mir(tcx: TyCtxt<'_>, hir_id: HirId) -> Option<&Body<'_>> {
     let body_owner_local_def_id = tcx.hir_enclosing_body_owner(hir_id);
     if tcx.hir_body_owner_kind(body_owner_local_def_id).is_fn_or_closure() {
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 152b427..f2bffc8 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -15,7 +15,6 @@
 /// Collects the possible borrowers of each local.
 /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
 /// possible borrowers of `a`.
-#[allow(clippy::module_name_repetitions)]
 struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
     possible_borrower: TransitiveRelation,
     body: &'b mir::Body<'tcx>,
@@ -167,7 +166,6 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
 }
 
 /// Result of `PossibleBorrowerVisitor`.
-#[allow(clippy::module_name_repetitions)]
 pub struct PossibleBorrowerMap<'b, 'tcx> {
     /// Mapping `Local -> its possible borrowers`
     pub map: FxHashMap<mir::Local, DenseBitSet<mir::Local>>,
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
index 3d253fd..fee22c4 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
@@ -8,7 +8,6 @@
 /// Collect possible borrowed for every `&mut` local.
 /// For example, `_1 = &mut _2` generate _1: {_2,...}
 /// Known Problems: not sure all borrowed are tracked
-#[allow(clippy::module_name_repetitions)]
 pub(super) struct PossibleOriginVisitor<'a, 'tcx> {
     possible_origin: TransitiveRelation,
     body: &'a mir::Body<'tcx>,
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 5ab8e16..8aa6631 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -4,7 +4,8 @@
 //! Whenever possible, please consider diagnostic items over hardcoded paths.
 //! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
 
-use crate::{MaybePath, path_def_id, sym};
+use crate::res::MaybeQPath;
+use crate::sym;
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::Namespace::{MacroNS, TypeNS, ValueNS};
@@ -96,8 +97,11 @@ pub fn matches<'tcx>(&self, tcx: &impl HasTyCtxt<'tcx>, def_id: DefId) -> bool {
     }
 
     /// Resolves `maybe_path` to a [`DefId`] and checks if the [`PathLookup`] matches it
-    pub fn matches_path<'tcx>(&self, cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> bool {
-        path_def_id(cx, maybe_path).is_some_and(|def_id| self.matches(cx, def_id))
+    pub fn matches_path<'tcx>(&self, cx: &LateContext<'_>, maybe_path: impl MaybeQPath<'tcx>) -> bool {
+        maybe_path
+            .res(cx)
+            .opt_def_id()
+            .is_some_and(|def_id| self.matches(cx, def_id))
     }
 
     /// Checks if the path resolves to `ty`'s definition, must be an `Adt`
@@ -127,11 +131,6 @@ macro_rules! $name {
     macro_path: PathNS::Macro,
 }
 
-pub static F16_CONSTS: PathLookup = type_path!(core::f16::consts);
-pub static F32_CONSTS: PathLookup = type_path!(core::f32::consts);
-pub static F64_CONSTS: PathLookup = type_path!(core::f64::consts);
-pub static F128_CONSTS: PathLookup = type_path!(core::f128::consts);
-
 // Paths in external crates
 pub static FUTURES_IO_ASYNCREADEXT: PathLookup = type_path!(futures_util::AsyncReadExt);
 pub static FUTURES_IO_ASYNCWRITEEXT: PathLookup = type_path!(futures_util::AsyncWriteExt);
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 b9027fe..7722beb 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
@@ -232,9 +232,7 @@ fn check_statement<'tcx>(
 
         StatementKind::FakeRead(box (_, place)) => check_place(cx, *place, span, body, msrv),
         // just an assignment
-        StatementKind::SetDiscriminant { place, .. } => {
-            check_place(cx, **place, span, body, msrv)
-        },
+        StatementKind::SetDiscriminant { place, .. } => check_place(cx, **place, span, body, msrv),
 
         StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(cx, op, span, body, msrv),
 
diff --git a/src/tools/clippy/clippy_utils/src/res.rs b/src/tools/clippy/clippy_utils/src/res.rs
new file mode 100644
index 0000000..90b95292
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/res.rs
@@ -0,0 +1,643 @@
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{
+    self as hir, Expr, ExprKind, HirId, LangItem, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, TyKind,
+};
+use rustc_lint::LateContext;
+use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::ty::{AdtDef, AdtKind, Binder, EarlyBinder, Ty, TypeckResults};
+use rustc_span::{Ident, Symbol};
+
+/// Either a `HirId` or a type which can be identified by one.
+pub trait HasHirId: Copy {
+    fn hir_id(self) -> HirId;
+}
+impl HasHirId for HirId {
+    #[inline]
+    fn hir_id(self) -> HirId {
+        self
+    }
+}
+impl HasHirId for &Expr<'_> {
+    #[inline]
+    fn hir_id(self) -> HirId {
+        self.hir_id
+    }
+}
+
+type DefRes = (DefKind, DefId);
+
+pub trait MaybeTypeckRes<'tcx> {
+    /// Gets the contained `TypeckResults`.
+    ///
+    /// With debug assertions enabled this will always return `Some`. `None` is
+    /// only returned so logic errors can be handled by not emitting a lint on
+    /// release builds.
+    fn typeck_res(&self) -> Option<&TypeckResults<'tcx>>;
+
+    /// Gets the type-dependent resolution of the specified node.
+    ///
+    /// With debug assertions enabled this will always return `Some`. `None` is
+    /// only returned so logic errors can be handled by not emitting a lint on
+    /// release builds.
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    fn ty_based_def(&self, node: impl HasHirId) -> Option<DefRes> {
+        #[inline]
+        #[cfg_attr(debug_assertions, track_caller)]
+        fn f(typeck: &TypeckResults<'_>, id: HirId) -> Option<DefRes> {
+            if typeck.hir_owner == id.owner {
+                let def = typeck.type_dependent_def(id);
+                debug_assert!(
+                    def.is_some(),
+                    "attempted type-dependent lookup for a node with no definition\
+                        \n  node `{id:?}`",
+                );
+                def
+            } else {
+                debug_assert!(
+                    false,
+                    "attempted type-dependent lookup for a node in the wrong body\
+                        \n  in body `{:?}`\
+                        \n  expected body `{:?}`",
+                    typeck.hir_owner, id.owner,
+                );
+                None
+            }
+        }
+        self.typeck_res().and_then(|typeck| f(typeck, node.hir_id()))
+    }
+}
+impl<'tcx> MaybeTypeckRes<'tcx> for LateContext<'tcx> {
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    fn typeck_res(&self) -> Option<&TypeckResults<'tcx>> {
+        if let Some(typeck) = self.maybe_typeck_results() {
+            Some(typeck)
+        } else {
+            // It's possible to get the `TypeckResults` for any other body, but
+            // attempting to lookup the type of something across bodies like this
+            // is a good indication of a bug.
+            debug_assert!(false, "attempted type-dependent lookup in a non-body context");
+            None
+        }
+    }
+}
+impl<'tcx> MaybeTypeckRes<'tcx> for TypeckResults<'tcx> {
+    #[inline]
+    fn typeck_res(&self) -> Option<&TypeckResults<'tcx>> {
+        Some(self)
+    }
+}
+
+/// A `QPath` with the `HirId` of the node containing it.
+type QPathId<'tcx> = (&'tcx QPath<'tcx>, HirId);
+
+/// A HIR node which might be a `QPath`.
+pub trait MaybeQPath<'a>: Copy {
+    /// If this node is a path gets both the contained path and the `HirId` to
+    /// use for type dependant lookup.
+    fn opt_qpath(self) -> Option<QPathId<'a>>;
+
+    /// If this node is a `QPath::LangItem` gets the item it resolves to.
+    #[inline]
+    fn opt_lang_path(self) -> Option<LangItem> {
+        match self.opt_qpath() {
+            Some((&QPath::LangItem(item, _), _)) => Some(item),
+            _ => None,
+        }
+    }
+
+    /// If this is a path gets its resolution. Returns `Res::Err` otherwise.
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    fn res<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Res {
+        #[cfg_attr(debug_assertions, track_caller)]
+        fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>) -> Res {
+            match *qpath {
+                QPath::Resolved(_, p) => p.res,
+                QPath::TypeRelative(..) | QPath::LangItem(..) if let Some((kind, id)) = typeck.ty_based_def(id) => {
+                    Res::Def(kind, id)
+                },
+                QPath::TypeRelative(..) | QPath::LangItem(..) => Res::Err,
+            }
+        }
+        match self.opt_qpath() {
+            Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck),
+            _ => Res::Err,
+        }
+    }
+
+    /// If this is a path with the specified name as its final segment gets its
+    /// resolution. Returns `Res::Err` otherwise.
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    fn res_if_named<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>, name: Symbol) -> Res {
+        #[cfg_attr(debug_assertions, track_caller)]
+        fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>, name: Symbol) -> Res {
+            match *qpath {
+                QPath::Resolved(_, p)
+                    if let [.., seg] = p.segments
+                        && seg.ident.name == name =>
+                {
+                    p.res
+                },
+                QPath::TypeRelative(_, seg)
+                    if seg.ident.name == name
+                        && let Some((kind, id)) = typeck.ty_based_def(id) =>
+                {
+                    Res::Def(kind, id)
+                },
+                QPath::Resolved(..) | QPath::TypeRelative(..) | QPath::LangItem(..) => Res::Err,
+            }
+        }
+        match self.opt_qpath() {
+            Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck, name),
+            _ => Res::Err,
+        }
+    }
+
+    /// If this is a path gets both its resolution and final segment.
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    fn res_with_seg<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> (Res, Option<&'a PathSegment<'a>>) {
+        #[cfg_attr(debug_assertions, track_caller)]
+        fn f<'a>(qpath: &QPath<'a>, id: HirId, typeck: &TypeckResults<'_>) -> (Res, Option<&'a PathSegment<'a>>) {
+            match *qpath {
+                QPath::Resolved(_, p) if let [.., seg] = p.segments => (p.res, Some(seg)),
+                QPath::TypeRelative(_, seg) if let Some((kind, id)) = typeck.ty_based_def(id) => {
+                    (Res::Def(kind, id), Some(seg))
+                },
+                QPath::Resolved(..) | QPath::TypeRelative(..) | QPath::LangItem(..) => (Res::Err, None),
+            }
+        }
+        match self.opt_qpath() {
+            Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck),
+            _ => (Res::Err, None),
+        }
+    }
+
+    /// If this is a path without an explicit `Self` type gets its resolution.
+    /// Returns `Res::Err` otherwise.
+    ///
+    /// Only paths to trait items can optionally contain a `Self` type.
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    fn typeless_res<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Res {
+        #[cfg_attr(debug_assertions, track_caller)]
+        fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>) -> Res {
+            match *qpath {
+                QPath::Resolved(
+                    None
+                    | Some(&hir::Ty {
+                        kind: TyKind::Infer(()),
+                        ..
+                    }),
+                    p,
+                ) => p.res,
+                QPath::TypeRelative(
+                    &hir::Ty {
+                        kind: TyKind::Infer(()),
+                        ..
+                    },
+                    _,
+                ) if let Some((kind, id)) = typeck.ty_based_def(id) => Res::Def(kind, id),
+                QPath::Resolved(..) | QPath::TypeRelative(..) | QPath::LangItem(..) => Res::Err,
+            }
+        }
+        match self.opt_qpath() {
+            Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck),
+            _ => Res::Err,
+        }
+    }
+
+    /// If this is a path without an explicit `Self` type to an item with the
+    /// specified name gets its resolution. Returns `Res::Err` otherwise.
+    ///
+    /// Only paths to trait items can optionally contain a `Self` type.
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    fn typeless_res_if_named<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>, name: Symbol) -> Res {
+        #[cfg_attr(debug_assertions, track_caller)]
+        fn f(qpath: &QPath<'_>, id: HirId, typeck: &TypeckResults<'_>, name: Symbol) -> Res {
+            match *qpath {
+                QPath::Resolved(
+                    None
+                    | Some(&hir::Ty {
+                        kind: TyKind::Infer(()),
+                        ..
+                    }),
+                    p,
+                ) if let [.., seg] = p.segments
+                    && seg.ident.name == name =>
+                {
+                    p.res
+                },
+                QPath::TypeRelative(
+                    &hir::Ty {
+                        kind: TyKind::Infer(()),
+                        ..
+                    },
+                    seg,
+                ) if seg.ident.name == name
+                    && let Some((kind, id)) = typeck.ty_based_def(id) =>
+                {
+                    Res::Def(kind, id)
+                },
+                QPath::Resolved(..) | QPath::TypeRelative(..) | QPath::LangItem(..) => Res::Err,
+            }
+        }
+        match self.opt_qpath() {
+            Some((qpath, id)) if let Some(typeck) = typeck.typeck_res() => f(qpath, id, typeck, name),
+            _ => Res::Err,
+        }
+    }
+
+    /// If this is a type-relative path gets the definition it resolves to.
+    ///
+    /// Only inherent associated items require a type-relative path.
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    fn ty_rel_def<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Option<DefRes> {
+        match self.opt_qpath() {
+            Some((QPath::TypeRelative(..), id)) => typeck.ty_based_def(id),
+            _ => None,
+        }
+    }
+
+    /// If this is a type-relative path to an item with the specified name gets
+    /// the definition it resolves to.
+    ///
+    /// Only inherent associated items require a type-relative path.
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    fn ty_rel_def_if_named<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>, name: Symbol) -> Option<DefRes> {
+        match self.opt_qpath() {
+            Some((&QPath::TypeRelative(_, seg), id)) if seg.ident.name == name => typeck.ty_based_def(id),
+            _ => None,
+        }
+    }
+
+    /// If this is a type-relative path gets the definition it resolves to and
+    /// its final segment.
+    ///
+    /// Only inherent associated items require a type-relative path.
+    #[inline]
+    #[cfg_attr(debug_assertions, track_caller)]
+    fn ty_rel_def_with_seg<'tcx>(self, typeck: &impl MaybeTypeckRes<'tcx>) -> Option<(DefRes, &'a PathSegment<'a>)> {
+        match self.opt_qpath() {
+            Some((QPath::TypeRelative(_, seg), id)) if let Some(def) = typeck.ty_based_def(id) => Some((def, seg)),
+            _ => None,
+        }
+    }
+}
+
+impl<'tcx> MaybeQPath<'tcx> for QPathId<'tcx> {
+    #[inline]
+    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
+        Some((self.0, self.1))
+    }
+}
+impl<'tcx> MaybeQPath<'tcx> for &'tcx Expr<'_> {
+    #[inline]
+    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
+        match &self.kind {
+            ExprKind::Path(qpath) => Some((qpath, self.hir_id)),
+            _ => None,
+        }
+    }
+}
+impl<'tcx> MaybeQPath<'tcx> for &'tcx PatExpr<'_> {
+    #[inline]
+    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
+        match &self.kind {
+            PatExprKind::Path(qpath) => Some((qpath, self.hir_id)),
+            _ => None,
+        }
+    }
+}
+impl<'tcx, AmbigArg> MaybeQPath<'tcx> for &'tcx hir::Ty<'_, AmbigArg> {
+    #[inline]
+    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
+        match &self.kind {
+            TyKind::Path(qpath) => Some((qpath, self.hir_id)),
+            _ => None,
+        }
+    }
+}
+impl<'tcx> MaybeQPath<'tcx> for &'_ Pat<'tcx> {
+    #[inline]
+    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
+        match self.kind {
+            PatKind::Expr(e) => e.opt_qpath(),
+            _ => None,
+        }
+    }
+}
+impl<'tcx, T: MaybeQPath<'tcx>> MaybeQPath<'tcx> for Option<T> {
+    #[inline]
+    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
+        self.and_then(T::opt_qpath)
+    }
+}
+impl<'tcx, T: Copy + MaybeQPath<'tcx>> MaybeQPath<'tcx> for &Option<T> {
+    #[inline]
+    fn opt_qpath(self) -> Option<QPathId<'tcx>> {
+        self.and_then(T::opt_qpath)
+    }
+}
+
+/// A resolved path and the explicit `Self` type if there is one.
+type OptResPath<'tcx> = (Option<&'tcx hir::Ty<'tcx>>, Option<&'tcx Path<'tcx>>);
+
+/// A HIR node which might be a `QPath::Resolved`.
+///
+/// The following are resolved paths:
+/// * A path to a module or crate item.
+/// * A path to a trait item via the trait's name.
+/// * A path to a struct or variant constructor via the original type's path.
+/// * A local.
+///
+/// All other paths are `TypeRelative` and require using `PathRes` to lookup the
+/// resolution.
+pub trait MaybeResPath<'a>: Copy {
+    /// If this node is a resolved path gets both the contained path and the
+    /// type associated with it.
+    fn opt_res_path(self) -> OptResPath<'a>;
+
+    /// If this node is a resolved path gets it's resolution. Returns `Res::Err`
+    /// otherwise.
+    #[inline]
+    fn basic_res(self) -> &'a Res {
+        self.opt_res_path().1.map_or(&Res::Err, |p| &p.res)
+    }
+
+    /// If this node is a path to a local gets the local's `HirId`.
+    #[inline]
+    fn res_local_id(self) -> Option<HirId> {
+        if let (_, Some(p)) = self.opt_res_path()
+            && let Res::Local(id) = p.res
+        {
+            Some(id)
+        } else {
+            None
+        }
+    }
+
+    /// If this node is a path to a local gets the local's `HirId` and identifier.
+    fn res_local_id_and_ident(self) -> Option<(HirId, &'a Ident)> {
+        if let (_, Some(p)) = self.opt_res_path()
+            && let Res::Local(id) = p.res
+            && let [seg] = p.segments
+        {
+            Some((id, &seg.ident))
+        } else {
+            None
+        }
+    }
+}
+impl<'a> MaybeResPath<'a> for &'a Path<'a> {
+    #[inline]
+    fn opt_res_path(self) -> OptResPath<'a> {
+        (None, Some(self))
+    }
+
+    #[inline]
+    fn basic_res(self) -> &'a Res {
+        &self.res
+    }
+}
+impl<'a> MaybeResPath<'a> for &QPath<'a> {
+    #[inline]
+    fn opt_res_path(self) -> OptResPath<'a> {
+        match *self {
+            QPath::Resolved(ty, path) => (ty, Some(path)),
+            _ => (None, None),
+        }
+    }
+}
+impl<'a> MaybeResPath<'a> for &Expr<'a> {
+    #[inline]
+    fn opt_res_path(self) -> OptResPath<'a> {
+        match &self.kind {
+            ExprKind::Path(qpath) => qpath.opt_res_path(),
+            _ => (None, None),
+        }
+    }
+}
+impl<'a> MaybeResPath<'a> for &PatExpr<'a> {
+    #[inline]
+    fn opt_res_path(self) -> OptResPath<'a> {
+        match &self.kind {
+            PatExprKind::Path(qpath) => qpath.opt_res_path(),
+            _ => (None, None),
+        }
+    }
+}
+impl<'a, AmbigArg> MaybeResPath<'a> for &hir::Ty<'a, AmbigArg> {
+    #[inline]
+    fn opt_res_path(self) -> OptResPath<'a> {
+        match &self.kind {
+            TyKind::Path(qpath) => qpath.opt_res_path(),
+            _ => (None, None),
+        }
+    }
+}
+impl<'a> MaybeResPath<'a> for &Pat<'a> {
+    #[inline]
+    fn opt_res_path(self) -> OptResPath<'a> {
+        match self.kind {
+            PatKind::Expr(e) => e.opt_res_path(),
+            _ => (None, None),
+        }
+    }
+}
+impl<'a, T: MaybeResPath<'a>> MaybeResPath<'a> for Option<T> {
+    #[inline]
+    fn opt_res_path(self) -> OptResPath<'a> {
+        match self {
+            Some(x) => T::opt_res_path(x),
+            None => (None, None),
+        }
+    }
+
+    #[inline]
+    fn basic_res(self) -> &'a Res {
+        self.map_or(&Res::Err, T::basic_res)
+    }
+}
+
+/// A type which may either contain a `DefId` or be referred to by a `DefId`.
+pub trait MaybeDef: Copy {
+    fn opt_def_id(self) -> Option<DefId>;
+
+    /// Gets this definition's id and kind. This will lookup the kind in the def
+    /// tree if needed.
+    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)>;
+
+    /// Gets the diagnostic name of this definition if it has one.
+    #[inline]
+    fn opt_diag_name<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<Symbol> {
+        self.opt_def_id().and_then(|id| tcx.tcx().get_diagnostic_name(id))
+    }
+
+    /// Checks if this definition has the specified diagnostic name.
+    #[inline]
+    fn is_diag_item<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>, name: Symbol) -> bool {
+        self.opt_def_id()
+            .is_some_and(|id| tcx.tcx().is_diagnostic_item(name, id))
+    }
+
+    /// Checks if this definition is the specified `LangItem`.
+    #[inline]
+    fn is_lang_item<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>, item: LangItem) -> bool {
+        self.opt_def_id()
+            .is_some_and(|id| tcx.tcx().lang_items().get(item) == Some(id))
+    }
+
+    /// If this definition is an impl block gets its type.
+    #[inline]
+    fn opt_impl_ty<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<EarlyBinder<'tcx, Ty<'tcx>>> {
+        match self.opt_def(tcx) {
+            Some((DefKind::Impl { .. }, id)) => Some(tcx.tcx().type_of(id)),
+            _ => None,
+        }
+    }
+
+    /// Gets the parent of this definition if it has one.
+    #[inline]
+    fn opt_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
+        self.opt_def_id().and_then(|id| tcx.tcx().opt_parent(id))
+    }
+
+    /// Checks if this definition is an impl block.
+    #[inline]
+    fn is_impl<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> bool {
+        matches!(self.opt_def(tcx), Some((DefKind::Impl { .. }, _)))
+    }
+
+    /// If this definition is a constructor gets the `DefId` of it's type or variant.
+    #[inline]
+    fn ctor_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
+        match self.opt_def(tcx) {
+            Some((DefKind::Ctor(..), id)) => tcx.tcx().opt_parent(id),
+            _ => None,
+        }
+    }
+
+    /// If this definition is an associated item of an impl or trait gets the
+    /// `DefId` of its parent.
+    #[inline]
+    fn assoc_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
+        match self.opt_def(tcx) {
+            Some((DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, id)) => tcx.tcx().opt_parent(id),
+            _ => None,
+        }
+    }
+
+    /// If this definition is an associated function of an impl or trait gets the
+    /// `DefId` of its parent.
+    #[inline]
+    fn assoc_fn_parent<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<DefId> {
+        match self.opt_def(tcx) {
+            Some((DefKind::AssocFn, id)) => tcx.tcx().opt_parent(id),
+            _ => None,
+        }
+    }
+}
+impl MaybeDef for DefId {
+    #[inline]
+    fn opt_def_id(self) -> Option<DefId> {
+        Some(self)
+    }
+
+    #[inline]
+    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
+        self.opt_def_id().map(|id| (tcx.tcx().def_kind(id), id))
+    }
+}
+impl MaybeDef for (DefKind, DefId) {
+    #[inline]
+    fn opt_def_id(self) -> Option<DefId> {
+        Some(self.1)
+    }
+
+    #[inline]
+    fn opt_def<'tcx>(self, _: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
+        Some(self)
+    }
+}
+impl MaybeDef for AdtDef<'_> {
+    #[inline]
+    fn opt_def_id(self) -> Option<DefId> {
+        Some(self.did())
+    }
+
+    #[inline]
+    fn opt_def<'tcx>(self, _: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
+        let did = self.did();
+        match self.adt_kind() {
+            AdtKind::Enum => Some((DefKind::Enum, did)),
+            AdtKind::Struct => Some((DefKind::Struct, did)),
+            AdtKind::Union => Some((DefKind::Union, did)),
+        }
+    }
+}
+impl MaybeDef for Ty<'_> {
+    #[inline]
+    fn opt_def_id(self) -> Option<DefId> {
+        self.ty_adt_def().opt_def_id()
+    }
+
+    #[inline]
+    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
+        self.ty_adt_def().opt_def(tcx)
+    }
+}
+impl MaybeDef for Res {
+    #[inline]
+    fn opt_def_id(self) -> Option<DefId> {
+        Res::opt_def_id(&self)
+    }
+
+    #[inline]
+    fn opt_def<'tcx>(self, _: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
+        match self {
+            Res::Def(kind, id) => Some((kind, id)),
+            _ => None,
+        }
+    }
+}
+impl<T: MaybeDef> MaybeDef for Option<T> {
+    #[inline]
+    fn opt_def_id(self) -> Option<DefId> {
+        self.and_then(T::opt_def_id)
+    }
+
+    #[inline]
+    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
+        self.and_then(|x| T::opt_def(x, tcx))
+    }
+}
+impl<T: MaybeDef> MaybeDef for EarlyBinder<'_, T> {
+    #[inline]
+    fn opt_def_id(self) -> Option<DefId> {
+        self.skip_binder().opt_def_id()
+    }
+
+    #[inline]
+    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
+        self.skip_binder().opt_def(tcx)
+    }
+}
+impl<T: MaybeDef> MaybeDef for Binder<'_, T> {
+    #[inline]
+    fn opt_def_id(self) -> Option<DefId> {
+        self.skip_binder().opt_def_id()
+    }
+
+    #[inline]
+    fn opt_def<'tcx>(self, tcx: &impl HasTyCtxt<'tcx>) -> Option<(DefKind, DefId)> {
+        self.skip_binder().opt_def(tcx)
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 638d329..83d7f6b 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -143,7 +143,6 @@ fn map_range(
         map_range(cx.sess().source_map(), self.into_range(), f)
     }
 
-    #[allow(rustdoc::invalid_rust_codeblocks, reason = "The codeblock is intentionally broken")]
     /// Extends the range to include all preceding whitespace characters.
     ///
     /// The range will not be expanded if it would cross a line boundary, the line the range would
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index a63333c..581c2b0 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -33,7 +33,7 @@ pub enum Sugg<'a> {
     /// or `-`, but only if the type with and without the operator is kept identical.
     /// It means that doubling the operator can be used to remove it instead, in
     /// order to provide better suggestions.
-    UnOp(UnOp, Box<Sugg<'a>>),
+    UnOp(UnOp, Box<Self>),
 }
 
 /// Literal constant `0`, for convenience.
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 2d0d4a5..8e8a80a 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -34,6 +34,7 @@ macro_rules! generate {
 //
 // `cargo dev fmt` ensures that the content of the `generate!()` macro call stays sorted.
 generate! {
+    Applicability,
     AsyncReadExt,
     AsyncWriteExt,
     BACKSLASH_SINGLE_QUOTE: r"\'",
@@ -45,10 +46,12 @@ macro_rules! generate {
     Current,
     DOUBLE_QUOTE: "\"",
     Deserialize,
+    EarlyContext,
     EarlyLintPass,
     IntoIter,
     Itertools,
     LF: "\n",
+    LateContext,
     Lazy,
     Lint,
     LowerExp,
@@ -75,7 +78,9 @@ macro_rules! generate {
     Weak,
     abs,
     ambiguous_glob_reexports,
+    app,
     append,
+    applicability,
     arg,
     as_bytes,
     as_deref,
@@ -115,7 +120,6 @@ macro_rules! generate {
     collapsible_if,
     collect,
     const_ptr,
-    consts,
     contains,
     copied,
     copy_from,
@@ -125,6 +129,7 @@ macro_rules! generate {
     count_ones,
     create,
     create_new,
+    cx,
     cycle,
     cyclomatic_complexity,
     de,
@@ -176,6 +181,7 @@ macro_rules! generate {
     hidden_glob_reexports,
     hygiene,
     insert,
+    insert_str,
     inspect,
     int_roundings,
     into,
@@ -259,12 +265,14 @@ macro_rules! generate {
     powi,
     product,
     push,
+    push_str,
     read,
     read_exact,
     read_line,
     read_to_end,
     read_to_string,
     read_unaligned,
+    read_volatile,
     redundant_imports,
     redundant_pub_crate,
     regex,
@@ -286,8 +294,10 @@ macro_rules! generate {
     rsplit_terminator,
     rsplitn,
     rsplitn_mut,
+    rustc_errors,
     rustc_lint,
     rustc_lint_defs,
+    rustc_middle,
     rustc_span,
     rustfmt_skip,
     rwlock,
@@ -330,6 +340,7 @@ macro_rules! generate {
     symbol,
     take,
     take_while,
+    tcx,
     then,
     then_some,
     to_ascii_lowercase,
@@ -374,6 +385,7 @@ macro_rules! generate {
     wrapping_offset,
     write,
     write_unaligned,
+    write_volatile,
     writeln,
     zip,
 }
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index ebf4f2c..a90d64e 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -3,7 +3,6 @@
 #![allow(clippy::module_name_repetitions)]
 
 use core::ops::ControlFlow;
-use itertools::Itertools;
 use rustc_abi::VariantIdx;
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -22,8 +21,8 @@
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, BoundVarIndexKind, FnSig, GenericArg,
-    GenericArgKind, GenericArgsRef, GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt,
-    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
+    GenericArgKind, GenericArgsRef, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
@@ -34,8 +33,8 @@
 use std::collections::hash_map::Entry;
 use std::{iter, mem};
 
-use crate::path_res;
 use crate::paths::{PathNS, lookup_path_str};
+use crate::res::{MaybeDef, MaybeQPath};
 
 mod type_certainty;
 pub use type_certainty::expr_type_is_certain;
@@ -157,20 +156,6 @@ pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Optio
         .and_then(|iter_did| cx.get_associated_type(ty, iter_did, sym::Item))
 }
 
-/// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type
-/// implements a trait marked with a diagnostic item use [`implements_trait`].
-///
-/// For a further exploitation what diagnostic items are see [diagnostic items] in
-/// rustc-dev-guide.
-///
-/// [Diagnostic Items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
-pub fn get_type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<Symbol> {
-    match ty.kind() {
-        ty::Adt(adt, _) => cx.tcx.get_diagnostic_name(adt.did()),
-        _ => None,
-    }
-}
-
 /// Returns true if `ty` is a type on which calling `Clone` through a function instead of
 /// as a method, such as `Arc::clone()` is considered idiomatic.
 ///
@@ -178,7 +163,7 @@ pub fn get_type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<Symb
 /// of those types.
 pub fn should_call_clone_as_function(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     matches!(
-        get_type_diagnostic_name(cx, ty),
+        ty.opt_diag_name(cx),
         Some(sym::Arc | sym::ArcWeak | sym::Rc | sym::RcWeak)
     )
 }
@@ -379,42 +364,6 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
     }
 }
 
-/// Checks if the type is a reference equals to a diagnostic item
-pub fn is_type_ref_to_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
-    match ty.kind() {
-        ty::Ref(_, ref_ty, _) => is_type_diagnostic_item(cx, *ref_ty, diag_item),
-        _ => false,
-    }
-}
-
-/// Checks if the type is equal to a diagnostic item. To check if a type implements a
-/// trait marked with a diagnostic item use [`implements_trait`].
-///
-/// For a further exploitation what diagnostic items are see [diagnostic items] in
-/// rustc-dev-guide.
-///
-/// ---
-///
-/// If you change the signature, remember to update the internal lint `MatchTypeOnDiagItem`
-///
-/// [Diagnostic Items]: https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-items.html
-pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symbol) -> bool {
-    match ty.kind() {
-        ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(diag_item, adt.did()),
-        _ => false,
-    }
-}
-
-/// Checks if the type is equal to a lang item.
-///
-/// Returns `false` if the `LangItem` is not defined.
-pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: LangItem) -> bool {
-    match ty.kind() {
-        ty::Adt(adt, _) => cx.tcx.lang_items().get(lang_item) == Some(adt.did()),
-        _ => false,
-    }
-}
-
 /// Return `true` if the passed `typ` is `isize` or `usize`.
 pub fn is_isize_or_usize(typ: Ty<'_>) -> bool {
     matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
@@ -433,9 +382,9 @@ fn needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &m
             false
         }
         // Check for std types which implement drop, but only for memory allocation.
-        else if is_type_lang_item(cx, ty, LangItem::OwnedBox)
+        else if ty.is_lang_item(cx, LangItem::OwnedBox)
             || matches!(
-                get_type_diagnostic_name(cx, ty),
+                ty.opt_diag_name(cx),
                 Some(sym::HashSet | sym::Rc | sym::Arc | sym::cstring_type | sym::RcWeak | sym::ArcWeak)
             )
         {
@@ -628,7 +577,7 @@ pub fn predicates_id(&self) -> Option<DefId> {
 
 /// If the expression is function like, get the signature for it.
 pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
-    if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) {
+    if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = expr.res(cx) {
         Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).instantiate_identity(), Some(id)))
     } else {
         ty_sig(cx, cx.typeck_results().expr_ty_adjusted(expr).peel_refs())
@@ -953,9 +902,10 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
     }
 }
 
+#[cfg(debug_assertions)]
 /// Asserts that the given arguments match the generic parameters of the given item.
-#[allow(dead_code)]
 fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[GenericArg<'tcx>]) {
+    use itertools::Itertools;
     let g = tcx.generics_of(did);
     let parent = g.parent.map(|did| tcx.generics_of(did));
     let count = g.parent_count + g.own_params.len();
@@ -971,7 +921,7 @@ fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[Generi
             note: the expected arguments are: `[{}]`\n\
             the given arguments are: `{args:#?}`",
         args.len(),
-        params.clone().map(GenericParamDefKind::descr).format(", "),
+        params.clone().map(ty::GenericParamDefKind::descr).format(", "),
     );
 
     if let Some((idx, (param, arg))) =
@@ -980,13 +930,13 @@ fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[Generi
             .zip(args.iter().map(|&x| x.kind()))
             .enumerate()
             .find(|(_, (param, arg))| match (param, arg) {
-                (GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
-                | (GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
-                | (GenericParamDefKind::Const { .. }, GenericArgKind::Const(_)) => false,
+                (ty::GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
+                | (ty::GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
+                | (ty::GenericParamDefKind::Const { .. }, GenericArgKind::Const(_)) => false,
                 (
-                    GenericParamDefKind::Lifetime
-                    | GenericParamDefKind::Type { .. }
-                    | GenericParamDefKind::Const { .. },
+                    ty::GenericParamDefKind::Lifetime
+                    | ty::GenericParamDefKind::Type { .. }
+                    | ty::GenericParamDefKind::Const { .. },
                     _,
                 ) => true,
             })
@@ -996,7 +946,7 @@ fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[Generi
                 note: the expected arguments are `[{}]`\n\
                 the given arguments are `{args:#?}`",
             param.descr(),
-            params.clone().map(GenericParamDefKind::descr).format(", "),
+            params.clone().map(ty::GenericParamDefKind::descr).format(", "),
         );
     }
 }
@@ -1299,11 +1249,14 @@ pub fn get_field_by_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) ->
 
 /// Check if `ty` is an `Option` and return its argument type if it is.
 pub fn option_arg_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
-    match ty.kind() {
-        ty::Adt(adt, args) => cx
-            .tcx
-            .is_diagnostic_item(sym::Option, adt.did())
-            .then(|| args.type_at(0)),
+    match *ty.kind() {
+        ty::Adt(adt, args)
+            if let [arg] = &**args
+                && let Some(arg) = arg.as_type()
+                && adt.is_diag_item(cx, sym::Option) =>
+        {
+            Some(arg)
+        },
         _ => None,
     }
 }
@@ -1357,7 +1310,7 @@ fn has_non_owning_mutable_access_inner<'tcx>(
 
 /// Check if `ty` is slice-like, i.e., `&[T]`, `[T; N]`, or `Vec<T>`.
 pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    ty.is_slice() || ty.is_array() || is_type_diagnostic_item(cx, ty, sym::Vec)
+    ty.is_slice() || ty.is_array() || ty.is_diag_item(cx, sym::Vec)
 }
 
 pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option<usize> {
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index d9c7e6e..d46c7bd 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -329,7 +329,7 @@ fn update_res(
     None
 }
 
-#[allow(clippy::cast_possible_truncation)]
+#[expect(clippy::cast_possible_truncation)]
 fn type_is_inferable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let Some(callee_def_id) = (match expr.kind {
         ExprKind::Call(callee, _) => {
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 6eccbcd..e27f1da 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -1,4 +1,5 @@
 use crate::macros::root_macro_call_first_node;
+use crate::res::MaybeResPath;
 use crate::visitors::{Descend, Visitable, for_each_expr, for_each_expr_without_closures};
 use crate::{self as utils, get_enclosing_loop_or_multi_call_closure};
 use core::ops::ControlFlow;
@@ -196,7 +197,7 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
 
 pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool {
     for_each_expr(cx, v, |e| {
-        if utils::path_to_local_id(e, local_id) {
+        if e.res_local_id() == Some(local_id) {
             ControlFlow::Break(())
         } else {
             ControlFlow::Continue(())
@@ -222,7 +223,7 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr
     let mut past_expr = false;
     for_each_expr(cx, block, |e| {
         if past_expr {
-            if utils::path_to_local_id(e, local_id) {
+            if e.res_local_id() == Some(local_id) {
                 ControlFlow::Break(())
             } else {
                 ControlFlow::Continue(Descend::Yes)
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index c9f5401..84e4f04 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -1,7 +1,8 @@
+use crate::get_enclosing_block;
 use crate::msrvs::Msrv;
 use crate::qualify_min_const_fn::is_stable_const_fn;
+use crate::res::MaybeResPath;
 use crate::ty::needs_ordered_drop;
-use crate::{get_enclosing_block, path_to_local_id};
 use core::ops::ControlFlow;
 use rustc_ast::visit::{VisitorResult, try_visit};
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -312,7 +313,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
 /// Checks if the given local is used.
 pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool {
     for_each_expr(cx, visitable, |e| {
-        if path_to_local_id(e, id) {
+        if e.res_local_id() == Some(id) {
             ControlFlow::Break(())
         } else {
             ControlFlow::Continue(())
@@ -564,7 +565,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
             if self.res.is_break() {
                 return;
             }
-            if path_to_local_id(e, self.local_id) {
+            if e.res_local_id() == Some(self.local_id) {
                 self.res = (self.f)(e);
             } else {
                 walk_expr(self, e);
@@ -591,7 +592,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
 // Calls the given function for every unconsumed temporary created by the expression. Note the
 // function is only guaranteed to be called for types which need to be dropped, but it may be called
 // for other types.
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 pub fn for_each_unconsumed_temporary<'tcx, B>(
     cx: &LateContext<'tcx>,
     e: &'tcx Expr<'tcx>,
@@ -740,7 +741,7 @@ fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
         fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
             if let ExprKind::Assign(lhs, rhs, _) = e.kind
                 && self.res.is_continue()
-                && path_to_local_id(lhs, self.local_id)
+                && lhs.res_local_id() == Some(self.local_id)
             {
                 self.res = (self.f)(rhs);
                 self.visit_expr(rhs);
@@ -785,7 +786,7 @@ pub fn local_used_once<'tcx>(
     let mut expr = None;
 
     let cf = for_each_expr(cx, visitable, |e| {
-        if path_to_local_id(e, id) && expr.replace(e).is_some() {
+        if e.res_local_id() == Some(id) && expr.replace(e).is_some() {
             ControlFlow::Break(())
         } else {
             ControlFlow::Continue(())
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index 3b2ebf0..5d52148 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -2,7 +2,7 @@
 use std::num::NonZero;
 use std::path::PathBuf;
 
-#[allow(clippy::struct_excessive_bools)]
+#[expect(clippy::struct_excessive_bools)]
 #[derive(Parser, Clone, Debug)]
 #[command(args_conflicts_with_subcommands = true)]
 pub(crate) struct LintcheckConfig {
diff --git a/src/tools/clippy/lintcheck/src/input.rs b/src/tools/clippy/lintcheck/src/input.rs
index 1ed059d..7dda2b7 100644
--- a/src/tools/clippy/lintcheck/src/input.rs
+++ b/src/tools/clippy/lintcheck/src/input.rs
@@ -180,7 +180,7 @@ pub fn download_and_prepare(&self) -> Crate {
     /// copies a local folder
     #[expect(clippy::too_many_lines)]
     fn download_and_extract(&self) -> Crate {
-        #[allow(clippy::result_large_err)]
+        #[expect(clippy::result_large_err)]
         fn get(path: &str) -> Result<ureq::Response, ureq::Error> {
             const MAX_RETRIES: u8 = 4;
             let mut retries = 0;
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 3a60cfa..b30df79 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -66,7 +66,7 @@ struct Crate {
 impl Crate {
     /// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy
     /// issued
-    #[allow(clippy::too_many_arguments, clippy::too_many_lines)]
+    #[expect(clippy::too_many_lines)]
     fn run_clippy_lints(
         &self,
         clippy_driver_path: &Path,
@@ -314,7 +314,7 @@ fn main() {
     }
 }
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 fn lintcheck(config: LintcheckConfig) {
     let clippy_ver = build_clippy(config.perf);
     let clippy_driver_path = fs::canonicalize(format!(
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index e936f5d..d5d9644 100644
--- a/src/tools/clippy/rust-toolchain.toml
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2025-10-06"
+channel = "nightly-2025-10-16"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 6bddcbf..102ca3f 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -133,8 +133,7 @@ struct ClippyCallbacks {
 }
 
 impl rustc_driver::Callbacks for ClippyCallbacks {
-    // JUSTIFICATION: necessary in clippy driver to set `mir_opt_level`
-    #[allow(rustc::bad_opt_access)]
+    #[expect(rustc::bad_opt_access, reason = "necessary in clippy driver to set `mir_opt_level`")]
     fn config(&mut self, config: &mut interface::Config) {
         let conf_path = clippy_config::lookup_conf_file();
         let previous = config.register_lints.take();
@@ -182,15 +181,13 @@ fn config(&mut self, config: &mut interface::Config) {
     }
 }
 
-#[allow(clippy::ignored_unit_patterns)]
 fn display_help() {
     println!("{}", help_message());
 }
 
 const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml";
 
-#[allow(clippy::too_many_lines)]
-#[allow(clippy::ignored_unit_patterns)]
+#[expect(clippy::too_many_lines)]
 pub fn main() {
     // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs
     // about jemalloc.
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index 3c2eec1..688161c 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -10,12 +10,10 @@
 
 use anstream::println;
 
-#[allow(clippy::ignored_unit_patterns)]
 fn show_help() {
     println!("{}", help_message());
 }
 
-#[allow(clippy::ignored_unit_patterns)]
 fn show_version() {
     let version_info = rustc_tools_util::get_version_info!();
     println!("{version_info}");
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 71cd8a6..1ac6889 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -291,7 +291,6 @@ fn run_ui_toml(cx: &TestContext) {
 }
 
 // Allow `Default::default` as `OptWithSpan` is not nameable
-#[allow(clippy::default_trait_access)]
 fn run_ui_cargo(cx: &TestContext) {
     if IS_RUSTC_TEST_SUITE {
         return;
@@ -473,7 +472,7 @@ struct DiagnosticCollector {
 }
 
 impl DiagnosticCollector {
-    #[allow(clippy::assertions_on_constants)]
+    #[expect(clippy::assertions_on_constants)]
     fn spawn() -> (Self, thread::JoinHandle<()>) {
         assert!(!IS_RUSTC_TEST_SUITE && !RUN_INTERNAL_TESTS);
 
diff --git a/src/tools/clippy/tests/symbols-used.rs b/src/tools/clippy/tests/symbols-used.rs
index a1049ba..f78f151 100644
--- a/src/tools/clippy/tests/symbols-used.rs
+++ b/src/tools/clippy/tests/symbols-used.rs
@@ -18,7 +18,6 @@
 type AnyError = Box<dyn std::error::Error>;
 
 #[test]
-#[allow(clippy::case_sensitive_file_extension_comparisons)]
 fn all_symbols_are_used() -> Result<()> {
     if option_env!("RUSTC_TEST_SUITE").is_some() {
         return Ok(());
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/Cargo.stderr
new file mode 100644
index 0000000..51c46e4
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/Cargo.stderr
@@ -0,0 +1,7 @@
+error: error reading Clippy's configuration file: unknown variant `FooBar`, expected one of `crate`, `file`, `module`
+ --> $DIR/tests/ui-cargo/multiple_inherent_impl/config_fail/clippy.toml:1:28
+  |
+1 | inherent-impl-lint-scope = "FooBar"
+  |                            ^^^^^^^^
+
+error: could not compile `config_fail` (bin "config_fail") due to 1 previous error
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/Cargo.toml
new file mode 100644
index 0000000..0a4cb6e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "config_fail"
+version = "0.1.0"
+edition = "2024"
+publish = false
+
+[dependencies]
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/clippy.toml b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/clippy.toml
new file mode 100644
index 0000000..7ad4267
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/clippy.toml
@@ -0,0 +1 @@
+inherent-impl-lint-scope = "FooBar"
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/src/main.rs
new file mode 100644
index 0000000..7d5e783
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/config_fail/src/main.rs
@@ -0,0 +1,3 @@
+#![allow(dead_code)]
+#![deny(clippy::multiple_inherent_impl)]
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/Cargo.stderr
new file mode 100644
index 0000000..15e0086
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/Cargo.stderr
@@ -0,0 +1,57 @@
+error: multiple implementations of this structure
+  --> src/main.rs:11:1
+   |
+11 | / impl S {
+12 | |     //^ Must trigger
+13 | |     fn second() {}
+14 | | }
+   | |_^
+   |
+note: first implementation here
+  --> src/main.rs:7:1
+   |
+ 7 | / impl S {
+ 8 | |     fn first() {}
+ 9 | | }
+   | |_^
+note: the lint level is defined here
+  --> src/main.rs:2:9
+   |
+ 2 | #![deny(clippy::multiple_inherent_impl)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: multiple implementations of this structure
+  --> src/main.rs:22:5
+   |
+22 | /     impl T {
+23 | |         //^ Must trigger
+24 | |         fn second() {}
+25 | |     }
+   | |_____^
+   |
+note: first implementation here
+  --> src/main.rs:16:1
+   |
+16 | / impl T {
+17 | |     fn first() {}
+18 | | }
+   | |_^
+
+error: multiple implementations of this structure
+  --> src/main.rs:36:1
+   |
+36 | / impl b::T {
+37 | |     //^ Must trigger
+38 | |     fn second() {}
+39 | | }
+   | |_^
+   |
+note: first implementation here
+  --> src/b.rs:4:1
+   |
+ 4 | / impl T {
+ 5 | |     fn first() {}
+ 6 | | }
+   | |_^
+
+error: could not compile `crate_fail` (bin "crate_fail") due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/Cargo.toml
new file mode 100644
index 0000000..a280da1
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "crate_fail"
+version = "0.1.0"
+edition = "2024"
+publish = false
+
+[dependencies]
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/clippy.toml b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/clippy.toml
new file mode 100644
index 0000000..262e42e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/clippy.toml
@@ -0,0 +1 @@
+inherent-impl-lint-scope = "crate"
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/src/b.rs b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/src/b.rs
new file mode 100644
index 0000000..9d01e61
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/src/b.rs
@@ -0,0 +1,6 @@
+pub struct S;
+pub struct T;
+
+impl T {
+    fn first() {}
+}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/src/main.rs
new file mode 100644
index 0000000..ad95a42
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/crate_fail/src/main.rs
@@ -0,0 +1,41 @@
+#![allow(dead_code)]
+#![deny(clippy::multiple_inherent_impl)]
+
+struct S;
+struct T;
+
+impl S {
+    fn first() {}
+}
+
+impl S {
+    //^ Must trigger
+    fn second() {}
+}
+
+impl T {
+    fn first() {}
+}
+
+mod a {
+    use super::T;
+    impl T {
+        //^ Must trigger
+        fn second() {}
+    }
+}
+
+mod b;
+
+impl b::S {
+    //^ Must NOT trigger
+    fn first() {}
+    fn second() {}
+}
+
+impl b::T {
+    //^ Must trigger
+    fn second() {}
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/Cargo.stderr
new file mode 100644
index 0000000..eb7cf4e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/Cargo.stderr
@@ -0,0 +1,58 @@
+error: multiple implementations of this structure
+  --> src/main.rs:13:5
+   |
+13 | /     impl S {
+14 | |         //^ Must trigger
+15 | |         fn second() {}
+16 | |     }
+   | |_____^
+   |
+note: first implementation here
+  --> src/main.rs:6:1
+   |
+ 6 | / impl S {
+ 7 | |     fn first() {}
+ 8 | | }
+   | |_^
+note: the lint level is defined here
+  --> src/main.rs:2:9
+   |
+ 2 | #![deny(clippy::multiple_inherent_impl)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: multiple implementations of this structure
+  --> src/main.rs:26:5
+   |
+26 | /     impl S {
+27 | |         //^ Must trigger
+28 | |
+29 | |         fn second() {}
+30 | |     }
+   | |_____^
+   |
+note: first implementation here
+  --> src/main.rs:22:5
+   |
+22 | /     impl S {
+23 | |         fn first() {}
+24 | |     }
+   | |_____^
+
+error: multiple implementations of this structure
+  --> src/c.rs:17:5
+   |
+17 | /     impl T {
+18 | |         //^ Must trigger
+19 | |         fn second() {}
+20 | |     }
+   | |_____^
+   |
+note: first implementation here
+  --> src/c.rs:10:5
+   |
+10 | /     impl T {
+11 | |         fn first() {}
+12 | |     }
+   | |_____^
+
+error: could not compile `file_fail` (bin "file_fail") due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/Cargo.toml
new file mode 100644
index 0000000..7f767c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "file_fail"
+version = "0.1.0"
+edition = "2024"
+publish = false
+
+[dependencies]
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/clippy.toml b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/clippy.toml
new file mode 100644
index 0000000..4229797
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/clippy.toml
@@ -0,0 +1 @@
+inherent-impl-lint-scope = "file"
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/src/c.rs b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/src/c.rs
new file mode 100644
index 0000000..7757061
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/src/c.rs
@@ -0,0 +1,21 @@
+pub struct S;
+struct T;
+
+impl S {
+    fn first() {}
+}
+
+mod d {
+    use super::T;
+    impl T {
+        fn first() {}
+    }
+}
+
+mod e {
+    use super::T;
+    impl T {
+        //^ Must trigger
+        fn second() {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/src/main.rs
new file mode 100644
index 0000000..97514fd
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/file_fail/src/main.rs
@@ -0,0 +1,40 @@
+#![allow(dead_code)]
+#![deny(clippy::multiple_inherent_impl)]
+
+struct S;
+
+impl S {
+    fn first() {}
+}
+
+mod a {
+    use super::S;
+
+    impl S {
+        //^ Must trigger
+        fn second() {}
+    }
+}
+
+mod b {
+    struct S;
+
+    impl S {
+        fn first() {}
+    }
+
+    impl S {
+        //^ Must trigger
+
+        fn second() {}
+    }
+}
+
+mod c;
+
+impl c::S {
+    //^ Must NOT trigger
+    fn second() {}
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/Cargo.stderr
new file mode 100644
index 0000000..dd02afa
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/Cargo.stderr
@@ -0,0 +1,41 @@
+error: multiple implementations of this structure
+  --> src/main.rs:26:5
+   |
+26 | /     impl S {
+27 | |         //^ Must trigger
+28 | |
+29 | |         fn second() {}
+30 | |     }
+   | |_____^
+   |
+note: first implementation here
+  --> src/main.rs:22:5
+   |
+22 | /     impl S {
+23 | |         fn first() {}
+24 | |     }
+   | |_____^
+note: the lint level is defined here
+  --> src/main.rs:2:9
+   |
+ 2 | #![deny(clippy::multiple_inherent_impl)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: multiple implementations of this structure
+  --> src/c.rs:12:1
+   |
+12 | / impl T {
+13 | |     //^ Must trigger
+14 | |     fn second() {}
+15 | | }
+   | |_^
+   |
+note: first implementation here
+  --> src/c.rs:8:1
+   |
+ 8 | / impl T {
+ 9 | |     fn first() {}
+10 | | }
+   | |_^
+
+error: could not compile `module_fail` (bin "module_fail") due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/Cargo.toml
new file mode 100644
index 0000000..4b57af0
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "module_fail"
+version = "0.1.0"
+edition = "2024"
+publish = false
+
+[dependencies]
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/clippy.toml b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/clippy.toml
new file mode 100644
index 0000000..293dfa1
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/clippy.toml
@@ -0,0 +1 @@
+inherent-impl-lint-scope = "module"
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/src/c.rs b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/src/c.rs
new file mode 100644
index 0000000..1d51ebe
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/src/c.rs
@@ -0,0 +1,15 @@
+pub struct S;
+struct T;
+
+impl S {
+    fn first() {}
+}
+
+impl T {
+    fn first() {}
+}
+
+impl T {
+    //^ Must trigger
+    fn second() {}
+}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/src/main.rs
new file mode 100644
index 0000000..17b1b77
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/multiple_inherent_impl/module_fail/src/main.rs
@@ -0,0 +1,40 @@
+#![allow(dead_code)]
+#![deny(clippy::multiple_inherent_impl)]
+
+struct S;
+
+impl S {
+    fn first() {}
+}
+
+mod a {
+    use super::S;
+
+    impl S {
+        //^ Must NOT trigger
+        fn second() {}
+    }
+}
+
+mod b {
+    struct S;
+
+    impl S {
+        fn first() {}
+    }
+
+    impl S {
+        //^ Must trigger
+
+        fn second() {}
+    }
+}
+
+mod c;
+
+impl c::S {
+    //^ Must NOT trigger
+    fn second() {}
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr
index 59a7146..bfe2486 100644
--- a/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr
@@ -5,10 +5,10 @@
   | ^^^^^^^^
   |
 help: consider removing the safety comment
- --> src/main.rs:1:1
+ --> src/main.rs:1:4
   |
 1 | // SAFETY: ...
-  | ^^^^^^^^^^^^^^
+  |    ^^^^^^^
   = note: requested on the command line with `-D clippy::unnecessary-safety-comment`
 
 error: module has unnecessary safety comment
@@ -18,9 +18,9 @@
   | ^^^^^^^^
   |
 help: consider removing the safety comment
- --> src/main.rs:4:1
+ --> src/main.rs:4:4
   |
 4 | // SAFETY: ...
-  | ^^^^^^^^^^^^^^
+  |    ^^^^^^^
 
 error: could not compile `undocumented_unsafe_blocks` (bin "undocumented_unsafe_blocks") due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 20aeb4b..2d9503c 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -49,6 +49,7 @@
            excessive-nesting-threshold
            future-size-threshold
            ignore-interior-mutability
+           inherent-impl-lint-scope
            large-error-threshold
            lint-commented-code
            literal-representation-threshold
@@ -66,6 +67,7 @@
            msrv
            pass-by-value-size-limit
            pub-underscore-fields-behavior
+           recursive-self-in-type-definitions
            semicolon-inside-block-ignore-singleline
            semicolon-outside-block-ignore-multiline
            single-char-binding-names-threshold
@@ -144,6 +146,7 @@
            excessive-nesting-threshold
            future-size-threshold
            ignore-interior-mutability
+           inherent-impl-lint-scope
            large-error-threshold
            lint-commented-code
            literal-representation-threshold
@@ -161,6 +164,7 @@
            msrv
            pass-by-value-size-limit
            pub-underscore-fields-behavior
+           recursive-self-in-type-definitions
            semicolon-inside-block-ignore-singleline
            semicolon-outside-block-ignore-multiline
            single-char-binding-names-threshold
@@ -239,6 +243,7 @@
            excessive-nesting-threshold
            future-size-threshold
            ignore-interior-mutability
+           inherent-impl-lint-scope
            large-error-threshold
            lint-commented-code
            literal-representation-threshold
@@ -256,6 +261,7 @@
            msrv
            pass-by-value-size-limit
            pub-underscore-fields-behavior
+           recursive-self-in-type-definitions
            semicolon-inside-block-ignore-singleline
            semicolon-outside-block-ignore-multiline
            single-char-binding-names-threshold
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr
index bfc14be..61e5af8 100644
--- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr
@@ -247,10 +247,10 @@
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:507:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:507:8
    |
 LL |     // SAFETY:
-   |     ^^^^^^^^^^
+   |        ^^^^^^^
    = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]`
 
@@ -289,10 +289,10 @@
    | |______^
    |
 help: consider removing the safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:542:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:542:8
    |
 LL |     // SAFETY: this is more than one level away, so it should warn
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsafe block missing a safety comment
   --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:545:12
@@ -342,17 +342,137 @@
    |
    = help: consider adding a safety comment on the preceding line
 
+error: constant has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:701:5
+   |
+LL |     const UNIX_EPOCH_JULIAN_DAY: i32 =
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:699:8
+   |
+LL |     // SAFETY: fail ONLY if `accept-comment-above-attribute = false`
+   |        ^^^^^^^
+
 error: statement has unnecessary safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:719:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:721:5
    |
 LL |     _ = bar();
    |     ^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:718:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:720:8
    |
 LL |     // SAFETY: unnecessary_safety_comment triggers here
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 40 previous errors
+error: module has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:741:5
+   |
+LL |     mod x {}
+   |     ^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:740:8
+   |
+LL |     // SAFETY: ...
+   |        ^^^^^^^
+
+error: module has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:746:5
+   |
+LL |     mod y {}
+   |     ^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:744:8
+   |
+LL |     // SAFETY: ...
+   |        ^^^^^^^
+
+error: module has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:751:5
+   |
+LL |     mod z {}
+   |     ^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:750:8
+   |
+LL |     // SAFETY: ...
+   |        ^^^^^^^
+
+error: module has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:759:5
+   |
+LL |     mod y {}
+   |     ^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:757:8
+   |
+LL |     // SAFETY: ...
+   |        ^^^^^^^
+
+error: statement has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:774:9
+   |
+LL |         let x = 34;
+   |         ^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:772:12
+   |
+LL |         // SAFETY: ...
+   |            ^^^^^^^^^^^
+
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:781:5
+   |
+LL |     unsafe fn unsafe_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the `safety` comment for a `# Safety` doc comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:780:8
+   |
+LL |     // SAFETY: Bla
+   |        ^^^^^^^
+
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:787:5
+   |
+LL |     unsafe fn unsafe_block_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the `safety` comment for a `# Safety` doc comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:785:8
+   |
+LL |        SAFETY: Bla
+   |        ^^^^^^^
+
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:791:5
+   |
+LL |     fn safe_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:790:8
+   |
+LL |     // SAFETY: Bla
+   |        ^^^^^^^
+
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:795:5
+   |
+LL |     fn safe_doc_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:794:9
+   |
+LL |     /// SAFETY: Bla
+   |         ^^^^^^^
+
+error: aborting due to 50 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr
index cebfc48..e252cff 100644
--- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr
@@ -247,10 +247,10 @@
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:507:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:507:8
    |
 LL |     // SAFETY:
-   |     ^^^^^^^^^^
+   |        ^^^^^^^
    = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]`
 
@@ -297,10 +297,10 @@
    | |______^
    |
 help: consider removing the safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:542:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:542:8
    |
 LL |     // SAFETY: this is more than one level away, so it should warn
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsafe block missing a safety comment
   --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:545:12
@@ -439,24 +439,104 @@
    = help: consider adding a safety comment on the preceding line
 
 error: statement has unnecessary safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:719:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:721:5
    |
 LL |     _ = bar();
    |     ^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:718:5
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:720:8
    |
 LL |     // SAFETY: unnecessary_safety_comment triggers here
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unsafe block missing a safety comment
-  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:733:12
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:735:12
    |
 LL |     return unsafe { h() };
    |            ^^^^^^^^^^^^^^
    |
    = help: consider adding a safety comment on the preceding line
 
-error: aborting due to 53 previous errors
+error: module has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:741:5
+   |
+LL |     mod x {}
+   |     ^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:740:8
+   |
+LL |     // SAFETY: ...
+   |        ^^^^^^^
+
+error: module has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:751:5
+   |
+LL |     mod z {}
+   |     ^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:750:8
+   |
+LL |     // SAFETY: ...
+   |        ^^^^^^^
+
+error: unsafe block missing a safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:766:9
+   |
+LL |         unsafe {}
+   |         ^^^^^^^^^
+   |
+   = help: consider adding a safety comment on the preceding line
+
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:781:5
+   |
+LL |     unsafe fn unsafe_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the `safety` comment for a `# Safety` doc comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:780:8
+   |
+LL |     // SAFETY: Bla
+   |        ^^^^^^^
+
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:787:5
+   |
+LL |     unsafe fn unsafe_block_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider changing the `safety` comment for a `# Safety` doc comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:785:8
+   |
+LL |        SAFETY: Bla
+   |        ^^^^^^^
+
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:791:5
+   |
+LL |     fn safe_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:790:8
+   |
+LL |     // SAFETY: Bla
+   |        ^^^^^^^
+
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:795:5
+   |
+LL |     fn safe_doc_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:794:9
+   |
+LL |     /// SAFETY: Bla
+   |         ^^^^^^^
+
+error: aborting due to 60 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs
index a2d7c1b..db9e81c 100644
--- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs
@@ -701,6 +701,8 @@ const fn into_julian_day_just_make_this_line_longer(self) -> i32 {
     const UNIX_EPOCH_JULIAN_DAY: i32 =
         unsafe { Date::__from_ordinal_date_unchecked(1970, 1) }.into_julian_day_just_make_this_line_longer();
     //~[disabled]^ undocumented_unsafe_blocks
+    // This shouldn't be linted, Issue #15755
+    //~[default]^^^^ unnecessary_safety_comment
 }
 
 fn issue_13039() {
@@ -734,4 +736,64 @@ unsafe fn h() -> i32 {
     //~[disabled]^ ERROR: unsafe block missing a safety comment
 }
 
+mod issue_14555 {
+    // SAFETY: ...
+    mod x {}
+    //~^ unnecessary_safety_comment
+
+    // SAFETY: ...
+    #[doc(hidden)]
+    mod y {}
+    //~[default]^ unnecessary_safety_comment
+
+    #[doc(hidden)]
+    // SAFETY: ...
+    mod z {}
+    //~^ unnecessary_safety_comment
+}
+
+mod issue_15754 {
+    #[must_use]
+    // SAFETY: ...
+    #[doc(hidden)]
+    mod y {}
+    //~[default]^ unnecessary_safety_comment
+
+    fn foo() {
+        #[doc(hidden)]
+        // SAFETY: unnecessary_safety_comment should not trigger here
+        #[allow(unsafe_code)]
+        unsafe {}
+        //~[disabled]^ undocumented_unsafe_blocks
+    }
+
+    fn bar() {
+        #[doc(hidden)]
+        // SAFETY: ...
+        #[allow(clippy::unnecessary_cast)]
+        let x = 34;
+        //~[default]^ unnecessary_safety_comment
+    }
+}
+
+mod unsafe_fns {
+    // SAFETY: Bla
+    unsafe fn unsafe_comment() {}
+    //~^ unnecessary_safety_comment
+
+    /*
+       SAFETY: Bla
+    */
+    unsafe fn unsafe_block_comment() {}
+    //~^ unnecessary_safety_comment
+
+    // SAFETY: Bla
+    fn safe_comment() {}
+    //~^ unnecessary_safety_comment
+
+    /// SAFETY: Bla
+    fn safe_doc_comment() {}
+    //~^ unnecessary_safety_comment
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.default.fixed b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.default.fixed
new file mode 100644
index 0000000..cc8d502
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.default.fixed
@@ -0,0 +1,20 @@
+//@aux-build:../../ui/auxiliary/proc_macro_unsafe.rs
+//@revisions: default disabled
+//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/undocumented_unsafe_blocks/default
+//@[disabled] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/undocumented_unsafe_blocks/disabled
+
+#![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)]
+
+mod unsafe_fns {
+    /// # Safety Bla
+    unsafe fn unsafe_doc_comment() {}
+    //~^ unnecessary_safety_comment
+
+    /**
+     * # Safety Bla
+     */
+    unsafe fn unsafe_block_doc_comment() {}
+    //~^ unnecessary_safety_comment
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.default.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.default.stderr
new file mode 100644
index 0000000..95e47dc
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.default.stderr
@@ -0,0 +1,22 @@
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.rs:10:5
+   |
+LL |     /// SAFETY: Bla
+   |         ------- help: consider changing it to a `# Safety` section: `# Safety`
+LL |     unsafe fn unsafe_doc_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]`
+
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.rs:16:5
+   |
+LL |      * SAFETY: Bla
+   |        ------- help: consider changing it to a `# Safety` section: `# Safety`
+LL |      */
+LL |     unsafe fn unsafe_block_doc_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.disabled.fixed b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.disabled.fixed
new file mode 100644
index 0000000..cc8d502
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.disabled.fixed
@@ -0,0 +1,20 @@
+//@aux-build:../../ui/auxiliary/proc_macro_unsafe.rs
+//@revisions: default disabled
+//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/undocumented_unsafe_blocks/default
+//@[disabled] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/undocumented_unsafe_blocks/disabled
+
+#![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)]
+
+mod unsafe_fns {
+    /// # Safety Bla
+    unsafe fn unsafe_doc_comment() {}
+    //~^ unnecessary_safety_comment
+
+    /**
+     * # Safety Bla
+     */
+    unsafe fn unsafe_block_doc_comment() {}
+    //~^ unnecessary_safety_comment
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.disabled.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.disabled.stderr
new file mode 100644
index 0000000..95e47dc
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.disabled.stderr
@@ -0,0 +1,22 @@
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.rs:10:5
+   |
+LL |     /// SAFETY: Bla
+   |         ------- help: consider changing it to a `# Safety` section: `# Safety`
+LL |     unsafe fn unsafe_doc_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]`
+
+error: function has unnecessary safety comment
+  --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.rs:16:5
+   |
+LL |      * SAFETY: Bla
+   |        ------- help: consider changing it to a `# Safety` section: `# Safety`
+LL |      */
+LL |     unsafe fn unsafe_block_doc_comment() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.rs b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.rs
new file mode 100644
index 0000000..14b9112
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks_fixable.rs
@@ -0,0 +1,20 @@
+//@aux-build:../../ui/auxiliary/proc_macro_unsafe.rs
+//@revisions: default disabled
+//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/undocumented_unsafe_blocks/default
+//@[disabled] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/undocumented_unsafe_blocks/disabled
+
+#![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)]
+
+mod unsafe_fns {
+    /// SAFETY: Bla
+    unsafe fn unsafe_doc_comment() {}
+    //~^ unnecessary_safety_comment
+
+    /**
+     * SAFETY: Bla
+     */
+    unsafe fn unsafe_block_doc_comment() {}
+    //~^ unnecessary_safety_comment
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/use_self/default/clippy.toml b/src/tools/clippy/tests/ui-toml/use_self/default/clippy.toml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/use_self/default/clippy.toml
diff --git a/src/tools/clippy/tests/ui-toml/use_self/disabled/clippy.toml b/src/tools/clippy/tests/ui-toml/use_self/disabled/clippy.toml
new file mode 100644
index 0000000..866cc5c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/use_self/disabled/clippy.toml
@@ -0,0 +1 @@
+recursive-self-in-type-definitions = false
diff --git a/src/tools/clippy/tests/ui-toml/use_self/use_self.default.fixed b/src/tools/clippy/tests/ui-toml/use_self/use_self.default.fixed
new file mode 100644
index 0000000..288e304
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/use_self/use_self.default.fixed
@@ -0,0 +1,17 @@
+//@revisions: default disabled
+//@[disabled] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/use_self/disabled
+//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/use_self/default
+
+#![warn(clippy::use_self)]
+
+fn main() {}
+
+struct Basic {
+    flag: Option<Box<Self>>,
+    //~[default]^ use_self
+}
+
+impl Basic {
+    fn x(_: Self) {}
+    //~[default,disabled]^ use_self
+}
diff --git a/src/tools/clippy/tests/ui-toml/use_self/use_self.default.stderr b/src/tools/clippy/tests/ui-toml/use_self/use_self.default.stderr
new file mode 100644
index 0000000..34cfdfd
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/use_self/use_self.default.stderr
@@ -0,0 +1,17 @@
+error: unnecessary structure name repetition
+  --> tests/ui-toml/use_self/use_self.rs:10:22
+   |
+LL |     flag: Option<Box<Basic>>,
+   |                      ^^^^^ help: use the applicable keyword: `Self`
+   |
+   = note: `-D clippy::use-self` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::use_self)]`
+
+error: unnecessary structure name repetition
+  --> tests/ui-toml/use_self/use_self.rs:15:13
+   |
+LL |     fn x(_: Basic) {}
+   |             ^^^^^ help: use the applicable keyword: `Self`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/use_self/use_self.disabled.fixed b/src/tools/clippy/tests/ui-toml/use_self/use_self.disabled.fixed
new file mode 100644
index 0000000..227606e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/use_self/use_self.disabled.fixed
@@ -0,0 +1,17 @@
+//@revisions: default disabled
+//@[disabled] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/use_self/disabled
+//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/use_self/default
+
+#![warn(clippy::use_self)]
+
+fn main() {}
+
+struct Basic {
+    flag: Option<Box<Basic>>,
+    //~[default]^ use_self
+}
+
+impl Basic {
+    fn x(_: Self) {}
+    //~[default,disabled]^ use_self
+}
diff --git a/src/tools/clippy/tests/ui-toml/use_self/use_self.disabled.stderr b/src/tools/clippy/tests/ui-toml/use_self/use_self.disabled.stderr
new file mode 100644
index 0000000..1801744
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/use_self/use_self.disabled.stderr
@@ -0,0 +1,11 @@
+error: unnecessary structure name repetition
+  --> tests/ui-toml/use_self/use_self.rs:15:13
+   |
+LL |     fn x(_: Basic) {}
+   |             ^^^^^ help: use the applicable keyword: `Self`
+   |
+   = note: `-D clippy::use-self` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::use_self)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/use_self/use_self.rs b/src/tools/clippy/tests/ui-toml/use_self/use_self.rs
new file mode 100644
index 0000000..d20006d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/use_self/use_self.rs
@@ -0,0 +1,17 @@
+//@revisions: default disabled
+//@[disabled] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/use_self/disabled
+//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/use_self/default
+
+#![warn(clippy::use_self)]
+
+fn main() {}
+
+struct Basic {
+    flag: Option<Box<Basic>>,
+    //~[default]^ use_self
+}
+
+impl Basic {
+    fn x(_: Basic) {}
+    //~[default,disabled]^ use_self
+}
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
index e453299..ff9fe24 100644
--- a/src/tools/clippy/tests/ui/author/blocks.stdout
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -23,13 +23,13 @@
     && let StmtKind::Let(local) = block.stmts[0].kind
     && let Some(init) = local.init
     && let ExprKind::Call(func, args) = init.kind
-    && is_path_diagnostic_item(cx, func, sym::string_new)
+    && func.res(cx).is_diag_item(cx, sym::string_new)
     && args.is_empty()
     && let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind
     && name.as_str() == "expr"
     && let Some(trailing_expr) = block.expr
     && let ExprKind::Call(func1, args1) = trailing_expr.kind
-    && is_path_diagnostic_item(cx, func1, sym::mem_drop)
+    && func1.res(cx).is_diag_item(cx, sym::mem_drop)
     && args1.len() == 1
 {
     // report your lint here
diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui/author/call.stdout
index 2b179d4..024121b 100644
--- a/src/tools/clippy/tests/ui/author/call.stdout
+++ b/src/tools/clippy/tests/ui/author/call.stdout
@@ -1,7 +1,7 @@
 if let StmtKind::Let(local) = stmt.kind
     && let Some(init) = local.init
     && let ExprKind::Call(func, args) = init.kind
-    && is_path_diagnostic_item(cx, func, sym::cmp_min)
+    && func.res(cx).is_diag_item(cx, sym::cmp_min)
     && args.len() == 2
     && let ExprKind::Lit(ref lit) = args[0].kind
     && let LitKind::Int(3, LitIntType::Unsuffixed) = lit.node
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.stdout b/src/tools/clippy/tests/ui/author/issue_3849.stdout
index f02ea5b..b88058f 100644
--- a/src/tools/clippy/tests/ui/author/issue_3849.stdout
+++ b/src/tools/clippy/tests/ui/author/issue_3849.stdout
@@ -1,7 +1,7 @@
 if let StmtKind::Let(local) = stmt.kind
     && let Some(init) = local.init
     && let ExprKind::Call(func, args) = init.kind
-    && is_path_diagnostic_item(cx, func, sym::transmute)
+    && func.res(cx).is_diag_item(cx, sym::transmute)
     && args.len() == 1
     && let PatKind::Wild = local.pat.kind
 {
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs
index e5c094f..c8774c7 100644
--- a/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs
@@ -1,4 +1,3 @@
-//@no-rustfix
 #![warn(clippy::char_lit_as_u8)]
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr
index 49e555a..4c2770c 100644
--- a/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr
@@ -1,5 +1,5 @@
 error: casting a character literal to `u8` truncates
-  --> tests/ui/char_lit_as_u8_unfixable.rs:6:13
+  --> tests/ui/char_lit_as_u8_unfixable.rs:5:13
    |
 LL |     let _ = '❤' as u8;
    |             ^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/clone_on_ref_ptr.fixed b/src/tools/clippy/tests/ui/clone_on_ref_ptr.fixed
index 8ef4b36..ede9d17 100644
--- a/src/tools/clippy/tests/ui/clone_on_ref_ptr.fixed
+++ b/src/tools/clippy/tests/ui/clone_on_ref_ptr.fixed
@@ -49,3 +49,33 @@
         //~^ clone_on_ref_ptr
     }
 }
+
+#[allow(
+    clippy::needless_borrow,
+    reason = "the suggestion creates `Weak::clone(&rec)`, but `rec` is already a reference"
+)]
+mod issue15009 {
+    use std::rc::{Rc, Weak};
+    use std::sync::atomic::{AtomicU32, Ordering};
+
+    fn main() {
+        let counter = AtomicU32::new(0);
+        let counter_ref = &counter;
+        let factorial = Rc::new_cyclic(move |rec| {
+            let rec = std::rc::Weak::</* generic */>::clone(&rec) as Weak<dyn Fn(u32) -> u32>;
+            //~^ clone_on_ref_ptr
+            move |x| {
+                // can capture env
+                counter_ref.fetch_add(1, Ordering::Relaxed);
+                match x {
+                    0 => 1,
+                    x => x * rec.upgrade().unwrap()(x - 1),
+                }
+            }
+        });
+        println!("{}", factorial(5)); // 120
+        println!("{}", counter.load(Ordering::Relaxed)); // 6
+        println!("{}", factorial(7)); // 5040
+        println!("{}", counter.load(Ordering::Relaxed)); // 14
+    }
+}
diff --git a/src/tools/clippy/tests/ui/clone_on_ref_ptr.rs b/src/tools/clippy/tests/ui/clone_on_ref_ptr.rs
index fbd7870..5999b40 100644
--- a/src/tools/clippy/tests/ui/clone_on_ref_ptr.rs
+++ b/src/tools/clippy/tests/ui/clone_on_ref_ptr.rs
@@ -49,3 +49,33 @@ fn func() -> Option<Rc<u8>> {
         //~^ clone_on_ref_ptr
     }
 }
+
+#[allow(
+    clippy::needless_borrow,
+    reason = "the suggestion creates `Weak::clone(&rec)`, but `rec` is already a reference"
+)]
+mod issue15009 {
+    use std::rc::{Rc, Weak};
+    use std::sync::atomic::{AtomicU32, Ordering};
+
+    fn main() {
+        let counter = AtomicU32::new(0);
+        let counter_ref = &counter;
+        let factorial = Rc::new_cyclic(move |rec| {
+            let rec = rec.clone() as Weak<dyn Fn(u32) -> u32>;
+            //~^ clone_on_ref_ptr
+            move |x| {
+                // can capture env
+                counter_ref.fetch_add(1, Ordering::Relaxed);
+                match x {
+                    0 => 1,
+                    x => x * rec.upgrade().unwrap()(x - 1),
+                }
+            }
+        });
+        println!("{}", factorial(5)); // 120
+        println!("{}", counter.load(Ordering::Relaxed)); // 6
+        println!("{}", factorial(7)); // 5040
+        println!("{}", counter.load(Ordering::Relaxed)); // 14
+    }
+}
diff --git a/src/tools/clippy/tests/ui/clone_on_ref_ptr.stderr b/src/tools/clippy/tests/ui/clone_on_ref_ptr.stderr
index b15f0e8..b8ddc30 100644
--- a/src/tools/clippy/tests/ui/clone_on_ref_ptr.stderr
+++ b/src/tools/clippy/tests/ui/clone_on_ref_ptr.stderr
@@ -37,5 +37,11 @@
 LL |         Some(try_opt!(Some(rc)).clone())
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::rc::Rc::<u8>::clone(&try_opt!(Some(rc)))`
 
-error: aborting due to 6 previous errors
+error: using `.clone()` on a ref-counted pointer
+  --> tests/ui/clone_on_ref_ptr.rs:65:23
+   |
+LL |             let rec = rec.clone() as Weak<dyn Fn(u32) -> u32>;
+   |                       ^^^^^^^^^^^ help: try: `std::rc::Weak::</* generic */>::clone(&rec)`
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs
index 8931a3a..84f958e 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.rs
+++ b/src/tools/clippy/tests/ui/collapsible_match.rs
@@ -304,16 +304,25 @@ pub fn test_2(x: Issue9647) {
     }
 }
 
-// https://github.com/rust-lang/rust-clippy/issues/14281
-fn lint_emitted_at_right_node(opt: Option<Result<u64, String>>) {
-    let n = match opt {
-        #[expect(clippy::collapsible_match)]
-        Some(n) => match n {
-            Ok(n) => n,
-            _ => return,
-        },
-        None => return,
-    };
+mod issue_13287 {
+    enum Token {
+        Name,
+        Other,
+    }
+
+    struct Error {
+        location: u32,
+        token: Option<Token>,
+    }
+
+    fn struct_field_pat_with_binding_mode(err: Option<Error>) {
+        if let Some(Error { ref token, .. }) = err {
+            if let Some(Token::Name) = token {
+                //~^ collapsible_match
+                println!("token used as a ref");
+            }
+        }
+    }
 }
 
 pub fn issue_14155() {
@@ -357,6 +366,18 @@ pub fn issue_14155() {
     }
 }
 
+// https://github.com/rust-lang/rust-clippy/issues/14281
+fn lint_emitted_at_right_node(opt: Option<Result<u64, String>>) {
+    let n = match opt {
+        #[expect(clippy::collapsible_match)]
+        Some(n) => match n {
+            Ok(n) => n,
+            _ => return,
+        },
+        None => return,
+    };
+}
+
 fn make<T>() -> T {
     unimplemented!()
 }
diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr
index 14b1c1b..d217948 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_match.stderr
@@ -230,7 +230,7 @@
 LL |     if let Issue9647::A { a, .. } = x {
    |                           ^ replace this binding
 LL |         if let Some(u) = a {
-   |                ^^^^^^^ with this pattern, prefixed by `a`:
+   |                ^^^^^^^ with this pattern, prefixed by `a: `
 
 error: this `if let` can be collapsed into the outer `if let`
   --> tests/ui/collapsible_match.rs:299:9
@@ -250,8 +250,25 @@
 LL |         if let Some(u) = a {
    |                ^^^^^^^ with this pattern
 
+error: this `if let` can be collapsed into the outer `if let`
+  --> tests/ui/collapsible_match.rs:320:13
+   |
+LL | /             if let Some(Token::Name) = token {
+LL | |
+LL | |                 println!("token used as a ref");
+LL | |             }
+   | |_____________^
+   |
+help: the outer pattern can be modified to include the inner pattern
+  --> tests/ui/collapsible_match.rs:319:29
+   |
+LL |         if let Some(Error { ref token, .. }) = err {
+   |                             ^^^^^^^^^ replace this binding
+LL |             if let Some(Token::Name) = token {
+   |                    ^^^^^^^^^^^^^^^^^ with this pattern, prefixed by `token: `
+
 error: this `match` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:322:9
+  --> tests/ui/collapsible_match.rs:331:9
    |
 LL | /         match *last {
 LL | |
@@ -263,7 +280,7 @@
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:321:17
+  --> tests/ui/collapsible_match.rs:330:17
    |
 LL |     if let Some(last) = arr.last() {
    |                 ^^^^    ---------- use: `arr.last().copied()`
@@ -274,7 +291,7 @@
    |             ^^^^^^^^^ with this pattern
 
 error: this `match` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:332:9
+  --> tests/ui/collapsible_match.rs:341:9
    |
 LL | /         match &last {
 LL | |
@@ -286,7 +303,7 @@
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:331:17
+  --> tests/ui/collapsible_match.rs:340:17
    |
 LL |     if let Some(last) = arr.last() {
    |                 ^^^^    ---------- use: `arr.last().as_ref()`
@@ -297,7 +314,7 @@
    |             ^^^^^^^^^^^^^ with this pattern
 
 error: this `match` can be collapsed into the outer `if let`
-  --> tests/ui/collapsible_match.rs:342:9
+  --> tests/ui/collapsible_match.rs:351:9
    |
 LL | /         match &mut last {
 LL | |
@@ -309,7 +326,7 @@
    | |_________^
    |
 help: the outer pattern can be modified to include the inner pattern
-  --> tests/ui/collapsible_match.rs:341:17
+  --> tests/ui/collapsible_match.rs:350:17
    |
 LL |     if let Some(mut last) = arr.last_mut() {
    |                 ^^^^^^^^    -------------- use: `arr.last_mut().as_mut()`
@@ -319,5 +336,5 @@
 LL |             &mut &mut "a" | &mut &mut "b" => {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ with this pattern
 
-error: aborting due to 16 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-15684.rs b/src/tools/clippy/tests/ui/crashes/ice-15684.rs
new file mode 100644
index 0000000..12f3604
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-15684.rs
@@ -0,0 +1,10 @@
+#![warn(clippy::unnecessary_safety_comment)]
+
+fn foo() -> i32 {
+    // SAFETY: fail ONLY if `accept-comment-above-attribute = false`
+    #[must_use]
+    return 33;
+    //~^ unnecessary_safety_comment
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-15684.stderr b/src/tools/clippy/tests/ui/crashes/ice-15684.stderr
new file mode 100644
index 0000000..0d4eb62
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-15684.stderr
@@ -0,0 +1,16 @@
+error: statement has unnecessary safety comment
+  --> tests/ui/crashes/ice-15684.rs:6:5
+   |
+LL |     return 33;
+   |     ^^^^^^^^^^
+   |
+help: consider removing the safety comment
+  --> tests/ui/crashes/ice-15684.rs:4:8
+   |
+LL |     // SAFETY: fail ONLY if `accept-comment-above-attribute = false`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/derive.rs b/src/tools/clippy/tests/ui/derive.rs
index b8adb76..6b60421c 100644
--- a/src/tools/clippy/tests/ui/derive.rs
+++ b/src/tools/clippy/tests/ui/derive.rs
@@ -133,7 +133,7 @@ fn clone(&self) -> Self {
 fn main() {}
 
 mod issue15708 {
-    // Check that the lint posts on the type definition node
+    // Check that `allow`/`expect` attributes are recognized on the type definition node
     #[expect(clippy::expl_impl_clone_on_copy)]
     #[derive(Copy)]
     struct S;
@@ -144,3 +144,16 @@ fn clone(&self) -> Self {
         }
     }
 }
+
+mod issue15842 {
+    #[derive(Copy)]
+    struct S;
+
+    // Check that `allow`/`expect` attributes are recognized on the `impl Clone` node
+    #[expect(clippy::expl_impl_clone_on_copy)]
+    impl Clone for S {
+        fn clone(&self) -> Self {
+            S
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/derive.stderr b/src/tools/clippy/tests/ui/derive.stderr
index 7dbc38a..2b97a58 100644
--- a/src/tools/clippy/tests/ui/derive.stderr
+++ b/src/tools/clippy/tests/ui/derive.stderr
@@ -9,16 +9,7 @@
 LL | | }
    | |_^
    |
-help: consider deriving `Clone` or removing `Copy`
-  --> tests/ui/derive.rs:16:1
-   |
-LL | / impl Clone for Qux {
-LL | |
-LL | |
-LL | |     fn clone(&self) -> Self {
-...  |
-LL | | }
-   | |_^
+   = help: consider deriving `Clone` or removing `Copy`
    = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
 
@@ -33,16 +24,7 @@
 LL | | }
    | |_^
    |
-help: consider deriving `Clone` or removing `Copy`
-  --> tests/ui/derive.rs:42:1
-   |
-LL | / impl<'a> Clone for Lt<'a> {
-LL | |
-LL | |
-LL | |     fn clone(&self) -> Self {
-...  |
-LL | | }
-   | |_^
+   = help: consider deriving `Clone` or removing `Copy`
 
 error: you are implementing `Clone` explicitly on a `Copy` type
   --> tests/ui/derive.rs:55:1
@@ -55,16 +37,7 @@
 LL | | }
    | |_^
    |
-help: consider deriving `Clone` or removing `Copy`
-  --> tests/ui/derive.rs:55:1
-   |
-LL | / impl Clone for BigArray {
-LL | |
-LL | |
-LL | |     fn clone(&self) -> Self {
-...  |
-LL | | }
-   | |_^
+   = help: consider deriving `Clone` or removing `Copy`
 
 error: you are implementing `Clone` explicitly on a `Copy` type
   --> tests/ui/derive.rs:68:1
@@ -77,16 +50,7 @@
 LL | | }
    | |_^
    |
-help: consider deriving `Clone` or removing `Copy`
-  --> tests/ui/derive.rs:68:1
-   |
-LL | / impl Clone for FnPtr {
-LL | |
-LL | |
-LL | |     fn clone(&self) -> Self {
-...  |
-LL | | }
-   | |_^
+   = help: consider deriving `Clone` or removing `Copy`
 
 error: you are implementing `Clone` explicitly on a `Copy` type
   --> tests/ui/derive.rs:90:1
@@ -99,16 +63,7 @@
 LL | | }
    | |_^
    |
-help: consider deriving `Clone` or removing `Copy`
-  --> tests/ui/derive.rs:90:1
-   |
-LL | / impl<T: Clone> Clone for Generic2<T> {
-LL | |
-LL | |
-LL | |     fn clone(&self) -> Self {
-...  |
-LL | | }
-   | |_^
+   = help: consider deriving `Clone` or removing `Copy`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_write_in_test.rs b/src/tools/clippy/tests/ui/explicit_write_in_test.rs
new file mode 100644
index 0000000..df020b7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/explicit_write_in_test.rs
@@ -0,0 +1,9 @@
+//@ check-pass
+#![warn(clippy::explicit_write)]
+
+#[test]
+fn test() {
+    use std::io::Write;
+    writeln!(std::io::stderr(), "I am an explicit write.").unwrap();
+    eprintln!("I am not an explicit write.");
+}
diff --git a/src/tools/clippy/tests/ui/explicit_write_in_test.stderr b/src/tools/clippy/tests/ui/explicit_write_in_test.stderr
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tools/clippy/tests/ui/explicit_write_in_test.stderr
diff --git a/src/tools/clippy/tests/ui/impl.rs b/src/tools/clippy/tests/ui/impl.rs
index 1b9e4a5..15cb61c 100644
--- a/src/tools/clippy/tests/ui/impl.rs
+++ b/src/tools/clippy/tests/ui/impl.rs
@@ -68,7 +68,20 @@ impl AllowedImpl {}
 impl OneAllowedImpl {}
 #[allow(clippy::multiple_inherent_impl)]
 impl OneAllowedImpl {}
-impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed.
+impl OneAllowedImpl {}
+//~^ multiple_inherent_impl
+
+#[expect(clippy::multiple_inherent_impl)]
+struct ExpectedFulfilled;
+
+impl ExpectedFulfilled {}
+impl ExpectedFulfilled {}
+
+struct OneExpected;
+impl OneExpected {}
+#[expect(clippy::multiple_inherent_impl)]
+impl OneExpected {}
+impl OneExpected {}
 //~^ multiple_inherent_impl
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/impl.stderr b/src/tools/clippy/tests/ui/impl.stderr
index 355927b..93d4b39 100644
--- a/src/tools/clippy/tests/ui/impl.stderr
+++ b/src/tools/clippy/tests/ui/impl.stderr
@@ -57,7 +57,7 @@
 error: multiple implementations of this structure
   --> tests/ui/impl.rs:71:1
    |
-LL | impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed.
+LL | impl OneAllowedImpl {}
    | ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: first implementation here
@@ -66,5 +66,17 @@
 LL | impl OneAllowedImpl {}
    | ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: multiple implementations of this structure
+  --> tests/ui/impl.rs:84:1
+   |
+LL | impl OneExpected {}
+   | ^^^^^^^^^^^^^^^^^^^
+   |
+note: first implementation here
+  --> tests/ui/impl.rs:81:1
+   |
+LL | impl OneExpected {}
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/infinite_loops.rs b/src/tools/clippy/tests/ui/infinite_loops.rs
index 7d01a7f..0bde31a 100644
--- a/src/tools/clippy/tests/ui/infinite_loops.rs
+++ b/src/tools/clippy/tests/ui/infinite_loops.rs
@@ -1,7 +1,7 @@
 //@no-rustfix: multiple suggestions add `-> !` to the same fn
 //@aux-build:proc_macros.rs
 
-#![allow(clippy::never_loop)]
+#![allow(clippy::never_loop, clippy::while_let_loop)]
 #![warn(clippy::infinite_loop)]
 
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs
index 9bf0f7f..084d97f 100644
--- a/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs
+++ b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs
@@ -77,3 +77,14 @@ fn msrv_juust_right() {
     use std::u32::MAX;
     //~^ ERROR: importing a legacy numeric constant
 }
+
+macro_rules! foo {
+    ($a: ty) => {
+        let _ = <$a>::max_value();
+        let _ = (<$a>::max_value)();
+    };
+}
+
+fn issue15805() {
+    foo!(u8);
+}
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
new file mode 100644
index 0000000..d1f798b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
@@ -0,0 +1,98 @@
+//@revisions: edition2018 edition2021
+//@[edition2018] edition:2018
+//@[edition2021] edition:2021
+
+#![warn(clippy::manual_assert)]
+#![allow(dead_code, unused_doc_comments)]
+#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args, clippy::useless_vec)]
+
+macro_rules! one {
+    () => {
+        1
+    };
+}
+
+fn main() {
+    let a = vec![1, 2, 3];
+    let c = Some(2);
+    if !a.is_empty()
+        && a.len() == 3
+        && c.is_some()
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+    {
+        panic!("qaqaq{:?}", a);
+    }
+    //~^ manual_assert
+    assert!(a.is_empty(), "qaqaq{:?}", a);
+    //~^ manual_assert
+    assert!(a.is_empty(), "qwqwq");
+    if a.len() == 3 {
+        println!("qwq");
+        println!("qwq");
+        println!("qwq");
+    }
+    if let Some(b) = c {
+        panic!("orz {}", b);
+    }
+    if a.len() == 3 {
+        panic!("qaqaq");
+    } else {
+        println!("qwq");
+    }
+    let b = vec![1, 2, 3];
+    //~^ manual_assert
+    assert!(!b.is_empty(), "panic1");
+    //~^ manual_assert
+    assert!(!(b.is_empty() && a.is_empty()), "panic2");
+    //~^ manual_assert
+    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+    //~^ manual_assert
+    assert!(!(b.is_empty() || a.is_empty()), "panic4");
+    //~^ manual_assert
+    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+    //~^ manual_assert
+    assert!(!a.is_empty(), "with expansion {}", one!());
+    if a.is_empty() {
+        let _ = 0;
+    } else if a.len() == 1 {
+        panic!("panic6");
+    }
+}
+
+fn issue7730(a: u8) {
+    // Suggestion should preserve comment
+    //~^ manual_assert
+    // comment
+    /* this is a
+            multiline
+            comment */
+    /// Doc comment
+    // comment after `panic!`
+    assert!(a <= 2, "panic with comment");
+}
+
+fn issue12505() {
+    struct Foo<T, const N: usize>(T);
+
+    impl<T, const N: usize> Foo<T, N> {
+        const BAR: () = //~^ manual_assert
+        assert!(N != 0, );
+    }
+}
+
+fn issue15227(left: u64, right: u64) -> u64 {
+    macro_rules! is_x86_feature_detected {
+        ($feature:literal) => {
+            $feature.len() > 0 && $feature.starts_with("ss")
+        };
+    }
+
+    //~^ manual_assert
+    assert!(is_x86_feature_detected!("ssse3"), "SSSE3 is not supported");
+    unsafe { todo!() }
+}
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
index 2e9c904..c81a855 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
@@ -1,5 +1,5 @@
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:32:5
+  --> tests/ui/manual_assert.rs:30:5
    |
 LL | /     if !a.is_empty() {
 LL | |
@@ -9,17 +9,14 @@
    |
    = note: `-D clippy::manual-assert` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::manual_assert)]`
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if !a.is_empty() {
-LL -
-LL -         panic!("qaqaq{:?}", a);
-LL -     }
+LL ~
 LL +     assert!(a.is_empty(), "qaqaq{:?}", a);
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:36:5
+  --> tests/ui/manual_assert.rs:34:5
    |
 LL | /     if !a.is_empty() {
 LL | |
@@ -27,17 +24,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if !a.is_empty() {
-LL -
-LL -         panic!("qwqwq");
-LL -     }
+LL ~
 LL +     assert!(a.is_empty(), "qwqwq");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:54:5
+  --> tests/ui/manual_assert.rs:52:5
    |
 LL | /     if b.is_empty() {
 LL | |
@@ -45,17 +39,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if b.is_empty() {
-LL -
-LL -         panic!("panic1");
-LL -     }
+LL ~
 LL +     assert!(!b.is_empty(), "panic1");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:58:5
+  --> tests/ui/manual_assert.rs:56:5
    |
 LL | /     if b.is_empty() && a.is_empty() {
 LL | |
@@ -63,17 +54,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if b.is_empty() && a.is_empty() {
-LL -
-LL -         panic!("panic2");
-LL -     }
+LL ~
 LL +     assert!(!(b.is_empty() && a.is_empty()), "panic2");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:62:5
+  --> tests/ui/manual_assert.rs:60:5
    |
 LL | /     if a.is_empty() && !b.is_empty() {
 LL | |
@@ -81,17 +69,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if a.is_empty() && !b.is_empty() {
-LL -
-LL -         panic!("panic3");
-LL -     }
+LL ~
 LL +     assert!(!(a.is_empty() && !b.is_empty()), "panic3");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:66:5
+  --> tests/ui/manual_assert.rs:64:5
    |
 LL | /     if b.is_empty() || a.is_empty() {
 LL | |
@@ -99,17 +84,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if b.is_empty() || a.is_empty() {
-LL -
-LL -         panic!("panic4");
-LL -     }
+LL ~
 LL +     assert!(!(b.is_empty() || a.is_empty()), "panic4");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:70:5
+  --> tests/ui/manual_assert.rs:68:5
    |
 LL | /     if a.is_empty() || !b.is_empty() {
 LL | |
@@ -117,17 +99,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if a.is_empty() || !b.is_empty() {
-LL -
-LL -         panic!("panic5");
-LL -     }
+LL ~
 LL +     assert!(!(a.is_empty() || !b.is_empty()), "panic5");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:74:5
+  --> tests/ui/manual_assert.rs:72:5
    |
 LL | /     if a.is_empty() {
 LL | |
@@ -135,17 +114,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if a.is_empty() {
-LL -
-LL -         panic!("with expansion {}", one!())
-LL -     }
+LL ~
 LL +     assert!(!a.is_empty(), "with expansion {}", one!());
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:87:5
+  --> tests/ui/manual_assert.rs:85:5
    |
 LL | /     if a > 2 {
 LL | |
@@ -156,22 +132,20 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if a > 2 {
-LL -
-LL -         // comment
-LL -         /* this is a
-LL -         multiline
-LL -         comment */
-LL -         /// Doc comment
-LL -         panic!("panic with comment") // comment after `panic!`
-LL -     }
+LL ~
+LL +     // comment
+LL +     /* this is a
+LL +             multiline
+LL +             comment */
+LL +     /// Doc comment
+LL +     // comment after `panic!`
 LL +     assert!(a <= 2, "panic with comment");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:102:25
+  --> tests/ui/manual_assert.rs:100:25
    |
 LL |           const BAR: () = if N == 0 {
    |  _________________________^
@@ -180,17 +154,14 @@
 LL | |         };
    | |_________^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -         const BAR: () = if N == 0 {
-LL -
-LL -             panic!()
-LL -         };
-LL +         const BAR: () = assert!(N != 0, );
+LL ~         const BAR: () =
+LL ~         assert!(N != 0, );
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:116:5
+  --> tests/ui/manual_assert.rs:114:5
    |
 LL | /     if !is_x86_feature_detected!("ssse3") {
 LL | |
@@ -198,12 +169,9 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if !is_x86_feature_detected!("ssse3") {
-LL -
-LL -         panic!("SSSE3 is not supported");
-LL -     }
+LL ~
 LL +     assert!(is_x86_feature_detected!("ssse3"), "SSSE3 is not supported");
    |
 
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
new file mode 100644
index 0000000..d1f798b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
@@ -0,0 +1,98 @@
+//@revisions: edition2018 edition2021
+//@[edition2018] edition:2018
+//@[edition2021] edition:2021
+
+#![warn(clippy::manual_assert)]
+#![allow(dead_code, unused_doc_comments)]
+#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args, clippy::useless_vec)]
+
+macro_rules! one {
+    () => {
+        1
+    };
+}
+
+fn main() {
+    let a = vec![1, 2, 3];
+    let c = Some(2);
+    if !a.is_empty()
+        && a.len() == 3
+        && c.is_some()
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+        && !a.is_empty()
+        && a.len() == 3
+    {
+        panic!("qaqaq{:?}", a);
+    }
+    //~^ manual_assert
+    assert!(a.is_empty(), "qaqaq{:?}", a);
+    //~^ manual_assert
+    assert!(a.is_empty(), "qwqwq");
+    if a.len() == 3 {
+        println!("qwq");
+        println!("qwq");
+        println!("qwq");
+    }
+    if let Some(b) = c {
+        panic!("orz {}", b);
+    }
+    if a.len() == 3 {
+        panic!("qaqaq");
+    } else {
+        println!("qwq");
+    }
+    let b = vec![1, 2, 3];
+    //~^ manual_assert
+    assert!(!b.is_empty(), "panic1");
+    //~^ manual_assert
+    assert!(!(b.is_empty() && a.is_empty()), "panic2");
+    //~^ manual_assert
+    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+    //~^ manual_assert
+    assert!(!(b.is_empty() || a.is_empty()), "panic4");
+    //~^ manual_assert
+    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+    //~^ manual_assert
+    assert!(!a.is_empty(), "with expansion {}", one!());
+    if a.is_empty() {
+        let _ = 0;
+    } else if a.len() == 1 {
+        panic!("panic6");
+    }
+}
+
+fn issue7730(a: u8) {
+    // Suggestion should preserve comment
+    //~^ manual_assert
+    // comment
+    /* this is a
+            multiline
+            comment */
+    /// Doc comment
+    // comment after `panic!`
+    assert!(a <= 2, "panic with comment");
+}
+
+fn issue12505() {
+    struct Foo<T, const N: usize>(T);
+
+    impl<T, const N: usize> Foo<T, N> {
+        const BAR: () = //~^ manual_assert
+        assert!(N != 0, );
+    }
+}
+
+fn issue15227(left: u64, right: u64) -> u64 {
+    macro_rules! is_x86_feature_detected {
+        ($feature:literal) => {
+            $feature.len() > 0 && $feature.starts_with("ss")
+        };
+    }
+
+    //~^ manual_assert
+    assert!(is_x86_feature_detected!("ssse3"), "SSSE3 is not supported");
+    unsafe { todo!() }
+}
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
index 2e9c904..c81a855 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
@@ -1,5 +1,5 @@
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:32:5
+  --> tests/ui/manual_assert.rs:30:5
    |
 LL | /     if !a.is_empty() {
 LL | |
@@ -9,17 +9,14 @@
    |
    = note: `-D clippy::manual-assert` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::manual_assert)]`
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if !a.is_empty() {
-LL -
-LL -         panic!("qaqaq{:?}", a);
-LL -     }
+LL ~
 LL +     assert!(a.is_empty(), "qaqaq{:?}", a);
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:36:5
+  --> tests/ui/manual_assert.rs:34:5
    |
 LL | /     if !a.is_empty() {
 LL | |
@@ -27,17 +24,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if !a.is_empty() {
-LL -
-LL -         panic!("qwqwq");
-LL -     }
+LL ~
 LL +     assert!(a.is_empty(), "qwqwq");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:54:5
+  --> tests/ui/manual_assert.rs:52:5
    |
 LL | /     if b.is_empty() {
 LL | |
@@ -45,17 +39,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if b.is_empty() {
-LL -
-LL -         panic!("panic1");
-LL -     }
+LL ~
 LL +     assert!(!b.is_empty(), "panic1");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:58:5
+  --> tests/ui/manual_assert.rs:56:5
    |
 LL | /     if b.is_empty() && a.is_empty() {
 LL | |
@@ -63,17 +54,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if b.is_empty() && a.is_empty() {
-LL -
-LL -         panic!("panic2");
-LL -     }
+LL ~
 LL +     assert!(!(b.is_empty() && a.is_empty()), "panic2");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:62:5
+  --> tests/ui/manual_assert.rs:60:5
    |
 LL | /     if a.is_empty() && !b.is_empty() {
 LL | |
@@ -81,17 +69,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if a.is_empty() && !b.is_empty() {
-LL -
-LL -         panic!("panic3");
-LL -     }
+LL ~
 LL +     assert!(!(a.is_empty() && !b.is_empty()), "panic3");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:66:5
+  --> tests/ui/manual_assert.rs:64:5
    |
 LL | /     if b.is_empty() || a.is_empty() {
 LL | |
@@ -99,17 +84,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if b.is_empty() || a.is_empty() {
-LL -
-LL -         panic!("panic4");
-LL -     }
+LL ~
 LL +     assert!(!(b.is_empty() || a.is_empty()), "panic4");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:70:5
+  --> tests/ui/manual_assert.rs:68:5
    |
 LL | /     if a.is_empty() || !b.is_empty() {
 LL | |
@@ -117,17 +99,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if a.is_empty() || !b.is_empty() {
-LL -
-LL -         panic!("panic5");
-LL -     }
+LL ~
 LL +     assert!(!(a.is_empty() || !b.is_empty()), "panic5");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:74:5
+  --> tests/ui/manual_assert.rs:72:5
    |
 LL | /     if a.is_empty() {
 LL | |
@@ -135,17 +114,14 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if a.is_empty() {
-LL -
-LL -         panic!("with expansion {}", one!())
-LL -     }
+LL ~
 LL +     assert!(!a.is_empty(), "with expansion {}", one!());
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:87:5
+  --> tests/ui/manual_assert.rs:85:5
    |
 LL | /     if a > 2 {
 LL | |
@@ -156,22 +132,20 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if a > 2 {
-LL -
-LL -         // comment
-LL -         /* this is a
-LL -         multiline
-LL -         comment */
-LL -         /// Doc comment
-LL -         panic!("panic with comment") // comment after `panic!`
-LL -     }
+LL ~
+LL +     // comment
+LL +     /* this is a
+LL +             multiline
+LL +             comment */
+LL +     /// Doc comment
+LL +     // comment after `panic!`
 LL +     assert!(a <= 2, "panic with comment");
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:102:25
+  --> tests/ui/manual_assert.rs:100:25
    |
 LL |           const BAR: () = if N == 0 {
    |  _________________________^
@@ -180,17 +154,14 @@
 LL | |         };
    | |_________^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -         const BAR: () = if N == 0 {
-LL -
-LL -             panic!()
-LL -         };
-LL +         const BAR: () = assert!(N != 0, );
+LL ~         const BAR: () =
+LL ~         assert!(N != 0, );
    |
 
 error: only a `panic!` in `if`-then statement
-  --> tests/ui/manual_assert.rs:116:5
+  --> tests/ui/manual_assert.rs:114:5
    |
 LL | /     if !is_x86_feature_detected!("ssse3") {
 LL | |
@@ -198,12 +169,9 @@
 LL | |     }
    | |_____^
    |
-help: try instead
+help: replace `if`-then-`panic!` with `assert!`
    |
-LL -     if !is_x86_feature_detected!("ssse3") {
-LL -
-LL -         panic!("SSSE3 is not supported");
-LL -     }
+LL ~
 LL +     assert!(is_x86_feature_detected!("ssse3"), "SSSE3 is not supported");
    |
 
diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs
index ab02bd5..7611795 100644
--- a/src/tools/clippy/tests/ui/manual_assert.rs
+++ b/src/tools/clippy/tests/ui/manual_assert.rs
@@ -2,8 +2,6 @@
 //@[edition2018] edition:2018
 //@[edition2021] edition:2021
 
-//@no-rustfix: need to change the suggestion to a multipart suggestion
-
 #![warn(clippy::manual_assert)]
 #![allow(dead_code, unused_doc_comments)]
 #![allow(clippy::nonminimal_bool, clippy::uninlined_format_args, clippy::useless_vec)]
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.fixed b/src/tools/clippy/tests/ui/manual_div_ceil.fixed
index 58ee697..cd91be8 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.fixed
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.fixed
@@ -100,3 +100,8 @@
     let _ = (-8 + y) / -7;
     let _ = (y - 8) / -7;
 }
+
+fn issue_15705(size: u64, c: &u64) {
+    let _ = size.div_ceil(*c);
+    //~^ manual_div_ceil
+}
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.rs b/src/tools/clippy/tests/ui/manual_div_ceil.rs
index aa0d81b..9899c7d 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.rs
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.rs
@@ -100,3 +100,8 @@ fn issue_13950() {
     let _ = (-8 + y) / -7;
     let _ = (y - 8) / -7;
 }
+
+fn issue_15705(size: u64, c: &u64) {
+    let _ = (size + c - 1) / c;
+    //~^ manual_div_ceil
+}
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.stderr b/src/tools/clippy/tests/ui/manual_div_ceil.stderr
index 9be5a19..44de3ba 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.stderr
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.stderr
@@ -125,5 +125,11 @@
 LL |     let _ = (7 + x) / 8;
    |             ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)`
 
-error: aborting due to 19 previous errors
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:105:13
+   |
+LL |     let _ = (size + c - 1) / c;
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `size.div_ceil(*c)`
+
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_rotate.fixed b/src/tools/clippy/tests/ui/manual_rotate.fixed
index 49db866..1012ffc 100644
--- a/src/tools/clippy/tests/ui/manual_rotate.fixed
+++ b/src/tools/clippy/tests/ui/manual_rotate.fixed
@@ -4,6 +4,7 @@
     let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64);
     let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64);
     let a_u32 = 1u32;
+    const N: u32 = 5;
     // True positives
     let y_u8 = x_u8.rotate_right(3);
     //~^ manual_rotate
@@ -29,6 +30,9 @@
     //~^ manual_rotate
     let y_u64_as = (x_u32 as u64).rotate_right(8);
     //~^ manual_rotate
+    // shift by a const
+    let _ = x_i64.rotate_right(N);
+    //~^ manual_rotate
 
     // False positives - can't be replaced with a rotation
     let y_u8_false = (x_u8 >> 6) | (x_u8 << 3);
@@ -40,3 +44,20 @@
     let mut l = vec![12_u8, 34];
     let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5);
 }
+
+fn issue13028() {
+    let s = 5;
+    let u = 5;
+    let x: u32 = 123456;
+
+    let _ = x.rotate_left(s);
+    //~^ manual_rotate
+    let _ = x.rotate_left(s);
+    //~^ manual_rotate
+    // still works with consts
+    let _ = x.rotate_right(9);
+    //~^ manual_rotate
+
+    // don't lint, because `s` and `u` are different variables, albeit with the same value
+    let _ = (x << s) | (x >> (32 - u));
+}
diff --git a/src/tools/clippy/tests/ui/manual_rotate.rs b/src/tools/clippy/tests/ui/manual_rotate.rs
index 6445e60..3cdc796 100644
--- a/src/tools/clippy/tests/ui/manual_rotate.rs
+++ b/src/tools/clippy/tests/ui/manual_rotate.rs
@@ -4,6 +4,7 @@ fn main() {
     let (x_u8, x_u16, x_u32, x_u64) = (1u8, 1u16, 1u32, 1u64);
     let (x_i8, x_i16, x_i32, x_i64) = (1i8, 1i16, 1i32, 1i64);
     let a_u32 = 1u32;
+    const N: u32 = 5;
     // True positives
     let y_u8 = (x_u8 >> 3) | (x_u8 << 5);
     //~^ manual_rotate
@@ -29,6 +30,9 @@ fn main() {
     //~^ manual_rotate
     let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56);
     //~^ manual_rotate
+    // shift by a const
+    let _ = (x_i64 >> N) | (x_i64 << (64 - N));
+    //~^ manual_rotate
 
     // False positives - can't be replaced with a rotation
     let y_u8_false = (x_u8 >> 6) | (x_u8 << 3);
@@ -40,3 +44,20 @@ fn main() {
     let mut l = vec![12_u8, 34];
     let y = (l.pop().unwrap() << 3) + (l.pop().unwrap() >> 5);
 }
+
+fn issue13028() {
+    let s = 5;
+    let u = 5;
+    let x: u32 = 123456;
+
+    let _ = (x << s) | (x >> (32 - s));
+    //~^ manual_rotate
+    let _ = (x << s) | (x >> (31 ^ s));
+    //~^ manual_rotate
+    // still works with consts
+    let _ = (x >> 9) | (x << (32 - 9));
+    //~^ manual_rotate
+
+    // don't lint, because `s` and `u` are different variables, albeit with the same value
+    let _ = (x << s) | (x >> (32 - u));
+}
diff --git a/src/tools/clippy/tests/ui/manual_rotate.stderr b/src/tools/clippy/tests/ui/manual_rotate.stderr
index a28721f..ea04ee0 100644
--- a/src/tools/clippy/tests/ui/manual_rotate.stderr
+++ b/src/tools/clippy/tests/ui/manual_rotate.stderr
@@ -1,5 +1,5 @@
 error: there is no need to manually implement bit rotation
-  --> tests/ui/manual_rotate.rs:8:16
+  --> tests/ui/manual_rotate.rs:9:16
    |
 LL |     let y_u8 = (x_u8 >> 3) | (x_u8 << 5);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u8.rotate_right(3)`
@@ -8,64 +8,88 @@
    = help: to override `-D warnings` add `#[allow(clippy::manual_rotate)]`
 
 error: there is no need to manually implement bit rotation
-  --> tests/ui/manual_rotate.rs:10:17
+  --> tests/ui/manual_rotate.rs:11:17
    |
 LL |     let y_u16 = (x_u16 >> 7) | (x_u16 << 9);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u16.rotate_right(7)`
 
 error: there is no need to manually implement bit rotation
-  --> tests/ui/manual_rotate.rs:12:17
+  --> tests/ui/manual_rotate.rs:13:17
    |
 LL |     let y_u32 = (x_u32 >> 8) | (x_u32 << 24);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)`
 
 error: there is no need to manually implement bit rotation
-  --> tests/ui/manual_rotate.rs:14:17
+  --> tests/ui/manual_rotate.rs:15:17
    |
 LL |     let y_u64 = (x_u64 >> 9) | (x_u64 << 55);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u64.rotate_right(9)`
 
 error: there is no need to manually implement bit rotation
-  --> tests/ui/manual_rotate.rs:16:16
+  --> tests/ui/manual_rotate.rs:17:16
    |
 LL |     let y_i8 = (x_i8 >> 3) | (x_i8 << 5);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i8.rotate_right(3)`
 
 error: there is no need to manually implement bit rotation
-  --> tests/ui/manual_rotate.rs:18:17
+  --> tests/ui/manual_rotate.rs:19:17
    |
 LL |     let y_i16 = (x_i16 >> 7) | (x_i16 << 9);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i16.rotate_right(7)`
 
 error: there is no need to manually implement bit rotation
-  --> tests/ui/manual_rotate.rs:20:17
+  --> tests/ui/manual_rotate.rs:21:17
    |
 LL |     let y_i32 = (x_i32 >> 8) | (x_i32 << 24);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i32.rotate_right(8)`
 
 error: there is no need to manually implement bit rotation
-  --> tests/ui/manual_rotate.rs:22:17
+  --> tests/ui/manual_rotate.rs:23:17
    |
 LL |     let y_i64 = (x_i64 >> 9) | (x_i64 << 55);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i64.rotate_right(9)`
 
 error: there is no need to manually implement bit rotation
-  --> tests/ui/manual_rotate.rs:25:22
+  --> tests/ui/manual_rotate.rs:26:22
    |
 LL |     let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)`
 
 error: there is no need to manually implement bit rotation
-  --> tests/ui/manual_rotate.rs:28:25
+  --> tests/ui/manual_rotate.rs:29:25
    |
 LL |     let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 | 3256).rotate_right(8)`
 
 error: there is no need to manually implement bit rotation
-  --> tests/ui/manual_rotate.rs:30:20
+  --> tests/ui/manual_rotate.rs:31:20
    |
 LL |     let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 as u64).rotate_right(8)`
 
-error: aborting due to 11 previous errors
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:34:13
+   |
+LL |     let _ = (x_i64 >> N) | (x_i64 << (64 - N));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i64.rotate_right(N)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:53:13
+   |
+LL |     let _ = (x << s) | (x >> (32 - s));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x.rotate_left(s)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:55:13
+   |
+LL |     let _ = (x << s) | (x >> (31 ^ s));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x.rotate_left(s)`
+
+error: there is no need to manually implement bit rotation
+  --> tests/ui/manual_rotate.rs:58:13
+   |
+LL |     let _ = (x >> 9) | (x << (32 - 9));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x.rotate_right(9)`
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
index 189fe87..11023ac 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
@@ -32,6 +32,15 @@
 
     let x: Result<String, i64> = Ok(String::new());
     x.unwrap_or_default();
+
+    // edge case
+    // because the `Some(bizarro)` pattern is not actually reachable,
+    // changing this match to `unwrap_or_default` would have side effects
+    let bizarro = Some(String::new());
+    match bizarro {
+        _ => String::new(),
+        Some(bizarro) => bizarro,
+    };
 }
 
 // Issue #12531
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
index ca87926..bf06d9a 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
@@ -64,6 +64,15 @@ fn main() {
     } else {
         String::new()
     };
+
+    // edge case
+    // because the `Some(bizarro)` pattern is not actually reachable,
+    // changing this match to `unwrap_or_default` would have side effects
+    let bizarro = Some(String::new());
+    match bizarro {
+        _ => String::new(),
+        Some(bizarro) => bizarro,
+    };
 }
 
 // Issue #12531
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr
index e8f38a2..0311008 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr
@@ -76,7 +76,7 @@
    | |_____^ help: replace it with: `x.unwrap_or_default()`
 
 error: match can be simplified with `.unwrap_or_default()`
-  --> tests/ui/manual_unwrap_or_default.rs:74:24
+  --> tests/ui/manual_unwrap_or_default.rs:83:24
    |
 LL |               Some(_) => match *b {
    |  ________________________^
@@ -87,7 +87,7 @@
    | |_____________^ help: replace it with: `(*b).unwrap_or_default()`
 
 error: if let can be simplified with `.unwrap_or_default()`
-  --> tests/ui/manual_unwrap_or_default.rs:143:5
+  --> tests/ui/manual_unwrap_or_default.rs:152:5
    |
 LL | /     if let Some(x) = Some(42) {
 LL | |
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_like_matches_macro.fixed
similarity index 97%
rename from src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
rename to src/tools/clippy/tests/ui/match_like_matches_macro.fixed
index 8530ab1..a1c95e8 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
+++ b/src/tools/clippy/tests/ui/match_like_matches_macro.fixed
@@ -1,7 +1,6 @@
 #![warn(clippy::match_like_matches_macro)]
 #![allow(
     unreachable_patterns,
-    dead_code,
     clippy::equatable_if_let,
     clippy::needless_borrowed_reference,
     clippy::redundant_guards
@@ -14,11 +13,11 @@
     let _y = matches!(x, Some(0));
     //~^^^^ match_like_matches_macro
 
-    // Lint
+    // No lint: covered by `redundant_pattern_matching`
     let _w = x.is_some();
     //~^^^^ redundant_pattern_matching
 
-    // Turn into is_none
+    // No lint: covered by `redundant_pattern_matching`
     let _z = x.is_none();
     //~^^^^ redundant_pattern_matching
 
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_like_matches_macro.rs
similarity index 97%
rename from src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
rename to src/tools/clippy/tests/ui/match_like_matches_macro.rs
index 8101793..eb419ba5 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
+++ b/src/tools/clippy/tests/ui/match_like_matches_macro.rs
@@ -1,7 +1,6 @@
 #![warn(clippy::match_like_matches_macro)]
 #![allow(
     unreachable_patterns,
-    dead_code,
     clippy::equatable_if_let,
     clippy::needless_borrowed_reference,
     clippy::redundant_guards
@@ -17,14 +16,14 @@ fn main() {
     };
     //~^^^^ match_like_matches_macro
 
-    // Lint
+    // No lint: covered by `redundant_pattern_matching`
     let _w = match x {
         Some(_) => true,
         _ => false,
     };
     //~^^^^ redundant_pattern_matching
 
-    // Turn into is_none
+    // No lint: covered by `redundant_pattern_matching`
     let _z = match x {
         Some(_) => false,
         None => true,
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_like_matches_macro.stderr
similarity index 84%
rename from src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
rename to src/tools/clippy/tests/ui/match_like_matches_macro.stderr
index 8fceb05..ae277ce 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
+++ b/src/tools/clippy/tests/ui/match_like_matches_macro.stderr
@@ -1,5 +1,5 @@
 error: match expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:14:14
+  --> tests/ui/match_like_matches_macro.rs:13:14
    |
 LL |       let _y = match x {
    |  ______________^
@@ -12,7 +12,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::match_like_matches_macro)]`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> tests/ui/match_expr_like_matches_macro.rs:21:14
+  --> tests/ui/match_like_matches_macro.rs:20:14
    |
 LL |       let _w = match x {
    |  ______________^
@@ -25,7 +25,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> tests/ui/match_expr_like_matches_macro.rs:28:14
+  --> tests/ui/match_like_matches_macro.rs:27:14
    |
 LL |       let _z = match x {
    |  ______________^
@@ -35,7 +35,7 @@
    | |_____^ help: try: `x.is_none()`
 
 error: match expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:35:15
+  --> tests/ui/match_like_matches_macro.rs:34:15
    |
 LL |       let _zz = match x {
    |  _______________^
@@ -45,13 +45,13 @@
    | |_____^ help: try: `!matches!(x, Some(r) if r == 0)`
 
 error: if let .. else expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:42:16
+  --> tests/ui/match_like_matches_macro.rs:41:16
    |
 LL |     let _zzz = if let Some(5) = x { true } else { false };
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(x, Some(5))`
 
 error: match expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:67:20
+  --> tests/ui/match_like_matches_macro.rs:66:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -62,7 +62,7 @@
    | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:78:20
+  --> tests/ui/match_like_matches_macro.rs:77:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -74,7 +74,7 @@
    | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:89:20
+  --> tests/ui/match_like_matches_macro.rs:88:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -85,7 +85,7 @@
    | |_________^ help: try: `!matches!(x, E::B(_) | E::C)`
 
 error: match expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:150:18
+  --> tests/ui/match_like_matches_macro.rs:149:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -95,7 +95,7 @@
    | |_________^ help: try: `matches!(z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:160:18
+  --> tests/ui/match_like_matches_macro.rs:159:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -105,7 +105,7 @@
    | |_________^ help: try: `matches!(&z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:178:21
+  --> tests/ui/match_like_matches_macro.rs:177:21
    |
 LL |               let _ = match &z {
    |  _____________________^
@@ -115,7 +115,7 @@
    | |_____________^ help: try: `matches!(&z, AnEnum::X)`
 
 error: match expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:193:20
+  --> tests/ui/match_like_matches_macro.rs:192:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -125,7 +125,7 @@
    | |_________^ help: try: `matches!(&val, &Some(ref _a))`
 
 error: match expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:206:20
+  --> tests/ui/match_like_matches_macro.rs:205:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -135,7 +135,7 @@
    | |_________^ help: try: `matches!(&val, &Some(ref _a))`
 
 error: match expression looks like `matches!` macro
-  --> tests/ui/match_expr_like_matches_macro.rs:265:14
+  --> tests/ui/match_like_matches_macro.rs:264:14
    |
 LL |       let _y = match Some(5) {
    |  ______________^
diff --git a/src/tools/clippy/tests/ui/must_use_unit_unfixable.rs b/src/tools/clippy/tests/ui/must_use_unit_unfixable.rs
index 0dba799..8eeaf36 100644
--- a/src/tools/clippy/tests/ui/must_use_unit_unfixable.rs
+++ b/src/tools/clippy/tests/ui/must_use_unit_unfixable.rs
@@ -1,5 +1,3 @@
-//@no-rustfix
-
 #[cfg_attr(all(), must_use, deprecated)]
 fn issue_12320() {}
 //~^ must_use_unit
diff --git a/src/tools/clippy/tests/ui/must_use_unit_unfixable.stderr b/src/tools/clippy/tests/ui/must_use_unit_unfixable.stderr
index 0876821..8b5e556 100644
--- a/src/tools/clippy/tests/ui/must_use_unit_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/must_use_unit_unfixable.stderr
@@ -1,11 +1,11 @@
 error: this unit-returning function has a `#[must_use]` attribute
-  --> tests/ui/must_use_unit_unfixable.rs:4:1
+  --> tests/ui/must_use_unit_unfixable.rs:2:1
    |
 LL | fn issue_12320() {}
    | ^^^^^^^^^^^^^^^^
    |
 help: remove `must_use`
-  --> tests/ui/must_use_unit_unfixable.rs:3:19
+  --> tests/ui/must_use_unit_unfixable.rs:1:19
    |
 LL | #[cfg_attr(all(), must_use, deprecated)]
    |                   ^^^^^^^^
@@ -13,13 +13,13 @@
    = help: to override `-D warnings` add `#[allow(clippy::must_use_unit)]`
 
 error: this unit-returning function has a `#[must_use]` attribute
-  --> tests/ui/must_use_unit_unfixable.rs:8:1
+  --> tests/ui/must_use_unit_unfixable.rs:6:1
    |
 LL | fn issue_12320_2() {}
    | ^^^^^^^^^^^^^^^^^^
    |
 help: remove `must_use`
-  --> tests/ui/must_use_unit_unfixable.rs:7:44
+  --> tests/ui/must_use_unit_unfixable.rs:5:44
    |
 LL | #[cfg_attr(all(), deprecated, doc = "foo", must_use)]
    |                                            ^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/mutex_atomic.fixed b/src/tools/clippy/tests/ui/mutex_atomic.fixed
new file mode 100644
index 0000000..e421872
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mutex_atomic.fixed
@@ -0,0 +1,67 @@
+#![warn(clippy::mutex_integer)]
+#![warn(clippy::mutex_atomic)]
+#![allow(clippy::borrow_as_ptr)]
+
+use std::sync::Mutex;
+
+fn main() {
+    let _ = std::sync::atomic::AtomicBool::new(true);
+    //~^ mutex_atomic
+
+    let _ = std::sync::atomic::AtomicUsize::new(5usize);
+    //~^ mutex_atomic
+
+    let _ = std::sync::atomic::AtomicIsize::new(9isize);
+    //~^ mutex_atomic
+
+    let mut x = 4u32;
+    // `AtomicPtr` only accepts `*mut T`, so this should not lint
+    let _ = Mutex::new(&x as *const u32);
+
+    let _ = std::sync::atomic::AtomicPtr::new(&mut x as *mut u32);
+    //~^ mutex_atomic
+
+    let _ = std::sync::atomic::AtomicU32::new(0u32);
+    //~^ mutex_integer
+
+    let _ = std::sync::atomic::AtomicI32::new(0i32);
+    //~^ mutex_integer
+
+    let _ = Mutex::new(0f32); // there are no float atomics, so this should not lint
+    let _ = std::sync::atomic::AtomicU8::new(0u8);
+    //~^ mutex_integer
+
+    let _ = std::sync::atomic::AtomicI16::new(0i16);
+    //~^ mutex_integer
+
+    let _x = std::sync::atomic::AtomicI8::new(0);
+    //~^ mutex_integer
+
+    const X: i64 = 0;
+    let _ = std::sync::atomic::AtomicI64::new(X);
+    //~^ mutex_integer
+
+    // there are no 128 atomics, so these two should not lint
+    {
+        let _ = Mutex::new(0u128);
+        let _x: Mutex<i128> = Mutex::new(0);
+    }
+}
+
+// don't lint on _use_, only declaration
+fn issue13378() {
+    static MTX: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
+    //~^ mutex_integer
+
+    let mtx = std::sync::atomic::AtomicI32::new(0);
+    //~^ mutex_integer
+    // This will still lint, since we're reassigning the mutex to a variable -- oh well.
+    // But realistically something like this won't really come up.
+    let reassigned = mtx;
+    //~^ mutex_integer
+
+    // don't eat the `)` when removing the type ascription -- see
+    // https://github.com/rust-lang/rust-clippy/issues/15377
+    let (funky_mtx) = std::sync::atomic::AtomicU64::new(0);
+    //~^ mutex_integer
+}
diff --git a/src/tools/clippy/tests/ui/mutex_atomic.rs b/src/tools/clippy/tests/ui/mutex_atomic.rs
index 7db5c9f..95f2b13 100644
--- a/src/tools/clippy/tests/ui/mutex_atomic.rs
+++ b/src/tools/clippy/tests/ui/mutex_atomic.rs
@@ -2,47 +2,66 @@
 #![warn(clippy::mutex_atomic)]
 #![allow(clippy::borrow_as_ptr)]
 
+use std::sync::Mutex;
+
 fn main() {
-    use std::sync::Mutex;
-    Mutex::new(true);
+    let _ = Mutex::new(true);
     //~^ mutex_atomic
 
-    Mutex::new(5usize);
+    let _ = Mutex::new(5usize);
     //~^ mutex_atomic
 
-    Mutex::new(9isize);
+    let _ = Mutex::new(9isize);
     //~^ mutex_atomic
 
     let mut x = 4u32;
-    Mutex::new(&x as *const u32);
+    // `AtomicPtr` only accepts `*mut T`, so this should not lint
+    let _ = Mutex::new(&x as *const u32);
+
+    let _ = Mutex::new(&mut x as *mut u32);
     //~^ mutex_atomic
 
-    Mutex::new(&mut x as *mut u32);
-    //~^ mutex_atomic
-
-    Mutex::new(0u32);
+    let _ = Mutex::new(0u32);
     //~^ mutex_integer
 
-    Mutex::new(0i32);
+    let _ = Mutex::new(0i32);
     //~^ mutex_integer
 
-    Mutex::new(0f32); // there are no float atomics, so this should not lint
-    Mutex::new(0u8);
+    let _ = Mutex::new(0f32); // there are no float atomics, so this should not lint
+    let _ = Mutex::new(0u8);
     //~^ mutex_integer
 
-    Mutex::new(0i16);
+    let _ = Mutex::new(0i16);
     //~^ mutex_integer
 
     let _x: Mutex<i8> = Mutex::new(0);
     //~^ mutex_integer
 
     const X: i64 = 0;
-    Mutex::new(X);
+    let _ = Mutex::new(X);
     //~^ mutex_integer
 
     // there are no 128 atomics, so these two should not lint
     {
-        Mutex::new(0u128);
+        let _ = Mutex::new(0u128);
         let _x: Mutex<i128> = Mutex::new(0);
     }
 }
+
+// don't lint on _use_, only declaration
+fn issue13378() {
+    static MTX: Mutex<u32> = Mutex::new(0);
+    //~^ mutex_integer
+
+    let mtx = Mutex::new(0);
+    //~^ mutex_integer
+    // This will still lint, since we're reassigning the mutex to a variable -- oh well.
+    // But realistically something like this won't really come up.
+    let reassigned = mtx;
+    //~^ mutex_integer
+
+    // don't eat the `)` when removing the type ascription -- see
+    // https://github.com/rust-lang/rust-clippy/issues/15377
+    let (funky_mtx): Mutex<u64> = Mutex::new(0);
+    //~^ mutex_integer
+}
diff --git a/src/tools/clippy/tests/ui/mutex_atomic.stderr b/src/tools/clippy/tests/ui/mutex_atomic.stderr
index a6d5d60..0afc6d5 100644
--- a/src/tools/clippy/tests/ui/mutex_atomic.stderr
+++ b/src/tools/clippy/tests/ui/mutex_atomic.stderr
@@ -1,74 +1,134 @@
-error: consider using an `AtomicBool` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> tests/ui/mutex_atomic.rs:7:5
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:8:13
    |
-LL |     Mutex::new(true);
-   |     ^^^^^^^^^^^^^^^^
+LL |     let _ = Mutex::new(true);
+   |             ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicBool::new(true)`
    |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
    = note: `-D clippy::mutex-atomic` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::mutex_atomic)]`
 
-error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> tests/ui/mutex_atomic.rs:10:5
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:11:13
    |
-LL |     Mutex::new(5usize);
-   |     ^^^^^^^^^^^^^^^^^^
+LL |     let _ = Mutex::new(5usize);
+   |             ^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicUsize::new(5usize)`
+   |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 
-error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> tests/ui/mutex_atomic.rs:13:5
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:14:13
    |
-LL |     Mutex::new(9isize);
-   |     ^^^^^^^^^^^^^^^^^^
+LL |     let _ = Mutex::new(9isize);
+   |             ^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicIsize::new(9isize)`
+   |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 
-error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> tests/ui/mutex_atomic.rs:17:5
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:21:13
    |
-LL |     Mutex::new(&x as *const u32);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _ = Mutex::new(&mut x as *mut u32);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicPtr::new(&mut x as *mut u32)`
+   |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 
-error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> tests/ui/mutex_atomic.rs:20:5
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:24:13
    |
-LL |     Mutex::new(&mut x as *mut u32);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: consider using an `AtomicU32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> tests/ui/mutex_atomic.rs:23:5
+LL |     let _ = Mutex::new(0u32);
+   |             ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU32::new(0u32)`
    |
-LL |     Mutex::new(0u32);
-   |     ^^^^^^^^^^^^^^^^
-   |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
    = note: `-D clippy::mutex-integer` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::mutex_integer)]`
 
-error: consider using an `AtomicI32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> tests/ui/mutex_atomic.rs:26:5
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:27:13
    |
-LL |     Mutex::new(0i32);
-   |     ^^^^^^^^^^^^^^^^
-
-error: consider using an `AtomicU8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> tests/ui/mutex_atomic.rs:30:5
+LL |     let _ = Mutex::new(0i32);
+   |             ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI32::new(0i32)`
    |
-LL |     Mutex::new(0u8);
-   |     ^^^^^^^^^^^^^^^
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 
-error: consider using an `AtomicI16` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> tests/ui/mutex_atomic.rs:33:5
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:31:13
    |
-LL |     Mutex::new(0i16);
-   |     ^^^^^^^^^^^^^^^^
+LL |     let _ = Mutex::new(0u8);
+   |             ^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU8::new(0u8)`
+   |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
 
-error: consider using an `AtomicI8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> tests/ui/mutex_atomic.rs:36:25
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:34:13
+   |
+LL |     let _ = Mutex::new(0i16);
+   |             ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI16::new(0i16)`
+   |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:37:25
    |
 LL |     let _x: Mutex<i8> = Mutex::new(0);
    |                         ^^^^^^^^^^^^^
-
-error: consider using an `AtomicI64` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> tests/ui/mutex_atomic.rs:40:5
    |
-LL |     Mutex::new(X);
-   |     ^^^^^^^^^^^^^
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+help: try
+   |
+LL -     let _x: Mutex<i8> = Mutex::new(0);
+LL +     let _x = std::sync::atomic::AtomicI8::new(0);
+   |
 
-error: aborting due to 11 previous errors
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:41:13
+   |
+LL |     let _ = Mutex::new(X);
+   |             ^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI64::new(X)`
+   |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:53:30
+   |
+LL |     static MTX: Mutex<u32> = Mutex::new(0);
+   |                              ^^^^^^^^^^^^^
+   |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+help: try
+   |
+LL -     static MTX: Mutex<u32> = Mutex::new(0);
+LL +     static MTX: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
+   |
+
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:56:15
+   |
+LL |     let mtx = Mutex::new(0);
+   |               ^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI32::new(0)`
+   |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:60:22
+   |
+LL |     let reassigned = mtx;
+   |                      ^^^
+   |
+   = help: consider using an `AtomicI32` instead
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic.rs:65:35
+   |
+LL |     let (funky_mtx): Mutex<u64> = Mutex::new(0);
+   |                                   ^^^^^^^^^^^^^
+   |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+help: try
+   |
+LL -     let (funky_mtx): Mutex<u64> = Mutex::new(0);
+LL +     let (funky_mtx) = std::sync::atomic::AtomicU64::new(0);
+   |
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/mutex_atomic_unfixable.rs b/src/tools/clippy/tests/ui/mutex_atomic_unfixable.rs
new file mode 100644
index 0000000..0c04f48
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mutex_atomic_unfixable.rs
@@ -0,0 +1,13 @@
+//@no-rustfix
+#![warn(clippy::mutex_atomic, clippy::mutex_integer)]
+
+use std::sync::Mutex;
+
+fn issue13378() {
+    static MTX: Mutex<u32> = Mutex::new(0);
+    //~^ mutex_integer
+
+    // unfixable because we don't fix this `lock`
+    let mut guard = MTX.lock().unwrap();
+    *guard += 1;
+}
diff --git a/src/tools/clippy/tests/ui/mutex_atomic_unfixable.stderr b/src/tools/clippy/tests/ui/mutex_atomic_unfixable.stderr
new file mode 100644
index 0000000..27ffb13
--- /dev/null
+++ b/src/tools/clippy/tests/ui/mutex_atomic_unfixable.stderr
@@ -0,0 +1,17 @@
+error: using a `Mutex` where an atomic would do
+  --> tests/ui/mutex_atomic_unfixable.rs:7:30
+   |
+LL |     static MTX: Mutex<u32> = Mutex::new(0);
+   |                              ^^^^^^^^^^^^^
+   |
+   = help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+   = note: `-D clippy::mutex-integer` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::mutex_integer)]`
+help: try
+   |
+LL -     static MTX: Mutex<u32> = Mutex::new(0);
+LL +     static MTX: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.fixed b/src/tools/clippy/tests/ui/needless_borrow_pat.fixed
index fe966a7..5071866 100644
--- a/src/tools/clippy/tests/ui/needless_borrow_pat.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow_pat.fixed
@@ -1,5 +1,3 @@
-// FIXME: run-rustfix waiting on multi-span suggestions
-
 #![warn(clippy::needless_borrow)]
 #![allow(clippy::needless_borrowed_reference, clippy::explicit_auto_deref)]
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.rs b/src/tools/clippy/tests/ui/needless_borrow_pat.rs
index a6b4385..ef0f973 100644
--- a/src/tools/clippy/tests/ui/needless_borrow_pat.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow_pat.rs
@@ -1,5 +1,3 @@
-// FIXME: run-rustfix waiting on multi-span suggestions
-
 #![warn(clippy::needless_borrow)]
 #![allow(clippy::needless_borrowed_reference, clippy::explicit_auto_deref)]
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr
index 25c570e..34f167c 100644
--- a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr
@@ -1,5 +1,5 @@
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:59:14
+  --> tests/ui/needless_borrow_pat.rs:57:14
    |
 LL |         Some(ref x) => x,
    |              ^^^^^ help: try: `x`
@@ -8,7 +8,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]`
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:66:14
+  --> tests/ui/needless_borrow_pat.rs:64:14
    |
 LL |         Some(ref x) => *x,
    |              ^^^^^
@@ -20,7 +20,7 @@
    |
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:73:14
+  --> tests/ui/needless_borrow_pat.rs:71:14
    |
 LL |         Some(ref x) => {
    |              ^^^^^
@@ -35,19 +35,19 @@
    |
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:85:14
+  --> tests/ui/needless_borrow_pat.rs:83:14
    |
 LL |         Some(ref x) => m1!(x),
    |              ^^^^^ help: try: `x`
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:91:15
+  --> tests/ui/needless_borrow_pat.rs:89:15
    |
 LL |     let _ = |&ref x: &&String| {
    |               ^^^^^ help: try: `x`
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:98:10
+  --> tests/ui/needless_borrow_pat.rs:96:10
    |
 LL |     let (ref y,) = (&x,);
    |          ^^^^^
@@ -61,13 +61,13 @@
    |
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:110:14
+  --> tests/ui/needless_borrow_pat.rs:108:14
    |
 LL |         Some(ref x) => x.0,
    |              ^^^^^ help: try: `x`
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:121:14
+  --> tests/ui/needless_borrow_pat.rs:119:14
    |
 LL |         E::A(ref x) | E::B(ref x) => *x,
    |              ^^^^^         ^^^^^
@@ -79,13 +79,13 @@
    |
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:128:21
+  --> tests/ui/needless_borrow_pat.rs:126:21
    |
 LL |         if let Some(ref x) = Some(&String::new());
    |                     ^^^^^ help: try: `x`
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:138:12
+  --> tests/ui/needless_borrow_pat.rs:136:12
    |
 LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
    |            ^^^^^
@@ -100,13 +100,13 @@
    |
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:147:11
+  --> tests/ui/needless_borrow_pat.rs:145:11
    |
 LL |     fn f(&ref x: &&String) {
    |           ^^^^^ help: try: `x`
 
 error: this pattern creates a reference to a reference
-  --> tests/ui/needless_borrow_pat.rs:157:11
+  --> tests/ui/needless_borrow_pat.rs:155:11
    |
 LL |     fn f(&ref x: &&String) {
    |           ^^^^^
diff --git a/src/tools/clippy/tests/ui/needless_continue.rs b/src/tools/clippy/tests/ui/needless_continue.rs
index e873db6..88b7905 100644
--- a/src/tools/clippy/tests/ui/needless_continue.rs
+++ b/src/tools/clippy/tests/ui/needless_continue.rs
@@ -244,3 +244,101 @@ fn some_expr() -> bool {
         true
     }
 }
+
+#[allow(clippy::let_unit_value)]
+mod issue14550 {
+    fn match_with_value(mut producer: impl Iterator<Item = Result<i32, u32>>) -> Result<u32, u32> {
+        let mut counter = 2;
+        loop {
+            match producer.next().unwrap() {
+                Ok(ok) => break Ok((ok + 1) as u32),
+                Err(12) => {
+                    counter -= 1;
+                    continue;
+                },
+                err => err?,
+            };
+        }
+    }
+
+    fn inside_macro() {
+        macro_rules! mac {
+            ($e:expr => $($rest:tt);*) => {
+                loop {
+                    match $e {
+                        1 => continue,
+                        2 => break,
+                        n => println!("{n}"),
+                    }
+                    $($rest;)*
+                }
+            };
+        }
+
+        mac!(2 => );
+        mac!(1 => {println!("foobar")});
+    }
+
+    mod partially_inside_macro {
+        macro_rules! select {
+            (
+                $expr:expr,
+                $( $pat:pat => $then:expr ),*
+            ) => {
+                fn foo() {
+                    loop {
+                        match $expr {
+                            $(
+                                $pat => $then,
+                            )*
+                        }
+                    }
+                }
+            };
+        }
+
+        select!(Some(1),
+            Some(1) => {
+                println!("one");
+                continue;
+            },
+            Some(2) => {},
+            None => break,
+            _ => ()
+        );
+
+        macro_rules! choose {
+            (
+            $expr:expr,
+            $case:expr
+        ) => {
+                fn bar() {
+                    loop {
+                        match $expr {
+                            $case => {
+                                println!("matched");
+                                continue;
+                            },
+                            _ => {
+                                println!("not matched");
+                                break;
+                            },
+                        }
+                    }
+                }
+            };
+        }
+
+        choose!(todo!(), 5);
+    }
+}
+
+fn issue15548() {
+    loop {
+        if todo!() {
+        } else {
+            //~^ needless_continue
+            continue;
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_continue.stderr b/src/tools/clippy/tests/ui/needless_continue.stderr
index 878c1e7..7a65872 100644
--- a/src/tools/clippy/tests/ui/needless_continue.stderr
+++ b/src/tools/clippy/tests/ui/needless_continue.stderr
@@ -220,5 +220,21 @@
                            do_something();
                        }
 
-error: aborting due to 15 previous errors
+error: this `else` block is redundant
+  --> tests/ui/needless_continue.rs:339:16
+   |
+LL |           } else {
+   |  ________________^
+LL | |
+LL | |             continue;
+LL | |         }
+   | |_________^
+   |
+   = help: consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block
+                   if todo!() {
+           // merged code follows:
+           
+                   }
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/non_canonical_clone_impl.fixed b/src/tools/clippy/tests/ui/non_canonical_clone_impl.fixed
index 11616f2..d9be98d 100644
--- a/src/tools/clippy/tests/ui/non_canonical_clone_impl.fixed
+++ b/src/tools/clippy/tests/ui/non_canonical_clone_impl.fixed
@@ -4,7 +4,7 @@
 #![no_main]
 
 extern crate proc_macros;
-use proc_macros::with_span;
+use proc_macros::inline_macros;
 
 // lint
 
@@ -100,18 +100,45 @@
 
 impl<A: std::fmt::Debug + Copy + Clone> Copy for Uwu<A> {}
 
-// should skip proc macros, see https://github.com/rust-lang/rust-clippy/issues/12788
-#[derive(proc_macro_derive::NonCanonicalClone)]
-pub struct G;
+#[inline_macros]
+mod issue12788 {
+    use proc_macros::{external, with_span};
 
-with_span!(
-    span
+    // lint -- not an external macro
+    inline!(
+        #[derive(Copy)]
+        pub struct A;
 
-    #[derive(Copy)]
-    struct H;
-    impl Clone for H {
-        fn clone(&self) -> Self {
-            todo!()
+        impl Clone for A {
+            fn clone(&self) -> Self { *self }
         }
-    }
-);
+    );
+
+    // do not lint -- should skip external macros
+    external!(
+        #[derive(Copy)]
+        pub struct B;
+
+        impl Clone for B {
+            fn clone(&self) -> Self {
+                todo!()
+            }
+        }
+    );
+
+    // do not lint -- should skip proc macros
+    #[derive(proc_macro_derive::NonCanonicalClone)]
+    pub struct C;
+
+    with_span!(
+        span
+
+        #[derive(Copy)]
+        struct D;
+        impl Clone for D {
+            fn clone(&self) -> Self {
+                todo!()
+            }
+        }
+    );
+}
diff --git a/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs b/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs
index 7d10191..3db22bd 100644
--- a/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs
+++ b/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs
@@ -4,7 +4,7 @@
 #![no_main]
 
 extern crate proc_macros;
-use proc_macros::with_span;
+use proc_macros::inline_macros;
 
 // lint
 
@@ -114,18 +114,48 @@ fn clone_from(&mut self, source: &Self) {
 
 impl<A: std::fmt::Debug + Copy + Clone> Copy for Uwu<A> {}
 
-// should skip proc macros, see https://github.com/rust-lang/rust-clippy/issues/12788
-#[derive(proc_macro_derive::NonCanonicalClone)]
-pub struct G;
+#[inline_macros]
+mod issue12788 {
+    use proc_macros::{external, with_span};
 
-with_span!(
-    span
+    // lint -- not an external macro
+    inline!(
+        #[derive(Copy)]
+        pub struct A;
 
-    #[derive(Copy)]
-    struct H;
-    impl Clone for H {
-        fn clone(&self) -> Self {
-            todo!()
+        impl Clone for A {
+            fn clone(&self) -> Self {
+                //~^ non_canonical_clone_impl
+                todo!()
+            }
         }
-    }
-);
+    );
+
+    // do not lint -- should skip external macros
+    external!(
+        #[derive(Copy)]
+        pub struct B;
+
+        impl Clone for B {
+            fn clone(&self) -> Self {
+                todo!()
+            }
+        }
+    );
+
+    // do not lint -- should skip proc macros
+    #[derive(proc_macro_derive::NonCanonicalClone)]
+    pub struct C;
+
+    with_span!(
+        span
+
+        #[derive(Copy)]
+        struct D;
+        impl Clone for D {
+            fn clone(&self) -> Self {
+                todo!()
+            }
+        }
+    );
+}
diff --git a/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr b/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr
index 5500984..cf36a8f 100644
--- a/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr
+++ b/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr
@@ -41,5 +41,17 @@
 LL | |     }
    | |_____^ help: remove it
 
-error: aborting due to 4 previous errors
+error: non-canonical implementation of `clone` on a `Copy` type
+  --> tests/ui/non_canonical_clone_impl.rs:127:37
+   |
+LL |               fn clone(&self) -> Self {
+   |  _____________________________________^
+LL | |
+LL | |                 todo!()
+LL | |             }
+   | |_____________^ help: change this to: `{ *self }`
+   |
+   = note: this error originates in the macro `__inline_mac_mod_issue12788` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
index 6915e19..aa23fd9 100644
--- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
@@ -1,5 +1,9 @@
+//@aux-build:proc_macro_derive.rs
 #![no_main]
 
+extern crate proc_macros;
+use proc_macros::inline_macros;
+
 use std::cmp::Ordering;
 
 // lint
@@ -163,6 +167,73 @@
     }
 }
 
+#[inline_macros]
+mod issue12788 {
+    use std::cmp::Ordering;
+
+    use proc_macros::{external, with_span};
+
+    // lint -- not an external macro
+    inline!(
+        #[derive(PartialEq, Eq)]
+        pub struct A;
+
+        impl Ord for A {
+            fn cmp(&self, other: &Self) -> Ordering {
+                todo!();
+            }
+        }
+
+        impl PartialOrd for A {
+            //~^ non_canonical_partial_ord_impl
+            fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
+        }
+    );
+
+    // do not lint -- should skip external macros
+    external!(
+        #[derive(PartialEq, Eq)]
+        pub struct B;
+
+        impl Ord for B {
+            fn cmp(&self, other: &Self) -> Ordering {
+                todo!();
+            }
+        }
+
+        impl PartialOrd for B {
+            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+                todo!();
+            }
+        }
+
+    );
+
+    // do not lint -- should skip proc macros
+    #[derive(proc_macro_derive::NonCanonicalClone)]
+    pub struct C;
+
+    with_span!(
+        span
+
+        #[derive(PartialEq, Eq)]
+        pub struct D;
+
+        impl Ord for D {
+            fn cmp(&self, other: &Self) -> Ordering {
+                todo!();
+            }
+        }
+
+        impl PartialOrd for D {
+            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+                todo!();
+            }
+        }
+
+    );
+}
+
 // #13640, do not lint
 
 #[derive(Eq, PartialEq)]
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
index 7ce4cdc..da7f73f 100644
--- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
@@ -1,5 +1,9 @@
+//@aux-build:proc_macro_derive.rs
 #![no_main]
 
+extern crate proc_macros;
+use proc_macros::inline_macros;
+
 use std::cmp::Ordering;
 
 // lint
@@ -167,6 +171,75 @@ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
     }
 }
 
+#[inline_macros]
+mod issue12788 {
+    use std::cmp::Ordering;
+
+    use proc_macros::{external, with_span};
+
+    // lint -- not an external macro
+    inline!(
+        #[derive(PartialEq, Eq)]
+        pub struct A;
+
+        impl Ord for A {
+            fn cmp(&self, other: &Self) -> Ordering {
+                todo!();
+            }
+        }
+
+        impl PartialOrd for A {
+            //~^ non_canonical_partial_ord_impl
+            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+                todo!();
+            }
+        }
+    );
+
+    // do not lint -- should skip external macros
+    external!(
+        #[derive(PartialEq, Eq)]
+        pub struct B;
+
+        impl Ord for B {
+            fn cmp(&self, other: &Self) -> Ordering {
+                todo!();
+            }
+        }
+
+        impl PartialOrd for B {
+            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+                todo!();
+            }
+        }
+
+    );
+
+    // do not lint -- should skip proc macros
+    #[derive(proc_macro_derive::NonCanonicalClone)]
+    pub struct C;
+
+    with_span!(
+        span
+
+        #[derive(PartialEq, Eq)]
+        pub struct D;
+
+        impl Ord for D {
+            fn cmp(&self, other: &Self) -> Ordering {
+                todo!();
+            }
+        }
+
+        impl PartialOrd for D {
+            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+                todo!();
+            }
+        }
+
+    );
+}
+
 // #13640, do not lint
 
 #[derive(Eq, PartialEq)]
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
index 9bd6b1f..8e55603 100644
--- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
@@ -1,5 +1,5 @@
 error: non-canonical implementation of `partial_cmp` on an `Ord` type
-  --> tests/ui/non_canonical_partial_ord_impl.rs:16:1
+  --> tests/ui/non_canonical_partial_ord_impl.rs:20:1
    |
 LL | /  impl PartialOrd for A {
 LL | |
@@ -15,7 +15,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::non_canonical_partial_ord_impl)]`
 
 error: non-canonical implementation of `partial_cmp` on an `Ord` type
-  --> tests/ui/non_canonical_partial_ord_impl.rs:51:1
+  --> tests/ui/non_canonical_partial_ord_impl.rs:55:1
    |
 LL | / impl PartialOrd for C {
 LL | |
@@ -32,7 +32,22 @@
    |
 
 error: non-canonical implementation of `partial_cmp` on an `Ord` type
-  --> tests/ui/non_canonical_partial_ord_impl.rs:198:1
+  --> tests/ui/non_canonical_partial_ord_impl.rs:191:9
+   |
+LL | /          impl PartialOrd for A {
+LL | |
+LL | |              fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+   | | _____________________________________________________________________-
+LL | ||                 todo!();
+LL | ||             }
+   | ||_____________- help: change this to: `{ Some(self.cmp(other)) }`
+LL | |          }
+   | |__________^
+   |
+   = note: this error originates in the macro `__inline_mac_mod_issue12788` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: non-canonical implementation of `partial_cmp` on an `Ord` type
+  --> tests/ui/non_canonical_partial_ord_impl.rs:271:1
    |
 LL | /  impl PartialOrd for K {
 LL | |
@@ -45,7 +60,7 @@
    | |__^
 
 error: non-canonical implementation of `partial_cmp` on an `Ord` type
-  --> tests/ui/non_canonical_partial_ord_impl.rs:216:1
+  --> tests/ui/non_canonical_partial_ord_impl.rs:289:1
    |
 LL | /  impl PartialOrd for L {
 LL | |
@@ -57,5 +72,5 @@
 LL | |  }
    | |__^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index 6ce067f..a2ecea7 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -6,7 +6,8 @@
     clippy::redundant_locals,
     clippy::manual_midpoint,
     clippy::manual_unwrap_or_default,
-    clippy::manual_unwrap_or
+    clippy::manual_unwrap_or,
+    clippy::unnecessary_option_map_or_else
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index 096d3aa..3adbc78 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -6,7 +6,8 @@
     clippy::redundant_locals,
     clippy::manual_midpoint,
     clippy::manual_unwrap_or_default,
-    clippy::manual_unwrap_or
+    clippy::manual_unwrap_or,
+    clippy::unnecessary_option_map_or_else
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index 21a80ae..f5578f6 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:13:5
+  --> tests/ui/option_if_let_else.rs:14:5
    |
 LL | /     if let Some(x) = string {
 LL | |
@@ -13,19 +13,19 @@
    = help: to override `-D warnings` add `#[allow(clippy::option_if_let_else)]`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:32:13
+  --> tests/ui/option_if_let_else.rs:33:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:34:13
+  --> tests/ui/option_if_let_else.rs:35:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:36:13
+  --> tests/ui/option_if_let_else.rs:37:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -47,13 +47,13 @@
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:43:13
+  --> tests/ui/option_if_let_else.rs:44:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:45:13
+  --> tests/ui/option_if_let_else.rs:46:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -75,7 +75,7 @@
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:52:13
+  --> tests/ui/option_if_let_else.rs:53:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -97,7 +97,7 @@
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:62:5
+  --> tests/ui/option_if_let_else.rs:63:5
    |
 LL | /     if let Some(x) = arg {
 LL | |
@@ -118,7 +118,7 @@
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:76:13
+  --> tests/ui/option_if_let_else.rs:77:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -131,7 +131,7 @@
    | |_____^ help: try: `arg.map_or_else(side_effect, |x| x)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:86:13
+  --> tests/ui/option_if_let_else.rs:87:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -154,7 +154,7 @@
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:120:13
+  --> tests/ui/option_if_let_else.rs:121:13
    |
 LL | /             if let Some(idx) = s.find('.') {
 LL | |
@@ -165,7 +165,7 @@
    | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:132:5
+  --> tests/ui/option_if_let_else.rs:133:5
    |
 LL | /     if let Ok(binding) = variable {
 LL | |
@@ -189,7 +189,7 @@
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:157:5
+  --> tests/ui/option_if_let_else.rs:158:5
    |
 LL | /     match r {
 LL | |
@@ -199,7 +199,7 @@
    | |_____^ help: try: `r.map_or_else(|_| Vec::new(), |s| s.to_owned())`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:166:5
+  --> tests/ui/option_if_let_else.rs:167:5
    |
 LL | /     if let Ok(s) = r { s.to_owned() }
 LL | |
@@ -207,13 +207,13 @@
    | |_______________________^ help: try: `r.map_or_else(|_| Vec::new(), |s| s.to_owned())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:173:13
+  --> tests/ui/option_if_let_else.rs:174:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:184:13
+  --> tests/ui/option_if_let_else.rs:185:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -235,13 +235,13 @@
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:213:13
+  --> tests/ui/option_if_let_else.rs:214:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:218:13
+  --> tests/ui/option_if_let_else.rs:219:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -263,7 +263,7 @@
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:258:13
+  --> tests/ui/option_if_let_else.rs:259:13
    |
 LL |       let _ = match s {
    |  _____________^
@@ -274,7 +274,7 @@
    | |_____^ help: try: `s.map_or(1, |string| string.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:263:13
+  --> tests/ui/option_if_let_else.rs:264:13
    |
 LL |       let _ = match Some(10) {
    |  _____________^
@@ -285,7 +285,7 @@
    | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:270:13
+  --> tests/ui/option_if_let_else.rs:271:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -296,7 +296,7 @@
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:275:13
+  --> tests/ui/option_if_let_else.rs:276:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -307,13 +307,13 @@
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:280:13
+  --> tests/ui/option_if_let_else.rs:281:13
    |
 LL |     let _ = if let Ok(a) = res { a + 1 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:298:17
+  --> tests/ui/option_if_let_else.rs:299:17
    |
 LL |           let _ = match initial {
    |  _________________^
@@ -324,7 +324,7 @@
    | |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:306:17
+  --> tests/ui/option_if_let_else.rs:307:17
    |
 LL |           let _ = match initial {
    |  _________________^
@@ -335,7 +335,7 @@
    | |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:330:24
+  --> tests/ui/option_if_let_else.rs:331:24
    |
 LL |       let mut _hashmap = if let Some(hm) = &opt {
    |  ________________________^
@@ -347,19 +347,19 @@
    | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:337:19
+  --> tests/ui/option_if_let_else.rs:338:19
    |
 LL |     let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() };
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:388:22
+  --> tests/ui/option_if_let_else.rs:389:22
    |
 LL |     let _ = unsafe { if let Some(o) = *opt_raw_ptr { o } else { 1 } };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*opt_raw_ptr).map_or(1, |o| o)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:394:13
+  --> tests/ui/option_if_let_else.rs:395:13
    |
 LL |       let _ = match res {
    |  _____________^
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 386351a..314da08 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -5,6 +5,7 @@
     clippy::unnecessary_wraps,
     clippy::unnecessary_literal_unwrap,
     clippy::unnecessary_result_map_or_else,
+    clippy::unnecessary_option_map_or_else,
     clippy::useless_vec
 )]
 
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index e27f9aa..2a19614 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -5,6 +5,7 @@
     clippy::unnecessary_wraps,
     clippy::unnecessary_literal_unwrap,
     clippy::unnecessary_result_map_or_else,
+    clippy::unnecessary_option_map_or_else,
     clippy::useless_vec
 )]
 
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 6bce06a..3d55f2c 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -1,5 +1,5 @@
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:52:22
+  --> tests/ui/or_fun_call.rs:53:22
    |
 LL |     with_constructor.unwrap_or(make());
    |                      ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(make)`
@@ -8,7 +8,7 @@
    = help: to override `-D warnings` add `#[allow(clippy::or_fun_call)]`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:56:14
+  --> tests/ui/or_fun_call.rs:57:14
    |
 LL |     with_new.unwrap_or(Vec::new());
    |              ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
@@ -17,205 +17,205 @@
    = help: to override `-D warnings` add `#[allow(clippy::unwrap_or_default)]`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:60:21
+  --> tests/ui/or_fun_call.rs:61:21
    |
 LL |     with_const_args.unwrap_or(Vec::with_capacity(12));
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Vec::with_capacity(12))`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:64:14
+  --> tests/ui/or_fun_call.rs:65:14
    |
 LL |     with_err.unwrap_or(make());
    |              ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| make())`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:68:19
+  --> tests/ui/or_fun_call.rs:69:19
    |
 LL |     with_err_args.unwrap_or(Vec::with_capacity(12));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:72:24
+  --> tests/ui/or_fun_call.rs:73:24
    |
 LL |     with_default_trait.unwrap_or(Default::default());
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:76:23
+  --> tests/ui/or_fun_call.rs:77:23
    |
 LL |     with_default_type.unwrap_or(u64::default());
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:96:18
+  --> tests/ui/or_fun_call.rs:97:18
    |
 LL |     self_default.unwrap_or(<FakeDefault>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(<FakeDefault>::default)`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:100:18
+  --> tests/ui/or_fun_call.rs:101:18
    |
 LL |     real_default.unwrap_or(<FakeDefault as Default>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:104:14
+  --> tests/ui/or_fun_call.rs:105:14
    |
 LL |     with_vec.unwrap_or(Vec::new());
    |              ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:108:21
+  --> tests/ui/or_fun_call.rs:109:21
    |
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:112:19
+  --> tests/ui/or_fun_call.rs:113:19
    |
 LL |     map.entry(42).or_insert(String::new());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:116:23
+  --> tests/ui/or_fun_call.rs:117:23
    |
 LL |     map_vec.entry(42).or_insert(Vec::new());
    |                       ^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:120:21
+  --> tests/ui/or_fun_call.rs:121:21
    |
 LL |     btree.entry(42).or_insert(String::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert` to construct default value
-  --> tests/ui/or_fun_call.rs:124:25
+  --> tests/ui/or_fun_call.rs:125:25
    |
 LL |     btree_vec.entry(42).or_insert(Vec::new());
    |                         ^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:128:21
+  --> tests/ui/or_fun_call.rs:129:21
    |
 LL |     let _ = stringy.unwrap_or(String::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `ok_or`
-  --> tests/ui/or_fun_call.rs:133:17
+  --> tests/ui/or_fun_call.rs:134:17
    |
 LL |     let _ = opt.ok_or(format!("{} world.", hello));
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:138:21
+  --> tests/ui/or_fun_call.rs:139:21
    |
 LL |     let _ = Some(1).unwrap_or(map[&1]);
    |                     ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:141:21
+  --> tests/ui/or_fun_call.rs:142:21
    |
 LL |     let _ = Some(1).unwrap_or(map[&1]);
    |                     ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
 
 error: function call inside of `or`
-  --> tests/ui/or_fun_call.rs:166:35
+  --> tests/ui/or_fun_call.rs:167:35
    |
 LL |     let _ = Some("a".to_string()).or(Some("b".to_string()));
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:209:18
+  --> tests/ui/or_fun_call.rs:210:18
    |
 LL |             None.unwrap_or(ptr_to_ref(s));
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:217:14
+  --> tests/ui/or_fun_call.rs:218:14
    |
 LL |         None.unwrap_or(unsafe { ptr_to_ref(s) });
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:220:14
+  --> tests/ui/or_fun_call.rs:221:14
    |
 LL |         None.unwrap_or( unsafe { ptr_to_ref(s) }    );
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:296:25
+  --> tests/ui/or_fun_call.rs:297:25
    |
 LL |         let _ = Some(4).map_or(g(), |v| v);
    |                         ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:298:25
+  --> tests/ui/or_fun_call.rs:299:25
    |
 LL |         let _ = Some(4).map_or(g(), f);
    |                         ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:301:25
+  --> tests/ui/or_fun_call.rs:302:25
    |
 LL |         let _ = Some(4).map_or("asd".to_string().len() as i32, f);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| "asd".to_string().len() as i32, f)`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:332:18
+  --> tests/ui/or_fun_call.rs:333:18
    |
 LL |         with_new.unwrap_or_else(Vec::new);
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:336:28
+  --> tests/ui/or_fun_call.rs:337:28
    |
 LL |         with_default_trait.unwrap_or_else(Default::default);
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:340:27
+  --> tests/ui/or_fun_call.rs:341:27
    |
 LL |         with_default_type.unwrap_or_else(u64::default);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:344:22
+  --> tests/ui/or_fun_call.rs:345:22
    |
 LL |         real_default.unwrap_or_else(<FakeDefault as Default>::default);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `or_insert_with` to construct default value
-  --> tests/ui/or_fun_call.rs:348:23
+  --> tests/ui/or_fun_call.rs:349:23
    |
 LL |         map.entry(42).or_insert_with(String::new);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert_with` to construct default value
-  --> tests/ui/or_fun_call.rs:352:25
+  --> tests/ui/or_fun_call.rs:353:25
    |
 LL |         btree.entry(42).or_insert_with(String::new);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:356:25
+  --> tests/ui/or_fun_call.rs:357:25
    |
 LL |         let _ = stringy.unwrap_or_else(String::new);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:398:17
+  --> tests/ui/or_fun_call.rs:399:17
    |
 LL |     let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)`
    |                 ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:403:17
+  --> tests/ui/or_fun_call.rs:404:17
    |
 LL |     let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)`
    |                 ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:408:17
+  --> tests/ui/or_fun_call.rs:409:17
    |
 LL |       let _ = opt.unwrap_or({
    |  _________________^
@@ -235,79 +235,79 @@
    |
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:414:17
+  --> tests/ui/or_fun_call.rs:415:17
    |
 LL |     let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)`
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:419:17
+  --> tests/ui/or_fun_call.rs:420:17
    |
 LL |     let _ = opt.unwrap_or({ i32::default() });
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:426:21
+  --> tests/ui/or_fun_call.rs:427:21
    |
 LL |     let _ = opt_foo.unwrap_or(Foo { val: String::default() });
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:441:19
+  --> tests/ui/or_fun_call.rs:442:19
    |
 LL |         let _ = x.map_or(g(), |v| v);
    |                   ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), |v| v)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:443:19
+  --> tests/ui/or_fun_call.rs:444:19
    |
 LL |         let _ = x.map_or(g(), f);
    |                   ^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), f)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:446:19
+  --> tests/ui/or_fun_call.rs:447:19
    |
 LL |         let _ = x.map_or("asd".to_string().len() as i32, f);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| "asd".to_string().len() as i32, f)`
 
 error: function call inside of `get_or_insert`
-  --> tests/ui/or_fun_call.rs:457:15
+  --> tests/ui/or_fun_call.rs:458:15
    |
 LL |     let _ = x.get_or_insert(g());
    |               ^^^^^^^^^^^^^^^^^^ help: try: `get_or_insert_with(g)`
 
 error: function call inside of `and`
-  --> tests/ui/or_fun_call.rs:467:15
+  --> tests/ui/or_fun_call.rs:468:15
    |
 LL |     let _ = x.and(g());
    |               ^^^^^^^^ help: try: `and_then(|_| g())`
 
 error: function call inside of `and`
-  --> tests/ui/or_fun_call.rs:477:15
+  --> tests/ui/or_fun_call.rs:478:15
    |
 LL |     let _ = x.and(g());
    |               ^^^^^^^^ help: try: `and_then(|_| g())`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:483:17
+  --> tests/ui/or_fun_call.rs:484:17
    |
 LL |     let _ = opt.unwrap_or(Default::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:485:17
+  --> tests/ui/or_fun_call.rs:486:17
    |
 LL |     let _ = res.unwrap_or(Default::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Default::default())`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:491:17
+  --> tests/ui/or_fun_call.rs:492:17
    |
 LL |     let _ = opt.unwrap_or(Default::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:493:17
+  --> tests/ui/or_fun_call.rs:494:17
    |
 LL |     let _ = res.unwrap_or(Default::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
diff --git a/src/tools/clippy/tests/ui/replace_box.fixed b/src/tools/clippy/tests/ui/replace_box.fixed
new file mode 100644
index 0000000..58c8ed1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/replace_box.fixed
@@ -0,0 +1,72 @@
+#![warn(clippy::replace_box)]
+
+fn with_default<T: Default>(b: &mut Box<T>) {
+    **b = T::default();
+    //~^ replace_box
+}
+
+fn with_sized<T>(b: &mut Box<T>, t: T) {
+    **b = t;
+    //~^ replace_box
+}
+
+fn with_unsized<const N: usize>(b: &mut Box<[u32]>) {
+    // No lint for assigning to Box<T> where T: !Default
+    *b = Box::new([42; N]);
+}
+
+macro_rules! create_default {
+    () => {
+        Default::default()
+    };
+}
+
+macro_rules! create_zero_box {
+    () => {
+        Box::new(0)
+    };
+}
+
+macro_rules! same {
+    ($v:ident) => {
+        $v
+    };
+}
+
+macro_rules! mac {
+    (three) => {
+        3u32
+    };
+}
+
+fn main() {
+    let mut b = Box::new(1u32);
+    *b = Default::default();
+    //~^ replace_box
+    *b = Default::default();
+    //~^ replace_box
+
+    // No lint for assigning to the storage
+    *b = Default::default();
+    *b = u32::default();
+
+    // No lint if either LHS or RHS originates in macro
+    b = create_default!();
+    b = create_zero_box!();
+    same!(b) = Default::default();
+
+    *b = 5;
+    //~^ replace_box
+
+    *b = mac!(three);
+    //~^ replace_box
+
+    // No lint for assigning to Box<T> where T: !Default
+    let mut b = Box::<str>::from("hi".to_string());
+    b = Default::default();
+
+    // No lint for late initializations
+    #[allow(clippy::needless_late_init)]
+    let bb: Box<u32>;
+    bb = Default::default();
+}
diff --git a/src/tools/clippy/tests/ui/replace_box.rs b/src/tools/clippy/tests/ui/replace_box.rs
new file mode 100644
index 0000000..e1fb223
--- /dev/null
+++ b/src/tools/clippy/tests/ui/replace_box.rs
@@ -0,0 +1,72 @@
+#![warn(clippy::replace_box)]
+
+fn with_default<T: Default>(b: &mut Box<T>) {
+    *b = Box::new(T::default());
+    //~^ replace_box
+}
+
+fn with_sized<T>(b: &mut Box<T>, t: T) {
+    *b = Box::new(t);
+    //~^ replace_box
+}
+
+fn with_unsized<const N: usize>(b: &mut Box<[u32]>) {
+    // No lint for assigning to Box<T> where T: !Default
+    *b = Box::new([42; N]);
+}
+
+macro_rules! create_default {
+    () => {
+        Default::default()
+    };
+}
+
+macro_rules! create_zero_box {
+    () => {
+        Box::new(0)
+    };
+}
+
+macro_rules! same {
+    ($v:ident) => {
+        $v
+    };
+}
+
+macro_rules! mac {
+    (three) => {
+        3u32
+    };
+}
+
+fn main() {
+    let mut b = Box::new(1u32);
+    b = Default::default();
+    //~^ replace_box
+    b = Box::default();
+    //~^ replace_box
+
+    // No lint for assigning to the storage
+    *b = Default::default();
+    *b = u32::default();
+
+    // No lint if either LHS or RHS originates in macro
+    b = create_default!();
+    b = create_zero_box!();
+    same!(b) = Default::default();
+
+    b = Box::new(5);
+    //~^ replace_box
+
+    b = Box::new(mac!(three));
+    //~^ replace_box
+
+    // No lint for assigning to Box<T> where T: !Default
+    let mut b = Box::<str>::from("hi".to_string());
+    b = Default::default();
+
+    // No lint for late initializations
+    #[allow(clippy::needless_late_init)]
+    let bb: Box<u32>;
+    bb = Default::default();
+}
diff --git a/src/tools/clippy/tests/ui/replace_box.stderr b/src/tools/clippy/tests/ui/replace_box.stderr
new file mode 100644
index 0000000..7d9c85d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/replace_box.stderr
@@ -0,0 +1,52 @@
+error: creating a new box
+  --> tests/ui/replace_box.rs:4:5
+   |
+LL |     *b = Box::new(T::default());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace existing content with inner value instead: `**b = T::default()`
+   |
+   = note: this creates a needless allocation
+   = note: `-D clippy::replace-box` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::replace_box)]`
+
+error: creating a new box
+  --> tests/ui/replace_box.rs:9:5
+   |
+LL |     *b = Box::new(t);
+   |     ^^^^^^^^^^^^^^^^ help: replace existing content with inner value instead: `**b = t`
+   |
+   = note: this creates a needless allocation
+
+error: creating a new box with default content
+  --> tests/ui/replace_box.rs:44:5
+   |
+LL |     b = Default::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: replace existing content with default instead: `*b = Default::default()`
+   |
+   = note: this creates a needless allocation
+
+error: creating a new box with default content
+  --> tests/ui/replace_box.rs:46:5
+   |
+LL |     b = Box::default();
+   |     ^^^^^^^^^^^^^^^^^^ help: replace existing content with default instead: `*b = Default::default()`
+   |
+   = note: this creates a needless allocation
+
+error: creating a new box
+  --> tests/ui/replace_box.rs:58:5
+   |
+LL |     b = Box::new(5);
+   |     ^^^^^^^^^^^^^^^ help: replace existing content with inner value instead: `*b = 5`
+   |
+   = note: this creates a needless allocation
+
+error: creating a new box
+  --> tests/ui/replace_box.rs:61:5
+   |
+LL |     b = Box::new(mac!(three));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace existing content with inner value instead: `*b = mac!(three)`
+   |
+   = note: this creates a needless allocation
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.fixed b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.fixed
new file mode 100644
index 0000000..9974ee2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.fixed
@@ -0,0 +1,75 @@
+#![warn(clippy::unnecessary_option_map_or_else)]
+#![allow(
+    clippy::let_and_return,
+    clippy::let_unit_value,
+    clippy::unnecessary_lazy_evaluations,
+    clippy::unnecessary_literal_unwrap
+)]
+
+const fn identity<T>(x: T) -> T {
+    x
+}
+
+const fn double_it(x: i32) -> i32 {
+    x * 2
+}
+
+fn main() {
+    // Expected errors
+    // Basic scenario
+    let option = Some(());
+    option.unwrap_or_else(|| ()); //~ ERROR: unused "map closure" when calling
+
+    // Type ascription
+    let option = Some(());
+    option.unwrap_or_else(|| ()); //~ ERROR: unused "map closure" when calling
+
+    // Auto-deref
+    let string = String::new();
+    let option = Some(&string);
+    let _: &str = option.unwrap_or_else(|| &string); //~ ERROR: unused "map closure" when calling
+
+    // Temporary variable
+    let option = Some(());
+    option.unwrap_or_else(|| ());
+
+    // Identity
+    let string = String::new();
+    let option = Some(&string);
+    let _: &str = option.unwrap_or_else(|| &string); //~ ERROR: unused "map closure" when calling
+
+    // Closure bound to a variable
+    let do_nothing = |x: String| x;
+    let string = String::new();
+    let option = Some(string.clone());
+    let _: String = option.unwrap_or_else(|| string); //~ ERROR: unused "map closure" when calling
+
+    // Correct usages
+    let option = Some(());
+    option.map_or_else(|| (), |_| ());
+
+    let option = Some(());
+    option.map_or_else(|| (), |_: ()| ());
+
+    let string = String::new();
+    let option = Some(&string);
+    let _: &str = option.map_or_else(|| &string, |_| &string);
+
+    let option = Some(());
+    option.map_or_else(
+        || (),
+        |_| {
+            let tmp = ();
+            tmp
+        },
+    );
+
+    let num = 5;
+    let option = Some(num);
+    let _: i32 = option.map_or_else(|| 0, double_it);
+
+    let increase = |x: i32| x + 1;
+    let num = 5;
+    let option = Some(num);
+    let _: i32 = option.map_or_else(|| 0, increase);
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.rs b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.rs
new file mode 100644
index 0000000..9b53f3fc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.rs
@@ -0,0 +1,82 @@
+#![warn(clippy::unnecessary_option_map_or_else)]
+#![allow(
+    clippy::let_and_return,
+    clippy::let_unit_value,
+    clippy::unnecessary_lazy_evaluations,
+    clippy::unnecessary_literal_unwrap
+)]
+
+const fn identity<T>(x: T) -> T {
+    x
+}
+
+const fn double_it(x: i32) -> i32 {
+    x * 2
+}
+
+fn main() {
+    // Expected errors
+    // Basic scenario
+    let option = Some(());
+    option.map_or_else(|| (), |x| x); //~ ERROR: unused "map closure" when calling
+
+    // Type ascription
+    let option = Some(());
+    option.map_or_else(|| (), |x: ()| x); //~ ERROR: unused "map closure" when calling
+
+    // Auto-deref
+    let string = String::new();
+    let option = Some(&string);
+    let _: &str = option.map_or_else(|| &string, |x| x); //~ ERROR: unused "map closure" when calling
+
+    // Temporary variable
+    let option = Some(());
+    option.map_or_else(
+        //~^ ERROR: unused "map closure" when calling
+        || (),
+        |x| {
+            let tmp = x;
+            tmp
+        },
+    );
+
+    // Identity
+    let string = String::new();
+    let option = Some(&string);
+    let _: &str = option.map_or_else(|| &string, identity); //~ ERROR: unused "map closure" when calling
+
+    // Closure bound to a variable
+    let do_nothing = |x: String| x;
+    let string = String::new();
+    let option = Some(string.clone());
+    let _: String = option.map_or_else(|| string, do_nothing); //~ ERROR: unused "map closure" when calling
+
+    // Correct usages
+    let option = Some(());
+    option.map_or_else(|| (), |_| ());
+
+    let option = Some(());
+    option.map_or_else(|| (), |_: ()| ());
+
+    let string = String::new();
+    let option = Some(&string);
+    let _: &str = option.map_or_else(|| &string, |_| &string);
+
+    let option = Some(());
+    option.map_or_else(
+        || (),
+        |_| {
+            let tmp = ();
+            tmp
+        },
+    );
+
+    let num = 5;
+    let option = Some(num);
+    let _: i32 = option.map_or_else(|| 0, double_it);
+
+    let increase = |x: i32| x + 1;
+    let num = 5;
+    let option = Some(num);
+    let _: i32 = option.map_or_else(|| 0, increase);
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.stderr b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.stderr
new file mode 100644
index 0000000..d90875e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_option_map_or_else.stderr
@@ -0,0 +1,47 @@
+error: unused "map closure" when calling `Option::map_or_else` value
+  --> tests/ui/unnecessary_option_map_or_else.rs:21:5
+   |
+LL |     option.map_or_else(|| (), |x| x);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
+   |
+   = note: `-D clippy::unnecessary-option-map-or-else` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_option_map_or_else)]`
+
+error: unused "map closure" when calling `Option::map_or_else` value
+  --> tests/ui/unnecessary_option_map_or_else.rs:25:5
+   |
+LL |     option.map_or_else(|| (), |x: ()| x);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
+
+error: unused "map closure" when calling `Option::map_or_else` value
+  --> tests/ui/unnecessary_option_map_or_else.rs:30:19
+   |
+LL |     let _: &str = option.map_or_else(|| &string, |x| x);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| &string)`
+
+error: unused "map closure" when calling `Option::map_or_else` value
+  --> tests/ui/unnecessary_option_map_or_else.rs:34:5
+   |
+LL | /     option.map_or_else(
+LL | |
+LL | |         || (),
+LL | |         |x| {
+...  |
+LL | |         },
+LL | |     );
+   | |_____^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
+
+error: unused "map closure" when calling `Option::map_or_else` value
+  --> tests/ui/unnecessary_option_map_or_else.rs:46:19
+   |
+LL |     let _: &str = option.map_or_else(|| &string, identity);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| &string)`
+
+error: unused "map closure" when calling `Option::map_or_else` value
+  --> tests/ui/unnecessary_option_map_or_else.rs:52:21
+   |
+LL |     let _: String = option.map_or_else(|| string, do_nothing);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| string)`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr b/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr
index 732e676..6ad94f9 100644
--- a/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr
@@ -5,10 +5,10 @@
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui/unnecessary_safety_comment.rs:5:5
+  --> tests/ui/unnecessary_safety_comment.rs:5:8
    |
 LL |     // SAFETY:
-   |     ^^^^^^^^^^
+   |        ^^^^^^^
    = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]`
 
@@ -19,10 +19,10 @@
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui/unnecessary_safety_comment.rs:9:5
+  --> tests/ui/unnecessary_safety_comment.rs:9:8
    |
 LL |     // SAFETY:
-   |     ^^^^^^^^^^
+   |        ^^^^^^^
 
 error: struct has unnecessary safety comment
   --> tests/ui/unnecessary_safety_comment.rs:14:5
@@ -31,10 +31,10 @@
    |     ^^^^^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui/unnecessary_safety_comment.rs:13:5
+  --> tests/ui/unnecessary_safety_comment.rs:13:8
    |
 LL |     // SAFETY:
-   |     ^^^^^^^^^^
+   |        ^^^^^^^
 
 error: enum has unnecessary safety comment
   --> tests/ui/unnecessary_safety_comment.rs:18:5
@@ -43,10 +43,10 @@
    |     ^^^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui/unnecessary_safety_comment.rs:17:5
+  --> tests/ui/unnecessary_safety_comment.rs:17:8
    |
 LL |     // SAFETY:
-   |     ^^^^^^^^^^
+   |        ^^^^^^^
 
 error: module has unnecessary safety comment
   --> tests/ui/unnecessary_safety_comment.rs:22:5
@@ -55,10 +55,10 @@
    |     ^^^^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui/unnecessary_safety_comment.rs:21:5
+  --> tests/ui/unnecessary_safety_comment.rs:21:8
    |
 LL |     // SAFETY:
-   |     ^^^^^^^^^^
+   |        ^^^^^^^
 
 error: impl has unnecessary safety comment
   --> tests/ui/unnecessary_safety_comment.rs:42:13
@@ -70,10 +70,10 @@
    |     ------------------------- in this macro invocation
    |
 help: consider removing the safety comment
-  --> tests/ui/unnecessary_safety_comment.rs:41:13
+  --> tests/ui/unnecessary_safety_comment.rs:41:16
    |
 LL |             // Safety: unnecessary
-   |             ^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^
    = note: this error originates in the macro `with_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expression has unnecessary safety comment
@@ -83,10 +83,10 @@
    |     ^^
    |
 help: consider removing the safety comment
-  --> tests/ui/unnecessary_safety_comment.rs:59:5
+  --> tests/ui/unnecessary_safety_comment.rs:59:8
    |
 LL |     // SAFETY: unnecessary
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^
 
 error: statement has unnecessary safety comment
   --> tests/ui/unnecessary_safety_comment.rs:52:5
@@ -95,10 +95,10 @@
    |     ^^^^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui/unnecessary_safety_comment.rs:51:5
+  --> tests/ui/unnecessary_safety_comment.rs:51:8
    |
 LL |     // SAFETY: unnecessary
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^
 
 error: statement has unnecessary safety comment
   --> tests/ui/unnecessary_safety_comment.rs:56:5
@@ -107,10 +107,10 @@
    |     ^^^^^^^^^^^^^^
    |
 help: consider removing the safety comment
-  --> tests/ui/unnecessary_safety_comment.rs:55:5
+  --> tests/ui/unnecessary_safety_comment.rs:55:8
    |
 LL |     // SAFETY: unnecessary
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/use_self_structs.fixed b/src/tools/clippy/tests/ui/use_self_structs.fixed
new file mode 100644
index 0000000..bd7bc3e0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/use_self_structs.fixed
@@ -0,0 +1,134 @@
+#![warn(clippy::use_self)]
+#![allow(clippy::type_complexity)]
+
+fn main() {}
+
+struct Basic {
+    flag: Option<Box<Self>>,
+    //~^ use_self
+}
+
+struct BasicSelf {
+    okay: Option<Box<Self>>,
+}
+
+struct Generic<'q, T: From<u8>> {
+    t: &'q T,
+    flag: Option<Box<Self>>,
+    //~^ use_self
+}
+
+struct GenericSelf<'q, T: From<u8>> {
+    t: &'q T,
+    okay: Option<Box<Self>>,
+}
+
+struct MixedLifetimes<'q, T: From<u8> + 'static> {
+    t: &'q T,
+    okay: Option<Box<MixedLifetimes<'static, T>>>,
+}
+
+struct ConcreteType<'q, T: From<u8>> {
+    t: &'q T,
+    okay: Option<Box<ConcreteType<'q, u64>>>,
+}
+
+struct ConcreteAndGeneric<'q, T: From<u8>> {
+    t: &'q T,
+    flag: Option<Box<Self>>,
+    //~^ use_self
+    okay: Option<Box<ConcreteAndGeneric<'q, u64>>>,
+}
+
+struct ConcreteAndGenericSelf<'q, T: From<u8>> {
+    t: &'q T,
+    okay_1: Option<Box<Self>>,
+    okay_2: Option<Box<ConcreteAndGeneric<'q, u64>>>,
+}
+
+macro_rules! recursive_struct {
+    ($name:ident) => {
+        struct $name {
+            okay: Option<Box<$name>>,
+        }
+    };
+}
+
+recursive_struct!(X);
+recursive_struct!(Y);
+recursive_struct!(Z);
+
+struct Tree {
+    left: Option<Box<Self>>,
+    //~^ use_self
+    right: Option<Box<Self>>,
+    //~^ use_self
+}
+
+struct TreeSelf {
+    left: Option<Box<Self>>,
+    right: Option<Box<Self>>,
+}
+
+struct TreeMixed {
+    left: Option<Box<Self>>,
+    right: Option<Box<Self>>,
+    //~^ use_self
+}
+
+struct Nested {
+    flag: Option<Box<Option<Box<Self>>>>,
+    //~^ use_self
+}
+
+struct NestedSelf {
+    okay: Option<Box<Option<Box<Self>>>>,
+}
+
+struct Tuple(Option<Box<Self>>);
+//~^ use_self
+
+struct TupleSelf(Option<Box<Self>>);
+
+use std::cell::RefCell;
+use std::rc::{Rc, Weak};
+
+struct Containers {
+    flag: Vec<Option<Rc<RefCell<Weak<Vec<Box<Self>>>>>>>,
+    //~^ use_self
+}
+
+struct ContainersSelf {
+    okay: Vec<Option<Rc<RefCell<Weak<Vec<Box<Self>>>>>>>,
+}
+
+type Wrappers<T> = Vec<Option<Rc<RefCell<Weak<Vec<Box<T>>>>>>>;
+
+struct Alias {
+    flag: Wrappers<Self>,
+    //~^ use_self
+}
+
+struct AliasSelf {
+    okay: Wrappers<Self>,
+}
+
+struct Array<const N: usize> {
+    flag: [Option<Box<Self>>; N],
+    //~^ use_self
+}
+
+struct ArraySelf<const N: usize> {
+    okay: [Option<Box<Self>>; N],
+}
+
+enum Enum {
+    Nil,
+    Cons(Box<Self>),
+    //~^ use_self
+}
+
+enum EnumSelf {
+    Nil,
+    Cons(Box<Self>),
+}
diff --git a/src/tools/clippy/tests/ui/use_self_structs.rs b/src/tools/clippy/tests/ui/use_self_structs.rs
new file mode 100644
index 0000000..624f158
--- /dev/null
+++ b/src/tools/clippy/tests/ui/use_self_structs.rs
@@ -0,0 +1,134 @@
+#![warn(clippy::use_self)]
+#![allow(clippy::type_complexity)]
+
+fn main() {}
+
+struct Basic {
+    flag: Option<Box<Basic>>,
+    //~^ use_self
+}
+
+struct BasicSelf {
+    okay: Option<Box<Self>>,
+}
+
+struct Generic<'q, T: From<u8>> {
+    t: &'q T,
+    flag: Option<Box<Generic<'q, T>>>,
+    //~^ use_self
+}
+
+struct GenericSelf<'q, T: From<u8>> {
+    t: &'q T,
+    okay: Option<Box<Self>>,
+}
+
+struct MixedLifetimes<'q, T: From<u8> + 'static> {
+    t: &'q T,
+    okay: Option<Box<MixedLifetimes<'static, T>>>,
+}
+
+struct ConcreteType<'q, T: From<u8>> {
+    t: &'q T,
+    okay: Option<Box<ConcreteType<'q, u64>>>,
+}
+
+struct ConcreteAndGeneric<'q, T: From<u8>> {
+    t: &'q T,
+    flag: Option<Box<ConcreteAndGeneric<'q, T>>>,
+    //~^ use_self
+    okay: Option<Box<ConcreteAndGeneric<'q, u64>>>,
+}
+
+struct ConcreteAndGenericSelf<'q, T: From<u8>> {
+    t: &'q T,
+    okay_1: Option<Box<Self>>,
+    okay_2: Option<Box<ConcreteAndGeneric<'q, u64>>>,
+}
+
+macro_rules! recursive_struct {
+    ($name:ident) => {
+        struct $name {
+            okay: Option<Box<$name>>,
+        }
+    };
+}
+
+recursive_struct!(X);
+recursive_struct!(Y);
+recursive_struct!(Z);
+
+struct Tree {
+    left: Option<Box<Tree>>,
+    //~^ use_self
+    right: Option<Box<Tree>>,
+    //~^ use_self
+}
+
+struct TreeSelf {
+    left: Option<Box<Self>>,
+    right: Option<Box<Self>>,
+}
+
+struct TreeMixed {
+    left: Option<Box<Self>>,
+    right: Option<Box<TreeMixed>>,
+    //~^ use_self
+}
+
+struct Nested {
+    flag: Option<Box<Option<Box<Nested>>>>,
+    //~^ use_self
+}
+
+struct NestedSelf {
+    okay: Option<Box<Option<Box<Self>>>>,
+}
+
+struct Tuple(Option<Box<Tuple>>);
+//~^ use_self
+
+struct TupleSelf(Option<Box<Self>>);
+
+use std::cell::RefCell;
+use std::rc::{Rc, Weak};
+
+struct Containers {
+    flag: Vec<Option<Rc<RefCell<Weak<Vec<Box<Containers>>>>>>>,
+    //~^ use_self
+}
+
+struct ContainersSelf {
+    okay: Vec<Option<Rc<RefCell<Weak<Vec<Box<Self>>>>>>>,
+}
+
+type Wrappers<T> = Vec<Option<Rc<RefCell<Weak<Vec<Box<T>>>>>>>;
+
+struct Alias {
+    flag: Wrappers<Alias>,
+    //~^ use_self
+}
+
+struct AliasSelf {
+    okay: Wrappers<Self>,
+}
+
+struct Array<const N: usize> {
+    flag: [Option<Box<Array<N>>>; N],
+    //~^ use_self
+}
+
+struct ArraySelf<const N: usize> {
+    okay: [Option<Box<Self>>; N],
+}
+
+enum Enum {
+    Nil,
+    Cons(Box<Enum>),
+    //~^ use_self
+}
+
+enum EnumSelf {
+    Nil,
+    Cons(Box<Self>),
+}
diff --git a/src/tools/clippy/tests/ui/use_self_structs.stderr b/src/tools/clippy/tests/ui/use_self_structs.stderr
new file mode 100644
index 0000000..766d1d4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/use_self_structs.stderr
@@ -0,0 +1,77 @@
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:7:22
+   |
+LL |     flag: Option<Box<Basic>>,
+   |                      ^^^^^ help: use the applicable keyword: `Self`
+   |
+   = note: `-D clippy::use-self` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::use_self)]`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:17:22
+   |
+LL |     flag: Option<Box<Generic<'q, T>>>,
+   |                      ^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:38:22
+   |
+LL |     flag: Option<Box<ConcreteAndGeneric<'q, T>>>,
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:62:22
+   |
+LL |     left: Option<Box<Tree>>,
+   |                      ^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:64:23
+   |
+LL |     right: Option<Box<Tree>>,
+   |                       ^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:75:23
+   |
+LL |     right: Option<Box<TreeMixed>>,
+   |                       ^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:80:33
+   |
+LL |     flag: Option<Box<Option<Box<Nested>>>>,
+   |                                 ^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:88:25
+   |
+LL | struct Tuple(Option<Box<Tuple>>);
+   |                         ^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:97:46
+   |
+LL |     flag: Vec<Option<Rc<RefCell<Weak<Vec<Box<Containers>>>>>>>,
+   |                                              ^^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:108:20
+   |
+LL |     flag: Wrappers<Alias>,
+   |                    ^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:117:23
+   |
+LL |     flag: [Option<Box<Array<N>>>; N],
+   |                       ^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self_structs.rs:127:14
+   |
+LL |     Cons(Box<Enum>),
+   |              ^^^^ help: use the applicable keyword: `Self`
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/volatile_composites.rs b/src/tools/clippy/tests/ui/volatile_composites.rs
new file mode 100644
index 0000000..e7e7daf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/volatile_composites.rs
@@ -0,0 +1,221 @@
+#![feature(ptr_metadata)]
+#![feature(portable_simd)]
+#![warn(clippy::volatile_composites)]
+
+use std::ptr::null_mut;
+
+#[repr(C)]
+#[derive(Copy, Clone, Default)]
+struct MyDevRegisters {
+    baseaddr: usize,
+    count: usize,
+}
+
+#[repr(transparent)]
+struct Wrapper<T>((), T, ());
+
+// Not to be confused with std::ptr::NonNull
+struct NonNull<T>(T);
+
+impl<T> NonNull<T> {
+    fn write_volatile(&self, _arg: &T) {
+        unimplemented!("Something entirely unrelated to std::ptr::NonNull");
+    }
+}
+
+fn main() {
+    let regs = MyDevRegisters {
+        baseaddr: 0xabc123,
+        count: 42,
+    };
+
+    const DEVICE_ADDR: *mut MyDevRegisters = 0xdead as *mut _;
+
+    // Raw pointer methods
+    unsafe {
+        (&raw mut (*DEVICE_ADDR).baseaddr).write_volatile(regs.baseaddr); // OK
+        (&raw mut (*DEVICE_ADDR).count).write_volatile(regs.count); // OK
+
+        DEVICE_ADDR.write_volatile(regs);
+        //~^ volatile_composites
+
+        let _regs = MyDevRegisters {
+            baseaddr: (&raw const (*DEVICE_ADDR).baseaddr).read_volatile(), // OK
+            count: (&raw const (*DEVICE_ADDR).count).read_volatile(),       // OK
+        };
+
+        let _regs = DEVICE_ADDR.read_volatile();
+        //~^ volatile_composites
+    }
+
+    // std::ptr functions
+    unsafe {
+        std::ptr::write_volatile(&raw mut (*DEVICE_ADDR).baseaddr, regs.baseaddr); // OK
+        std::ptr::write_volatile(&raw mut (*DEVICE_ADDR).count, regs.count); // OK
+
+        std::ptr::write_volatile(DEVICE_ADDR, regs);
+        //~^ volatile_composites
+
+        let _regs = MyDevRegisters {
+            baseaddr: std::ptr::read_volatile(&raw const (*DEVICE_ADDR).baseaddr), // OK
+            count: std::ptr::read_volatile(&raw const (*DEVICE_ADDR).count),       // OK
+        };
+
+        let _regs = std::ptr::read_volatile(DEVICE_ADDR);
+        //~^ volatile_composites
+    }
+
+    // core::ptr functions
+    unsafe {
+        core::ptr::write_volatile(&raw mut (*DEVICE_ADDR).baseaddr, regs.baseaddr); // OK
+        core::ptr::write_volatile(&raw mut (*DEVICE_ADDR).count, regs.count); // OK
+
+        core::ptr::write_volatile(DEVICE_ADDR, regs);
+        //~^ volatile_composites
+
+        let _regs = MyDevRegisters {
+            baseaddr: core::ptr::read_volatile(&raw const (*DEVICE_ADDR).baseaddr), // OK
+            count: core::ptr::read_volatile(&raw const (*DEVICE_ADDR).count),       // OK
+        };
+
+        let _regs = core::ptr::read_volatile(DEVICE_ADDR);
+        //~^ volatile_composites
+    }
+
+    // std::ptr::NonNull
+    unsafe {
+        let ptr = std::ptr::NonNull::new(DEVICE_ADDR).unwrap();
+
+        ptr.write_volatile(regs);
+        //~^ volatile_composites
+
+        let _regs = ptr.read_volatile();
+        //~^ volatile_composites
+    }
+
+    // Red herring
+    {
+        let thing = NonNull("hello".to_string());
+
+        thing.write_volatile(&"goodbye".into()); // OK
+    }
+
+    // Zero size types OK
+    unsafe {
+        struct Empty;
+
+        (0xdead as *mut Empty).write_volatile(Empty); // OK
+        // Note that this is OK because Wrapper<Empty> is itself ZST, not because of the repr transparent
+        // handling tested below.
+        (0xdead as *mut Wrapper<Empty>).write_volatile(Wrapper((), Empty, ())); // OK
+    }
+
+    // Via repr transparent newtype
+    unsafe {
+        (0xdead as *mut Wrapper<usize>).write_volatile(Wrapper((), 123, ())); // OK
+        (0xdead as *mut Wrapper<Wrapper<usize>>).write_volatile(Wrapper((), Wrapper((), 123, ()), ())); // OK
+
+        (0xdead as *mut Wrapper<MyDevRegisters>).write_volatile(Wrapper((), MyDevRegisters::default(), ()));
+        //~^ volatile_composites
+    }
+
+    // Plain type alias OK
+    unsafe {
+        type MyU64 = u64;
+
+        (0xdead as *mut MyU64).write_volatile(123); // OK
+    }
+
+    // Wide pointers are not OK as data
+    unsafe {
+        let things: &[u32] = &[1, 2, 3];
+
+        (0xdead as *mut *const u32).write_volatile(things.as_ptr()); // OK
+
+        let wideptr: *const [u32] = std::ptr::from_raw_parts(things.as_ptr(), things.len());
+        (0xdead as *mut *const [u32]).write_volatile(wideptr);
+        //~^ volatile_composites
+    }
+
+    // Plain pointers and pointers with lifetimes are OK
+    unsafe {
+        let v: u32 = 123;
+        let rv: &u32 = &v;
+
+        (0xdead as *mut &u32).write_volatile(rv); // OK
+    }
+
+    // C-style enums are OK
+    unsafe {
+        // Bad: need some specific repr
+        enum PlainEnum {
+            A = 1,
+            B = 2,
+            C = 3,
+        }
+
+        (0xdead as *mut PlainEnum).write_volatile(PlainEnum::A);
+        //~^ volatile_composites
+
+        // OK
+        #[repr(u32)]
+        enum U32Enum {
+            A = 1,
+            B = 2,
+            C = 3,
+        }
+
+        (0xdead as *mut U32Enum).write_volatile(U32Enum::A); // OK
+
+        // OK
+        #[repr(C)]
+        enum CEnum {
+            A = 1,
+            B = 2,
+            C = 3,
+        }
+        (0xdead as *mut CEnum).write_volatile(CEnum::A); // OK
+
+        // Nope
+        enum SumType {
+            A(String),
+            B(u32),
+            C,
+        }
+        (0xdead as *mut SumType).write_volatile(SumType::C);
+        //~^ volatile_composites
+
+        // A repr on a complex sum type is not good enough
+        #[repr(C)]
+        enum ReprSumType {
+            A(String),
+            B(u32),
+            C,
+        }
+        (0xdead as *mut ReprSumType).write_volatile(ReprSumType::C);
+        //~^ volatile_composites
+    }
+
+    // SIMD is OK
+    unsafe {
+        (0xdead as *mut std::simd::u32x4).write_volatile(std::simd::u32x4::splat(1)); // OK
+    }
+
+    // Can't see through generic wrapper
+    unsafe {
+        do_device_write::<MyDevRegisters>(0xdead as *mut _, Default::default()); // OK
+    }
+
+    let mut s = String::from("foo");
+    unsafe {
+        std::ptr::write_volatile(&mut s, String::from("bar"));
+        //~^ volatile_composites
+    }
+}
+
+// Generic OK
+unsafe fn do_device_write<T>(ptr: *mut T, v: T) {
+    unsafe {
+        ptr.write_volatile(v); // OK
+    }
+}
diff --git a/src/tools/clippy/tests/ui/volatile_composites.stderr b/src/tools/clippy/tests/ui/volatile_composites.stderr
new file mode 100644
index 0000000..1545fc9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/volatile_composites.stderr
@@ -0,0 +1,89 @@
+error: type `MyDevRegisters` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:39:9
+   |
+LL |         DEVICE_ADDR.write_volatile(regs);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::volatile-composites` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::volatile_composites)]`
+
+error: type `MyDevRegisters` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:47:21
+   |
+LL |         let _regs = DEVICE_ADDR.read_volatile();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: type `MyDevRegisters` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:56:9
+   |
+LL |         std::ptr::write_volatile(DEVICE_ADDR, regs);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: type `MyDevRegisters` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:64:21
+   |
+LL |         let _regs = std::ptr::read_volatile(DEVICE_ADDR);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: type `MyDevRegisters` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:73:9
+   |
+LL |         core::ptr::write_volatile(DEVICE_ADDR, regs);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: type `MyDevRegisters` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:81:21
+   |
+LL |         let _regs = core::ptr::read_volatile(DEVICE_ADDR);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: type `MyDevRegisters` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:89:9
+   |
+LL |         ptr.write_volatile(regs);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: type `MyDevRegisters` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:92:21
+   |
+LL |         let _regs = ptr.read_volatile();
+   |                     ^^^^^^^^^^^^^^^^^^^
+
+error: type `Wrapper<MyDevRegisters>` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:118:9
+   |
+LL |         (0xdead as *mut Wrapper<MyDevRegisters>).write_volatile(Wrapper((), MyDevRegisters::default(), ()));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: type `*const [u32]` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:136:9
+   |
+LL |         (0xdead as *mut *const [u32]).write_volatile(wideptr);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: type `main::PlainEnum` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:157:9
+   |
+LL |         (0xdead as *mut PlainEnum).write_volatile(PlainEnum::A);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: type `main::SumType` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:185:9
+   |
+LL |         (0xdead as *mut SumType).write_volatile(SumType::C);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: type `main::ReprSumType` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:195:9
+   |
+LL |         (0xdead as *mut ReprSumType).write_volatile(ReprSumType::C);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: type `std::string::String` is not volatile-compatible
+  --> tests/ui/volatile_composites.rs:211:9
+   |
+LL |         std::ptr::write_volatile(&mut s, String::from("bar"));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/while_let_loop.rs b/src/tools/clippy/tests/ui/while_let_loop.rs
index 95062c9..f28c504 100644
--- a/src/tools/clippy/tests/ui/while_let_loop.rs
+++ b/src/tools/clippy/tests/ui/while_let_loop.rs
@@ -24,6 +24,19 @@ fn main() {
 
     loop {
         //~^ while_let_loop
+        let Some(_x) = y else { break };
+    }
+
+    loop {
+        // no error, else branch does something other than break
+        let Some(_x) = y else {
+            let _z = 1;
+            break;
+        };
+    }
+
+    loop {
+        //~^ while_let_loop
 
         match y {
             Some(_x) => true,
diff --git a/src/tools/clippy/tests/ui/while_let_loop.stderr b/src/tools/clippy/tests/ui/while_let_loop.stderr
index ed42628..b9aee6e 100644
--- a/src/tools/clippy/tests/ui/while_let_loop.stderr
+++ b/src/tools/clippy/tests/ui/while_let_loop.stderr
@@ -17,6 +17,15 @@
    |
 LL | /     loop {
 LL | |
+LL | |         let Some(_x) = y else { break };
+LL | |     }
+   | |_____^ help: try: `while let Some(_x) = y { .. }`
+
+error: this loop could be written as a `while let` loop
+  --> tests/ui/while_let_loop.rs:38:5
+   |
+LL | /     loop {
+LL | |
 LL | |
 LL | |         match y {
 ...  |
@@ -25,7 +34,7 @@
    | |_____^ help: try: `while let Some(_x) = y { .. }`
 
 error: this loop could be written as a `while let` loop
-  --> tests/ui/while_let_loop.rs:34:5
+  --> tests/ui/while_let_loop.rs:47:5
    |
 LL | /     loop {
 LL | |
@@ -37,7 +46,7 @@
    | |_____^ help: try: `while let Some(x) = y { .. }`
 
 error: this loop could be written as a `while let` loop
-  --> tests/ui/while_let_loop.rs:45:5
+  --> tests/ui/while_let_loop.rs:58:5
    |
 LL | /     loop {
 LL | |
@@ -48,7 +57,7 @@
    | |_____^ help: try: `while let Some(x) = y { .. }`
 
 error: this loop could be written as a `while let` loop
-  --> tests/ui/while_let_loop.rs:77:5
+  --> tests/ui/while_let_loop.rs:90:5
    |
 LL | /     loop {
 LL | |
@@ -68,7 +77,7 @@
    |
 
 error: this loop could be written as a `while let` loop
-  --> tests/ui/while_let_loop.rs:167:9
+  --> tests/ui/while_let_loop.rs:180:9
    |
 LL | /         loop {
 LL | |
@@ -88,7 +97,7 @@
    |
 
 error: this loop could be written as a `while let` loop
-  --> tests/ui/while_let_loop.rs:182:5
+  --> tests/ui/while_let_loop.rs:195:5
    |
 LL | /     loop {
 LL | |
@@ -107,7 +116,7 @@
    |
 
 error: this loop could be written as a `while let` loop
-  --> tests/ui/while_let_loop.rs:194:5
+  --> tests/ui/while_let_loop.rs:207:5
    |
 LL | /     loop {
 LL | |
@@ -126,7 +135,7 @@
    |
 
 error: this loop could be written as a `while let` loop
-  --> tests/ui/while_let_loop.rs:206:5
+  --> tests/ui/while_let_loop.rs:219:5
    |
 LL | /     loop {
 LL | |
@@ -137,7 +146,7 @@
    | |_____^ help: try: `while let Some(x) = Some(3) { .. }`
 
 error: this loop could be written as a `while let` loop
-  --> tests/ui/while_let_loop.rs:218:5
+  --> tests/ui/while_let_loop.rs:231:5
    |
 LL | /     loop {
 LL | |
@@ -156,7 +165,7 @@
    |
 
 error: this loop could be written as a `while let` loop
-  --> tests/ui/while_let_loop.rs:230:5
+  --> tests/ui/while_let_loop.rs:243:5
    |
 LL | /     loop {
 LL | |
@@ -177,5 +186,5 @@
 LL +     }
    |
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed b/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed
index e6c451c..b5fca36 100644
--- a/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed
+++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed
@@ -1,5 +1,6 @@
 #![warn(clippy::zero_repeat_side_effects)]
 #![expect(clippy::unnecessary_operation, clippy::useless_vec, clippy::needless_late_init)]
+#![allow(clippy::no_effect)] // only fires _after_ the fix
 
 fn f() -> i32 {
     println!("side effect");
@@ -13,36 +14,47 @@
     // should trigger
 
     // on arrays
-    f(); let a: [i32; 0] = [];
+    f();
+    let a: [i32; 0] = [];
     //~^ zero_repeat_side_effects
     let mut b;
-    f(); b = [] as [i32; 0];
+    f();
+    b = [] as [i32; 0];
     //~^ zero_repeat_side_effects
 
     // on vecs
     // vecs dont support inferring value of consts
-    f(); let c: std::vec::Vec<i32> = vec![];
+    f();
+    let c: std::vec::Vec<i32> = vec![];
     //~^ zero_repeat_side_effects
     let d;
-    f(); d = vec![] as std::vec::Vec<i32>;
+    f();
+    d = vec![] as std::vec::Vec<i32>;
     //~^ zero_repeat_side_effects
 
     // for macros
-    println!("side effect"); let e: [(); 0] = [];
+    println!("side effect");
+    let e: [(); 0] = [];
     //~^ zero_repeat_side_effects
 
     // for nested calls
-    { f() }; let g: [i32; 0] = [];
+    { f() };
+    let g: [i32; 0] = [];
     //~^ zero_repeat_side_effects
 
     // as function param
-    drop({ f(); vec![] as std::vec::Vec<i32> });
+    drop({
+        f();
+        vec![] as std::vec::Vec<i32>
+    });
     //~^ zero_repeat_side_effects
 
     // when singled out/not part of assignment/local
-    { f(); vec![] as std::vec::Vec<i32> };
+    f();
+    vec![] as std::vec::Vec<i32>;
     //~^ zero_repeat_side_effects
-    { f(); [] as [i32; 0] };
+    f();
+    [] as [i32; 0];
     //~^ zero_repeat_side_effects
 
     // should not trigger
@@ -96,8 +108,14 @@
 
     foo(&[Some(0i64); 0]);
     foo(&[Some(Some(0i64)); 0]);
-    foo(&{ Some(f()); [] as [std::option::Option<i32>; 0] });
+    foo(&{
+        Some(f());
+        [] as [std::option::Option<i32>; 0]
+    });
     //~^ zero_repeat_side_effects
-    foo(&{ Some(Some(S::new())); [] as [std::option::Option<std::option::Option<S>>; 0] });
+    foo(&{
+        Some(Some(S::new()));
+        [] as [std::option::Option<std::option::Option<S>>; 0]
+    });
     //~^ zero_repeat_side_effects
 }
diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs b/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs
index f8a4979..ea043d2 100644
--- a/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs
+++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs
@@ -1,5 +1,6 @@
 #![warn(clippy::zero_repeat_side_effects)]
 #![expect(clippy::unnecessary_operation, clippy::useless_vec, clippy::needless_late_init)]
+#![allow(clippy::no_effect)] // only fires _after_ the fix
 
 fn f() -> i32 {
     println!("side effect");
diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr b/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr
index 771b71c..49e850d 100644
--- a/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr
+++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr
@@ -1,5 +1,5 @@
 error: expression with side effects as the initial value in a zero-sized array initializer
-  --> tests/ui/zero_repeat_side_effects.rs:16:5
+  --> tests/ui/zero_repeat_side_effects.rs:17:5
    |
 LL |     let a = [f(); 0];
    |     ^^^^^^^^^^^^^^^^^
@@ -8,128 +8,134 @@
    = help: to override `-D warnings` add `#[allow(clippy::zero_repeat_side_effects)]`
 help: consider performing the side effect separately
    |
-LL -     let a = [f(); 0];
-LL +     f(); let a: [i32; 0] = [];
+LL ~     f();
+LL +     let a: [i32; 0] = [];
    |
 
 error: expression with side effects as the initial value in a zero-sized array initializer
-  --> tests/ui/zero_repeat_side_effects.rs:19:5
+  --> tests/ui/zero_repeat_side_effects.rs:20:5
    |
 LL |     b = [f(); 0];
    |     ^^^^^^^^^^^^
    |
 help: consider performing the side effect separately
    |
-LL -     b = [f(); 0];
-LL +     f(); b = [] as [i32; 0];
+LL ~     f();
+LL ~     b = [] as [i32; 0];
    |
 
 error: expression with side effects as the initial value in a zero-sized array initializer
-  --> tests/ui/zero_repeat_side_effects.rs:24:5
+  --> tests/ui/zero_repeat_side_effects.rs:25:5
    |
 LL |     let c = vec![f(); 0];
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider performing the side effect separately
    |
-LL -     let c = vec![f(); 0];
-LL +     f(); let c: std::vec::Vec<i32> = vec![];
+LL ~     f();
+LL +     let c: std::vec::Vec<i32> = vec![];
    |
 
 error: expression with side effects as the initial value in a zero-sized array initializer
-  --> tests/ui/zero_repeat_side_effects.rs:27:5
+  --> tests/ui/zero_repeat_side_effects.rs:28:5
    |
 LL |     d = vec![f(); 0];
    |     ^^^^^^^^^^^^^^^^
    |
 help: consider performing the side effect separately
    |
-LL -     d = vec![f(); 0];
-LL +     f(); d = vec![] as std::vec::Vec<i32>;
+LL ~     f();
+LL ~     d = vec![] as std::vec::Vec<i32>;
    |
 
 error: expression with side effects as the initial value in a zero-sized array initializer
-  --> tests/ui/zero_repeat_side_effects.rs:31:5
+  --> tests/ui/zero_repeat_side_effects.rs:32:5
    |
 LL |     let e = [println!("side effect"); 0];
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider performing the side effect separately
    |
-LL -     let e = [println!("side effect"); 0];
-LL +     println!("side effect"); let e: [(); 0] = [];
+LL ~     println!("side effect");
+LL +     let e: [(); 0] = [];
    |
 
 error: expression with side effects as the initial value in a zero-sized array initializer
-  --> tests/ui/zero_repeat_side_effects.rs:35:5
+  --> tests/ui/zero_repeat_side_effects.rs:36:5
    |
 LL |     let g = [{ f() }; 0];
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider performing the side effect separately
    |
-LL -     let g = [{ f() }; 0];
-LL +     { f() }; let g: [i32; 0] = [];
+LL ~     { f() };
+LL +     let g: [i32; 0] = [];
    |
 
 error: expression with side effects as the initial value in a zero-sized array initializer
-  --> tests/ui/zero_repeat_side_effects.rs:39:10
+  --> tests/ui/zero_repeat_side_effects.rs:40:10
    |
 LL |     drop(vec![f(); 0]);
    |          ^^^^^^^^^^^^
    |
 help: consider performing the side effect separately
    |
-LL -     drop(vec![f(); 0]);
-LL +     drop({ f(); vec![] as std::vec::Vec<i32> });
+LL ~     drop({
+LL +         f();
+LL +         vec![] as std::vec::Vec<i32>
+LL ~     });
    |
 
 error: expression with side effects as the initial value in a zero-sized array initializer
-  --> tests/ui/zero_repeat_side_effects.rs:43:5
+  --> tests/ui/zero_repeat_side_effects.rs:44:5
    |
 LL |     vec![f(); 0];
    |     ^^^^^^^^^^^^
    |
 help: consider performing the side effect separately
    |
-LL -     vec![f(); 0];
-LL +     { f(); vec![] as std::vec::Vec<i32> };
+LL ~     f();
+LL ~     vec![] as std::vec::Vec<i32>;
    |
 
 error: expression with side effects as the initial value in a zero-sized array initializer
-  --> tests/ui/zero_repeat_side_effects.rs:45:5
+  --> tests/ui/zero_repeat_side_effects.rs:46:5
    |
 LL |     [f(); 0];
    |     ^^^^^^^^
    |
 help: consider performing the side effect separately
    |
-LL -     [f(); 0];
-LL +     { f(); [] as [i32; 0] };
+LL ~     f();
+LL ~     [] as [i32; 0];
    |
 
 error: expression with side effects as the initial value in a zero-sized array initializer
-  --> tests/ui/zero_repeat_side_effects.rs:99:10
+  --> tests/ui/zero_repeat_side_effects.rs:100:10
    |
 LL |     foo(&[Some(f()); 0]);
    |          ^^^^^^^^^^^^^^
    |
 help: consider performing the side effect separately
    |
-LL -     foo(&[Some(f()); 0]);
-LL +     foo(&{ Some(f()); [] as [std::option::Option<i32>; 0] });
+LL ~     foo(&{
+LL +         Some(f());
+LL +         [] as [std::option::Option<i32>; 0]
+LL ~     });
    |
 
 error: expression with side effects as the initial value in a zero-sized array initializer
-  --> tests/ui/zero_repeat_side_effects.rs:101:10
+  --> tests/ui/zero_repeat_side_effects.rs:102:10
    |
 LL |     foo(&[Some(Some(S::new())); 0]);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider performing the side effect separately
    |
-LL -     foo(&[Some(Some(S::new())); 0]);
-LL +     foo(&{ Some(Some(S::new())); [] as [std::option::Option<std::option::Option<S>>; 0] });
+LL ~     foo(&{
+LL +         Some(Some(S::new()));
+LL +         [] as [std::option::Option<std::option::Option<S>>; 0]
+LL ~     });
    |
 
 error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects_never_pattern.fixed b/src/tools/clippy/tests/ui/zero_repeat_side_effects_never_pattern.fixed
new file mode 100644
index 0000000..3d03751
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects_never_pattern.fixed
@@ -0,0 +1,10 @@
+#![warn(clippy::zero_repeat_side_effects)]
+#![allow(clippy::diverging_sub_expression)]
+#![feature(never_type)]
+
+fn issue_14998() {
+    // nameable type thanks to `never_type` being enabled, suggest
+    panic!();
+    let _data: [!; 0] = [];
+    //~^ zero_repeat_side_effects
+}
diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects_never_pattern.rs b/src/tools/clippy/tests/ui/zero_repeat_side_effects_never_pattern.rs
new file mode 100644
index 0000000..3dc1929
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects_never_pattern.rs
@@ -0,0 +1,9 @@
+#![warn(clippy::zero_repeat_side_effects)]
+#![allow(clippy::diverging_sub_expression)]
+#![feature(never_type)]
+
+fn issue_14998() {
+    // nameable type thanks to `never_type` being enabled, suggest
+    let _data = [panic!(); 0];
+    //~^ zero_repeat_side_effects
+}
diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects_never_pattern.stderr b/src/tools/clippy/tests/ui/zero_repeat_side_effects_never_pattern.stderr
new file mode 100644
index 0000000..2809557
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects_never_pattern.stderr
@@ -0,0 +1,16 @@
+error: expression with side effects as the initial value in a zero-sized array initializer
+  --> tests/ui/zero_repeat_side_effects_never_pattern.rs:7:5
+   |
+LL |     let _data = [panic!(); 0];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::zero-repeat-side-effects` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::zero_repeat_side_effects)]`
+help: consider performing the side effect separately
+   |
+LL ~     panic!();
+LL +     let _data: [!; 0] = [];
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects_unfixable.rs b/src/tools/clippy/tests/ui/zero_repeat_side_effects_unfixable.rs
new file mode 100644
index 0000000..82f0884
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects_unfixable.rs
@@ -0,0 +1,13 @@
+//@no-rustfix
+#![warn(clippy::zero_repeat_side_effects)]
+#![expect(clippy::diverging_sub_expression)]
+
+fn issue_14998() {
+    // unnameable types, don't suggest
+    let _data = [|| 3i32; 0];
+    //~^ zero_repeat_side_effects
+
+    // unnameable type because `never_type` is not enabled, don't suggest
+    let _data = [panic!(); 0];
+    //~^ zero_repeat_side_effects
+}
diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects_unfixable.stderr b/src/tools/clippy/tests/ui/zero_repeat_side_effects_unfixable.stderr
new file mode 100644
index 0000000..450617f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects_unfixable.stderr
@@ -0,0 +1,20 @@
+error: expression with side effects as the initial value in a zero-sized array initializer
+  --> tests/ui/zero_repeat_side_effects_unfixable.rs:7:5
+   |
+LL |     let _data = [|| 3i32; 0];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider performing the side effect separately
+   = note: `-D clippy::zero-repeat-side-effects` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::zero_repeat_side_effects)]`
+
+error: expression with side effects as the initial value in a zero-sized array initializer
+  --> tests/ui/zero_repeat_side_effects_unfixable.rs:11:5
+   |
+LL |     let _data = [panic!(); 0];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider performing the side effect separately
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index b2fb509..db951b9 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -45,6 +45,9 @@
 [autolabel."S-waiting-on-review"]
 new_pr = true
 
+[autolabel."needs-fcp"]
+trigger_files = ["clippy_lints/src/declared_lints.rs"]
+
 [concern]
 # These labels are set when there are unresolved concerns, removed otherwise
 labels = ["S-waiting-on-concerns"]
@@ -60,6 +63,7 @@
 users_on_vacation = [
     "matthiaskrgr",
     "Manishearth",
+    "blyxyas",
 ]
 
 [assign.owners]
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index 8792d90..d66529a 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -794,9 +794,9 @@
 
 [[package]]
 name = "libffi"
-version = "4.1.1"
+version = "5.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7681c6fab541f799a829e44a445a0666cf8d8a6cfebf89419e6aed52c604e87"
+checksum = "0444124f3ffd67e1b0b0c661a7f81a278a135eb54aaad4078e79fbc8be50c8a5"
 dependencies = [
  "libc",
  "libffi-sys",
@@ -804,9 +804,9 @@
 
 [[package]]
 name = "libffi-sys"
-version = "3.3.2"
+version = "4.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b0d828d367b4450ed08e7d510dc46636cd660055f50d67ac943bfe788767c29"
+checksum = "3d722da8817ea580d0669da6babe2262d7b86a1af1103da24102b8bb9c101ce7"
 dependencies = [
  "cc",
 ]
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index 12123c26..8bb4f1c 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -39,7 +39,7 @@
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
 # native-lib dependencies
-libffi = { version = "4.1.1", optional = true }
+libffi = { version = "5.0.0", optional = true }
 libloading = { version = "0.8", optional = true }
 serde = { version = "1.0.219", features = ["derive"], optional = true }
 
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index f877706..1160b1b 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-36e4f5d1fe1d63953a5bf1758ce2b64172623e2e
+28d0a4a205f9e511ad2f51ee79a4aa19a704a455
diff --git a/src/tools/miri/src/concurrency/genmc/global_allocations.rs b/src/tools/miri/src/concurrency/genmc/global_allocations.rs
index 272f8d2..7f34c60 100644
--- a/src/tools/miri/src/concurrency/genmc/global_allocations.rs
+++ b/src/tools/miri/src/concurrency/genmc/global_allocations.rs
@@ -6,7 +6,7 @@
 use rand::rngs::StdRng;
 use rustc_const_eval::interpret::{AllocId, AllocInfo, InterpResult, interp_ok};
 use rustc_data_structures::fx::FxHashMap;
-use tracing::debug;
+use rustc_log::tracing::debug;
 
 use crate::alloc_addresses::AddressGenerator;
 
diff --git a/src/tools/miri/src/concurrency/genmc/run.rs b/src/tools/miri/src/concurrency/genmc/run.rs
index 6721a38..6eb51e1 100644
--- a/src/tools/miri/src/concurrency/genmc/run.rs
+++ b/src/tools/miri/src/concurrency/genmc/run.rs
@@ -3,6 +3,7 @@
 use std::time::Instant;
 
 use genmc_sys::EstimationResult;
+use rustc_log::tracing;
 use rustc_middle::ty::TyCtxt;
 
 use super::GlobalState;
diff --git a/src/tools/miri/src/concurrency/genmc/scheduling.rs b/src/tools/miri/src/concurrency/genmc/scheduling.rs
index 6ccbaf4..0703e05 100644
--- a/src/tools/miri/src/concurrency/genmc/scheduling.rs
+++ b/src/tools/miri/src/concurrency/genmc/scheduling.rs
@@ -1,4 +1,5 @@
 use genmc_sys::{ActionKind, ExecutionState};
+use rustc_data_structures::either::Either;
 use rustc_middle::mir::TerminatorKind;
 use rustc_middle::ty::{self, Ty};
 
@@ -38,7 +39,7 @@ fn get_next_instruction_kind<'tcx>(
     let Some(frame) = thread_manager.active_thread_stack().last() else {
         return interp_ok(NonAtomic);
     };
-    let either::Either::Left(loc) = frame.current_loc() else {
+    let Either::Left(loc) = frame.current_loc() else {
         // We are unwinding, so the next step is definitely not atomic.
         return interp_ok(NonAtomic);
     };
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index d3486dc..1c3de90 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -139,6 +139,7 @@ pub enum NonHaltingDiagnostic {
     NativeCallSharedMem {
         tracing: bool,
     },
+    NativeCallFnPtr,
     WeakMemoryOutdatedLoad {
         ptr: Pointer,
     },
@@ -644,6 +645,11 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
             Int2Ptr { .. } => ("integer-to-pointer cast".to_string(), DiagLevel::Warning),
             NativeCallSharedMem { .. } =>
                 ("sharing memory with a native function".to_string(), DiagLevel::Warning),
+            NativeCallFnPtr =>
+                (
+                    "sharing a function pointer with a native function".to_string(),
+                    DiagLevel::Warning,
+                ),
             ExternTypeReborrow =>
                 ("reborrow of reference to `extern type`".to_string(), DiagLevel::Warning),
             GenmcCompareExchangeWeak | GenmcCompareExchangeOrderingMismatch { .. } =>
@@ -682,6 +688,8 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
             Int2Ptr { .. } => format!("integer-to-pointer cast"),
             NativeCallSharedMem { .. } =>
                 format!("sharing memory with a native function called via FFI"),
+            NativeCallFnPtr =>
+                format!("sharing a function pointer with a native function called via FFI"),
             WeakMemoryOutdatedLoad { ptr } =>
                 format!("weak memory emulation: outdated value returned from load at {ptr}"),
             ExternTypeReborrow =>
@@ -779,6 +787,11 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
                         ),
                     ]
                 },
+            NativeCallFnPtr => {
+                vec![note!(
+                    "calling Rust functions from C is not supported and will, in the best case, crash the program"
+                )]
+            }
             ExternTypeReborrow => {
                 assert!(self.borrow_tracker.as_ref().is_some_and(|b| {
                     matches!(
diff --git a/src/tools/miri/src/shims/native_lib/ffi.rs b/src/tools/miri/src/shims/native_lib/ffi.rs
index 0badf22..196f43c 100644
--- a/src/tools/miri/src/shims/native_lib/ffi.rs
+++ b/src/tools/miri/src/shims/native_lib/ffi.rs
@@ -9,11 +9,9 @@
 ///
 /// The safety invariants of the foreign function being called must be upheld (if any).
 pub unsafe fn call<R: libffi::high::CType>(fun: CodePtr, args: &mut [OwnedArg]) -> R {
-    let arg_ptrs: Vec<_> = args.iter().map(|arg| arg.ptr()).collect();
     let cif = Cif::new(args.iter_mut().map(|arg| arg.ty.take().unwrap()), R::reify().into_middle());
-    // SAFETY: Caller upholds that the function is safe to call, and since we
-    // were passed a slice reference we know the `OwnedArg`s won't have been
-    // dropped by this point.
+    let arg_ptrs: Vec<_> = args.iter().map(|arg| ArgPtr::new(&*arg.bytes)).collect();
+    // SAFETY: Caller upholds that the function is safe to call.
     unsafe { cif.call(fun, &arg_ptrs) }
 }
 
@@ -31,16 +29,4 @@ impl OwnedArg {
     pub fn new(ty: FfiType, bytes: Box<[u8]>) -> Self {
         Self { ty: Some(ty), bytes }
     }
-
-    /// Creates a libffi argument pointer pointing to this argument's bytes.
-    /// NB: Since `libffi::middle::Arg` ignores the lifetime of the reference
-    /// it's derived from, it is up to the caller to ensure the `OwnedArg` is
-    /// not dropped before unsafely calling `libffi::middle::Cif::call()`!
-    fn ptr(&self) -> ArgPtr {
-        // FIXME: Using `&self.bytes[0]` to reference the whole array is
-        // definitely unsound under SB, but we're waiting on
-        // https://github.com/libffi-rs/libffi-rs/commit/112a37b3b6ffb35bd75241fbcc580de40ba74a73
-        // to land in a release so that we don't need to do this.
-        ArgPtr::new(&self.bytes[0])
-    }
 }
diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs
index d111d8d..0a0d1bc 100644
--- a/src/tools/miri/src/shims/native_lib/mod.rs
+++ b/src/tools/miri/src/shims/native_lib/mod.rs
@@ -7,7 +7,7 @@
 use libffi::middle::Type as FfiType;
 use rustc_abi::{HasDataLayout, Size};
 use rustc_data_structures::either;
-use rustc_middle::ty::layout::HasTypingEnv;
+use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{self, IntTy, Ty, UintTy};
 use rustc_span::Symbol;
 use serde::{Deserialize, Serialize};
@@ -278,7 +278,7 @@ fn op_to_ffi_arg(&self, v: &OpTy<'tcx>, tracing: bool) -> InterpResult<'tcx, Own
 
         // This should go first so that we emit unsupported before doing a bunch
         // of extra work for types that aren't supported yet.
-        let ty = this.ty_to_ffitype(v.layout.ty)?;
+        let ty = this.ty_to_ffitype(v.layout)?;
 
         // Helper to print a warning when a pointer is shared with the native code.
         let expose = |prov: Provenance| -> InterpResult<'tcx> {
@@ -387,34 +387,44 @@ fn adt_to_ffitype(
         let this = self.eval_context_ref();
         let mut fields = vec![];
         for field in &adt_def.non_enum_variant().fields {
-            fields.push(this.ty_to_ffitype(field.ty(*this.tcx, args))?);
+            let layout = this.layout_of(field.ty(*this.tcx, args))?;
+            fields.push(this.ty_to_ffitype(layout)?);
         }
 
         interp_ok(FfiType::structure(fields))
     }
 
     /// Gets the matching libffi type for a given Ty.
-    fn ty_to_ffitype(&self, ty: Ty<'tcx>) -> InterpResult<'tcx, FfiType> {
-        let this = self.eval_context_ref();
-        interp_ok(match ty.kind() {
-            ty::Int(IntTy::I8) => FfiType::i8(),
-            ty::Int(IntTy::I16) => FfiType::i16(),
-            ty::Int(IntTy::I32) => FfiType::i32(),
-            ty::Int(IntTy::I64) => FfiType::i64(),
-            ty::Int(IntTy::Isize) => FfiType::isize(),
-            ty::Uint(UintTy::U8) => FfiType::u8(),
-            ty::Uint(UintTy::U16) => FfiType::u16(),
-            ty::Uint(UintTy::U32) => FfiType::u32(),
-            ty::Uint(UintTy::U64) => FfiType::u64(),
-            ty::Uint(UintTy::Usize) => FfiType::usize(),
-            ty::RawPtr(pointee_ty, _mut) => {
-                if !pointee_ty.is_sized(*this.tcx, this.typing_env()) {
-                    throw_unsup_format!("passing a pointer to an unsized type over FFI: {}", ty);
-                }
-                FfiType::pointer()
-            }
-            ty::Adt(adt_def, args) => self.adt_to_ffitype(ty, *adt_def, args)?,
-            _ => throw_unsup_format!("unsupported argument type for native call: {}", ty),
+    fn ty_to_ffitype(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, FfiType> {
+        use rustc_abi::{AddressSpace, BackendRepr, Integer, Primitive};
+
+        // `BackendRepr::Scalar` is also a signal to pass this type as a scalar in the ABI. This
+        // matches what codegen does. This does mean that we support some types whose ABI is not
+        // stable, but that's fine -- we are anyway quite conservative in native-lib mode.
+        if let BackendRepr::Scalar(s) = layout.backend_repr {
+            // Simple sanity-check: this cannot be `repr(C)`.
+            assert!(!layout.ty.ty_adt_def().is_some_and(|adt| adt.repr().c()));
+            return interp_ok(match s.primitive() {
+                Primitive::Int(Integer::I8, /* signed */ true) => FfiType::i8(),
+                Primitive::Int(Integer::I16, /* signed */ true) => FfiType::i16(),
+                Primitive::Int(Integer::I32, /* signed */ true) => FfiType::i32(),
+                Primitive::Int(Integer::I64, /* signed */ true) => FfiType::i64(),
+                Primitive::Int(Integer::I8, /* signed */ false) => FfiType::u8(),
+                Primitive::Int(Integer::I16, /* signed */ false) => FfiType::u16(),
+                Primitive::Int(Integer::I32, /* signed */ false) => FfiType::u32(),
+                Primitive::Int(Integer::I64, /* signed */ false) => FfiType::u64(),
+                Primitive::Pointer(AddressSpace::ZERO) => FfiType::pointer(),
+                _ =>
+                    throw_unsup_format!(
+                        "unsupported scalar argument type for native call: {}",
+                        layout.ty
+                    ),
+            });
+        }
+        interp_ok(match layout.ty.kind() {
+            // Scalar types have already been handled above.
+            ty::Adt(adt_def, args) => self.adt_to_ffitype(layout.ty, *adt_def, args)?,
+            _ => throw_unsup_format!("unsupported argument type for native call: {}", layout.ty),
         })
     }
 }
@@ -455,6 +465,13 @@ fn call_native_fn(
         // pointer was passed as argument). Uninitialised memory is left as-is, but any data
         // exposed this way is garbage anyway.
         this.visit_reachable_allocs(this.exposed_allocs(), |this, alloc_id, info| {
+            if matches!(info.kind, AllocKind::Function) {
+                static DEDUP: AtomicBool = AtomicBool::new(false);
+                if !DEDUP.swap(true, std::sync::atomic::Ordering::Relaxed) {
+                    // Newly set, so first time we get here.
+                    this.emit_diagnostic(NonHaltingDiagnostic::NativeCallFnPtr);
+                }
+            }
             // If there is no data behind this pointer, skip this.
             if !matches!(info.kind, AllocKind::LiveData) {
                 return interp_ok(());
diff --git a/src/tools/miri/src/shims/native_lib/trace/child.rs b/src/tools/miri/src/shims/native_lib/trace/child.rs
index 95b0617a..795ad4a 100644
--- a/src/tools/miri/src/shims/native_lib/trace/child.rs
+++ b/src/tools/miri/src/shims/native_lib/trace/child.rs
@@ -228,9 +228,10 @@ pub unsafe fn init_sv() -> Result<(), SvInitError> {
                 match init {
                     // The "Ok" case means that we couldn't ptrace.
                     Ok(e) => return Err(e),
-                    Err(p) => {
+                    Err(_p) => {
                         eprintln!(
-                            "Supervisor process panicked!\n{p:?}\n\nTry running again without using the native-lib tracer."
+                            "Supervisor process panicked!\n\"
+                            Try running again without `-Zmiri-native-lib-enable-tracing`."
                         );
                         std::process::exit(1);
                     }
diff --git a/src/tools/miri/src/shims/native_lib/trace/parent.rs b/src/tools/miri/src/shims/native_lib/trace/parent.rs
index 3ae9825..335188b 100644
--- a/src/tools/miri/src/shims/native_lib/trace/parent.rs
+++ b/src/tools/miri/src/shims/native_lib/trace/parent.rs
@@ -530,7 +530,18 @@ fn handle_segfault(
     // Don't use wait_for_signal here since 1 instruction doesn't give room
     // for any uncertainty + we don't want it `cont()`ing randomly by accident
     // Also, don't let it continue with unprotected memory if something errors!
-    let _ = wait::waitid(wait::Id::Pid(pid), WAIT_FLAGS).map_err(|_| ExecEnd(None))?;
+    let stat = wait::waitid(wait::Id::Pid(pid), WAIT_FLAGS).map_err(|_| ExecEnd(None))?;
+    match stat {
+        wait::WaitStatus::Signaled(_, s, _)
+        | wait::WaitStatus::Stopped(_, s)
+        | wait::WaitStatus::PtraceEvent(_, s, _) =>
+            assert!(
+                !matches!(s, signal::SIGSEGV),
+                "native code segfaulted when re-trying memory access\n\
+                is the native code trying to call a Rust function?"
+            ),
+        _ => (),
+    }
 
     // Zero out again to be safe
     for a in (ch_stack..ch_stack.strict_add(CALLBACK_STACK_SIZE)).step_by(ARCH_WORD_SIZE) {
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index d04ef5e..1f8e604 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -815,7 +815,9 @@ fn emulate_foreign_item_inner(
             "pthread_cond_timedwait" => {
                 let [cond, mutex, abstime] =
                     this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
-                this.pthread_cond_timedwait(cond, mutex, abstime, dest, /* macos_relative_np */ false)?;
+                this.pthread_cond_timedwait(
+                    cond, mutex, abstime, dest, /* macos_relative_np */ false,
+                )?;
             }
             "pthread_cond_destroy" => {
                 let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 0754eb4..1b27359 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -310,7 +310,9 @@ fn emulate_foreign_item_inner(
             "pthread_cond_timedwait_relative_np" => {
                 let [cond, mutex, reltime] =
                     this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
-                this.pthread_cond_timedwait(cond, mutex, reltime, dest, /* macos_relative_np */ true)?;
+                this.pthread_cond_timedwait(
+                    cond, mutex, reltime, dest, /* macos_relative_np */ true,
+                )?;
             }
 
             _ => return interp_ok(EmulateItemResult::NotSupported),
diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr
index 04a3025..200eba8 100644
--- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr
+++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.notrace.stderr
@@ -16,3 +16,18 @@
 LL |     test_access_pointer();
    |     ^^^^^^^^^^^^^^^^^^^^^
 
+warning: sharing a function pointer with a native function called via FFI
+  --> tests/native-lib/pass/ptr_read_access.rs:LL:CC
+   |
+LL |         pass_fn_ptr(Some(nop)); // this one is not
+   |         ^^^^^^^^^^^^^^^^^^^^^^ sharing a function pointer with a native function
+   |
+   = help: calling Rust functions from C is not supported and will, in the best case, crash the program
+   = note: BACKTRACE:
+   = note: inside `pass_fn_ptr` at tests/native-lib/pass/ptr_read_access.rs:LL:CC
+note: inside `main`
+  --> tests/native-lib/pass/ptr_read_access.rs:LL:CC
+   |
+LL |     pass_fn_ptr();
+   |     ^^^^^^^^^^^^^
+
diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs
index bab73f7..36eff04 100644
--- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs
+++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs
@@ -3,11 +3,14 @@
 //@[trace] compile-flags: -Zmiri-native-lib-enable-tracing
 //@compile-flags: -Zmiri-permissive-provenance
 
+use std::ptr::NonNull;
+
 fn main() {
     test_access_pointer();
     test_access_simple();
     test_access_nested();
     test_access_static();
+    pass_fn_ptr();
 }
 
 /// Test function that dereferences an int pointer and prints its contents from C.
@@ -30,11 +33,15 @@ struct Simple {
 
     extern "C" {
         fn access_simple(s_ptr: *const Simple) -> i32;
+        fn access_simple2(s_ptr: NonNull<Simple>) -> i32;
+        fn access_simple3(s_ptr: Option<NonNull<Simple>>) -> i32;
     }
 
     let simple = Simple { field: -42 };
 
     assert_eq!(unsafe { access_simple(&simple) }, -42);
+    assert_eq!(unsafe { access_simple2(NonNull::from(&simple)) }, -42);
+    assert_eq!(unsafe { access_simple3(Some(NonNull::from(&simple))) }, -42);
 }
 
 /// Test function that dereferences nested struct pointers and accesses fields.
@@ -75,3 +82,16 @@ struct Static {
 
     assert_eq!(unsafe { access_static(&STATIC) }, 9001);
 }
+
+fn pass_fn_ptr() {
+    extern "C" {
+        fn pass_fn_ptr(s: Option<extern "C" fn()>);
+    }
+
+    extern "C" fn nop() {}
+
+    unsafe {
+        pass_fn_ptr(None); // this one is fine
+        pass_fn_ptr(Some(nop)); // this one is not
+    }
+}
diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr
index c2a4508..5c0e954 100644
--- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr
+++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.trace.stderr
@@ -17,3 +17,18 @@
 LL |     test_access_pointer();
    |     ^^^^^^^^^^^^^^^^^^^^^
 
+warning: sharing a function pointer with a native function called via FFI
+  --> tests/native-lib/pass/ptr_read_access.rs:LL:CC
+   |
+LL |         pass_fn_ptr(Some(nop)); // this one is not
+   |         ^^^^^^^^^^^^^^^^^^^^^^ sharing a function pointer with a native function
+   |
+   = help: calling Rust functions from C is not supported and will, in the best case, crash the program
+   = note: BACKTRACE:
+   = note: inside `pass_fn_ptr` at tests/native-lib/pass/ptr_read_access.rs:LL:CC
+note: inside `main`
+  --> tests/native-lib/pass/ptr_read_access.rs:LL:CC
+   |
+LL |     pass_fn_ptr();
+   |     ^^^^^^^^^^^^^
+
diff --git a/src/tools/miri/tests/native-lib/ptr_read_access.c b/src/tools/miri/tests/native-lib/ptr_read_access.c
index 021eb6a..5f071ca 100644
--- a/src/tools/miri/tests/native-lib/ptr_read_access.c
+++ b/src/tools/miri/tests/native-lib/ptr_read_access.c
@@ -19,6 +19,13 @@
 EXPORT int32_t access_simple(const Simple *s_ptr) {
   return s_ptr->field;
 }
+// Some copies so Rust can import them at different types.
+EXPORT int32_t access_simple2(const Simple *s_ptr) {
+  return s_ptr->field;
+}
+EXPORT int32_t access_simple3(const Simple *s_ptr) {
+  return s_ptr->field;
+}
 
 /* Test: test_access_nested */
 
@@ -55,3 +62,9 @@
 EXPORT uintptr_t do_one_deref(const int32_t ***ptr) {
   return (uintptr_t)*ptr;
 }
+
+/* Test: pass_fn_ptr */
+
+EXPORT void pass_fn_ptr(void f(void)) {
+  (void)f; // suppress unused warning
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-mem.rs b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs
index 531d637..7105b07 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-mem.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs
@@ -1,6 +1,10 @@
 #![feature(pointer_is_aligned_to)]
 use std::{mem, ptr, slice};
 
+#[path = "../../utils/mod.rs"]
+mod utils;
+use utils::check_nondet;
+
 fn test_memcpy() {
     unsafe {
         let src = [1i8, 2, 3];
@@ -120,13 +124,12 @@ fn test_memset() {
 }
 
 fn test_malloc() {
-    // Test that small allocations sometimes *are* not very aligned.
-    let saw_unaligned = (0..64).any(|_| unsafe {
+    // Test that small allocations sometimes are *not* very aligned (and sometimes they are).
+    check_nondet(|| unsafe {
         let p = libc::malloc(3);
         libc::free(p);
-        (p as usize) % 4 != 0 // find any that this is *not* 4-aligned
+        (p as usize) % 4 == 0
     });
-    assert!(saw_unaligned);
 
     unsafe {
         let p1 = libc::malloc(20);
diff --git a/src/tools/miri/tests/pass/dyn-traits.rs b/src/tools/miri/tests/pass/dyn-traits.rs
index f622012..47f913a 100644
--- a/src/tools/miri/tests/pass/dyn-traits.rs
+++ b/src/tools/miri/tests/pass/dyn-traits.rs
@@ -1,3 +1,7 @@
+#[path = "../utils/mod.rs"]
+mod utils;
+use utils::check_nondet;
+
 fn ref_box_dyn() {
     struct Struct(i32);
 
@@ -147,7 +151,7 @@ fn vtable_ptr_eq() {
     // We don't always get the same vtable when casting this to a wide pointer.
     let x = &2;
     let x_wide = x as &dyn fmt::Display;
-    assert!((0..256).any(|_| !ptr::eq(x as &dyn fmt::Display, x_wide)));
+    check_nondet(|| ptr::eq(x as &dyn fmt::Display, x_wide));
 }
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/function_pointers.rs b/src/tools/miri/tests/pass/function_pointers.rs
index 7145be3..96f6f25 100644
--- a/src/tools/miri/tests/pass/function_pointers.rs
+++ b/src/tools/miri/tests/pass/function_pointers.rs
@@ -2,6 +2,10 @@
 
 use std::mem;
 
+#[path = "../utils/mod.rs"]
+mod utils;
+use utils::check_nondet;
+
 trait Answer {
     fn answer() -> Self;
 }
@@ -30,6 +34,7 @@ fn i() -> i32 {
     73
 }
 
+#[inline(never)] // optimizations mask the non-determinism we test for below
 fn return_fn_ptr(f: fn() -> i32) -> fn() -> i32 {
     f
 }
@@ -85,7 +90,7 @@ fn main() {
     assert!(return_fn_ptr(i) as unsafe fn() -> i32 == i as fn() -> i32 as unsafe fn() -> i32);
     // Miri gives different addresses to different reifications of a generic function.
     // at least if we try often enough.
-    assert!((0..256).any(|_| return_fn_ptr(f) != f));
+    check_nondet(|| return_fn_ptr(f) == f);
     // However, if we only turn `f` into a function pointer and use that pointer,
     // it is equal to itself.
     let f2 = f as fn() -> i32;
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 022dcc5..43fbf6b 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -13,6 +13,7 @@
 
 #[path = "../../utils/mod.rs"]
 mod utils;
+use utils::check_nondet;
 
 fn main() {
     test_path_conversion();
@@ -81,25 +82,25 @@ fn test_file() {
 }
 
 fn test_file_partial_reads_writes() {
-    let path = utils::prepare_with_content("miri_test_fs_file.txt", b"abcdefg");
+    let path1 = utils::prepare_with_content("miri_test_fs_file1.txt", b"abcdefg");
+    let path2 = utils::prepare_with_content("miri_test_fs_file2.txt", b"abcdefg");
 
     // Ensure we sometimes do incomplete writes.
-    let got_short_write = (0..16).any(|_| {
-        let _ = remove_file(&path); // FIXME(win, issue #4483): errors if the file already exists
-        let mut file = File::create(&path).unwrap();
-        file.write(&[0; 4]).unwrap() != 4
+    check_nondet(|| {
+        let _ = remove_file(&path1); // FIXME(win, issue #4483): errors if the file already exists
+        let mut file = File::create(&path1).unwrap();
+        file.write(&[0; 4]).unwrap() == 4
     });
-    assert!(got_short_write);
     // Ensure we sometimes do incomplete reads.
-    let got_short_read = (0..16).any(|_| {
-        let mut file = File::open(&path).unwrap();
+    check_nondet(|| {
+        let mut file = File::open(&path2).unwrap();
         let mut buf = [0; 4];
-        file.read(&mut buf).unwrap() != 4
+        file.read(&mut buf).unwrap() == 4
     });
-    assert!(got_short_read);
 
     // Clean up
-    remove_file(&path).unwrap();
+    remove_file(&path1).unwrap();
+    remove_file(&path2).unwrap();
 }
 
 fn test_file_clone() {
diff --git a/src/tools/miri/tests/utils/mod.rs b/src/tools/miri/tests/utils/mod.rs
index 37f9996..f855f11 100644
--- a/src/tools/miri/tests/utils/mod.rs
+++ b/src/tools/miri/tests/utils/mod.rs
@@ -55,7 +55,10 @@ pub fn check_all_outcomes<T: Eq + std::hash::Hash + std::fmt::Debug>(
 /// Check that the operation is non-deterministic
 #[track_caller]
 pub fn check_nondet<T: PartialEq + std::fmt::Debug>(f: impl Fn() -> T) {
-    let rounds = 50;
+    // We test some rather unlikely events with this, such as two global allocations getting the
+    // same "salt" (1/32 chance). So give this *many* shots before we consider the test to have
+    // failed.
+    let rounds = 500;
     let first = f();
     for _ in 1..rounds {
         if f() != first {
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 3f40bef..3164dcc 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -569,6 +569,7 @@ macro_rules! location {
     "libc",
     "memchr",
     "miniz_oxide",
+    "moto-rt",
     "object",
     "r-efi",
     "r-efi-alloc",
diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff
index 24b1021..5df2232 100644
--- a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff
@@ -3,23 +3,17 @@
   
   fn hello() -> () {
       let mut _0: ();
-      let mut _1: bool;
-      let mut _2: !;
+      let mut _1: !;
   
       bb0: {
-          StorageLive(_1);
--         _1 = const <bool as NeedsDrop>::NEEDS;
--         switchInt(move _1) -> [0: bb2, otherwise: bb1];
-+         _1 = const false;
-+         switchInt(const false) -> [0: bb2, otherwise: bb1];
+          goto -> bb2;
       }
   
       bb1: {
-          _2 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable;
+          _1 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable;
       }
   
       bb2: {
-          StorageDead(_1);
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff
index a73485e..788a442 100644
--- a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff
@@ -3,23 +3,17 @@
   
   fn hello() -> () {
       let mut _0: ();
-      let mut _1: bool;
-      let mut _2: !;
+      let mut _1: !;
   
       bb0: {
-          StorageLive(_1);
--         _1 = const <bool as NeedsDrop>::NEEDS;
--         switchInt(move _1) -> [0: bb2, otherwise: bb1];
-+         _1 = const false;
-+         switchInt(const false) -> [0: bb2, otherwise: bb1];
+          goto -> bb2;
       }
   
       bb1: {
-          _2 = begin_panic::<&str>(const "explicit panic") -> unwind continue;
+          _1 = begin_panic::<&str>(const "explicit panic") -> unwind continue;
       }
   
       bb2: {
-          StorageDead(_1);
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/control_flow_simplification.rs b/tests/mir-opt/const_prop/control_flow_simplification.rs
index 64605ca..8ec630d 100644
--- a/tests/mir-opt/const_prop/control_flow_simplification.rs
+++ b/tests/mir-opt/const_prop/control_flow_simplification.rs
@@ -1,4 +1,3 @@
-// skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 //@ test-mir-pass: GVN
 //@ compile-flags: -Zmir-opt-level=1
@@ -12,6 +11,9 @@ impl<This> NeedsDrop for This {}
 // EMIT_MIR control_flow_simplification.hello.GVN.diff
 // EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir
 fn hello<T>() {
+    // CHECK-LABEL: fn hello(
+    // CHECK: bb0:
+    // CHECK-NEXT: return;
     if <bool>::NEEDS {
         panic!()
     }
diff --git a/tests/mir-opt/const_prop/trivial_const.rs b/tests/mir-opt/const_prop/trivial_const.rs
new file mode 100644
index 0000000..e9134c1
--- /dev/null
+++ b/tests/mir-opt/const_prop/trivial_const.rs
@@ -0,0 +1,15 @@
+//@ test-mir-pass: SimplifyConstCondition-after-inst-simplify
+//@ compile-flags: -Zmir-enable-passes=+InstSimplify-after-simplifycfg -Zub_checks=false -Zinline-mir
+
+#![crate_type = "lib"]
+
+// EMIT_MIR trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff
+pub fn unwrap_unchecked(v: &Option<i32>) -> i32 {
+    // CHECK-LABEL: fn unwrap_unchecked(
+    // CHECK: bb0: {
+    // CHECK: switchInt({{.*}}) -> [0: [[AssumeFalseBB:bb.*]], 1:
+    // CHECK: [[AssumeFalseBB]]: {
+    // CHECK-NEXT: unreachable;
+    let v = unsafe { v.unwrap_unchecked() };
+    v
+}
diff --git a/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff b/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff
new file mode 100644
index 0000000..d14c42a
--- /dev/null
+++ b/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff
@@ -0,0 +1,58 @@
+- // MIR for `unwrap_unchecked` before SimplifyConstCondition-after-inst-simplify
++ // MIR for `unwrap_unchecked` after SimplifyConstCondition-after-inst-simplify
+  
+  fn unwrap_unchecked(_1: &Option<i32>) -> i32 {
+      debug v => _1;
+      let mut _0: i32;
+      let _2: i32;
+      let mut _3: std::option::Option<i32>;
+      scope 1 {
+          debug v => _2;
+      }
+      scope 2 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
+          let mut _4: isize;
+          scope 3 {
+          }
+          scope 4 (inlined #[track_caller] unreachable_unchecked) {
+              let _5: ();
+              scope 5 (inlined core::ub_checks::check_language_ub) {
+                  let mut _6: bool;
+                  scope 6 (inlined core::ub_checks::check_language_ub::runtime) {
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = copy (*_1);
+          StorageLive(_4);
+          StorageLive(_5);
+          _4 = discriminant(_3);
+          switchInt(move _4) -> [0: bb2, 1: bb3, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+-         StorageLive(_6);
+-         _6 = const false;
+-         assume(copy _6);
+-         _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable];
++         unreachable;
+      }
+  
+      bb3: {
+          _2 = move ((_3 as Some).0: i32);
+          StorageDead(_5);
+          StorageDead(_4);
+          StorageDead(_3);
+          _0 = copy _2;
+          StorageDead(_2);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs
index 4368933..5534a45 100644
--- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs
+++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs
@@ -1,10 +1,14 @@
-// skip-filecheck
-//@ compile-flags: -Zmir-enable-passes=+Inline,+GVN --crate-type lib
+//@ test-mir-pass: GVN
+//@ compile-flags: -Zinline-mir --crate-type lib
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // EMIT_MIR dont_reset_cast_kind_without_updating_operand.test.GVN.diff
 
 fn test() {
+    // CHECK-LABEL: fn test(
+    // CHECK: debug slf => [[SLF:_.*]];
+    // CHECK: debug _x => [[X:_.*]];
+    // CHECK: [[X]] = copy [[SLF]] as *mut () (PtrToPtr);
     let vp_ctx: &Box<()> = &Box::new(());
     let slf: *const () = &raw const **vp_ctx;
     let bytes = std::ptr::slice_from_raw_parts(slf, 1);
diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff
index bb10fc8..5d7343a 100644
--- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff
@@ -6,24 +6,26 @@
       let _1: &std::boxed::Box<()>;
       let _2: &std::boxed::Box<()>;
       let _3: std::boxed::Box<()>;
-      let mut _6: *const ();
-      let mut _8: *const [()];
-      let mut _9: *const ();
-      let mut _22: usize;
-      let mut _23: std::ptr::NonNull<()>;
+      let mut _4: ();
+      let mut _7: *const ();
+      let mut _9: *const [()];
+      let mut _10: std::boxed::Box<()>;
+      let mut _11: *const ();
+      let mut _25: usize;
       scope 1 {
           debug vp_ctx => _1;
-          let _4: *const ();
+          let _5: *const ();
           scope 2 {
-              debug slf => _9;
-              let _5: *const [()];
+              debug slf => _5;
+              let _6: *const [()];
               scope 3 {
-                  debug bytes => _5;
-                  let _7: *mut ();
+                  debug bytes => _6;
+                  let _8: *mut ();
                   scope 4 {
-                      debug _x => _7;
+                      debug _x => _8;
                   }
                   scope 18 (inlined foo) {
+                      let mut _26: *const [()];
                   }
               }
               scope 16 (inlined slice_from_raw_parts::<()>) {
@@ -33,21 +35,22 @@
           }
       }
       scope 5 (inlined Box::<()>::new) {
-          let mut _10: usize;
-          let mut _11: usize;
-          let mut _12: *mut u8;
+          let mut _12: usize;
+          let mut _13: usize;
+          let mut _14: *mut u8;
+          let mut _15: *const ();
           scope 6 (inlined alloc::alloc::exchange_malloc) {
-              let _13: std::alloc::Layout;
-              let mut _14: std::result::Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError>;
-              let mut _15: isize;
-              let mut _17: !;
+              let _16: std::alloc::Layout;
+              let mut _17: std::result::Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError>;
+              let mut _18: isize;
+              let mut _20: !;
               scope 7 {
-                  let _16: std::ptr::NonNull<[u8]>;
+                  let _19: std::ptr::NonNull<[u8]>;
                   scope 8 {
                       scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) {
                           scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) {
                               scope 13 (inlined NonNull::<[u8]>::cast::<u8>) {
-                                  let mut _21: *mut [u8];
+                                  let mut _24: *mut [u8];
                                   scope 14 (inlined NonNull::<[u8]>::as_ptr) {
                                   }
                               }
@@ -60,31 +63,37 @@
                   }
               }
               scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) {
-                  let mut _18: bool;
-                  let _19: ();
-                  let mut _20: std::ptr::Alignment;
+                  let mut _21: bool;
+                  let _22: ();
+                  let mut _23: std::ptr::Alignment;
               }
           }
       }
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
-          StorageLive(_10);
-          StorageLive(_11);
+          StorageLive(_4);
+-         _4 = ();
++         _4 = const ();
           StorageLive(_12);
--         _10 = SizeOf(());
--         _11 = AlignOf(());
-+         _10 = const 0_usize;
-+         _11 = const 1_usize;
           StorageLive(_13);
+          StorageLive(_14);
           StorageLive(_15);
+-         _12 = SizeOf(());
+-         _13 = AlignOf(());
++         _12 = const 0_usize;
++         _13 = const 1_usize;
           StorageLive(_16);
           StorageLive(_18);
-          _18 = const false;
--         switchInt(move _18) -> [0: bb6, otherwise: bb5];
-+         switchInt(const false) -> [0: bb6, otherwise: bb5];
+          StorageLive(_19);
+          StorageLive(_20);
+          StorageLive(_22);
+          StorageLive(_21);
+          _21 = UbChecks();
+          switchInt(move _21) -> [0: bb6, otherwise: bb5];
       }
   
       bb1: {
@@ -98,76 +107,91 @@
       }
   
       bb3: {
--         _17 = handle_alloc_error(move _13) -> unwind unreachable;
-+         _17 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}) -> unwind unreachable;
+-         _20 = handle_alloc_error(move _16) -> unwind unreachable;
++         _20 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}) -> unwind unreachable;
       }
   
       bb4: {
-          _16 = copy ((_14 as Ok).0: std::ptr::NonNull<[u8]>);
-          StorageLive(_21);
-          _21 = copy _16 as *mut [u8] (Transmute);
-          _12 = copy _21 as *mut u8 (PtrToPtr);
-          StorageDead(_21);
-          StorageDead(_14);
-          StorageDead(_16);
-          StorageDead(_15);
-          StorageDead(_13);
-          _3 = ShallowInitBox(copy _12, ());
-          StorageDead(_12);
-          StorageDead(_11);
-          StorageDead(_10);
-          _2 = &_3;
-          _1 = copy _2;
-          StorageDead(_2);
-          StorageLive(_4);
-          _23 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>);
-          _9 = copy _23 as *const () (Transmute);
-          _4 = copy _9;
--         StorageLive(_5);
-+         nop;
-          StorageLive(_6);
--         _6 = copy _4;
-+         _6 = copy _9;
-          StorageLive(_22);
-          _22 = const 1_usize;
--         _5 = *const [()] from (copy _6, copy _22);
-+         _5 = *const [()] from (copy _9, const 1_usize);
+          _19 = copy ((_17 as Ok).0: std::ptr::NonNull<[u8]>);
+          StorageLive(_24);
+          _24 = copy _19 as *mut [u8] (Transmute);
+          _14 = copy _24 as *mut u8 (PtrToPtr);
+          StorageDead(_24);
+          StorageDead(_17);
           StorageDead(_22);
-          StorageDead(_6);
+          StorageDead(_20);
+          StorageDead(_19);
+          StorageDead(_18);
+          StorageDead(_16);
+          _3 = ShallowInitBox(copy _14, ());
+          _15 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute);
+-         (*_15) = move _4;
++         (*_15) = const ();
+          StorageDead(_15);
+          StorageDead(_14);
+          StorageDead(_13);
+          StorageDead(_12);
+          StorageDead(_4);
+          _2 = &_3;
+          _1 = &(*_2);
+-         StorageDead(_2);
+-         StorageLive(_5);
+-         _10 = copy (*_1);
++         nop;
++         nop;
++         _10 = copy (*_2);
+          _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute);
+          _5 = &raw const (*_11);
+-         StorageLive(_6);
++         nop;
           StorageLive(_7);
-          StorageLive(_8);
-          _8 = copy _5;
--         _7 = copy _8 as *mut () (PtrToPtr);
-+         _7 = copy _23 as *mut () (Transmute);
-          StorageDead(_8);
+          _7 = copy _5;
+          StorageLive(_25);
+          _25 = const 1_usize;
+-         _6 = *const [()] from (copy _7, copy _25);
++         _6 = *const [()] from (copy _5, const 1_usize);
+          StorageDead(_25);
           StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          _9 = copy _6;
+          StorageLive(_26);
+-         _26 = copy _9;
+-         _8 = copy _9 as *mut () (PtrToPtr);
++         _26 = copy _6;
++         _8 = copy _5 as *mut () (PtrToPtr);
+          StorageDead(_26);
+          StorageDead(_9);
+          _0 = const ();
+          StorageDead(_8);
+-         StorageDead(_6);
 -         StorageDead(_5);
 +         nop;
-          StorageDead(_4);
++         nop;
           drop(_3) -> [return: bb1, unwind unreachable];
       }
   
       bb5: {
--         _19 = Layout::from_size_align_unchecked::precondition_check(copy _10, copy _11) -> [return: bb6, unwind unreachable];
-+         _19 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable];
+-         _22 = Layout::from_size_align_unchecked::precondition_check(copy _12, copy _13) -> [return: bb6, unwind unreachable];
++         _22 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable];
       }
   
       bb6: {
-          StorageDead(_18);
-          StorageLive(_20);
--         _20 = copy _11 as std::ptr::Alignment (Transmute);
--         _13 = Layout { size: copy _10, align: move _20 };
-+         _20 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0);
-+         _13 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }};
-          StorageDead(_20);
-          StorageLive(_14);
--         _14 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _13, const false) -> [return: bb7, unwind unreachable];
-+         _14 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable];
+          StorageDead(_21);
+          StorageLive(_23);
+-         _23 = copy _13 as std::ptr::Alignment (Transmute);
+-         _16 = Layout { size: copy _12, align: move _23 };
++         _23 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0);
++         _16 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }};
+          StorageDead(_23);
+          StorageLive(_17);
+-         _17 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _16, const false) -> [return: bb7, unwind unreachable];
++         _17 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable];
       }
   
       bb7: {
-          _15 = discriminant(_14);
-          switchInt(move _15) -> [0: bb4, 1: bb3, otherwise: bb2];
+          _18 = discriminant(_17);
+          switchInt(move _18) -> [0: bb4, 1: bb3, otherwise: bb2];
       }
 + }
 + 
diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff
index 88754cb..82a14a8 100644
--- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-unwind.diff
@@ -6,24 +6,26 @@
       let _1: &std::boxed::Box<()>;
       let _2: &std::boxed::Box<()>;
       let _3: std::boxed::Box<()>;
-      let mut _6: *const ();
-      let mut _8: *const [()];
-      let mut _9: *const ();
-      let mut _10: usize;
-      let mut _11: std::ptr::NonNull<()>;
+      let mut _4: ();
+      let mut _7: *const ();
+      let mut _9: *const [()];
+      let mut _10: std::boxed::Box<()>;
+      let mut _11: *const ();
+      let mut _12: usize;
       scope 1 {
           debug vp_ctx => _1;
-          let _4: *const ();
+          let _5: *const ();
           scope 2 {
-              debug slf => _9;
-              let _5: *const [()];
+              debug slf => _5;
+              let _6: *const [()];
               scope 3 {
-                  debug bytes => _5;
-                  let _7: *mut ();
+                  debug bytes => _6;
+                  let _8: *mut ();
                   scope 4 {
-                      debug _x => _7;
+                      debug _x => _8;
                   }
                   scope 7 (inlined foo) {
+                      let mut _13: *const [()];
                   }
               }
               scope 5 (inlined slice_from_raw_parts::<()>) {
@@ -35,40 +37,54 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
-          _3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue];
+          StorageLive(_4);
+-         _4 = ();
+-         _3 = Box::<()>::new(move _4) -> [return: bb1, unwind continue];
++         _4 = const ();
++         _3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue];
       }
   
       bb1: {
+          StorageDead(_4);
           _2 = &_3;
-          _1 = copy _2;
-          StorageDead(_2);
-          StorageLive(_4);
-          _11 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>);
-          _9 = copy _11 as *const () (Transmute);
-          _4 = copy _9;
+          _1 = &(*_2);
+-         StorageDead(_2);
 -         StorageLive(_5);
+-         _10 = copy (*_1);
 +         nop;
-          StorageLive(_6);
--         _6 = copy _4;
-+         _6 = copy _9;
-          StorageLive(_10);
-          _10 = const 1_usize;
--         _5 = *const [()] from (copy _6, copy _10);
-+         _5 = *const [()] from (copy _9, const 1_usize);
-          StorageDead(_10);
-          StorageDead(_6);
++         nop;
++         _10 = copy (*_2);
+          _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute);
+          _5 = &raw const (*_11);
+-         StorageLive(_6);
++         nop;
           StorageLive(_7);
-          StorageLive(_8);
-          _8 = copy _5;
--         _7 = copy _8 as *mut () (PtrToPtr);
-+         _7 = copy _11 as *mut () (Transmute);
-          StorageDead(_8);
+          _7 = copy _5;
+          StorageLive(_12);
+          _12 = const 1_usize;
+-         _6 = *const [()] from (copy _7, copy _12);
++         _6 = *const [()] from (copy _5, const 1_usize);
+          StorageDead(_12);
           StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          _9 = copy _6;
+          StorageLive(_13);
+-         _13 = copy _9;
+-         _8 = copy _9 as *mut () (PtrToPtr);
++         _13 = copy _6;
++         _8 = copy _5 as *mut () (PtrToPtr);
+          StorageDead(_13);
+          StorageDead(_9);
+          _0 = const ();
+          StorageDead(_8);
+-         StorageDead(_6);
 -         StorageDead(_5);
 +         nop;
-          StorageDead(_4);
++         nop;
           drop(_3) -> [return: bb2, unwind: bb3];
       }
   
diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff
index 97b7c9a..ba5fe28 100644
--- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff
@@ -6,24 +6,26 @@
       let _1: &std::boxed::Box<()>;
       let _2: &std::boxed::Box<()>;
       let _3: std::boxed::Box<()>;
-      let mut _6: *const ();
-      let mut _8: *const [()];
-      let mut _9: *const ();
-      let mut _22: usize;
-      let mut _23: std::ptr::NonNull<()>;
+      let mut _4: ();
+      let mut _7: *const ();
+      let mut _9: *const [()];
+      let mut _10: std::boxed::Box<()>;
+      let mut _11: *const ();
+      let mut _25: usize;
       scope 1 {
           debug vp_ctx => _1;
-          let _4: *const ();
+          let _5: *const ();
           scope 2 {
-              debug slf => _9;
-              let _5: *const [()];
+              debug slf => _5;
+              let _6: *const [()];
               scope 3 {
-                  debug bytes => _5;
-                  let _7: *mut ();
+                  debug bytes => _6;
+                  let _8: *mut ();
                   scope 4 {
-                      debug _x => _7;
+                      debug _x => _8;
                   }
                   scope 18 (inlined foo) {
+                      let mut _26: *const [()];
                   }
               }
               scope 16 (inlined slice_from_raw_parts::<()>) {
@@ -33,21 +35,22 @@
           }
       }
       scope 5 (inlined Box::<()>::new) {
-          let mut _10: usize;
-          let mut _11: usize;
-          let mut _12: *mut u8;
+          let mut _12: usize;
+          let mut _13: usize;
+          let mut _14: *mut u8;
+          let mut _15: *const ();
           scope 6 (inlined alloc::alloc::exchange_malloc) {
-              let _13: std::alloc::Layout;
-              let mut _14: std::result::Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError>;
-              let mut _15: isize;
-              let mut _17: !;
+              let _16: std::alloc::Layout;
+              let mut _17: std::result::Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError>;
+              let mut _18: isize;
+              let mut _20: !;
               scope 7 {
-                  let _16: std::ptr::NonNull<[u8]>;
+                  let _19: std::ptr::NonNull<[u8]>;
                   scope 8 {
                       scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) {
                           scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) {
                               scope 13 (inlined NonNull::<[u8]>::cast::<u8>) {
-                                  let mut _21: *mut [u8];
+                                  let mut _24: *mut [u8];
                                   scope 14 (inlined NonNull::<[u8]>::as_ptr) {
                                   }
                               }
@@ -60,31 +63,37 @@
                   }
               }
               scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) {
-                  let mut _18: bool;
-                  let _19: ();
-                  let mut _20: std::ptr::Alignment;
+                  let mut _21: bool;
+                  let _22: ();
+                  let mut _23: std::ptr::Alignment;
               }
           }
       }
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
-          StorageLive(_10);
-          StorageLive(_11);
+          StorageLive(_4);
+-         _4 = ();
++         _4 = const ();
           StorageLive(_12);
--         _10 = SizeOf(());
--         _11 = AlignOf(());
-+         _10 = const 0_usize;
-+         _11 = const 1_usize;
           StorageLive(_13);
+          StorageLive(_14);
           StorageLive(_15);
+-         _12 = SizeOf(());
+-         _13 = AlignOf(());
++         _12 = const 0_usize;
++         _13 = const 1_usize;
           StorageLive(_16);
           StorageLive(_18);
-          _18 = const false;
--         switchInt(move _18) -> [0: bb6, otherwise: bb5];
-+         switchInt(const false) -> [0: bb6, otherwise: bb5];
+          StorageLive(_19);
+          StorageLive(_20);
+          StorageLive(_22);
+          StorageLive(_21);
+          _21 = UbChecks();
+          switchInt(move _21) -> [0: bb6, otherwise: bb5];
       }
   
       bb1: {
@@ -98,76 +107,91 @@
       }
   
       bb3: {
--         _17 = handle_alloc_error(move _13) -> unwind unreachable;
-+         _17 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}) -> unwind unreachable;
+-         _20 = handle_alloc_error(move _16) -> unwind unreachable;
++         _20 = handle_alloc_error(const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}) -> unwind unreachable;
       }
   
       bb4: {
-          _16 = copy ((_14 as Ok).0: std::ptr::NonNull<[u8]>);
-          StorageLive(_21);
-          _21 = copy _16 as *mut [u8] (Transmute);
-          _12 = copy _21 as *mut u8 (PtrToPtr);
-          StorageDead(_21);
-          StorageDead(_14);
-          StorageDead(_16);
-          StorageDead(_15);
-          StorageDead(_13);
-          _3 = ShallowInitBox(copy _12, ());
-          StorageDead(_12);
-          StorageDead(_11);
-          StorageDead(_10);
-          _2 = &_3;
-          _1 = copy _2;
-          StorageDead(_2);
-          StorageLive(_4);
-          _23 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>);
-          _9 = copy _23 as *const () (Transmute);
-          _4 = copy _9;
--         StorageLive(_5);
-+         nop;
-          StorageLive(_6);
--         _6 = copy _4;
-+         _6 = copy _9;
-          StorageLive(_22);
-          _22 = const 1_usize;
--         _5 = *const [()] from (copy _6, copy _22);
-+         _5 = *const [()] from (copy _9, const 1_usize);
+          _19 = copy ((_17 as Ok).0: std::ptr::NonNull<[u8]>);
+          StorageLive(_24);
+          _24 = copy _19 as *mut [u8] (Transmute);
+          _14 = copy _24 as *mut u8 (PtrToPtr);
+          StorageDead(_24);
+          StorageDead(_17);
           StorageDead(_22);
-          StorageDead(_6);
+          StorageDead(_20);
+          StorageDead(_19);
+          StorageDead(_18);
+          StorageDead(_16);
+          _3 = ShallowInitBox(copy _14, ());
+          _15 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute);
+-         (*_15) = move _4;
++         (*_15) = const ();
+          StorageDead(_15);
+          StorageDead(_14);
+          StorageDead(_13);
+          StorageDead(_12);
+          StorageDead(_4);
+          _2 = &_3;
+          _1 = &(*_2);
+-         StorageDead(_2);
+-         StorageLive(_5);
+-         _10 = copy (*_1);
++         nop;
++         nop;
++         _10 = copy (*_2);
+          _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute);
+          _5 = &raw const (*_11);
+-         StorageLive(_6);
++         nop;
           StorageLive(_7);
-          StorageLive(_8);
-          _8 = copy _5;
--         _7 = copy _8 as *mut () (PtrToPtr);
-+         _7 = copy _23 as *mut () (Transmute);
-          StorageDead(_8);
+          _7 = copy _5;
+          StorageLive(_25);
+          _25 = const 1_usize;
+-         _6 = *const [()] from (copy _7, copy _25);
++         _6 = *const [()] from (copy _5, const 1_usize);
+          StorageDead(_25);
           StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          _9 = copy _6;
+          StorageLive(_26);
+-         _26 = copy _9;
+-         _8 = copy _9 as *mut () (PtrToPtr);
++         _26 = copy _6;
++         _8 = copy _5 as *mut () (PtrToPtr);
+          StorageDead(_26);
+          StorageDead(_9);
+          _0 = const ();
+          StorageDead(_8);
+-         StorageDead(_6);
 -         StorageDead(_5);
 +         nop;
-          StorageDead(_4);
++         nop;
           drop(_3) -> [return: bb1, unwind unreachable];
       }
   
       bb5: {
--         _19 = Layout::from_size_align_unchecked::precondition_check(copy _10, copy _11) -> [return: bb6, unwind unreachable];
-+         _19 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable];
+-         _22 = Layout::from_size_align_unchecked::precondition_check(copy _12, copy _13) -> [return: bb6, unwind unreachable];
++         _22 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable];
       }
   
       bb6: {
-          StorageDead(_18);
-          StorageLive(_20);
--         _20 = copy _11 as std::ptr::Alignment (Transmute);
--         _13 = Layout { size: copy _10, align: move _20 };
-+         _20 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0);
-+         _13 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }};
-          StorageDead(_20);
-          StorageLive(_14);
--         _14 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _13, const false) -> [return: bb7, unwind unreachable];
-+         _14 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable];
+          StorageDead(_21);
+          StorageLive(_23);
+-         _23 = copy _13 as std::ptr::Alignment (Transmute);
+-         _16 = Layout { size: copy _12, align: move _23 };
++         _23 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0);
++         _16 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }};
+          StorageDead(_23);
+          StorageLive(_17);
+-         _17 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _16, const false) -> [return: bb7, unwind unreachable];
++         _17 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable];
       }
   
       bb7: {
-          _15 = discriminant(_14);
-          switchInt(move _15) -> [0: bb4, 1: bb3, otherwise: bb2];
+          _18 = discriminant(_17);
+          switchInt(move _18) -> [0: bb4, 1: bb3, otherwise: bb2];
       }
 + }
 + 
diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff
index 88754cb..82a14a8 100644
--- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-unwind.diff
@@ -6,24 +6,26 @@
       let _1: &std::boxed::Box<()>;
       let _2: &std::boxed::Box<()>;
       let _3: std::boxed::Box<()>;
-      let mut _6: *const ();
-      let mut _8: *const [()];
-      let mut _9: *const ();
-      let mut _10: usize;
-      let mut _11: std::ptr::NonNull<()>;
+      let mut _4: ();
+      let mut _7: *const ();
+      let mut _9: *const [()];
+      let mut _10: std::boxed::Box<()>;
+      let mut _11: *const ();
+      let mut _12: usize;
       scope 1 {
           debug vp_ctx => _1;
-          let _4: *const ();
+          let _5: *const ();
           scope 2 {
-              debug slf => _9;
-              let _5: *const [()];
+              debug slf => _5;
+              let _6: *const [()];
               scope 3 {
-                  debug bytes => _5;
-                  let _7: *mut ();
+                  debug bytes => _6;
+                  let _8: *mut ();
                   scope 4 {
-                      debug _x => _7;
+                      debug _x => _8;
                   }
                   scope 7 (inlined foo) {
+                      let mut _13: *const [()];
                   }
               }
               scope 5 (inlined slice_from_raw_parts::<()>) {
@@ -35,40 +37,54 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
-          _3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue];
+          StorageLive(_4);
+-         _4 = ();
+-         _3 = Box::<()>::new(move _4) -> [return: bb1, unwind continue];
++         _4 = const ();
++         _3 = Box::<()>::new(const ()) -> [return: bb1, unwind continue];
       }
   
       bb1: {
+          StorageDead(_4);
           _2 = &_3;
-          _1 = copy _2;
-          StorageDead(_2);
-          StorageLive(_4);
-          _11 = copy ((_3.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>);
-          _9 = copy _11 as *const () (Transmute);
-          _4 = copy _9;
+          _1 = &(*_2);
+-         StorageDead(_2);
 -         StorageLive(_5);
+-         _10 = copy (*_1);
 +         nop;
-          StorageLive(_6);
--         _6 = copy _4;
-+         _6 = copy _9;
-          StorageLive(_10);
-          _10 = const 1_usize;
--         _5 = *const [()] from (copy _6, copy _10);
-+         _5 = *const [()] from (copy _9, const 1_usize);
-          StorageDead(_10);
-          StorageDead(_6);
++         nop;
++         _10 = copy (*_2);
+          _11 = copy ((_10.0: std::ptr::Unique<()>).0: std::ptr::NonNull<()>) as *const () (Transmute);
+          _5 = &raw const (*_11);
+-         StorageLive(_6);
++         nop;
           StorageLive(_7);
-          StorageLive(_8);
-          _8 = copy _5;
--         _7 = copy _8 as *mut () (PtrToPtr);
-+         _7 = copy _11 as *mut () (Transmute);
-          StorageDead(_8);
+          _7 = copy _5;
+          StorageLive(_12);
+          _12 = const 1_usize;
+-         _6 = *const [()] from (copy _7, copy _12);
++         _6 = *const [()] from (copy _5, const 1_usize);
+          StorageDead(_12);
           StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          _9 = copy _6;
+          StorageLive(_13);
+-         _13 = copy _9;
+-         _8 = copy _9 as *mut () (PtrToPtr);
++         _13 = copy _6;
++         _8 = copy _5 as *mut () (PtrToPtr);
+          StorageDead(_13);
+          StorageDead(_9);
+          _0 = const ();
+          StorageDead(_8);
+-         StorageDead(_6);
 -         StorageDead(_5);
 +         nop;
-          StorageDead(_4);
++         nop;
           drop(_3) -> [return: bb2, unwind: bb3];
       }
   
diff --git a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.rs b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.rs
new file mode 100644
index 0000000..7b742b9
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -O
+
+#![crate_type = "lib"]
+
+// EMIT_MIR two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff
+// EMIT_MIR two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir
+pub fn two_unwrap_unchecked(v: &Option<i32>) -> i32 {
+    // CHECK-LABEL: fn two_unwrap_unchecked(
+    // CHECK: [[DEREF_V:_.*]] = copy (*_1);
+    // CHECK: [[V1V2:_.*]] = copy (([[DEREF_V]] as Some).0: i32);
+    // CHECK: _0 = Add(copy [[V1V2]], copy [[V1V2]]);
+    let v1 = unsafe { v.unwrap_unchecked() };
+    let v2 = unsafe { v.unwrap_unchecked() };
+    v1 + v2
+}
diff --git a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff
new file mode 100644
index 0000000..5b063e6
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.GVN.diff
@@ -0,0 +1,105 @@
+- // MIR for `two_unwrap_unchecked` before GVN
++ // MIR for `two_unwrap_unchecked` after GVN
+  
+  fn two_unwrap_unchecked(_1: &Option<i32>) -> i32 {
+      debug v => _1;
+      let mut _0: i32;
+      let _2: i32;
+      let mut _3: std::option::Option<i32>;
+      let mut _5: std::option::Option<i32>;
+      let mut _6: i32;
+      let mut _7: i32;
+      scope 1 {
+          debug v1 => _2;
+          let _4: i32;
+          scope 2 {
+              debug v2 => _4;
+          }
+          scope 8 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
+              let mut _9: isize;
+              scope 9 {
+              }
+              scope 10 (inlined #[track_caller] unreachable_unchecked) {
+                  scope 11 (inlined core::ub_checks::check_language_ub) {
+                      scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
+                      }
+                  }
+              }
+          }
+      }
+      scope 3 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
+          let mut _8: isize;
+          scope 4 {
+          }
+          scope 5 (inlined #[track_caller] unreachable_unchecked) {
+              scope 6 (inlined core::ub_checks::check_language_ub) {
+                  scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_2);
+-         StorageLive(_3);
++         nop;
++         nop;
+          _3 = copy (*_1);
+-         StorageLive(_8);
++         nop;
+          _8 = discriminant(_3);
+-         switchInt(move _8) -> [0: bb2, 1: bb3, otherwise: bb1];
++         switchInt(copy _8) -> [0: bb2, 1: bb3, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          unreachable;
+      }
+  
+      bb3: {
+-         _2 = move ((_3 as Some).0: i32);
+-         StorageDead(_8);
+-         StorageDead(_3);
++         _2 = copy ((_3 as Some).0: i32);
++         nop;
++         nop;
+          StorageLive(_4);
+          StorageLive(_5);
+-         _5 = copy (*_1);
++         _5 = copy _3;
+          StorageLive(_9);
+-         _9 = discriminant(_5);
+-         switchInt(move _9) -> [0: bb4, 1: bb5, otherwise: bb1];
++         _9 = copy _8;
++         switchInt(copy _8) -> [0: bb4, 1: bb5, otherwise: bb1];
+      }
+  
+      bb4: {
+          unreachable;
+      }
+  
+      bb5: {
+-         _4 = move ((_5 as Some).0: i32);
++         _4 = copy _2;
+          StorageDead(_9);
+          StorageDead(_5);
+          StorageLive(_6);
+          _6 = copy _2;
+          StorageLive(_7);
+-         _7 = copy _4;
+-         _0 = Add(move _6, move _7);
++         _7 = copy _2;
++         _0 = Add(copy _2, copy _2);
+          StorageDead(_7);
+          StorageDead(_6);
+          StorageDead(_4);
+-         StorageDead(_2);
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir
new file mode 100644
index 0000000..b2b7f88
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/two_unwrap_unchecked.two_unwrap_unchecked.PreCodegen.after.mir
@@ -0,0 +1,51 @@
+// MIR for `two_unwrap_unchecked` after PreCodegen
+
+fn two_unwrap_unchecked(_1: &Option<i32>) -> i32 {
+    debug v => _1;
+    let mut _0: i32;
+    let mut _2: std::option::Option<i32>;
+    let _4: i32;
+    scope 1 {
+        debug v1 => _4;
+        scope 2 {
+            debug v2 => _4;
+        }
+        scope 8 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
+            scope 9 {
+            }
+            scope 10 (inlined #[track_caller] unreachable_unchecked) {
+                scope 11 (inlined core::ub_checks::check_language_ub) {
+                    scope 12 (inlined core::ub_checks::check_language_ub::runtime) {
+                    }
+                }
+            }
+        }
+    }
+    scope 3 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
+        let mut _3: isize;
+        scope 4 {
+        }
+        scope 5 (inlined #[track_caller] unreachable_unchecked) {
+            scope 6 (inlined core::ub_checks::check_language_ub) {
+                scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
+                }
+            }
+        }
+    }
+
+    bb0: {
+        _2 = copy (*_1);
+        _3 = discriminant(_2);
+        switchInt(copy _3) -> [0: bb2, 1: bb1, otherwise: bb2];
+    }
+
+    bb1: {
+        _4 = copy ((_2 as Some).0: i32);
+        _0 = Add(copy _4, copy _4);
+        return;
+    }
+
+    bb2: {
+        unreachable;
+    }
+}
diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-abort.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-abort.diff
deleted file mode 100644
index c3076fb..0000000
--- a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-abort.diff
+++ /dev/null
@@ -1,21 +0,0 @@
-- // MIR for `main` before SimplifyConstCondition-after-const-prop
-+ // MIR for `main` after SimplifyConstCondition-after-const-prop
-  
-  fn main() -> () {
-      let mut _0: ();
-      let _1: ();
-  
-      bb0: {
--         switchInt(const false) -> [0: bb2, otherwise: bb1];
-+         goto -> bb2;
-      }
-  
-      bb1: {
-          _1 = noop() -> [return: bb2, unwind unreachable];
-      }
-  
-      bb2: {
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff
deleted file mode 100644
index 6c346e2..0000000
--- a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff
+++ /dev/null
@@ -1,21 +0,0 @@
-- // MIR for `main` before SimplifyConstCondition-after-const-prop
-+ // MIR for `main` after SimplifyConstCondition-after-const-prop
-  
-  fn main() -> () {
-      let mut _0: ();
-      let _1: ();
-  
-      bb0: {
--         switchInt(const false) -> [0: bb2, otherwise: bb1];
-+         goto -> bb2;
-      }
-  
-      bb1: {
-          _1 = noop() -> [return: bb2, unwind continue];
-      }
-  
-      bb2: {
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-abort.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-abort.diff
new file mode 100644
index 0000000..c67fd69
--- /dev/null
+++ b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-abort.diff
@@ -0,0 +1,25 @@
+- // MIR for `main` before SimplifyConstCondition-after-inst-simplify
++ // MIR for `main` after SimplifyConstCondition-after-inst-simplify
+  
+  fn main() -> () {
+      let mut _0: ();
+      let mut _1: bool;
+      let _2: ();
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const false;
+-         switchInt(move _1) -> [0: bb2, otherwise: bb1];
++         goto -> bb2;
+      }
+  
+      bb1: {
+          _2 = noop() -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-unwind.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-unwind.diff
new file mode 100644
index 0000000..07f179d
--- /dev/null
+++ b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-inst-simplify.panic-unwind.diff
@@ -0,0 +1,25 @@
+- // MIR for `main` before SimplifyConstCondition-after-inst-simplify
++ // MIR for `main` after SimplifyConstCondition-after-inst-simplify
+  
+  fn main() -> () {
+      let mut _0: ();
+      let mut _1: bool;
+      let _2: ();
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const false;
+-         switchInt(move _1) -> [0: bb2, otherwise: bb1];
++         goto -> bb2;
+      }
+  
+      bb1: {
+          _2 = noop() -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          StorageDead(_1);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/simplify_if.rs b/tests/mir-opt/simplify_if.rs
index f600c05..6aca233 100644
--- a/tests/mir-opt/simplify_if.rs
+++ b/tests/mir-opt/simplify_if.rs
@@ -2,7 +2,7 @@
 #[inline(never)]
 fn noop() {}
 
-// EMIT_MIR simplify_if.main.SimplifyConstCondition-after-const-prop.diff
+// EMIT_MIR simplify_if.main.SimplifyConstCondition-after-inst-simplify.diff
 fn main() {
     // CHECK-LABEL: fn main(
 
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index 70ab3fb..f0d2c10 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -9,17 +9,16 @@
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
-error: malformed `cfg_attr` attribute input
+error[E0539]: malformed `cfg_attr` attribute input
   --> $DIR/malformed-attrs.rs:103:1
    |
 LL | #[cfg_attr]
    | ^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
-help: missing condition and attribute
-   |
-LL | #[cfg_attr(condition, attribute, other_attribute, ...)]
-   |           ++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0463]: can't find crate for `wloop`
   --> $DIR/malformed-attrs.rs:209:1
diff --git a/tests/ui/binop/let-chain-type-issue-147665.rs b/tests/ui/binop/let-chain-type-issue-147665.rs
new file mode 100644
index 0000000..4a6b40c
--- /dev/null
+++ b/tests/ui/binop/let-chain-type-issue-147665.rs
@@ -0,0 +1,7 @@
+// Shouldn't highlight `let x = 1` as having type bool.
+//@ edition:2024
+
+fn main() {
+    if let x = 1 && 2 {}
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/binop/let-chain-type-issue-147665.stderr b/tests/ui/binop/let-chain-type-issue-147665.stderr
new file mode 100644
index 0000000..b2b8222
--- /dev/null
+++ b/tests/ui/binop/let-chain-type-issue-147665.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/let-chain-type-issue-147665.rs:5:21
+   |
+LL |     if let x = 1 && 2 {}
+   |                     ^ expected `bool`, found integer
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/cfg/cfg-path-error.rs b/tests/ui/cfg/cfg-path-error.rs
index 9db1f19..f22e6be 100644
--- a/tests/ui/cfg/cfg-path-error.rs
+++ b/tests/ui/cfg/cfg-path-error.rs
@@ -3,19 +3,27 @@
 #![allow(unexpected_cfgs)] // invalid cfgs
 
 #[cfg(any(foo, foo::bar))]
-//~^ERROR `cfg` predicate key must be an identifier
+//~^ ERROR malformed `cfg` attribute input
+//~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 fn foo1() {}
 
 #[cfg(any(foo::bar, foo))]
-//~^ERROR `cfg` predicate key must be an identifier
+//~^ ERROR malformed `cfg` attribute input
+//~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 fn foo2() {}
 
 #[cfg(all(foo, foo::bar))]
-//~^ERROR `cfg` predicate key must be an identifier
+//~^ ERROR malformed `cfg` attribute input
+//~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 fn foo3() {}
 
 #[cfg(all(foo::bar, foo))]
-//~^ERROR `cfg` predicate key must be an identifier
+//~^ ERROR malformed `cfg` attribute input
+//~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 fn foo4() {}
 
 fn main() {}
diff --git a/tests/ui/cfg/cfg-path-error.stderr b/tests/ui/cfg/cfg-path-error.stderr
index 4f68fa3..bb9b703 100644
--- a/tests/ui/cfg/cfg-path-error.stderr
+++ b/tests/ui/cfg/cfg-path-error.stderr
@@ -1,26 +1,47 @@
-error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-path-error.rs:5:16
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-path-error.rs:5:1
    |
 LL | #[cfg(any(foo, foo::bar))]
-   |                ^^^^^^^^
+   | ^^^^^^^^^^^^^^^--------^^^
+   | |              |
+   | |              expected a valid identifier here
+   | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
-error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-path-error.rs:9:11
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-path-error.rs:11:1
    |
 LL | #[cfg(any(foo::bar, foo))]
-   |           ^^^^^^^^
+   | ^^^^^^^^^^--------^^^^^^^^
+   | |         |
+   | |         expected a valid identifier here
+   | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
-error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-path-error.rs:13:16
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-path-error.rs:17:1
    |
 LL | #[cfg(all(foo, foo::bar))]
-   |                ^^^^^^^^
+   | ^^^^^^^^^^^^^^^--------^^^
+   | |              |
+   | |              expected a valid identifier here
+   | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
-error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-path-error.rs:17:11
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-path-error.rs:23:1
    |
 LL | #[cfg(all(foo::bar, foo))]
-   |           ^^^^^^^^
+   | ^^^^^^^^^^--------^^^^^^^^
+   | |         |
+   | |         expected a valid identifier here
+   | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/cfg/cfg-target-compact-errors.rs b/tests/ui/cfg/cfg-target-compact-errors.rs
index cfb19c5..1ce6833 100644
--- a/tests/ui/cfg/cfg-target-compact-errors.rs
+++ b/tests/ui/cfg/cfg-target-compact-errors.rs
@@ -19,7 +19,7 @@ fn three() {}
 fn four() {}
 
 #[cfg(target(clippy::os = "linux"))]
-//~^ ERROR `cfg` predicate key must be an identifier
+//~^ ERROR malformed `cfg` attribute input
 fn five() {}
 
 fn main() {}
diff --git a/tests/ui/cfg/cfg-target-compact-errors.stderr b/tests/ui/cfg/cfg-target-compact-errors.stderr
index cf61f94..3ca1b73 100644
--- a/tests/ui/cfg/cfg-target-compact-errors.stderr
+++ b/tests/ui/cfg/cfg-target-compact-errors.stderr
@@ -42,11 +42,16 @@
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
-error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-target-compact-errors.rs:21:14
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-target-compact-errors.rs:21:1
    |
 LL | #[cfg(target(clippy::os = "linux"))]
-   |              ^^^^^^^^^^
+   | ^^^^^^^^^^^^^----------^^^^^^^^^^^^^
+   | |            |
+   | |            expected a valid identifier here
+   | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/conditional-compilation/cfg-attr-parse.stderr b/tests/ui/conditional-compilation/cfg-attr-parse.stderr
index 76f199c..b08915e 100644
--- a/tests/ui/conditional-compilation/cfg-attr-parse.stderr
+++ b/tests/ui/conditional-compilation/cfg-attr-parse.stderr
@@ -1,49 +1,56 @@
-error: malformed `cfg_attr` attribute input
+error[E0539]: malformed `cfg_attr` attribute input
   --> $DIR/cfg-attr-parse.rs:4:1
    |
 LL | #[cfg_attr()]
-   | ^^^^^^^^^^^^^
+   | ^^^^^^^^^^--^
+   | |         |
+   | |         expected at least 1 argument here
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
-help: missing condition and attribute
-   |
-LL | #[cfg_attr(condition, attribute, other_attribute, ...)]
-   |            ++++++++++++++++++++++++++++++++++++++++++
 
 error: expected `,`, found end of `cfg_attr` input
   --> $DIR/cfg-attr-parse.rs:8:17
    |
 LL | #[cfg_attr(all())]
-   |                 ^ expected `,`
+   | ----------------^-
+   | |               |
+   | |               expected `,`
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
-   = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 error: expected identifier, found `,`
   --> $DIR/cfg-attr-parse.rs:16:18
    |
 LL | #[cfg_attr(all(),,)]
-   |                  ^ expected identifier
+   | -----------------^--
+   | |                |
+   | |                expected identifier
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
-   = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 error: expected identifier, found `,`
   --> $DIR/cfg-attr-parse.rs:28:28
    |
 LL | #[cfg_attr(all(), must_use,,)]
-   |                            ^ expected identifier
+   | ---------------------------^--
+   | |                          |
+   | |                          expected identifier
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
-   = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 error: expected identifier, found `,`
   --> $DIR/cfg-attr-parse.rs:40:40
    |
 LL | #[cfg_attr(all(), must_use, deprecated,,)]
-   |                                        ^ expected identifier
+   | ---------------------------------------^--
+   | |                                      |
+   | |                                      expected identifier
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
-   = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 error: wrong `cfg_attr` delimiters
@@ -62,9 +69,11 @@
   --> $DIR/cfg-attr-parse.rs:44:18
    |
 LL | #[cfg_attr[all(),,]]
-   |                  ^ expected identifier
+   | -----------------^--
+   | |                |
+   | |                expected identifier
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
-   = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 error: wrong `cfg_attr` delimiters
@@ -83,10 +92,13 @@
   --> $DIR/cfg-attr-parse.rs:50:18
    |
 LL | #[cfg_attr{all(),,}]
-   |                  ^ expected identifier
+   | -----------------^--
+   | |                |
+   | |                expected identifier
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
-   = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 error: aborting due to 9 previous errors
 
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
index 2c84a96..7d4fd20 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
@@ -22,10 +22,16 @@
 //~| NOTE for more information, visit
 struct S4;
 
-#[cfg("str")] //~ ERROR `cfg` predicate key must be an identifier
+#[cfg("str")]
+//~^ ERROR malformed `cfg` attribute input
+//~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 struct S5;
 
-#[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier
+#[cfg(a::b)]
+//~^ ERROR malformed `cfg` attribute input
+//~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 struct S6;
 
 #[cfg(a())] //~ ERROR invalid predicate `a`
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
index 59ff611..e73b20f 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
@@ -42,26 +42,36 @@
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
-error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-attr-syntax-validation.rs:25:7
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-attr-syntax-validation.rs:25:1
    |
 LL | #[cfg("str")]
-   |       ^^^^^
+   | ^^^^^^-----^^
+   | |     |
+   | |     expected a valid identifier here
+   | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
-error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-attr-syntax-validation.rs:28:7
+error[E0539]: malformed `cfg` attribute input
+  --> $DIR/cfg-attr-syntax-validation.rs:31:1
    |
 LL | #[cfg(a::b)]
-   |       ^^^^
+   | ^^^^^^----^^
+   | |     |
+   | |     expected a valid identifier here
+   | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error[E0537]: invalid predicate `a`
-  --> $DIR/cfg-attr-syntax-validation.rs:31:7
+  --> $DIR/cfg-attr-syntax-validation.rs:37:7
    |
 LL | #[cfg(a())]
    |       ^^^
 
 error[E0539]: malformed `cfg` attribute input
-  --> $DIR/cfg-attr-syntax-validation.rs:34:1
+  --> $DIR/cfg-attr-syntax-validation.rs:40:1
    |
 LL | #[cfg(a = 10)]
    | ^^^^^^^^^^--^^
@@ -72,7 +82,7 @@
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error[E0539]: malformed `cfg` attribute input
-  --> $DIR/cfg-attr-syntax-validation.rs:39:1
+  --> $DIR/cfg-attr-syntax-validation.rs:45:1
    |
 LL | #[cfg(a = b"hi")]
    | ^^^^^^^^^^-^^^^^^
@@ -82,7 +92,7 @@
    = note: expected a normal string literal, not a byte string literal
 
 error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable
-  --> $DIR/cfg-attr-syntax-validation.rs:45:25
+  --> $DIR/cfg-attr-syntax-validation.rs:51:25
    |
 LL |         #[cfg(feature = $expr)]
    |                         ^^^^^
diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs
new file mode 100644
index 0000000..c08762d
--- /dev/null
+++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs
@@ -0,0 +1,50 @@
+#[cfg_attr]
+//~^ ERROR malformed `cfg_attr` attribute
+struct S1;
+
+#[cfg_attr = 10]
+//~^ ERROR malformed `cfg_attr` attribute
+struct S2;
+
+#[cfg_attr()]
+//~^ ERROR malformed `cfg_attr` attribute
+struct S3;
+
+#[cfg_attr("str")] //~ ERROR malformed `cfg_attr` attribute input
+struct S5;
+
+#[cfg_attr(a::b)] //~ ERROR malformed `cfg_attr` attribute input
+struct S6;
+
+#[cfg_attr(a())] //~ ERROR invalid predicate `a`
+struct S7;
+
+#[cfg_attr(a = 10)] //~ ERROR malformed `cfg_attr` attribute input
+struct S8;
+
+#[cfg_attr(a = b"hi")]  //~ ERROR malformed `cfg_attr` attribute input
+struct S9;
+
+macro_rules! generate_s10 {
+    ($expr: expr) => {
+        #[cfg_attr(feature = $expr)]
+        //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable
+        struct S10;
+    }
+}
+
+generate_s10!(concat!("nonexistent"));
+
+#[cfg_attr(true)] //~ ERROR expected `,`, found end of `cfg_attr` input
+struct S11;
+
+#[cfg_attr(true, unknown_attribute)] //~ ERROR cannot find attribute `unknown_attribute` in this scope
+struct S12;
+
+#[cfg_attr(true, link_section)] //~ ERROR malformed `link_section` attribute input
+struct S13;
+
+#[cfg_attr(true, inline())] //~ ERROR malformed `inline` attribute input
+fn f1() {}
+
+fn main() {}
diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr
new file mode 100644
index 0000000..99117af
--- /dev/null
+++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr
@@ -0,0 +1,144 @@
+error[E0539]: malformed `cfg_attr` attribute input
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:1:1
+   |
+LL | #[cfg_attr]
+   | ^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+error[E0539]: malformed `cfg_attr` attribute input
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:5:1
+   |
+LL | #[cfg_attr = 10]
+   | ^^^^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+error[E0539]: malformed `cfg_attr` attribute input
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:9:1
+   |
+LL | #[cfg_attr()]
+   | ^^^^^^^^^^--^
+   | |         |
+   | |         expected at least 1 argument here
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+error[E0539]: malformed `cfg_attr` attribute input
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:13:1
+   |
+LL | #[cfg_attr("str")]
+   | ^^^^^^^^^^^-----^^
+   | |          |
+   | |          expected a valid identifier here
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+error[E0539]: malformed `cfg_attr` attribute input
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:16:1
+   |
+LL | #[cfg_attr(a::b)]
+   | ^^^^^^^^^^^----^^
+   | |          |
+   | |          expected a valid identifier here
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+error[E0537]: invalid predicate `a`
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:19:12
+   |
+LL | #[cfg_attr(a())]
+   |            ^^^
+
+error[E0539]: malformed `cfg_attr` attribute input
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:22:1
+   |
+LL | #[cfg_attr(a = 10)]
+   | ^^^^^^^^^^^^^^^--^^
+   | |              |
+   | |              expected a string literal here
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+error[E0539]: malformed `cfg_attr` attribute input
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:25:1
+   |
+LL | #[cfg_attr(a = b"hi")]
+   | ^^^^^^^^^^^^^^^-^^^^^^
+   |                |
+   |                help: consider removing the prefix
+   |
+   = note: expected a normal string literal, not a byte string literal
+
+error: expected `,`, found end of `cfg_attr` input
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:38:16
+   |
+LL | #[cfg_attr(true)]
+   | ---------------^-
+   | |              |
+   | |              expected `,`
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:30:30
+   |
+LL |         #[cfg_attr(feature = $expr)]
+   |         ---------------------^^^^^-- help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
+...
+LL | generate_s10!(concat!("nonexistent"));
+   | ------------------------------------- in this macro invocation
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+   = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot find attribute `unknown_attribute` in this scope
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:41:18
+   |
+LL | #[cfg_attr(true, unknown_attribute)]
+   |                  ^^^^^^^^^^^^^^^^^
+
+error[E0539]: malformed `link_section` attribute input
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:44:18
+   |
+LL | #[cfg_attr(true, link_section)]
+   |                  ^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute>
+
+error[E0805]: malformed `inline` attribute input
+  --> $DIR/cfg_attr-attr-syntax-validation.rs:47:18
+   |
+LL | #[cfg_attr(true, inline())]
+   |                  ^^^^^^--
+   |                        |
+   |                        expected a single argument here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[cfg_attr(true, inline())]
+LL + #[cfg_attr(true, #[inline(always)])]
+   |
+LL - #[cfg_attr(true, inline())]
+LL + #[cfg_attr(true, #[inline(never)])]
+   |
+LL - #[cfg_attr(true, inline())]
+LL + #[cfg_attr(true, #[inline])]
+   |
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0537, E0539, E0805.
+For more information about an error, try `rustc --explain E0537`.
diff --git a/tests/ui/consts/precise-drop-nested-deref-ice.rs b/tests/ui/consts/precise-drop-nested-deref-ice.rs
new file mode 100644
index 0000000..3ac5bea
--- /dev/null
+++ b/tests/ui/consts/precise-drop-nested-deref-ice.rs
@@ -0,0 +1,15 @@
+//! Tests that multiple derefs in a projection does not cause an ICE
+//! when checking const precise drops.
+//!
+//! Regression test for <https://github.com/rust-lang/rust/issues/147733>
+
+#![feature(const_precise_live_drops)]
+struct Foo(u32);
+impl Foo {
+    const fn get(self: Box<&Self>, f: &u32) -> u32 {
+        //~^ ERROR destructor of `Box<&Foo>` cannot be evaluated at compile-time
+        self.0
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/consts/precise-drop-nested-deref-ice.stderr b/tests/ui/consts/precise-drop-nested-deref-ice.stderr
new file mode 100644
index 0000000..4e5af10
--- /dev/null
+++ b/tests/ui/consts/precise-drop-nested-deref-ice.stderr
@@ -0,0 +1,12 @@
+error[E0493]: destructor of `Box<&Foo>` cannot be evaluated at compile-time
+  --> $DIR/precise-drop-nested-deref-ice.rs:9:18
+   |
+LL |     const fn get(self: Box<&Self>, f: &u32) -> u32 {
+   |                  ^^^^ the destructor for this type cannot be evaluated in constant functions
+...
+LL |     }
+   |     - value is dropped here
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr
index c1ae42b..9f65e4f 100644
--- a/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr
+++ b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr
@@ -1,17 +1,17 @@
 error[E0080]: evaluation panicked: explicit panic
-  --> $DIR/collect-in-promoted-const.rs:11:19
+  --> $DIR/collect-in-promoted-const.rs:9:19
    |
 LL |     const C: () = panic!();
    |                   ^^^^^^^^ evaluation of `Fail::<i32>::C` failed here
 
 note: erroneous constant encountered
-  --> $DIR/collect-in-promoted-const.rs:22:21
+  --> $DIR/collect-in-promoted-const.rs:17:21
    |
 LL |         let _val = &Fail::<T>::C;
    |                     ^^^^^^^^^^^^
 
 note: the above error was encountered while instantiating `fn f::<i32>`
-  --> $DIR/collect-in-promoted-const.rs:27:5
+  --> $DIR/collect-in-promoted-const.rs:22:5
    |
 LL |     f::<i32>();
    |     ^^^^^^^^^^
diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr
index 0d7ac48..9f65e4f 100644
--- a/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr
+++ b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr
@@ -1,35 +1,21 @@
 error[E0080]: evaluation panicked: explicit panic
-  --> $DIR/collect-in-promoted-const.rs:11:19
-   |
-LL |     const C: () = panic!();
-   |                   ^^^^^^^^ evaluation of `Fail::<T>::C` failed here
-
-note: erroneous constant encountered
-  --> $DIR/collect-in-promoted-const.rs:22:21
-   |
-LL |         let _val = &Fail::<T>::C;
-   |                     ^^^^^^^^^^^^
-
-error[E0080]: evaluation panicked: explicit panic
-  --> $DIR/collect-in-promoted-const.rs:11:19
+  --> $DIR/collect-in-promoted-const.rs:9:19
    |
 LL |     const C: () = panic!();
    |                   ^^^^^^^^ evaluation of `Fail::<i32>::C` failed here
 
 note: erroneous constant encountered
-  --> $DIR/collect-in-promoted-const.rs:22:21
+  --> $DIR/collect-in-promoted-const.rs:17:21
    |
 LL |         let _val = &Fail::<T>::C;
    |                     ^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 note: the above error was encountered while instantiating `fn f::<i32>`
-  --> $DIR/collect-in-promoted-const.rs:27:5
+  --> $DIR/collect-in-promoted-const.rs:22:5
    |
 LL |     f::<i32>();
    |     ^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.rs b/tests/ui/consts/required-consts/collect-in-promoted-const.rs
index 498328a..c475720 100644
--- a/tests/ui/consts/required-consts/collect-in-promoted-const.rs
+++ b/tests/ui/consts/required-consts/collect-in-promoted-const.rs
@@ -1,17 +1,12 @@
 //@revisions: noopt opt
 //@ build-fail
 //@[noopt] compile-flags: -Copt-level=0
-// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo=0
-//@[opt] compile-flags: -C debuginfo=0
 //@[opt] compile-flags: -O
 //! Make sure we error on erroneous consts even if they get promoted.
 
 struct Fail<T>(T);
 impl<T> Fail<T> {
     const C: () = panic!(); //~ERROR evaluation panicked: explicit panic
-    //[opt]~^ ERROR evaluation panicked: explicit panic
-    // (Not sure why optimizations lead to this being emitted twice, but as long as compilation
-    // fails either way it's fine.)
 }
 
 #[inline(never)]
diff --git a/tests/ui/consts/zst_no_llvm_alloc.rs b/tests/ui/consts/zst_no_llvm_alloc.rs
index 1e92e3b..ec5600a 100644
--- a/tests/ui/consts/zst_no_llvm_alloc.rs
+++ b/tests/ui/consts/zst_no_llvm_alloc.rs
@@ -1,10 +1,21 @@
 //@ run-pass
 
+// We need some non-1 alignment to test we use the alignment of the type in the compiler.
 #[repr(align(4))]
 struct Foo;
 
 static FOO: Foo = Foo;
 
+// This tests for regression of https://github.com/rust-lang/rust/issues/147516
+//
+// The compiler will codegen `&Zst` without creating a real allocation, just a properly aligned
+// `usize` (i.e., ptr::dangling). However, code can add an arbitrary offset from that base
+// allocation. We confirm here that we correctly codegen that offset combined with the necessary
+// alignment of the base &() as a 1-ZST and &Foo as a 4-ZST.
+const A: *const () = (&() as *const ()).wrapping_byte_add(2);
+const B: *const () = (&Foo as *const _ as *const ()).wrapping_byte_add(usize::MAX);
+const C: *const () = (&Foo as *const _ as *const ()).wrapping_byte_add(2);
+
 fn main() {
     // There's no stable guarantee that these are true.
     // However, we want them to be true so that our LLVM IR and runtime are a bit faster:
@@ -15,6 +26,13 @@ fn main() {
     let x: &'static Foo = &Foo;
     assert_eq!(x as *const Foo as usize, 4);
 
+    // * A 1-aligned ZST (1-ZST) is placed at 0x1. Then offsetting that by 2 results in 3.
+    // * Foo is a 4-aligned ZST, so is placed at 0x4. +2 = 6
+    // * Foo is a 4-aligned ZST, so is placed at 0x4. +usize::MAX = -1 (same bit pattern) = 3
+    assert_eq!(A.addr(), 3);
+    assert_eq!(B.addr(), 3);
+    assert_eq!(C.addr(), 6);
+
     // The exact addresses returned by these library functions are not necessarily stable guarantees
     // but for now we assert that we're still matching.
     #[allow(dangling_pointers_from_temporaries)]
diff --git a/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs b/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs
new file mode 100644
index 0000000..d234acb
--- /dev/null
+++ b/tests/ui/contracts/contracts-disabled-side-effect-ensures.rs
@@ -0,0 +1,17 @@
+//@ run-pass
+#![feature(contracts)]
+//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+extern crate core;
+use core::contracts::ensures;
+
+#[ensures({*x = 0; |_ret| true})]
+fn buggy_add(x: &mut u32, y: u32) {
+    *x = *x + y;
+}
+
+fn main() {
+    let mut x = 10;
+    buggy_add(&mut x, 100);
+    assert_eq!(x, 110);
+}
diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.unchk_fail_post.stderr b/tests/ui/contracts/contracts-disabled-side-effect-ensures.stderr
similarity index 76%
rename from tests/ui/contracts/internal_machinery/contract-lang-items.unchk_fail_post.stderr
rename to tests/ui/contracts/contracts-disabled-side-effect-ensures.stderr
index a60ce16..dd9ebe9 100644
--- a/tests/ui/contracts/internal_machinery/contract-lang-items.unchk_fail_post.stderr
+++ b/tests/ui/contracts/contracts-disabled-side-effect-ensures.stderr
@@ -1,7 +1,7 @@
 warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/contract-lang-items.rs:15:12
+  --> $DIR/contracts-disabled-side-effect-ensures.rs:2:12
    |
-LL | #![feature(contracts)] // to access core::contracts
+LL | #![feature(contracts)]
    |            ^^^^^^^^^
    |
    = note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
diff --git a/tests/ui/contracts/cross-crate-checks/auxiliary/id.rs b/tests/ui/contracts/cross-crate-checks/auxiliary/id.rs
new file mode 100644
index 0000000..c621037
--- /dev/null
+++ b/tests/ui/contracts/cross-crate-checks/auxiliary/id.rs
@@ -0,0 +1,16 @@
+//@ [unchk_pass] compile-flags: -Zcontract-checks=no
+//@ [unchk_fail] compile-flags: -Zcontract-checks=yes
+//@ [chk_pass] compile-flags: -Zcontract-checks=no
+//@ [chk_fail] compile-flags: -Zcontract-checks=yes
+
+#![crate_type = "lib"]
+#![feature(contracts)]
+
+extern crate core;
+use core::contracts::requires;
+
+/// Example function with a spec to be called across a crate boundary.
+#[requires(x > 0)]
+pub fn id_if_positive(x: u32) -> u32 {
+    x
+}
diff --git a/tests/ui/contracts/cross-crate-checks/cross-crate.rs b/tests/ui/contracts/cross-crate-checks/cross-crate.rs
new file mode 100644
index 0000000..43f81fe
--- /dev/null
+++ b/tests/ui/contracts/cross-crate-checks/cross-crate.rs
@@ -0,0 +1,26 @@
+//@ aux-build:id.rs
+//@ revisions: unchk_pass unchk_fail chk_pass chk_fail
+//
+// The dependency crate `id` can be compiled with runtime contract checking
+// enabled independently of whether this crate is compiled with contract checks
+// or not.
+//
+// chk/unchk indicates whether this crate is compiled with contracts or not
+// and pass/fail indicates whether the `id` crate is compiled with contract checks.
+//
+//@ [unchk_pass] run-pass
+//@ [unchk_fail] run-crash
+//@ [chk_pass] run-pass
+//@ [chk_fail] run-crash
+//
+//
+//@ [unchk_pass] compile-flags: -Zcontract-checks=no
+//@ [unchk_fail] compile-flags: -Zcontract-checks=no
+//@ [chk_pass] compile-flags: -Zcontract-checks=yes
+//@ [chk_fail] compile-flags: -Zcontract-checks=yes
+
+extern crate id;
+
+fn main() {
+    id::id_if_positive(0);
+}
diff --git a/tests/ui/contracts/empty-ensures.rs b/tests/ui/contracts/empty-ensures.rs
new file mode 100644
index 0000000..d897f27
--- /dev/null
+++ b/tests/ui/contracts/empty-ensures.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -Zcontract-checks=yes
+#![feature(contracts)]
+//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+extern crate core;
+use core::contracts::ensures;
+
+#[ensures()]
+//~^ ERROR expected a `Fn(&_)` closure, found `()` [E0277]
+fn foo(x: u32) -> u32 {
+    x * 2
+}
+
+fn main() {
+    foo(1);
+}
diff --git a/tests/ui/contracts/empty-ensures.stderr b/tests/ui/contracts/empty-ensures.stderr
new file mode 100644
index 0000000..407a253
--- /dev/null
+++ b/tests/ui/contracts/empty-ensures.stderr
@@ -0,0 +1,25 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/empty-ensures.rs:2:12
+   |
+LL | #![feature(contracts)]
+   |            ^^^^^^^^^
+   |
+   = note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: expected a `Fn(&_)` closure, found `()`
+  --> $DIR/empty-ensures.rs:8:1
+   |
+LL | #[ensures()]
+   | ^^^^^^^^^^^^
+   | |
+   | expected an `Fn(&_)` closure, found `()`
+   | required by a bound introduced by this call
+   |
+   = help: the trait `for<'a> Fn(&'a _)` is not implemented for `()`
+note: required by a bound in `build_check_ensures`
+  --> $SRC_DIR/core/src/contracts.rs:LL:COL
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/contracts/empty-requires.rs b/tests/ui/contracts/empty-requires.rs
new file mode 100644
index 0000000..e3c72dc
--- /dev/null
+++ b/tests/ui/contracts/empty-requires.rs
@@ -0,0 +1,18 @@
+//@ dont-require-annotations: NOTE
+//@ compile-flags: -Zcontract-checks=yes
+#![feature(contracts)]
+//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+extern crate core;
+use core::contracts::requires;
+
+#[requires()]
+//~^ ERROR mismatched types [E0308]
+//~| NOTE expected `bool`, found `()`
+fn foo(x: u32) -> u32 {
+    x * 2
+}
+
+fn main() {
+    foo(1);
+}
diff --git a/tests/ui/contracts/empty-requires.stderr b/tests/ui/contracts/empty-requires.stderr
new file mode 100644
index 0000000..b48e547
--- /dev/null
+++ b/tests/ui/contracts/empty-requires.stderr
@@ -0,0 +1,18 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/empty-requires.rs:3:12
+   |
+LL | #![feature(contracts)]
+   |            ^^^^^^^^^
+   |
+   = note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/empty-requires.rs:9:1
+   |
+LL | #[requires()]
+   | ^^^^^^^^^^^^^ expected `bool`, found `()`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs
index 6e613b5..9dd5167 100644
--- a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs
+++ b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs
@@ -1,36 +1,23 @@
-//@ revisions: default unchk_pass chk_pass chk_fail_ensures chk_fail_requires
+//@ revisions: default chk_fail_ensures chk_fail_requires
 //
 //@ [default] run-pass
-//@ [unchk_pass] run-pass
-//@ [chk_pass] run-pass
 //@ [chk_fail_requires] run-crash
 //@ [chk_fail_ensures] run-crash
-//
-//@ [unchk_pass] compile-flags: -Zcontract-checks=no
-//@ [chk_pass] compile-flags: -Zcontract-checks=yes
-//@ [chk_fail_requires] compile-flags: -Zcontract-checks=yes
-//@ [chk_fail_ensures] compile-flags: -Zcontract-checks=yes
-#![feature(cfg_contract_checks, contracts_internals, core_intrinsics)]
+#![feature(contracts_internals, core_intrinsics)]
 
 fn main() {
-    #[cfg(any(default, unchk_pass))] // default: disabled
-    assert_eq!(core::intrinsics::contract_checks(), false);
-
-    #[cfg(chk_pass)] // explicitly enabled
-    assert_eq!(core::intrinsics::contract_checks(), true);
-
     // always pass
     core::intrinsics::contract_check_requires(|| true);
 
-    // fail if enabled
-    #[cfg(any(default, unchk_pass, chk_fail_requires))]
+    // always fail
+    #[cfg(chk_fail_requires)]
     core::intrinsics::contract_check_requires(|| false);
 
     let doubles_to_two = { let old = 2; move |ret: &u32 | ret + ret == old };
     // Always pass
-    core::intrinsics::contract_check_ensures(doubles_to_two, 1);
+    core::intrinsics::contract_check_ensures(Some(doubles_to_two), 1);
 
-    // Fail if enabled
-    #[cfg(any(default, unchk_pass, chk_fail_ensures))]
-    core::intrinsics::contract_check_ensures(doubles_to_two, 2);
+    // always fail
+    #[cfg(chk_fail_ensures)]
+    core::intrinsics::contract_check_ensures(Some(doubles_to_two), 2);
 }
diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.chk_fail_post.stderr b/tests/ui/contracts/internal_machinery/contract-lang-items.chk_fail_post.stderr
index a60ce16..acce6b1 100644
--- a/tests/ui/contracts/internal_machinery/contract-lang-items.chk_fail_post.stderr
+++ b/tests/ui/contracts/internal_machinery/contract-lang-items.chk_fail_post.stderr
@@ -1,5 +1,5 @@
 warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/contract-lang-items.rs:15:12
+  --> $DIR/contract-lang-items.rs:8:12
    |
 LL | #![feature(contracts)] // to access core::contracts
    |            ^^^^^^^^^
diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.chk_pass.stderr b/tests/ui/contracts/internal_machinery/contract-lang-items.chk_pass.stderr
index a60ce16..acce6b1 100644
--- a/tests/ui/contracts/internal_machinery/contract-lang-items.chk_pass.stderr
+++ b/tests/ui/contracts/internal_machinery/contract-lang-items.chk_pass.stderr
@@ -1,5 +1,5 @@
 warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/contract-lang-items.rs:15:12
+  --> $DIR/contract-lang-items.rs:8:12
    |
 LL | #![feature(contracts)] // to access core::contracts
    |            ^^^^^^^^^
diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.rs b/tests/ui/contracts/internal_machinery/contract-lang-items.rs
index ac72d23..ad88ebf 100644
--- a/tests/ui/contracts/internal_machinery/contract-lang-items.rs
+++ b/tests/ui/contracts/internal_machinery/contract-lang-items.rs
@@ -1,25 +1,16 @@
-//@ revisions: unchk_pass unchk_fail_post chk_pass chk_fail_post
+//@ revisions: unchk_pass chk_pass chk_fail_post
 //
 //@ [unchk_pass] run-pass
-//@ [unchk_fail_post] run-pass
 //@ [chk_pass] run-pass
 //
 //@ [chk_fail_post] run-crash
-//
-//@ [unchk_pass] compile-flags: -Zcontract-checks=no
-//@ [unchk_fail_post] compile-flags: -Zcontract-checks=no
-//
-//@ [chk_pass] compile-flags: -Zcontract-checks=yes
-//@ [chk_fail_post] compile-flags: -Zcontract-checks=yes
 
 #![feature(contracts)] // to access core::contracts
 //~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
 #![feature(contracts_internals)] // to access check_requires lang item
 #![feature(core_intrinsics)]
 fn foo(x: Baz) -> i32 {
-    let injected_checker = {
-        core::contracts::build_check_ensures(|ret| *ret > 100)
-    };
+    let injected_checker =  Some(core::contracts::build_check_ensures(|ret| *ret > 100));
 
     let ret = x.baz + 50;
     core::intrinsics::contract_check_ensures(injected_checker, ret)
@@ -29,11 +20,11 @@ struct Baz { baz: i32 }
 
 
 const BAZ_PASS_PRE_POST: Baz = Baz { baz: 100 };
-#[cfg(any(unchk_fail_post, chk_fail_post))]
+#[cfg(chk_fail_post)]
 const BAZ_FAIL_POST: Baz = Baz { baz: 10 };
 
 fn main() {
     assert_eq!(foo(BAZ_PASS_PRE_POST), 150);
-    #[cfg(any(unchk_fail_post, chk_fail_post))]
+    #[cfg(chk_fail_post)]
     foo(BAZ_FAIL_POST);
 }
diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.unchk_pass.stderr b/tests/ui/contracts/internal_machinery/contract-lang-items.unchk_pass.stderr
index a60ce16..acce6b1 100644
--- a/tests/ui/contracts/internal_machinery/contract-lang-items.unchk_pass.stderr
+++ b/tests/ui/contracts/internal_machinery/contract-lang-items.unchk_pass.stderr
@@ -1,5 +1,5 @@
 warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/contract-lang-items.rs:15:12
+  --> $DIR/contract-lang-items.rs:8:12
    |
 LL | #![feature(contracts)] // to access core::contracts
    |            ^^^^^^^^^
diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs
index 6e5a7a3..48bd376 100644
--- a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs
+++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs
@@ -2,11 +2,9 @@
 
 fn main() {
     // intrinsics are guarded by contracts_internals feature gate.
-    core::intrinsics::contract_checks();
-    //~^ ERROR use of unstable library feature `contracts_internals`
     core::intrinsics::contract_check_requires(|| true);
     //~^ ERROR use of unstable library feature `contracts_internals`
-    core::intrinsics::contract_check_ensures( |_|true, &1);
+    core::intrinsics::contract_check_ensures(Some(|_: &&u32| true), &1);
     //~^ ERROR use of unstable library feature `contracts_internals`
 
     core::contracts::build_check_ensures(|_: &()| true);
diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
index 1e39bd6..c1318fc 100644
--- a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
+++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
@@ -1,5 +1,5 @@
 error[E0658]: contract internal machinery is for internal use only
-  --> $DIR/internal-feature-gating.rs:16:28
+  --> $DIR/internal-feature-gating.rs:14:28
    |
 LL |     fn identity_1() -> i32 contract_requires(|| true) { 10 }
    |                            ^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: contract internal machinery is for internal use only
-  --> $DIR/internal-feature-gating.rs:18:28
+  --> $DIR/internal-feature-gating.rs:16:28
    |
 LL |     fn identity_2() -> i32 contract_ensures(|_| true) { 10 }
    |                            ^^^^^^^^^^^^^^^^
@@ -21,16 +21,6 @@
 error[E0658]: use of unstable library feature `contracts_internals`
   --> $DIR/internal-feature-gating.rs:5:5
    |
-LL |     core::intrinsics::contract_checks();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
-   = help: add `#![feature(contracts_internals)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature `contracts_internals`
-  --> $DIR/internal-feature-gating.rs:7:5
-   |
 LL |     core::intrinsics::contract_check_requires(|| true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -39,9 +29,9 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature `contracts_internals`
-  --> $DIR/internal-feature-gating.rs:9:5
+  --> $DIR/internal-feature-gating.rs:7:5
    |
-LL |     core::intrinsics::contract_check_ensures( |_|true, &1);
+LL |     core::intrinsics::contract_check_ensures(Some(|_: &&u32| true), &1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
@@ -49,7 +39,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature `contracts_internals`
-  --> $DIR/internal-feature-gating.rs:12:5
+  --> $DIR/internal-feature-gating.rs:10:5
    |
 LL |     core::contracts::build_check_ensures(|_: &()| true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -58,6 +48,6 @@
    = help: add `#![feature(contracts_internals)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/link-native-libs/issue-43925.rs b/tests/ui/link-native-libs/issue-43925.rs
index e3ce713..09248db 100644
--- a/tests/ui/link-native-libs/issue-43925.rs
+++ b/tests/ui/link-native-libs/issue-43925.rs
@@ -1,6 +1,6 @@
 #[link(name = "foo", cfg("rlib"))]
 //~^ ERROR link cfg is unstable
-//~| ERROR `cfg` predicate key must be an identifier
+//~| ERROR malformed `link` attribute input
 extern "C" {}
 
 fn main() {}
diff --git a/tests/ui/link-native-libs/issue-43925.stderr b/tests/ui/link-native-libs/issue-43925.stderr
index 82d2042..68a0205 100644
--- a/tests/ui/link-native-libs/issue-43925.stderr
+++ b/tests/ui/link-native-libs/issue-43925.stderr
@@ -7,12 +7,32 @@
    = help: add `#![feature(link_cfg)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: `cfg` predicate key must be an identifier
-  --> $DIR/issue-43925.rs:1:26
+error[E0539]: malformed `link` attribute input
+  --> $DIR/issue-43925.rs:1:1
    |
 LL | #[link(name = "foo", cfg("rlib"))]
-   |                          ^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^------^^^
+   |                          |
+   |                          expected a valid identifier here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[link(name = "foo", cfg("rlib"))]
+LL + #[link(name = "...")]
+   |
+LL - #[link(name = "foo", cfg("rlib"))]
+LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]
+   |
+LL - #[link(name = "foo", cfg("rlib"))]
+LL + #[link(name = "...", kind = "dylib|static|...")]
+   |
+LL - #[link(name = "foo", cfg("rlib"))]
+LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]
+   |
+   = and 1 other candidate
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0539, E0658.
+For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/link-native-libs/link-attr-validation-late.rs b/tests/ui/link-native-libs/link-attr-validation-late.rs
index d2947b5..c24acca 100644
--- a/tests/ui/link-native-libs/link-attr-validation-late.rs
+++ b/tests/ui/link-native-libs/link-attr-validation-late.rs
@@ -22,7 +22,7 @@
 #[link(name = "...", modifiers())] //~ ERROR malformed `link` attribute input
 #[link(name = "...", cfg)] //~ ERROR malformed `link` attribute input
 #[link(name = "...", cfg = "literal")] //~ ERROR malformed `link` attribute input
-#[link(name = "...", cfg("literal"))] //~ ERROR `cfg` predicate key must be an identifier
+#[link(name = "...", cfg("literal"))] //~ ERROR malformed `link` attribute input
 #[link(name = "...", wasm_import_module)] //~ ERROR malformed `link` attribute input
 #[link(name = "...", wasm_import_module())] //~ ERROR malformed `link` attribute input
 extern "C" {}
diff --git a/tests/ui/link-native-libs/link-attr-validation-late.stderr b/tests/ui/link-native-libs/link-attr-validation-late.stderr
index 834dca0..106b7ce 100644
--- a/tests/ui/link-native-libs/link-attr-validation-late.stderr
+++ b/tests/ui/link-native-libs/link-attr-validation-late.stderr
@@ -367,11 +367,30 @@
    |
    = and 1 other candidate
 
-error: `cfg` predicate key must be an identifier
-  --> $DIR/link-attr-validation-late.rs:25:26
+error[E0539]: malformed `link` attribute input
+  --> $DIR/link-attr-validation-late.rs:25:1
    |
 LL | #[link(name = "...", cfg("literal"))]
-   |                          ^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^---------^^^
+   |                          |
+   |                          expected a valid identifier here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[link(name = "...", cfg("literal"))]
+LL + #[link(name = "...")]
+   |
+LL - #[link(name = "...", cfg("literal"))]
+LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]
+   |
+LL - #[link(name = "...", cfg("literal"))]
+LL + #[link(name = "...", kind = "dylib|static|...")]
+   |
+LL - #[link(name = "...", cfg("literal"))]
+LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]
+   |
+   = and 1 other candidate
 
 error[E0539]: malformed `link` attribute input
   --> $DIR/link-attr-validation-late.rs:26:1
diff --git a/tests/ui/malformed/malformed-special-attrs.stderr b/tests/ui/malformed/malformed-special-attrs.stderr
index b6a1a6b..91e5939 100644
--- a/tests/ui/malformed/malformed-special-attrs.stderr
+++ b/tests/ui/malformed/malformed-special-attrs.stderr
@@ -1,27 +1,24 @@
-error: malformed `cfg_attr` attribute input
+error[E0539]: malformed `cfg_attr` attribute input
   --> $DIR/malformed-special-attrs.rs:1:1
    |
 LL | #[cfg_attr]
    | ^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
-help: missing condition and attribute
-   |
-LL | #[cfg_attr(condition, attribute, other_attribute, ...)]
-   |           ++++++++++++++++++++++++++++++++++++++++++++
 
-error: malformed `cfg_attr` attribute input
+error[E0539]: malformed `cfg_attr` attribute input
   --> $DIR/malformed-special-attrs.rs:4:1
    |
 LL | #[cfg_attr = ""]
    | ^^^^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
-help: missing condition and attribute
-   |
-LL - #[cfg_attr = ""]
-LL + #[cfg_attr(condition, attribute, other_attribute, ...)]
-   |
 
 error: malformed `derive` attribute input
   --> $DIR/malformed-special-attrs.rs:7:1
@@ -37,3 +34,4 @@
 
 error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/rfcs/rfc-2091-track-caller/shim-does-not-modify-symbol.rs b/tests/ui/rfcs/rfc-2091-track-caller/shim-does-not-modify-symbol.rs
new file mode 100644
index 0000000..255e2c1
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2091-track-caller/shim-does-not-modify-symbol.rs
@@ -0,0 +1,26 @@
+//@ run-pass
+#![feature(rustc_attrs)]
+
+// The shim that is generated for a function annotated with `#[track_caller]` should not inherit
+// attributes that modify its symbol name. Failing to remove these attributes from the shim
+// leads to errors like `symbol `foo` is already defined`.
+//
+// See also https://github.com/rust-lang/rust/issues/143162.
+
+#[unsafe(no_mangle)]
+#[track_caller]
+pub fn foo() {}
+
+#[unsafe(export_name = "bar")]
+#[track_caller]
+pub fn bar() {}
+
+#[rustc_std_internal_symbol]
+#[track_caller]
+pub fn baz() {}
+
+fn main() {
+    let _a = foo as fn();
+    let _b = bar as fn();
+    let _c = baz as fn();
+}
diff --git a/tests/ui/rfcs/rfc-2091-track-caller/track-caller-ffi.rs b/tests/ui/rfcs/rfc-2091-track-caller/track-caller-ffi.rs
index ee8be90..d82bd12 100644
--- a/tests/ui/rfcs/rfc-2091-track-caller/track-caller-ffi.rs
+++ b/tests/ui/rfcs/rfc-2091-track-caller/track-caller-ffi.rs
@@ -2,14 +2,14 @@
 
 use std::panic::Location;
 
-extern "Rust" {
+unsafe extern "Rust" {
     #[track_caller]
-    fn rust_track_caller_ffi_test_tracked() -> &'static Location<'static>;
-    fn rust_track_caller_ffi_test_untracked() -> &'static Location<'static>;
+    safe fn rust_track_caller_ffi_test_tracked() -> &'static Location<'static>;
+    safe fn rust_track_caller_ffi_test_untracked() -> &'static Location<'static>;
 }
 
 fn rust_track_caller_ffi_test_nested_tracked() -> &'static Location<'static> {
-    unsafe { rust_track_caller_ffi_test_tracked() }
+    rust_track_caller_ffi_test_tracked()
 }
 
 mod provides {
@@ -31,12 +31,12 @@ fn main() {
     assert_eq!(location.line(), 29);
     assert_eq!(location.column(), 20);
 
-    let tracked = unsafe { rust_track_caller_ffi_test_tracked() };
+    let tracked = rust_track_caller_ffi_test_tracked();
     assert_eq!(tracked.file(), file!());
     assert_eq!(tracked.line(), 34);
-    assert_eq!(tracked.column(), 28);
+    assert_eq!(tracked.column(), 19);
 
-    let untracked = unsafe { rust_track_caller_ffi_test_untracked() };
+    let untracked = rust_track_caller_ffi_test_untracked();
     assert_eq!(untracked.file(), file!());
     assert_eq!(untracked.line(), 24);
     assert_eq!(untracked.column(), 9);
@@ -44,5 +44,10 @@ fn main() {
     let contained = rust_track_caller_ffi_test_nested_tracked();
     assert_eq!(contained.file(), file!());
     assert_eq!(contained.line(), 12);
-    assert_eq!(contained.column(), 14);
+    assert_eq!(contained.column(), 5);
+
+    let indirect = (rust_track_caller_ffi_test_tracked as fn() -> &'static Location<'static>)();
+    assert_eq!(indirect.file(), file!());
+    assert_eq!(indirect.line(), 7);
+    assert_eq!(indirect.column(), 5);
 }
diff --git a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.fixed b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.fixed
index 028f86eb0..b4b47dc 100644
--- a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.fixed
+++ b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.fixed
@@ -1,6 +1,7 @@
 //@ edition:2018
 //@ aux-build: remove-extern-crate.rs
 //@ run-rustfix
+//@ rustfix-only-machine-applicable
 
 #![warn(rust_2018_idioms)]
 
diff --git a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.rs b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.rs
index 1acf531..f3c591a 100644
--- a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.rs
+++ b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.rs
@@ -1,6 +1,7 @@
 //@ edition:2018
 //@ aux-build: remove-extern-crate.rs
 //@ run-rustfix
+//@ rustfix-only-machine-applicable
 
 #![warn(rust_2018_idioms)]
 
diff --git a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.stderr b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.stderr
index 632ecd6..fc6afa5 100644
--- a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.stderr
+++ b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.stderr
@@ -1,29 +1,33 @@
 error: expected identifier, found `"macro_use"`
-  --> $DIR/removing-extern-crate-malformed-cfg.rs:7:18
+  --> $DIR/removing-extern-crate-malformed-cfg.rs:8:18
    |
 LL | #[cfg_attr(test, "macro_use")]
-   |                  ^^^^^^^^^^^ expected identifier
+   | -----------------^^^^^^^^^^^--
+   | |                |
+   | |                expected identifier
+   | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
-   = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 error: expected one of `(`, `,`, `::`, or `=`, found `<eof>`
-  --> $DIR/removing-extern-crate-malformed-cfg.rs:12:16
+  --> $DIR/removing-extern-crate-malformed-cfg.rs:13:16
    |
 LL |     #[cfg_attr(test)]
-   |                ^^^^ expected one of `(`, `,`, `::`, or `=`
+   |     -----------^^^^--
+   |     |          |
+   |     |          expected one of `(`, `,`, `::`, or `=`
+   |     help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]`
    |
-   = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]`
    = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
 
 warning: unused extern crate
-  --> $DIR/removing-extern-crate-malformed-cfg.rs:8:1
+  --> $DIR/removing-extern-crate-malformed-cfg.rs:9:1
    |
 LL | extern crate remove_extern_crate as foo;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused
    |
 note: the lint level is defined here
-  --> $DIR/removing-extern-crate-malformed-cfg.rs:5:9
+  --> $DIR/removing-extern-crate-malformed-cfg.rs:6:9
    |
 LL | #![warn(rust_2018_idioms)]
    |         ^^^^^^^^^^^^^^^^
@@ -36,7 +40,7 @@
    |
 
 warning: unused extern crate
-  --> $DIR/removing-extern-crate-malformed-cfg.rs:9:1
+  --> $DIR/removing-extern-crate-malformed-cfg.rs:10:1
    |
 LL | extern crate core;
    | ^^^^^^^^^^^^^^^^^^ unused
@@ -48,7 +52,7 @@
    |
 
 warning: unused extern crate
-  --> $DIR/removing-extern-crate-malformed-cfg.rs:13:5
+  --> $DIR/removing-extern-crate-malformed-cfg.rs:14:5
    |
 LL |     extern crate remove_extern_crate as foo;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused
@@ -61,7 +65,7 @@
    |
 
 warning: unused extern crate
-  --> $DIR/removing-extern-crate-malformed-cfg.rs:14:5
+  --> $DIR/removing-extern-crate-malformed-cfg.rs:15:5
    |
 LL |     extern crate core;
    |     ^^^^^^^^^^^^^^^^^^ unused