@@ -12,13 +12,13 @@ pub(crate) struct PointerCheck<'tcx> {
12
12
pub ( crate ) assert_kind : Box < AssertKind < Operand < ' tcx > > > ,
13
13
}
14
14
15
- /// Indicates whether we insert the checks for borrow places of a raw pointer.
16
- /// Concretely places with [MutatingUseContext::Borrow] or
17
- /// [NonMutatingUseContext::SharedBorrow] .
15
+ /// When checking for borrows of field projections (`&(*ptr).a`), we might want
16
+ /// to check for the field type (type of `.a` in the example). This enum defines
17
+ /// the variations (pass the pointer [Ty] or the field [Ty]) .
18
18
#[ derive( Copy , Clone ) ]
19
- pub ( crate ) enum BorrowCheckMode {
20
- IncludeBorrows ,
21
- ExcludeBorrows ,
19
+ pub ( crate ) enum BorrowedFieldProjectionMode {
20
+ FollowProjections ,
21
+ NoFollowProjections ,
22
22
}
23
23
24
24
/// Utility for adding a check for read/write on every sized, raw pointer.
@@ -27,8 +27,8 @@ pub(crate) enum BorrowCheckMode {
27
27
/// new basic block directly before the pointer access. (Read/write accesses
28
28
/// are determined by the `PlaceContext` of the MIR visitor.) Then calls
29
29
/// `on_finding` to insert the actual logic for a pointer check (e.g. check for
30
- /// alignment). A check can choose to be inserted for (mutable) borrows of
31
- /// raw pointers via the `borrow_check_mode ` parameter.
30
+ /// alignment). A check can choose to follow borrows of field projections via
31
+ /// the `field_projection_mode ` parameter.
32
32
///
33
33
/// This utility takes care of the right order of blocks, the only thing a
34
34
/// caller must do in `on_finding` is:
@@ -45,7 +45,7 @@ pub(crate) fn check_pointers<'tcx, F>(
45
45
body : & mut Body < ' tcx > ,
46
46
excluded_pointees : & [ Ty < ' tcx > ] ,
47
47
on_finding : F ,
48
- borrow_check_mode : BorrowCheckMode ,
48
+ field_projection_mode : BorrowedFieldProjectionMode ,
49
49
) where
50
50
F : Fn (
51
51
/* tcx: */ TyCtxt < ' tcx > ,
@@ -82,7 +82,7 @@ pub(crate) fn check_pointers<'tcx, F>(
82
82
local_decls,
83
83
typing_env,
84
84
excluded_pointees,
85
- borrow_check_mode ,
85
+ field_projection_mode ,
86
86
) ;
87
87
finder. visit_statement ( statement, location) ;
88
88
@@ -128,7 +128,7 @@ struct PointerFinder<'a, 'tcx> {
128
128
typing_env : ty:: TypingEnv < ' tcx > ,
129
129
pointers : Vec < ( Place < ' tcx > , Ty < ' tcx > , PlaceContext ) > ,
130
130
excluded_pointees : & ' a [ Ty < ' tcx > ] ,
131
- borrow_check_mode : BorrowCheckMode ,
131
+ field_projection_mode : BorrowedFieldProjectionMode ,
132
132
}
133
133
134
134
impl < ' a , ' tcx > PointerFinder < ' a , ' tcx > {
@@ -137,15 +137,15 @@ impl<'a, 'tcx> PointerFinder<'a, 'tcx> {
137
137
local_decls : & ' a mut LocalDecls < ' tcx > ,
138
138
typing_env : ty:: TypingEnv < ' tcx > ,
139
139
excluded_pointees : & ' a [ Ty < ' tcx > ] ,
140
- borrow_check_mode : BorrowCheckMode ,
140
+ field_projection_mode : BorrowedFieldProjectionMode ,
141
141
) -> Self {
142
142
PointerFinder {
143
143
tcx,
144
144
local_decls,
145
145
typing_env,
146
146
excluded_pointees,
147
147
pointers : Vec :: new ( ) ,
148
- borrow_check_mode ,
148
+ field_projection_mode ,
149
149
}
150
150
}
151
151
@@ -163,15 +163,14 @@ impl<'a, 'tcx> PointerFinder<'a, 'tcx> {
163
163
MutatingUseContext :: Store
164
164
| MutatingUseContext :: Call
165
165
| MutatingUseContext :: Yield
166
- | MutatingUseContext :: Drop ,
166
+ | MutatingUseContext :: Drop
167
+ | MutatingUseContext :: Borrow ,
167
168
) => true ,
168
169
PlaceContext :: NonMutatingUse (
169
- NonMutatingUseContext :: Copy | NonMutatingUseContext :: Move ,
170
+ NonMutatingUseContext :: Copy
171
+ | NonMutatingUseContext :: Move
172
+ | NonMutatingUseContext :: SharedBorrow ,
170
173
) => true ,
171
- PlaceContext :: MutatingUse ( MutatingUseContext :: Borrow )
172
- | PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: SharedBorrow ) => {
173
- matches ! ( self . borrow_check_mode, BorrowCheckMode :: IncludeBorrows )
174
- }
175
174
_ => false ,
176
175
}
177
176
}
@@ -183,19 +182,29 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> {
183
182
return ;
184
183
}
185
184
186
- // Since Deref projections must come first and only once, the pointer for an indirect place
187
- // is the Local that the Place is based on.
185
+ // Get the place and type we visit.
188
186
let pointer = Place :: from ( place. local ) ;
189
- let pointer_ty = self . local_decls [ place . local ] . ty ;
187
+ let pointer_ty = pointer . ty ( self . local_decls , self . tcx ) . ty ;
190
188
191
189
// We only want to check places based on raw pointers
192
- if ! pointer_ty. is_raw_ptr ( ) {
190
+ let & ty :: RawPtr ( mut pointee_ty , _ ) = pointer_ty. kind ( ) else {
193
191
trace ! ( "Indirect, but not based on an raw ptr, not checking {:?}" , place) ;
194
192
return ;
193
+ } ;
194
+
195
+ // If we see a borrow of a field projection, we want to pass the field type to the
196
+ // check and not the pointee type.
197
+ if matches ! ( self . field_projection_mode, BorrowedFieldProjectionMode :: FollowProjections )
198
+ && matches ! (
199
+ context,
200
+ PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: SharedBorrow )
201
+ | PlaceContext :: MutatingUse ( MutatingUseContext :: Borrow )
202
+ )
203
+ {
204
+ // Naturally, the field type is type of the initial place we look at.
205
+ pointee_ty = place. ty ( self . local_decls , self . tcx ) . ty ;
195
206
}
196
207
197
- let pointee_ty =
198
- pointer_ty. builtin_deref ( true ) . expect ( "no builtin_deref for an raw pointer" ) ;
199
208
// Ideally we'd support this in the future, but for now we are limited to sized types.
200
209
if !pointee_ty. is_sized ( self . tcx , self . typing_env ) {
201
210
trace ! ( "Raw pointer, but pointee is not known to be sized: {:?}" , pointer_ty) ;
@@ -207,6 +216,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> {
207
216
ty:: Array ( ty, _) => * ty,
208
217
_ => pointee_ty,
209
218
} ;
219
+ // Check if we excluded this pointee type from the check.
210
220
if self . excluded_pointees . contains ( & element_ty) {
211
221
trace ! ( "Skipping pointer for type: {:?}" , pointee_ty) ;
212
222
return ;
0 commit comments