Skip to content

Commit 58d6eb5

Browse files
committed
auto merge of #8797 : nikomatsakis/rust/issue-8625-assign-to-andmut-in-borrowed-loc-2, r=pcwalton
Fixes for #8625 to prevent assigning to `&mut` in borrowed or aliasable locations. The old code was insufficient in that it failed to catch bizarre cases like `& &mut &mut`. r? @pnkfelix
2 parents d5c144a + 8c09865 commit 58d6eb5

16 files changed

+166
-79
lines changed

src/librustc/middle/astencode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ impl tr for ast::def {
383383
ast::def_method(did0.tr(xcx), did1.map(|did1| did1.tr(xcx)))
384384
}
385385
ast::def_self_ty(nid) => { ast::def_self_ty(xcx.tr_id(nid)) }
386-
ast::def_self(nid, i) => { ast::def_self(xcx.tr_id(nid), i) }
386+
ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) }
387387
ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }
388388
ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) }
389389
ast::def_static(did, m) => { ast::def_static(did.tr(xcx), m) }

src/librustc/middle/borrowck/check_loans.rs

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,6 @@ impl<'self> CheckLoanCtxt<'self> {
367367

368368
mc::cat_rvalue(*) |
369369
mc::cat_static_item |
370-
mc::cat_implicit_self |
371370
mc::cat_copied_upvar(*) |
372371
mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
373372
mc::cat_deref(_, _, mc::gc_ptr(*)) |
@@ -406,15 +405,7 @@ impl<'self> CheckLoanCtxt<'self> {
406405
mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) => {
407406
// Statically prohibit writes to `&mut` when aliasable
408407

409-
match b.freely_aliasable() {
410-
None => {}
411-
Some(cause) => {
412-
this.bccx.report_aliasability_violation(
413-
expr.span,
414-
MutabilityViolation,
415-
cause);
416-
}
417-
}
408+
check_for_aliasability_violation(this, expr, b);
418409
}
419410

420411
mc::cat_deref(_, deref_count, mc::gc_ptr(ast::m_mutbl)) => {
@@ -434,6 +425,51 @@ impl<'self> CheckLoanCtxt<'self> {
434425
return true; // no errors reported
435426
}
436427

428+
fn check_for_aliasability_violation(this: &CheckLoanCtxt,
429+
expr: @ast::expr,
430+
cmt: mc::cmt) -> bool {
431+
let mut cmt = cmt;
432+
433+
loop {
434+
match cmt.cat {
435+
mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) |
436+
mc::cat_downcast(b) |
437+
mc::cat_stack_upvar(b) |
438+
mc::cat_deref(b, _, mc::uniq_ptr) |
439+
mc::cat_interior(b, _) |
440+
mc::cat_discr(b, _) => {
441+
// Aliasability depends on base cmt
442+
cmt = b;
443+
}
444+
445+
mc::cat_copied_upvar(_) |
446+
mc::cat_rvalue(*) |
447+
mc::cat_local(*) |
448+
mc::cat_arg(_) |
449+
mc::cat_self(*) |
450+
mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
451+
mc::cat_static_item(*) |
452+
mc::cat_deref(_, _, mc::gc_ptr(_)) |
453+
mc::cat_deref(_, _, mc::region_ptr(m_const, _)) |
454+
mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) => {
455+
// Aliasability is independent of base cmt
456+
match cmt.freely_aliasable() {
457+
None => {
458+
return true;
459+
}
460+
Some(cause) => {
461+
this.bccx.report_aliasability_violation(
462+
expr.span,
463+
MutabilityViolation,
464+
cause);
465+
return false;
466+
}
467+
}
468+
}
469+
}
470+
}
471+
}
472+
437473
fn check_for_assignment_to_restricted_or_frozen_location(
438474
this: &CheckLoanCtxt,
439475
expr: @ast::expr,
@@ -511,6 +547,12 @@ impl<'self> CheckLoanCtxt<'self> {
511547
// path, and check that the super path was not lent out as
512548
// mutable or immutable (a const loan is ok).
513549
//
550+
// Mutability of a path can be dependent on the super path
551+
// in two ways. First, it might be inherited mutability.
552+
// Second, the pointee of an `&mut` pointer can only be
553+
// mutated if it is found in an unaliased location, so we
554+
// have to check that the owner location is not borrowed.
555+
//
514556
// Note that we are *not* checking for any and all
515557
// restrictions. We are only interested in the pointers
516558
// that the user created, whereas we add restrictions for
@@ -528,9 +570,12 @@ impl<'self> CheckLoanCtxt<'self> {
528570
let mut loan_path = loan_path;
529571
loop {
530572
match *loan_path {
531-
// Peel back one layer if `loan_path` has
532-
// inherited mutability
533-
LpExtend(lp_base, mc::McInherited, _) => {
573+
// Peel back one layer if, for `loan_path` to be
574+
// mutable, `lp_base` must be mutable. This occurs
575+
// with inherited mutability and with `&mut`
576+
// pointers.
577+
LpExtend(lp_base, mc::McInherited, _) |
578+
LpExtend(lp_base, _, LpDeref(mc::region_ptr(ast::m_mutbl, _))) => {
534579
loan_path = lp_base;
535580
}
536581

src/librustc/middle/borrowck/gather_loans/gather_moves.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ fn check_is_legal_to_move_from(bccx: @BorrowckCtxt,
100100
cmt0: mc::cmt,
101101
cmt: mc::cmt) -> bool {
102102
match cmt.cat {
103-
mc::cat_implicit_self(*) |
104103
mc::cat_deref(_, _, mc::region_ptr(*)) |
105104
mc::cat_deref(_, _, mc::gc_ptr(*)) |
106105
mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ impl GuaranteeLifetimeContext {
6868
6969
match cmt.cat {
7070
mc::cat_rvalue(*) |
71-
mc::cat_implicit_self |
7271
mc::cat_copied_upvar(*) | // L-Local
7372
mc::cat_local(*) | // L-Local
7473
mc::cat_arg(*) | // L-Local
@@ -301,7 +300,6 @@ impl GuaranteeLifetimeContext {
301300
}
302301
mc::cat_rvalue(*) |
303302
mc::cat_static_item |
304-
mc::cat_implicit_self |
305303
mc::cat_copied_upvar(*) |
306304
mc::cat_deref(*) => {
307305
false
@@ -328,7 +326,6 @@ impl GuaranteeLifetimeContext {
328326
mc::cat_rvalue(cleanup_scope_id) => {
329327
ty::re_scope(cleanup_scope_id)
330328
}
331-
mc::cat_implicit_self |
332329
mc::cat_copied_upvar(_) => {
333330
ty::re_scope(self.item_scope_id)
334331
}

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ impl RestrictionsContext {
101101
self.extend(result, cmt.mutbl, LpInterior(i), restrictions)
102102
}
103103

104-
mc::cat_deref(cmt_base, _, mc::uniq_ptr) => {
104+
mc::cat_deref(cmt_base, _, pk @ mc::uniq_ptr) => {
105105
// R-Deref-Send-Pointer
106106
//
107107
// When we borrow the interior of an owned pointer, we
@@ -110,12 +110,11 @@ impl RestrictionsContext {
110110
let result = self.restrict(
111111
cmt_base,
112112
restrictions | RESTR_MUTATE | RESTR_CLAIM);
113-
self.extend(result, cmt.mutbl, LpDeref, restrictions)
113+
self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
114114
}
115115

116116
mc::cat_copied_upvar(*) | // FIXME(#2152) allow mutation of upvars
117117
mc::cat_static_item(*) |
118-
mc::cat_implicit_self(*) |
119118
mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) |
120119
mc::cat_deref(_, _, mc::gc_ptr(m_imm)) => {
121120
// R-Deref-Imm-Borrowed
@@ -129,7 +128,7 @@ impl RestrictionsContext {
129128
Safe
130129
}
131130

132-
mc::cat_deref(cmt_base, _, mc::gc_ptr(m_mutbl)) => {
131+
mc::cat_deref(cmt_base, _, pk @ mc::gc_ptr(m_mutbl)) => {
133132
// R-Deref-Managed-Borrowed
134133
//
135134
// Technically, no restrictions are *necessary* here.
@@ -170,14 +169,14 @@ impl RestrictionsContext {
170169
match opt_loan_path(cmt_base) {
171170
None => Safe,
172171
Some(lp_base) => {
173-
let lp = @LpExtend(lp_base, cmt.mutbl, LpDeref);
172+
let lp = @LpExtend(lp_base, cmt.mutbl, LpDeref(pk));
174173
SafeIf(lp, ~[Restriction {loan_path: lp,
175174
set: restrictions}])
176175
}
177176
}
178177
}
179178

180-
mc::cat_deref(cmt_base, _, mc::region_ptr(m_mutbl, _)) => {
179+
mc::cat_deref(cmt_base, _, pk @ mc::region_ptr(m_mutbl, _)) => {
181180
// Because an `&mut` pointer does not inherit its
182181
// mutability, we can only prevent mutation or prevent
183182
// freezing if it is not aliased. Therefore, in such
@@ -187,7 +186,7 @@ impl RestrictionsContext {
187186
let result = self.restrict(
188187
cmt_base,
189188
RESTR_ALIAS | RESTR_MUTATE | RESTR_CLAIM);
190-
self.extend(result, cmt.mutbl, LpDeref, restrictions)
189+
self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
191190
} else {
192191
// R-Deref-Mut-Borrowed-2
193192
Safe

src/librustc/middle/borrowck/mod.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ pub enum LoanPath {
261261

262262
#[deriving(Eq, IterBytes)]
263263
pub enum LoanPathElem {
264-
LpDeref, // `*LV` in doc.rs
264+
LpDeref(mc::PointerKind), // `*LV` in doc.rs
265265
LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
266266
}
267267

@@ -284,8 +284,7 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
284284
match cmt.cat {
285285
mc::cat_rvalue(*) |
286286
mc::cat_static_item |
287-
mc::cat_copied_upvar(_) |
288-
mc::cat_implicit_self => {
287+
mc::cat_copied_upvar(_) => {
289288
None
290289
}
291290

@@ -295,9 +294,9 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
295294
Some(@LpVar(id))
296295
}
297296

298-
mc::cat_deref(cmt_base, _, _) => {
297+
mc::cat_deref(cmt_base, _, pk) => {
299298
do opt_loan_path(cmt_base).map_move |lp| {
300-
@LpExtend(lp, cmt.mutbl, LpDeref)
299+
@LpExtend(lp, cmt.mutbl, LpDeref(pk))
301300
}
302301
}
303302

@@ -728,7 +727,7 @@ impl BorrowckCtxt {
728727
loan_path: &LoanPath,
729728
out: &mut ~str) {
730729
match *loan_path {
731-
LpExtend(_, _, LpDeref) => {
730+
LpExtend(_, _, LpDeref(_)) => {
732731
out.push_char('(');
733732
self.append_loan_path_to_str(loan_path, out);
734733
out.push_char(')');
@@ -776,7 +775,7 @@ impl BorrowckCtxt {
776775
out.push_str("[]");
777776
}
778777

779-
LpExtend(lp_base, _, LpDeref) => {
778+
LpExtend(lp_base, _, LpDeref(_)) => {
780779
out.push_char('*');
781780
self.append_loan_path_to_str(lp_base, out);
782781
}
@@ -854,7 +853,7 @@ impl Repr for LoanPath {
854853
fmt!("$(%?)", id)
855854
}
856855

857-
&LpExtend(lp, _, LpDeref) => {
856+
&LpExtend(lp, _, LpDeref(_)) => {
858857
fmt!("%s.*", lp.repr(tcx))
859858
}
860859

0 commit comments

Comments
 (0)