Skip to content

Commit 10941d8

Browse files
make sure that retagging body arguments are the first thing to be done
1 parent fe2be6e commit 10941d8

File tree

2 files changed

+52
-20
lines changed

2 files changed

+52
-20
lines changed

compiler/rustc_mir_transform/src/coroutine/relocate_upvars.rs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102

103103
use std::borrow::Cow;
104104

105+
use itertools::Itertools;
105106
use rustc_abi::FieldIdx;
106107
use rustc_index::bit_set::DenseBitSet;
107108
use rustc_index::{IndexSlice, IndexVec};
@@ -261,6 +262,28 @@ impl RelocateUpvars {
261262
| ty::InstanceKind::FnPtrAddrShim(..) => unreachable!(),
262263
};
263264

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+
264287
if let Some(mir_dumper) = MirDumper::new(tcx, "RelocateUpvars", body) {
265288
mir_dumper.set_disambiguator(&"before").dump_mir(body);
266289
}
@@ -308,7 +331,7 @@ impl RelocateUpvars {
308331
SubstituteUpvarVisitor { tcx, mappings: &substitution_mapping }.visit_body(body);
309332

310333
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);
312335
patch_missing_storage_deads(tcx, body, &substitution_mapping);
313336
hydrate_var_debug_info(body, &substitution_mapping);
314337
if let Some(mir_dumper) = MirDumper::new(tcx, "RelocateUpvars", body) {
@@ -445,10 +468,11 @@ fn rewrite_drop_coroutine_struct<'tcx>(
445468

446469
fn insert_substitution_prologue<'tcx>(
447470
body: &mut Body<'tcx>,
471+
retagged_start_block: Option<BasicBlock>,
448472
substitution_mapping: &IndexSlice<FieldIdx, UpvarSubstitution<'tcx>>,
449473
) {
450474
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());
452476
for &UpvarSubstitution { local, reloc, upvar_place, span, name: _ } in substitution_mapping {
453477
// For each upvar-local _$i
454478
let source_info = SourceInfo::outermost(span);
@@ -481,22 +505,30 @@ fn insert_substitution_prologue<'tcx>(
481505
let source_info = SourceInfo::outermost(body.span);
482506
let prologue = patch.new_block(BasicBlockData::new_stmts(
483507
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+
}),
485512
false,
486513
));
487514
patch.apply(body);
488515

489516
// 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);
498531
}
499-
basic_blocks.swap(START_BLOCK, prologue);
500532
}
501533

502534
/// Occasionally there are upvar locals left without `StorageDead` because

tests/ui/rustc_public-ir-print/async-closure.relocate.stdout

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo
5858
bb1: {
5959
StorageLive(_5);
6060
StorageLive(_6);
61-
_10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:12:22: 14:6}));
62-
_6 = move (((*_10) as variant#0).0: &i32);
61+
_11 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:12:22: 14:6}));
62+
_6 = move (((*_11) as variant#0).0: &i32);
6363
_5 = move _6;
6464
StorageDead(_6);
6565
StorageLive(_3);
@@ -69,8 +69,8 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo
6969
StorageDead(_3);
7070
StorageDead(_5);
7171
_0 = std::task::Poll::Ready(move _7);
72-
_11 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:12:22: 14:6}));
73-
discriminant((*_11)) = 1;
72+
_10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:12:22: 14:6}));
73+
discriminant((*_10)) = 1;
7474
return;
7575
}
7676
bb2: {
@@ -103,8 +103,8 @@ fn foo::{closure#0}::{synthetic#0}(_1: Pin<&mut {async closure body@$DIR/async-c
103103
bb1: {
104104
StorageLive(_5);
105105
StorageLive(_6);
106-
_10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:12:22: 14:6}));
107-
_6 = move (((*_10) as variant#0).0: &i32);
106+
_11 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:12:22: 14:6}));
107+
_6 = move (((*_11) as variant#0).0: &i32);
108108
_5 = move _6;
109109
StorageDead(_6);
110110
StorageLive(_3);
@@ -114,8 +114,8 @@ fn foo::{closure#0}::{synthetic#0}(_1: Pin<&mut {async closure body@$DIR/async-c
114114
StorageDead(_3);
115115
StorageDead(_5);
116116
_0 = std::task::Poll::Ready(move _7);
117-
_11 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:12:22: 14:6}));
118-
discriminant((*_11)) = 1;
117+
_10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:12:22: 14:6}));
118+
discriminant((*_10)) = 1;
119119
return;
120120
}
121121
bb2: {

0 commit comments

Comments
 (0)