Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5ca383b

Browse files
committedMay 18, 2013
Distinguish tuple elements by index in mem_categorization. Fixes #5362.
1 parent ff08198 commit 5ca383b

File tree

8 files changed

+246
-81
lines changed

8 files changed

+246
-81
lines changed
 

‎src/librustc/middle/borrowck/check_loans.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ pub impl<'self> CheckLoanCtxt<'self> {
400400
cmt = b;
401401
}
402402

403+
mc::cat_downcast(b) |
403404
mc::cat_interior(b, _) => {
404405
if cmt.mutbl == mc::McInherited {
405406
cmt = b;

‎src/librustc/middle/borrowck/gather_loans/lifetime.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ impl GuaranteeLifetimeContext {
105105
}
106106
}
107107

108+
mc::cat_downcast(base) |
108109
mc::cat_deref(base, _, mc::uniq_ptr(*)) |
109110
mc::cat_interior(base, _) => {
110111
self.check(base, discr_scope)
@@ -303,6 +304,7 @@ impl GuaranteeLifetimeContext {
303304
mc::cat_deref(*) => {
304305
false
305306
}
307+
r @ mc::cat_downcast(*) |
306308
r @ mc::cat_interior(*) |
307309
r @ mc::cat_stack_upvar(*) |
308310
r @ mc::cat_discr(*) => {
@@ -340,6 +342,7 @@ impl GuaranteeLifetimeContext {
340342
mc::cat_deref(_, _, mc::region_ptr(_, r)) => {
341343
r
342344
}
345+
mc::cat_downcast(cmt) |
343346
mc::cat_deref(cmt, _, mc::uniq_ptr(*)) |
344347
mc::cat_deref(cmt, _, mc::gc_ptr(*)) |
345348
mc::cat_interior(cmt, _) |

‎src/librustc/middle/borrowck/gather_loans/restrictions.rs‎

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,24 +80,17 @@ impl RestrictionsContext {
8080
set: restrictions}])
8181
}
8282

83-
mc::cat_interior(cmt_base, i @ mc::interior_variant(_)) => {
83+
mc::cat_downcast(cmt_base) => {
8484
// When we borrow the interior of an enum, we have to
8585
// ensure the enum itself is not mutated, because that
8686
// could cause the type of the memory to change.
87-
let result = self.compute(cmt_base, restrictions | RESTR_MUTATE);
88-
self.extend(result, cmt.mutbl, LpInterior(i), restrictions)
87+
self.compute(cmt_base, restrictions | RESTR_MUTATE)
8988
}
9089

91-
mc::cat_interior(cmt_base, i @ mc::interior_tuple) |
92-
mc::cat_interior(cmt_base, i @ mc::interior_anon_field) |
93-
mc::cat_interior(cmt_base, i @ mc::interior_field(*)) |
94-
mc::cat_interior(cmt_base, i @ mc::interior_index(*)) => {
95-
// For all of these cases, overwriting the base would
96-
// not change the type of the memory, so no additional
97-
// restrictions are needed.
98-
//
99-
// FIXME(#5397) --- Mut fields are not treated soundly
100-
// (hopefully they will just get phased out)
90+
mc::cat_interior(cmt_base, i) => {
91+
// Overwriting the base would not change the type of
92+
// the memory, so no additional restrictions are
93+
// needed.
10194
let result = self.compute(cmt_base, restrictions);
10295
self.extend(result, cmt.mutbl, LpInterior(i), restrictions)
10396
}

‎src/librustc/middle/borrowck/mod.rs‎

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ pub enum LoanPath {
236236

237237
#[deriving(Eq)]
238238
pub enum LoanPathElem {
239-
LpDeref, // `*LV` in doc.rs
240-
LpInterior(mc::interior_kind) // `LV.f` in doc.rs
239+
LpDeref, // `*LV` in doc.rs
240+
LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
241241
}
242242

243243
pub impl LoanPath {
@@ -280,6 +280,7 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
280280
|&lp| @LpExtend(lp, cmt.mutbl, LpInterior(ik)))
281281
}
282282

283+
mc::cat_downcast(cmt_base) |
283284
mc::cat_stack_upvar(cmt_base) |
284285
mc::cat_discr(cmt_base, _) => {
285286
opt_loan_path(cmt_base)
@@ -616,24 +617,25 @@ pub impl BorrowckCtxt {
616617
}
617618
}
618619

619-
LpExtend(lp_base, _, LpInterior(mc::interior_field(fld))) => {
620+
LpExtend(lp_base, _, LpInterior(mc::InteriorField(fname))) => {
620621
self.append_loan_path_to_str_from_interior(lp_base, out);
621-
str::push_char(out, '.');
622-
str::push_str(out, *self.tcx.sess.intr().get(fld));
622+
match fname {
623+
mc::NamedField(fname) => {
624+
str::push_char(out, '.');
625+
str::push_str(out, *self.tcx.sess.intr().get(fname));
626+
}
627+
mc::PositionalField(idx) => {
628+
str::push_char(out, '#'); // invent a notation here
629+
str::push_str(out, idx.to_str());
630+
}
631+
}
623632
}
624633

625-
LpExtend(lp_base, _, LpInterior(mc::interior_index(*))) => {
634+
LpExtend(lp_base, _, LpInterior(mc::InteriorElement(_))) => {
626635
self.append_loan_path_to_str_from_interior(lp_base, out);
627636
str::push_str(out, "[]");
628637
}
629638

630-
LpExtend(lp_base, _, LpInterior(mc::interior_tuple)) |
631-
LpExtend(lp_base, _, LpInterior(mc::interior_anon_field)) |
632-
LpExtend(lp_base, _, LpInterior(mc::interior_variant(_))) => {
633-
self.append_loan_path_to_str_from_interior(lp_base, out);
634-
str::push_str(out, ".(tuple)");
635-
}
636-
637639
LpExtend(lp_base, _, LpDeref) => {
638640
str::push_char(out, '*');
639641
self.append_loan_path_to_str(lp_base, out);

‎src/librustc/middle/mem_categorization.rs‎

Lines changed: 106 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,12 @@ pub enum categorization {
6666
cat_local(ast::node_id), // local variable
6767
cat_arg(ast::node_id), // formal argument
6868
cat_deref(cmt, uint, ptr_kind), // deref of a ptr
69-
cat_interior(cmt, interior_kind), // something interior
69+
cat_interior(cmt, InteriorKind), // something interior: field, tuple, etc
70+
cat_downcast(cmt), // selects a particular enum variant (*)
7071
cat_discr(cmt, ast::node_id), // match discriminant (see preserve())
7172
cat_self(ast::node_id), // explicit `self`
73+
74+
// (*) downcast is only required if the enum has more than one variant
7275
}
7376

7477
#[deriving(Eq)]
@@ -89,14 +92,15 @@ pub enum ptr_kind {
8992
// We use the term "interior" to mean "something reachable from the
9093
// base without a pointer dereference", e.g. a field
9194
#[deriving(Eq)]
92-
pub enum interior_kind {
93-
interior_tuple, // elt in a tuple
94-
interior_anon_field, // anonymous field (in e.g.
95-
// struct Foo(int, int);
96-
interior_variant(ast::def_id), // internals to a variant of given enum
97-
interior_field(ast::ident), // name of field
98-
interior_index(ty::t, // type of vec/str/etc being deref'd
99-
ast::mutability) // mutability of vec content
95+
pub enum InteriorKind {
96+
InteriorField(FieldName),
97+
InteriorElement(ty::t), // ty::t is the type of the vec/str
98+
}
99+
100+
#[deriving(Eq)]
101+
pub enum FieldName {
102+
NamedField(ast::ident),
103+
PositionalField(uint)
100104
}
101105

102106
#[deriving(Eq)]
@@ -134,7 +138,10 @@ pub type cmt = @cmt_;
134138

135139
// We pun on *T to mean both actual deref of a ptr as well
136140
// as accessing of components:
137-
pub enum deref_kind {deref_ptr(ptr_kind), deref_interior(interior_kind)}
141+
pub enum deref_kind {
142+
deref_ptr(ptr_kind),
143+
deref_interior(InteriorKind),
144+
}
138145

139146
// Categorizes a derefable type. Note that we include vectors and strings as
140147
// derefable (we model an index as the combination of a deref and then a
@@ -176,20 +183,14 @@ pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
176183
Some(deref_ptr(unsafe_ptr))
177184
}
178185

179-
ty::ty_enum(did, _) => {
180-
Some(deref_interior(interior_variant(did)))
181-
}
182-
183-
ty::ty_struct(_, _) => {
184-
Some(deref_interior(interior_anon_field))
185-
}
186-
187-
ty::ty_evec(mt, ty::vstore_fixed(_)) => {
188-
Some(deref_interior(interior_index(t, mt.mutbl)))
186+
ty::ty_enum(*) |
187+
ty::ty_struct(*) => { // newtype
188+
Some(deref_interior(InteriorField(PositionalField(0))))
189189
}
190190

191+
ty::ty_evec(_, ty::vstore_fixed(_)) |
191192
ty::ty_estr(ty::vstore_fixed(_)) => {
192-
Some(deref_interior(interior_index(t, m_imm)))
193+
Some(deref_interior(InteriorElement(t)))
193194
}
194195

195196
_ => None
@@ -579,7 +580,7 @@ pub impl mem_categorization_ctxt {
579580
@cmt_ {
580581
id: node.id(),
581582
span: node.span(),
582-
cat: cat_interior(base_cmt, interior_field(f_name)),
583+
cat: cat_interior(base_cmt, InteriorField(NamedField(f_name))),
583584
mutbl: base_cmt.mutbl.inherit(),
584585
ty: f_ty
585586
}
@@ -737,15 +738,16 @@ pub impl mem_categorization_ctxt {
737738
}
738739
};
739740

740-
fn interior<N: ast_node>(elt: N, of_cmt: cmt,
741-
vect: ty::t, mutbl: MutabilityCategory,
741+
fn interior<N: ast_node>(elt: N,
742+
of_cmt: cmt,
743+
vec_ty: ty::t,
744+
mutbl: MutabilityCategory,
742745
mt: ty::mt) -> cmt
743746
{
744-
let interior = interior_index(vect, mt.mutbl);
745747
@cmt_ {
746748
id:elt.id(),
747749
span:elt.span(),
748-
cat:cat_interior(of_cmt, interior),
750+
cat:cat_interior(of_cmt, InteriorElement(vec_ty)),
749751
mutbl:mutbl,
750752
ty:mt.ty
751753
}
@@ -756,7 +758,7 @@ pub impl mem_categorization_ctxt {
756758
node: N,
757759
base_cmt: cmt,
758760
interior_ty: ty::t,
759-
interior: interior_kind) -> cmt {
761+
interior: InteriorKind) -> cmt {
760762
@cmt_ {
761763
id: node.id(),
762764
span: node.span(),
@@ -766,6 +768,19 @@ pub impl mem_categorization_ctxt {
766768
}
767769
}
768770

771+
fn cat_downcast<N:ast_node>(&self,
772+
node: N,
773+
base_cmt: cmt,
774+
downcast_ty: ty::t) -> cmt {
775+
@cmt_ {
776+
id: node.id(),
777+
span: node.span(),
778+
cat: cat_downcast(base_cmt),
779+
mutbl: base_cmt.mutbl.inherit(),
780+
ty: downcast_ty
781+
}
782+
}
783+
769784
fn cat_pattern(&self,
770785
cmt: cmt,
771786
pat: @ast::pat,
@@ -835,21 +850,34 @@ pub impl mem_categorization_ctxt {
835850
match self.tcx.def_map.find(&pat.id) {
836851
Some(&ast::def_variant(enum_did, _)) => {
837852
// variant(x, y, z)
838-
for subpats.each |&subpat| {
853+
854+
let downcast_cmt = {
855+
if ty::enum_is_univariant(tcx, enum_did) {
856+
cmt // univariant, no downcast needed
857+
} else {
858+
self.cat_downcast(pat, cmt, cmt.ty)
859+
}
860+
};
861+
862+
for subpats.eachi |i, &subpat| {
839863
let subpat_ty = self.pat_ty(subpat); // see (*)
864+
840865
let subcmt =
841-
self.cat_imm_interior(pat, cmt, subpat_ty,
842-
interior_variant(enum_did));
866+
self.cat_imm_interior(
867+
pat, downcast_cmt, subpat_ty,
868+
InteriorField(PositionalField(i)));
869+
843870
self.cat_pattern(subcmt, subpat, op);
844871
}
845872
}
846873
Some(&ast::def_fn(*)) |
847874
Some(&ast::def_struct(*)) => {
848-
for subpats.each |&subpat| {
875+
for subpats.eachi |i, &subpat| {
849876
let subpat_ty = self.pat_ty(subpat); // see (*)
850877
let cmt_field =
851-
self.cat_imm_interior(pat, cmt, subpat_ty,
852-
interior_anon_field);
878+
self.cat_imm_interior(
879+
pat, cmt, subpat_ty,
880+
InteriorField(PositionalField(i)));
853881
self.cat_pattern(cmt_field, subpat, op);
854882
}
855883
}
@@ -885,10 +913,12 @@ pub impl mem_categorization_ctxt {
885913

886914
ast::pat_tup(ref subpats) => {
887915
// (p1, ..., pN)
888-
for subpats.each |&subpat| {
916+
for subpats.eachi |i, &subpat| {
889917
let subpat_ty = self.pat_ty(subpat); // see (*)
890-
let subcmt = self.cat_imm_interior(pat, cmt, subpat_ty,
891-
interior_tuple);
918+
let subcmt =
919+
self.cat_imm_interior(
920+
pat, cmt, subpat_ty,
921+
InteriorField(PositionalField(i)));
892922
self.cat_pattern(subcmt, subpat, op);
893923
}
894924
}
@@ -931,22 +961,37 @@ pub impl mem_categorization_ctxt {
931961

932962
fn cmt_to_str(&self, cmt: cmt) -> ~str {
933963
match cmt.cat {
934-
cat_static_item => ~"static item",
935-
cat_implicit_self => ~"self reference",
964+
cat_static_item => {
965+
~"static item"
966+
}
967+
cat_implicit_self => {
968+
~"self reference"
969+
}
936970
cat_copied_upvar(_) => {
937971
~"captured outer variable in a heap closure"
938972
}
939-
cat_rvalue => ~"non-lvalue",
940-
cat_local(_) => ~"local variable",
941-
cat_self(_) => ~"self value",
942-
cat_arg(*) => ~"argument",
943-
cat_deref(_, _, pk) => fmt!("dereference of %s pointer",
944-
ptr_sigil(pk)),
945-
cat_interior(_, interior_field(*)) => ~"field",
946-
cat_interior(_, interior_tuple) => ~"tuple content",
947-
cat_interior(_, interior_anon_field) => ~"anonymous field",
948-
cat_interior(_, interior_variant(_)) => ~"enum content",
949-
cat_interior(_, interior_index(t, _)) => {
973+
cat_rvalue => {
974+
~"non-lvalue"
975+
}
976+
cat_local(_) => {
977+
~"local variable"
978+
}
979+
cat_self(_) => {
980+
~"self value"
981+
}
982+
cat_arg(*) => {
983+
~"argument"
984+
}
985+
cat_deref(_, _, pk) => {
986+
fmt!("dereference of %s pointer", ptr_sigil(pk))
987+
}
988+
cat_interior(_, InteriorField(NamedField(_))) => {
989+
~"field"
990+
}
991+
cat_interior(_, InteriorField(PositionalField(_))) => {
992+
~"anonymous field"
993+
}
994+
cat_interior(_, InteriorElement(t)) => {
950995
match ty::get(t).sty {
951996
ty::ty_evec(*) => ~"vec content",
952997
ty::ty_estr(*) => ~"str content",
@@ -959,6 +1004,9 @@ pub impl mem_categorization_ctxt {
9591004
cat_discr(cmt, _) => {
9601005
self.cmt_to_str(cmt)
9611006
}
1007+
cat_downcast(cmt) => {
1008+
self.cmt_to_str(cmt)
1009+
}
9621010
}
9631011
}
9641012

@@ -1027,6 +1075,7 @@ pub impl cmt_ {
10271075
cat_deref(_, _, region_ptr(*)) => {
10281076
self
10291077
}
1078+
cat_downcast(b) |
10301079
cat_stack_upvar(b) |
10311080
cat_discr(b, _) |
10321081
cat_interior(b, _) |
@@ -1075,6 +1124,7 @@ pub impl cmt_ {
10751124
Some(AliasableBorrowed(m))
10761125
}
10771126

1127+
cat_downcast(b) |
10781128
cat_stack_upvar(b) |
10791129
cat_deref(b, _, uniq_ptr(*)) |
10801130
cat_interior(b, _) |
@@ -1114,6 +1164,9 @@ impl Repr for categorization {
11141164
cmt.cat.repr(tcx),
11151165
interior.repr(tcx))
11161166
}
1167+
cat_downcast(cmt) => {
1168+
fmt!("%s->(enum)", cmt.cat.repr(tcx))
1169+
}
11171170
cat_stack_upvar(cmt) |
11181171
cat_discr(cmt, _) => cmt.cat.repr(tcx)
11191172
}
@@ -1129,14 +1182,12 @@ pub fn ptr_sigil(ptr: ptr_kind) -> ~str {
11291182
}
11301183
}
11311184
1132-
impl Repr for interior_kind {
1185+
impl Repr for InteriorKind {
11331186
fn repr(&self, tcx: ty::ctxt) -> ~str {
11341187
match *self {
1135-
interior_field(fld) => copy *tcx.sess.str_of(fld),
1136-
interior_index(*) => ~"[]",
1137-
interior_tuple => ~"()",
1138-
interior_anon_field => ~"<anonymous field>",
1139-
interior_variant(_) => ~"<enum>"
1188+
InteriorField(NamedField(fld)) => copy *tcx.sess.str_of(fld),
1189+
InteriorField(PositionalField(i)) => fmt!("#%?", i),
1190+
InteriorElement(_) => ~"[]",
11401191
}
11411192
}
11421193
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Tests that we are able to distinguish when loans borrow different
2+
// anonymous fields of an tuple vs the same anonymous field.
3+
4+
struct Y(uint, uint);
5+
6+
fn distinct_variant() {
7+
let mut y = Y(1, 2);
8+
9+
let a = match y {
10+
Y(ref mut a, _) => a
11+
};
12+
13+
let b = match y {
14+
Y(_, ref mut b) => b
15+
};
16+
17+
*a += 1;
18+
*b += 1;
19+
}
20+
21+
fn same_variant() {
22+
let mut y = Y(1, 2);
23+
24+
let a = match y {
25+
Y(ref mut a, _) => a
26+
};
27+
28+
let b = match y {
29+
Y(ref mut b, _) => b //~ ERROR cannot borrow
30+
};
31+
32+
*a += 1;
33+
*b += 1;
34+
}
35+
36+
fn main() {
37+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Tests that we are able to distinguish when loans borrow different
2+
// anonymous fields of a tuple vs the same anonymous field.
3+
4+
fn distinct_variant() {
5+
let mut y = (1, 2);
6+
7+
let a = match y {
8+
(ref mut a, _) => a
9+
};
10+
11+
let b = match y {
12+
(_, ref mut b) => b
13+
};
14+
15+
*a += 1;
16+
*b += 1;
17+
}
18+
19+
fn same_variant() {
20+
let mut y = (1, 2);
21+
22+
let a = match y {
23+
(ref mut a, _) => a
24+
};
25+
26+
let b = match y {
27+
(ref mut b, _) => b //~ ERROR cannot borrow
28+
};
29+
30+
*a += 1;
31+
*b += 1;
32+
}
33+
34+
fn main() {
35+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Tests that we are able to distinguish when loans borrow different
2+
// anonymous fields of an enum variant vs the same anonymous field.
3+
4+
enum Foo {
5+
X, Y(uint, uint)
6+
}
7+
8+
fn distinct_variant() {
9+
let mut y = Y(1, 2);
10+
11+
let a = match y {
12+
Y(ref mut a, _) => a,
13+
X => fail!()
14+
};
15+
16+
let b = match y {
17+
Y(_, ref mut b) => b,
18+
X => fail!()
19+
};
20+
21+
*a += 1;
22+
*b += 1;
23+
}
24+
25+
fn same_variant() {
26+
let mut y = Y(1, 2);
27+
28+
let a = match y {
29+
Y(ref mut a, _) => a,
30+
X => fail!()
31+
};
32+
33+
let b = match y {
34+
Y(ref mut b, _) => b, //~ ERROR cannot borrow
35+
X => fail!()
36+
};
37+
38+
*a += 1;
39+
*b += 1;
40+
}
41+
42+
fn main() {
43+
}

5 commit comments

Comments
 (5)

bors commented on May 21, 2013

@bors
Collaborator

saw approval from graydon
at nikomatsakis@5ca383b

bors commented on May 21, 2013

@bors
Collaborator

merging nikomatsakis/rust/issue-5362-tuple-indices = 5ca383b into auto

bors commented on May 21, 2013

@bors
Collaborator

nikomatsakis/rust/issue-5362-tuple-indices = 5ca383b merged ok, testing candidate = 32e30aa

bors commented on May 21, 2013

@bors
Collaborator

fast-forwarding incoming to auto = 32e30aa

Please sign in to comment.