@@ -12,13 +12,13 @@ pub(crate) struct PointerCheck<'tcx> {
1212 pub ( crate ) assert_kind : Box < AssertKind < Operand < ' tcx > > > ,
1313}
1414
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]) .
1818#[ derive( Copy , Clone ) ]
19- pub ( crate ) enum BorrowCheckMode {
20- IncludeBorrows ,
21- ExcludeBorrows ,
19+ pub ( crate ) enum BorrowedFieldProjectionMode {
20+ FollowProjections ,
21+ NoFollowProjections ,
2222}
2323
2424/// Utility for adding a check for read/write on every sized, raw pointer.
@@ -27,8 +27,8 @@ pub(crate) enum BorrowCheckMode {
2727/// new basic block directly before the pointer access. (Read/write accesses
2828/// are determined by the `PlaceContext` of the MIR visitor.) Then calls
2929/// `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.
3232///
3333/// This utility takes care of the right order of blocks, the only thing a
3434/// caller must do in `on_finding` is:
@@ -45,7 +45,7 @@ pub(crate) fn check_pointers<'tcx, F>(
4545 body : & mut Body < ' tcx > ,
4646 excluded_pointees : & [ Ty < ' tcx > ] ,
4747 on_finding : F ,
48- borrow_check_mode : BorrowCheckMode ,
48+ field_projection_mode : BorrowedFieldProjectionMode ,
4949) where
5050 F : Fn (
5151 /* tcx: */ TyCtxt < ' tcx > ,
@@ -82,7 +82,7 @@ pub(crate) fn check_pointers<'tcx, F>(
8282 local_decls,
8383 typing_env,
8484 excluded_pointees,
85- borrow_check_mode ,
85+ field_projection_mode ,
8686 ) ;
8787 finder. visit_statement ( statement, location) ;
8888
@@ -128,7 +128,7 @@ struct PointerFinder<'a, 'tcx> {
128128 typing_env : ty:: TypingEnv < ' tcx > ,
129129 pointers : Vec < ( Place < ' tcx > , Ty < ' tcx > , PlaceContext ) > ,
130130 excluded_pointees : & ' a [ Ty < ' tcx > ] ,
131- borrow_check_mode : BorrowCheckMode ,
131+ field_projection_mode : BorrowedFieldProjectionMode ,
132132}
133133
134134impl < ' a , ' tcx > PointerFinder < ' a , ' tcx > {
@@ -137,15 +137,15 @@ impl<'a, 'tcx> PointerFinder<'a, 'tcx> {
137137 local_decls : & ' a mut LocalDecls < ' tcx > ,
138138 typing_env : ty:: TypingEnv < ' tcx > ,
139139 excluded_pointees : & ' a [ Ty < ' tcx > ] ,
140- borrow_check_mode : BorrowCheckMode ,
140+ field_projection_mode : BorrowedFieldProjectionMode ,
141141 ) -> Self {
142142 PointerFinder {
143143 tcx,
144144 local_decls,
145145 typing_env,
146146 excluded_pointees,
147147 pointers : Vec :: new ( ) ,
148- borrow_check_mode ,
148+ field_projection_mode ,
149149 }
150150 }
151151
@@ -163,15 +163,14 @@ impl<'a, 'tcx> PointerFinder<'a, 'tcx> {
163163 MutatingUseContext :: Store
164164 | MutatingUseContext :: Call
165165 | MutatingUseContext :: Yield
166- | MutatingUseContext :: Drop ,
166+ | MutatingUseContext :: Drop
167+ | MutatingUseContext :: Borrow ,
167168 ) => true ,
168169 PlaceContext :: NonMutatingUse (
169- NonMutatingUseContext :: Copy | NonMutatingUseContext :: Move ,
170+ NonMutatingUseContext :: Copy
171+ | NonMutatingUseContext :: Move
172+ | NonMutatingUseContext :: SharedBorrow ,
170173 ) => true ,
171- PlaceContext :: MutatingUse ( MutatingUseContext :: Borrow )
172- | PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: SharedBorrow ) => {
173- matches ! ( self . borrow_check_mode, BorrowCheckMode :: IncludeBorrows )
174- }
175174 _ => false ,
176175 }
177176 }
@@ -183,19 +182,29 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> {
183182 return ;
184183 }
185184
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.
188186 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 ;
190188
191189 // 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 {
193191 trace ! ( "Indirect, but not based on an raw ptr, not checking {:?}" , place) ;
194192 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 ;
195206 }
196207
197- let pointee_ty =
198- pointer_ty. builtin_deref ( true ) . expect ( "no builtin_deref for an raw pointer" ) ;
199208 // Ideally we'd support this in the future, but for now we are limited to sized types.
200209 if !pointee_ty. is_sized ( self . tcx , self . typing_env ) {
201210 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> {
207216 ty:: Array ( ty, _) => * ty,
208217 _ => pointee_ty,
209218 } ;
219+ // Check if we excluded this pointee type from the check.
210220 if self . excluded_pointees . contains ( & element_ty) {
211221 trace ! ( "Skipping pointer for type: {:?}" , pointee_ty) ;
212222 return ;
0 commit comments