Skip to content

Commit 9d67267

Browse files
committed
Make borrowck's notion of scopes consistent with trans's notion of scopes
This eliminates an ICE in trans where the scope for a particular borrow was a statement ID, but the code in trans that does cleanups wasn't finding the block with that scope. As per #3860 preserve looks at a node ID to see if it's for a statement -- if it is, it uses the enclosing scope instead when updating the map that trans looks at later. I added a comment noting that this is not the best fix (since it may cause boxes to be frozen for longer than necessary) and referring to #3511. r=nmatsakis
1 parent 519b60f commit 9d67267

File tree

6 files changed

+47
-11
lines changed

6 files changed

+47
-11
lines changed

Diff for: src/librustc/middle/borrowck/gather_loans.rs

+14
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ fn gather_loans(bccx: borrowck_ctxt, crate: @ast::crate) -> req_maps {
8484
mut ignore_adjustments: LinearMap()});
8585
let v = visit::mk_vt(@visit::Visitor {visit_expr: req_loans_in_expr,
8686
visit_fn: req_loans_in_fn,
87+
visit_stmt: add_stmt_to_map,
8788
.. *visit::default_visitor()});
8889
visit::visit_crate(*crate, glcx, v);
8990
return glcx.req_maps;
@@ -573,3 +574,16 @@ impl gather_loan_ctxt {
573574
}
574575
}
575576

577+
// Setting up info that preserve needs.
578+
// This is just the most convenient place to do it.
579+
fn add_stmt_to_map(stmt: @ast::stmt,
580+
&&self: gather_loan_ctxt,
581+
vt: visit::vt<gather_loan_ctxt>) {
582+
match stmt.node {
583+
ast::stmt_expr(_, id) | ast::stmt_semi(_, id) => {
584+
self.bccx.stmt_map.insert(id, ());
585+
}
586+
_ => ()
587+
}
588+
visit::visit_stmt(stmt, self, vt);
589+
}

Diff for: src/librustc/middle/borrowck/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ use middle::liveness;
232232
use middle::mem_categorization::*;
233233
use middle::region;
234234
use middle::ty;
235-
use util::common::indenter;
235+
use util::common::{indenter, stmt_set};
236236
use util::ppaux::{expr_repr, note_and_explain_region};
237237
use util::ppaux::{ty_to_str, region_to_str, explain_region};
238238

@@ -272,6 +272,7 @@ fn check_crate(tcx: ty::ctxt,
272272
root_map: root_map(),
273273
mutbl_map: HashMap(),
274274
write_guard_map: HashMap(),
275+
stmt_map: HashMap(),
275276
mut loaned_paths_same: 0,
276277
mut loaned_paths_imm: 0,
277278
mut stable_paths: 0,
@@ -313,6 +314,7 @@ type borrowck_ctxt_ = {tcx: ty::ctxt,
313314
root_map: root_map,
314315
mutbl_map: mutbl_map,
315316
write_guard_map: write_guard_map,
317+
stmt_map: stmt_set,
316318

317319
// Statistics:
318320
mut loaned_paths_same: uint,

Diff for: src/librustc/middle/borrowck/preserve.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -357,10 +357,30 @@ priv impl &preserve_ctxt {
357357
if self.bccx.is_subregion_of(self.scope_region, root_region) {
358358
debug!("Elected to root");
359359
let rk = {id: base.id, derefs: derefs};
360+
// This code could potentially lead cause boxes to be frozen
361+
// for longer than necessarily at runtime. It prevents an ICE
362+
// in trans; the fundamental problem is that it's hard to make
363+
// sure trans and borrowck have the same notion of scope. The
364+
// real fix is to clean up how trans handles cleanups, but
365+
// that's hard. If this becomes an issue, it's an option to just
366+
// change this to `let scope_to_use = scope_id;`. Though that
367+
// would potentially re-introduce the ICE. See #3511 for more
368+
// details.
369+
let scope_to_use = if
370+
self.bccx.stmt_map.contains_key(scope_id) {
371+
// Root it in its parent scope, b/c
372+
// trans won't introduce a new scope for the
373+
// stmt
374+
self.root_ub
375+
}
376+
else {
377+
// Use the more precise scope
378+
scope_id
379+
};
360380
// We freeze if and only if this is a *mutable* @ box that
361381
// we're borrowing into a pointer.
362382
self.bccx.root_map.insert(rk, RootInfo {
363-
scope: scope_id,
383+
scope: scope_to_use,
364384
freezes: cmt.cat.derefs_through_mutable_box()
365385
});
366386
return Ok(pc_ok);

Diff for: src/librustc/middle/region.rs

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use middle::resolve;
2525
use middle::ty::{region_variance, rv_covariant, rv_invariant};
2626
use middle::ty::{rv_contravariant};
2727
use middle::ty;
28+
use util::common::stmt_set;
2829

2930
use core::cmp;
3031
use core::dvec::DVec;
@@ -254,6 +255,7 @@ fn resolve_stmt(stmt: @ast::stmt, cx: ctxt, visitor: visit::vt<ctxt>) {
254255
ast::stmt_decl(*) => {
255256
visit::visit_stmt(stmt, cx, visitor);
256257
}
258+
// This code has to be kept consistent with trans::base::trans_stmt
257259
ast::stmt_expr(_, stmt_id) |
258260
ast::stmt_semi(_, stmt_id) => {
259261
record_parent(cx, stmt_id);

Diff for: src/librustc/util/common.rs

+3
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ fn pluralize(n: uint, +s: ~str) -> ~str {
112112
else { str::concat([s, ~"s"]) }
113113
}
114114

115+
// A set of node IDs (used to keep track of which node IDs are for statements)
116+
type stmt_set = HashMap<ast::node_id, ()>;
117+
115118
//
116119
// Local Variables:
117120
// mode: rust

Diff for: src/test/run-pass/issue-3860.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// xfail-test
1211
struct Foo { x: int }
1312

1413
impl Foo {
@@ -19,11 +18,7 @@ impl Foo {
1918

2019
fn main() {
2120
let mut x = @mut Foo { x: 3 };
22-
x.stuff(); // error: internal compiler error: no enclosing scope with id 49
23-
// storing the result removes the error, so replacing the above
24-
// with the following, works:
25-
// let _y = x.stuff()
26-
27-
// also making 'stuff()' not return anything fixes it
28-
// I guess the "dangling &ptr" cuases issues?
29-
}
21+
// Neither of the next two lines should cause an error
22+
let _ = x.stuff();
23+
x.stuff();
24+
}

0 commit comments

Comments
 (0)