Skip to content

Commit

Permalink
Issue the correct deref count for the implicit deref that occurs
Browse files Browse the repository at this point in the history
as part of an autoslice operation (rust-lang#6272).

Fixes rust-lang#6272.
  • Loading branch information
nikomatsakis authored and James Miller committed May 12, 2013
1 parent 94b60bc commit db20601
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 19 deletions.
4 changes: 2 additions & 2 deletions src/librustc/middle/borrowck/gather_loans/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ pub impl GatherLoanCtxt {
r)
}
ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
let cmt_index = mcx.cat_index(expr, cmt);
let cmt_index = mcx.cat_index(expr, cmt, autoderefs+1);
self.guarantee_valid(expr.id,
expr.span,
cmt_index,
Expand Down Expand Up @@ -574,7 +574,7 @@ pub impl GatherLoanCtxt {
let (slice_mutbl, slice_r) =
self.vec_slice_info(slice_pat, slice_ty);
let mcx = self.bccx.mc_ctxt();
let cmt_index = mcx.cat_index(slice_pat, cmt);
let cmt_index = mcx.cat_index(slice_pat, cmt, 0);
self.guarantee_valid(pat.id, pat.span,
cmt_index, slice_mutbl, slice_r);
}
Expand Down
10 changes: 10 additions & 0 deletions src/librustc/middle/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,16 @@ pub type LoanMap = @mut HashMap<ast::node_id, @Loan>;
//
// Note that there is no entry with derefs:3---the type of that expression
// is T, which is not a box.
//
// Note that implicit dereferences also occur with indexing of `@[]`,
// `@str`, etc. The same rules apply. So, for example, given a
// variable `x` of type `@[@[...]]`, if I have an instance of the
// expression `x[0]` which is then auto-slice'd, there would be two
// potential entries in the root map, both with the id of the `x[0]`
// expression. The entry with `derefs==0` refers to the deref of `x`
// used as part of evaluating `x[0]`. The entry with `derefs==1`
// refers to the deref of the `x[0]` that occurs as part of the
// auto-slice.
#[deriving(Eq, IterBytes)]
pub struct root_map_key {
id: ast::node_id,
Expand Down
41 changes: 36 additions & 5 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ pub impl mem_categorization_ctxt {
}

let base_cmt = self.cat_expr(base);
self.cat_index(expr, base_cmt)
self.cat_index(expr, base_cmt, 0)
}

ast::expr_path(_) => {
Expand Down Expand Up @@ -670,7 +670,39 @@ pub impl mem_categorization_ctxt {

fn cat_index<N:ast_node>(&self,
elt: N,
base_cmt: cmt) -> cmt {
base_cmt: cmt,
derefs: uint) -> cmt {
//! Creates a cmt for an indexing operation (`[]`); this
//! indexing operation may occurs as part of an
//! AutoBorrowVec, which when converting a `~[]` to an `&[]`
//! effectively takes the address of the 0th element.
//!
//! One subtle aspect of indexing that may not be
//! immediately obvious: for anything other than a fixed-length
//! vector, an operation like `x[y]` actually consists of two
//! disjoint (from the point of view of borrowck) operations.
//! The first is a deref of `x` to create a pointer `p` that points
//! at the first element in the array. The second operation is
//! an index which adds `y*sizeof(T)` to `p` to obtain the
//! pointer to `x[y]`. `cat_index` will produce a resulting
//! cmt containing both this deref and the indexing,
//! presuming that `base_cmt` is not of fixed-length type.
//!
//! In the event that a deref is needed, the "deref count"
//! is taken from the parameter `derefs`. See the comment
//! on the def'n of `root_map_key` in borrowck/mod.rs
//! for more details about deref counts; the summary is
//! that `derefs` should be 0 for an explicit indexing
//! operation and N+1 for an indexing that is part of
//! an auto-adjustment, where N is the number of autoderefs
//! in that adjustment.
//!
//! # Parameters
//! - `elt`: the AST node being indexed
//! - `base_cmt`: the cmt of `elt`
//! - `derefs`: the deref number to be used for
//! the implicit index deref, if any (see above)

let mt = match ty::index(base_cmt.ty) {
Some(mt) => mt,
None => {
Expand Down Expand Up @@ -698,7 +730,7 @@ pub impl mem_categorization_ctxt {
let deref_cmt = @cmt_ {
id:elt.id(),
span:elt.span(),
cat:cat_deref(base_cmt, 0u, ptr),
cat:cat_deref(base_cmt, derefs, ptr),
mutbl:m,
ty:mt.ty
};
Expand Down Expand Up @@ -878,8 +910,8 @@ pub impl mem_categorization_ctxt {
}

ast::pat_vec(ref before, slice, ref after) => {
let elt_cmt = self.cat_index(pat, cmt, 0);
for before.each |&before_pat| {
let elt_cmt = self.cat_index(pat, cmt);
self.cat_pattern(elt_cmt, before_pat, op);
}
for slice.each |&slice_pat| {
Expand All @@ -888,7 +920,6 @@ pub impl mem_categorization_ctxt {
self.cat_pattern(slice_cmt, slice_pat, op);
}
for after.each |&after_pat| {
let elt_cmt = self.cat_index(pat, cmt);
self.cat_pattern(elt_cmt, after_pat, op);
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/trans/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,8 @@ pub fn extract_vec_elems(bcx: block,
-> ExtractedBlock {
let _icx = bcx.insn_ctxt("match::extract_vec_elems");
let vec_datum = match_datum(bcx, val, pat_id);
let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span, pat_id);
let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span,
pat_id, 0);
let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id));

let mut elems = do vec::from_fn(elem_count) |i| {
Expand Down
5 changes: 3 additions & 2 deletions src/librustc/middle/trans/datum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,13 +735,14 @@ pub impl Datum {
fn get_vec_base_and_len(&self,
mut bcx: block,
span: span,
expr_id: ast::node_id)
expr_id: ast::node_id,
derefs: uint)
-> (block, ValueRef, ValueRef) {
//! Converts a vector into the slice pair. Performs rooting
//! and write guards checks.

// only imp't for @[] and @str, but harmless
bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, 0);
bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs);
let (base, len) = self.get_vec_base_and_len_no_root(bcx);
(bcx, base, len)
}
Expand Down
23 changes: 14 additions & 9 deletions src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,9 @@ use middle::trans::tvec;
use middle::trans::type_of;
use middle::ty::struct_fields;
use middle::ty::{AutoDerefRef, AutoAddEnv};
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn};
use middle::ty;
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn,
AutoDerefRef, AutoAddEnv, AutoUnsafe};
use middle::ty;
use util::common::indenter;
use util::ppaux::Repr;

Expand Down Expand Up @@ -215,10 +214,12 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
unpack_datum!(bcx, auto_ref(bcx, datum))
}
Some(AutoBorrowVec(*)) => {
unpack_datum!(bcx, auto_slice(bcx, expr, datum))
unpack_datum!(bcx, auto_slice(bcx, adj.autoderefs,
expr, datum))
}
Some(AutoBorrowVecRef(*)) => {
unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
unpack_datum!(bcx, auto_slice_and_ref(bcx, adj.autoderefs,
expr, datum))
}
Some(AutoBorrowFn(*)) => {
let adjusted_ty = ty::adjust_ty(bcx.tcx(), expr.span,
Expand Down Expand Up @@ -246,7 +247,10 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
mode: datum.mode, source: datum.source}}
}

fn auto_slice(bcx: block, expr: @ast::expr, datum: Datum) -> DatumBlock {
fn auto_slice(bcx: block,
autoderefs: uint,
expr: @ast::expr,
datum: Datum) -> DatumBlock {
// This is not the most efficient thing possible; since slices
// are two words it'd be better if this were compiled in
// 'dest' mode, but I can't find a nice way to structure the
Expand All @@ -256,9 +260,8 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
let tcx = bcx.tcx();
let unit_ty = ty::sequence_element_type(tcx, datum.ty);

// FIXME(#6272) need to distinguish "auto-slice" from explicit index?
let (bcx, base, len) =
datum.get_vec_base_and_len(bcx, expr.span, expr.id);
datum.get_vec_base_and_len(bcx, expr.span, expr.id, autoderefs+1);

// this type may have a different region/mutability than the
// real one, but it will have the same runtime representation
Expand Down Expand Up @@ -292,9 +295,10 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock {
}

fn auto_slice_and_ref(bcx: block,
autoderefs: uint,
expr: @ast::expr,
datum: Datum) -> DatumBlock {
let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum);
let DatumBlock { bcx, datum } = auto_slice(bcx, autoderefs, expr, datum);
auto_ref(bcx, datum)
}
}
Expand Down Expand Up @@ -913,7 +917,8 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
base::maybe_name_value(bcx.ccx(), scaled_ix, ~"scaled_ix");

let mut (bcx, base, len) =
base_datum.get_vec_base_and_len(bcx, index_expr.span, index_expr.id);
base_datum.get_vec_base_and_len(bcx, index_expr.span,
index_expr.id, 0);

if ty::type_is_str(base_ty) {
// acccount for null terminator in the case of string
Expand Down

0 comments on commit db20601

Please sign in to comment.