Skip to content

Commit

Permalink
Fix #2979: inference for lifetimes of & expressions
Browse files Browse the repository at this point in the history
What we now do is to create a region variable for each &
expression (and also each borrow).  The lifetime of this
variable will be checked by borrowck to ensure it is not greater
than the lifetime of the underlying data.  This both leads to
shorter lifetimes in some cases but also longer in others,
such as taking the address to the interior of unique boxes
tht are rooted in region pointers (e.g., returning a pointer
to the interior of a sendable map).

This may lead to issue #2977 if the rvalue is not POD, because
we may drop the data in trans sooner than borrowck expects us
to.  Need to work out precisely where that fix ought to occur.
  • Loading branch information
nikomatsakis committed Jul 30, 2012
1 parent 6ef13e7 commit 5d32d03
Show file tree
Hide file tree
Showing 34 changed files with 719 additions and 322 deletions.
26 changes: 8 additions & 18 deletions src/rustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,21 +436,6 @@ impl of tr for method_origin {
}
}

// ______________________________________________________________________
// Encoding and decoding of borrow

trait read_borrow_helper {
fn read_borrow(xcx: extended_decode_ctxt) -> ty::borrow;
}

impl helper of read_borrow_helper for ebml::ebml_deserializer {
fn read_borrow(xcx: extended_decode_ctxt) -> ty::borrow {
let borrow = ty::deserialize_borrow(self);
{scope_id: xcx.tr_id(borrow.scope_id),
mutbl: borrow.mutbl}
}
}

// ______________________________________________________________________
// Encoding and decoding vtable_res

Expand Down Expand Up @@ -766,11 +751,13 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt,
}
}

do option::iter(tcx.borrowings.find(id)) |borrow| {
do option::iter(tcx.borrowings.find(id)) |_borrow| {
do ebml_w.tag(c::tag_table_borrowings) {
ebml_w.id(id);
do ebml_w.tag(c::tag_table_val) {
ty::serialize_borrow(ebml_w, borrow)
// N.B. We don't actually serialize borrows as, in
// trans, we only care whether a value is borrowed or
// not.
}
}
}
Expand Down Expand Up @@ -890,7 +877,10 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
dcx.maps.vtable_map.insert(id,
val_dsr.read_vtable_res(xcx));
} else if tag == (c::tag_table_borrowings as uint) {
let borrow = val_dsr.read_borrow(xcx);
// N.B.: we don't actually *serialize* borrows because, in
// trans, the only thing we care about is whether a value was
// borrowed or not.
let borrow = {region: ty::re_static, mutbl: ast::m_imm};
dcx.tcx.borrowings.insert(id, borrow);
} else {
xcx.dcx.tcx.sess.bug(
Expand Down
55 changes: 35 additions & 20 deletions src/rustc/middle/borrowck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,9 +321,10 @@ type binding_map = std::map::hashmap<ast::node_id, ast::mutability>;
enum bckerr_code {
err_mut_uniq,
err_mut_variant,
err_preserve_gc,
err_mutbl(ast::mutability,
ast::mutability)
err_root_not_permitted,
err_mutbl(ast::mutability, ast::mutability),
err_out_of_root_scope(ty::region, ty::region), // superscope, subscope
err_out_of_scope(ty::region, ty::region) // superscope, subscope
}

// Combination of an error code and the categorization of the expression
Expand All @@ -346,7 +347,7 @@ enum categorization {
}

// different kinds of pointers:
enum ptr_kind {uniq_ptr, gc_ptr, region_ptr, unsafe_ptr}
enum ptr_kind {uniq_ptr, gc_ptr, region_ptr(ty::region), unsafe_ptr}

// I am coining the term "components" to mean "pieces of a data
// structure accessible without a dereference":
Expand Down Expand Up @@ -391,10 +392,15 @@ enum loan_path {
lp_comp(@loan_path, comp_kind)
}

// a complete record of a loan that was granted
/// a complete record of a loan that was granted
type loan = {lp: @loan_path, cmt: cmt, mutbl: ast::mutability};

// maps computed by `gather_loans` that are then used by `check_loans`
/// maps computed by `gather_loans` that are then used by `check_loans`
///
/// - `req_loan_map`: map from each block/expr to the required loans needed
/// for the duration of that block/expr
/// - `pure_map`: map from block/expr that must be pure to the error message
/// that should be reported if they are not pure
type req_maps = {
req_loan_map: hashmap<ast::node_id, @dvec<@dvec<loan>>>,
pure_map: hashmap<ast::node_id, bckerr>
Expand Down Expand Up @@ -519,7 +525,7 @@ impl to_str_methods for borrowck_ctxt {
alt ptr {
uniq_ptr { ~"~" }
gc_ptr { ~"@" }
region_ptr { ~"&" }
region_ptr(_) { ~"&" }
unsafe_ptr { ~"*" }
}
}
Expand Down Expand Up @@ -561,15 +567,6 @@ impl to_str_methods for borrowck_ctxt {
ty_to_str(self.tcx, cmt.ty)]
}

fn pk_to_sigil(pk: ptr_kind) -> ~str {
alt pk {
uniq_ptr {~"~"}
gc_ptr {~"@"}
region_ptr {~"&"}
unsafe_ptr {~"*"}
}
}
fn cmt_to_str(cmt: cmt) -> ~str {
let mut_str = self.mut_to_str(cmt.mutbl);
alt cmt.cat {
Expand All @@ -584,7 +581,7 @@ impl to_str_methods for borrowck_ctxt {
cat_binding(_) { ~"pattern binding" }
cat_arg(_) { ~"argument" }
cat_deref(_, _, pk) { #fmt["dereference of %s %s pointer",
mut_str, self.pk_to_sigil(pk)] }
mut_str, self.ptr_sigil(pk)] }
cat_stack_upvar(_) {
~"captured outer " + mut_str + ~" variable in a stack closure"
}
Expand Down Expand Up @@ -622,12 +619,30 @@ impl to_str_methods for borrowck_ctxt {
err_mut_variant {
~"enum variant in aliasable, mutable location"
}
err_preserve_gc {
~"GC'd value would have to be preserved for longer \
than the scope of the function"
err_root_not_permitted {
// note: I don't expect users to ever see this error
// message, reasons are discussed in attempt_root() in
// preserve.rs.
~"rooting is not permitted"
}
err_out_of_root_scope(super_scope, sub_scope) {
#fmt["managed value would have to be rooted for lifetime %s, \
but can only be rooted for lifetime %s",
self.region_to_str(sub_scope),
self.region_to_str(super_scope)]
}
err_out_of_scope(super_scope, sub_scope) {
#fmt["borrowed pointer has lifetime %s, \
but the borrowed value only has lifetime %s",
self.region_to_str(sub_scope),
self.region_to_str(super_scope)]
}
}
}

fn region_to_str(r: ty::region) -> ~str {
region_to_str(self.tcx, r)
}
}

// The inherent mutability of a component is its default mutability
Expand Down
14 changes: 7 additions & 7 deletions src/rustc/middle/borrowck/categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ fn opt_deref_kind(t: ty::t) -> option<deref_kind> {
some(deref_ptr(uniq_ptr))
}

ty::ty_rptr(*) |
ty::ty_evec(_, ty::vstore_slice(_)) |
ty::ty_estr(ty::vstore_slice(_)) {
some(deref_ptr(region_ptr))
ty::ty_rptr(r, _) |
ty::ty_evec(_, ty::vstore_slice(r)) |
ty::ty_estr(ty::vstore_slice(r)) {
some(deref_ptr(region_ptr(r)))
}

ty::ty_box(*) |
Expand Down Expand Up @@ -343,7 +343,7 @@ impl public_methods for borrowck_ctxt {
// not loanable.
alt ptr {
uniq_ptr => {some(@lp_deref(l, ptr))}
gc_ptr | region_ptr | unsafe_ptr => {none}
gc_ptr | region_ptr(_) | unsafe_ptr => {none}
}
};

Expand All @@ -353,7 +353,7 @@ impl public_methods for borrowck_ctxt {
uniq_ptr => {
self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
}
gc_ptr | region_ptr | unsafe_ptr => {
gc_ptr | region_ptr(_) | unsafe_ptr => {
mt.mutbl
}
};
Expand Down Expand Up @@ -402,7 +402,7 @@ impl public_methods for borrowck_ctxt {
uniq_ptr => {
self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
}
gc_ptr | region_ptr | unsafe_ptr => {
gc_ptr | region_ptr(_) | unsafe_ptr => {
mt.mutbl
}
};
Expand Down
Loading

0 comments on commit 5d32d03

Please sign in to comment.