Skip to content

Commit 6b238e6

Browse files
committed
implicit_unsafe_autorefs: note the reason why reference is created
1 parent 356f201 commit 6b238e6

File tree

2 files changed

+53
-6
lines changed

2 files changed

+53
-6
lines changed

compiler/rustc_lint/src/implicit_unsafe_autorefs.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{LateContext, LateLintPass, LintContext};
22

33
use rustc_errors::Applicability;
4-
use rustc_hir::{Expr, ExprKind, Mutability, UnOp};
4+
use rustc_hir::{self as hir, Expr, ExprKind, Mutability, UnOp};
55
use rustc_middle::ty::{
66
adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref},
77
TyCtxt, TypeckResults,
@@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitUnsafeAutorefs {
6363
if let Some(adjustments) = adjustments_table.get(expr.hir_id)
6464
&& let [adjustment] = &**adjustments
6565
// An auto-borrow
66-
&& let Some(mutbl) = has_implicit_borrow(adjustment)
66+
&& let Some((mutbl, implicit_borrow)) = has_implicit_borrow(adjustment)
6767
// ... of a place derived from a deref
6868
&& let ExprKind::Unary(UnOp::Deref, dereferenced) = peel_place_mappers(cx.tcx, typeck, &expr).kind
6969
// ... of a raw pointer
@@ -74,7 +74,13 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitUnsafeAutorefs {
7474
let msg = "implicit auto-ref creates a reference to a dereference of a raw pointer";
7575
cx.struct_span_lint(IMPLICIT_UNSAFE_AUTOREFS, expr.span, msg, |lint| {
7676
lint
77-
.note("creating a reference requires the pointer to be valid and imposes aliasing requirements")
77+
.note("creating a reference requires the pointer to be valid and imposes aliasing requirements");
78+
79+
if let Some(reason) = reason(cx.tcx, implicit_borrow, expr) {
80+
lint.note(format!("a reference is implicitly created {reason}"));
81+
}
82+
83+
lint
7884
.multipart_suggestion(
7985
"try using a raw pointer method instead; or if this reference is intentional, make it explicit",
8086
vec![
@@ -111,10 +117,43 @@ fn peel_place_mappers<'tcx>(
111117
}
112118

113119
/// Returns `Some(mutability)` if the argument adjustment has implicit borrow in it.
114-
fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option<Mutability> {
120+
fn has_implicit_borrow(
121+
Adjustment { kind, .. }: &Adjustment<'_>,
122+
) -> Option<(Mutability, ImplicitBorrow)> {
115123
match kind {
116-
&Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some(mutbl),
117-
&Adjust::Borrow(AutoBorrow::Ref(_, mutbl)) => Some(mutbl.into()),
124+
&Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some((mutbl, ImplicitBorrow::Deref)),
125+
&Adjust::Borrow(AutoBorrow::Ref(_, mutbl)) => Some((mutbl.into(), ImplicitBorrow::Borrow)),
118126
_ => None,
119127
}
120128
}
129+
130+
enum ImplicitBorrow {
131+
Deref,
132+
Borrow,
133+
}
134+
135+
fn reason(tcx: TyCtxt<'_>, borrow_kind: ImplicitBorrow, expr: &Expr<'_>) -> Option<&'static str> {
136+
match borrow_kind {
137+
ImplicitBorrow::Deref => Some("because a deref coercion is being applied"),
138+
ImplicitBorrow::Borrow => {
139+
let parent = tcx.hir().get(tcx.hir().find_parent_node(expr.hir_id)?);
140+
141+
let hir::Node::Expr(expr) = parent else {
142+
return None
143+
};
144+
145+
let reason = match expr.kind {
146+
ExprKind::MethodCall(_, _, _, _) => "to match the method receiver type",
147+
ExprKind::AssignOp(_, _, _) => {
148+
"because a user-defined assignment with an operator is being used"
149+
}
150+
ExprKind::Index(_, _) => {
151+
"because a user-defined indexing operation is being called"
152+
}
153+
_ => return None,
154+
};
155+
156+
Some(reason)
157+
}
158+
}
159+
}

src/test/ui/lint/implicit_unsafe_autorefs.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | addr_of_mut!((*ptr)[..16])
55
| ^^^^^^
66
|
77
= note: creating a reference requires the pointer to be valid and imposes aliasing requirements
8+
= note: a reference is implicitly created because a user-defined indexing operation is being called
89
= note: `#[warn(implicit_unsafe_autorefs)]` on by default
910
help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
1011
|
@@ -18,6 +19,7 @@ LL | addr_of!((*ptr)[..16])
1819
| ^^^^^^
1920
|
2021
= note: creating a reference requires the pointer to be valid and imposes aliasing requirements
22+
= note: a reference is implicitly created because a user-defined indexing operation is being called
2123
help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
2224
|
2325
LL | addr_of!((&(*ptr))[..16])
@@ -30,6 +32,7 @@ LL | let l = (*ptr).field.len();
3032
| ^^^^^^^^^^^^
3133
|
3234
= note: creating a reference requires the pointer to be valid and imposes aliasing requirements
35+
= note: a reference is implicitly created to match the method receiver type
3336
help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
3437
|
3538
LL | let l = (&(*ptr).field).len();
@@ -42,6 +45,7 @@ LL | addr_of!((*ptr).field[..l - 1])
4245
| ^^^^^^^^^^^^
4346
|
4447
= note: creating a reference requires the pointer to be valid and imposes aliasing requirements
48+
= note: a reference is implicitly created because a user-defined indexing operation is being called
4549
help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
4650
|
4751
LL | addr_of!((&(*ptr).field)[..l - 1])
@@ -54,6 +58,7 @@ LL | _ = (*a)[0].len();
5458
| ^^^^^^^
5559
|
5660
= note: creating a reference requires the pointer to be valid and imposes aliasing requirements
61+
= note: a reference is implicitly created to match the method receiver type
5762
help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
5863
|
5964
LL | _ = (&(*a)[0]).len();
@@ -66,6 +71,7 @@ LL | _ = (*a)[..1][0].len();
6671
| ^^^^
6772
|
6873
= note: creating a reference requires the pointer to be valid and imposes aliasing requirements
74+
= note: a reference is implicitly created because a user-defined indexing operation is being called
6975
help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
7076
|
7177
LL | _ = (&(*a))[..1][0].len();
@@ -78,6 +84,7 @@ LL | _ = addr_of!((*ptr).field);
7884
| ^^^^^^
7985
|
8086
= note: creating a reference requires the pointer to be valid and imposes aliasing requirements
87+
= note: a reference is implicitly created because a deref coercion is being applied
8188
help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
8289
|
8390
LL | _ = addr_of!((&(*ptr)).field);
@@ -90,6 +97,7 @@ LL | _ = addr_of_mut!((*ptr).field);
9097
| ^^^^^^
9198
|
9299
= note: creating a reference requires the pointer to be valid and imposes aliasing requirements
100+
= note: a reference is implicitly created because a deref coercion is being applied
93101
help: try using a raw pointer method instead; or if this reference is intentional, make it explicit
94102
|
95103
LL | _ = addr_of_mut!((&mut (*ptr)).field);

0 commit comments

Comments
 (0)