@@ -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
}
@@ -194,8 +193,24 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> {
194
193
return ;
195
194
}
196
195
197
- let pointee_ty =
198
- pointer_ty. builtin_deref ( true ) . expect ( "no builtin_deref for an raw pointer" ) ;
196
+ // If we see a borrow of a field projection, we want to pass the field Ty to the
197
+ // check and not the pointee Ty.
198
+ let pointee_ty = match self . field_projection_mode {
199
+ BorrowedFieldProjectionMode :: FollowProjections
200
+ if matches ! (
201
+ context,
202
+ PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: SharedBorrow )
203
+ | PlaceContext :: MutatingUse ( MutatingUseContext :: Borrow )
204
+ ) =>
205
+ {
206
+ if let Some ( PlaceElem :: Field ( _, ty) ) = place. projection . last ( ) {
207
+ * ty
208
+ } else {
209
+ pointer_ty. builtin_deref ( true ) . expect ( "no builtin_deref for an raw pointer" )
210
+ }
211
+ }
212
+ _ => pointer_ty. builtin_deref ( true ) . expect ( "no builtin_deref for an raw pointer" ) ,
213
+ } ;
199
214
// Ideally we'd support this in the future, but for now we are limited to sized types.
200
215
if !pointee_ty. is_sized ( self . tcx , self . typing_env ) {
201
216
trace ! ( "Raw pointer, but pointee is not known to be sized: {:?}" , pointer_ty) ;
0 commit comments