Skip to content

Commit 1062955

Browse files
committed
Tweak mem categorization of upvar mutability
- Correctly categorize env pointer deref for `FnMut` as declared rather than inherited. This fixes an assert in borrowck. Closes #18238 - Categorize env pointer deref as mutable only if the closure is `FnMut` *and* the original variable is declared mutable. This disallows capture-by-value `FnMut` closures from mutating captured variables that aren't declared mutable. This is a difference from the equivalent desugared code which would permit it, but it is consistent with the behavior of procs. Closes #18335 - Avoid computing info about the env pointer if there isn't one.
1 parent 2877e47 commit 1062955

File tree

1 file changed

+69
-62
lines changed

1 file changed

+69
-62
lines changed

src/librustc/middle/mem_categorization.rs

Lines changed: 69 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -656,51 +656,54 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
656656
// FnOnce | copied | upvar -> &'up bk
657657
// old stack | N/A | upvar -> &'env mut -> &'up bk
658658
// old proc/once | copied | N/A
659+
let var_ty = if_ok!(self.node_ty(var_id));
660+
659661
let upvar_id = ty::UpvarId { var_id: var_id,
660662
closure_expr_id: fn_node_id };
661663

662-
// Do we need to deref through an env reference?
663-
let has_env_deref = kind != ty::FnOnceUnboxedClosureKind;
664-
665664
// Mutability of original variable itself
666665
let var_mutbl = MutabilityCategory::from_local(self.tcx(), var_id);
667666

668-
// Mutability of environment dereference
669-
let env_mutbl = match kind {
670-
ty::FnOnceUnboxedClosureKind => var_mutbl,
671-
ty::FnMutUnboxedClosureKind => McInherited,
672-
ty::FnUnboxedClosureKind => McImmutable
667+
// Construct information about env pointer dereference, if any
668+
let mutbl = match kind {
669+
ty::FnOnceUnboxedClosureKind => None, // None, env is by-value
670+
ty::FnMutUnboxedClosureKind => match mode { // Depends on capture type
671+
ast::CaptureByValue => Some(var_mutbl), // Mutable if the original var is
672+
ast::CaptureByRef => Some(McDeclared) // Mutable regardless
673+
},
674+
ty::FnUnboxedClosureKind => Some(McImmutable) // Never mutable
673675
};
676+
let env_info = mutbl.map(|env_mutbl| {
677+
// Look up the node ID of the closure body so we can construct
678+
// a free region within it
679+
let fn_body_id = {
680+
let fn_expr = match self.tcx().map.find(fn_node_id) {
681+
Some(ast_map::NodeExpr(e)) => e,
682+
_ => unreachable!()
683+
};
674684

675-
// Look up the node ID of the closure body so we can construct
676-
// a free region within it
677-
let fn_body_id = {
678-
let fn_expr = match self.tcx().map.find(fn_node_id) {
679-
Some(ast_map::NodeExpr(e)) => e,
680-
_ => unreachable!()
685+
match fn_expr.node {
686+
ast::ExprFnBlock(_, _, ref body) |
687+
ast::ExprProc(_, ref body) |
688+
ast::ExprUnboxedFn(_, _, _, ref body) => body.id,
689+
_ => unreachable!()
690+
}
681691
};
682692

683-
match fn_expr.node {
684-
ast::ExprFnBlock(_, _, ref body) |
685-
ast::ExprProc(_, ref body) |
686-
ast::ExprUnboxedFn(_, _, _, ref body) => body.id,
687-
_ => unreachable!()
688-
}
689-
};
693+
// Region of environment pointer
694+
let env_region = ty::ReFree(ty::FreeRegion {
695+
scope_id: fn_body_id,
696+
bound_region: ty::BrEnv
697+
});
690698

691-
// Region of environment pointer
692-
let env_region = ty::ReFree(ty::FreeRegion {
693-
scope_id: fn_body_id,
694-
bound_region: ty::BrEnv
695-
});
696-
697-
let env_ptr = BorrowedPtr(if env_mutbl.is_mutable() {
698-
ty::MutBorrow
699-
} else {
700-
ty::ImmBorrow
701-
}, env_region);
699+
let env_ptr = BorrowedPtr(if env_mutbl.is_mutable() {
700+
ty::MutBorrow
701+
} else {
702+
ty::ImmBorrow
703+
}, env_region);
702704

703-
let var_ty = if_ok!(self.node_ty(var_id));
705+
(env_mutbl, env_ptr)
706+
});
704707

705708
// First, switch by capture mode
706709
Ok(match mode {
@@ -718,25 +721,27 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
718721
note: NoteNone
719722
};
720723

721-
if has_env_deref {
722-
// We need to add the env deref. This means that
723-
// the above is actually immutable and has a ref
724-
// type. However, nothing should actually look at
725-
// the type, so we can get away with stuffing a
726-
// `ty_err` in there instead of bothering to
727-
// construct a proper one.
728-
base.mutbl = McImmutable;
729-
base.ty = ty::mk_err();
730-
Rc::new(cmt_ {
731-
id: id,
732-
span: span,
733-
cat: cat_deref(Rc::new(base), 0, env_ptr),
734-
mutbl: env_mutbl,
735-
ty: var_ty,
736-
note: NoteClosureEnv(upvar_id)
737-
})
738-
} else {
739-
Rc::new(base)
724+
match env_info {
725+
Some((env_mutbl, env_ptr)) => {
726+
// We need to add the env deref. This means
727+
// that the above is actually immutable and
728+
// has a ref type. However, nothing should
729+
// actually look at the type, so we can get
730+
// away with stuffing a `ty_err` in there
731+
// instead of bothering to construct a proper
732+
// one.
733+
base.mutbl = McImmutable;
734+
base.ty = ty::mk_err();
735+
Rc::new(cmt_ {
736+
id: id,
737+
span: span,
738+
cat: cat_deref(Rc::new(base), 0, env_ptr),
739+
mutbl: env_mutbl,
740+
ty: var_ty,
741+
note: NoteClosureEnv(upvar_id)
742+
})
743+
}
744+
None => Rc::new(base)
740745
}
741746
},
742747
ast::CaptureByRef => {
@@ -756,16 +761,18 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
756761
note: NoteNone
757762
};
758763

759-
// As in the by-value case, add env deref if needed
760-
if has_env_deref {
761-
base = cmt_ {
762-
id: id,
763-
span: span,
764-
cat: cat_deref(Rc::new(base), 0, env_ptr),
765-
mutbl: env_mutbl,
766-
ty: ty::mk_err(),
767-
note: NoteClosureEnv(upvar_id)
768-
};
764+
match env_info {
765+
Some((env_mutbl, env_ptr)) => {
766+
base = cmt_ {
767+
id: id,
768+
span: span,
769+
cat: cat_deref(Rc::new(base), 0, env_ptr),
770+
mutbl: env_mutbl,
771+
ty: ty::mk_err(),
772+
note: NoteClosureEnv(upvar_id)
773+
};
774+
}
775+
None => {}
769776
}
770777

771778
// Look up upvar borrow so we can get its region

0 commit comments

Comments
 (0)