Repository: rust-lang/rust
Pull request #123239: Implement a lint for implicit autoref of raw pointer dereference - take 2
Author: login: Urgau
Labels: name: A-attributes
description: Area: Attributes (`#[…]`, `#![…]`)
name: T-lang
description: Relevant to the language team
name: S-waiting-on-bors
description: Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
name: disposition-merge
description: This issue / PR is in PFCP or FCP with a disposition to merge it.
name: finished-final-comment-period
description: The final comment period is finished for this PR / Issue.
name: merged-by-bors
description: This PR was explicitly merged by bors.
name: O-SGX
description: Target: SGX
name: perf-regression
description: Performance regression.
name: perf-regression-triaged
description: The performance regression has been triaged.
name: CI-spurious-fail-mingw
description: CI spurious failure: target env mingw
name: CI-spurious-fail-rust-lld-crash
description: CI spurious failure: `rust-lld` crashing / SIGSEGV / 0xc0000374 heap corruption
name: L-dangerous_implicit_autorefs
description: Lint: dangerous_implicit_autorefs
Created: 2024-03-30T16:28:03Z | Merged: 2025-04-28T11:34:47Z

*[t-lang nomination comment](https://github.com/rust-lang/rust/pull/123239#issuecomment-2727551097)*

This PR aims at implementing a lint for implicit autoref of raw pointer dereference, it is based on #103735 with suggestion and improvements from https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305.

The goal is to catch cases like this, where the user probably doesn't realise it just created a reference.

```rust
pub struct Test {
    data: [u8],
}

pub fn test_len(t: *const Test) -> usize {
    unsafe { (*t).data.len() }  // this calls <[T]>::len(&self)
}
```

Since #103735 already went 2 times through T-lang, where they T-lang ended-up asking for a more restricted version (which is what this PR does), I would prefer this PR to be reviewed first before re-nominating it for T-lang.

----

Compared to the PR it is as based on, this PR adds 3 restrictions on the outer most expression, which must either be:
   1. A deref followed by any non-deref place projection (that intermediate deref will typically be auto-inserted)
   2. A method call annotated with `#[rustc_no_implicit_refs]`.
   3. A deref followed by a `addr_of!` or `addr_of_mut!`. See bottom of post for details.

There are several points that are not 100% clear to me when implementing the modifications:
 - ~~"4. Any number of automatically inserted deref/derefmut calls." I as never able to trigger this. Am I missing something?~~ Fixed
 - Are "index" and "field" enough?

---- 

cc @JakobDegen @WaffleLapkin
r? @RalfJung

try-job: dist-various-1
try-job: dist-various-2


Diff:
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 3b441729d7552..8993108b53c54 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -931,6 +931,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         EncodeCrossCrate::Yes,
         "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
     ),
+    rustc_attr!(
+        rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
+        "`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument."
+    ),
     rustc_attr!(
         rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
         "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 60c183bd56b1f..a6499b07fe26c 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -360,6 +360,10 @@ lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than pos
 lint_impl_trait_redundant_captures = all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
     .suggestion = remove the `use<...>` syntax
 
+lint_implicit_unsafe_autorefs = implicit autoref creates a reference to the dereference of a raw pointer
+    .note = creating a reference requires the pointer target to be valid and imposes aliasing requirements
+    .suggestion = try using a raw pointer method instead; or if this reference is intentional, make it explicit
+
 lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe
     .label = not FFI-safe
     .note = the type is defined here
diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs
new file mode 100644
index 0000000000000..5dd26854c9570
--- /dev/null
+++ b/compiler/rustc_lint/src/autorefs.rs
@@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to the dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements.
+    ///
+    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (&mut *ptr)[..16]
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals using only raw pointers:
+    ///
+    /// ```rust
+    /// use std::slice;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     slice::from_raw_parts_mut(ptr.cast(), 16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // <https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305>
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //      deref will typically be auto-inserted).
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `&raw const` or `&raw mut`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => inner,
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls.
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference (might come from a deref).
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections.
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer.
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => expr = &base,
+            ExprKind::Field(e, _) => expr = &e,
+            _ => break expr,
+        }
+    }
+}
+
+/// Peel derefs adjustments until the last last element.
+fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] {
+    while let [Adjustment { kind: Adjust::Deref(_), .. }, end @ ..] = adjs
+        && !end.is_empty()
+    {
+        adjs = end;
+    }
+    adjs
+}
+
+/// Test if some adjustment has some implicit borrow.
+///
+/// Returns `Some(mutability)` if the argument adjustment has implicit borrow in it.
+fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option<Mutability> {
+    match kind {
+        &Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some(mutbl),
+        &Adjust::Borrow(AutoBorrow::Ref(mutbl)) => Some(mutbl.into()),
+        Adjust::NeverToAny
+        | Adjust::Pointer(..)
+        | Adjust::ReborrowPin(..)
+        | Adjust::Deref(None)
+        | Adjust::Borrow(AutoBorrow::RawPtr(..)) => None,
+    }
+}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 212368bea8266..79c984cb634fc 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -36,6 +36,7 @@
 
 mod async_closures;
 mod async_fn_in_trait;
+mod autorefs;
 pub mod builtin;
 mod context;
 mod dangling;
@@ -83,6 +84,7 @@ mod utils;
 
 use async_closures::AsyncClosureUsage;
 use async_fn_in_trait::AsyncFnInTrait;
+use autorefs::*;
 use builtin::*;
 use dangling::*;
 use default_could_be_derived::DefaultCouldBeDerived;
@@ -200,6 +202,7 @@ late_lint_methods!(
             PathStatements: PathStatements,
             LetUnderscore: LetUnderscore,
             InvalidReferenceCasting: InvalidReferenceCasting,
+            ImplicitAutorefs: ImplicitAutorefs,
             // Depends on referenced function signatures in expressions
             UnusedResults: UnusedResults,
             UnitBindings: UnitBindings,
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 8ab64fbd127af..487184b836a43 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -55,6 +55,26 @@ pub(crate) enum ShadowedIntoIterDiagSub {
     },
 }
 
+// autorefs.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_implicit_unsafe_autorefs)]
+#[note]
+pub(crate) struct ImplicitUnsafeAutorefsDiag {
+    #[subdiagnostic]
+    pub suggestion: ImplicitUnsafeAutorefsSuggestion,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")]
+pub(crate) struct ImplicitUnsafeAutorefsSuggestion {
+    pub mutbl: &'static str,
+    pub deref: &'static str,
+    #[suggestion_part(code = "({mutbl}{deref}")]
+    pub start_span: Span,
+    #[suggestion_part(code = ")")]
+    pub end_span: Span,
+}
+
 // builtin.rs
 #[derive(LintDiagnostic)]
 #[diag(lint_builtin_while_true)]
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index cbe5058b55191..016837b8b8531 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -179,6 +179,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         [sym::rustc_as_ptr, ..] => {
                             self.check_applied_to_fn_or_method(hir_id, attr, span, target)
                         }
+                        [sym::rustc_no_implicit_autorefs, ..] => {
+                            self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                        }
                         [sym::rustc_never_returns_null_ptr, ..] => {
                             self.check_applied_to_fn_or_method(hir_id, attr, span, target)
                         }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ac7efaffefb8f..1bc08e60098ff 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1830,6 +1830,7 @@ symbols! {
         rustc_must_implement_one_of,
         rustc_never_returns_null_ptr,
         rustc_never_type_options,
+        rustc_no_implicit_autorefs,
         rustc_no_mir_inline,
         rustc_nonnull_optimization_guaranteed,
         rustc_nounwind,
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 9a161d057db09..cd9e04a915aa2 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1832,6 +1832,7 @@ impl String {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")]
     #[rustc_confusables("length", "size")]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     pub const fn len(&self) -> usize {
         self.vec.len()
     }
@@ -1851,6 +1852,7 @@ impl String {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 68e4add30e5d0..65a83cb98ba6a 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2588,7 +2588,7 @@ impl<T, A: Allocator> Vec<T, A> {
     #[inline]
     #[track_caller]
     unsafe fn append_elements(&mut self, other: *const [T]) {
-        let count = unsafe { (*other).len() };
+        let count = other.len();
         self.reserve(count);
         let len = self.len();
         unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) };
diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs
index 37d9a28fb99c0..8106c088f0ba2 100644
--- a/library/core/src/ops/index.rs
+++ b/library/core/src/ops/index.rs
@@ -67,6 +67,7 @@ pub trait Index<Idx: ?Sized> {
     ///
     /// May panic if the index is out of bounds.
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     #[track_caller]
     fn index(&self, index: Idx) -> &Self::Output;
 }
@@ -171,6 +172,7 @@ pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
     ///
     /// May panic if the index is out of bounds.
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     #[track_caller]
     fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
 }
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 48ed5ae451e40..39c11572e4757 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -676,7 +676,7 @@
 //!             let data_ptr = unpinned_src.data.as_ptr() as *const u8;
 //!             let slice_ptr = unpinned_src.slice.as_ptr() as *const u8;
 //!             let offset = slice_ptr.offset_from(data_ptr) as usize;
-//!             let len = (*unpinned_src.slice.as_ptr()).len();
+//!             let len = unpinned_src.slice.as_ptr().len();
 //!
 //!             unpinned_self.slice = NonNull::from(&mut unpinned_self.data[offset..offset+len]);
 //!         }
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 7b2a3fac38a32..1e2c943c14d3c 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -109,6 +109,7 @@ impl<T> [T] {
     #[lang = "slice_len_fn"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     #[inline]
     #[must_use]
     pub const fn len(&self) -> usize {
@@ -128,6 +129,7 @@ impl<T> [T] {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.39.0")]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     #[inline]
     #[must_use]
     pub const fn is_empty(&self) -> bool {
@@ -562,6 +564,7 @@ impl<T> [T] {
     /// assert_eq!(None, v.get(0..4));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     #[inline]
     #[must_use]
     pub fn get<I>(&self, index: I) -> Option<&I::Output>
@@ -587,6 +590,7 @@ impl<T> [T] {
     /// assert_eq!(x, &[0, 42, 2]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     #[inline]
     #[must_use]
     pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
@@ -624,6 +628,7 @@ impl<T> [T] {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     #[inline]
     #[must_use]
     pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
@@ -666,6 +671,7 @@ impl<T> [T] {
     /// assert_eq!(x, &[1, 13, 4]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     #[inline]
     #[must_use]
     pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 79b4953fcc11a..2099327d2f14a 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -134,6 +134,7 @@ impl str {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_str_len", since = "1.39.0")]
     #[rustc_diagnostic_item = "str_len"]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     #[must_use]
     #[inline]
     pub const fn len(&self) -> usize {
@@ -153,6 +154,7 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_str_is_empty", since = "1.39.0")]
+    #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)]
     #[must_use]
     #[inline]
     pub const fn is_empty(&self) -> bool {
diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
index 3fe6dee3d6f4f..a60b83213fd96 100644
--- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
+++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs
@@ -675,7 +675,7 @@ where
 
     /// Obtain the number of elements in this user slice.
     pub fn len(&self) -> usize {
-        unsafe { (*self.0.get()).len() }
+        unsafe { self.0.get().len() }
     }
 
     /// Copies the value from user memory and appends it to `dest`.
diff --git a/src/tools/miri/tests/pass/dst-raw.rs b/src/tools/miri/tests/pass/dst-raw.rs
index f26191a1d5998..3d0b843b3da22 100644
--- a/src/tools/miri/tests/pass/dst-raw.rs
+++ b/src/tools/miri/tests/pass/dst-raw.rs
@@ -1,5 +1,7 @@
 // Test DST raw pointers
 
+#![allow(dangerous_implicit_autorefs)]
+
 trait Trait {
     fn foo(&self) -> isize;
 }
diff --git a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs b/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs
index 830e9c33847cf..e86cb3711acb0 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs
@@ -1,3 +1,5 @@
+#![allow(dangerous_implicit_autorefs)]
+
 use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
 use std::mem::{self, MaybeUninit};
 
diff --git a/tests/ui/dynamically-sized-types/dst-raw.rs b/tests/ui/dynamically-sized-types/dst-raw.rs
index 111848c5a7f05..935f0f11ca61f 100644
--- a/tests/ui/dynamically-sized-types/dst-raw.rs
+++ b/tests/ui/dynamically-sized-types/dst-raw.rs
@@ -1,6 +1,8 @@
 //@ run-pass
 // Test DST raw pointers
 
+#![allow(dangerous_implicit_autorefs)]
+
 trait Trait {
     fn foo(&self) -> isize;
 }
diff --git a/tests/ui/lint/implicit_autorefs.fixed b/tests/ui/lint/implicit_autorefs.fixed
new file mode 100644
index 0000000000000..96a617b20c918
--- /dev/null
+++ b/tests/ui/lint/implicit_autorefs.fixed
@@ -0,0 +1,99 @@
+//@ check-pass
+//@ run-rustfix
+
+#![allow(dead_code)] // For the rustfix-ed code.
+
+use std::mem::ManuallyDrop;
+use std::ops::Deref;
+
+unsafe fn test_const(ptr: *const [u8]) {
+    let _ = (&(*ptr))[..16];
+    //~^ WARN implicit autoref
+}
+
+struct Test {
+    field: [u8],
+}
+
+unsafe fn test_field(ptr: *const Test) -> *const [u8] {
+    let l = (&(*ptr).field).len();
+    //~^ WARN implicit autoref
+
+    &raw const (&(*ptr).field)[..l - 1]
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_builtin_index(a: *mut [String]) {
+    _ = (&(*a)[0]).len();
+    //~^ WARN implicit autoref
+
+    _ = (&(&(*a))[..1][0]).len();
+    //~^ WARN implicit autoref
+    //~^^ WARN implicit autoref
+}
+
+unsafe fn test_overloaded_deref_const(ptr: *const ManuallyDrop<Test>) {
+    let _ = (&(*ptr)).field;
+    //~^ WARN implicit autoref
+    let _ = &raw const (&(*ptr)).field;
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_overloaded_deref_mut(ptr: *mut ManuallyDrop<Test>) {
+    let _ = (&(*ptr)).field;
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_double_overloaded_deref_const(ptr: *const ManuallyDrop<ManuallyDrop<Test>>) {
+    let _ = (&(*ptr)).field;
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_manually_overloaded_deref() {
+    struct W<T>(T);
+
+    impl<T> Deref for W<T> {
+        type Target = T;
+        fn deref(&self) -> &T { &self.0 }
+    }
+
+    let w: W<i32> = W(5);
+    let w = &raw const w;
+    let _p: *const i32 = &raw const *(&**w);
+    //~^ WARN implicit autoref
+}
+
+struct Test2 {
+    // Derefs to `[u8]`.
+    field: &'static [u8]
+}
+
+fn test_more_manual_deref(ptr: *const Test2) -> usize {
+    unsafe { (&(*ptr).field).len() }
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_no_attr(ptr: *mut ManuallyDrop<u8>) {
+    ptr.write(ManuallyDrop::new(1)); // Should not warn, as `ManuallyDrop::write` is not
+                                     // annotated with `#[rustc_no_implicit_auto_ref]`
+}
+
+unsafe fn test_vec_get(ptr: *mut Vec<u8>) {
+    let _ = (&(*ptr)).get(0);
+    //~^ WARN implicit autoref
+    let _ = (&(*ptr)).get_unchecked(0);
+    //~^ WARN implicit autoref
+    let _ = (&mut (*ptr)).get_mut(0);
+    //~^ WARN implicit autoref
+    let _ = (&mut (*ptr)).get_unchecked_mut(0);
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_string(ptr: *mut String) {
+    let _ = (&(*ptr)).len();
+    //~^ WARN implicit autoref
+    let _ = (&(*ptr)).is_empty();
+    //~^ WARN implicit autoref
+}
+
+fn main() {}
diff --git a/tests/ui/lint/implicit_autorefs.rs b/tests/ui/lint/implicit_autorefs.rs
new file mode 100644
index 0000000000000..61dd0ac50ce75
--- /dev/null
+++ b/tests/ui/lint/implicit_autorefs.rs
@@ -0,0 +1,99 @@
+//@ check-pass
+//@ run-rustfix
+
+#![allow(dead_code)] // For the rustfix-ed code.
+
+use std::mem::ManuallyDrop;
+use std::ops::Deref;
+
+unsafe fn test_const(ptr: *const [u8]) {
+    let _ = (*ptr)[..16];
+    //~^ WARN implicit autoref
+}
+
+struct Test {
+    field: [u8],
+}
+
+unsafe fn test_field(ptr: *const Test) -> *const [u8] {
+    let l = (*ptr).field.len();
+    //~^ WARN implicit autoref
+
+    &raw const (*ptr).field[..l - 1]
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_builtin_index(a: *mut [String]) {
+    _ = (*a)[0].len();
+    //~^ WARN implicit autoref
+
+    _ = (*a)[..1][0].len();
+    //~^ WARN implicit autoref
+    //~^^ WARN implicit autoref
+}
+
+unsafe fn test_overloaded_deref_const(ptr: *const ManuallyDrop<Test>) {
+    let _ = (*ptr).field;
+    //~^ WARN implicit autoref
+    let _ = &raw const (*ptr).field;
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_overloaded_deref_mut(ptr: *mut ManuallyDrop<Test>) {
+    let _ = (*ptr).field;
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_double_overloaded_deref_const(ptr: *const ManuallyDrop<ManuallyDrop<Test>>) {
+    let _ = (*ptr).field;
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_manually_overloaded_deref() {
+    struct W<T>(T);
+
+    impl<T> Deref for W<T> {
+        type Target = T;
+        fn deref(&self) -> &T { &self.0 }
+    }
+
+    let w: W<i32> = W(5);
+    let w = &raw const w;
+    let _p: *const i32 = &raw const **w;
+    //~^ WARN implicit autoref
+}
+
+struct Test2 {
+    // Derefs to `[u8]`.
+    field: &'static [u8]
+}
+
+fn test_more_manual_deref(ptr: *const Test2) -> usize {
+    unsafe { (*ptr).field.len() }
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_no_attr(ptr: *mut ManuallyDrop<u8>) {
+    ptr.write(ManuallyDrop::new(1)); // Should not warn, as `ManuallyDrop::write` is not
+                                     // annotated with `#[rustc_no_implicit_auto_ref]`
+}
+
+unsafe fn test_vec_get(ptr: *mut Vec<u8>) {
+    let _ = (*ptr).get(0);
+    //~^ WARN implicit autoref
+    let _ = (*ptr).get_unchecked(0);
+    //~^ WARN implicit autoref
+    let _ = (*ptr).get_mut(0);
+    //~^ WARN implicit autoref
+    let _ = (*ptr).get_unchecked_mut(0);
+    //~^ WARN implicit autoref
+}
+
+unsafe fn test_string(ptr: *mut String) {
+    let _ = (*ptr).len();
+    //~^ WARN implicit autoref
+    let _ = (*ptr).is_empty();
+    //~^ WARN implicit autoref
+}
+
+fn main() {}
diff --git a/tests/ui/lint/implicit_autorefs.stderr b/tests/ui/lint/implicit_autorefs.stderr
new file mode 100644
index 0000000000000..6dd1ac65ada98
--- /dev/null
+++ b/tests/ui/lint/implicit_autorefs.stderr
@@ -0,0 +1,219 @@
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:10:13
+   |
+LL |     let _ = (*ptr)[..16];
+   |             ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+   = note: `#[warn(dangerous_implicit_autorefs)]` on by default
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _ = (&(*ptr))[..16];
+   |             ++      +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:19:13
+   |
+LL |     let l = (*ptr).field.len();
+   |             ^^^^^^^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let l = (&(*ptr).field).len();
+   |             ++            +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:22:16
+   |
+LL |     &raw const (*ptr).field[..l - 1]
+   |                ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     &raw const (&(*ptr).field)[..l - 1]
+   |                ++            +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:27:9
+   |
+LL |     _ = (*a)[0].len();
+   |         ^^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     _ = (&(*a)[0]).len();
+   |         ++       +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:30:9
+   |
+LL |     _ = (*a)[..1][0].len();
+   |         ^^^^^^^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     _ = (&(*a)[..1][0]).len();
+   |         ++            +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:30:9
+   |
+LL |     _ = (*a)[..1][0].len();
+   |         ^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     _ = (&(*a))[..1][0].len();
+   |         ++    +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:36:13
+   |
+LL |     let _ = (*ptr).field;
+   |             ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _ = (&(*ptr)).field;
+   |             ++      +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:38:24
+   |
+LL |     let _ = &raw const (*ptr).field;
+   |                        ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _ = &raw const (&(*ptr)).field;
+   |                        ++      +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:43:13
+   |
+LL |     let _ = (*ptr).field;
+   |             ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _ = (&(*ptr)).field;
+   |             ++      +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:48:13
+   |
+LL |     let _ = (*ptr).field;
+   |             ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _ = (&(*ptr)).field;
+   |             ++      +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:62:26
+   |
+LL |     let _p: *const i32 = &raw const **w;
+   |                          ^^^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _p: *const i32 = &raw const *(&**w);
+   |                                      +++  +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:72:14
+   |
+LL |     unsafe { (*ptr).field.len() }
+   |              ^^^^^^^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     unsafe { (&(*ptr).field).len() }
+   |              ++            +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:82:13
+   |
+LL |     let _ = (*ptr).get(0);
+   |             ^^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _ = (&(*ptr)).get(0);
+   |             ++      +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:84:13
+   |
+LL |     let _ = (*ptr).get_unchecked(0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _ = (&(*ptr)).get_unchecked(0);
+   |             ++      +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:86:13
+   |
+LL |     let _ = (*ptr).get_mut(0);
+   |             ^^^^^^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _ = (&mut (*ptr)).get_mut(0);
+   |             +++++       +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:88:13
+   |
+LL |     let _ = (*ptr).get_unchecked_mut(0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _ = (&mut (*ptr)).get_unchecked_mut(0);
+   |             +++++       +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:93:13
+   |
+LL |     let _ = (*ptr).len();
+   |             ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _ = (&(*ptr)).len();
+   |             ++      +
+
+warning: implicit autoref creates a reference to the dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:95:13
+   |
+LL |     let _ = (*ptr).is_empty();
+   |             ^^^^^^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     let _ = (&(*ptr)).is_empty();
+   |             ++      +
+
+warning: 18 warnings emitted
+


Reviews:
user: login: fmease
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-05-15T12:14:25Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-05-15T17:23:37Z
user: login: tmandry
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-05-28T22:38:02Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-05-29T06:00:53Z
user: login: jieyouxu
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-08-13T10:22:43Z
user: login: fmease
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-08-13T12:45:35Z
user: login: wesleywiser
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-11-14T15:51:27Z
user: login: jdonszelmann
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-08T19:36:51Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-08T20:29:31Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-08T20:30:52Z
user: login: jdonszelmann
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-08T21:05:58Z
user: login: jdonszelmann
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-08T21:27:17Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-08T22:51:24Z
user: login: jdonszelmann
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-08T22:58:26Z
user: login: jdonszelmann
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-08T23:08:23Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-09T11:50:31Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-09T12:13:20Z
user: login: jdonszelmann
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-09T12:19:50Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-09T12:24:52Z
user: login: jdonszelmann
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-09T12:34:27Z
user: login: jdonszelmann
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-09T12:35:25Z
user: login: jdonszelmann
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-09T12:35:53Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T19:48:16Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T19:53:38Z
user: login: jdonszelmann
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T22:09:16Z
user: login: jdonszelmann
body: apart from that, the logic looks about right to me! let's ask for T-lang?
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T22:10:11Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-15T23:50:35Z
user: login: traviscross
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T01:22:24Z
user: login: traviscross
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T01:50:12Z
user: login: Urgau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-17T17:46:43Z
user: login: traviscross
body: Some nits mostly.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-20T01:37:24Z
user: login: traviscross
body: With the nits above resolved, this looks right to me, so, @jdonszelmann, `r=me` along with your own review.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-20T01:38:38Z

Review comments:
diff_hunk: @@ -0,0 +1,180 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::{
+    adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref},
+    TyCtxt, TypeckResults,
+};
+use rustc_session::declare_lint;
+use rustc_session::declare_lint_pass;
+use rustc_span::sym;
+
+use crate::{
+    lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion},
+    LateContext, LateLintPass, LintContext,
+};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
path: compiler/rustc_lint/src/autorefs.rs
user: login: fmease
body: ```suggestion
/// the usual reference requirements potentially without you realizing that.
```

More neutral, less “condescending” imo.
created_at: 2024-05-15T12:00:19Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,111 @@
+warning: implicit auto-ref creates a reference to a dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:12:14
+   |
+LL |     addr_of!((*ptr)[..16])
+   |              ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer to be valid and imposes aliasing requirements
+   = note: `#[warn(dangerous_implicit_autorefs)]` on by default
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     addr_of!((&(*ptr))[..16])
+   |              ++      +
path: tests/ui/lint/implicit_autorefs.stderr
user: login: fmease
body: While catching up with the comments posted in the now closed PR, I thought the plan was to avoid suggesting explicit borrows and to instead suggest `#[allow]`'ing the lint: Sth. like *if this reference is intentional make it explicit by adding `#[allow(implicit_unsafe_autorefs)]`*.

CC 1st paragraph of https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305; https://github.com/rust-lang/rust/pull/103735#issuecomment-1826826298; https://github.com/rust-lang/rust/pull/103735#issuecomment-1826886519
created_at: 2024-05-15T12:13:08Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,111 @@
+warning: implicit auto-ref creates a reference to a dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:12:14
+   |
+LL |     addr_of!((*ptr)[..16])
+   |              ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer to be valid and imposes aliasing requirements
+   = note: `#[warn(dangerous_implicit_autorefs)]` on by default
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     addr_of!((&(*ptr))[..16])
+   |              ++      +
path: tests/ui/lint/implicit_autorefs.stderr
user: login: Urgau
body: There has been concern from T-lang member about having only `#[allow]` as an option for lint, cc https://github.com/rust-lang/rust/pull/118833#issuecomment-1875723905 (and maybe a bit https://github.com/rust-lang/rust/issues/122759#issue-2196513165).

I think it would make sense to ask T-lang about this in the nomination, to see what they want, worst case it's just removing some code.
created_at: 2024-05-15T17:23:36Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,111 @@
+warning: implicit auto-ref creates a reference to a dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:12:14
+   |
+LL |     addr_of!((*ptr)[..16])
+   |              ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer to be valid and imposes aliasing requirements
+   = note: `#[warn(dangerous_implicit_autorefs)]` on by default
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     addr_of!((&(*ptr))[..16])
+   |              ++      +
path: tests/ui/lint/implicit_autorefs.stderr
user: login: tmandry
body: FWIW, nothing in #122759 is meant to imply that we shouldn't have lints whose suggestion is `#[allow]`.
created_at: 2024-05-28T22:38:02Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,111 @@
+warning: implicit auto-ref creates a reference to a dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:12:14
+   |
+LL |     addr_of!((*ptr)[..16])
+   |              ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer to be valid and imposes aliasing requirements
+   = note: `#[warn(dangerous_implicit_autorefs)]` on by default
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     addr_of!((&(*ptr))[..16])
+   |              ++      +
path: tests/ui/lint/implicit_autorefs.stderr
user: login: Urgau
body: Good to know. Thanks.
created_at: 2024-05-29T06:00:53Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,111 @@
+warning: implicit auto-ref creates a reference to a dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:12:14
+   |
+LL |     addr_of!((*ptr)[..16])
+   |              ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer to be valid and imposes aliasing requirements
+   = note: `#[warn(dangerous_implicit_autorefs)]` on by default
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     addr_of!((&(*ptr))[..16])
+   |              ++      +
path: tests/ui/lint/implicit_autorefs.stderr
user: login: jieyouxu
body: > I think it would make sense to ask T-lang about this in the nomination, to see what they want, worst case it's just removing some code.

@Urgau how do you want to proceed here, should we ask for T-lang feedback?
created_at: 2024-08-13T10:22:43Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,111 @@
+warning: implicit auto-ref creates a reference to a dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:12:14
+   |
+LL |     addr_of!((*ptr)[..16])
+   |              ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer to be valid and imposes aliasing requirements
+   = note: `#[warn(dangerous_implicit_autorefs)]` on by default
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     addr_of!((&(*ptr))[..16])
+   |              ++      +
path: tests/ui/lint/implicit_autorefs.stderr
user: login: fmease
body: We want to nominate this for T-lang in any case -- once I've reviewed this PR ^^' I'll really try to get to it tonight.
created_at: 2024-08-13T12:45:35Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,111 @@
+warning: implicit auto-ref creates a reference to a dereference of a raw pointer
+  --> $DIR/implicit_autorefs.rs:12:14
+   |
+LL |     addr_of!((*ptr)[..16])
+   |              ^^^^^^^^^^^^
+   |
+   = note: creating a reference requires the pointer to be valid and imposes aliasing requirements
+   = note: `#[warn(dangerous_implicit_autorefs)]` on by default
+help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
+   |
+LL |     addr_of!((&(*ptr))[..16])
+   |              ++      +
path: tests/ui/lint/implicit_autorefs.stderr
user: login: wesleywiser
body: Hi @fmease, just wanted to remind you to take a look at this PR if you are still interested. Thanks! 🙂 
created_at: 2024-11-14T15:51:27Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,173 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_middle::ty::{TyCtxt, TypeckResults};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _idx, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Call(path, [expr, ..])
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: I think this covers the case where you do use UFCS (`Type::method(receiver, ...)`) but it seems to me that this shouldn't trigger the lint since there's no implicit deref happening on receiver (like would've happened with a method call's `.`). Whether or not that's the case, I don't think any of the tests walks this path.
created_at: 2025-03-08T19:33:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,173 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_middle::ty::{TyCtxt, TypeckResults};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _idx, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Call(path, [expr, ..])
+                if let ExprKind::Path(ref qpath) = path.kind
+                    && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                expr
+            }
+            ExprKind::Field(inner, _) => {
+                let typeck = cx.typeck_results();
+                let adjustments_table = typeck.adjustments();
+                if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+                    && let [adjustment] = &**adjustments
+                    && let &Adjust::Deref(Some(OverloadedDeref { .. })) = &adjustment.kind
+                {
+                    inner
+                } else {
+                    return;
+                }
+            }
+            _ => return,
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: it could be nice to be exhaustive here? Any new ExprKind that could be a place projection should be added here.
created_at: 2025-03-08T19:34:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,173 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_middle::ty::{TyCtxt, TypeckResults};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _idx, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Call(path, [expr, ..])
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: though I realise that that's a lot of cases. The consequences aren't huge, this lint will just fail to fire which is mostly fine since until now it didn't exist. However, it would prevent that future bug.
created_at: 2025-03-08T19:36:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,173 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_middle::ty::{TyCtxt, TypeckResults};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _idx, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Call(path, [expr, ..])
+                if let ExprKind::Path(ref qpath) = path.kind
+                    && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                expr
+            }
+            ExprKind::Field(inner, _) => {
+                let typeck = cx.typeck_results();
+                let adjustments_table = typeck.adjustments();
+                if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+                    && let [adjustment] = &**adjustments
+                    && let &Adjust::Deref(Some(OverloadedDeref { .. })) = &adjustment.kind
+                {
+                    inner
+                } else {
+                    return;
+                }
+            }
+            _ => return,
path: compiler/rustc_lint/src/autorefs.rs
user: login: Urgau
body: I made the match exhaustive, not sure it's an improvement TBH. It's kind of huge and distracting now.
created_at: 2025-03-08T20:29:31Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,173 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_middle::ty::{TyCtxt, TypeckResults};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _idx, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Call(path, [expr, ..])
path: compiler/rustc_lint/src/autorefs.rs
user: login: Urgau
body: Indeed I don't it can happen with UFCS expression. Removed arm since we don't have test for it.
created_at: 2025-03-08T20:30:52Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,173 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_middle::ty::{TyCtxt, TypeckResults};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _idx, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Call(path, [expr, ..])
+                if let ExprKind::Path(ref qpath) = path.kind
+                    && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                expr
+            }
+            ExprKind::Field(inner, _) => {
+                let typeck = cx.typeck_results();
+                let adjustments_table = typeck.adjustments();
+                if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+                    && let [adjustment] = &**adjustments
+                    && let &Adjust::Deref(Some(OverloadedDeref { .. })) = &adjustment.kind
+                {
+                    inner
+                } else {
+                    return;
+                }
+            }
+            _ => return,
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: Hmm, I think I agree. And even then the march in the function below isn't exhaustive either. Not sure this is an improvement. Hmm
created_at: 2025-03-08T21:05:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,193 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: the issue comment you're referring to has 5 steps, this would be its step 5, followed by step 4 (any number of deref(mut) calls). I don't think I see that reflected here?
created_at: 2025-03-08T21:27:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,193 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
path: compiler/rustc_lint/src/autorefs.rs
user: login: Urgau
body: It's been a while, but I don't seems be to have ever been able to trigger it.
At least accordingly to my PR description.
created_at: 2025-03-08T22:51:24Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,193 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: right. let's think if I can think of a situation where it'd make a difference. In any case, the link in the comments on the code still points to that github comment, which doesn't match the following numbering. 
created_at: 2025-03-08T22:58:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,193 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: it seems this reproduces it:

```rust
struct Test2 {
    // derefs to [u8]
    field: &'static [u8]
}

fn more_manual_deref(ptr: *const Test2) -> usize {
    unsafe { (*ptr).field.len() }
    //~^ WARN implicit auto-ref (not emitted but should be)
}
```

created_at: 2025-03-08T23:08:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,193 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
path: compiler/rustc_lint/src/autorefs.rs
user: login: Urgau
body: Perfect, thanks you. I've adjusted the logic, comments and tests.
created_at: 2025-03-09T11:50:31Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,173 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_middle::ty::{TyCtxt, TypeckResults};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 4. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _idx, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Call(path, [expr, ..])
+                if let ExprKind::Path(ref qpath) = path.kind
+                    && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                expr
+            }
+            ExprKind::Field(inner, _) => {
+                let typeck = cx.typeck_results();
+                let adjustments_table = typeck.adjustments();
+                if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+                    && let [adjustment] = &**adjustments
+                    && let &Adjust::Deref(Some(OverloadedDeref { .. })) = &adjustment.kind
+                {
+                    inner
+                } else {
+                    return;
+                }
+            }
+            _ => return,
path: compiler/rustc_lint/src/autorefs.rs
user: login: Urgau
body: Reverted back to the non-exhaustive match.
created_at: 2025-03-09T12:13:20Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,166 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => {
+                let typeck = cx.typeck_results();
+                let adjustments_table = typeck.adjustments();
+                if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+                    && let [adjustment] = &**adjustments
+                    && let &Adjust::Deref(Some(OverloadedDeref { .. })) = &adjustment.kind
+                {
+                    inner
+                } else {
+                    return;
+                }
+            }
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference.
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => {
+                expr = &base;
+            }
+            ExprKind::Field(e, _) => expr = &e,
+            _ => break expr,
+        }
+    }
+}
+
+/// Peel derefs adjustments
+fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] {
+    while let [Adjustment { kind: Adjust::Deref(None), .. }, end @ ..] = adjs {
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: are you sure asserting None here is correct? I wrote some tests and can't find an example going wrong but I'm not 100% sure to be honest when this would be Some.
created_at: 2025-03-09T12:19:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,166 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => {
+                let typeck = cx.typeck_results();
+                let adjustments_table = typeck.adjustments();
+                if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+                    && let [adjustment] = &**adjustments
+                    && let &Adjust::Deref(Some(OverloadedDeref { .. })) = &adjustment.kind
+                {
+                    inner
+                } else {
+                    return;
+                }
+            }
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference.
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => {
+                expr = &base;
+            }
+            ExprKind::Field(e, _) => expr = &e,
+            _ => break expr,
+        }
+    }
+}
+
+/// Peel derefs adjustments
+fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] {
+    while let [Adjustment { kind: Adjust::Deref(None), .. }, end @ ..] = adjs {
path: compiler/rustc_lint/src/autorefs.rs
user: login: Urgau
body: We check the `Some()` case in `has_implicit_borrow` so we can't peel it otherwise we will miss it in `has_implicit_borrow`.
created_at: 2025-03-09T12:24:52Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,166 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => {
+                let typeck = cx.typeck_results();
+                let adjustments_table = typeck.adjustments();
+                if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+                    && let [adjustment] = &**adjustments
+                    && let &Adjust::Deref(Some(OverloadedDeref { .. })) = &adjustment.kind
+                {
+                    inner
+                } else {
+                    return;
+                }
+            }
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference.
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => {
+                expr = &base;
+            }
+            ExprKind::Field(e, _) => expr = &e,
+            _ => break expr,
+        }
+    }
+}
+
+/// Peel derefs adjustments
+fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] {
+    while let [Adjustment { kind: Adjust::Deref(None), .. }, end @ ..] = adjs {
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: ah, yea that makes sense!
created_at: 2025-03-09T12:34:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,166 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => {
+                let typeck = cx.typeck_results();
+                let adjustments_table = typeck.adjustments();
+                if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+                    && let [adjustment] = &**adjustments
+                    && let &Adjust::Deref(Some(OverloadedDeref { .. })) = &adjustment.kind
+                {
+                    inner
+                } else {
+                    return;
+                }
+            }
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference.
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => {
+                expr = &base;
+            }
+            ExprKind::Field(e, _) => expr = &e,
+            _ => break expr,
+        }
+    }
+}
+
+/// Peel derefs adjustments
+fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] {
+    while let [Adjustment { kind: Adjust::Deref(None), .. }, end @ ..] = adjs {
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: could it ever happen that there are multiple `Some` cases in a row before a deref of a raw pointer?
created_at: 2025-03-09T12:35:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,166 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => {
+                let typeck = cx.typeck_results();
+                let adjustments_table = typeck.adjustments();
+                if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+                    && let [adjustment] = &**adjustments
+                    && let &Adjust::Deref(Some(OverloadedDeref { .. })) = &adjustment.kind
+                {
+                    inner
+                } else {
+                    return;
+                }
+            }
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference.
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => {
+                expr = &base;
+            }
+            ExprKind::Field(e, _) => expr = &e,
+            _ => break expr,
+        }
+    }
+}
+
+/// Peel derefs adjustments
+fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] {
+    while let [Adjustment { kind: Adjust::Deref(None), .. }, end @ ..] = adjs {
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: (since `has_implicit_borrow` only strips one layer)
created_at: 2025-03-09T12:35:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,166 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => {
+                let typeck = cx.typeck_results();
+                let adjustments_table = typeck.adjustments();
+                if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+                    && let [adjustment] = &**adjustments
+                    && let &Adjust::Deref(Some(OverloadedDeref { .. })) = &adjustment.kind
+                {
+                    inner
+                } else {
+                    return;
+                }
+            }
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference.
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => {
+                expr = &base;
+            }
+            ExprKind::Field(e, _) => expr = &e,
+            _ => break expr,
+        }
+    }
+}
+
+/// Peel derefs adjustments
+fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] {
+    while let [Adjustment { kind: Adjust::Deref(None), .. }, end @ ..] = adjs {
path: compiler/rustc_lint/src/autorefs.rs
user: login: Urgau
body: Yes, found an example with `*const ManuallyDrop<ManuallyDrop<Test>>` were we have a double deref of `ManuallyDrop`. I have adjusted the code and tests to take it into account.
created_at: 2025-03-11T19:48:16Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,166 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements without you even knowing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => {
+                let typeck = cx.typeck_results();
+                let adjustments_table = typeck.adjustments();
+                if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+                    && let [adjustment] = &**adjustments
+                    && let &Adjust::Deref(Some(OverloadedDeref { .. })) = &adjustment.kind
+                {
+                    inner
+                } else {
+                    return;
+                }
+            }
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference.
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => {
+                expr = &base;
+            }
+            ExprKind::Field(e, _) => expr = &e,
+            _ => break expr,
+        }
+    }
+}
+
+/// Peel derefs adjustments
+fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] {
+    while let [Adjustment { kind: Adjust::Deref(None), .. }, end @ ..] = adjs {
path: compiler/rustc_lint/src/autorefs.rs
user: login: Urgau
body: And fixing it also fixed a false-negative with the deref of `Vec<T> -> [T]`. Yay.
created_at: 2025-03-11T19:53:38Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,157 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements potentially without realizing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => inner,
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference (might come from a deref).
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => {
+                expr = &base;
+            }
+            ExprKind::Field(e, _) => expr = &e,
+            _ => break expr,
+        }
+    }
+}
+
+/// Peel derefs adjustments until the last last element.
+fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] {
+    while let [Adjustment { kind: Adjust::Deref(_), .. }, end @ ..] = adjs
path: compiler/rustc_lint/src/autorefs.rs
user: login: jdonszelmann
body: you could add an underscore to the pattern to represent the !is_empty
created_at: 2025-03-14T22:09:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,157 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements potentially without realizing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `addr_of!` or `addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => inner,
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference (might come from a deref).
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => {
+                expr = &base;
+            }
+            ExprKind::Field(e, _) => expr = &e,
+            _ => break expr,
+        }
+    }
+}
+
+/// Peel derefs adjustments until the last last element.
+fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] {
+    while let [Adjustment { kind: Adjust::Deref(_), .. }, end @ ..] = adjs
path: compiler/rustc_lint/src/autorefs.rs
user: login: Urgau
body: I'm not following. `_` mean "exactly one", but we want "one or more" so `end @ _` won't work, and since we need to keep the `..` (to get a slice) I don't see another way but to use `!adjs.is_empty()`.
created_at: 2025-03-15T23:50:34Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,157 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
    ///     &raw mut (*ptr)[..16]
```

Here and everywhere in this PR, including in the tests, let's please switch to the `&raw` syntax.

created_at: 2025-03-17T01:22:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,157 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
    /// since they inflict additional safety requirements. Unfortunately, it's
    /// possible
```
created_at: 2025-03-17T01:25:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,157 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements potentially without realizing that.
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
    /// the usual reference requirements.
```

We've already said "implicitly" here, so it seems fine to just truncate this.  Alternatively, it'd need to be reworded to add somewhere in there, e.g. "potentially without you realizing that" or "potentially without that being obvious" or likewise.
created_at: 2025-03-17T01:26:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,157 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements potentially without realizing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
    /// If you are sure that you can soundly take a reference, then you can take
    /// it explicitly:
```
created_at: 2025-03-17T01:27:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,157 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements potentially without realizing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
    /// Otherwise try to find an alternative way to achive your goals using only
    /// raw pointers:
```
created_at: 2025-03-17T01:29:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,157 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements potentially without realizing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: Surely we shouldn't be suggesting to people to turn on nightly features as a replacement for what we're linting against.
created_at: 2025-03-17T01:31:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,157 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::ptr::addr_of_mut;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((*ptr)[..16])
+    ///     //                 ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                        implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict a lot of safety requirement. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements potentially without realizing that.
+    ///
+    /// If you are sure, you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// # use std::ptr::addr_of_mut;
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     addr_of_mut!((&mut *ptr)[..16])
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals that work only with
+    /// raw pointers:
+    /// ```rust
+    /// #![feature(slice_ptr_get)]
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     ptr.get_unchecked_mut(..16)
+    /// }
+    /// ```
path: compiler/rustc_lint/src/autorefs.rs
user: login: Urgau
body: Switch this example to `slice::from_raw_parts_mut`, but more generally we don't always have a great story around raw pointers (as can be seen by the `slice_ptr_get` feature being nightly-only).
created_at: 2025-03-17T17:46:42Z
author_association: MEMBER
diff_hunk: @@ -360,6 +360,10 @@ lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than pos
 lint_impl_trait_redundant_captures = all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
     .suggestion = remove the `use<...>` syntax
 
+lint_implicit_unsafe_autorefs = implicit auto-ref creates a reference to a dereference of a raw pointer
path: compiler/rustc_lint/messages.ftl
user: login: traviscross
body: ```suggestion
lint_implicit_unsafe_autorefs = implicit autoref creates a reference to the dereference of a raw pointer
```

We don't hyphenate this (and "the" is a bit better in the first case here).
created_at: 2025-04-20T00:26:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -360,6 +360,10 @@ lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than pos
 lint_impl_trait_redundant_captures = all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
     .suggestion = remove the `use<...>` syntax
 
+lint_implicit_unsafe_autorefs = implicit auto-ref creates a reference to a dereference of a raw pointer
+    .note = creating a reference requires the pointer to be valid and imposes aliasing requirements
path: compiler/rustc_lint/messages.ftl
user: login: traviscross
body: ```suggestion
    .note = creating a reference requires the pointer target to be valid and imposes aliasing requirements
```

Maybe that's an improvement.  It can be a bit ambiguous when talking about pointers whether one means the pointer itself or its target.

created_at: 2025-04-20T00:29:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements.
+    ///
+    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
    ///
    /// ```rust
```
created_at: 2025-04-20T00:33:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements.
+    ///
+    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (&mut *ptr)[..16]
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals using only raw pointers:
+    /// ```rust
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
    /// Otherwise try to find an alternative way to achieve your goals using only raw pointers:
    ///
    /// ```rust
```
created_at: 2025-04-20T00:34:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements.
+    ///
+    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (&mut *ptr)[..16]
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals using only raw pointers:
+    /// ```rust
+    /// use std::slice;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     slice::from_raw_parts_mut(ptr.cast(), 16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
        // This logic has mostly been taken from:
        // <https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305>.
        //
```
created_at: 2025-04-20T00:39:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements.
+    ///
+    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (&mut *ptr)[..16]
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals using only raw pointers:
+    /// ```rust
+    /// use std::slice;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     slice::from_raw_parts_mut(ptr.cast(), 16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
        //   deref will typically be auto-inserted).
```
created_at: 2025-04-20T00:39:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements.
+    ///
+    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (&mut *ptr)[..16]
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals using only raw pointers:
+    /// ```rust
+    /// use std::slice;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     slice::from_raw_parts_mut(ptr.cast(), 16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `&raw const/addr_of!` or `&raw mut/addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => inner,
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
            // 4. Any number of automatically inserted deref/derefmut calls.
```
created_at: 2025-04-20T00:40:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements.
+    ///
+    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (&mut *ptr)[..16]
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals using only raw pointers:
+    /// ```rust
+    /// use std::slice;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     slice::from_raw_parts_mut(ptr.cast(), 16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `&raw const/addr_of!` or `&raw mut/addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => inner,
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference (might come from a deref).
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
                // 2. Any number of place projections.
```
created_at: 2025-04-20T00:40:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements.
+    ///
+    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (&mut *ptr)[..16]
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals using only raw pointers:
+    /// ```rust
+    /// use std::slice;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     slice::from_raw_parts_mut(ptr.cast(), 16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `&raw const/addr_of!` or `&raw mut/addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => inner,
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference (might come from a deref).
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
            // 1. Deref of a raw pointer.
```
created_at: 2025-04-20T00:40:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements.
+    ///
+    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (&mut *ptr)[..16]
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals using only raw pointers:
+    /// ```rust
+    /// use std::slice;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     slice::from_raw_parts_mut(ptr.cast(), 16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `&raw const/addr_of!` or `&raw mut/addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => inner,
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference (might come from a deref).
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => {
+                expr = &base;
+            }
+            ExprKind::Field(e, _) => expr = &e,
+            _ => break expr,
+        }
+    }
+}
+
+/// Peel derefs adjustments until the last last element.
+fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] {
+    while let [Adjustment { kind: Adjust::Deref(_), .. }, end @ ..] = adjs
+        && !end.is_empty()
+    {
+        adjs = end;
+    }
+    adjs
+}
+
+/// Test if some adjustment has some implicit borrow
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
/// Test if some adjustment has some implicit borrow.
```
created_at: 2025-04-20T00:41:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,99 @@
+//@ check-pass
+//@ run-rustfix
+
+#![allow(dead_code)] // for the rustfix-ed code
+
+use std::mem::ManuallyDrop;
+use std::ops::Deref;
+
+unsafe fn test_const(ptr: *const [u8]) {
+    let _ = (*ptr)[..16];
+    //~^ WARN implicit auto-ref
+}
+
+struct Test {
+    field: [u8],
+}
+
+unsafe fn test_field(ptr: *const Test) -> *const [u8] {
+    let l = (*ptr).field.len();
+    //~^ WARN implicit auto-ref
+
+    &raw const (*ptr).field[..l - 1]
+    //~^ WARN implicit auto-ref
+}
+
+unsafe fn test_builtin_index(a: *mut [String]) {
+    _ = (*a)[0].len();
+    //~^ WARN implicit auto-ref
+
+    _ = (*a)[..1][0].len();
+    //~^ WARN implicit auto-ref
+    //~^^ WARN implicit auto-ref
+}
+
+unsafe fn test_overloaded_deref_const(ptr: *const ManuallyDrop<Test>) {
+    let _ = (*ptr).field;
+    //~^ WARN implicit auto-ref
+    let _ = &raw const (*ptr).field;
+    //~^ WARN implicit auto-ref
+}
+
+unsafe fn test_overloaded_deref_mut(ptr: *mut ManuallyDrop<Test>) {
+    let _ = (*ptr).field;
+    //~^ WARN implicit auto-ref
+}
+
+unsafe fn test_double_overloaded_deref_const(ptr: *const ManuallyDrop<ManuallyDrop<Test>>) {
+    let _ = (*ptr).field;
+    //~^ WARN implicit auto-ref
+}
+
+unsafe fn test_manually_overloaded_deref() {
+    struct W<T>(T);
+
+    impl<T> Deref for W<T> {
+        type Target = T;
+        fn deref(&self) -> &T { &self.0 }
+    }
+
+    let w: W<i32> = W(5);
+    let w = &raw const w;
+    let _p: *const i32 = &raw const **w;
+    //~^ WARN implicit auto-ref
+}
+
+struct Test2 {
+    // derefs to [u8]
+    field: &'static [u8]
+}
+
+fn test_more_manual_deref(ptr: *const Test2) -> usize {
+    unsafe { (*ptr).field.len() }
+    //~^ WARN implicit auto-ref
+}
+
+unsafe fn test_no_attr(ptr: *mut ManuallyDrop<u8>) {
+    ptr.write(ManuallyDrop::new(1)); // should not warn, as `ManuallyDrop::write` is not
+                                     // annotated with `#[rustc_no_implicit_auto_ref]`
path: tests/ui/lint/implicit_autorefs.rs
user: login: traviscross
body: ```suggestion
    // Should not warn, as `ManuallyDrop::write` is not annotated with
    // `#[rustc_no_implicit_auto_ref]`.
    ptr.write(ManuallyDrop::new(1));
```

created_at: 2025-04-20T00:49:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,99 @@
+//@ check-pass
+//@ run-rustfix
+
+#![allow(dead_code)] // for the rustfix-ed code
path: tests/ui/lint/implicit_autorefs.rs
user: login: traviscross
body: ```suggestion
#![allow(dead_code)] // For the rustfix-ed code.
```
created_at: 2025-04-20T00:49:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,99 @@
+//@ check-pass
+//@ run-rustfix
+
+#![allow(dead_code)] // for the rustfix-ed code
+
+use std::mem::ManuallyDrop;
+use std::ops::Deref;
+
+unsafe fn test_const(ptr: *const [u8]) {
+    let _ = (*ptr)[..16];
+    //~^ WARN implicit auto-ref
+}
+
+struct Test {
+    field: [u8],
+}
+
+unsafe fn test_field(ptr: *const Test) -> *const [u8] {
+    let l = (*ptr).field.len();
+    //~^ WARN implicit auto-ref
+
+    &raw const (*ptr).field[..l - 1]
+    //~^ WARN implicit auto-ref
+}
+
+unsafe fn test_builtin_index(a: *mut [String]) {
+    _ = (*a)[0].len();
+    //~^ WARN implicit auto-ref
+
+    _ = (*a)[..1][0].len();
+    //~^ WARN implicit auto-ref
+    //~^^ WARN implicit auto-ref
+}
+
+unsafe fn test_overloaded_deref_const(ptr: *const ManuallyDrop<Test>) {
+    let _ = (*ptr).field;
+    //~^ WARN implicit auto-ref
+    let _ = &raw const (*ptr).field;
+    //~^ WARN implicit auto-ref
+}
+
+unsafe fn test_overloaded_deref_mut(ptr: *mut ManuallyDrop<Test>) {
+    let _ = (*ptr).field;
+    //~^ WARN implicit auto-ref
+}
+
+unsafe fn test_double_overloaded_deref_const(ptr: *const ManuallyDrop<ManuallyDrop<Test>>) {
+    let _ = (*ptr).field;
+    //~^ WARN implicit auto-ref
+}
+
+unsafe fn test_manually_overloaded_deref() {
+    struct W<T>(T);
+
+    impl<T> Deref for W<T> {
+        type Target = T;
+        fn deref(&self) -> &T { &self.0 }
+    }
+
+    let w: W<i32> = W(5);
+    let w = &raw const w;
+    let _p: *const i32 = &raw const **w;
+    //~^ WARN implicit auto-ref
+}
+
+struct Test2 {
+    // derefs to [u8]
path: tests/ui/lint/implicit_autorefs.rs
user: login: traviscross
body: ```suggestion
    // Derefs to `[u8]`.
```
created_at: 2025-04-20T00:49:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -916,6 +916,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         EncodeCrossCrate::Yes,
         "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
     ),
+    rustc_attr!(
+        rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
+        "#[rustc_no_implicit_autorefs] is used to mark functions that should not autorefs in raw pointers context."
path: compiler/rustc_feature/src/builtin_attrs.rs
user: login: traviscross
body: ```suggestion
        "`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument."
```

It probably doesn't make a difference in practice, and we could always change it later, but I wonder whether on principle this attribute would be better applied to the `self` parameter rather than to the function.  It would make the description of what this attribute does a bit more concise.

created_at: 2025-04-20T00:51:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
    /// to take a reference to the dereference of a raw pointer implicitly, which inflicts
```
created_at: 2025-04-20T01:01:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements.
+    ///
+    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (&mut *ptr)[..16]
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals using only raw pointers:
+    /// ```rust
+    /// use std::slice;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     slice::from_raw_parts_mut(ptr.cast(), 16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `&raw const/addr_of!` or `&raw mut/addr_of_mut!`.
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
        //   c. A deref followed by a `&raw const` or `&raw mut`.
```

(We don't need to increase the grep hits for the old syntax.)
created_at: 2025-04-20T01:03:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,153 @@
+use rustc_ast::{BorrowKind, UnOp};
+use rustc_hir::{Expr, ExprKind, Mutability};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::sym;
+
+use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion};
+use crate::{LateContext, LateLintPass, LintContext};
+
+declare_lint! {
+    /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references
+    /// to dereferences of raw pointers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (*ptr)[..16]
+    ///     //             ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
+    ///     //                    implicitly creating a reference
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When working with raw pointers it's usually undesirable to create references,
+    /// since they inflict additional safety requirements. Unfortunately, it's possible
+    /// to take a reference to a dereference of a raw pointer implicitly, which inflicts
+    /// the usual reference requirements.
+    ///
+    /// If you are sure that you can soundly take a reference, then you can take it explicitly:
+    /// ```rust
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     &raw mut (&mut *ptr)[..16]
+    /// }
+    /// ```
+    ///
+    /// Otherwise try to find an alternative way to achive your goals using only raw pointers:
+    /// ```rust
+    /// use std::slice;
+    ///
+    /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
+    ///     slice::from_raw_parts_mut(ptr.cast(), 16)
+    /// }
+    /// ```
+    pub DANGEROUS_IMPLICIT_AUTOREFS,
+    Warn,
+    "implicit reference to a dereference of a raw pointer",
+    report_in_external_macro
+}
+
+declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]);
+
+impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        // This logic has mostly been taken from
+        // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305
+
+        // 5. Either of the following:
+        //   a. A deref followed by any non-deref place projection (that intermediate
+        //   deref will typically be auto-inserted)
+        //   b. A method call annotated with `#[rustc_no_implicit_refs]`.
+        //   c. A deref followed by a `&raw const/addr_of!` or `&raw mut/addr_of_mut!`.
+        let mut is_coming_from_deref = false;
+        let inner = match expr.kind {
+            ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind {
+                ExprKind::Unary(UnOp::Deref, inner) => {
+                    is_coming_from_deref = true;
+                    inner
+                }
+                _ => return,
+            },
+            ExprKind::Index(base, _, _) => base,
+            ExprKind::MethodCall(_, inner, _, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) =>
+            {
+                inner
+            }
+            ExprKind::Field(inner, _) => inner,
+            _ => return,
+        };
+
+        let typeck = cx.typeck_results();
+        let adjustments_table = typeck.adjustments();
+
+        if let Some(adjustments) = adjustments_table.get(inner.hir_id)
+            // 4. Any number of automatically inserted deref/derefmut calls
+            && let adjustments = peel_derefs_adjustments(&**adjustments)
+            // 3. An automatically inserted reference (might come from a deref).
+            && let [adjustment] = adjustments
+            && let Some(borrow_mutbl) = has_implicit_borrow(adjustment)
+            && let ExprKind::Unary(UnOp::Deref, dereferenced) =
+                // 2. Any number of place projections
+                peel_place_mappers(inner).kind
+            // 1. Deref of a raw pointer
+            && typeck.expr_ty(dereferenced).is_raw_ptr()
+        {
+            cx.emit_span_lint(
+                DANGEROUS_IMPLICIT_AUTOREFS,
+                expr.span.source_callsite(),
+                ImplicitUnsafeAutorefsDiag {
+                    suggestion: ImplicitUnsafeAutorefsSuggestion {
+                        mutbl: borrow_mutbl.ref_prefix_str(),
+                        deref: if is_coming_from_deref { "*" } else { "" },
+                        start_span: inner.span.shrink_to_lo(),
+                        end_span: inner.span.shrink_to_hi(),
+                    },
+                },
+            )
+        }
+    }
+}
+
+/// Peels expressions from `expr` that can map a place.
+fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    loop {
+        match expr.kind {
+            ExprKind::Index(base, _idx, _) => {
+                expr = &base;
+            }
path: compiler/rustc_lint/src/autorefs.rs
user: login: traviscross
body: ```suggestion
            ExprKind::Index(base, _idx, _) => expr = &base,
```
created_at: 2025-04-20T01:09:02Z
author_association: CONTRIBUTOR

PR comments:
user: login: rustbot
created_at: 2024-03-30T16:28:12Z
body: The Miri subtree was changed

cc @rust-lang/miri
author_association: COLLABORATOR
user: login: RalfJung
created_at: 2024-03-30T16:32:58Z
body: Sorry, I can't take on more reviews currently.
r? compiler
(or feel free to pick someone specific who's suited)
author_association: MEMBER
user: login: rust-log-analyzer
created_at: 2024-03-30T16:53:09Z
body: 
The job **`x86_64-gnu-llvm-17`** failed! Check out the build log: [(web)](https://github.com/rust-lang/rust/actions/runs/8491999278/job/23264536112) [(plain)](https://github.com/rust-lang/rust/commit/12f1ea526400ad3638181ad0d16f82a914495506/checks/23264536112/logs)

<details><summary><i>Click to see the possible cause of the failure (guessed by this bot)</i></summary>

```plain
#17 exporting to docker image format
#17 sending tarball 29.5s done
#17 DONE 34.9s
##[endgroup]
Setting extra environment values for docker:  --env ENABLE_GCC_CODEGEN=1 --env GCC_EXEC_PREFIX=/usr/lib/gcc/
[CI_JOB_NAME=x86_64-gnu-llvm-17]
---
sccache: Starting the server...
##[group]Configure the build
configure: processing command line
configure: 
configure: build.configure-args := ['--build=x86_64-unknown-linux-gnu', '--llvm-root=/usr/lib/llvm-17', '--enable-llvm-link-shared', '--set', 'rust.thin-lto-import-instr-limit=10', '--set', 'change-id=99999999', '--enable-verbose-configure', '--enable-sccache', '--disable-manage-submodules', '--enable-locked-deps', '--enable-cargo-native-static', '--set', 'rust.codegen-units-std=1', '--set', 'dist.compression-profile=balanced', '--dist-compression-formats=xz', '--disable-dist-src', '--release-channel=nightly', '--enable-debug-assertions', '--enable-overflow-checks', '--enable-llvm-assertions', '--set', 'rust.verify-llvm-ir', '--set', 'rust.codegen-backends=llvm,cranelift,gcc', '--set', 'llvm.static-libstdcpp', '--enable-new-symbol-mangling']
configure: target.x86_64-unknown-linux-gnu.llvm-config := /usr/lib/llvm-17/bin/llvm-config
configure: llvm.link-shared     := True
configure: rust.thin-lto-import-instr-limit := 10
configure: change-id            := 99999999
---
  Downloaded boml v0.3.1
   Compiling boml v0.3.1
   Compiling y v0.1.0 (/checkout/compiler/rustc_codegen_gcc/build_system)
    Finished `release` profile [optimized] target(s) in 3.35s
     Running `/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-codegen/x86_64-unknown-linux-gnu/release/y test --use-system-gcc --use-backend gcc --out-dir /checkout/obj/build/x86_64-unknown-linux-gnu/stage1-tools/cg_gcc --release --mini-tests --std-tests`
Using system GCC
[BUILD] example
[AOT] mini_core_hello_world
/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-tools/cg_gcc/mini_core_hello_world
abc
---
---- library/core/src/pin.rs - pin (line 653) stdout ----
error: implicit auto-ref creates a reference to a dereference of a raw pointer
##[error]  --> library/core/src/pin.rs:679:23
   |
29 |             let len = (*unpinned_src.slice.as_ptr()).len();
   |
   = note: creating a reference requires the pointer to be valid and imposes aliasing requirements
note: the lint level is defined here
  --> library/core/src/pin.rs:651:9
  --> library/core/src/pin.rs:651:9
   |
1  | #![deny(warnings)]
   |         ^^^^^^^^
   = note: `#[deny(dangerous_implicit_autorefs)]` implied by `#[deny(warnings)]`
help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
   |
29 |             let len = (&(*unpinned_src.slice.as_ptr())).len();
   |                       ++                              +
error: aborting due to 1 previous error

Couldn't compile the test.


failures:
    library/core/src/pin.rs - pin (line 653)

test result: FAILED. 4598 passed; 1 failed; 43 ignored; 0 measured; 0 filtered out; finished in 52.63s

error: doctest failed, to rerun pass `-p core --doc`
  local time: Sat Mar 30 16:53:00 UTC 2024
  network time: Sat, 30 Mar 2024 16:53:00 GMT
##[error]Process completed with exit code 1.
Post job cleanup.
```

</details>
        
author_association: COLLABORATOR
user: login: rust-log-analyzer
created_at: 2024-03-30T17:13:46Z
body: 
The job **`mingw-check`** failed! Check out the build log: [(web)](https://github.com/rust-lang/rust/actions/runs/8492139283/job/23264828959) [(plain)](https://github.com/rust-lang/rust/commit/bb6ab413d84c0e66e068ebb790356e0ab9a232e8/checks/23264828959/logs)

<details><summary><i>Click to see the possible cause of the failure (guessed by this bot)</i></summary>

```plain
---- library/core/src/pin.rs - pin (line 653) stdout ----
error[E0658]: use of unstable library feature 'slice_ptr_len'
##[error]  --> library/core/src/pin.rs:679:51
   |
29 |             let len = unpinned_src.slice.as_ptr().len();
   |
   = note: see issue #71146 <https://github.com/rust-lang/rust/issues/71146> for more information
   = help: add `#![feature(slice_ptr_len)]` to the crate attributes to enable
   = note: this compiler was built on 2024-03-18; consider upgrading it if it is out of date
---
    library/core/src/pin.rs - pin (line 653)

test result: FAILED. 4597 passed; 1 failed; 43 ignored; 0 measured; 0 filtered out; finished in 142.14s

error: doctest failed, to rerun pass `-p core --doc`
  local time: Sat Mar 30 17:13:35 UTC 2024
  network time: Sat, 30 Mar 2024 17:13:35 GMT
##[error]Process completed with exit code 1.
Post job cleanup.
```

</details>
        
author_association: COLLABORATOR
user: login: bors
created_at: 2024-05-14T10:43:53Z
body: :umbrella: The latest upstream changes (presumably #124228) made this pull request unmergeable. Please [resolve the merge conflicts](https://rustc-dev-guide.rust-lang.org/git.html#rebasing-and-conflicts).
author_association: COLLABORATOR
user: login: rust-log-analyzer
created_at: 2024-05-14T17:42:15Z
body: 
The job **`mingw-check`** failed! Check out the build log: [(web)](https://github.com/rust-lang/rust/actions/runs/9083563375/job/24962521817) [(plain)](https://github.com/rust-lang/rust/commit/57f641636f7a5ce3dccad1842540c88e7049da58/checks/24962521817/logs)

<details><summary><i>Click to see the possible cause of the failure (guessed by this bot)</i></summary>

```plain
    library/core/src/pin.rs - pin (line 653)

test result: FAILED. 4627 passed; 1 failed; 42 ignored; 0 measured; 0 filtered out; finished in 144.79s

error: doctest failed, to rerun pass `-p core --doc`
  local time: Tue May 14 17:42:04 UTC 2024
  network time: Tue, 14 May 2024 17:42:04 GMT
##[error]Process completed with exit code 1.
Post job cleanup.
```

</details>
        
author_association: COLLABORATOR
user: login: bors
created_at: 2024-05-22T06:54:50Z
body: :umbrella: The latest upstream changes (presumably #125326) made this pull request unmergeable. Please [resolve the merge conflicts](https://rustc-dev-guide.rust-lang.org/git.html#rebasing-and-conflicts).
author_association: COLLABORATOR
user: login: bors
created_at: 2024-08-05T07:19:11Z
body: :umbrella: The latest upstream changes (presumably #128672) made this pull request unmergeable. Please [resolve the merge conflicts](https://rustc-dev-guide.rust-lang.org/git.html#rebasing-and-conflicts).
author_association: COLLABORATOR
user: login: Dylan-DPC
created_at: 2024-08-12T11:58:19Z
body: @Urgau if you can rebase the latest conflicts we can push this forward and maybe get it reviewed by another reviewer
author_association: MEMBER
user: login: Urgau
created_at: 2024-08-12T17:49:41Z
body: @Dylan-DPC rebased.

@rustbot review
author_association: MEMBER
user: login: rust-log-analyzer
created_at: 2024-10-09T14:08:48Z
body: 
The job **`mingw-check`** failed! Check out the build log: [(web)](https://github.com/rust-lang/rust/actions/runs/11256533777/job/31298666398) [(plain)](https://github.com/rust-lang/rust/commit/d06061566e3d989b23e55f99bb954c53732546b3/checks/31298666398/logs)

<details><summary><i>Click to see the possible cause of the failure (guessed by this bot)</i></summary>

```plain
#16 2.885 Building wheels for collected packages: reuse
#16 2.886   Building wheel for reuse (pyproject.toml): started
#16 3.133   Building wheel for reuse (pyproject.toml): finished with status 'done'
#16 3.134   Created wheel for reuse: filename=reuse-4.0.3-cp310-cp310-manylinux_2_35_x86_64.whl size=132715 sha256=dfa09868353292d98f811d3efdb0d54d07389e808efc71d68e3b93c514bf8bec
#16 3.134   Stored in directory: /tmp/pip-ephem-wheel-cache-ieeszcgp/wheels/3d/8d/0a/e0fc6aba4494b28a967ab5eaf951c121d9c677958714e34532
#16 3.137 Installing collected packages: boolean-py, binaryornot, tomlkit, reuse, python-debian, markupsafe, license-expression, jinja2, chardet, attrs
#16 3.537 Successfully installed attrs-23.2.0 binaryornot-0.4.4 boolean-py-4.0 chardet-5.2.0 jinja2-3.1.4 license-expression-30.3.0 markupsafe-2.1.5 python-debian-0.1.49 reuse-4.0.3 tomlkit-0.13.0
#16 3.537 WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
#16 DONE 3.6s
---
    Checking rustc_codegen_ssa v0.0.0 (/checkout/compiler/rustc_codegen_ssa)
error: unreachable `pub` item
  --> compiler/rustc_lint/src/lints.rs:61:1
   |
61 | pub struct ImplicitUnsafeAutorefsDiag {
   | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   | |
   | help: consider restricting its visibility: `pub(crate)`
   = help: or consider exporting it for use by other crates
   = note: `-D unreachable-pub` implied by `-D warnings`
   = help: to override `-D warnings` add `#[allow(unreachable_pub)]`


error: unreachable `pub` item
  --> compiler/rustc_lint/src/lints.rs:68:1
   |
68 | pub struct ImplicitUnsafeAutorefsSuggestion {
   | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   | |
   | help: consider restricting its visibility: `pub(crate)`
   = help: or consider exporting it for use by other crates

error: could not compile `rustc_lint` (lib) due to 2 previous errors
warning: build failed, waiting for other jobs to finish...
```

</details>
        
author_association: COLLABORATOR
user: login: bors
created_at: 2025-02-25T02:35:56Z
body: :umbrella: The latest upstream changes (presumably #135726) made this pull request unmergeable. Please [resolve the merge conflicts](https://rustc-dev-guide.rust-lang.org/git.html#rebasing-and-conflicts).
author_association: COLLABORATOR
user: login: rustbot
created_at: 2025-03-03T18:56:28Z
body: Some changes occurred in compiler/rustc_passes/src/check_attr.rs

cc @jdonszelmann
author_association: COLLABORATOR
user: login: bors
created_at: 2025-03-05T18:39:54Z
body: :umbrella: The latest upstream changes (presumably #138058) made this pull request unmergeable. Please [resolve the merge conflicts](https://rustc-dev-guide.rust-lang.org/git.html#rebasing-and-conflicts).
author_association: COLLABORATOR
user: login: RalfJung
created_at: 2025-03-05T20:31:24Z
body: @Urgau I recommend asking on Zulip to find another reviewer. I would generally recommend doing that after about 2 weeks of silence; it's been half a year since we last heard from @fmease so I think you've been unreasonably patient already. :)
author_association: MEMBER
user: login: Urgau
created_at: 2025-03-06T21:10:12Z
body: r? @jdonszelmann per https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler/topic/reviewer.20for.20.23123239
author_association: MEMBER
user: login: rustbot
created_at: 2025-03-06T21:10:15Z
body: Failed to set assignee to `jdonszelmann`: invalid assignee

> **Note**: Only org members with at least the repository "read" role, users with write permissions, or people who have commented on the PR may be assigned.
author_association: COLLABORATOR
user: login: jdonszelmann
created_at: 2025-03-06T21:12:49Z
body: Heya, this looks somewhat interesting and I think I understand most parts involved so I'm willing to review it :)
author_association: CONTRIBUTOR
user: login: jdonszelmann
created_at: 2025-03-08T19:17:36Z
body: It seems like there's still an open comment asking for T-lang feedback here? It's from august, did that ever happen? Not here at least it seems.
author_association: CONTRIBUTOR
user: login: Urgau
created_at: 2025-03-08T20:32:46Z
body: > It seems like there's still an open comment asking for T-lang feedback here? It's from august, did that ever happen? Not here at least it seems.

Not yet. That will be a question for the T-lang nomination, which will be after the logic in this PR is checked to be correct-ish.
author_association: MEMBER
user: login: rust-log-analyzer
created_at: 2025-03-08T20:35:53Z
body: 
The job **`x86_64-gnu-llvm-18`** failed! Check out the build log: [(web)](https://github.com/rust-lang/rust/actions/runs/13741198588/job/38430662324) [(plain)](https://github.com/rust-lang/rust/commit/1e9582a7b3d267723b67758fdb7d9e4f8e40f0ab/checks/38430662324/logs)

<details><summary><i>Click to see the possible cause of the failure (guessed by this bot)</i></summary>

```plain
#20 exporting to docker image format
#20 sending tarball 19.6s done
#20 DONE 25.2s
##[endgroup]
Setting extra environment values for docker:  --env ENABLE_GCC_CODEGEN=1 --env GCC_EXEC_PREFIX=/usr/lib/gcc/
[CI_JOB_NAME=x86_64-gnu-llvm-18]
debug: `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` configured.
---
sccache: Listening on address 127.0.0.1:4226
##[group]Configure the build
configure: processing command line
configure: 
configure: build.configure-args := ['--build=x86_64-unknown-linux-gnu', '--llvm-root=/usr/lib/llvm-18', '--enable-llvm-link-shared', '--set', 'rust.randomize-layout=true', '--set', 'rust.thin-lto-import-instr-limit=10', '--enable-verbose-configure', '--enable-sccache', '--disable-manage-submodules', '--enable-locked-deps', '--enable-cargo-native-static', '--set', 'rust.codegen-units-std=1', '--set', 'dist.compression-profile=balanced', '--dist-compression-formats=xz', '--set', 'rust.lld=false', '--disable-dist-src', '--release-channel=nightly', '--enable-debug-assertions', '--enable-overflow-checks', '--enable-llvm-assertions', '--set', 'rust.verify-llvm-ir', '--set', 'rust.codegen-backends=llvm,cranelift,gcc', '--set', 'llvm.static-libstdcpp', '--enable-new-symbol-mangling']
configure: target.x86_64-unknown-linux-gnu.llvm-config := /usr/lib/llvm-18/bin/llvm-config
configure: llvm.link-shared     := True
configure: rust.randomize-layout := True
configure: rust.thin-lto-import-instr-limit := 10
---
   Compiling rustc_const_eval v0.0.0 (/checkout/compiler/rustc_const_eval)
   Compiling rustc_traits v0.0.0 (/checkout/compiler/rustc_traits)
   Compiling rustc_hir_analysis v0.0.0 (/checkout/compiler/rustc_hir_analysis)
   Compiling rustc_borrowck v0.0.0 (/checkout/compiler/rustc_borrowck)
error[E0004]: non-exhaustive patterns: `rustc_hir::ExprKind::Use(_, _)` not covered
    --> compiler/rustc_lint/src/autorefs.rs:71:27
71   |         let inner = match expr.kind {
71   |         let inner = match expr.kind {
     |                           ^^^^^^^^^ pattern `rustc_hir::ExprKind::Use(_, _)` not covered
note: `rustc_hir::ExprKind<'_>` defined here
    --> /checkout/compiler/rustc_hir/src/hir.rs:2525:1
     |
2525 | pub enum ExprKind<'hir> {
2525 | pub enum ExprKind<'hir> {
     | ^^^^^^^^^^^^^^^^^^^^^^^
...
2555 |     Use(&'hir Expr<'hir>, Span),
     = note: the matched value is of type `rustc_hir::ExprKind<'_>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
     |
129  ~             | ExprKind::Err(..) => return,
129  ~             | ExprKind::Err(..) => return,
130  ~             rustc_hir::ExprKind::Use(_, _) => todo!(),

For more information about this error, try `rustc --explain E0004`.
error: could not compile `rustc_lint` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
```

</details>
        
author_association: COLLABORATOR
user: login: jdonszelmann
created_at: 2025-03-08T21:08:54Z
body: Hmm, okay. I'll give it one more look but I'm reasonably confident this now at least implements the logic from the linked comment.
author_association: CONTRIBUTOR
user: login: bors
created_at: 2025-03-09T15:41:35Z
body: :umbrella: The latest upstream changes (presumably #138267) made this pull request unmergeable. Please [resolve the merge conflicts](https://rustc-dev-guide.rust-lang.org/git.html#rebasing-and-conflicts).
author_association: COLLABORATOR
user: login: bors
created_at: 2025-03-16T05:28:21Z
body: :umbrella: The latest upstream changes (presumably #138548) made this pull request unmergeable. Please [resolve the merge conflicts](https://rustc-dev-guide.rust-lang.org/git.html#rebasing-and-conflicts).
author_association: COLLABORATOR
user: login: Urgau
created_at: 2025-03-16T17:21:46Z
body: Dear @rust-lang/lang (and @rust-lang/lang-advisors), this PR is implementing a lint `dangerous_implicit_autorefs` for linting against implicit autoref of raw pointer dereference (as deny-by-default), it is based on https://github.com/rust-lang/rust/pull/103735 with suggestion and improvements from https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305 which result in a more restricted version (as asked).

**Examples and algorithm: https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305**

The goal is to catch cases like this, where the user probably doesn't realise it just created a reference.

```rust
pub struct Test {
    data: [u8],
}

pub fn test_len(t: *const Test) -> usize {
    unsafe { (*t).data.len() }  // this calls <[T]>::len(&self)
}
```

#103735 (the previous attempt) already went through you 2 times (https://github.com/rust-lang/rust/pull/103735#issuecomment-1331291281 and https://github.com/rust-lang/rust/pull/103735#issuecomment-1370186378) which prompted [this summary and suggestions](https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305) from `@JakobDegen` which is what this PR implements.

You can see in [`tests/ui/lint/implicit_autorefs.rs`](https://github.com/rust-lang/rust/blob/653c98b342299104a5c96452a1c299f6aac155b2/tests/ui/lint/implicit_autorefs.rs) the cases the lint would lint on.

One difference from Jakob suggestion is that this PR suggestion is to add explicit `&` references instead of suggesting to `#[allow(dangerous_implicit_autorefs)]` the lint. Which suggestion to use is left in your hands.

@rustbot labels +I-lang-nominated +S-waiting-on-team -S-waiting-on-review -T-libs -T-compiler
author_association: MEMBER
user: login: WaffleLapkin
created_at: 2025-04-09T13:48:25Z
body: Is this still blocked on lang?
author_association: MEMBER
user: login: RalfJung
created_at: 2025-04-09T14:03:58Z
body: Yes I think it is.
author_association: MEMBER
user: login: scottmcm
created_at: 2025-04-09T17:08:54Z
body: I agree that I don't like rustc lints that suggest suppressing them, so the change the suggest adding explicit `&`s if they're ok makes sense to me.

Let's do this.  The `addr_of!((*ptr)[..16])` example is a really nice one, since `[16]` and `[..16]` sure *look* like they might be the same related to this, but they're not.

@rfcbot fcp merge 

author_association: MEMBER
user: login: rfcbot
created_at: 2025-04-09T17:08:56Z
body: Team member @scottmcm has proposed to merge this. The next step is review by the rest of the tagged team members:

* [ ] @joshtriplett
* [ ] @nikomatsakis
* [x] @scottmcm
* [x] @tmandry
* [x] @traviscross

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns.
See [this document](https://github.com/rust-lang/rfcbot-rs/blob/master/README.md) for info about what commands tagged team members can give me.
author_association: NONE
user: login: traviscross
created_at: 2025-04-09T17:48:25Z
body: Sounds right.  Thanks to @Urgau for pushing this forward and answering some of my earlier questions on it.  Thanks to @JakobDegen for putting together [the algorithm](https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305) for this.

@rfcbot reviewed
author_association: CONTRIBUTOR
user: login: rfcbot
created_at: 2025-04-09T17:59:10Z
body: :bell: **This is now entering its final comment period**, as per the [review above](https://github.com/rust-lang/rust/pull/123239#issuecomment-2790416795). :bell:
author_association: NONE
user: login: bors
created_at: 2025-04-10T04:03:43Z
body: :umbrella: The latest upstream changes (presumably #139279) made this pull request unmergeable. Please [resolve the merge conflicts](https://rustc-dev-guide.rust-lang.org/git.html#rebasing-and-conflicts).
author_association: COLLABORATOR
user: login: rfcbot
created_at: 2025-04-19T18:00:06Z
body: The final comment period, with a disposition to **merge**, as per the [review above](https://github.com/rust-lang/rust/pull/123239#issuecomment-2790416795), is now **complete**.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

This will be merged soon.
author_association: NONE
user: login: jdonszelmann
created_at: 2025-04-20T19:40:43Z
body: I'll give a final review soon, hopefully tomorrow and then this should be ok :tada:
author_association: CONTRIBUTOR
user: login: jdonszelmann
created_at: 2025-04-25T13:51:18Z
body: I gave it one more pass, and found nothing notable (though I agree with TCs comments). Awesome work @Urgau, I'm super happy (in general and for you) this finally reached the finish line :D

@bors r=jdonszelmann,traviscross rollup=iffy
author_association: CONTRIBUTOR
user: login: bors
created_at: 2025-04-25T13:51:21Z
body: :pushpin: Commit e8a6c175c51fbc347ea0b4479cc1b2de0932ddab has been approved by `jdonszelmann,traviscross`

It is now in the [queue](https://bors.rust-lang.org/homu/queue/rust) for this repository.

<!-- @bors r=jdonszelmann,traviscross e8a6c175c51fbc347ea0b4479cc1b2de0932ddab -->
<!-- homu: {"type":"Approved","sha":"e8a6c175c51fbc347ea0b4479cc1b2de0932ddab","approver":"jdonszelmann,traviscross","queue":"https://bors.rust-lang.org/homu/queue/rust"} -->
author_association: COLLABORATOR
user: login: traviscross
created_at: 2025-04-25T15:12:26Z
body: @bors rollup=always

author_association: CONTRIBUTOR
user: login: matthiaskrgr
created_at: 2025-04-26T14:12:06Z
body: @bors r- rollup=never
https://github.com/rust-lang/rust/pull/140335#issuecomment-2832230798

author_association: MEMBER
user: login: Urgau
created_at: 2025-04-27T10:09:18Z
body: @bors try
author_association: MEMBER
user: login: bors
created_at: 2025-04-27T10:10:30Z
body: :hourglass: Trying commit 05f2b2265dd96655e9984c1b2b8ef207f09a88f9 with merge 40da18f879506d0cf9879a1d61f68a52ba2c658f...
<!-- homu: {"type":"TryBuildStarted","head_sha":"05f2b2265dd96655e9984c1b2b8ef207f09a88f9","merge_sha":"40da18f879506d0cf9879a1d61f68a52ba2c658f"} -->
author_association: COLLABORATOR
user: login: bors
created_at: 2025-04-27T11:36:29Z
body: :sunny: Try build successful - [checks-actions](https://github.com/rust-lang-ci/rust/actions/runs/14690960107/job/41227702007)
Build commit: 40da18f879506d0cf9879a1d61f68a52ba2c658f (`40da18f879506d0cf9879a1d61f68a52ba2c658f`)
<!-- homu: {"type":"TryBuildCompleted","builders":{"checks-actions":"https://github.com/rust-lang-ci/rust/actions/runs/14690960107/job/41227702007"},"merge_sha":"40da18f879506d0cf9879a1d61f68a52ba2c658f"} -->
author_association: COLLABORATOR
user: login: Urgau
created_at: 2025-04-27T11:44:04Z
body: @bors r=jdonszelmann,traviscross
author_association: MEMBER
user: login: bors
created_at: 2025-04-27T11:44:07Z
body: :pushpin: Commit 05f2b2265dd96655e9984c1b2b8ef207f09a88f9 has been approved by `jdonszelmann,traviscross`

It is now in the [queue](https://bors.rust-lang.org/homu/queue/rust) for this repository.

<!-- @bors r=jdonszelmann,traviscross 05f2b2265dd96655e9984c1b2b8ef207f09a88f9 -->
<!-- homu: {"type":"Approved","sha":"05f2b2265dd96655e9984c1b2b8ef207f09a88f9","approver":"jdonszelmann,traviscross","queue":"https://bors.rust-lang.org/homu/queue/rust"} -->
author_association: COLLABORATOR
user: login: bors
created_at: 2025-04-27T14:03:22Z
body: :hourglass: Testing commit 05f2b2265dd96655e9984c1b2b8ef207f09a88f9 with merge 5311e65c63ce1c46c566f7cde0c3249b712cdb45...
<!-- homu: {"type":"BuildStarted","head_sha":"05f2b2265dd96655e9984c1b2b8ef207f09a88f9","merge_sha":"5311e65c63ce1c46c566f7cde0c3249b712cdb45"} -->
author_association: COLLABORATOR
user: login: rust-log-analyzer
created_at: 2025-04-27T16:37:25Z
body: 
The job **`x86_64-mingw-1`** failed! Check out the build log: [(web)](https://github.com/rust-lang-ci/rust/actions/runs/14692866083/job/41230602115) [(plain)](https://github.com/rust-lang-ci/rust/commit/5311e65c63ce1c46c566f7cde0c3249b712cdb45/checks/41230602115/logs)

<details><summary><i>Click to see the possible cause of the failure (guessed by this bot)</i></summary>

```plain
---- [run-make] tests\run-make\amdgpu-kd stdout ----

error: rmake recipe failed to complete
status: exit code: 1
command: "D:\\a\\rust\\rust\\build\\x86_64-pc-windows-gnu\\test\\run-make\\amdgpu-kd\\rmake.exe"
stdout: none
--- stderr -------------------------------
command failed at line 18
Command { cmd: "D:\\a\\rust\\rust\\build\\x86_64-pc-windows-gnu\\stage2\\bin\\rustc.exe" "-L" "D:\\a\\rust\\rust\\build\\x86_64-pc-windows-gnu\\test\\run-make\\amdgpu-kd\\rmake_out" "--crate-name" "foo" "--target=amdgcn-amd-amdhsa" "-Ctarget-cpu=gfx900" "--crate-type" "cdylib" "foo.rs", stdin_buf: None, stdin: None, stdout: None, stderr: None, drop_bomb: DropBomb { command: "D:\\a\\rust\\rust\\build\\x86_64-pc-windows-gnu\\stage2\\bin\\rustc.exe", defused: true, armed_location: Location { file: "D:\\a\\rust\\rust\\tests\\run-make\\amdgpu-kd\\rmake.rs", line: 12, col: 5 } }, already_executed: true }
output status: `exit code: 1`
=== STDOUT ===



=== STDERR ===
error: linking with `rust-lld` failed: exit code: 0xc0000374
  |
  = note: "rust-lld" "-flavor" "gnu" "--version-script=C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\rustcDK81Hk\\list" "--no-undefined-version" "<1 object files omitted>" "--as-needed" "-L" "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\rustcDK81Hk\\raw-dylibs" "-Bdynamic" "--eh-frame-hdr" "-z" "noexecstack" "-L" "D:\\a\\rust\\rust\\build\\x86_64-pc-windows-gnu\\test\\run-make\\amdgpu-kd\\rmake_out" "-o" "foo.elf" "--gc-sections" "-shared"
  = note: some arguments are omitted. use `--verbose` to show all linker arguments
  = note: 

error: aborting due to 1 previous error
------------------------------------------
---
test result: FAILED. 279 passed; 1 failed; 110 ignored; 0 measured; 6 filtered out; finished in 199.20s

Some tests failed in compiletest suite=run-make mode=run-make host=x86_64-pc-windows-gnu target=x86_64-pc-windows-gnu
Build completed unsuccessfully in 2:25:17
make: *** [Makefile:124: ci-mingw-x] Error 1
  local time: Sun Apr 27 16:37:09 CUT 2025
  network time: Sun, 27 Apr 2025 16:37:09 GMT
##[error]Process completed with exit code 2.
Post job cleanup.
[command]"C:\Program Files\Git\bin\git.exe" version
```

</details>

author_association: COLLABORATOR
user: login: bors
created_at: 2025-04-27T16:37:54Z
body: :broken_heart: Test failed - [checks-actions](https://github.com/rust-lang-ci/rust/actions/runs/14692866083/job/41233341890)
<!-- homu: {"type":"BuildFailed","builder_url":"https://github.com/rust-lang-ci/rust/actions/runs/14692866083/job/41233341890","builder_name":"checks-actions"} -->
author_association: COLLABORATOR
user: login: Urgau
created_at: 2025-04-27T16:50:15Z
body: CI error is unrelated to this PR. Seems spurious.

@bors retry 
author_association: MEMBER
user: login: bors
created_at: 2025-04-27T19:48:42Z
body: :hourglass: Testing commit 05f2b2265dd96655e9984c1b2b8ef207f09a88f9 with merge af9aa86f909dbc0990a114148a12f36a9ff4828f...
<!-- homu: {"type":"BuildStarted","head_sha":"05f2b2265dd96655e9984c1b2b8ef207f09a88f9","merge_sha":"af9aa86f909dbc0990a114148a12f36a9ff4828f"} -->
author_association: COLLABORATOR
user: login: rust-log-analyzer
created_at: 2025-04-27T22:19:46Z
body: 
The job **`x86_64-mingw-1`** failed! Check out the build log: [(web)](https://github.com/rust-lang-ci/rust/actions/runs/14695546382/job/41236668377) [(plain)](https://github.com/rust-lang-ci/rust/commit/af9aa86f909dbc0990a114148a12f36a9ff4828f/checks/41236668377/logs)

<details><summary><i>Click to see the possible cause of the failure (guessed by this bot)</i></summary>

```plain
---- [run-make] tests\run-make\amdgpu-kd stdout ----

error: rmake recipe failed to complete
status: exit code: 1
command: "D:\\a\\rust\\rust\\build\\x86_64-pc-windows-gnu\\test\\run-make\\amdgpu-kd\\rmake.exe"
stdout: none
--- stderr -------------------------------
command failed at line 18
Command { cmd: "D:\\a\\rust\\rust\\build\\x86_64-pc-windows-gnu\\stage2\\bin\\rustc.exe" "-L" "D:\\a\\rust\\rust\\build\\x86_64-pc-windows-gnu\\test\\run-make\\amdgpu-kd\\rmake_out" "--crate-name" "foo" "--target=amdgcn-amd-amdhsa" "-Ctarget-cpu=gfx900" "--crate-type" "cdylib" "foo.rs", stdin_buf: None, stdin: None, stdout: None, stderr: None, drop_bomb: DropBomb { command: "D:\\a\\rust\\rust\\build\\x86_64-pc-windows-gnu\\stage2\\bin\\rustc.exe", defused: true, armed_location: Location { file: "D:\\a\\rust\\rust\\tests\\run-make\\amdgpu-kd\\rmake.rs", line: 12, col: 5 } }, already_executed: true }
output status: `exit code: 1`
=== STDOUT ===



=== STDERR ===
error: linking with `rust-lld` failed: exit code: 0xc0000374
  |
  = note: "rust-lld" "-flavor" "gnu" "--version-script=C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\rustcE0cB7E\\list" "--no-undefined-version" "<1 object files omitted>" "--as-needed" "-L" "C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\rustcE0cB7E\\raw-dylibs" "-Bdynamic" "--eh-frame-hdr" "-z" "noexecstack" "-L" "D:\\a\\rust\\rust\\build\\x86_64-pc-windows-gnu\\test\\run-make\\amdgpu-kd\\rmake_out" "-o" "foo.elf" "--gc-sections" "-shared"
  = note: some arguments are omitted. use `--verbose` to show all linker arguments
  = note: 

error: aborting due to 1 previous error
------------------------------------------
---
test result: FAILED. 279 passed; 1 failed; 110 ignored; 0 measured; 6 filtered out; finished in 196.65s

Some tests failed in compiletest suite=run-make mode=run-make host=x86_64-pc-windows-gnu target=x86_64-pc-windows-gnu
Build completed unsuccessfully in 2:23:37
make: *** [Makefile:124: ci-mingw-x] Error 1
  local time: Sun Apr 27 22:19:28 CUT 2025
  network time: Sun, 27 Apr 2025 22:19:28 GMT
##[error]Process completed with exit code 2.
Post job cleanup.
[command]"C:\Program Files\Git\bin\git.exe" version
```

</details>

author_association: COLLABORATOR
user: login: bors
created_at: 2025-04-27T22:20:27Z
body: :broken_heart: Test failed - [checks-actions](https://github.com/rust-lang-ci/rust/actions/runs/14695546382/job/41239260470)
<!-- homu: {"type":"BuildFailed","builder_url":"https://github.com/rust-lang-ci/rust/actions/runs/14695546382/job/41239260470","builder_name":"checks-actions"} -->
author_association: COLLABORATOR
user: login: Urgau
created_at: 2025-04-28T05:37:53Z
body: @bors retry
author_association: MEMBER
user: login: bors
created_at: 2025-04-28T08:25:27Z
body: :hourglass: Testing commit 05f2b2265dd96655e9984c1b2b8ef207f09a88f9 with merge a932eb36f8adf6c8cdfc450f063943da3112d621...
<!-- homu: {"type":"BuildStarted","head_sha":"05f2b2265dd96655e9984c1b2b8ef207f09a88f9","merge_sha":"a932eb36f8adf6c8cdfc450f063943da3112d621"} -->
author_association: COLLABORATOR
user: login: bors
created_at: 2025-04-28T11:34:42Z
body: :sunny: Test successful - [checks-actions](https://github.com/rust-lang-ci/rust/actions/runs/14703560364/job/41268886698)
Approved by: jdonszelmann,traviscross
Pushing a932eb36f8adf6c8cdfc450f063943da3112d621 to master...
<!-- homu: {"type":"BuildCompleted","approved_by":"jdonszelmann,traviscross","base_ref":"master","builders":{"checks-actions":"https://github.com/rust-lang-ci/rust/actions/runs/14703560364/job/41268886698"},"merge_sha":"a932eb36f8adf6c8cdfc450f063943da3112d621"} -->
author_association: COLLABORATOR
user: login: github-actions[bot]
created_at: 2025-04-28T11:37:04Z
body: <details>
<summary>What is this?</summary>
This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.
</details>


Comparing 0134651fb81314870903e21b1bcbdd993d75b61a (parent) -> a932eb36f8adf6c8cdfc450f063943da3112d621 (this PR)

# Test differences
<details>
<summary>Show 1165 test diffs
</summary>

## Stage 1
- `[ui] tests/ui/lint/implicit_autorefs.rs`: [missing] -> pass (**J0**)
## Stage 2
- `[ui] tests/ui/lint/implicit_autorefs.rs`: [missing] -> pass (**J1**)

Additionally, 1163 doctest diffs were found. These are ignored, as they are noisy.

**Job group index**

- **J0**: [x86_64-gnu-llvm-19-3](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258225413), [x86_64-gnu-llvm-20-3](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258222847)
- **J1**: [aarch64-apple](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258237077), [aarch64-gnu](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258183095), [arm-android](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258183870), [armhf-gnu](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258184278), [dist-i586-gnu-i586-i686-musl](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258194694), [i686-gnu-1](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258209226), [i686-gnu-nopt-1](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258210370), [i686-msvc-1](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258239354), [test-various](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258213509), [x86_64-apple-2](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258234978), [x86_64-gnu](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258215904), [x86_64-gnu-llvm-19-1](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258223666), [x86_64-gnu-llvm-19-2](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258224522), [x86_64-gnu-llvm-20-1](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258221277), [x86_64-gnu-llvm-20-2](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258222121), [x86_64-gnu-nopt](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258226417), [x86_64-gnu-stable](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258217122), [x86_64-mingw-1](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258243574), [x86_64-msvc-1](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258238049)
</details>

<details>
<summary>Test dashboard</summary>

Run

```bash
cargo run --manifest-path src/ci/citool/Cargo.toml -- \
    test-dashboard a932eb36f8adf6c8cdfc450f063943da3112d621 --output-dir test-dashboard
```
And then open `test-dashboard/index.html` in your browser to see an overview of all executed tests.

</details>

# Job duration changes
1. [x86_64-apple-1](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258233113): 8218.0s -> 6083.4s (-26.0%)
2. [dist-apple-various](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258231432): 6754.9s -> 8167.9s (20.9%)
3. [x86_64-msvc-ext2](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258242053): 6995.0s -> 5859.1s (-16.2%)
4. [dist-aarch64-apple](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258236569): 5175.2s -> 4666.8s (-9.8%)
5. [x86_64-msvc-2](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258238826): 7361.5s -> 6645.3s (-9.7%)
6. [dist-x86_64-apple](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258228731): 10267.2s -> 9484.6s (-7.6%)
7. [dist-i686-mingw](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258247969): 7817.4s -> 8250.3s (5.5%)
8. [dist-powerpc64le-linux](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258203128): 9389.9s -> 9859.3s (5.0%)
9. [x86_64-gnu-llvm-19-1](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258223666): 5337.6s -> 5100.5s (-4.4%)
10. [dist-i586-gnu-i586-i686-musl](https://github.com/rust-lang-ci/rust/actions/runs/14703560364#summary-41258194694): 5084.7s -> 5301.8s (4.3%)

<details>
<summary>How to interpret the job duration changes?</summary>

Job durations can vary a lot, based on the actual runner instance
that executed the job, system noise, invalidated caches, etc. The table above is provided
mostly for t-infra members, for simpler debugging of potential CI slow-downs.
</details>


author_association: CONTRIBUTOR
user: login: rust-timer
created_at: 2025-04-28T14:19:48Z
body: Finished benchmarking commit (a932eb36f8adf6c8cdfc450f063943da3112d621): [comparison URL](https://perf.rust-lang.org/compare.html?start=0134651fb81314870903e21b1bcbdd993d75b61a&end=a932eb36f8adf6c8cdfc450f063943da3112d621&stat=instructions:u).

### Overall result: ❌ regressions - please read the text below


Our benchmarks found a performance regression caused by this PR.
This might be an actual regression, but it can also be just noise.

**Next Steps**:

- If the regression was expected or you think it can be justified,
please write a comment with sufficient written justification, and add
`@rustbot label: +perf-regression-triaged` to it, to mark the regression as triaged.
- If you think that you know of a way to resolve the regression, try to create
a new PR with a fix for the regression.
- If you do not understand the regression or you think that it is just noise,
you can ask the `@rust-lang/wg-compiler-performance` working group for help (members of this group
were already notified of this PR).

@rustbot label: +perf-regression
cc @rust-lang/wg-compiler-performance



### [Instruction count](https://perf.rust-lang.org/compare.html?start=0134651fb81314870903e21b1bcbdd993d75b61a&end=a932eb36f8adf6c8cdfc450f063943da3112d621&stat=instructions:u)
This is the most reliable metric that we have; it was used to determine the overall result at the top of this comment. However, even this metric can sometimes exhibit noise.

|                                    | mean | range        | count |
|:----------------------------------:|:----:|:------------:|:-----:|
| Regressions ❌ <br /> (primary)    | 1.8% | [0.3%, 3.6%] | 6     |
| Regressions ❌ <br /> (secondary)  | -    | -            | 0     |
| Improvements ✅ <br /> (primary)   | -    | -            | 0     |
| Improvements ✅ <br /> (secondary) | -    | -            | 0     |
| All ❌✅ (primary)                 | 1.8% | [0.3%, 3.6%] | 6     |

### [Max RSS (memory usage)](https://perf.rust-lang.org/compare.html?start=0134651fb81314870903e21b1bcbdd993d75b61a&end=a932eb36f8adf6c8cdfc450f063943da3112d621&stat=max-rss)
<details>
<summary>Results (primary 0.4%, secondary -0.5%)</summary>

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

|                                    | mean  | range          | count |
|:----------------------------------:|:-----:|:--------------:|:-----:|
| Regressions ❌ <br /> (primary)    | 1.2%  | [0.5%, 2.3%]   | 4     |
| Regressions ❌ <br /> (secondary)  | 2.8%  | [2.8%, 2.8%]   | 1     |
| Improvements ✅ <br /> (primary)   | -0.6% | [-0.7%, -0.5%] | 3     |
| Improvements ✅ <br /> (secondary) | -2.2% | [-3.2%, -1.2%] | 2     |
| All ❌✅ (primary)                 | 0.4%  | [-0.7%, 2.3%]  | 7     |
</details>

### [Cycles](https://perf.rust-lang.org/compare.html?start=0134651fb81314870903e21b1bcbdd993d75b61a&end=a932eb36f8adf6c8cdfc450f063943da3112d621&stat=cycles:u)
<details>
<summary>Results (primary 1.0%)</summary>

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

|                                    | mean  | range          | count |
|:----------------------------------:|:-----:|:--------------:|:-----:|
| Regressions ❌ <br /> (primary)    | 2.1%  | [0.5%, 2.7%]   | 4     |
| Regressions ❌ <br /> (secondary)  | -     | -              | 0     |
| Improvements ✅ <br /> (primary)   | -0.5% | [-0.6%, -0.5%] | 3     |
| Improvements ✅ <br /> (secondary) | -     | -              | 0     |
| All ❌✅ (primary)                 | 1.0%  | [-0.6%, 2.7%]  | 7     |
</details>

### [Binary size](https://perf.rust-lang.org/compare.html?start=0134651fb81314870903e21b1bcbdd993d75b61a&end=a932eb36f8adf6c8cdfc450f063943da3112d621&stat=size:linked_artifact)
<details>
<summary>Results (primary 0.0%)</summary>

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

|                                    | mean | range        | count |
|:----------------------------------:|:----:|:------------:|:-----:|
| Regressions ❌ <br /> (primary)    | 0.0% | [0.0%, 0.0%] | 1     |
| Regressions ❌ <br /> (secondary)  | -    | -            | 0     |
| Improvements ✅ <br /> (primary)   | -    | -            | 0     |
| Improvements ✅ <br /> (secondary) | -    | -            | 0     |
| All ❌✅ (primary)                 | 0.0% | [0.0%, 0.0%] | 1     |
</details>

**Bootstrap**: 761.588s -> 761.378s (-0.03%)
**Artifact size**: 365.21 MiB -> 365.18 MiB (-0.01%)
author_association: COLLABORATOR
user: login: rylev
created_at: 2025-04-29T11:48:30Z
body: The perf regression is reversed in https://github.com/rust-lang/rust/pull/140406

@rustbot label: +perf-regression-triaged
author_association: MEMBER