1
1
use crate :: { LateContext , LateLintPass , LintContext } ;
2
2
3
3
use rustc_errors:: Applicability ;
4
- use rustc_hir:: { Expr , ExprKind , Mutability , UnOp } ;
4
+ use rustc_hir:: { self as hir , Expr , ExprKind , Mutability , UnOp } ;
5
5
use rustc_middle:: ty:: {
6
6
adjustment:: { Adjust , Adjustment , AutoBorrow , OverloadedDeref } ,
7
7
TyCtxt , TypeckResults ,
@@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitUnsafeAutorefs {
63
63
if let Some ( adjustments) = adjustments_table. get ( expr. hir_id )
64
64
&& let [ adjustment] = & * * adjustments
65
65
// An auto-borrow
66
- && let Some ( mutbl) = has_implicit_borrow ( adjustment)
66
+ && let Some ( ( mutbl, implicit_borrow ) ) = has_implicit_borrow ( adjustment)
67
67
// ... of a place derived from a deref
68
68
&& let ExprKind :: Unary ( UnOp :: Deref , dereferenced) = peel_place_mappers ( cx. tcx , typeck, & expr) . kind
69
69
// ... of a raw pointer
@@ -74,7 +74,13 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitUnsafeAutorefs {
74
74
let msg = "implicit auto-ref creates a reference to a dereference of a raw pointer" ;
75
75
cx. struct_span_lint ( IMPLICIT_UNSAFE_AUTOREFS , expr. span , msg, |lint| {
76
76
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
78
84
. multipart_suggestion (
79
85
"try using a raw pointer method instead; or if this reference is intentional, make it explicit" ,
80
86
vec ! [
@@ -111,10 +117,43 @@ fn peel_place_mappers<'tcx>(
111
117
}
112
118
113
119
/// 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 ) > {
115
123
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 ) ) ,
118
126
_ => None ,
119
127
}
120
128
}
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
+ }
0 commit comments