@@ -384,33 +384,23 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
384
384
// StorageDead, but we don't always emit those (notably on unwind paths),
385
385
// so this "extra check" serves as a kind of backup.
386
386
let domain = flow_state. borrows . base_results . operator ( ) ;
387
- for borrow in domain. borrows ( ) {
388
- let root_place = self . prefixes (
389
- & borrow. place ,
390
- PrefixSet :: All
391
- ) . last ( ) . unwrap ( ) ;
392
- match root_place {
393
- Place :: Static ( _) => {
394
- self . access_place (
395
- ContextKind :: StorageDead . new ( loc) ,
396
- ( & root_place, self . mir . source_info ( borrow. location ) . span ) ,
397
- ( Deep , Write ( WriteKind :: StorageDeadOrDrop ) ) ,
398
- LocalMutationIsAllowed :: Yes ,
399
- flow_state
400
- ) ;
401
- }
402
- Place :: Local ( _) => {
403
- self . access_place (
404
- ContextKind :: StorageDead . new ( loc) ,
405
- ( & root_place, self . mir . source_info ( borrow. location ) . span ) ,
406
- ( Shallow ( None ) , Write ( WriteKind :: StorageDeadOrDrop ) ) ,
407
- LocalMutationIsAllowed :: Yes ,
408
- flow_state
409
- ) ;
410
- }
411
- Place :: Projection ( _) => ( )
387
+ let data = domain. borrows ( ) ;
388
+ flow_state. borrows . with_elems_outgoing ( |borrows| for i in borrows {
389
+ let borrow = & data[ i] ;
390
+
391
+ if self . place_is_invalidated_at_exit ( & borrow. place ) {
392
+ debug ! ( "borrow conflicts at exit {:?}" , borrow) ;
393
+ let borrow_span = self . mir . source_info ( borrow. location ) . span ;
394
+ // FIXME: should be talking about the region lifetime instead
395
+ // of just a span here.
396
+ let end_span = domain. opt_region_end_span ( & borrow. region ) ;
397
+
398
+ self . report_borrowed_value_does_not_live_long_enough (
399
+ ContextKind :: StorageDead . new ( loc) ,
400
+ ( & borrow. place , borrow_span) ,
401
+ end_span)
412
402
}
413
- }
403
+ } ) ;
414
404
}
415
405
TerminatorKind :: Goto { target : _ } |
416
406
TerminatorKind :: Unreachable |
@@ -594,7 +584,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
594
584
context, common_prefix, place_span, bk,
595
585
& borrow, end_issued_loan_span)
596
586
}
597
- WriteKind :: StorageDeadOrDrop => {
587
+ WriteKind :: StorageDeadOrDrop => {
598
588
let end_span =
599
589
flow_state. borrows . base_results . operator ( ) . opt_region_end_span (
600
590
& borrow. region ) ;
@@ -751,6 +741,50 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
751
741
Operand :: Constant ( _) => { }
752
742
}
753
743
}
744
+
745
+ /// Returns whether a borrow of this place is invalidated when the function
746
+ /// exits
747
+ fn place_is_invalidated_at_exit ( & self , place : & Place < ' tcx > ) -> bool {
748
+ debug ! ( "place_is_invalidated_at_exit({:?})" , place) ;
749
+ let root_place = self . prefixes ( place, PrefixSet :: All ) . last ( ) . unwrap ( ) ;
750
+
751
+ // FIXME(nll-rfc#40): do more precise destructor tracking here. For now
752
+ // we just know that all locals are dropped at function exit (otherwise
753
+ // we'll have a memory leak) and assume that all statics have a destructor.
754
+ let ( might_be_alive, will_be_dropped) = match root_place {
755
+ Place :: Static ( statik) => {
756
+ // Thread-locals might be dropped after the function exits, but
757
+ // "true" statics will never be.
758
+ let is_thread_local = self . tcx . get_attrs ( statik. def_id ) . iter ( ) . any ( |attr| {
759
+ attr. check_name ( "thread_local" )
760
+ } ) ;
761
+
762
+ ( true , is_thread_local)
763
+ }
764
+ Place :: Local ( _) => {
765
+ // Locals are always dropped at function exit, and if they
766
+ // have a destructor it would've been called already.
767
+ ( false , true )
768
+ }
769
+ Place :: Projection ( ..) => bug ! ( "root of {:?} is a projection ({:?})?" ,
770
+ place, root_place)
771
+ } ;
772
+
773
+ if !will_be_dropped {
774
+ debug ! ( "place_is_invalidated_at_exit({:?}) - won't be dropped" , place) ;
775
+ return false ;
776
+ }
777
+
778
+ // FIXME: replace this with a proper borrow_conflicts_with_place when
779
+ // that is merged.
780
+ let prefix_set = if might_be_alive {
781
+ PrefixSet :: Supporting
782
+ } else {
783
+ PrefixSet :: Shallow
784
+ } ;
785
+
786
+ self . prefixes ( place, prefix_set) . any ( |prefix| prefix == root_place)
787
+ }
754
788
}
755
789
756
790
impl < ' cx , ' gcx , ' tcx > MirBorrowckCtxt < ' cx , ' gcx , ' tcx > {
@@ -1667,13 +1701,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1667
1701
1668
1702
fn report_borrowed_value_does_not_live_long_enough ( & mut self ,
1669
1703
_: Context ,
1670
- ( place, span) : ( & Place , Span ) ,
1704
+ ( place, span) : ( & Place < ' tcx > , Span ) ,
1671
1705
end_span : Option < Span > ) {
1672
- let proper_span = match * place {
1706
+ let root_place = self . prefixes ( place, PrefixSet :: All ) . last ( ) . unwrap ( ) ;
1707
+ let proper_span = match * root_place {
1673
1708
Place :: Local ( local) => self . mir . local_decls [ local] . source_info . span ,
1674
1709
_ => span
1675
1710
} ;
1676
-
1677
1711
let mut err = self . tcx . path_does_not_live_long_enough ( span, "borrowed value" , Origin :: Mir ) ;
1678
1712
err. span_label ( proper_span, "temporary value created here" ) ;
1679
1713
err. span_label ( span, "temporary value dropped here while still borrowed" ) ;
@@ -2162,4 +2196,12 @@ impl<BD> FlowInProgress<BD> where BD: BitDenotation {
2162
2196
let univ = self . base_results . sets ( ) . bits_per_block ( ) ;
2163
2197
self . curr_state . elems ( univ)
2164
2198
}
2199
+
2200
+ fn with_elems_outgoing < F > ( & self , f : F ) where F : FnOnce ( indexed_set:: Elems < BD :: Idx > ) {
2201
+ let mut curr_state = self . curr_state . clone ( ) ;
2202
+ curr_state. union ( & self . stmt_gen ) ;
2203
+ curr_state. subtract ( & self . stmt_kill ) ;
2204
+ let univ = self . base_results . sets ( ) . bits_per_block ( ) ;
2205
+ f ( curr_state. elems ( univ) ) ;
2206
+ }
2165
2207
}
0 commit comments