| 
102 | 102 | 
 
  | 
103 | 103 | use std::borrow::Cow;  | 
104 | 104 | 
 
  | 
 | 105 | +use itertools::Itertools;  | 
105 | 106 | use rustc_abi::FieldIdx;  | 
106 | 107 | use rustc_index::bit_set::DenseBitSet;  | 
107 | 108 | use rustc_index::{IndexSlice, IndexVec};  | 
@@ -261,6 +262,28 @@ impl RelocateUpvars {  | 
261 | 262 |             | ty::InstanceKind::FnPtrAddrShim(..) => unreachable!(),  | 
262 | 263 |         };  | 
263 | 264 | 
 
  | 
 | 265 | +        // HACK: in case `AddRetag` is already run, we have one `Retag` at the body entrance  | 
 | 266 | +        // so we need to make sure that first `Retag` is run.  | 
 | 267 | +        let last_retag = body.basic_blocks[START_BLOCK]  | 
 | 268 | +            .statements  | 
 | 269 | +            .iter()  | 
 | 270 | +            .find_position(|stmt| !matches!(stmt.kind, StatementKind::Retag(_, _)));  | 
 | 271 | +        let retagged_start_block = if let Some((index, _)) = last_retag {  | 
 | 272 | +            let span = body.span;  | 
 | 273 | +            let bbs = body.basic_blocks_mut();  | 
 | 274 | +            let stmts = bbs[START_BLOCK].statements.split_off(index);  | 
 | 275 | +            let terminator = bbs[START_BLOCK].terminator.take();  | 
 | 276 | +            let split_start_block = bbs.push(BasicBlockData::new_stmts(stmts, terminator, false));  | 
 | 277 | +            bbs[START_BLOCK].statements.shrink_to_fit();  | 
 | 278 | +            bbs[START_BLOCK].terminator = Some(Terminator {  | 
 | 279 | +                kind: TerminatorKind::Goto { target: split_start_block },  | 
 | 280 | +                source_info: SourceInfo::outermost(span),  | 
 | 281 | +            });  | 
 | 282 | +            Some(split_start_block)  | 
 | 283 | +        } else {  | 
 | 284 | +            None  | 
 | 285 | +        };  | 
 | 286 | + | 
264 | 287 |         if let Some(mir_dumper) = MirDumper::new(tcx, "RelocateUpvars", body) {  | 
265 | 288 |             mir_dumper.set_disambiguator(&"before").dump_mir(body);  | 
266 | 289 |         }  | 
@@ -308,7 +331,7 @@ impl RelocateUpvars {  | 
308 | 331 |         SubstituteUpvarVisitor { tcx, mappings: &substitution_mapping }.visit_body(body);  | 
309 | 332 | 
 
  | 
310 | 333 |         rewrite_drop_coroutine_struct(tcx, body, &substitution_mapping);  | 
311 |  | -        insert_substitution_prologue(body, &substitution_mapping);  | 
 | 334 | +        insert_substitution_prologue(body, retagged_start_block, &substitution_mapping);  | 
312 | 335 |         patch_missing_storage_deads(tcx, body, &substitution_mapping);  | 
313 | 336 |         hydrate_var_debug_info(body, &substitution_mapping);  | 
314 | 337 |         if let Some(mir_dumper) = MirDumper::new(tcx, "RelocateUpvars", body) {  | 
@@ -445,10 +468,11 @@ fn rewrite_drop_coroutine_struct<'tcx>(  | 
445 | 468 | 
 
  | 
446 | 469 | fn insert_substitution_prologue<'tcx>(  | 
447 | 470 |     body: &mut Body<'tcx>,  | 
 | 471 | +    retagged_start_block: Option<BasicBlock>,  | 
448 | 472 |     substitution_mapping: &IndexSlice<FieldIdx, UpvarSubstitution<'tcx>>,  | 
449 | 473 | ) {  | 
450 | 474 |     let mut patch = MirPatch::new(body);  | 
451 |  | -    let mut stmts = Vec::with_capacity(2 * substitution_mapping.len());  | 
 | 475 | +    let mut stmts = Vec::with_capacity(5 * substitution_mapping.len());  | 
452 | 476 |     for &UpvarSubstitution { local, reloc, upvar_place, span, name: _ } in substitution_mapping {  | 
453 | 477 |         // For each upvar-local _$i  | 
454 | 478 |         let source_info = SourceInfo::outermost(span);  | 
@@ -481,22 +505,30 @@ fn insert_substitution_prologue<'tcx>(  | 
481 | 505 |     let source_info = SourceInfo::outermost(body.span);  | 
482 | 506 |     let prologue = patch.new_block(BasicBlockData::new_stmts(  | 
483 | 507 |         stmts,  | 
484 |  | -        Some(Terminator { source_info, kind: TerminatorKind::Goto { target: START_BLOCK } }),  | 
 | 508 | +        Some(Terminator {  | 
 | 509 | +            source_info,  | 
 | 510 | +            kind: TerminatorKind::Goto { target: retagged_start_block.unwrap_or(START_BLOCK) },  | 
 | 511 | +        }),  | 
485 | 512 |         false,  | 
486 | 513 |     ));  | 
487 | 514 |     patch.apply(body);  | 
488 | 515 | 
 
  | 
489 | 516 |     // Manually patch so that prologue is the new entry-point  | 
490 |  | -    let preds = body.basic_blocks.predecessors()[START_BLOCK].clone();  | 
491 |  | -    let basic_blocks = body.basic_blocks.as_mut();  | 
492 |  | -    for pred in preds {  | 
493 |  | -        basic_blocks[pred].terminator_mut().successors_mut(|target| {  | 
494 |  | -            if *target == START_BLOCK {  | 
495 |  | -                *target = prologue;  | 
496 |  | -            }  | 
497 |  | -        });  | 
 | 517 | +    if retagged_start_block.is_some() {  | 
 | 518 | +        let basic_blocks = body.basic_blocks.as_mut();  | 
 | 519 | +        basic_blocks[START_BLOCK].terminator_mut().successors_mut(|target| *target = prologue);  | 
 | 520 | +    } else {  | 
 | 521 | +        let preds = body.basic_blocks.predecessors()[START_BLOCK].clone();  | 
 | 522 | +        let basic_blocks = body.basic_blocks.as_mut();  | 
 | 523 | +        for pred in preds {  | 
 | 524 | +            basic_blocks[pred].terminator_mut().successors_mut(|target| {  | 
 | 525 | +                if *target == START_BLOCK {  | 
 | 526 | +                    *target = prologue;  | 
 | 527 | +                }  | 
 | 528 | +            });  | 
 | 529 | +        }  | 
 | 530 | +        basic_blocks.swap(START_BLOCK, prologue);  | 
498 | 531 |     }  | 
499 |  | -    basic_blocks.swap(START_BLOCK, prologue);  | 
500 | 532 | }  | 
501 | 533 | 
 
  | 
502 | 534 | /// Occasionally there are upvar locals left without `StorageDead` because  | 
 | 
0 commit comments