Skip to content

Commit

Permalink
implicit_unsafe_autorefs: note the reason why reference is created
Browse files Browse the repository at this point in the history
  • Loading branch information
WaffleLapkin committed Nov 7, 2022
1 parent 356f201 commit 6b238e6
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 6 deletions.
51 changes: 45 additions & 6 deletions compiler/rustc_lint/src/implicit_unsafe_autorefs.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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![
Expand Down Expand Up @@ -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<Mutability> {
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)
}
}
}
8 changes: 8 additions & 0 deletions src/test/ui/lint/implicit_unsafe_autorefs.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand All @@ -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])
Expand All @@ -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();
Expand All @@ -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])
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit 6b238e6

Please sign in to comment.