From 8fb4c41f35fee3b224ea87148cb2ae31a9ed4675 Mon Sep 17 00:00:00 2001 From: Ziru Niu Date: Wed, 31 May 2023 06:25:27 +0800 Subject: [PATCH 1/3] merge `BorrowKind::Unique` into `BorrowKind::Mut` --- compiler/rustc_borrowck/src/borrow_set.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 40 ++++++++++++------- .../rustc_borrowck/src/diagnostics/mod.rs | 6 +-- .../src/diagnostics/mutability_errors.rs | 4 +- compiler/rustc_borrowck/src/invalidation.rs | 13 +++--- compiler/rustc_borrowck/src/lib.rs | 38 +++++++----------- .../rustc_borrowck/src/places_conflict.rs | 6 ++- .../src/transform/check_consts/check.rs | 3 +- .../src/transform/check_consts/resolver.rs | 2 +- .../src/transform/promote_consts.rs | 4 +- compiler/rustc_middle/src/mir/mod.rs | 12 +++--- compiler/rustc_middle/src/mir/syntax.rs | 24 +++++------ compiler/rustc_middle/src/mir/tcx.rs | 5 --- compiler/rustc_middle/src/mir/visit.rs | 3 -- .../src/build/expr/as_rvalue.rs | 6 +-- .../rustc_mir_build/src/check_unsafety.rs | 20 ++++++---- compiler/rustc_mir_build/src/thir/cx/expr.rs | 16 +++++--- .../rustc_mir_build/src/thir/pattern/mod.rs | 2 +- .../rustc_mir_dataflow/src/elaborate_drops.rs | 2 +- compiler/rustc_mir_transform/src/inline.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 4 +- 21 files changed, 109 insertions(+), 105 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 6be20b0974ddb..cf17b16b63aa4 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -72,7 +72,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { let kind = match self.kind { mir::BorrowKind::Shared => "", mir::BorrowKind::Shallow => "shallow ", - mir::BorrowKind::Unique => "uniq ", + mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ", mir::BorrowKind::Mut { .. } => "mut ", }; write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index fd5c21cfdf627..ca7b092a8a764 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -15,8 +15,9 @@ use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory, - FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, - ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, + FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place, + PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, + VarBindingForm, }; use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty}; use rustc_middle::util::CallKind; @@ -926,7 +927,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // FIXME: supply non-"" `opt_via` when appropriate let first_borrow_desc; let mut err = match (gen_borrow_kind, issued_borrow.kind) { - (BorrowKind::Shared, BorrowKind::Mut { .. }) => { + ( + BorrowKind::Shared, + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + ) => { first_borrow_desc = "mutable "; self.cannot_reborrow_already_borrowed( span, @@ -940,7 +944,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None, ) } - (BorrowKind::Mut { .. }, BorrowKind::Shared) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + BorrowKind::Shared, + ) => { first_borrow_desc = "immutable "; let mut err = self.cannot_reborrow_already_borrowed( span, @@ -962,7 +969,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } - (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, + ) => { first_borrow_desc = "first "; let mut err = self.cannot_mutably_borrow_multiply( span, @@ -985,12 +995,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err } - (BorrowKind::Unique, BorrowKind::Unique) => { + ( + BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, + BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, + ) => { first_borrow_desc = "first "; self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None) } - (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => { + (BorrowKind::Mut { .. }, BorrowKind::Shallow) => { if let Some(immutable_section_description) = self.classify_immutable_section(issued_borrow.assigned_place) { @@ -1004,7 +1017,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_spans.var_subdiag( None, &mut err, - Some(BorrowKind::Unique), + Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { @@ -1038,7 +1051,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - (BorrowKind::Unique, _) => { + (BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, _) => { first_borrow_desc = "first "; self.cannot_uniquely_borrow_by_one_closure( span, @@ -1052,7 +1065,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) } - (BorrowKind::Shared, BorrowKind::Unique) => { + (BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => { first_borrow_desc = "first "; self.cannot_reborrow_already_uniquely_borrowed( span, @@ -1067,7 +1080,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) } - (BorrowKind::Mut { .. }, BorrowKind::Unique) => { + (BorrowKind::Mut { .. }, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => { first_borrow_desc = "first "; self.cannot_reborrow_already_uniquely_borrowed( span, @@ -1085,10 +1098,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow) | ( BorrowKind::Shallow, - BorrowKind::Mut { .. } - | BorrowKind::Unique - | BorrowKind::Shared - | BorrowKind::Shallow, + BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow, ) => unreachable!(), }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 1d3cc851888cf..931ee8767d9b5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -629,9 +629,9 @@ impl UseSpans<'_> { Some(kd) => match kd { rustc_middle::mir::BorrowKind::Shared | rustc_middle::mir::BorrowKind::Shallow - | rustc_middle::mir::BorrowKind::Unique => { - CaptureVarKind::Immut { kind_span: capture_kind_span } - } + | rustc_middle::mir::BorrowKind::Mut { + kind: rustc_middle::mir::MutBorrowKind::ClosureCapture, + } => CaptureVarKind::Immut { kind_span: capture_kind_span }, rustc_middle::mir::BorrowKind::Mut { .. } => { CaptureVarKind::Mut { kind_span: capture_kind_span } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 34d466db2b409..1ba490e9a01c2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -234,7 +234,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { borrow_spans.var_subdiag( None, &mut err, - Some(mir::BorrowKind::Mut { allow_two_phase_borrow: false }), + Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), |_kind, var_span| { let place = self.describe_any_place(access_place.as_ref()); crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure { @@ -300,7 +300,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _, mir::Rvalue::Ref( _, - mir::BorrowKind::Mut { allow_two_phase_borrow: false }, + mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, _, ), )), diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index e4fbe6ea4f438..0152d89eb8366 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -255,7 +255,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) } BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Unique | BorrowKind::Mut { .. } => { + BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(bk) { (Deep, Reservation(wk)) @@ -273,7 +273,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { Mutability::Mut => ( Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut { - allow_two_phase_borrow: false, + kind: mir::MutBorrowKind::Default, })), ), Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), @@ -376,14 +376,11 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { } (Read(_), BorrowKind::Shallow | BorrowKind::Shared) - | ( - Read(ReadKind::Borrow(BorrowKind::Shallow)), - BorrowKind::Unique | BorrowKind::Mut { .. }, - ) => { + | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { // Reads don't invalidate shared or shallow borrows } - (Read(_), BorrowKind::Unique | BorrowKind::Mut { .. }) => { + (Read(_), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(&this.dominators, borrow, location) { // If the borrow isn't active yet, reads don't invalidate it @@ -425,7 +422,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Unique | BorrowKind::Mut { .. } => true, + BorrowKind::Mut { .. } => true, }); self.access_place( diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4fcdda311bfd3..d27dc542ad505 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -29,8 +29,8 @@ use rustc_infer::infer::{ InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, }; use rustc_middle::mir::{ - traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand, - Place, PlaceElem, PlaceRef, VarDebugInfoContents, + traversal, Body, ClearCrossCrate, Local, Location, MutBorrowKind, Mutability, + NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents, }; use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; @@ -1071,10 +1071,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } (Read(_), BorrowKind::Shared | BorrowKind::Shallow) - | ( - Read(ReadKind::Borrow(BorrowKind::Shallow)), - BorrowKind::Unique | BorrowKind::Mut { .. }, - ) => Control::Continue, + | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { + Control::Continue + } (Reservation(_), BorrowKind::Shallow | BorrowKind::Shared) => { // This used to be a future compatibility warning (to be @@ -1087,7 +1086,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Control::Continue } - (Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => { + (Read(kind), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(this.dominators(), borrow, location) { assert!(allow_two_phase_borrow(borrow.kind)); @@ -1194,7 +1193,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) } BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), - BorrowKind::Unique | BorrowKind::Mut { .. } => { + BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(bk) { (Deep, Reservation(wk)) @@ -1231,7 +1230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Mutability::Mut => ( Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut { - allow_two_phase_borrow: false, + kind: MutBorrowKind::Default, })), ), Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), @@ -1565,7 +1564,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Unique | BorrowKind::Mut { .. } => true, + BorrowKind::Mut { .. } => true, }); self.access_place( @@ -1959,14 +1958,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let the_place_err; match kind { - Reservation(WriteKind::MutableBorrow( - borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), - )) - | Write(WriteKind::MutableBorrow( - borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }), - )) => { + Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) + | Write(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) => { let is_local_mutation_allowed = match borrow_kind { - BorrowKind::Unique => LocalMutationIsAllowed::Yes, + BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { + LocalMutationIsAllowed::Yes + } BorrowKind::Mut { .. } => is_local_mutation_allowed, BorrowKind::Shared | BorrowKind::Shallow => unreachable!(), }; @@ -2031,12 +2028,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return false; } Read( - ReadKind::Borrow( - BorrowKind::Unique - | BorrowKind::Mut { .. } - | BorrowKind::Shared - | BorrowKind::Shallow, - ) + ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow) | ReadKind::Copy, ) => { // Access authorized diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 25c485b814f4a..c83d045a94e18 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -4,7 +4,9 @@ use crate::ArtificialField; use crate::Overlap; use crate::{AccessDepth, Deep, Shallow}; use rustc_hir as hir; -use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem}; +use rustc_middle::mir::{ + Body, BorrowKind, Local, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem, +}; use rustc_middle::ty::{self, TyCtxt}; use std::cmp::max; use std::iter; @@ -35,7 +37,7 @@ pub fn places_conflict<'tcx>( tcx, body, borrow_place, - BorrowKind::Mut { allow_two_phase_borrow: true }, + BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow }, access_place.as_ref(), AccessDepth::Deep, bias, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 2aaf1340eb409..ee85d12a27353 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -412,7 +412,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { BorrowKind::Shallow => { PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) } - BorrowKind::Unique => PlaceContext::MutatingUse(MutatingUseContext::Borrow), BorrowKind::Mut { .. } => { PlaceContext::MutatingUse(MutatingUseContext::Borrow) } @@ -457,7 +456,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - Rvalue::Ref(_, kind @ (BorrowKind::Mut { .. } | BorrowKind::Unique), place) => { + Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, place) => { let ty = place.ty(self.body, self.tcx).ty; let is_allowed = match ty.kind() { // Inside a `static mut`, `&mut [...]` is allowed. diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index 65fe164f8ec76..3a869f7f54721 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -103,7 +103,7 @@ where fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool { match kind { mir::BorrowKind::Mut { .. } => true, - mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => { + mir::BorrowKind::Shared | mir::BorrowKind::Shallow => { self.shared_borrow_allows_mutation(place) } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index f02464c7f99b6..c1abc4b5e998c 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -454,7 +454,9 @@ impl<'tcx> Validator<'_, 'tcx> { match kind { // Reject these borrow types just to be safe. // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase. - BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable), + BorrowKind::Shallow | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { + return Err(Unpromotable); + } BorrowKind::Shared => { let has_mut_interior = self.qualif_local::(place.local); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 6aa20dbed9294..7b61c375707ae 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2035,22 +2035,24 @@ impl<'tcx> Rvalue<'tcx> { impl BorrowKind { pub fn mutability(&self) -> Mutability { match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => Mutability::Not, + BorrowKind::Shared | BorrowKind::Shallow => Mutability::Not, BorrowKind::Mut { .. } => Mutability::Mut, } } pub fn allows_two_phase_borrow(&self) -> bool { match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, - BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, + BorrowKind::Shared | BorrowKind::Shallow => false, + BorrowKind::Mut { kind } => kind == MutBorrowKind::TwoPhaseBorrow, } } // FIXME: won't be used after diagnostic migration pub fn describe_mutability(&self) -> &str { match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => "immutable", + BorrowKind::Shared + | BorrowKind::Shallow + | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => "immutable", BorrowKind::Mut { .. } => "mutable", } } @@ -2090,7 +2092,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { let kind_str = match borrow_kind { BorrowKind::Shared => "", BorrowKind::Shallow => "shallow ", - BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", + BorrowKind::Mut { .. } => "mut ", }; // When printing regions, add trailing space if necessary. diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 10f368fc41cf0..458672676e2dc 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -182,6 +182,16 @@ pub enum BorrowKind { /// We can also report errors with this kind of borrow differently. Shallow, + /// Data is mutable and not aliasable. + Mut { kind: MutBorrowKind }, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Hash, HashStable)] +pub enum MutBorrowKind { + Default, + /// this borrow arose from method-call auto-ref. (i.e., `adjustment::Adjust::Borrow`) + TwoPhaseBorrow, /// Data must be immutable but not aliasable. This kind of borrow /// cannot currently be expressed by the user and is used only in /// implicit closure bindings. It is needed when the closure is @@ -220,19 +230,7 @@ pub enum BorrowKind { /// immutable, but not aliasable. This solves the problem. For /// simplicity, we don't give users the way to express this /// borrow, it's just used when translating closures. - /// - // FIXME(#112072): This is wrong. Unique borrows are mutable borrows except - // that they do not require their pointee to be marked as a mutable. - // They should still be treated as mutable borrows in every other way, - // e.g. for variance or overlap checking. - Unique, - - /// Data is mutable and not aliasable. - Mut { - /// `true` if this borrow arose from method-call auto-ref - /// (i.e., `adjustment::Adjust::Borrow`). - allow_two_phase_borrow: bool, - }, + ClosureCapture, } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 4a16abdd4e38f..65dff193c8067 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -269,11 +269,6 @@ impl BorrowKind { BorrowKind::Mut { .. } => hir::Mutability::Mut, BorrowKind::Shared => hir::Mutability::Not, - // We have no type corresponding to a unique imm borrow, so - // use `&mut`. It gives all the capabilities of a `&uniq` - // and hence is a safe "over approximation". - BorrowKind::Unique => hir::Mutability::Mut, - // We have no type corresponding to a shallow borrow, so use // `&` as an approximation. BorrowKind::Shallow => hir::Mutability::Not, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index ce55b770cbcb4..b030d1e6c3edf 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -650,9 +650,6 @@ macro_rules! make_mir_visitor { BorrowKind::Shallow => PlaceContext::NonMutatingUse( NonMutatingUseContext::ShallowBorrow ), - BorrowKind::Unique => PlaceContext::MutatingUse( - MutatingUseContext::Borrow - ), BorrowKind::Mut { .. } => PlaceContext::MutatingUse(MutatingUseContext::Borrow), }; diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index fd08b32807c40..ec00f9a96be20 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -442,7 +442,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match upvar.kind { ExprKind::Borrow { borrow_kind: - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, arg, } => unpack!( block = this.limit_capture_mutability( @@ -795,8 +795,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let borrow_kind = match mutability { - Mutability::Not => BorrowKind::Unique, - Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, + Mutability::Not => BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, + Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default }, }; let arg_place = arg_place_builder.to_place(this); diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 0506f2bf2385c..f7ef8485582fd 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -3,7 +3,7 @@ use crate::errors::*; use rustc_middle::thir::visit::{self, Visitor}; use rustc_hir as hir; -use rustc_middle::mir::BorrowKind; +use rustc_middle::mir::{BorrowKind, MutBorrowKind}; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; @@ -254,7 +254,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { ); }; match borrow_kind { - BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => { + BorrowKind::Shallow + | BorrowKind::Shared + | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { if !ty.is_freeze(self.tcx, self.param_env) { self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField); } @@ -440,15 +442,19 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_expr(&mut visitor, expr); if visitor.found { match borrow_kind { - BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique + BorrowKind::Shallow + | BorrowKind::Shared + | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) => { self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField) } - BorrowKind::Mut { .. } => { - self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField) - } - BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {} + BorrowKind::Mut { + kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow, + } => self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField), + BorrowKind::Shallow + | BorrowKind::Shared + | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {} } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index b20495d602e59..7f0c2e9ca3fb2 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1095,8 +1095,12 @@ impl<'tcx> Cx<'tcx> { ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow { ty::BorrowKind::ImmBorrow => BorrowKind::Shared, - ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique, - ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false }, + ty::BorrowKind::UniqueImmBorrow => { + BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } + } + ty::BorrowKind::MutBorrow => { + BorrowKind::Mut { kind: mir::MutBorrowKind::Default } + } }; Expr { temp_lifetime, @@ -1132,9 +1136,9 @@ impl ToBorrowKind for AutoBorrowMutability { use rustc_middle::ty::adjustment::AllowTwoPhase; match *self { AutoBorrowMutability::Mut { allow_two_phase_borrow } => BorrowKind::Mut { - allow_two_phase_borrow: match allow_two_phase_borrow { - AllowTwoPhase::Yes => true, - AllowTwoPhase::No => false, + kind: match allow_two_phase_borrow { + AllowTwoPhase::Yes => mir::MutBorrowKind::TwoPhaseBorrow, + AllowTwoPhase::No => mir::MutBorrowKind::Default, }, }, AutoBorrowMutability::Not => BorrowKind::Shared, @@ -1145,7 +1149,7 @@ impl ToBorrowKind for AutoBorrowMutability { impl ToBorrowKind for hir::Mutability { fn to_borrow_kind(&self) -> BorrowKind { match *self { - hir::Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, + hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default }, hir::Mutability::Not => BorrowKind::Shared, } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8eeb055ed82d0..c30c4b659392c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -287,7 +287,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue), ty::BindByReference(hir::Mutability::Mut) => ( Mutability::Not, - BindingMode::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }), + BindingMode::ByRef(BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), ), ty::BindByReference(hir::Mutability::Not) => { (Mutability::Not, BindingMode::ByRef(BorrowKind::Shared)) diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 27232b70d960b..c0102b15a1611 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -638,7 +638,7 @@ where Place::from(ref_place), Rvalue::Ref( tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, self.place, ), )], diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index b28fed7159f1e..703824f5bdacf 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -522,7 +522,7 @@ impl<'tcx> Inliner<'tcx> { trace!("creating temp for return destination"); let dest = Rvalue::Ref( self.tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, destination, ); let dest_ty = dest.ty(caller_body, self.tcx); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 9d6ef9db4ea1b..2ae5ec4d9e6c8 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -188,7 +188,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) // has been put into the body. let reborrow = Rvalue::Ref( tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, + BorrowKind::Mut { kind: MutBorrowKind::Default }, tcx.mk_place_deref(dropee_ptr), ); let ref_ty = reborrow.ty(body.local_decls(), tcx); @@ -712,7 +712,7 @@ fn build_call_shim<'tcx>( ) .immutable(), ); - let borrow_kind = BorrowKind::Mut { allow_two_phase_borrow: false }; + let borrow_kind = BorrowKind::Mut { kind: MutBorrowKind::Default }; statements.push(Statement { source_info, kind: StatementKind::Assign(Box::new(( From a52cc0a8c967253e0f61c7f77c820ab6e1f2e73e Mon Sep 17 00:00:00 2001 From: Ziru Niu Date: Wed, 31 May 2023 19:13:13 +0800 Subject: [PATCH 2/3] address most easy comments --- compiler/rustc_borrowck/src/borrow_set.rs | 5 ++++- .../rustc_borrowck/src/diagnostics/mod.rs | 7 +++---- compiler/rustc_borrowck/src/lib.rs | 15 +++++++------- .../src/transform/check_consts/check.rs | 8 ++------ .../src/transform/promote_consts.rs | 4 +++- compiler/rustc_middle/src/mir/mod.rs | 14 ++++--------- compiler/rustc_middle/src/ty/closure.rs | 2 ++ .../rustc_mir_build/src/check_unsafety.rs | 20 +++++++------------ 8 files changed, 33 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index cf17b16b63aa4..0b44beeb004c4 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -73,7 +73,10 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { mir::BorrowKind::Shared => "", mir::BorrowKind::Shallow => "shallow ", mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ", - mir::BorrowKind::Mut { .. } => "mut ", + // FIXME: differentiate `TwoPhaseBorrow` + mir::BorrowKind::Mut { + kind: mir::MutBorrowKind::Default | mir::MutBorrowKind::TwoPhaseBorrow, + } => "mut ", }; write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place) } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 931ee8767d9b5..2f8c970f806d3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -628,10 +628,9 @@ impl UseSpans<'_> { err.subdiagnostic(match kind { Some(kd) => match kd { rustc_middle::mir::BorrowKind::Shared - | rustc_middle::mir::BorrowKind::Shallow - | rustc_middle::mir::BorrowKind::Mut { - kind: rustc_middle::mir::MutBorrowKind::ClosureCapture, - } => CaptureVarKind::Immut { kind_span: capture_kind_span }, + | rustc_middle::mir::BorrowKind::Shallow => { + CaptureVarKind::Immut { kind_span: capture_kind_span } + } rustc_middle::mir::BorrowKind::Mut { .. } => { CaptureVarKind::Mut { kind_span: capture_kind_span } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d27dc542ad505..be3a3b777971a 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1958,14 +1958,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let the_place_err; match kind { - Reservation(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) - | Write(WriteKind::MutableBorrow(borrow_kind @ BorrowKind::Mut { .. })) => { - let is_local_mutation_allowed = match borrow_kind { - BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { - LocalMutationIsAllowed::Yes + Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) + | Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => { + let is_local_mutation_allowed = match mut_borrow_kind { + // `ClosureCapture` is used for mutable variable with a immutable binding. + // This is only behaviour difference between `ClosureCapture` and mutable borrows. + MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes, + MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => { + is_local_mutation_allowed } - BorrowKind::Mut { .. } => is_local_mutation_allowed, - BorrowKind::Shared | BorrowKind::Shallow => unreachable!(), }; match self.is_mutable(place.as_ref(), is_local_mutation_allowed) { Ok(root_place) => { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index ee85d12a27353..33c79ad7e5535 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -456,7 +456,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, place) => { + Rvalue::Ref(_, BorrowKind::Mut { .. }, place) => { let ty = place.ty(self.body, self.tcx).ty; let is_allowed = match ty.kind() { // Inside a `static mut`, `&mut [...]` is allowed. @@ -477,11 +477,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { }; if !is_allowed { - if let BorrowKind::Mut { .. } = kind { - self.check_mut_borrow(place.local, hir::BorrowKind::Ref) - } else { - self.check_op(ops::CellBorrow); - } + self.check_mut_borrow(place.local, hir::BorrowKind::Ref) } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index c1abc4b5e998c..dd80f745c2f0a 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -465,7 +465,9 @@ impl<'tcx> Validator<'_, 'tcx> { } } - BorrowKind::Mut { .. } => { + // FIXME: consider changing this to only promote &mut [] for default borrows, + // also forbidding two phase borrows + BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow } => { let ty = place.ty(self.body, self.tcx).ty; // In theory, any zero-sized value could be borrowed diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7b61c375707ae..669c609d99579 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2041,19 +2041,13 @@ impl BorrowKind { } pub fn allows_two_phase_borrow(&self) -> bool { - match *self { - BorrowKind::Shared | BorrowKind::Shallow => false, - BorrowKind::Mut { kind } => kind == MutBorrowKind::TwoPhaseBorrow, - } - } - - // FIXME: won't be used after diagnostic migration - pub fn describe_mutability(&self) -> &str { match *self { BorrowKind::Shared | BorrowKind::Shallow - | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => "immutable", - BorrowKind::Mut { .. } => "mutable", + | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => { + false + } + BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true, } } } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index be7b2b7ec671a..bc9273745491b 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -427,6 +427,8 @@ pub enum BorrowKind { /// immutable, but not aliasable. This solves the problem. For /// simplicity, we don't give users the way to express this /// borrow, it's just used when translating closures. + /// + /// FIXME: Rename this to indicate the borrow is actually not immutable. UniqueImmBorrow, /// Data is mutable and not aliasable. diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index f7ef8485582fd..4f3a574031dbc 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -3,7 +3,7 @@ use crate::errors::*; use rustc_middle::thir::visit::{self, Visitor}; use rustc_hir as hir; -use rustc_middle::mir::{BorrowKind, MutBorrowKind}; +use rustc_middle::mir::BorrowKind; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; @@ -254,9 +254,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { ); }; match borrow_kind { - BorrowKind::Shallow - | BorrowKind::Shared - | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => { + BorrowKind::Shallow | BorrowKind::Shared => { if !ty.is_freeze(self.tcx, self.param_env) { self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField); } @@ -442,19 +440,15 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_expr(&mut visitor, expr); if visitor.found { match borrow_kind { - BorrowKind::Shallow - | BorrowKind::Shared - | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } + BorrowKind::Shallow | BorrowKind::Shared if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) => { self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField) } - BorrowKind::Mut { - kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow, - } => self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField), - BorrowKind::Shallow - | BorrowKind::Shared - | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {} + BorrowKind::Mut { .. } => { + self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField) + } + BorrowKind::Shallow | BorrowKind::Shared => {} } } } From b8a250fc4f053636c481b7543cfaa1fab2df48ad Mon Sep 17 00:00:00 2001 From: Ziru Niu Date: Wed, 7 Jun 2023 15:44:32 +0800 Subject: [PATCH 3/3] update comment on `MutBorrowKind::ClosureCapture` --- compiler/rustc_middle/src/mir/syntax.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 458672676e2dc..abb3b3d953be0 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -190,7 +190,7 @@ pub enum BorrowKind { #[derive(Hash, HashStable)] pub enum MutBorrowKind { Default, - /// this borrow arose from method-call auto-ref. (i.e., `adjustment::Adjust::Borrow`) + /// This borrow arose from method-call auto-ref. (i.e., `adjustment::Adjust::Borrow`) TwoPhaseBorrow, /// Data must be immutable but not aliasable. This kind of borrow /// cannot currently be expressed by the user and is used only in @@ -226,9 +226,12 @@ pub enum MutBorrowKind { /// user code, if awkward, but extra weird for closures, since the /// borrow is hidden. /// - /// So we introduce a "unique imm" borrow -- the referent is - /// immutable, but not aliasable. This solves the problem. For - /// simplicity, we don't give users the way to express this + /// So we introduce a `ClosureCapture` borrow -- user will not have to mark the variable + /// containing the mutable reference as `mut`, as they didn't ever + /// intend to mutate the mutable reference itself. We still mutable capture it in order to + /// mutate the pointed value through it (but not mutating the reference itself). + /// + /// This solves the problem. For simplicity, we don't give users the way to express this /// borrow, it's just used when translating closures. ClosureCapture, }