diff --git a/compiler/rustc_lint/src/implicit_unsafe_autorefs.rs b/compiler/rustc_lint/src/implicit_unsafe_autorefs.rs index 979f1aab9b40b..41cc395e9175c 100644 --- a/compiler/rustc_lint/src/implicit_unsafe_autorefs.rs +++ b/compiler/rustc_lint/src/implicit_unsafe_autorefs.rs @@ -1,7 +1,7 @@ use crate::{LateContext, LateLintPass, LintContext}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Mutability, UnOp}; +use rustc_hir::{self as hir, Expr, ExprKind, Mutability, UnOp}; use rustc_middle::ty::{ adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref}, TyCtxt, TypeckResults, @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitUnsafeAutorefs { if let Some(adjustments) = adjustments_table.get(expr.hir_id) && let [adjustment] = &**adjustments // An auto-borrow - && let Some(mutbl) = has_implicit_borrow(adjustment) + && let Some((mutbl, implicit_borrow)) = has_implicit_borrow(adjustment) // ... of a place derived from a deref && let ExprKind::Unary(UnOp::Deref, dereferenced) = peel_place_mappers(cx.tcx, typeck, &expr).kind // ... of a raw pointer @@ -74,7 +74,13 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitUnsafeAutorefs { let msg = "implicit auto-ref creates a reference to a dereference of a raw pointer"; cx.struct_span_lint(IMPLICIT_UNSAFE_AUTOREFS, expr.span, msg, |lint| { lint - .note("creating a reference requires the pointer to be valid and imposes aliasing requirements") + .note("creating a reference requires the pointer to be valid and imposes aliasing requirements"); + + if let Some(reason) = reason(cx.tcx, implicit_borrow, expr) { + lint.note(format!("a reference is implicitly created {reason}")); + } + + lint .multipart_suggestion( "try using a raw pointer method instead; or if this reference is intentional, make it explicit", vec![ @@ -111,10 +117,43 @@ fn peel_place_mappers<'tcx>( } /// Returns `Some(mutability)` if the argument adjustment has implicit borrow in it. -fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option { +fn has_implicit_borrow( + Adjustment { kind, .. }: &Adjustment<'_>, +) -> Option<(Mutability, ImplicitBorrow)> { match kind { - &Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some(mutbl), - &Adjust::Borrow(AutoBorrow::Ref(_, mutbl)) => Some(mutbl.into()), + &Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some((mutbl, ImplicitBorrow::Deref)), + &Adjust::Borrow(AutoBorrow::Ref(_, mutbl)) => Some((mutbl.into(), ImplicitBorrow::Borrow)), _ => None, } } + +enum ImplicitBorrow { + Deref, + Borrow, +} + +fn reason(tcx: TyCtxt<'_>, borrow_kind: ImplicitBorrow, expr: &Expr<'_>) -> Option<&'static str> { + match borrow_kind { + ImplicitBorrow::Deref => Some("because a deref coercion is being applied"), + ImplicitBorrow::Borrow => { + let parent = tcx.hir().get(tcx.hir().find_parent_node(expr.hir_id)?); + + let hir::Node::Expr(expr) = parent else { + return None + }; + + let reason = match expr.kind { + ExprKind::MethodCall(_, _, _, _) => "to match the method receiver type", + ExprKind::AssignOp(_, _, _) => { + "because a user-defined assignment with an operator is being used" + } + ExprKind::Index(_, _) => { + "because a user-defined indexing operation is being called" + } + _ => return None, + }; + + Some(reason) + } + } +} diff --git a/src/test/ui/lint/implicit_unsafe_autorefs.stderr b/src/test/ui/lint/implicit_unsafe_autorefs.stderr index a9936705e9965..cee0c5256dfbf 100644 --- a/src/test/ui/lint/implicit_unsafe_autorefs.stderr +++ b/src/test/ui/lint/implicit_unsafe_autorefs.stderr @@ -5,6 +5,7 @@ LL | addr_of_mut!((*ptr)[..16]) | ^^^^^^ | = note: creating a reference requires the pointer to be valid and imposes aliasing requirements + = note: a reference is implicitly created because a user-defined indexing operation is being called = note: `#[warn(implicit_unsafe_autorefs)]` on by default help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | @@ -18,6 +19,7 @@ LL | addr_of!((*ptr)[..16]) | ^^^^^^ | = note: creating a reference requires the pointer to be valid and imposes aliasing requirements + = note: a reference is implicitly created because a user-defined indexing operation is being called help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | addr_of!((&(*ptr))[..16]) @@ -30,6 +32,7 @@ LL | let l = (*ptr).field.len(); | ^^^^^^^^^^^^ | = note: creating a reference requires the pointer to be valid and imposes aliasing requirements + = note: a reference is implicitly created to match the method receiver type help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | let l = (&(*ptr).field).len(); @@ -42,6 +45,7 @@ LL | addr_of!((*ptr).field[..l - 1]) | ^^^^^^^^^^^^ | = note: creating a reference requires the pointer to be valid and imposes aliasing requirements + = note: a reference is implicitly created because a user-defined indexing operation is being called help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | addr_of!((&(*ptr).field)[..l - 1]) @@ -54,6 +58,7 @@ LL | _ = (*a)[0].len(); | ^^^^^^^ | = note: creating a reference requires the pointer to be valid and imposes aliasing requirements + = note: a reference is implicitly created to match the method receiver type help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | _ = (&(*a)[0]).len(); @@ -66,6 +71,7 @@ LL | _ = (*a)[..1][0].len(); | ^^^^ | = note: creating a reference requires the pointer to be valid and imposes aliasing requirements + = note: a reference is implicitly created because a user-defined indexing operation is being called help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | _ = (&(*a))[..1][0].len(); @@ -78,6 +84,7 @@ LL | _ = addr_of!((*ptr).field); | ^^^^^^ | = note: creating a reference requires the pointer to be valid and imposes aliasing requirements + = note: a reference is implicitly created because a deref coercion is being applied help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | _ = addr_of!((&(*ptr)).field); @@ -90,6 +97,7 @@ LL | _ = addr_of_mut!((*ptr).field); | ^^^^^^ | = note: creating a reference requires the pointer to be valid and imposes aliasing requirements + = note: a reference is implicitly created because a deref coercion is being applied help: try using a raw pointer method instead; or if this reference is intentional, make it explicit | LL | _ = addr_of_mut!((&mut (*ptr)).field);