Skip to content

Commit bd12b60

Browse files
committed
[wip] Try to fix rust-lang#72247
1 parent 3d5d0f8 commit bd12b60

File tree

3 files changed

+93
-21
lines changed

3 files changed

+93
-21
lines changed

issue-72247.rs

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#![feature(generators)]
2+
#![feature(generator_trait)]
3+
#![feature(test)]
4+
use std::ops::Generator;
5+
use std::pin::Pin;
6+
use std::hint::black_box;
7+
8+
struct Big([u8; { 1024 * 1024 }]);
9+
impl Big {
10+
fn new(val: u8) -> Big {
11+
Big([val; { 1024 * 1024 }])
12+
}
13+
14+
fn sum(&self) -> usize {
15+
let mut sum = 0usize;
16+
for i in 0..self.0.len() {
17+
sum = sum.wrapping_add(self.0[i] as usize);
18+
}
19+
sum
20+
}
21+
}
22+
23+
#[allow(unused)]
24+
enum Kind {
25+
Thing1(Big),
26+
Thing2(Big),
27+
Thing3(Big),
28+
}
29+
30+
fn f1(kind: Kind) -> impl Generator<Yield = usize, Return = ()> {
31+
move || {
32+
match kind {
33+
Kind::Thing1(arr) => yield arr.sum(),
34+
Kind::Thing2(arr) => yield arr.sum(),
35+
Kind::Thing3(arr) => yield arr.sum(),
36+
}
37+
}
38+
}
39+
40+
fn main() {
41+
let mut gen = f1(Kind::Thing1(Big::new(1)));
42+
Pin::new(&mut gen).resume(());
43+
black_box(Kind::Thing1(Big::new(1)));
44+
black_box(Kind::Thing3(Big::new(2)));
45+
black_box(f1);
46+
black_box(Pin::new(&mut gen).resume(()));
47+
}

src/librustc_mir/transform/generator.rs

+39-15
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ use crate::transform::no_landing_pads::no_landing_pads;
5757
use crate::transform::simplify;
5858
use crate::transform::{MirPass, MirSource};
5959
use crate::util::dump_mir;
60+
use crate::util::patch::MirPatch;
6061
use crate::util::storage;
6162
use rustc_data_structures::fx::FxHashMap;
6263
use rustc_hir as hir;
@@ -494,15 +495,15 @@ fn locals_live_across_suspend_points(
494495
let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len());
495496

496497
for (block, data) in body.basic_blocks().iter_enumerated() {
497-
if !matches!(data.terminator().kind, TerminatorKind::Yield { .. }) {
498-
continue;
499-
}
500-
501498
// Store the storage liveness for later use so we can restore the state
502499
// after a suspension point
503500
storage_live.seek_to_block_end(block);
504501
storage_liveness_map[block] = Some(storage_live.get().clone());
505502

503+
if !matches!(data.terminator().kind, TerminatorKind::Yield { .. }) {
504+
continue;
505+
}
506+
506507
let mut live_locals = locals_live_across_yield_point(block);
507508

508509
// The combination of `MaybeInitializedLocals` and `MaybeBorrowedLocals` should be strictly
@@ -797,7 +798,6 @@ fn insert_switch<'tcx>(
797798
fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut Body<'tcx>) {
798799
use crate::shim::DropShimElaborator;
799800
use crate::util::elaborate_drops::{elaborate_drop, Unwind};
800-
use crate::util::patch::MirPatch;
801801

802802
// Note that `elaborate_drops` only drops the upvars of a generator, and
803803
// this is ok because `open_drop` can only be reached within that own
@@ -1007,32 +1007,56 @@ fn create_generator_resume_function<'tcx>(
10071007
// Poison the generator when it unwinds
10081008
if can_unwind {
10091009
let source_info = SourceInfo::outermost(body.span);
1010-
let poison_block = body.basic_blocks_mut().push(BasicBlockData {
1010+
let mut patch = MirPatch::new(body);
1011+
let poison_block = patch.new_block(BasicBlockData {
10111012
statements: vec![transform.set_discr(VariantIdx::new(POISONED), source_info)],
10121013
terminator: Some(Terminator { source_info, kind: TerminatorKind::Resume }),
10131014
is_cleanup: true,
10141015
});
10151016

1016-
for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() {
1017+
for (idx, block) in body.basic_blocks().iter_enumerated() {
10171018
let source_info = block.terminator().source_info;
1019+
let empty_liveness = BitSet::new_empty(0);
1020+
let storage_deads = transform
1021+
.storage_liveness.get(idx).map(|info| info.as_ref().unwrap()).unwrap_or(&empty_liveness)
1022+
.iter()
1023+
.filter(|local| *local != SELF_ARG)
1024+
.filter(|local| !transform.always_live_locals.contains(*local))
1025+
.filter(|local| !transform.remap.contains_key(local))
1026+
.map(|local| StatementKind::StorageDead(local));
10181027

10191028
if let TerminatorKind::Resume = block.terminator().kind {
10201029
// An existing `Resume` terminator is redirected to jump to our dedicated
10211030
// "poisoning block" above.
1022-
if idx != poison_block {
1023-
*block.terminator_mut() = Terminator {
1024-
source_info,
1025-
kind: TerminatorKind::Goto { target: poison_block },
1026-
};
1031+
patch.patch_terminator(idx, TerminatorKind::Goto { target: poison_block });
1032+
// Before redirecting, we declare StorageDead for any variables
1033+
// that might be StorageLive.
1034+
for stmt_kind in storage_deads {
1035+
patch.add_statement(patch.terminator_loc(body, idx), stmt_kind);
10271036
}
10281037
} else if !block.is_cleanup {
10291038
// Any terminators that *can* unwind but don't have an unwind target set are also
10301039
// pointed at our poisoning block (unless they're part of the cleanup path).
1031-
if let Some(unwind @ None) = block.terminator_mut().unwind_mut() {
1032-
*unwind = Some(poison_block);
1040+
let mut terminator = block.terminator().clone();
1041+
if let Some(unwind @ None) = terminator.unwind_mut() {
1042+
let storage_deads: Vec<_> = storage_deads.map(|kind| Statement { source_info, kind }).collect();
1043+
let target = if storage_deads.is_empty() {
1044+
poison_block
1045+
} else {
1046+
let storage_dead_block = patch.new_block(BasicBlockData {
1047+
statements: storage_deads,
1048+
terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target: poison_block }}),
1049+
is_cleanup: true,
1050+
});
1051+
storage_dead_block
1052+
};
1053+
*unwind = Some(target);
1054+
patch.patch_terminator(idx, terminator.kind);
10331055
}
10341056
}
10351057
}
1058+
1059+
patch.apply(body);
10361060
}
10371061

10381062
let mut cases = create_cases(body, &transform, Operation::Resume);
@@ -1219,7 +1243,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
12191243

12201244
// When first entering the generator, move the resume argument into its new local.
12211245
let source_info = SourceInfo::outermost(body.span);
1222-
let stmts = &mut body.basic_blocks_mut()[BasicBlock::new(0)].statements;
1246+
let stmts = &mut body.basic_blocks_mut()[START_BLOCK].statements;
12231247
stmts.insert(
12241248
0,
12251249
Statement {

src/librustc_session/session.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -1017,12 +1017,13 @@ impl Session {
10171017

10181018
/// Checks if LLVM lifetime markers should be emitted.
10191019
pub fn emit_lifetime_markers(&self) -> bool {
1020-
match self.opts.debugging_opts.sanitizer {
1021-
// AddressSanitizer uses lifetimes to detect use after scope bugs.
1022-
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
1023-
Some(Sanitizer::Address | Sanitizer::Memory) => true,
1024-
_ => self.opts.optimize != config::OptLevel::No,
1025-
}
1020+
true
1021+
//match self.opts.debugging_opts.sanitizer {
1022+
// // AddressSanitizer uses lifetimes to detect use after scope bugs.
1023+
// // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
1024+
// Some(Sanitizer::Address | Sanitizer::Memory) => true,
1025+
// _ => self.opts.optimize != config::OptLevel::No,
1026+
//}
10261027
}
10271028
}
10281029

0 commit comments

Comments
 (0)