Skip to content

Commit 0babbf1

Browse files
committed
Don't count MIR locals as borrowed after StorageDead when finding locals live across a yield terminator
1 parent f898179 commit 0babbf1

File tree

3 files changed

+39
-5
lines changed

3 files changed

+39
-5
lines changed

src/librustc_mir/dataflow/impls/borrowed_locals.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ use rustc::mir::visit::Visitor;
1515
use dataflow::BitDenotation;
1616

1717
/// This calculates if any part of a MIR local could have previously been borrowed.
18-
/// This means that once a local has been borrowed, its bit will always be set
19-
/// from that point and onwards, even if the borrow ends. You could also think of this
20-
/// as computing the lifetimes of infinite borrows.
18+
/// This means that once a local has been borrowed, its bit will be set
19+
/// from that point and onwards, until we see a StorageDead statement for the local,
20+
/// at which points there is no memory associated with the local, so it cannot be borrowed.
2121
/// This is used to compute which locals are live during a yield expression for
2222
/// immovable generators.
2323
#[derive(Copy, Clone)]
@@ -50,9 +50,17 @@ impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {
5050
fn statement_effect(&self,
5151
sets: &mut BlockSets<Local>,
5252
loc: Location) {
53+
let stmt = &self.mir[loc.block].statements[loc.statement_index];
54+
5355
BorrowedLocalsVisitor {
5456
sets,
55-
}.visit_statement(loc.block, &self.mir[loc.block].statements[loc.statement_index], loc);
57+
}.visit_statement(loc.block, stmt, loc);
58+
59+
// StorageDead invalidates all borrows and raw pointers to a local
60+
match stmt.kind {
61+
StatementKind::StorageDead(l) => sets.kill(&l),
62+
_ => (),
63+
}
5664
}
5765

5866
fn terminator_effect(&self,

src/librustc_mir/transform/generator.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,8 @@ fn locals_live_across_suspend_points<'a, 'tcx,>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
433433
// The `liveness` variable contains the liveness of MIR locals ignoring borrows.
434434
// This is correct for movable generators since borrows cannot live across
435435
// suspension points. However for immovable generators we need to account for
436-
// borrows, so we conseratively assume that all borrowed locals live forever.
436+
// borrows, so we conseratively assume that all borrowed locals are live until
437+
// we find a StorageDead statement referencing the locals.
437438
// To do this we just union our `liveness` result with `borrowed_locals`, which
438439
// contains all the locals which has been borrowed before this suspension point.
439440
// If a borrow is converted to a raw reference, we must also assume that it lives
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generators)]
12+
13+
fn main() {
14+
static || {
15+
loop {
16+
// Test that `opt` is not live across the yield, even when borrowed in a loop
17+
// See https://github.com/rust-lang/rust/issues/52792
18+
let opt = {
19+
yield;
20+
true
21+
};
22+
&opt;
23+
}
24+
};
25+
}

0 commit comments

Comments
 (0)