Skip to content

Commit 810182f

Browse files
committed
---
yaml --- r: 16002 b: refs/heads/try c: e0f59e8 h: refs/heads/master v: v3
1 parent ab6ec4e commit 810182f

File tree

9 files changed

+212
-66
lines changed

9 files changed

+212
-66
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
refs/heads/master: 61b1875c16de39c166b0f4d54bba19f9c6777d1a
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 4a81779abd786ff22d71434c6d9a5917ea4cdfff
5-
refs/heads/try: 00849191ceeba124e27f38e27306badc264e48d7
5+
refs/heads/try: e0f59e835e062d27543ae5085b49effb13294b61
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105

branches/try/src/rustc/middle/borrowck.rs

Lines changed: 127 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ fn check_crate(tcx: ty::ctxt,
3838
let req_maps = if msg_level > 0u {
3939
gather_loans(bccx, crate)
4040
} else {
41-
{req_loan_map: int_hash()}
41+
{req_loan_map: int_hash(),
42+
pure_map: int_hash()}
4243
};
4344
check_loans(bccx, req_maps, crate);
4445
ret (bccx.root_map, bccx.mutbl_map);
@@ -165,14 +166,16 @@ fn root_map() -> root_map {
165166
// sure that all of these loans are honored.
166167

167168
type req_maps = {
168-
req_loan_map: hashmap<ast::node_id, @mut [@const [loan]]>
169+
req_loan_map: hashmap<ast::node_id, @mut [@const [loan]]>,
170+
pure_map: hashmap<ast::node_id, bckerr>
169171
};
170172

171173
enum gather_loan_ctxt = @{bccx: borrowck_ctxt, req_maps: req_maps};
172174

173175
fn gather_loans(bccx: borrowck_ctxt, crate: @ast::crate) -> req_maps {
174176
let glcx = gather_loan_ctxt(@{bccx: bccx,
175-
req_maps: {req_loan_map: int_hash()}});
177+
req_maps: {req_loan_map: int_hash(),
178+
pure_map: int_hash()}});
176179
let v = visit::mk_vt(@{visit_expr: req_loans_in_expr
177180
with *visit::default_visitor()});
178181
visit::visit_crate(*crate, glcx, v);
@@ -293,15 +296,40 @@ impl methods for gather_loan_ctxt {
293296
// it dynamically (or see that it is preserved by virtue of being
294297
// rooted in some immutable path)
295298
none {
296-
self.bccx.report_if_err(
297-
self.check_mutbl(req_mutbl, cmt).chain { |_ok|
298-
let opt_scope_id = alt scope_r {
299-
ty::re_scope(scope_id) { some(scope_id) }
300-
_ { none }
301-
};
299+
let opt_scope_id = alt scope_r {
300+
ty::re_scope(scope_id) { some(scope_id) }
301+
_ { none }
302+
};
302303

304+
let result = {
305+
self.check_mutbl(req_mutbl, cmt).chain { |_ok|
303306
self.bccx.preserve(cmt, opt_scope_id)
304-
})
307+
}
308+
};
309+
310+
alt result {
311+
ok(()) {
312+
// we were able guarantee the validity of the ptr,
313+
// perhaps by rooting or because it is immutably
314+
// rooted. good.
315+
}
316+
err(e) {
317+
// not able to guarantee the validity of the ptr.
318+
// rather than report an error, presuming that the
319+
// borrow is for a limited scope, we'll make one last
320+
// ditch effort and require that the scope where the
321+
// borrow occurs be pure.
322+
alt opt_scope_id {
323+
some(scope_id) {
324+
self.req_maps.pure_map.insert(scope_id, e);
325+
}
326+
none {
327+
// otherwise, fine, I give up.
328+
self.bccx.report(e);
329+
}
330+
}
331+
}
332+
}
305333
}
306334
}
307335
}
@@ -475,16 +503,30 @@ enum check_loan_ctxt = @{
475503
// we are in a ctor, we track the self id
476504
mut in_ctor: bool,
477505

478-
mut is_pure: bool
506+
mut is_pure: purity_cause
479507
};
480508

509+
// if we are enforcing purity, why are we doing so?
510+
enum purity_cause {
511+
// not enforcing purity:
512+
pc_impure,
513+
514+
// enforcing purity because fn was declared pure:
515+
pc_declaration,
516+
517+
// enforce purity because we need to guarantee the
518+
// validity of some alias; `bckerr` describes the
519+
// reason we needed to enforce purity.
520+
pc_cmt(bckerr)
521+
}
522+
481523
fn check_loans(bccx: borrowck_ctxt,
482524
req_maps: req_maps,
483525
crate: @ast::crate) {
484526
let clcx = check_loan_ctxt(@{bccx: bccx,
485527
req_maps: req_maps,
486528
mut in_ctor: false,
487-
mut is_pure: false});
529+
mut is_pure: pc_impure});
488530
let vt = visit::mk_vt(@{visit_expr: check_loans_in_expr,
489531
visit_block: check_loans_in_block,
490532
visit_fn: check_loans_in_fn
@@ -595,24 +637,37 @@ impl methods for check_loan_ctxt {
595637
};
596638

597639
alt callee_purity {
598-
ast::crust_fn | ast::pure_fn { /*ok*/ }
599-
ast::impure_fn {
600-
self.bccx.span_err(
601-
expr.span,
602-
"pure function calls function \
603-
not known to be pure");
640+
ast::crust_fn | ast::pure_fn {
641+
/*ok*/
604642
}
605-
ast::unsafe_fn {
643+
ast::impure_fn | ast::unsafe_fn {
606644
self.bccx.span_err(
607645
expr.span,
608-
"pure function calls unsafe function");
646+
"access to non-pure functions \
647+
prohibited in a pure context");
648+
self.report_why_pure();
609649
}
610650
}
611651
}
612652
_ { /* not a fn, ok */ }
613653
}
614654
}
615655

656+
fn check_for_purity_requirement(scope_id: ast::node_id) {
657+
// if we are not already enforcing purity, check whether the
658+
// gather pass thought we needed to enforce purity for this
659+
// scope.
660+
alt self.is_pure {
661+
pc_declaration | pc_cmt(*) { }
662+
pc_impure {
663+
alt self.req_maps.pure_map.find(scope_id) {
664+
none {}
665+
some(e) {self.is_pure = pc_cmt(e)}
666+
}
667+
}
668+
}
669+
}
670+
616671
fn check_for_conflicting_loans(scope_id: ast::node_id) {
617672
let new_loanss = alt self.req_maps.req_loan_map.find(scope_id) {
618673
none { ret; }
@@ -683,11 +738,12 @@ impl methods for check_loan_ctxt {
683738
// if this is a pure function, only loan-able state can be
684739
// assigned, because it is uniquely tied to this function and
685740
// is not visible from the outside
686-
if self.is_pure && cmt.lp.is_none() {
741+
if self.is_pure != pc_impure && cmt.lp.is_none() {
687742
self.bccx.span_err(
688743
ex.span,
689-
#fmt["%s prohibited in pure functions",
744+
#fmt["%s prohibited in a pure context",
690745
at.ing_form(self.bccx.cmt_to_str(cmt))]);
746+
self.report_why_pure();
691747
}
692748

693749
// check for a conflicting loan as well, except in the case of
@@ -720,6 +776,23 @@ impl methods for check_loan_ctxt {
720776
self.bccx.add_to_mutbl_map(cmt);
721777
}
722778

779+
fn report_why_pure() {
780+
alt self.is_pure {
781+
pc_impure {
782+
self.tcx().sess.bug("report_why_pure() called when impure");
783+
}
784+
pc_declaration {
785+
// fn was declared pure; no need to report this, I think
786+
}
787+
pc_cmt(e) {
788+
self.tcx().sess.span_note(
789+
e.cmt.span,
790+
#fmt["pure context is required due to an illegal borrow: %s",
791+
self.bccx.bckerr_code_to_str(e.code)]);
792+
}
793+
}
794+
}
795+
723796
fn check_move_out(ex: @ast::expr) {
724797
let cmt = self.bccx.cat_expr(ex);
725798
self.check_move_out_from_cmt(cmt);
@@ -788,8 +861,11 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
788861
_ { self.in_ctor = false; }
789862
};
790863

864+
// NDM this doesn't seem algother right, what about fn items
865+
// nested in pure fns? etc?
866+
791867
alt decl.purity {
792-
ast::pure_fn { self.is_pure = true; }
868+
ast::pure_fn { self.is_pure = pc_declaration; }
793869
_ { }
794870
}
795871

@@ -802,6 +878,16 @@ fn check_loans_in_expr(expr: @ast::expr,
802878
&&self: check_loan_ctxt,
803879
vt: visit::vt<check_loan_ctxt>) {
804880
self.check_for_conflicting_loans(expr.id);
881+
save_and_restore(self.is_pure) {||
882+
self.check_for_purity_requirement(expr.id);
883+
check_loans_in_expr_1(expr, self, vt);
884+
}
885+
}
886+
887+
// avoid rightward drift by breaking this out into its own fn
888+
fn check_loans_in_expr_1(expr: @ast::expr,
889+
&&self: check_loan_ctxt,
890+
vt: visit::vt<check_loan_ctxt>) {
805891
alt expr.node {
806892
ast::expr_swap(l, r) {
807893
self.check_assignment(at_swap, l);
@@ -844,7 +930,7 @@ fn check_loans_in_expr(expr: @ast::expr,
844930
}
845931
}
846932
ast::expr_call(f, args, _) {
847-
if self.is_pure {
933+
if self.is_pure != pc_impure {
848934
self.check_pure(f);
849935
for args.each { |arg| self.check_pure(arg) }
850936
}
@@ -873,12 +959,27 @@ fn check_loans_in_block(blk: ast::blk,
873959
vt: visit::vt<check_loan_ctxt>) {
874960
save_and_restore(self.is_pure) {||
875961
self.check_for_conflicting_loans(blk.node.id);
962+
self.check_for_purity_requirement(blk.node.id);
876963

877964
alt blk.node.rules {
878965
ast::default_blk {
879966
}
880-
ast::unchecked_blk |
881-
ast::unsafe_blk { self.is_pure = false; }
967+
ast::unchecked_blk {
968+
alt self.is_pure {
969+
pc_impure | pc_declaration {
970+
self.is_pure = pc_impure;
971+
}
972+
pc_cmt(_) {
973+
// unchecked does not override purity requirements due
974+
// to borrows; unchecked didn't seem strong enough to
975+
// justify potential memory unsafety to me
976+
}
977+
}
978+
}
979+
ast::unsafe_blk {
980+
// unsafe blocks override everything
981+
self.is_pure = pc_impure;
982+
}
882983
}
883984

884985
visit::visit_block(blk, self, vt);

branches/try/src/test/compile-fail/borrowck-lend-args.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
fn borrow(_v: &int) {}
55

66
fn borrow_from_arg_imm_ref(&&v: ~int) {
7-
borrow(v); // ERROR unique value in aliasable, mutable location
7+
borrow(v);
88
}
99

1010
fn borrow_from_arg_mut_ref(&v: ~int) {
11-
borrow(v); //! ERROR unique value in aliasable, mutable location
11+
borrow(v); //! ERROR access to non-pure functions prohibited in a pure context
12+
//!^ NOTE pure context is required due to an illegal borrow: unique value in aliasable, mutable location
1213
}
1314

1415
fn borrow_from_arg_move(-v: ~int) {

branches/try/src/test/compile-fail/borrowck-pat-enum-in-box.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,31 @@ fn match_imm_box(v: &const @option<int>) -> int {
99
}
1010

1111
fn match_const_box(v: &const @const option<int>) -> int {
12+
alt *v {
13+
@some(i) { i } // ok because this is pure
14+
@none {0}
15+
}
16+
}
17+
18+
pure fn pure_process(_i: int) {}
19+
20+
fn match_const_box_and_do_pure_things(v: &const @const option<int>) {
1221
alt *v {
1322
@some(i) {
14-
//!^ ERROR enum variant in aliasable, mutable location
15-
i
23+
pure_process(i)
1624
}
17-
@none {0}
25+
@none {}
26+
}
27+
}
28+
29+
fn process(_i: int) {}
30+
31+
fn match_const_box_and_do_bad_things(v: &const @const option<int>) {
32+
alt *v {
33+
@some(i) { //! NOTE pure context is required due to an illegal borrow: enum variant in aliasable, mutable location
34+
process(i) //! ERROR access to non-pure functions prohibited in a pure context
35+
}
36+
@none {}
1837
}
1938
}
2039

branches/try/src/test/compile-fail/borrowck-pat-enum.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
fn match_ref(&&v: option<int>) -> int {
55
alt v {
66
some(i) {
7-
//^ ERROR enum variant in aliasable, mutable location
87
i
98
}
109
none {0}
@@ -20,25 +19,33 @@ fn match_ref_unused(&&v: option<int>) {
2019

2120
fn match_const_reg(v: &const option<int>) -> int {
2221
alt *v {
23-
some(i) {
24-
//!^ ERROR enum variant in aliasable, mutable location
25-
i
26-
}
22+
some(i) {i} // OK because this is pure
2723
none {0}
2824
}
2925
}
3026

27+
fn impure(_i: int) {
28+
}
29+
3130
fn match_const_reg_unused(v: &const option<int>) {
3231
alt *v {
33-
some(_) {}
32+
some(_) {impure(0)} // OK because nothing is captured
3433
none {}
3534
}
3635
}
3736

38-
fn match_imm_reg(v: &option<int>) -> int {
37+
fn match_const_reg_impure(v: &const option<int>) {
3938
alt *v {
40-
some(i) {i}
41-
none {0}
39+
some(i) {impure(i)} //! ERROR access to non-pure functions prohibited in a pure context
40+
//!^ NOTE pure context is required due to an illegal borrow: enum variant in aliasable, mutable location
41+
none {}
42+
}
43+
}
44+
45+
fn match_imm_reg(v: &option<int>) {
46+
alt *v {
47+
some(i) {impure(i)} // OK because immutable
48+
none {}
4249
}
4350
}
4451

0 commit comments

Comments
 (0)