Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Don't count MIR locals as borrowed after StorageDead when finding loc…
…als live across a yield terminator
  • Loading branch information
Zoxc committed Jul 31, 2018
1 parent f898179 commit 0babbf1
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 5 deletions.
16 changes: 12 additions & 4 deletions src/librustc_mir/dataflow/impls/borrowed_locals.rs
Expand Up @@ -15,9 +15,9 @@ use rustc::mir::visit::Visitor;
use dataflow::BitDenotation;

/// This calculates if any part of a MIR local could have previously been borrowed.
/// This means that once a local has been borrowed, its bit will always be set
/// from that point and onwards, even if the borrow ends. You could also think of this
/// as computing the lifetimes of infinite borrows.
/// This means that once a local has been borrowed, its bit will be set
/// from that point and onwards, until we see a StorageDead statement for the local,
/// at which points there is no memory associated with the local, so it cannot be borrowed.
/// This is used to compute which locals are live during a yield expression for
/// immovable generators.
#[derive(Copy, Clone)]
Expand Down Expand Up @@ -50,9 +50,17 @@ impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {
fn statement_effect(&self,
sets: &mut BlockSets<Local>,
loc: Location) {
let stmt = &self.mir[loc.block].statements[loc.statement_index];

BorrowedLocalsVisitor {
sets,
}.visit_statement(loc.block, &self.mir[loc.block].statements[loc.statement_index], loc);
}.visit_statement(loc.block, stmt, loc);

// StorageDead invalidates all borrows and raw pointers to a local
match stmt.kind {
StatementKind::StorageDead(l) => sets.kill(&l),
_ => (),
}
}

fn terminator_effect(&self,
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/transform/generator.rs
Expand Up @@ -433,7 +433,8 @@ fn locals_live_across_suspend_points<'a, 'tcx,>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// The `liveness` variable contains the liveness of MIR locals ignoring borrows.
// This is correct for movable generators since borrows cannot live across
// suspension points. However for immovable generators we need to account for
// borrows, so we conseratively assume that all borrowed locals live forever.
// borrows, so we conseratively assume that all borrowed locals are live until
// we find a StorageDead statement referencing the locals.
// To do this we just union our `liveness` result with `borrowed_locals`, which
// contains all the locals which has been borrowed before this suspension point.
// If a borrow is converted to a raw reference, we must also assume that it lives
Expand Down
25 changes: 25 additions & 0 deletions src/test/run-pass/generator/yield-in-initializer.rs
@@ -0,0 +1,25 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(generators)]

fn main() {
static || {
loop {
// Test that `opt` is not live across the yield, even when borrowed in a loop
// See https://github.com/rust-lang/rust/issues/52792
let opt = {
yield;
true
};
&opt;
}
};
}

0 comments on commit 0babbf1

Please sign in to comment.