@@ -384,33 +384,23 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
384384 // StorageDead, but we don't always emit those (notably on unwind paths),
385385 // so this "extra check" serves as a kind of backup.
386386 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)
412402 }
413- }
403+ } ) ;
414404 }
415405 TerminatorKind :: Goto { target : _ } |
416406 TerminatorKind :: Unreachable |
@@ -594,7 +584,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
594584 context, common_prefix, place_span, bk,
595585 & borrow, end_issued_loan_span)
596586 }
597- WriteKind :: StorageDeadOrDrop => {
587+ WriteKind :: StorageDeadOrDrop => {
598588 let end_span =
599589 flow_state. borrows . base_results . operator ( ) . opt_region_end_span (
600590 & borrow. region ) ;
@@ -751,6 +741,50 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
751741 Operand :: Constant ( _) => { }
752742 }
753743 }
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+ }
754788}
755789
756790impl < ' cx , ' gcx , ' tcx > MirBorrowckCtxt < ' cx , ' gcx , ' tcx > {
@@ -1667,13 +1701,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
16671701
16681702 fn report_borrowed_value_does_not_live_long_enough ( & mut self ,
16691703 _: Context ,
1670- ( place, span) : ( & Place , Span ) ,
1704+ ( place, span) : ( & Place < ' tcx > , Span ) ,
16711705 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 {
16731708 Place :: Local ( local) => self . mir . local_decls [ local] . source_info . span ,
16741709 _ => span
16751710 } ;
1676-
16771711 let mut err = self . tcx . path_does_not_live_long_enough ( span, "borrowed value" , Origin :: Mir ) ;
16781712 err. span_label ( proper_span, "temporary value created here" ) ;
16791713 err. span_label ( span, "temporary value dropped here while still borrowed" ) ;
@@ -2162,4 +2196,12 @@ impl<BD> FlowInProgress<BD> where BD: BitDenotation {
21622196 let univ = self . base_results . sets ( ) . bits_per_block ( ) ;
21632197 self . curr_state . elems ( univ)
21642198 }
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+ }
21652207}
0 commit comments