@@ -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 }
@@ -194,8 +193,24 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> {
194193 return ;
195194 }
196195
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+ } ;
199214 // Ideally we'd support this in the future, but for now we are limited to sized types.
200215 if !pointee_ty. is_sized ( self . tcx , self . typing_env ) {
201216 trace ! ( "Raw pointer, but pointee is not known to be sized: {:?}" , pointer_ty) ;
0 commit comments