Skip to content

Commit f74b1c4

Browse files
committed
Categorize upvars in Fn unboxed closures as freely aliasable
This causes borrowck to correctly reject mutation or mutable borrows of upvars in `Fn` unboxed closures since the closure environment is aliasable. This also tracks the responsible closure in the aliasability information returned and uses it to give a helpful diagnostic. Closes issue #17780
1 parent ea3ab73 commit f74b1c4

File tree

3 files changed

+23
-2
lines changed

3 files changed

+23
-2
lines changed

src/librustc/middle/borrowck/check_loans.rs

+6
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
854854
check_for_aliasability_violation(this, span, b.clone());
855855
}
856856

857+
mc::cat_copied_upvar(mc::CopiedUpvar {
858+
kind: mc::Unboxed(ty::FnUnboxedClosureKind), ..}) => {
859+
// Prohibit writes to capture-by-move upvars in non-once closures
860+
check_for_aliasability_violation(this, span, guarantor.clone());
861+
}
862+
857863
_ => {}
858864
}
859865

src/librustc/middle/borrowck/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
728728
format!("{} in an aliasable location",
729729
prefix).as_slice());
730730
}
731+
mc::AliasableClosure(id) => {
732+
self.tcx.sess.span_err(span,
733+
format!("{} in a free variable from an \
734+
immutable unboxed closure", prefix).as_slice());
735+
span_note!(self.tcx.sess, self.tcx.map.span(id),
736+
"consider changing this closure to take self by mutable reference");
737+
}
731738
mc::AliasableStatic(..) |
732739
mc::AliasableStaticMut(..) => {
733740
self.tcx.sess.span_err(

src/librustc/middle/mem_categorization.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ pub enum categorization {
8383
cat_rvalue(ty::Region), // temporary val, argument is its scope
8484
cat_static_item,
8585
cat_copied_upvar(CopiedUpvar), // upvar copied into proc env
86-
cat_upvar(ty::UpvarId, ty::UpvarBorrow, Option<ty::UnboxedClosureKind>), // by ref upvar from stack or unboxed closure
86+
cat_upvar(ty::UpvarId, ty::UpvarBorrow,
87+
Option<ty::UnboxedClosureKind>), // by ref upvar from stack or unboxed closure
8788
cat_local(ast::NodeId), // local variable
8889
cat_deref(cmt, uint, PointerKind), // deref of a ptr
8990
cat_interior(cmt, InteriorKind), // something interior: field, tuple, etc
@@ -1246,6 +1247,7 @@ pub enum InteriorSafety {
12461247

12471248
pub enum AliasableReason {
12481249
AliasableBorrowed,
1250+
AliasableClosure(ast::NodeId), // Aliasable due to capture by unboxed closure expr
12491251
AliasableOther,
12501252
AliasableStatic(InteriorSafety),
12511253
AliasableStaticMut(InteriorSafety),
@@ -1302,7 +1304,6 @@ impl cmt_ {
13021304

13031305
cat_rvalue(..) |
13041306
cat_local(..) |
1305-
cat_upvar(..) |
13061307
cat_deref(_, _, UnsafePtr(..)) => { // yes, it's aliasable, but...
13071308
None
13081309
}
@@ -1317,6 +1318,13 @@ impl cmt_ {
13171318
}
13181319
}
13191320

1321+
cat_upvar(ty::UpvarId { closure_expr_id: id, .. }, _,
1322+
Some(ty::FnUnboxedClosureKind)) => {
1323+
Some(AliasableClosure(id))
1324+
}
1325+
1326+
cat_upvar(..) => None,
1327+
13201328
cat_static_item(..) => {
13211329
let int_safe = if ty::type_interior_is_unsafe(ctxt, self.ty) {
13221330
InteriorUnsafe

0 commit comments

Comments
 (0)