@@ -128,9 +128,8 @@ use rustc_data_structures::graph::implementation::{Graph, NodeIndex};
128
128
use rustc_middle:: mir:: visit:: PlaceContext ;
129
129
use rustc_middle:: mir:: visit:: Visitor ;
130
130
use rustc_middle:: mir:: * ;
131
- use rustc_middle:: ty:: { self , Ty , TypeSuperVisitable , TypeVisitable } ;
131
+ use rustc_middle:: ty;
132
132
133
- use core:: ops:: ControlFlow ;
134
133
use either:: Either ;
135
134
136
135
#[ derive( Copy , Clone , Debug ) ]
@@ -158,43 +157,6 @@ impl NodeKind {
158
157
}
159
158
}
160
159
161
- /// TypeVisitor that looks for `ty::Ref`, `ty::RawPtr`. Additionally looks for `ty::Param`,
162
- /// which could themselves refer to references or raw pointers.
163
- struct MaybeHasRefsOrPointersVisitor {
164
- has_refs_or_pointers : bool ,
165
- has_params : bool ,
166
- }
167
-
168
- impl MaybeHasRefsOrPointersVisitor {
169
- fn new ( ) -> Self {
170
- MaybeHasRefsOrPointersVisitor { has_refs_or_pointers : false , has_params : false }
171
- }
172
- }
173
-
174
- impl < ' tcx > ty:: TypeVisitor < TyCtxt < ' tcx > > for MaybeHasRefsOrPointersVisitor {
175
- type BreakTy = ( ) ;
176
-
177
- #[ instrument( skip( self ) , level = "debug" ) ]
178
- fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
179
- match ty. kind ( ) {
180
- ty:: Ref ( ..) => {
181
- self . has_refs_or_pointers = true ;
182
- return ControlFlow :: Break ( ( ) ) ;
183
- }
184
- ty:: RawPtr ( ..) => {
185
- self . has_refs_or_pointers = true ;
186
- return ControlFlow :: Break ( ( ) ) ;
187
- }
188
- ty:: Param ( _) => {
189
- self . has_params = true ;
190
- }
191
- _ => { }
192
- }
193
-
194
- ty. super_visit_with ( self )
195
- }
196
- }
197
-
198
160
/// Used to build a dependency graph between borrows/pointers and the `Local`s that
199
161
/// they reference.
200
162
/// We add edges to the graph in two kinds of situations:
@@ -265,6 +227,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
265
227
match & statement. kind {
266
228
StatementKind :: Assign ( assign) => {
267
229
let assign_place = assign. 0 ;
230
+ debug ! ( "assign_place_ty: {:?}" , assign_place. ty( self . local_decls, self . tcx) . ty) ;
268
231
let assign_local = assign_place. local ;
269
232
self . current_local = Some ( assign_local) ;
270
233
debug ! ( "set current_local to {:?}" , self . current_local) ;
@@ -305,12 +268,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
305
268
let src_node_kind = NodeKind :: Borrow ( src_local) ;
306
269
let src_node_idx = self . maybe_create_node ( src_node_kind) ;
307
270
308
- let node_idx = if let Some ( node_idx) = self . locals_to_node_indexes . get ( & place. local )
309
- {
310
- * node_idx
311
- } else {
312
- bug ! ( "should have added a node for the moved borrowed place before" ) ;
313
- } ;
271
+ let node_kind = NodeKind :: Borrow ( place. local ) ;
272
+ let node_idx = self . maybe_create_node ( node_kind) ;
314
273
315
274
debug ! (
316
275
"adding edge from {:?}({:?}) -> {:?}({:?})" ,
@@ -346,10 +305,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
346
305
347
306
self . dep_graph . add_edge ( src_node_idx, node_idx, ( ) ) ;
348
307
}
349
- _ => {
350
- // FIXME Need to also create edges for `Local`s that correspond to `NodeKind::LocalWithRefs` here
308
+ Rvalue :: Cast ( ..) => {
309
+ // FIXME we probably should handle pointer casts here directly
310
+
351
311
self . super_rvalue ( rvalue, location)
352
312
}
313
+ _ => self . super_rvalue ( rvalue, location) ,
353
314
}
354
315
}
355
316
@@ -385,7 +346,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
385
346
None => { }
386
347
} ,
387
348
_ => {
388
- // FIXME Need to also create edges for `Local`s that correspond to `NodeKind::LocalWithRefs` here
349
+ // FIXME I think we probably need to introduce edges here if `place.local`
350
+ // corresponds to a `NodeKind::LocalWithRefs`
389
351
}
390
352
}
391
353
@@ -404,26 +366,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
404
366
let dest_ty = destination. ty ( self . local_decls , self . tcx ) . ty ;
405
367
debug ! ( ?dest_ty) ;
406
368
407
- let mut has_refs_or_pointers_visitor = MaybeHasRefsOrPointersVisitor :: new ( ) ;
408
- dest_ty. visit_with ( & mut has_refs_or_pointers_visitor) ;
409
-
410
- let dest_might_include_refs_or_pointers =
411
- if has_refs_or_pointers_visitor. has_refs_or_pointers {
412
- true
413
- } else if has_refs_or_pointers_visitor. has_params {
414
- // if we pass in any references or raw pointers as arguments and the
415
- // return type includes type parameters, these type parameters could
416
- // refer to those refs/ptrs, so we have to be conservative here and possibly
417
- // include an edge.
418
- true
419
- } else {
420
- false
421
- } ;
422
-
423
- if dest_might_include_refs_or_pointers {
424
- self . current_local = Some ( destination. local ) ;
425
- debug ! ( "self.current_local: {:?}" , self . current_local) ;
426
- }
369
+ // To ensure safety we need to add `destination` to the graph as a `Node` with `NodeKind::LocalWithRefs`
370
+ // if we pass in any refs/ptrs or `Local`s corresponding to `NodeKind::LocalWithRefs`. The reason for this
371
+ // is that the function could include those refs/ptrs in its return value. It's not sufficient
372
+ // to look for the existence of `ty::Ref` or `ty::RawPtr` in the type of the return type, since the
373
+ // function could also cast pointers to integers e.g. .
374
+ self . current_local = Some ( destination. local ) ;
427
375
428
376
self . visit_operand ( func, location) ;
429
377
for arg in args {
@@ -436,26 +384,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowDependencies<'a, 'tcx> {
436
384
let resume_arg_ty = resume_arg. ty ( self . local_decls , self . tcx ) . ty ;
437
385
debug ! ( ?resume_arg_ty) ;
438
386
439
- let mut has_refs_or_pointers_visitor = MaybeHasRefsOrPointersVisitor :: new ( ) ;
440
- resume_arg_ty. visit_with ( & mut has_refs_or_pointers_visitor) ;
441
-
442
- let dest_might_include_refs_or_pointers =
443
- if has_refs_or_pointers_visitor. has_refs_or_pointers {
444
- true
445
- } else if has_refs_or_pointers_visitor. has_params {
446
- // if we pass in any references or raw pointers as arguments and the
447
- // return type includes type parameters, these type parameters could
448
- // refer to those refs/ptrs, so we have to be conservative here and possibly
449
- // include an edge.
450
- true
451
- } else {
452
- false
453
- } ;
454
-
455
- if dest_might_include_refs_or_pointers {
456
- self . current_local = Some ( resume_arg. local ) ;
457
- debug ! ( "self.current_local: {:?}" , self . current_local) ;
458
- }
387
+ // We may need to add edges from `destination`, see the comment for this statement
388
+ // in `TerminatorKind::Call` for the rationale behind this.
389
+ self . current_local = Some ( resume_arg. local ) ;
459
390
460
391
self . super_operand ( value, location) ;
461
392
}
@@ -578,6 +509,7 @@ pub fn get_borrowed_locals_results<'mir, 'tcx>(
578
509
)
579
510
}
580
511
}
512
+
581
513
let live_borrows = LiveBorrows :: new ( body, tcx, borrow_deps) ;
582
514
let results =
583
515
live_borrows. into_engine ( tcx, body) . pass_name ( "borrowed_locals" ) . iterate_to_fixpoint ( ) ;
@@ -763,6 +695,15 @@ where
763
695
self . visit_rvalue ( & assign. 1 , location) ;
764
696
}
765
697
_ => {
698
+ if let Some ( node_idx) =
699
+ self . borrow_deps . locals_to_node_indexes . get ( & lhs_place. local )
700
+ {
701
+ let node = self . borrow_deps . dep_graph . node ( * node_idx) ;
702
+ if let NodeKind :: LocalWithRefs ( _) = node. data {
703
+ debug ! ( "killing {:?}" , lhs_place. local) ;
704
+ self . _trans . kill ( lhs_place. local ) ;
705
+ }
706
+ }
766
707
self . super_assign ( & assign. 0 , & assign. 1 , location) ;
767
708
}
768
709
}
@@ -828,18 +769,32 @@ where
828
769
829
770
#[ instrument( skip( self ) , level = "debug" ) ]
830
771
fn visit_terminator ( & mut self , terminator : & mir:: Terminator < ' tcx > , location : Location ) {
831
- match terminator. kind {
832
- TerminatorKind :: Call { destination, .. } => {
833
- debug ! ( "killing {:?}" , destination. local) ;
834
- self . _trans . kill ( destination. local ) ;
772
+ match & terminator. kind {
773
+ TerminatorKind :: Call { destination, args, .. } => {
774
+ match destination. projection . as_slice ( ) {
775
+ & [ ] | & [ ProjectionElem :: OpaqueCast ( _) ] => {
776
+ debug ! ( "killing {:?}" , destination. local) ;
777
+ self . _trans . kill ( destination. local ) ;
778
+
779
+ for arg in args {
780
+ self . visit_operand ( arg, location)
781
+ }
782
+ }
783
+ _ => self . super_terminator ( terminator, location) ,
784
+ }
835
785
}
836
- TerminatorKind :: Yield { resume_arg, .. } => {
837
- debug ! ( "killing {:?}" , resume_arg. local) ;
838
- self . _trans . kill ( resume_arg. local ) ;
786
+ TerminatorKind :: Yield { resume_arg, value, .. } => {
787
+ match resume_arg. projection . as_slice ( ) {
788
+ & [ ] | & [ ProjectionElem :: OpaqueCast ( _) ] => {
789
+ debug ! ( "killing {:?}" , resume_arg. local) ;
790
+ self . _trans . kill ( resume_arg. local ) ;
791
+
792
+ self . visit_operand ( value, location)
793
+ }
794
+ _ => self . super_terminator ( terminator, location) ,
795
+ }
839
796
}
840
- _ => { }
797
+ _ => self . super_terminator ( terminator , location ) ,
841
798
}
842
-
843
- self . super_terminator ( terminator, location) ;
844
799
}
845
800
}
0 commit comments