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
This commit is contained in:
parent
ea3ab731a3
commit
f74b1c4ee2
3 changed files with 23 additions and 2 deletions
|
|
@ -854,6 +854,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
|||
check_for_aliasability_violation(this, span, b.clone());
|
||||
}
|
||||
|
||||
mc::cat_copied_upvar(mc::CopiedUpvar {
|
||||
kind: mc::Unboxed(ty::FnUnboxedClosureKind), ..}) => {
|
||||
// Prohibit writes to capture-by-move upvars in non-once closures
|
||||
check_for_aliasability_violation(this, span, guarantor.clone());
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -728,6 +728,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
|||
format!("{} in an aliasable location",
|
||||
prefix).as_slice());
|
||||
}
|
||||
mc::AliasableClosure(id) => {
|
||||
self.tcx.sess.span_err(span,
|
||||
format!("{} in a free variable from an \
|
||||
immutable unboxed closure", prefix).as_slice());
|
||||
span_note!(self.tcx.sess, self.tcx.map.span(id),
|
||||
"consider changing this closure to take self by mutable reference");
|
||||
}
|
||||
mc::AliasableStatic(..) |
|
||||
mc::AliasableStaticMut(..) => {
|
||||
self.tcx.sess.span_err(
|
||||
|
|
|
|||
|
|
@ -83,7 +83,8 @@ pub enum categorization {
|
|||
cat_rvalue(ty::Region), // temporary val, argument is its scope
|
||||
cat_static_item,
|
||||
cat_copied_upvar(CopiedUpvar), // upvar copied into proc env
|
||||
cat_upvar(ty::UpvarId, ty::UpvarBorrow, Option<ty::UnboxedClosureKind>), // by ref upvar from stack or unboxed closure
|
||||
cat_upvar(ty::UpvarId, ty::UpvarBorrow,
|
||||
Option<ty::UnboxedClosureKind>), // by ref upvar from stack or unboxed closure
|
||||
cat_local(ast::NodeId), // local variable
|
||||
cat_deref(cmt, uint, PointerKind), // deref of a ptr
|
||||
cat_interior(cmt, InteriorKind), // something interior: field, tuple, etc
|
||||
|
|
@ -1246,6 +1247,7 @@ pub enum InteriorSafety {
|
|||
|
||||
pub enum AliasableReason {
|
||||
AliasableBorrowed,
|
||||
AliasableClosure(ast::NodeId), // Aliasable due to capture by unboxed closure expr
|
||||
AliasableOther,
|
||||
AliasableStatic(InteriorSafety),
|
||||
AliasableStaticMut(InteriorSafety),
|
||||
|
|
@ -1302,7 +1304,6 @@ impl cmt_ {
|
|||
|
||||
cat_rvalue(..) |
|
||||
cat_local(..) |
|
||||
cat_upvar(..) |
|
||||
cat_deref(_, _, UnsafePtr(..)) => { // yes, it's aliasable, but...
|
||||
None
|
||||
}
|
||||
|
|
@ -1317,6 +1318,13 @@ impl cmt_ {
|
|||
}
|
||||
}
|
||||
|
||||
cat_upvar(ty::UpvarId { closure_expr_id: id, .. }, _,
|
||||
Some(ty::FnUnboxedClosureKind)) => {
|
||||
Some(AliasableClosure(id))
|
||||
}
|
||||
|
||||
cat_upvar(..) => None,
|
||||
|
||||
cat_static_item(..) => {
|
||||
let int_safe = if ty::type_interior_is_unsafe(ctxt, self.ty) {
|
||||
InteriorUnsafe
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue