Skip to content

Commit ea549e7

Browse files
committed
make borrowck more conservative around rvalues.
this will require more temporaries, but is probably less magical. also, it means that borrowck matches trans better, so fewer crashes. bonus. Finally, stop warning about implicit copies when we are actually borrowing. Also, one test (vec-res-add) stopped failing due to #2587, and hence I added an xfail-test. Fixes #3217, #2977, #3067
1 parent 8f01343 commit ea549e7

File tree

9 files changed

+89
-49
lines changed

9 files changed

+89
-49
lines changed

src/libsyntax/ast_map.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import std::map;
22
import std::map::hashmap;
33
import ast::*;
44
import print::pprust;
5-
import ast_util::path_to_ident;
5+
import ast_util::{path_to_ident, stmt_id};
66
import diagnostic::span_handler;
77

88
enum path_elt { path_mod(ident), path_name(ident) }
@@ -39,6 +39,7 @@ enum ast_node {
3939
node_method(@method, def_id /* impl did */, @path /* path to the impl */),
4040
node_variant(variant, @item, @path),
4141
node_expr(@expr),
42+
node_stmt(@stmt),
4243
node_export(@view_path, @path),
4344
// Locals are numbered, because the alias analysis needs to know in which
4445
// order they are introduced.
@@ -65,6 +66,7 @@ fn mk_ast_map_visitor() -> vt {
6566
return visit::mk_vt(@{
6667
visit_item: map_item,
6768
visit_expr: map_expr,
69+
visit_stmt: map_stmt,
6870
visit_fn: map_fn,
6971
visit_local: map_local,
7072
visit_arm: map_arm,
@@ -284,6 +286,11 @@ fn map_expr(ex: @expr, cx: ctx, v: vt) {
284286
visit::visit_expr(ex, cx, v);
285287
}
286288

289+
fn map_stmt(stmt: @stmt, cx: ctx, v: vt) {
290+
cx.map.insert(stmt_id(*stmt), node_stmt(stmt));
291+
visit::visit_stmt(stmt, cx, v);
292+
}
293+
287294
fn node_id_to_str(map: map, id: node_id) -> ~str {
288295
match map.find(id) {
289296
none => {
@@ -313,6 +320,10 @@ fn node_id_to_str(map: map, id: node_id) -> ~str {
313320
fmt!{"expr %s (id=%?)",
314321
pprust::expr_to_str(expr), id}
315322
}
323+
some(node_stmt(stmt)) => {
324+
fmt!{"stmt %s (id=%?)",
325+
pprust::stmt_to_str(*stmt), id}
326+
}
316327
// FIXMEs are as per #2410
317328
some(node_export(_, path)) => {
318329
fmt!{"export %s (id=%?)", // add more info here

src/rustc/middle/borrowck/preserve.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,9 @@ priv impl &preserve_ctxt {
7979
let scope_region = if self.root_ub == 0 {
8080
ty::re_static
8181
} else {
82-
ty::re_scope(self.root_ub)
82+
ty::re_scope(self.tcx().region_map.get(cmt.id))
8383
};
8484

85-
// FIXME(#2977)--need to update trans!
8685
self.compare_scope(cmt, scope_region)
8786
}
8887
cat_stack_upvar(cmt) => {

src/rustc/middle/kind.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,17 @@ fn is_nullary_variant(cx: ctx, ex: @expr) -> bool {
389389

390390
fn check_copy_ex(cx: ctx, ex: @expr, implicit_copy: bool) {
391391
if ty::expr_is_lval(cx.method_map, ex) &&
392-
!cx.last_use_map.contains_key(ex.id) &&
393-
!is_nullary_variant(cx, ex) {
392+
393+
// this is a move
394+
!cx.last_use_map.contains_key(ex.id) &&
395+
396+
// a reference to a constant like `none`... no need to warn
397+
// about *this* even if the type is option<~int>
398+
!is_nullary_variant(cx, ex) &&
399+
400+
// borrowed unique value isn't really a copy
401+
!cx.tcx.borrowings.contains_key(ex.id)
402+
{
394403
let ty = ty::expr_ty(cx.tcx, ex);
395404
check_copy(cx, ex.id, ty, ex.span, implicit_copy);
396405
}

src/rustc/middle/region.rs

+45-24
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,24 @@ type binding = {node_id: ast::node_id,
2828
name: ~str,
2929
br: ty::bound_region};
3030

31-
/// Mapping from a block/expr/binding to the innermost scope that
32-
/// bounds its lifetime. For a block/expression, this is the lifetime
33-
/// in which it will be evaluated. For a binding, this is the lifetime
34-
/// in which is in scope.
31+
/**
32+
Encodes the bounding lifetime for a given AST node:
33+
34+
- Expressions are mapped to the expression or block encoding the maximum
35+
(static) lifetime of a value produced by that expression. This is
36+
generally the innermost call, statement, match, or block.
37+
38+
- Variables and bindings are mapped to the block in which they are declared.
39+
40+
*/
3541
type region_map = hashmap<ast::node_id, ast::node_id>;
3642

37-
type ctxt = {
38-
sess: session,
39-
def_map: resolve3::DefMap,
40-
region_map: region_map,
43+
struct ctxt {
44+
sess: session;
45+
def_map: resolve3::DefMap;
46+
47+
// Generated maps:
48+
region_map: region_map;
4149

4250
// Generally speaking, expressions are parented to their innermost
4351
// enclosing block. But some kinds of expressions serve as
@@ -46,9 +54,9 @@ type ctxt = {
4654
// the condition in a while loop is always a parent. In those
4755
// cases, we add the node id of such an expression to this set so
4856
// that when we visit it we can view it as a parent.
49-
root_exprs: hashmap<ast::node_id, ()>,
57+
root_exprs: hashmap<ast::node_id, ()>;
5058

51-
// The parent scope is the innermost block, call, or alt
59+
// The parent scope is the innermost block, statement, call, or alt
5260
// expression during the execution of which the current expression
5361
// will be evaluated. Generally speaking, the innermost parent
5462
// scope is also the closest suitable ancestor in the AST tree.
@@ -79,8 +87,8 @@ type ctxt = {
7987
// Here, the first argument `&**x` will be a borrow of the `~int`,
8088
// but the second argument overwrites that very value! Bad.
8189
// (This test is borrowck-pure-scope-in-call.rs, btw)
82-
parent: parent
83-
};
90+
parent: parent;
91+
}
8492

8593
/// Returns true if `subscope` is equal to or is lexically nested inside
8694
/// `superscope` and false otherwise.
@@ -186,12 +194,9 @@ fn parent_id(cx: ctxt, span: span) -> ast::node_id {
186194

187195
/// Records the current parent (if any) as the parent of `child_id`.
188196
fn record_parent(cx: ctxt, child_id: ast::node_id) {
189-
match cx.parent {
190-
none => { /* no-op */ }
191-
some(parent_id) => {
197+
for cx.parent.each |parent_id| {
192198
debug!{"parent of node %d is node %d", child_id, parent_id};
193199
cx.region_map.insert(child_id, parent_id);
194-
}
195200
}
196201
}
197202

@@ -200,7 +205,7 @@ fn resolve_block(blk: ast::blk, cx: ctxt, visitor: visit::vt<ctxt>) {
200205
record_parent(cx, blk.node.id);
201206

202207
// Descend.
203-
let new_cx: ctxt = {parent: some(blk.node.id) with cx};
208+
let new_cx: ctxt = ctxt {parent: some(blk.node.id) with cx};
204209
visit::visit_block(blk, new_cx, visitor);
205210
}
206211

@@ -228,6 +233,21 @@ fn resolve_pat(pat: @ast::pat, cx: ctxt, visitor: visit::vt<ctxt>) {
228233
visit::visit_pat(pat, cx, visitor);
229234
}
230235

236+
fn resolve_stmt(stmt: @ast::stmt, cx: ctxt, visitor: visit::vt<ctxt>) {
237+
match stmt.node {
238+
ast::stmt_decl(*) => {
239+
visit::visit_stmt(stmt, cx, visitor);
240+
}
241+
ast::stmt_expr(expr, stmt_id) |
242+
ast::stmt_semi(expr, stmt_id) => {
243+
record_parent(cx, stmt_id);
244+
let mut expr_cx = cx;
245+
expr_cx.parent = some(stmt_id);
246+
visit::visit_stmt(stmt, expr_cx, visitor);
247+
}
248+
}
249+
}
250+
231251
fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
232252
record_parent(cx, expr.id);
233253

@@ -270,7 +290,7 @@ fn resolve_local(local: @ast::local, cx: ctxt, visitor: visit::vt<ctxt>) {
270290

271291
fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt<ctxt>) {
272292
// Items create a new outer block scope as far as we're concerned.
273-
let new_cx: ctxt = {parent: none with cx};
293+
let new_cx: ctxt = ctxt {parent: none with cx};
274294
visit::visit_item(item, new_cx, visitor);
275295
}
276296

@@ -282,7 +302,7 @@ fn resolve_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
282302
visit::fk_item_fn(*) | visit::fk_method(*) |
283303
visit::fk_ctor(*) | visit::fk_dtor(*) => {
284304
// Top-level functions are a root scope.
285-
{parent: some(id) with cx}
305+
ctxt {parent: some(id) with cx}
286306
}
287307

288308
visit::fk_anon(*) | visit::fk_fn_block(*) => {
@@ -304,17 +324,18 @@ fn resolve_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
304324

305325
fn resolve_crate(sess: session, def_map: resolve3::DefMap,
306326
crate: @ast::crate) -> region_map {
307-
let cx: ctxt = {sess: sess,
308-
def_map: def_map,
309-
region_map: int_hash(),
310-
root_exprs: int_hash(),
311-
parent: none};
327+
let cx: ctxt = ctxt {sess: sess,
328+
def_map: def_map,
329+
region_map: int_hash(),
330+
root_exprs: int_hash(),
331+
parent: none};
312332
let visitor = visit::mk_vt(@{
313333
visit_block: resolve_block,
314334
visit_item: resolve_item,
315335
visit_fn: resolve_fn,
316336
visit_arm: resolve_arm,
317337
visit_pat: resolve_pat,
338+
visit_stmt: resolve_stmt,
318339
visit_expr: resolve_expr,
319340
visit_local: resolve_local
320341
with *visit::default_visitor()

src/rustc/middle/trans/base.rs

+10-14
Original file line numberDiff line numberDiff line change
@@ -2171,6 +2171,9 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id,
21712171
ast_map::node_expr(*) => {
21722172
ccx.tcx.sess.bug(~"Can't monomorphize an expr")
21732173
}
2174+
ast_map::node_stmt(*) => {
2175+
ccx.tcx.sess.bug(~"Can't monomorphize a stmt")
2176+
}
21742177
ast_map::node_export(*) => {
21752178
ccx.tcx.sess.bug(~"Can't monomorphize an export")
21762179
}
@@ -2270,21 +2273,14 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id,
22702273
dtor.node.id, psubsts, some(hash_id), parent_id)
22712274
}
22722275
// Ugh -- but this ensures any new variants won't be forgotten
2273-
ast_map::node_expr(*) => {
2274-
ccx.tcx.sess.bug(~"Can't monomorphize an expr")
2275-
}
2276-
ast_map::node_trait_method(*) => {
2277-
ccx.tcx.sess.bug(~"Can't monomorphize a trait method")
2278-
}
2279-
ast_map::node_export(*) => {
2280-
ccx.tcx.sess.bug(~"Can't monomorphize an export")
2281-
}
2282-
ast_map::node_arg(*) => ccx.tcx.sess.bug(~"Can't monomorphize an arg"),
2283-
ast_map::node_block(*) => {
2284-
ccx.tcx.sess.bug(~"Can't monomorphize a block")
2285-
}
2276+
ast_map::node_expr(*) |
2277+
ast_map::node_stmt(*) |
2278+
ast_map::node_trait_method(*) |
2279+
ast_map::node_export(*) |
2280+
ast_map::node_arg(*) |
2281+
ast_map::node_block(*) |
22862282
ast_map::node_local(*) => {
2287-
ccx.tcx.sess.bug(~"Can't monomorphize a local")
2283+
ccx.tcx.sess.bug(fmt!("Can't monomorphize a %?", map_node))
22882284
}
22892285
};
22902286
ccx.monomorphizing.insert(fn_id, depth);

src/rustc/middle/ty.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -2861,10 +2861,9 @@ fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path {
28612861
vec::append_one(*path, ast_map::path_name(@~"dtor"))
28622862
}
28632863

2864-
2865-
ast_map::node_expr(_) | ast_map::node_arg(_, _) |
2866-
ast_map::node_local(_) | ast_map::node_export(_, _) |
2867-
ast_map::node_block(_) => {
2864+
ast_map::node_stmt(*) | ast_map::node_expr(*) |
2865+
ast_map::node_arg(*) | ast_map::node_local(*) |
2866+
ast_map::node_export(*) | ast_map::node_block(*) => {
28682867
cx.sess.bug(fmt!{"cannot find item_path for node %?", node});
28692868
}
28702869
}

src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ fn b() {
2828

2929
// Here I create an outstanding loan and check that we get conflicts:
3030

31-
&mut p; //~ NOTE prior loan as mutable granted here
31+
let q = &mut p; //~ NOTE prior loan as mutable granted here
3232
//~^ NOTE prior loan as mutable granted here
3333

3434
p + 3; //~ ERROR loan of mutable local variable as immutable conflicts with prior loan
3535
p.times(3); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan
36+
37+
q.x += 1;
3638
}
3739

3840
fn c() {

src/test/compile-fail/borrowck-loan-rcvr.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@ fn b() {
3535

3636
// Here I create an outstanding loan and check that we get conflicts:
3737

38-
&mut p; //~ NOTE prior loan as mutable granted here
38+
let l = &mut p; //~ NOTE prior loan as mutable granted here
3939
//~^ NOTE prior loan as mutable granted here
4040

4141
p.purem(); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan
4242
p.impurem(); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan
43+
44+
l.x += 1;
4345
}
4446

4547
fn c() {

src/test/compile-fail/vec-res-add.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// xfail-test #2587
12
// error-pattern: copying a noncopyable value
23

34
struct r {

0 commit comments

Comments
 (0)