@@ -794,13 +794,11 @@ fn compute_layout<'tcx>(
794
794
// (RETURNED, POISONED) of the function.
795
795
const RESERVED_VARIANTS : usize = 3 ;
796
796
let body_span = body. source_scopes [ OUTERMOST_SOURCE_SCOPE ] . span ;
797
- let mut variant_source_info: IndexVec < VariantIdx , SourceInfo > = [
797
+ let mut variant_source_info: IndexVec < VariantIdx , SourceInfo > = std :: array :: IntoIter :: new ( [
798
798
SourceInfo :: outermost ( body_span. shrink_to_lo ( ) ) ,
799
799
SourceInfo :: outermost ( body_span. shrink_to_hi ( ) ) ,
800
800
SourceInfo :: outermost ( body_span. shrink_to_hi ( ) ) ,
801
- ]
802
- . iter ( )
803
- . copied ( )
801
+ ] )
804
802
. collect ( ) ;
805
803
806
804
// Build the generator variant field list.
@@ -1258,7 +1256,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
1258
1256
ty:: Generator ( _, substs, movability) => {
1259
1257
let substs = substs. as_generator ( ) ;
1260
1258
(
1261
- substs. upvar_tys ( ) . collect ( ) ,
1259
+ substs. upvar_tys ( ) . collect :: < Vec < _ > > ( ) ,
1262
1260
substs. witness ( ) ,
1263
1261
substs. discr_ty ( tcx) ,
1264
1262
movability == hir:: Movability :: Movable ,
@@ -1291,8 +1289,21 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
1291
1289
1292
1290
// When first entering the generator, move the resume argument into its new local.
1293
1291
let source_info = SourceInfo :: outermost ( body. span ) ;
1294
- let stmts = & mut body. basic_blocks_mut ( ) [ BasicBlock :: new ( 0 ) ] . statements ;
1295
- stmts. insert (
1292
+
1293
+ let mut upvar_collector = ExtractGeneratorUpvarLocals :: default ( ) ;
1294
+ for ( block, data) in body. basic_blocks ( ) . iter_enumerated ( ) {
1295
+ upvar_collector. visit_basic_block_data ( block, data) ;
1296
+ }
1297
+ let upvar_locals = upvar_collector. finish ( ) ;
1298
+ tracing:: info!( "Upvar locals: {:?}" , upvar_locals) ;
1299
+ tracing:: info!( "Upvar count: {:?}" , upvars. len( ) ) ;
1300
+ if upvar_locals. len ( ) != upvars. len ( ) {
1301
+ eprintln ! ( "{:#?}" , body) ;
1302
+ assert_eq ! ( upvar_locals. len( ) , upvars. len( ) ) ;
1303
+ }
1304
+
1305
+ let first_block = & mut body. basic_blocks_mut ( ) [ BasicBlock :: new ( 0 ) ] ;
1306
+ first_block. statements . insert (
1296
1307
0 ,
1297
1308
Statement {
1298
1309
source_info,
@@ -1375,6 +1386,53 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
1375
1386
}
1376
1387
}
1377
1388
1389
+ /// Finds locals that are assigned from generator upvars.
1390
+ #[ derive( Default ) ]
1391
+ struct ExtractGeneratorUpvarLocals {
1392
+ upvar_locals : FxHashMap < Field , Vec < Local > > ,
1393
+ }
1394
+
1395
+ impl ExtractGeneratorUpvarLocals {
1396
+ fn finish ( self ) -> FxHashMap < Field , Vec < Local > > {
1397
+ self . upvar_locals
1398
+ }
1399
+ }
1400
+
1401
+ impl < ' tcx > Visitor < ' tcx > for ExtractGeneratorUpvarLocals {
1402
+ fn visit_assign ( & mut self , place : & Place < ' tcx > , rvalue : & Rvalue < ' tcx > , location : Location ) {
1403
+ let mut visitor = FindGeneratorFieldAccess { field_index : None } ;
1404
+ visitor. visit_rvalue ( rvalue, location) ;
1405
+
1406
+ if let Some ( field_index) = visitor. field_index {
1407
+ self . upvar_locals . entry ( field_index) . or_insert_with ( || vec ! [ ] ) . push ( place. local ) ;
1408
+ }
1409
+ }
1410
+ }
1411
+
1412
+ struct FindGeneratorFieldAccess {
1413
+ field_index : Option < Field > ,
1414
+ }
1415
+
1416
+ impl < ' tcx > Visitor < ' tcx > for FindGeneratorFieldAccess {
1417
+ fn visit_projection (
1418
+ & mut self ,
1419
+ place_ref : PlaceRef < ' tcx > ,
1420
+ _context : PlaceContext ,
1421
+ _location : Location ,
1422
+ ) {
1423
+ tracing:: info!( "visit_projection, place_ref={:#?}" , place_ref) ;
1424
+
1425
+ if place_ref. local . as_usize ( ) == 1 {
1426
+ if !place_ref. projection . is_empty ( ) {
1427
+ if let Some ( ProjectionElem :: Field ( field, _) ) = place_ref. projection . get ( 0 ) {
1428
+ assert ! ( self . field_index. is_none( ) ) ;
1429
+ self . field_index = Some ( * field) ;
1430
+ }
1431
+ }
1432
+ }
1433
+ }
1434
+ }
1435
+
1378
1436
/// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields
1379
1437
/// in the generator state machine but whose storage is not marked as conflicting
1380
1438
///
0 commit comments