Skip to content

Commit f513380

Browse files
committed
Address Issue 14270 by making cmt::freely_aliasable result more fine-grained.
Instead of encoding the aliasability (i.e. whether the cmt is uniquely writable or not) as an option, now pass back an enum indicating either: 1. freely-aliasable (thus not uniquely-writable), 2. non-aliasble (thus uniquely writable), or 3. unique but immutable (and thus not uniquely writable, according to proposal from issue 14270.) This is all of course a giant hack that will hopefully go away with an eventually removal of special treatment of `Box<T>` (aka `ty_unique`) from the compiler.
1 parent 492b3b1 commit f513380

File tree

4 files changed

+64
-19
lines changed

4 files changed

+64
-19
lines changed

src/librustc/middle/mem_categorization.rs

+31-10
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ pub use self::Note::*;
7171
pub use self::deref_kind::*;
7272
pub use self::categorization::*;
7373

74+
use self::Aliasability::*;
75+
7476
use middle::check_const;
7577
use middle::def;
7678
use middle::region;
@@ -1387,17 +1389,25 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
13871389
}
13881390
}
13891391

1390-
#[derive(Copy)]
1392+
#[derive(Copy, Clone, Debug)]
13911393
pub enum InteriorSafety {
13921394
InteriorUnsafe,
13931395
InteriorSafe
13941396
}
13951397

1396-
#[derive(Copy)]
1398+
#[derive(Clone, Debug)]
1399+
pub enum Aliasability {
1400+
FreelyAliasable(AliasableReason),
1401+
NonAliasable,
1402+
ImmutableUnique(Box<Aliasability>),
1403+
}
1404+
1405+
#[derive(Copy, Clone, Debug)]
13971406
pub enum AliasableReason {
13981407
AliasableBorrowed,
13991408
AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env
14001409
AliasableOther,
1410+
UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique
14011411
AliasableStatic(InteriorSafety),
14021412
AliasableStaticMut(InteriorSafety),
14031413
}
@@ -1426,9 +1436,9 @@ impl<'tcx> cmt_<'tcx> {
14261436
}
14271437
}
14281438

1429-
/// Returns `Some(_)` if this lvalue represents a freely aliasable pointer type.
1439+
/// Returns `FreelyAliasable(_)` if this lvalue represents a freely aliasable pointer type.
14301440
pub fn freely_aliasable(&self, ctxt: &ty::ctxt<'tcx>)
1431-
-> Option<AliasableReason> {
1441+
-> Aliasability {
14321442
// Maybe non-obvious: copied upvars can only be considered
14331443
// non-aliasable in once closures, since any other kind can be
14341444
// aliased and eventually recused.
@@ -1439,17 +1449,27 @@ impl<'tcx> cmt_<'tcx> {
14391449
cat_deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
14401450
cat_deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
14411451
cat_downcast(ref b, _) |
1442-
cat_deref(ref b, _, Unique) |
14431452
cat_interior(ref b, _) => {
14441453
// Aliasability depends on base cmt
14451454
b.freely_aliasable(ctxt)
14461455
}
14471456

1457+
cat_deref(ref b, _, Unique) => {
1458+
let sub = b.freely_aliasable(ctxt);
1459+
if b.mutbl.is_mutable() {
1460+
// Aliasability depends on base cmt alone
1461+
sub
1462+
} else {
1463+
// Do not allow mutation through an immutable box.
1464+
ImmutableUnique(Box::new(sub))
1465+
}
1466+
}
1467+
14481468
cat_rvalue(..) |
14491469
cat_local(..) |
14501470
cat_upvar(..) |
14511471
cat_deref(_, _, UnsafePtr(..)) => { // yes, it's aliasable, but...
1452-
None
1472+
NonAliasable
14531473
}
14541474

14551475
cat_static_item(..) => {
@@ -1460,17 +1480,18 @@ impl<'tcx> cmt_<'tcx> {
14601480
};
14611481

14621482
if self.mutbl.is_mutable() {
1463-
Some(AliasableStaticMut(int_safe))
1483+
FreelyAliasable(AliasableStaticMut(int_safe))
14641484
} else {
1465-
Some(AliasableStatic(int_safe))
1485+
FreelyAliasable(AliasableStatic(int_safe))
14661486
}
14671487
}
14681488

14691489
cat_deref(ref base, _, BorrowedPtr(ty::ImmBorrow, _)) |
14701490
cat_deref(ref base, _, Implicit(ty::ImmBorrow, _)) => {
14711491
match base.cat {
1472-
cat_upvar(Upvar{ id, .. }) => Some(AliasableClosure(id.closure_expr_id)),
1473-
_ => Some(AliasableBorrowed)
1492+
cat_upvar(Upvar{ id, .. }) =>
1493+
FreelyAliasable(AliasableClosure(id.closure_expr_id)),
1494+
_ => FreelyAliasable(AliasableBorrowed)
14741495
}
14751496
}
14761497
}

src/librustc_borrowck/borrowck/check_loans.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -943,13 +943,20 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
943943
cmt: mc::cmt<'tcx>)
944944
-> bool {
945945
match cmt.freely_aliasable(this.tcx()) {
946-
None => {
946+
mc::Aliasability::NonAliasable => {
947947
return true;
948948
}
949-
Some(mc::AliasableStaticMut(..)) => {
949+
mc::Aliasability::FreelyAliasable(mc::AliasableStaticMut(..)) => {
950950
return true;
951951
}
952-
Some(cause) => {
952+
mc::Aliasability::ImmutableUnique(_) => {
953+
this.bccx.report_aliasability_violation(
954+
span,
955+
MutabilityViolation,
956+
mc::AliasableReason::UnaliasableImmutable);
957+
return false;
958+
}
959+
mc::Aliasability::FreelyAliasable(cause) => {
953960
this.bccx.report_aliasability_violation(
954961
span,
955962
MutabilityViolation,

src/librustc_borrowck/borrowck/gather_loans/mod.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,16 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
182182
req_kind: ty::BorrowKind)
183183
-> Result<(),()> {
184184

185-
match (cmt.freely_aliasable(bccx.tcx), req_kind) {
186-
(None, _) => {
185+
let aliasability = cmt.freely_aliasable(bccx.tcx);
186+
debug!("check_aliasability aliasability={:?} req_kind={:?}",
187+
aliasability, req_kind);
188+
189+
match (aliasability, req_kind) {
190+
(mc::Aliasability::NonAliasable, _) => {
187191
/* Uniquely accessible path -- OK for `&` and `&mut` */
188192
Ok(())
189193
}
190-
(Some(mc::AliasableStatic(safety)), ty::ImmBorrow) => {
194+
(mc::Aliasability::FreelyAliasable(mc::AliasableStatic(safety)), ty::ImmBorrow) => {
191195
// Borrow of an immutable static item:
192196
match safety {
193197
mc::InteriorUnsafe => {
@@ -203,13 +207,20 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
203207
}
204208
}
205209
}
206-
(Some(mc::AliasableStaticMut(..)), _) => {
210+
(mc::Aliasability::FreelyAliasable(mc::AliasableStaticMut(..)), _) => {
207211
// Even touching a static mut is considered unsafe. We assume the
208212
// user knows what they're doing in these cases.
209213
Ok(())
210214
}
211-
(Some(alias_cause), ty::UniqueImmBorrow) |
212-
(Some(alias_cause), ty::MutBorrow) => {
215+
(mc::Aliasability::ImmutableUnique(_), ty::MutBorrow) => {
216+
bccx.report_aliasability_violation(
217+
borrow_span,
218+
BorrowViolation(loan_cause),
219+
mc::AliasableReason::UnaliasableImmutable);
220+
Err(())
221+
}
222+
(mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) |
223+
(mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => {
213224
bccx.report_aliasability_violation(
214225
borrow_span,
215226
BorrowViolation(loan_cause),

src/librustc_borrowck/borrowck/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
844844
&format!("{} in an aliasable location",
845845
prefix));
846846
}
847+
mc::AliasableReason::UnaliasableImmutable => {
848+
self.tcx.sess.span_err(
849+
span,
850+
&format!("{} in an immutable container",
851+
prefix));
852+
}
847853
mc::AliasableClosure(id) => {
848854
self.tcx.sess.span_err(span,
849855
&format!("{} in a captured outer \

0 commit comments

Comments
 (0)