Auto merge of #53438 - matthewjasper:permissive-match-access, r=pnkfelix
[NLL] Be more permissive when checking access due to Match
Partially addresses #53114. notably, we should now have parity with AST borrowck. Matching on uninitialized values is still forbidden.
* ~~Give fake borrows for match their own `BorrowKind`~~
* ~~Allow borrows with this kind to happen on values that are already mutably borrowed.~~
* ~~Track borrows with this type even behind shared reference dereferences and consider all accesses to be deep when checking for conflicts with this borrow type. See [src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs](cb5c989598 (diff-a2126cd3263a1f5342e2ecd5e699fbc6)
) for an example soundness issue this fixes (a case of #27282 that wasn't handled correctly).~~
* Create a new `BorrowKind`: `Shallow` (name can be bike-shed)
* `Shallow` borrows differ from shared borrows in that
* When we check for access we treat them as a `Shallow(Some(_))` read
* When we check for conflicts with them, if the borrow place is a strict prefix of the access place then we don't consider that a conflict.
* For example, a `Shallow` borrow of `x` does not conflict with any access or borrow of `x.0` or `*x`
* Remove the current fake borrow in matches.
* When building matches, we take a `Shallow` borrow of any `Place` that we switch on or bind in a match, and any prefix of those places. (There are some optimizations where we do fewer borrows, but this shouldn't change semantics)
* `match x { &Some(1) => (), _ => (), }` would `Shallow` borrow `x`, `*x` and `(*x as Some).0` (the `*x` borrow is unnecessary, but I'm not sure how easy it would be to remove.)
* Replace the fake discriminant read with a `ReadForMatch`.
* Change ReadForMatch to only check for initializedness (to prevent `let x: !; match x {}`), but not conflicting borrows. It is still considered a use for liveness and `unsafe` checking.
* Give special cased error messages for this kind of borrow.
Table from the above issue after this PR
| Thing | AST | MIR | Want | Example |
| --- | --- | --- | --- |---|
| `let _ = <unsafe-field>` | 💚 | 💚 | ❌ | [playground](https://play.rust-lang.org/?gist=bb7843e42fa5318c1043d04bd72abfe4&version=nightly&mode=debug&edition=2015) |
| `match <unsafe_field> { _ => () }` | ❌ | ❌ | ❌ | [playground](https://play.rust-lang.org/?gist=3e3af05fbf1fae28fab2aaf9412fb2ea&version=nightly&mode=debug&edition=2015) |
| `let _ = <moved>` | 💚 | 💚 | 💚 | [playground](https://play.rust-lang.org/?gist=91a6efde8288558e584aaeee0a50558b&version=nightly&mode=debug&edition=2015) |
| `match <moved> { _ => () }` | ❌ | ❌ | 💚 | [playground](https://play.rust-lang.org/?gist=804f8185040b2fe131f2c4a64b3048ca&version=nightly&mode=debug&edition=2015) |
| `let _ = <borrowed>` | 💚 | 💚 | 💚 | [playground](https://play.rust-lang.org/?gist=0e487c2893b89cb772ec2f2b7c5da876&version=nightly&mode=debug&edition=2015) |
| `match <borrowed> { _ => () }` | 💚 | 💚 | 💚 | [playground](https://play.rust-lang.org/?gist=0e487c2893b89cb772ec2f2b7c5da876&version=nightly&mode=debug&edition=2015) |
r? @nikomatsakis
This commit is contained in:
commit
3a2190a9cd
53 changed files with 1197 additions and 906 deletions
|
@ -46,6 +46,7 @@ for mir::BorrowKind {
|
|||
|
||||
match *self {
|
||||
mir::BorrowKind::Shared |
|
||||
mir::BorrowKind::Shallow |
|
||||
mir::BorrowKind::Unique => {}
|
||||
mir::BorrowKind::Mut { allow_two_phase_borrow } => {
|
||||
allow_two_phase_borrow.hash_stable(hcx, hasher);
|
||||
|
@ -272,7 +273,7 @@ for mir::StatementKind<'gcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(enum mir::FakeReadCause { ForMatch, ForLet });
|
||||
impl_stable_hash_for!(enum mir::FakeReadCause { ForMatchGuard, ForMatchedPlace, ForLet });
|
||||
|
||||
impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>>
|
||||
for mir::ValidationOperand<'gcx, T>
|
||||
|
|
|
@ -451,11 +451,32 @@ impl From<Mutability> for hir::Mutability {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
|
||||
pub enum BorrowKind {
|
||||
/// Data must be immutable and is aliasable.
|
||||
Shared,
|
||||
|
||||
/// The immediately borrowed place must be immutable, but projections from
|
||||
/// it don't need to be. For example, a shallow borrow of `a.b` doesn't
|
||||
/// conflict with a mutable borrow of `a.b.c`.
|
||||
///
|
||||
/// This is used when lowering matches: when matching on a place we want to
|
||||
/// ensure that place have the same value from the start of the match until
|
||||
/// an arm is selected. This prevents this code from compiling:
|
||||
///
|
||||
/// let mut x = &Some(0);
|
||||
/// match *x {
|
||||
/// None => (),
|
||||
/// Some(_) if { x = &None; false } => (),
|
||||
/// Some(_) => (),
|
||||
/// }
|
||||
///
|
||||
/// This can't be a shared borrow because mutably borrowing (*x as Some).0
|
||||
/// should not prevent `if let None = x { ... }`, for example, becase the
|
||||
/// mutating `(*x as Some).0` can't affect the discriminant of `x`.
|
||||
/// We can also report errors with this kind of borrow differently.
|
||||
Shallow,
|
||||
|
||||
/// 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
|
||||
|
@ -504,7 +525,7 @@ pub enum BorrowKind {
|
|||
impl BorrowKind {
|
||||
pub fn allows_two_phase_borrow(&self) -> bool {
|
||||
match *self {
|
||||
BorrowKind::Shared | BorrowKind::Unique => false,
|
||||
BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false,
|
||||
BorrowKind::Mut {
|
||||
allow_two_phase_borrow,
|
||||
} => allow_two_phase_borrow,
|
||||
|
@ -1672,7 +1693,11 @@ pub enum FakeReadCause {
|
|||
///
|
||||
/// This should ensure that you cannot change the variant for an enum
|
||||
/// while you are in the midst of matching on it.
|
||||
ForMatch,
|
||||
ForMatchGuard,
|
||||
|
||||
/// `let x: !; match x {}` doesn't generate any read of x so we need to
|
||||
/// generate a read of x to check that it is initialized and safe.
|
||||
ForMatchedPlace,
|
||||
|
||||
/// Officially, the semantics of
|
||||
///
|
||||
|
@ -1773,7 +1798,7 @@ impl<'tcx> Debug for Statement<'tcx> {
|
|||
|
||||
/// A path to a value; something that can be evaluated without
|
||||
/// changing or disturbing program state.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub enum Place<'tcx> {
|
||||
/// local variable
|
||||
Local(Local),
|
||||
|
@ -1790,7 +1815,7 @@ pub enum Place<'tcx> {
|
|||
|
||||
/// The def-id of a static, along with its normalized type (which is
|
||||
/// stored to avoid requiring normalization when reading MIR).
|
||||
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct Static<'tcx> {
|
||||
pub def_id: DefId,
|
||||
pub ty: Ty<'tcx>,
|
||||
|
@ -1805,13 +1830,13 @@ impl_stable_hash_for!(struct Static<'tcx> {
|
|||
/// or `*B` or `B[index]`. Note that it is parameterized because it is
|
||||
/// shared between `Constant` and `Place`. See the aliases
|
||||
/// `PlaceProjection` etc below.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct Projection<'tcx, B, V, T> {
|
||||
pub base: B,
|
||||
pub elem: ProjectionElem<'tcx, V, T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub enum ProjectionElem<'tcx, V, T> {
|
||||
Deref,
|
||||
Field(Field, T),
|
||||
|
@ -2198,6 +2223,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
|||
Ref(region, borrow_kind, ref place) => {
|
||||
let kind_str = match borrow_kind {
|
||||
BorrowKind::Shared => "",
|
||||
BorrowKind::Shallow => "shallow ",
|
||||
BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ",
|
||||
};
|
||||
|
||||
|
|
|
@ -287,6 +287,10 @@ impl BorrowKind {
|
|||
// use `&mut`. It gives all the capabilities of an `&uniq`
|
||||
// and hence is a safe "over approximation".
|
||||
BorrowKind::Unique => hir::MutMutable,
|
||||
|
||||
// We have no type corresponding to a shallow borrow, so use
|
||||
// `&` as an approximation.
|
||||
BorrowKind::Shallow => hir::MutImmutable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -963,6 +963,7 @@ impl<'tcx> PlaceContext<'tcx> {
|
|||
|
||||
PlaceContext::Inspect |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Shared, .. } |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Shallow, .. } |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Unique, .. } |
|
||||
PlaceContext::Projection(Mutability::Not) |
|
||||
PlaceContext::Copy | PlaceContext::Move |
|
||||
|
@ -974,7 +975,9 @@ impl<'tcx> PlaceContext<'tcx> {
|
|||
/// Returns true if this place context represents a use that does not change the value.
|
||||
pub fn is_nonmutating_use(&self) -> bool {
|
||||
match *self {
|
||||
PlaceContext::Inspect | PlaceContext::Borrow { kind: BorrowKind::Shared, .. } |
|
||||
PlaceContext::Inspect |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Shared, .. } |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Shallow, .. } |
|
||||
PlaceContext::Borrow { kind: BorrowKind::Unique, .. } |
|
||||
PlaceContext::Projection(Mutability::Not) |
|
||||
PlaceContext::Copy | PlaceContext::Move => true,
|
||||
|
|
|
@ -87,6 +87,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
|||
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
|
||||
let kind = match self.kind {
|
||||
mir::BorrowKind::Shared => "",
|
||||
mir::BorrowKind::Shallow => "shallow ",
|
||||
mir::BorrowKind::Unique => "uniq ",
|
||||
mir::BorrowKind::Mut { .. } => "mut ",
|
||||
};
|
||||
|
@ -287,7 +288,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
|
|||
borrow_data.activation_location = match context {
|
||||
// The use of TMP in a shared borrow does not
|
||||
// count as an actual activation.
|
||||
PlaceContext::Borrow { kind: mir::BorrowKind::Shared, .. } => {
|
||||
PlaceContext::Borrow { kind: mir::BorrowKind::Shared, .. }
|
||||
| PlaceContext::Borrow { kind: mir::BorrowKind::Shallow, .. } => {
|
||||
TwoPhaseActivation::NotActivated
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -333,6 +333,27 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
Origin::Mir,
|
||||
),
|
||||
|
||||
(BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _)
|
||||
| (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => {
|
||||
let mut err = tcx.cannot_mutate_in_match_guard(
|
||||
span,
|
||||
issued_span,
|
||||
&desc_place,
|
||||
"mutably borrow",
|
||||
Origin::Mir,
|
||||
);
|
||||
borrow_spans.var_span_label(
|
||||
&mut err,
|
||||
format!(
|
||||
"borrow occurs due to use of `{}` in closure",
|
||||
desc_place
|
||||
),
|
||||
);
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
(BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure(
|
||||
span,
|
||||
&desc_place,
|
||||
|
@ -368,7 +389,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
Origin::Mir,
|
||||
),
|
||||
|
||||
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(),
|
||||
(BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
|
||||
| (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) => {
|
||||
// Shallow borrows are uses from the user's point of view.
|
||||
self.report_use_while_mutably_borrowed(context, (place, span), issued_borrow);
|
||||
return
|
||||
}
|
||||
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
|
||||
| (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
|
||||
| (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _)
|
||||
| (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(),
|
||||
};
|
||||
|
||||
if issued_spans == borrow_spans {
|
||||
|
@ -780,12 +810,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
let loan_span = loan_spans.args_or_use();
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let mut err = tcx.cannot_assign_to_borrowed(
|
||||
span,
|
||||
loan_span,
|
||||
&self.describe_place(place).unwrap_or("_".to_owned()),
|
||||
Origin::Mir,
|
||||
);
|
||||
let mut err = if loan.kind == BorrowKind::Shallow {
|
||||
tcx.cannot_mutate_in_match_guard(
|
||||
span,
|
||||
loan_span,
|
||||
&self.describe_place(place).unwrap_or("_".to_owned()),
|
||||
"assign",
|
||||
Origin::Mir,
|
||||
)
|
||||
} else {
|
||||
tcx.cannot_assign_to_borrowed(
|
||||
span,
|
||||
loan_span,
|
||||
&self.describe_place(place).unwrap_or("_".to_owned()),
|
||||
Origin::Mir,
|
||||
)
|
||||
};
|
||||
|
||||
loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
|
||||
|
||||
|
|
|
@ -499,11 +499,20 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||
);
|
||||
}
|
||||
StatementKind::FakeRead(_, ref place) => {
|
||||
self.access_place(
|
||||
// Read for match doesn't access any memory and is used to
|
||||
// assert that a place is safe and live. So we don't have to
|
||||
// do any checks here.
|
||||
//
|
||||
// FIXME: Remove check that the place is initialized. This is
|
||||
// needed for now because matches don't have never patterns yet.
|
||||
// So this is the only place we prevent
|
||||
// let x: !;
|
||||
// match x {};
|
||||
// from compiling.
|
||||
self.check_if_path_or_subpath_is_moved(
|
||||
ContextKind::FakeRead.new(location),
|
||||
InitializationRequiringAction::Use,
|
||||
(place, span),
|
||||
(Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
LocalMutationIsAllowed::No,
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
|
@ -755,6 +764,7 @@ use self::AccessDepth::{Deep, Shallow};
|
|||
enum ArtificialField {
|
||||
Discriminant,
|
||||
ArrayLength,
|
||||
ShallowBorrow,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
|
@ -835,6 +845,7 @@ enum LocalMutationIsAllowed {
|
|||
enum InitializationRequiringAction {
|
||||
Update,
|
||||
Borrow,
|
||||
MatchOn,
|
||||
Use,
|
||||
Assignment,
|
||||
}
|
||||
|
@ -849,6 +860,7 @@ impl InitializationRequiringAction {
|
|||
match self {
|
||||
InitializationRequiringAction::Update => "update",
|
||||
InitializationRequiringAction::Borrow => "borrow",
|
||||
InitializationRequiringAction::MatchOn => "use", // no good noun
|
||||
InitializationRequiringAction::Use => "use",
|
||||
InitializationRequiringAction::Assignment => "assign",
|
||||
}
|
||||
|
@ -858,6 +870,7 @@ impl InitializationRequiringAction {
|
|||
match self {
|
||||
InitializationRequiringAction::Update => "updated",
|
||||
InitializationRequiringAction::Borrow => "borrowed",
|
||||
InitializationRequiringAction::MatchOn => "matched on",
|
||||
InitializationRequiringAction::Use => "used",
|
||||
InitializationRequiringAction::Assignment => "assigned",
|
||||
}
|
||||
|
@ -972,7 +985,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
Control::Continue
|
||||
}
|
||||
|
||||
(Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => {
|
||||
(Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared)
|
||||
| (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) => {
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
(Write(WriteKind::Move), BorrowKind::Shallow) => {
|
||||
// Handled by initialization checks.
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
|
@ -984,7 +1003,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
match kind {
|
||||
ReadKind::Copy => {
|
||||
ReadKind::Copy => {
|
||||
error_reported = true;
|
||||
this.report_use_while_mutably_borrowed(context, place_span, borrow)
|
||||
}
|
||||
|
@ -1108,6 +1127,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
match *rvalue {
|
||||
Rvalue::Ref(_ /*rgn*/, bk, ref place) => {
|
||||
let access_kind = match bk {
|
||||
BorrowKind::Shallow => {
|
||||
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
|
||||
},
|
||||
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
||||
BorrowKind::Unique | BorrowKind::Mut { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
|
@ -1127,9 +1149,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
flow_state,
|
||||
);
|
||||
|
||||
let action = if bk == BorrowKind::Shallow {
|
||||
InitializationRequiringAction::MatchOn
|
||||
} else {
|
||||
InitializationRequiringAction::Borrow
|
||||
};
|
||||
|
||||
self.check_if_path_or_subpath_is_moved(
|
||||
context,
|
||||
InitializationRequiringAction::Borrow,
|
||||
action,
|
||||
(place, span),
|
||||
flow_state,
|
||||
);
|
||||
|
@ -1315,11 +1343,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
// FIXME: replace this with a proper borrow_conflicts_with_place when
|
||||
// that is merged.
|
||||
let sd = if might_be_alive { Deep } else { Shallow(None) };
|
||||
|
||||
if places_conflict::places_conflict(self.infcx.tcx, self.mir, place, root_place, sd) {
|
||||
if places_conflict::borrow_conflicts_with_place(
|
||||
self.infcx.tcx,
|
||||
self.mir,
|
||||
place,
|
||||
borrow.kind,
|
||||
root_place,
|
||||
sd
|
||||
) {
|
||||
debug!("check_for_invalidation_at_exit({:?}): INVALID", place);
|
||||
// FIXME: should be talking about the region lifetime instead
|
||||
// of just a span here.
|
||||
|
@ -1369,7 +1402,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
|
||||
// only mutable borrows should be 2-phase
|
||||
assert!(match borrow.kind {
|
||||
BorrowKind::Shared => false,
|
||||
BorrowKind::Shared | BorrowKind::Shallow => false,
|
||||
BorrowKind::Unique | BorrowKind::Mut { .. } => true,
|
||||
});
|
||||
|
||||
|
@ -1669,7 +1702,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
let is_local_mutation_allowed = match borrow_kind {
|
||||
BorrowKind::Unique => LocalMutationIsAllowed::Yes,
|
||||
BorrowKind::Mut { .. } => is_local_mutation_allowed,
|
||||
BorrowKind::Shared => unreachable!(),
|
||||
BorrowKind::Shared | BorrowKind::Shallow => unreachable!(),
|
||||
};
|
||||
match self.is_mutable(place, is_local_mutation_allowed) {
|
||||
Ok(root_place) => {
|
||||
|
@ -1699,8 +1732,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
| Write(wk @ WriteKind::Move)
|
||||
| Reservation(wk @ WriteKind::StorageDeadOrDrop)
|
||||
| Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shared))
|
||||
| Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow))
|
||||
| Write(wk @ WriteKind::StorageDeadOrDrop)
|
||||
| Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) => {
|
||||
| Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared))
|
||||
| Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) => {
|
||||
if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) {
|
||||
if self.infcx.tcx.migrate_borrowck() {
|
||||
// rust-lang/rust#46908: In pure NLL mode this
|
||||
|
@ -1743,6 +1778,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
Read(ReadKind::Borrow(BorrowKind::Unique))
|
||||
| Read(ReadKind::Borrow(BorrowKind::Mut { .. }))
|
||||
| Read(ReadKind::Borrow(BorrowKind::Shared))
|
||||
| Read(ReadKind::Borrow(BorrowKind::Shallow))
|
||||
| Read(ReadKind::Copy) => {
|
||||
// Access authorized
|
||||
return false;
|
||||
|
|
|
@ -329,6 +329,9 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||
match *rvalue {
|
||||
Rvalue::Ref(_ /*rgn*/, bk, ref place) => {
|
||||
let access_kind = match bk {
|
||||
BorrowKind::Shallow => {
|
||||
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
|
||||
},
|
||||
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
||||
BorrowKind::Unique | BorrowKind::Mut { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
|
@ -439,8 +442,9 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||
// have already taken the reservation
|
||||
}
|
||||
|
||||
(Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => {
|
||||
// Reads/reservations don't invalidate shared borrows
|
||||
(Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow)
|
||||
| (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => {
|
||||
// Reads/reservations don't invalidate shared or shallow borrows
|
||||
}
|
||||
|
||||
(Read(_), BorrowKind::Unique) | (Read(_), BorrowKind::Mut { .. }) => {
|
||||
|
|
|
@ -61,7 +61,14 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> (
|
|||
for i in candidates {
|
||||
let borrowed = &borrow_set[i];
|
||||
|
||||
if places_conflict::places_conflict(tcx, mir, &borrowed.borrowed_place, place, access) {
|
||||
if places_conflict::borrow_conflicts_with_place(
|
||||
tcx,
|
||||
mir,
|
||||
&borrowed.borrowed_place,
|
||||
borrowed.kind,
|
||||
place,
|
||||
access,
|
||||
) {
|
||||
debug!(
|
||||
"each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
|
||||
i, borrowed, place, access
|
||||
|
|
|
@ -12,20 +12,21 @@ use borrow_check::ArtificialField;
|
|||
use borrow_check::Overlap;
|
||||
use borrow_check::{Deep, Shallow, AccessDepth};
|
||||
use rustc::hir;
|
||||
use rustc::mir::{Mir, Place};
|
||||
use rustc::mir::{BorrowKind, Mir, Place};
|
||||
use rustc::mir::{Projection, ProjectionElem};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use std::cmp::max;
|
||||
|
||||
pub(super) fn places_conflict<'gcx, 'tcx>(
|
||||
pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
|
||||
tcx: TyCtxt<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
borrow_place: &Place<'tcx>,
|
||||
borrow_kind: BorrowKind,
|
||||
access_place: &Place<'tcx>,
|
||||
access: AccessDepth,
|
||||
) -> bool {
|
||||
debug!(
|
||||
"places_conflict({:?},{:?},{:?})",
|
||||
"borrow_conflicts_with_place({:?},{:?},{:?})",
|
||||
borrow_place, access_place, access
|
||||
);
|
||||
|
||||
|
@ -39,7 +40,14 @@ pub(super) fn places_conflict<'gcx, 'tcx>(
|
|||
|
||||
unroll_place(borrow_place, None, |borrow_components| {
|
||||
unroll_place(access_place, None, |access_components| {
|
||||
place_components_conflict(tcx, mir, borrow_components, access_components, access)
|
||||
place_components_conflict(
|
||||
tcx,
|
||||
mir,
|
||||
borrow_components,
|
||||
borrow_kind,
|
||||
access_components,
|
||||
access
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -48,6 +56,7 @@ fn place_components_conflict<'gcx, 'tcx>(
|
|||
tcx: TyCtxt<'_, 'gcx, 'tcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
mut borrow_components: PlaceComponentsIter<'_, 'tcx>,
|
||||
borrow_kind: BorrowKind,
|
||||
mut access_components: PlaceComponentsIter<'_, 'tcx>,
|
||||
access: AccessDepth,
|
||||
) -> bool {
|
||||
|
@ -95,10 +104,10 @@ fn place_components_conflict<'gcx, 'tcx>(
|
|||
loop {
|
||||
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
|
||||
if let Some(borrow_c) = borrow_components.next() {
|
||||
debug!("places_conflict: borrow_c = {:?}", borrow_c);
|
||||
debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
|
||||
|
||||
if let Some(access_c) = access_components.next() {
|
||||
debug!("places_conflict: access_c = {:?}", access_c);
|
||||
debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
|
||||
|
||||
// Borrow and access path both have more components.
|
||||
//
|
||||
|
@ -127,7 +136,7 @@ fn place_components_conflict<'gcx, 'tcx>(
|
|||
// idea, at least for now, so just give up and
|
||||
// report a conflict. This is unsafe code anyway so
|
||||
// the user could always use raw pointers.
|
||||
debug!("places_conflict: arbitrary -> conflict");
|
||||
debug!("borrow_conflicts_with_place: arbitrary -> conflict");
|
||||
return true;
|
||||
}
|
||||
Overlap::EqualOrDisjoint => {
|
||||
|
@ -136,7 +145,7 @@ fn place_components_conflict<'gcx, 'tcx>(
|
|||
Overlap::Disjoint => {
|
||||
// We have proven the borrow disjoint - further
|
||||
// projections will remain disjoint.
|
||||
debug!("places_conflict: disjoint");
|
||||
debug!("borrow_conflicts_with_place: disjoint");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +166,8 @@ fn place_components_conflict<'gcx, 'tcx>(
|
|||
|
||||
match (elem, &base_ty.sty, access) {
|
||||
(_, _, Shallow(Some(ArtificialField::Discriminant)))
|
||||
| (_, _, Shallow(Some(ArtificialField::ArrayLength))) => {
|
||||
| (_, _, Shallow(Some(ArtificialField::ArrayLength)))
|
||||
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
|
||||
// The discriminant and array length are like
|
||||
// additional fields on the type; they do not
|
||||
// overlap any existing data there. Furthermore,
|
||||
|
@ -167,7 +177,7 @@ fn place_components_conflict<'gcx, 'tcx>(
|
|||
//
|
||||
// e.g. a (mutable) borrow of `a[5]` while we read the
|
||||
// array length of `a`.
|
||||
debug!("places_conflict: implicit field");
|
||||
debug!("borrow_conflicts_with_place: implicit field");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -175,7 +185,7 @@ fn place_components_conflict<'gcx, 'tcx>(
|
|||
// e.g. a borrow of `*x.y` while we shallowly access `x.y` or some
|
||||
// prefix thereof - the shallow access can't touch anything behind
|
||||
// the pointer.
|
||||
debug!("places_conflict: shallow access behind ptr");
|
||||
debug!("borrow_conflicts_with_place: shallow access behind ptr");
|
||||
return false;
|
||||
}
|
||||
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => {
|
||||
|
@ -185,7 +195,7 @@ fn place_components_conflict<'gcx, 'tcx>(
|
|||
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
|
||||
// Values behind a mutatble reference are not access either by Dropping a
|
||||
// value, or by StorageDead
|
||||
debug!("places_conflict: drop access behind ptr");
|
||||
debug!("borrow_conflicts_with_place: drop access behind ptr");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -225,11 +235,13 @@ fn place_components_conflict<'gcx, 'tcx>(
|
|||
// If the second example, where we did, then we still know
|
||||
// that the borrow can access a *part* of our place that
|
||||
// our access cares about, so we still have a conflict.
|
||||
//
|
||||
// FIXME: Differs from AST-borrowck; includes drive-by fix
|
||||
// to #38899. Will probably need back-compat mode flag.
|
||||
debug!("places_conflict: full borrow, CONFLICT");
|
||||
return true;
|
||||
if borrow_kind == BorrowKind::Shallow && access_components.next().is_some() {
|
||||
debug!("borrow_conflicts_with_place: shallow borrow");
|
||||
return false;
|
||||
} else {
|
||||
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,7 +253,7 @@ fn place_components_conflict<'gcx, 'tcx>(
|
|||
///
|
||||
/// NB: This particular impl strategy is not the most obvious. It was
|
||||
/// chosen because it makes a measurable difference to NLL
|
||||
/// performance, as this code (`places_conflict`) is somewhat hot.
|
||||
/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot.
|
||||
struct PlaceComponents<'p, 'tcx: 'p> {
|
||||
component: &'p Place<'tcx>,
|
||||
next: Option<&'p PlaceComponents<'p, 'tcx>>,
|
||||
|
|
|
@ -57,39 +57,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
// See issue #47412 for this hole being discovered in the wild.
|
||||
//
|
||||
// HACK(eddyb) Work around the above issue by adding a dummy inspection
|
||||
// of `discriminant_place`, specifically by applying `Rvalue::Discriminant`
|
||||
// (which will work regardless of type) and storing the result in a temp.
|
||||
// of `discriminant_place`, specifically by applying `ReadForMatch`.
|
||||
//
|
||||
// NOTE: Under NLL, the above issue should no longer occur because it
|
||||
// injects a borrow of the matched input, which should have the same effect
|
||||
// as eddyb's hack. Once NLL is the default, we can remove the hack.
|
||||
|
||||
let dummy_source_info = self.source_info(discriminant_span);
|
||||
let dummy_access = Rvalue::Discriminant(discriminant_place.clone());
|
||||
let dummy_ty = dummy_access.ty(&self.local_decls, tcx);
|
||||
let dummy_temp = self.temp(dummy_ty, dummy_source_info.span);
|
||||
self.cfg
|
||||
.push_assign(block, dummy_source_info, &dummy_temp, dummy_access);
|
||||
// NOTE: ReadForMatch also checks that the discriminant is initialized.
|
||||
// This is currently needed to not allow matching on an uninitialized,
|
||||
// uninhabited value. If we get never patterns, those will check that
|
||||
// the place is initialized, and so this read would only be used to
|
||||
// check safety.
|
||||
|
||||
let source_info = self.source_info(discriminant_span);
|
||||
let borrowed_input_temp = if tcx.generate_borrow_of_any_match_input() {
|
||||
// The region is unknown at this point; we rely on NLL
|
||||
// inference to find an appropriate one. Therefore you can
|
||||
// only use this when NLL is turned on.
|
||||
assert!(tcx.use_mir_borrowck());
|
||||
let borrowed_input = Rvalue::Ref(
|
||||
tcx.types.re_empty,
|
||||
BorrowKind::Shared,
|
||||
self.cfg.push(block, Statement {
|
||||
source_info,
|
||||
kind: StatementKind::FakeRead(
|
||||
FakeReadCause::ForMatchedPlace,
|
||||
discriminant_place.clone(),
|
||||
);
|
||||
let borrowed_input_ty = borrowed_input.ty(&self.local_decls, tcx);
|
||||
let borrowed_input_temp = self.temp(borrowed_input_ty, span);
|
||||
self.cfg
|
||||
.push_assign(block, source_info, &borrowed_input_temp, borrowed_input);
|
||||
Some(borrowed_input_temp)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
),
|
||||
});
|
||||
|
||||
let mut arm_blocks = ArmBlocks {
|
||||
blocks: arms.iter().map(|_| self.cfg.start_new_block()).collect(),
|
||||
|
@ -118,6 +101,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
.map(|_| self.cfg.start_new_block())
|
||||
.collect();
|
||||
|
||||
let mut has_guard = false;
|
||||
|
||||
// assemble a list of candidates: there is one candidate per
|
||||
// pattern, which means there may be more than one candidate
|
||||
// *per arm*. These candidates are kept sorted such that the
|
||||
|
@ -140,24 +125,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
.map(
|
||||
|(
|
||||
(arm_index, pat_index, pattern, guard),
|
||||
(pre_binding_block, next_candidate_pre_binding_block),
|
||||
(pre_binding_block, next_candidate_pre_binding_block)
|
||||
)| {
|
||||
if let (true, Some(borrow_temp)) =
|
||||
(tcx.emit_read_for_match(), borrowed_input_temp.clone())
|
||||
{
|
||||
// Inject a fake read, see comments on `FakeReadCause::ForMatch`.
|
||||
let pattern_source_info = self.source_info(pattern.span);
|
||||
self.cfg.push(
|
||||
*pre_binding_block,
|
||||
Statement {
|
||||
source_info: pattern_source_info,
|
||||
kind: StatementKind::FakeRead(
|
||||
FakeReadCause::ForMatch,
|
||||
borrow_temp.clone(),
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
has_guard |= guard.is_some();
|
||||
|
||||
// One might ask: why not build up the match pair such that it
|
||||
// matches via `borrowed_input_temp.deref()` instead of
|
||||
|
@ -202,9 +172,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
TerminatorKind::Unreachable,
|
||||
);
|
||||
|
||||
// Maps a place to the kind of Fake borrow that we want to perform on
|
||||
// it: either Shallow or Shared, depending on whether the place is
|
||||
// bound in the match, or just switched on.
|
||||
// If there are no match guards then we don't need any fake borrows,
|
||||
// so don't track them.
|
||||
let mut fake_borrows = if has_guard && tcx.generate_borrow_of_any_match_input() {
|
||||
Some(FxHashMap())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let pre_binding_blocks: Vec<_> = candidates
|
||||
.iter()
|
||||
.map(|cand| (cand.pre_binding_block, cand.span))
|
||||
.collect();
|
||||
|
||||
// this will generate code to test discriminant_place and
|
||||
// branch to the appropriate arm block
|
||||
let otherwise = self.match_candidates(span, &mut arm_blocks, candidates, block);
|
||||
let otherwise = self.match_candidates(
|
||||
discriminant_span,
|
||||
&mut arm_blocks,
|
||||
candidates,
|
||||
block,
|
||||
&mut fake_borrows,
|
||||
);
|
||||
|
||||
if !otherwise.is_empty() {
|
||||
// All matches are exhaustive. However, because some matches
|
||||
|
@ -224,6 +216,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(fake_borrows) = fake_borrows {
|
||||
self.add_fake_borrows(&pre_binding_blocks, fake_borrows, source_info, block);
|
||||
}
|
||||
|
||||
// all the arm blocks will rejoin here
|
||||
let end_block = self.cfg.start_new_block();
|
||||
|
||||
|
@ -714,12 +710,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
/// up the list of candidates and recurse with a non-exhaustive
|
||||
/// list. This is important to keep the size of the generated code
|
||||
/// under control. See `test_candidates` for more details.
|
||||
///
|
||||
/// If `add_fake_borrows` is true, then places which need fake borrows
|
||||
/// will be added to it.
|
||||
fn match_candidates<'pat>(
|
||||
&mut self,
|
||||
span: Span,
|
||||
arm_blocks: &mut ArmBlocks,
|
||||
mut candidates: Vec<Candidate<'pat, 'tcx>>,
|
||||
mut block: BasicBlock,
|
||||
fake_borrows: &mut Option<FxHashMap<Place<'tcx>, BorrowKind>>,
|
||||
) -> Vec<BasicBlock> {
|
||||
debug!(
|
||||
"matched_candidate(span={:?}, block={:?}, candidates={:?})",
|
||||
|
@ -747,6 +747,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
);
|
||||
let mut unmatched_candidates = candidates.split_off(fully_matched);
|
||||
|
||||
// Insert a *Shared* borrow of any places that are bound.
|
||||
if let Some(fake_borrows) = fake_borrows {
|
||||
for Binding { source, .. }
|
||||
in candidates.iter().flat_map(|candidate| &candidate.bindings)
|
||||
{
|
||||
fake_borrows.insert(source.clone(), BorrowKind::Shared);
|
||||
}
|
||||
}
|
||||
|
||||
let fully_matched_with_guard = candidates.iter().take_while(|c| c.guard.is_some()).count();
|
||||
|
||||
let unreachable_candidates = if fully_matched_with_guard + 1 < candidates.len() {
|
||||
|
@ -783,7 +792,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
return vec![];
|
||||
} else {
|
||||
let target = self.cfg.start_new_block();
|
||||
return self.match_candidates(span, arm_blocks, unmatched_candidates, target);
|
||||
return self.match_candidates(
|
||||
span,
|
||||
arm_blocks,
|
||||
unmatched_candidates,
|
||||
target,
|
||||
&mut None,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -796,7 +811,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
|
||||
// Test candidates where possible.
|
||||
let (otherwise, tested_candidates) =
|
||||
self.test_candidates(span, arm_blocks, &unmatched_candidates, block);
|
||||
self.test_candidates(span, arm_blocks, &unmatched_candidates, block, fake_borrows);
|
||||
|
||||
// If the target candidates were exhaustive, then we are done.
|
||||
// But for borrowck continue build decision tree.
|
||||
|
@ -810,7 +825,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
|
||||
// Otherwise, let's process those remaining candidates.
|
||||
let join_block = self.join_otherwise_blocks(span, otherwise);
|
||||
self.match_candidates(span, arm_blocks, untested_candidates, join_block)
|
||||
self.match_candidates(span, arm_blocks, untested_candidates, join_block, &mut None)
|
||||
}
|
||||
|
||||
fn join_otherwise_blocks(&mut self, span: Span, mut otherwise: Vec<BasicBlock>) -> BasicBlock {
|
||||
|
@ -950,6 +965,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
arm_blocks: &mut ArmBlocks,
|
||||
candidates: &[Candidate<'pat, 'tcx>],
|
||||
block: BasicBlock,
|
||||
fake_borrows: &mut Option<FxHashMap<Place<'tcx>, BorrowKind>>,
|
||||
) -> (Vec<BasicBlock>, usize) {
|
||||
// extract the match-pair from the highest priority candidate
|
||||
let match_pair = &candidates.first().unwrap().match_pairs[0];
|
||||
|
@ -990,6 +1006,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
// Insert a Shallow borrow of any places that is switched on.
|
||||
fake_borrows.as_mut().map(|fb| {
|
||||
fb.entry(match_pair.place.clone()).or_insert(BorrowKind::Shallow)
|
||||
});
|
||||
|
||||
// perform the test, branching to one of N blocks. For each of
|
||||
// those N possible outcomes, create a (initially empty)
|
||||
// vector of candidates. Those are the candidates that still
|
||||
|
@ -1026,7 +1047,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
.into_iter()
|
||||
.zip(target_candidates)
|
||||
.flat_map(|(target_block, target_candidates)| {
|
||||
self.match_candidates(span, arm_blocks, target_candidates, target_block)
|
||||
self.match_candidates(
|
||||
span,
|
||||
arm_blocks,
|
||||
target_candidates,
|
||||
target_block,
|
||||
fake_borrows,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -1363,7 +1390,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
// borrow of the whole match input. See additional
|
||||
// discussion on rust-lang/rust#49870.
|
||||
let borrow_kind = match borrow_kind {
|
||||
BorrowKind::Shared | BorrowKind::Unique => borrow_kind,
|
||||
BorrowKind::Shared
|
||||
| BorrowKind::Shallow
|
||||
| BorrowKind::Unique => borrow_kind,
|
||||
BorrowKind::Mut { .. } => BorrowKind::Mut {
|
||||
allow_two_phase_borrow: true,
|
||||
},
|
||||
|
@ -1502,4 +1531,86 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
debug!("declare_binding: vars={:?}", locals);
|
||||
self.var_indices.insert(var_id, locals);
|
||||
}
|
||||
|
||||
// Determine the fake borrows that are needed to ensure that the place
|
||||
// will evaluate to the same thing until an arm has been chosen.
|
||||
fn add_fake_borrows<'pat>(
|
||||
&mut self,
|
||||
pre_binding_blocks: &[(BasicBlock, Span)],
|
||||
fake_borrows: FxHashMap<Place<'tcx>, BorrowKind>,
|
||||
source_info: SourceInfo,
|
||||
start_block: BasicBlock,
|
||||
) {
|
||||
let tcx = self.hir.tcx();
|
||||
|
||||
debug!("add_fake_borrows pre_binding_blocks = {:?}, fake_borrows = {:?}",
|
||||
pre_binding_blocks, fake_borrows);
|
||||
|
||||
let mut all_fake_borrows = Vec::with_capacity(fake_borrows.len());
|
||||
|
||||
// Insert a Shallow borrow of the prefixes of any fake borrows.
|
||||
for (place, borrow_kind) in fake_borrows
|
||||
{
|
||||
{
|
||||
let mut prefix_cursor = &place;
|
||||
while let Place::Projection(box Projection { base, elem }) = prefix_cursor {
|
||||
if let ProjectionElem::Deref = elem {
|
||||
// Insert a shallow borrow after a deref. For other
|
||||
// projections the borrow of prefix_cursor will
|
||||
// conflict with any mutation of base.
|
||||
all_fake_borrows.push((base.clone(), BorrowKind::Shallow));
|
||||
}
|
||||
prefix_cursor = base;
|
||||
}
|
||||
}
|
||||
|
||||
all_fake_borrows.push((place, borrow_kind));
|
||||
}
|
||||
|
||||
// Deduplicate and ensure a deterministic order.
|
||||
all_fake_borrows.sort();
|
||||
all_fake_borrows.dedup();
|
||||
|
||||
debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows);
|
||||
|
||||
// Add fake borrows to the start of the match and reads of them before
|
||||
// the start of each arm.
|
||||
let mut borrowed_input_temps = Vec::with_capacity(all_fake_borrows.len());
|
||||
|
||||
for (matched_place, borrow_kind) in all_fake_borrows {
|
||||
let borrowed_input =
|
||||
Rvalue::Ref(tcx.types.re_empty, borrow_kind, matched_place.clone());
|
||||
let borrowed_input_ty = borrowed_input.ty(&self.local_decls, tcx);
|
||||
let borrowed_input_temp = self.temp(borrowed_input_ty, source_info.span);
|
||||
self.cfg.push_assign(
|
||||
start_block,
|
||||
source_info,
|
||||
&borrowed_input_temp,
|
||||
borrowed_input
|
||||
);
|
||||
borrowed_input_temps.push(borrowed_input_temp);
|
||||
}
|
||||
|
||||
// FIXME: This could be a lot of reads (#fake borrows * #patterns).
|
||||
// The false edges that we currently generate would allow us to only do
|
||||
// this on the last Candidate, but it's possible that there might not be
|
||||
// so many false edges in the future, so we read for all Candidates for
|
||||
// now.
|
||||
// Another option would be to make our own block and add our own false
|
||||
// edges to it.
|
||||
if tcx.emit_read_for_match() {
|
||||
for &(pre_binding_block, span) in pre_binding_blocks {
|
||||
let pattern_source_info = self.source_info(span);
|
||||
for temp in &borrowed_input_temps {
|
||||
self.cfg.push(pre_binding_block, Statement {
|
||||
source_info: pattern_source_info,
|
||||
kind: StatementKind::FakeRead(
|
||||
FakeReadCause::ForMatchGuard,
|
||||
temp.clone(),
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1991,6 +1991,26 @@ fn main() {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0510: r##"
|
||||
Cannot mutate place in this match guard.
|
||||
|
||||
When matching on a variable it cannot be mutated in the match guards, as this
|
||||
could cause the match to be non-exhaustive:
|
||||
|
||||
```compile_fail,E0510
|
||||
#![feature(nll, bind_by_move_pattern_guards)]
|
||||
let mut x = Some(0);
|
||||
match x {
|
||||
None => (),
|
||||
Some(v) if { x = None; false } => (),
|
||||
Some(_) => (), // No longer matches
|
||||
}
|
||||
```
|
||||
|
||||
Here executing `x = None` would modify the value being matched and require us
|
||||
to go "back in time" to the `None` arm.
|
||||
"##,
|
||||
|
||||
E0579: r##"
|
||||
When matching against an exclusive range, the compiler verifies that the range
|
||||
is non-empty. Exclusive range patterns include the start point but not the end
|
||||
|
|
|
@ -14,7 +14,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
|||
|
||||
*/
|
||||
|
||||
#![cfg_attr(not(stage0), feature(nll))]
|
||||
#![feature(nll)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(impl_header_lifetime_elision)]
|
||||
#![feature(slice_patterns)]
|
||||
|
|
|
@ -33,7 +33,8 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
use rustc::middle::region;
|
||||
use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind};
|
||||
use rustc::mir::{BasicBlock, FakeReadCause, Local, Location, Mir, Place};
|
||||
use rustc::mir::{Rvalue, Statement, StatementKind};
|
||||
use rustc::mir::visit::{MutVisitor, Visitor, TyContext};
|
||||
use rustc::ty::{Ty, RegionKind, TyCtxt};
|
||||
use transform::{MirPass, MirSource};
|
||||
|
@ -135,3 +136,62 @@ impl<'tcx> MutVisitor<'tcx> for DeleteAscribeUserType {
|
|||
self.super_statement(block, statement, location);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CleanFakeReadsAndBorrows;
|
||||
|
||||
pub struct DeleteAndRecordFakeReads {
|
||||
fake_borrow_temporaries: FxHashSet<Local>,
|
||||
}
|
||||
|
||||
pub struct DeleteFakeBorrows {
|
||||
fake_borrow_temporaries: FxHashSet<Local>,
|
||||
}
|
||||
|
||||
// Removes any FakeReads from the MIR
|
||||
impl MirPass for CleanFakeReadsAndBorrows {
|
||||
fn run_pass<'a, 'tcx>(&self,
|
||||
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
_source: MirSource,
|
||||
mir: &mut Mir<'tcx>) {
|
||||
let mut delete_reads = DeleteAndRecordFakeReads {
|
||||
fake_borrow_temporaries: FxHashSet(),
|
||||
};
|
||||
delete_reads.visit_mir(mir);
|
||||
let mut delete_borrows = DeleteFakeBorrows {
|
||||
fake_borrow_temporaries: delete_reads.fake_borrow_temporaries,
|
||||
};
|
||||
delete_borrows.visit_mir(mir);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for DeleteAndRecordFakeReads {
|
||||
fn visit_statement(&mut self,
|
||||
block: BasicBlock,
|
||||
statement: &mut Statement<'tcx>,
|
||||
location: Location) {
|
||||
if let StatementKind::FakeRead(cause, ref place) = statement.kind {
|
||||
if let FakeReadCause::ForMatchGuard = cause {
|
||||
match *place {
|
||||
Place::Local(local) => self.fake_borrow_temporaries.insert(local),
|
||||
_ => bug!("Fake match guard read of non-local: {:?}", place),
|
||||
};
|
||||
}
|
||||
statement.make_nop();
|
||||
}
|
||||
self.super_statement(block, statement, location);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for DeleteFakeBorrows {
|
||||
fn visit_statement(&mut self,
|
||||
block: BasicBlock,
|
||||
statement: &mut Statement<'tcx>,
|
||||
location: Location) {
|
||||
if let StatementKind::Assign(Place::Local(local), _) = statement.kind {
|
||||
if self.fake_borrow_temporaries.contains(&local) {
|
||||
statement.make_nop();
|
||||
}
|
||||
}
|
||||
self.super_statement(block, statement, location);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -237,9 +237,12 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
|
|||
no_landing_pads::NoLandingPads,
|
||||
simplify_branches::SimplifyBranches::new("initial"),
|
||||
remove_noop_landing_pads::RemoveNoopLandingPads,
|
||||
simplify::SimplifyCfg::new("early-opt"),
|
||||
// Remove all `AscribeUserType` statements.
|
||||
cleanup_post_borrowck::CleanAscribeUserType,
|
||||
// Remove all `FakeRead` statements and the borrows that are only
|
||||
// used for checking matches
|
||||
cleanup_post_borrowck::CleanFakeReadsAndBorrows,
|
||||
simplify::SimplifyCfg::new("early-opt"),
|
||||
|
||||
// These next passes must be executed together
|
||||
add_call_guards::CriticalCallEdges,
|
||||
|
|
|
@ -555,6 +555,29 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
|
|||
self.cannot_borrow_path_as_mutable_because(span, path, "", o)
|
||||
}
|
||||
|
||||
fn cannot_mutate_in_match_guard(
|
||||
self,
|
||||
mutate_span: Span,
|
||||
match_span: Span,
|
||||
match_place: &str,
|
||||
action: &str,
|
||||
o: Origin,
|
||||
) -> DiagnosticBuilder<'cx> {
|
||||
let mut err = struct_span_err!(
|
||||
self,
|
||||
mutate_span,
|
||||
E0510,
|
||||
"cannot {} `{}` in match guard{OGN}",
|
||||
action,
|
||||
match_place,
|
||||
OGN = o
|
||||
);
|
||||
err.span_label(mutate_span, format!("cannot {}", action));
|
||||
err.span_label(match_span, format!("value is immutable in match guard"));
|
||||
|
||||
self.cancel_if_wrong_origin(err, o)
|
||||
}
|
||||
|
||||
fn cannot_borrow_across_generator_yield(
|
||||
self,
|
||||
span: Span,
|
||||
|
|
|
@ -63,7 +63,6 @@ impl Drop for S {
|
|||
//
|
||||
// bb4: {
|
||||
// StorageDead(_2);
|
||||
// FakeRead(ForLet, _1);
|
||||
// StorageLive(_4);
|
||||
// _4 = move _1;
|
||||
// _3 = const std::mem::drop(move _4) -> [return: bb5, unwind: bb7];
|
||||
|
|
|
@ -34,10 +34,9 @@ fn main() {
|
|||
// }
|
||||
// let mut _1: ();
|
||||
// let mut _3: bool;
|
||||
// let mut _4: u8;
|
||||
// let mut _5: !;
|
||||
// let mut _6: ();
|
||||
// let mut _7: &i32;
|
||||
// let mut _4: !;
|
||||
// let mut _5: ();
|
||||
// let mut _6: &i32;
|
||||
// bb0: {
|
||||
// goto -> bb1;
|
||||
// }
|
||||
|
@ -51,7 +50,7 @@ fn main() {
|
|||
// StorageLive(_2);
|
||||
// StorageLive(_3);
|
||||
// _3 = const true;
|
||||
// _4 = discriminant(_3);
|
||||
// FakeRead(ForMatchedPlace, _3);
|
||||
// switchInt(_3) -> [false: bb11, otherwise: bb10];
|
||||
// }
|
||||
// bb4: {
|
||||
|
@ -89,9 +88,9 @@ fn main() {
|
|||
// bb14: {
|
||||
// FakeRead(ForLet, _2);
|
||||
// StorageDead(_3);
|
||||
// StorageLive(_7);
|
||||
// _7 = &_2;
|
||||
// _6 = const std::mem::drop(move _7) -> [return: bb28, unwind: bb4];
|
||||
// StorageLive(_6);
|
||||
// _6 = &_2;
|
||||
// _5 = const std::mem::drop(move _6) -> [return: bb28, unwind: bb4];
|
||||
// }
|
||||
// bb15: {
|
||||
// goto -> bb16;
|
||||
|
@ -129,15 +128,15 @@ fn main() {
|
|||
// goto -> bb2;
|
||||
// }
|
||||
// bb26: {
|
||||
// _5 = ();
|
||||
// _4 = ();
|
||||
// unreachable;
|
||||
// }
|
||||
// bb27: {
|
||||
// StorageDead(_5);
|
||||
// StorageDead(_4);
|
||||
// goto -> bb14;
|
||||
// }
|
||||
// bb28: {
|
||||
// StorageDead(_7);
|
||||
// StorageDead(_6);
|
||||
// _1 = ();
|
||||
// StorageDead(_2);
|
||||
// goto -> bb1;
|
||||
|
|
|
@ -53,10 +53,11 @@ fn main() {
|
|||
// bb0: {
|
||||
// ...
|
||||
// _2 = std::option::Option<i32>::Some(const 42i32,);
|
||||
// _3 = discriminant(_2);
|
||||
// _4 = &(promoted[1]: std::option::Option<i32>);
|
||||
// _9 = discriminant(_2);
|
||||
// switchInt(move _9) -> [0isize: bb5, 1isize: bb3, otherwise: bb7];
|
||||
// FakeRead(ForMatchedPlace, _2);
|
||||
// _7 = discriminant(_2);
|
||||
// _9 = &shallow (promoted[2]: std::option::Option<i32>);
|
||||
// _10 = &(((promoted[1]: std::option::Option<i32>) as Some).0: i32);
|
||||
// switchInt(move _7) -> [0isize: bb5, 1isize: bb3, otherwise: bb7];
|
||||
// }
|
||||
// bb1: {
|
||||
// resume;
|
||||
|
@ -66,15 +67,18 @@ fn main() {
|
|||
// goto -> bb13;
|
||||
// }
|
||||
// bb3: { // binding3(empty) and arm3
|
||||
// FakeRead(ForMatch, _4);
|
||||
// FakeRead(ForMatchGuard, _9);
|
||||
// FakeRead(ForMatchGuard, _10);
|
||||
// falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
|
||||
// }
|
||||
// bb4: {
|
||||
// FakeRead(ForMatch, _4);
|
||||
// FakeRead(ForMatchGuard, _9);
|
||||
// FakeRead(ForMatchGuard, _10);
|
||||
// falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding2
|
||||
// }
|
||||
// bb5: {
|
||||
// FakeRead(ForMatch, _4);
|
||||
// FakeRead(ForMatchGuard, _9);
|
||||
// FakeRead(ForMatchGuard, _10);
|
||||
// falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3
|
||||
// }
|
||||
// bb6: {
|
||||
|
@ -84,31 +88,31 @@ fn main() {
|
|||
// unreachable;
|
||||
// }
|
||||
// bb8: { // binding1 and guard
|
||||
// StorageLive(_7);
|
||||
// _7 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
|
||||
// StorageLive(_10);
|
||||
// _10 = const guard() -> [return: bb9, unwind: bb1];
|
||||
// StorageLive(_5);
|
||||
// _5 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
|
||||
// StorageLive(_8);
|
||||
// _8 = const guard() -> [return: bb9, unwind: bb1];
|
||||
// }
|
||||
// bb9: {
|
||||
// switchInt(move _10) -> [false: bb10, otherwise: bb11];
|
||||
// switchInt(move _8) -> [false: bb10, otherwise: bb11];
|
||||
// }
|
||||
// bb10: { // to pre_binding2
|
||||
// falseEdges -> [real: bb4, imaginary: bb4];
|
||||
// }
|
||||
// bb11: { // bindingNoLandingPads.before.mir2 and arm2
|
||||
// StorageLive(_5);
|
||||
// _5 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_3);
|
||||
// _3 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_11);
|
||||
// _11 = _5;
|
||||
// _11 = _3;
|
||||
// _1 = (const 1i32, move _11);
|
||||
// StorageDead(_11);
|
||||
// goto -> bb13;
|
||||
// }
|
||||
// bb12: {
|
||||
// StorageLive(_8);
|
||||
// _8 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_6);
|
||||
// _6 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_12);
|
||||
// _12 = _8;
|
||||
// _12 = _6;
|
||||
// _1 = (const 2i32, move_12);
|
||||
// StorageDead(_12);
|
||||
// goto -> bb13;
|
||||
|
@ -123,10 +127,11 @@ fn main() {
|
|||
// bb0: {
|
||||
// ...
|
||||
// _2 = std::option::Option<i32>::Some(const 42i32,);
|
||||
// _3 = discriminant(_2);
|
||||
// _4 = &_2;
|
||||
// _9 = discriminant(_2);
|
||||
// switchInt(move _9) -> [0isize: bb4, 1isize: bb3, otherwise: bb7];
|
||||
// FakeRead(ForMatchedPlace, _2);
|
||||
// _7 = discriminant(_2);
|
||||
// _9 = &shallow _2;
|
||||
// _10 = &((_2 as Some).0: i32);
|
||||
// switchInt(move _7) -> [0isize: bb4, 1isize: bb3, otherwise: bb7];
|
||||
// }
|
||||
// bb1: {
|
||||
// resume;
|
||||
|
@ -136,15 +141,18 @@ fn main() {
|
|||
// goto -> bb13;
|
||||
// }
|
||||
// bb3: {
|
||||
// FakeRead(ForMatch, _4);
|
||||
// FakeRead(ForMatchGuard, _9);
|
||||
// FakeRead(ForMatchGuard, _10);
|
||||
// falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
|
||||
// }
|
||||
// bb4: {
|
||||
// FakeRead(ForMatch, _4);
|
||||
// FakeRead(ForMatchGuard, _9);
|
||||
// FakeRead(ForMatchGuard, _10);
|
||||
// falseEdges -> [real: bb2, imaginary: bb5]; //pre_binding2
|
||||
// }
|
||||
// bb5: {
|
||||
// FakeRead(ForMatch, _4);
|
||||
// FakeRead(ForMatchGuard, _9);
|
||||
// FakeRead(ForMatchGuard, _10);
|
||||
// falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3
|
||||
// }
|
||||
// bb6: {
|
||||
|
@ -154,31 +162,31 @@ fn main() {
|
|||
// unreachable;
|
||||
// }
|
||||
// bb8: { // binding1 and guard
|
||||
// StorageLive(_7);
|
||||
// _7 = &((_2 as Some).0: i32);
|
||||
// StorageLive(_10);
|
||||
// _10 = const guard() -> [return: bb9, unwind: bb1];
|
||||
// StorageLive(_5);
|
||||
// _5 = &((_2 as Some).0: i32);
|
||||
// StorageLive(_8);
|
||||
// _8 = const guard() -> [return: bb9, unwind: bb1];
|
||||
// }
|
||||
// bb9: { // end of guard
|
||||
// switchInt(move _10) -> [false: bb10, otherwise: bb11];
|
||||
// switchInt(move _8) -> [false: bb10, otherwise: bb11];
|
||||
// }
|
||||
// bb10: { // to pre_binding3 (can skip 2 since this is `Some`)
|
||||
// falseEdges -> [real: bb5, imaginary: bb4];
|
||||
// }
|
||||
// bb11: { // arm1
|
||||
// StorageLive(_5);
|
||||
// _5 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_3);
|
||||
// _3 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_11);
|
||||
// _11 = _5;
|
||||
// _11 = _3;
|
||||
// _1 = (const 1i32, move _11);
|
||||
// StorageDead(_11);
|
||||
// goto -> bb13;
|
||||
// }
|
||||
// bb12: { // binding3 and arm3
|
||||
// StorageLive(_8);
|
||||
// _8 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_6);
|
||||
// _6 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_12);
|
||||
// _12 = _8;
|
||||
// _12 = _6;
|
||||
// _1 = (const 2i32, move _12);
|
||||
// StorageDead(_12);
|
||||
// goto -> bb13;
|
||||
|
@ -193,81 +201,86 @@ fn main() {
|
|||
// bb0: {
|
||||
// ...
|
||||
// _2 = std::option::Option<i32>::Some(const 1i32,);
|
||||
// _3 = discriminant(_2);
|
||||
// _4 = &_2;
|
||||
// _13 = discriminant(_2);
|
||||
// switchInt(move _13) -> [1isize: bb2, otherwise: bb3];
|
||||
// FakeRead(ForMatchedPlace, _2);
|
||||
// _11 = discriminant(_2);
|
||||
// _16 = &shallow _2;
|
||||
// _17 = &((_2 as Some).0: i32);
|
||||
// switchInt(move _11) -> [1isize: bb2, otherwise: bb3];
|
||||
// }
|
||||
// bb1: {
|
||||
// resume;
|
||||
// }
|
||||
// bb2: {
|
||||
// FakeRead(ForMatch, _4);
|
||||
// FakeRead(ForMatchGuard, _16);
|
||||
// FakeRead(ForMatchGuard, _17);
|
||||
// falseEdges -> [real: bb7, imaginary: bb3]; //pre_binding1
|
||||
// }
|
||||
// bb3: {
|
||||
// FakeRead(ForMatch, _4);
|
||||
// FakeRead(ForMatchGuard, _16);
|
||||
// FakeRead(ForMatchGuard, _17);
|
||||
// falseEdges -> [real: bb11, imaginary: bb4]; //pre_binding2
|
||||
// }
|
||||
// bb4: {
|
||||
// FakeRead(ForMatch, _4);
|
||||
// FakeRead(ForMatchGuard, _16);
|
||||
// FakeRead(ForMatchGuard, _17);
|
||||
// falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding3
|
||||
// }
|
||||
// bb5: {
|
||||
// FakeRead(ForMatch, _4);
|
||||
// FakeRead(ForMatchGuard, _16);
|
||||
// FakeRead(ForMatchGuard, _17);
|
||||
// falseEdges -> [real: bb16, imaginary: bb6]; //pre_binding4
|
||||
// }
|
||||
// bb6: {
|
||||
// unreachable;
|
||||
// }
|
||||
// bb7: { // binding1: Some(w) if guard()
|
||||
// StorageLive(_7);
|
||||
// _7 = &((_2 as Some).0: i32);
|
||||
// StorageLive(_14);
|
||||
// _14 = const guard() -> [return: bb8, unwind: bb1];
|
||||
// StorageLive(_5);
|
||||
// _5 = &((_2 as Some).0: i32);
|
||||
// StorageLive(_12);
|
||||
// _12 = const guard() -> [return: bb8, unwind: bb1];
|
||||
// }
|
||||
// bb8: { //end of guard
|
||||
// switchInt(move _14) -> [false: bb9, otherwise: bb10];
|
||||
// switchInt(move _12) -> [false: bb9, otherwise: bb10];
|
||||
// }
|
||||
// bb9: { // to pre_binding2
|
||||
// falseEdges -> [real: bb3, imaginary: bb3];
|
||||
// }
|
||||
// bb10: { // set up bindings for arm1
|
||||
// StorageLive(_5);
|
||||
// _5 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_3);
|
||||
// _3 = ((_2 as Some).0: i32);
|
||||
// _1 = const 1i32;
|
||||
// goto -> bb17;
|
||||
// }
|
||||
// bb11: { // binding2 & arm2
|
||||
// StorageLive(_8);
|
||||
// _8 = _2;
|
||||
// StorageLive(_6);
|
||||
// _6 = _2;
|
||||
// _1 = const 2i32;
|
||||
// goto -> bb17;
|
||||
// }
|
||||
// bb12: { // binding3: Some(y) if guard2(y)
|
||||
// StorageLive(_11);
|
||||
// _11 = &((_2 as Some).0: i32);
|
||||
// StorageLive(_16);
|
||||
// StorageLive(_17);
|
||||
// _17 = (*_11);
|
||||
// _16 = const guard2(move _17) -> [return: bb13, unwind: bb1];
|
||||
// StorageLive(_9);
|
||||
// _9 = &((_2 as Some).0: i32);
|
||||
// StorageLive(_14);
|
||||
// StorageLive(_15);
|
||||
// _15 = (*_9);
|
||||
// _14 = const guard2(move _15) -> [return: bb13, unwind: bb1];
|
||||
// }
|
||||
// bb13: { // end of guard2
|
||||
// StorageDead(_17);
|
||||
// switchInt(move _16) -> [false: bb14, otherwise: bb15];
|
||||
// StorageDead(_15);
|
||||
// switchInt(move _14) -> [false: bb14, otherwise: bb15];
|
||||
// }
|
||||
// bb14: { // to pre_binding4
|
||||
// falseEdges -> [real: bb5, imaginary: bb5];
|
||||
// }
|
||||
// bb15: { // set up bindings for arm3
|
||||
// StorageLive(_9);
|
||||
// _9 = ((_2 as Some).0: i32);
|
||||
// StorageLive(_7);
|
||||
// _7 = ((_2 as Some).0: i32);
|
||||
// _1 = const 3i32;
|
||||
// goto -> bb17;
|
||||
// }
|
||||
// bb16: { // binding4 & arm4
|
||||
// StorageLive(_12);
|
||||
// _12 = _2;
|
||||
// StorageLive(_10);
|
||||
// _10 = _2;
|
||||
// _1 = const 4i32;
|
||||
// goto -> bb17;
|
||||
// }
|
||||
|
|
122
src/test/mir-opt/remove_fake_borrows.rs
Normal file
122
src/test/mir-opt/remove_fake_borrows.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
// Test that the fake borrows for matches are removed after borrow checking.
|
||||
|
||||
// ignore-wasm32-bare
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
fn match_guard(x: Option<&&i32>) -> i32 {
|
||||
match x {
|
||||
Some(0) if true => 0,
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match_guard(None);
|
||||
}
|
||||
|
||||
// END RUST SOURCE
|
||||
|
||||
// START rustc.match_guard.CleanFakeReadsAndBorrows.before.mir
|
||||
// bb0: {
|
||||
// FakeRead(ForMatchedPlace, _1);
|
||||
// _2 = discriminant(_1);
|
||||
// _3 = &shallow _1;
|
||||
// _4 = &shallow ((_1 as Some).0: &'<empty> &'<empty> i32);
|
||||
// _5 = &shallow (*((_1 as Some).0: &'<empty> &'<empty> i32));
|
||||
// _6 = &shallow (*(*((_1 as Some).0: &'<empty> &'<empty> i32)));
|
||||
// switchInt(move _2) -> [1isize: bb6, otherwise: bb4];
|
||||
// }
|
||||
// bb1: {
|
||||
// _0 = const 0i32;
|
||||
// goto -> bb9;
|
||||
// }
|
||||
// bb2: {
|
||||
// _0 = const 1i32;
|
||||
// goto -> bb9;
|
||||
// }
|
||||
// bb3: {
|
||||
// FakeRead(ForMatchGuard, _3);
|
||||
// FakeRead(ForMatchGuard, _4);
|
||||
// FakeRead(ForMatchGuard, _5);
|
||||
// FakeRead(ForMatchGuard, _6);
|
||||
// goto -> bb7;
|
||||
// }
|
||||
// bb4: {
|
||||
// FakeRead(ForMatchGuard, _3);
|
||||
// FakeRead(ForMatchGuard, _4);
|
||||
// FakeRead(ForMatchGuard, _5);
|
||||
// FakeRead(ForMatchGuard, _6);
|
||||
// goto -> bb2;
|
||||
// }
|
||||
// bb5: {
|
||||
// unreachable;
|
||||
// }
|
||||
// bb6: {
|
||||
// switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb3, otherwise: bb4];
|
||||
// }
|
||||
// bb7: {
|
||||
// goto -> bb1;
|
||||
// }
|
||||
// bb8: {
|
||||
// goto -> bb4;
|
||||
// }
|
||||
// bb9: {
|
||||
// return;
|
||||
// }
|
||||
// bb10: {
|
||||
// resume;
|
||||
// }
|
||||
// END rustc.match_guard.CleanFakeReadsAndBorrows.before.mir
|
||||
|
||||
// START rustc.match_guard.CleanFakeReadsAndBorrows.after.mir
|
||||
// bb0: {
|
||||
// nop;
|
||||
// _2 = discriminant(_1);
|
||||
// nop;
|
||||
// nop;
|
||||
// nop;
|
||||
// nop;
|
||||
// switchInt(move _2) -> [1isize: bb6, otherwise: bb4];
|
||||
// }
|
||||
// bb1: {
|
||||
// _0 = const 0i32;
|
||||
// goto -> bb9;
|
||||
// }
|
||||
// bb2: {
|
||||
// _0 = const 1i32;
|
||||
// goto -> bb9;
|
||||
// }
|
||||
// bb3: {
|
||||
// nop;
|
||||
// nop;
|
||||
// nop;
|
||||
// nop;
|
||||
// goto -> bb7;
|
||||
// }
|
||||
// bb4: {
|
||||
// nop;
|
||||
// nop;
|
||||
// nop;
|
||||
// nop;
|
||||
// goto -> bb2;
|
||||
// }
|
||||
// bb5: {
|
||||
// unreachable;
|
||||
// }
|
||||
// bb6: {
|
||||
// switchInt((*(*((_1 as Some).0: &'<empty> &'<empty> i32)))) -> [0i32: bb3, otherwise: bb4];
|
||||
// }
|
||||
// bb7: {
|
||||
// goto -> bb1;
|
||||
// }
|
||||
// bb8: {
|
||||
// goto -> bb4;
|
||||
// }
|
||||
// bb9: {
|
||||
// return;
|
||||
// }
|
||||
// bb10: {
|
||||
// resume;
|
||||
// }
|
||||
// END rustc.match_guard.CleanFakeReadsAndBorrows.after.mir
|
|
@ -67,7 +67,6 @@ fn main() {
|
|||
// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })), [(*_2): i32]);
|
||||
// _3 = &ReErased (*_2);
|
||||
// Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }) (imm)]);
|
||||
// FakeRead(ForLet, _3);
|
||||
// _0 = (*_3);
|
||||
// EndRegion(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }));
|
||||
// StorageDead(_3);
|
||||
|
|
|
@ -28,7 +28,6 @@ fn main() {
|
|||
// Validate(Acquire, [_1: std::boxed::Box<[i32]>]);
|
||||
// StorageDead(_2);
|
||||
// StorageDead(_3);
|
||||
// FakeRead(ForLet, _1);
|
||||
// _0 = ();
|
||||
// Validate(Release, [_1: std::boxed::Box<[i32]>]);
|
||||
// drop(_1) -> [return: bb2, unwind: bb3];
|
||||
|
|
|
@ -47,12 +47,10 @@ fn main() {
|
|||
// bb0: {
|
||||
// StorageLive(_1);
|
||||
// _1 = Test { x: const 0i32 };
|
||||
// FakeRead(ForLet, _1);
|
||||
// StorageLive(_2);
|
||||
// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 })), [_1: Test]);
|
||||
// _2 = &ReErased _1;
|
||||
// Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
|
||||
// FakeRead(ForLet, _2);
|
||||
// StorageLive(_4);
|
||||
// StorageLive(_5);
|
||||
// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]);
|
||||
|
|
|
@ -1,27 +1,3 @@
|
|||
error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-anon-fields-struct.rs:23:19
|
||||
|
|
||||
LL | Y(ref mut a, _) => a
|
||||
| --------- mutable borrow occurs here
|
||||
...
|
||||
LL | let b = match y {
|
||||
| ^ immutable borrow occurs here
|
||||
...
|
||||
LL | *a += 1;
|
||||
| ------- borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-anon-fields-struct.rs:38:19
|
||||
|
|
||||
LL | Y(ref mut a, _) => a
|
||||
| --------- mutable borrow occurs here
|
||||
...
|
||||
LL | let b = match y {
|
||||
| ^ immutable borrow occurs here
|
||||
...
|
||||
LL | *a += 1;
|
||||
| ------- borrow later used here
|
||||
|
||||
error[E0499]: cannot borrow `y.0` as mutable more than once at a time
|
||||
--> $DIR/borrowck-anon-fields-struct.rs:39:11
|
||||
|
|
||||
|
@ -34,7 +10,6 @@ LL | Y(ref mut b, _) => b //~ ERROR cannot borrow
|
|||
LL | *a += 1;
|
||||
| ------- borrow later used here
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
Some errors occurred: E0499, E0502.
|
||||
For more information about an error, try `rustc --explain E0499`.
|
||||
For more information about this error, try `rustc --explain E0499`.
|
||||
|
|
|
@ -1,27 +1,3 @@
|
|||
error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-anon-fields-tuple.rs:21:19
|
||||
|
|
||||
LL | (ref mut a, _) => a
|
||||
| --------- mutable borrow occurs here
|
||||
...
|
||||
LL | let b = match y {
|
||||
| ^ immutable borrow occurs here
|
||||
...
|
||||
LL | *a += 1;
|
||||
| ------- borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-anon-fields-tuple.rs:36:19
|
||||
|
|
||||
LL | (ref mut a, _) => a
|
||||
| --------- mutable borrow occurs here
|
||||
...
|
||||
LL | let b = match y {
|
||||
| ^ immutable borrow occurs here
|
||||
...
|
||||
LL | *a += 1;
|
||||
| ------- borrow later used here
|
||||
|
||||
error[E0499]: cannot borrow `y.0` as mutable more than once at a time
|
||||
--> $DIR/borrowck-anon-fields-tuple.rs:37:10
|
||||
|
|
||||
|
@ -34,7 +10,6 @@ LL | (ref mut b, _) => b //~ ERROR cannot borrow
|
|||
LL | *a += 1;
|
||||
| ------- borrow later used here
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
Some errors occurred: E0499, E0502.
|
||||
For more information about an error, try `rustc --explain E0499`.
|
||||
For more information about this error, try `rustc --explain E0499`.
|
||||
|
|
|
@ -1,27 +1,3 @@
|
|||
error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-anon-fields-variant.rs:26:19
|
||||
|
|
||||
LL | Foo::Y(ref mut a, _) => a,
|
||||
| --------- mutable borrow occurs here
|
||||
...
|
||||
LL | let b = match y {
|
||||
| ^ immutable borrow occurs here
|
||||
...
|
||||
LL | *a += 1;
|
||||
| ------- borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-anon-fields-variant.rs:43:19
|
||||
|
|
||||
LL | Foo::Y(ref mut a, _) => a,
|
||||
| --------- mutable borrow occurs here
|
||||
...
|
||||
LL | let b = match y {
|
||||
| ^ immutable borrow occurs here
|
||||
...
|
||||
LL | *a += 1;
|
||||
| ------- borrow later used here
|
||||
|
||||
error[E0499]: cannot borrow `y.0` as mutable more than once at a time
|
||||
--> $DIR/borrowck-anon-fields-variant.rs:44:14
|
||||
|
|
||||
|
@ -34,7 +10,6 @@ LL | Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow
|
|||
LL | *a += 1;
|
||||
| ------- borrow later used here
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
Some errors occurred: E0499, E0502.
|
||||
For more information about an error, try `rustc --explain E0499`.
|
||||
For more information about this error, try `rustc --explain E0499`.
|
||||
|
|
|
@ -28,17 +28,6 @@ LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow
|
|||
LL | *bar1;
|
||||
| ----- borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `*foo` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-borrow-from-owned-ptr.rs:72:11
|
||||
|
|
||||
LL | let bar1 = &mut foo.bar1;
|
||||
| ------------- mutable borrow occurs here
|
||||
LL | match *foo {
|
||||
| ^^^^ immutable borrow occurs here
|
||||
...
|
||||
LL | *bar1;
|
||||
| ----- borrow later used here
|
||||
|
||||
error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
|
||||
--> $DIR/borrowck-borrow-from-owned-ptr.rs:73:21
|
||||
|
|
||||
|
@ -121,7 +110,7 @@ LL | let foo = make_foo();
|
|||
LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow
|
||||
| ^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
Some errors occurred: E0499, E0502, E0596.
|
||||
For more information about an error, try `rustc --explain E0499`.
|
||||
|
|
|
@ -28,17 +28,6 @@ LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow
|
|||
LL | *bar1;
|
||||
| ----- borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-borrow-from-stack-variable.rs:70:11
|
||||
|
|
||||
LL | let bar1 = &mut foo.bar1;
|
||||
| ------------- mutable borrow occurs here
|
||||
LL | match foo {
|
||||
| ^^^ immutable borrow occurs here
|
||||
...
|
||||
LL | *bar1;
|
||||
| ----- borrow later used here
|
||||
|
||||
error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time
|
||||
--> $DIR/borrowck-borrow-from-stack-variable.rs:71:21
|
||||
|
|
||||
|
@ -121,7 +110,7 @@ LL | let foo = make_foo();
|
|||
LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow
|
||||
| ^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
Some errors occurred: E0499, E0502, E0596.
|
||||
For more information about an error, try `rustc --explain E0499`.
|
||||
|
|
|
@ -72,23 +72,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `e` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:77:15
|
||||
|
|
||||
LL | let x = e.x();
|
||||
| - borrow of `e` occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
| ^ use of borrowed `e`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `e.0` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:78:20
|
||||
|
|
||||
LL | let x = e.x();
|
||||
| - borrow of `e` occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
LL | match e {
|
||||
LL | Baz::X(value) => value
|
||||
| ^^^^^ use of borrowed `e`
|
||||
...
|
||||
|
@ -139,23 +128,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `*e` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:120:15
|
||||
|
|
||||
LL | let x = e.x();
|
||||
| - borrow of `*e` occurs here
|
||||
LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed
|
||||
| ^^ use of borrowed `*e`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `e.0` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:121:20
|
||||
|
|
||||
LL | let x = e.x();
|
||||
| - borrow of `*e` occurs here
|
||||
LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed
|
||||
LL | match *e {
|
||||
LL | Baz::X(value) => value
|
||||
| ^^^^^ use of borrowed `*e`
|
||||
...
|
||||
|
@ -173,41 +151,18 @@ LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrow
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:139:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:140:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
LL | match v {
|
||||
LL | &[x, _, .., _, _] => println!("{}", x),
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:145:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:146:18
|
||||
|
|
||||
|
@ -220,18 +175,6 @@ LL | &[_, x, .., _, _] => println!("{}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:151:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:152:25
|
||||
|
|
||||
|
@ -244,18 +187,6 @@ LL | &[_, _, .., x, _] => println!("{}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:157:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:158:28
|
||||
|
|
||||
|
@ -268,41 +199,18 @@ LL | &[_, _, .., _, x] => println!("{}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:169:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:170:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
LL | match v {
|
||||
LL | &[x..] => println!("{:?}", x),
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:175:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:176:18
|
||||
|
|
||||
|
@ -315,18 +223,6 @@ LL | &[_, x..] => println!("{:?}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:181:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:182:15
|
||||
|
|
||||
|
@ -339,18 +235,6 @@ LL | &[x.., _] => println!("{:?}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:187:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:188:18
|
||||
|
|
||||
|
@ -363,23 +247,12 @@ LL | &[_, x.., _] => println!("{:?}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `e` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:201:15
|
||||
|
|
||||
LL | let x = &mut e;
|
||||
| ------ borrow of `e` occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
| ^ use of borrowed `e`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `e` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:202:13
|
||||
|
|
||||
LL | let x = &mut e;
|
||||
| ------ borrow of `e` occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
LL | match e {
|
||||
LL | E::A(ref ax) =>
|
||||
| ^^^^^^^^^^^^ use of borrowed `e`
|
||||
...
|
||||
|
@ -391,7 +264,7 @@ error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mu
|
|||
|
|
||||
LL | let x = &mut e;
|
||||
| ------ mutable borrow occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
LL | match e {
|
||||
LL | E::A(ref ax) =>
|
||||
| ^^^^^^ immutable borrow occurs here
|
||||
...
|
||||
|
@ -410,41 +283,18 @@ LL | E::B { x: ref bx } =>
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `s` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:220:15
|
||||
|
|
||||
LL | let x = &mut s;
|
||||
| ------ borrow of `s` occurs here
|
||||
LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
|
||||
| ^ use of borrowed `s`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-describe-lvalue.rs:221:22
|
||||
|
|
||||
LL | let x = &mut s;
|
||||
| ------ mutable borrow occurs here
|
||||
LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
|
||||
LL | match s {
|
||||
LL | S { y: (ref y0, _), .. } =>
|
||||
| ^^^^^^ immutable borrow occurs here
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `s` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:227:15
|
||||
|
|
||||
LL | let x = &mut s;
|
||||
| ------ borrow of `s` occurs here
|
||||
...
|
||||
LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
|
||||
| ^ use of borrowed `s`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-describe-lvalue.rs:228:28
|
||||
|
|
||||
|
@ -479,23 +329,12 @@ LL | v[0].y;
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:282:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-describe-lvalue.rs:283:24
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ mutable borrow occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
LL | match v {
|
||||
LL | &[_, F {x: ref xf, ..}] => println!("{}", xf),
|
||||
| ^^^^^^ immutable borrow occurs here
|
||||
...
|
||||
|
@ -534,7 +373,7 @@ LL | drop(x); //[ast]~ ERROR use of moved value: `x`
|
|||
|
|
||||
= note: move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 46 previous errors
|
||||
error: aborting due to 32 previous errors
|
||||
|
||||
Some errors occurred: E0382, E0499, E0502, E0503.
|
||||
For more information about an error, try `rustc --explain E0382`.
|
||||
|
|
|
@ -27,7 +27,7 @@ error[E0503]: cannot use `e.0` because it was mutably borrowed
|
|||
|
|
||||
LL | let x = e.x();
|
||||
| - borrow of `e` occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
LL | match e {
|
||||
LL | Baz::X(value) => value
|
||||
| ^^^^^ use of borrowed `e`
|
||||
|
||||
|
@ -68,7 +68,7 @@ error[E0503]: cannot use `e.0` because it was mutably borrowed
|
|||
|
|
||||
LL | let x = e.x();
|
||||
| - borrow of `*e` occurs here
|
||||
LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed
|
||||
LL | match *e {
|
||||
LL | Baz::X(value) => value
|
||||
| ^^^^^ use of borrowed `*e`
|
||||
|
||||
|
@ -85,7 +85,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
|||
|
|
||||
LL | let x = &mut v;
|
||||
| - borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
LL | match v {
|
||||
LL | &[x, _, .., _, _] => println!("{}", x),
|
||||
| ^ use of borrowed `v`
|
||||
|
||||
|
@ -121,7 +121,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
|||
|
|
||||
LL | let x = &mut v;
|
||||
| - borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
LL | match v {
|
||||
LL | &[x..] => println!("{:?}", x),
|
||||
| ^ use of borrowed `v`
|
||||
|
||||
|
@ -157,7 +157,7 @@ error[E0502]: cannot borrow `e.0` as immutable because `e` is also borrowed as m
|
|||
|
|
||||
LL | let x = &mut e;
|
||||
| - mutable borrow occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
LL | match e {
|
||||
LL | E::A(ref ax) =>
|
||||
| ^^^^^^ immutable borrow occurs here
|
||||
...
|
||||
|
@ -181,7 +181,7 @@ error[E0502]: cannot borrow `s.y.0` as immutable because `s` is also borrowed as
|
|||
|
|
||||
LL | let x = &mut s;
|
||||
| - mutable borrow occurs here
|
||||
LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
|
||||
LL | match s {
|
||||
LL | S { y: (ref y0, _), .. } =>
|
||||
| ^^^^^^ immutable borrow occurs here
|
||||
...
|
||||
|
|
|
@ -72,23 +72,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `e` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:77:15
|
||||
|
|
||||
LL | let x = e.x();
|
||||
| - borrow of `e` occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
| ^ use of borrowed `e`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `e.0` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:78:20
|
||||
|
|
||||
LL | let x = e.x();
|
||||
| - borrow of `e` occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
LL | match e {
|
||||
LL | Baz::X(value) => value
|
||||
| ^^^^^ use of borrowed `e`
|
||||
...
|
||||
|
@ -139,23 +128,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `*e` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:120:15
|
||||
|
|
||||
LL | let x = e.x();
|
||||
| - borrow of `*e` occurs here
|
||||
LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed
|
||||
| ^^ use of borrowed `*e`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `e.0` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:121:20
|
||||
|
|
||||
LL | let x = e.x();
|
||||
| - borrow of `*e` occurs here
|
||||
LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed
|
||||
LL | match *e {
|
||||
LL | Baz::X(value) => value
|
||||
| ^^^^^ use of borrowed `*e`
|
||||
...
|
||||
|
@ -173,41 +151,18 @@ LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrow
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:139:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:140:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
LL | match v {
|
||||
LL | &[x, _, .., _, _] => println!("{}", x),
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:145:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:146:18
|
||||
|
|
||||
|
@ -220,18 +175,6 @@ LL | &[_, x, .., _, _] => println!("{}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:151:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:152:25
|
||||
|
|
||||
|
@ -244,18 +187,6 @@ LL | &[_, _, .., x, _] => println!("{}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:157:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:158:28
|
||||
|
|
||||
|
@ -268,41 +199,18 @@ LL | &[_, _, .., _, x] => println!("{}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:169:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:170:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
LL | match v {
|
||||
LL | &[x..] => println!("{:?}", x),
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:175:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:176:18
|
||||
|
|
||||
|
@ -315,18 +223,6 @@ LL | &[_, x..] => println!("{:?}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:181:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:182:15
|
||||
|
|
||||
|
@ -339,18 +235,6 @@ LL | &[x.., _] => println!("{:?}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:187:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
...
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v[..]` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:188:18
|
||||
|
|
||||
|
@ -363,23 +247,12 @@ LL | &[_, x.., _] => println!("{:?}", x),
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `e` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:201:15
|
||||
|
|
||||
LL | let x = &mut e;
|
||||
| ------ borrow of `e` occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
| ^ use of borrowed `e`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `e` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:202:13
|
||||
|
|
||||
LL | let x = &mut e;
|
||||
| ------ borrow of `e` occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
LL | match e {
|
||||
LL | E::A(ref ax) =>
|
||||
| ^^^^^^^^^^^^ use of borrowed `e`
|
||||
...
|
||||
|
@ -391,7 +264,7 @@ error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mu
|
|||
|
|
||||
LL | let x = &mut e;
|
||||
| ------ mutable borrow occurs here
|
||||
LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
LL | match e {
|
||||
LL | E::A(ref ax) =>
|
||||
| ^^^^^^ immutable borrow occurs here
|
||||
...
|
||||
|
@ -410,41 +283,18 @@ LL | E::B { x: ref bx } =>
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `s` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:220:15
|
||||
|
|
||||
LL | let x = &mut s;
|
||||
| ------ borrow of `s` occurs here
|
||||
LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
|
||||
| ^ use of borrowed `s`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-describe-lvalue.rs:221:22
|
||||
|
|
||||
LL | let x = &mut s;
|
||||
| ------ mutable borrow occurs here
|
||||
LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
|
||||
LL | match s {
|
||||
LL | S { y: (ref y0, _), .. } =>
|
||||
| ^^^^^^ immutable borrow occurs here
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `s` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:227:15
|
||||
|
|
||||
LL | let x = &mut s;
|
||||
| ------ borrow of `s` occurs here
|
||||
...
|
||||
LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
|
||||
| ^ use of borrowed `s`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-describe-lvalue.rs:228:28
|
||||
|
|
||||
|
@ -479,23 +329,12 @@ LL | v[0].y;
|
|||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `v` because it was mutably borrowed
|
||||
--> $DIR/borrowck-describe-lvalue.rs:282:15
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ borrow of `v` occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
| ^ use of borrowed `v`
|
||||
...
|
||||
LL | drop(x);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrowck-describe-lvalue.rs:283:24
|
||||
|
|
||||
LL | let x = &mut v;
|
||||
| ------ mutable borrow occurs here
|
||||
LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
LL | match v {
|
||||
LL | &[_, F {x: ref xf, ..}] => println!("{}", xf),
|
||||
| ^^^^^^ immutable borrow occurs here
|
||||
...
|
||||
|
@ -534,7 +373,7 @@ LL | drop(x); //[ast]~ ERROR use of moved value: `x`
|
|||
|
|
||||
= note: move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 46 previous errors
|
||||
error: aborting due to 32 previous errors
|
||||
|
||||
Some errors occurred: E0382, E0499, E0502, E0503.
|
||||
For more information about an error, try `rustc --explain E0382`.
|
||||
|
|
|
@ -74,7 +74,7 @@ fn main() {
|
|||
{
|
||||
let mut e = Baz::X(2);
|
||||
let x = e.x();
|
||||
match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
match e {
|
||||
Baz::X(value) => value
|
||||
//[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed
|
||||
//[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed
|
||||
|
@ -117,7 +117,7 @@ fn main() {
|
|||
{
|
||||
let mut e = Box::new(Baz::X(3));
|
||||
let x = e.x();
|
||||
match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed
|
||||
match *e {
|
||||
Baz::X(value) => value
|
||||
//[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed
|
||||
//[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed
|
||||
|
@ -136,25 +136,25 @@ fn main() {
|
|||
{
|
||||
let mut v = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
let x = &mut v;
|
||||
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
match v {
|
||||
&[x, _, .., _, _] => println!("{}", x),
|
||||
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
_ => panic!("other case"),
|
||||
}
|
||||
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
match v {
|
||||
&[_, x, .., _, _] => println!("{}", x),
|
||||
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
_ => panic!("other case"),
|
||||
}
|
||||
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
match v {
|
||||
&[_, _, .., x, _] => println!("{}", x),
|
||||
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
_ => panic!("other case"),
|
||||
}
|
||||
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
match v {
|
||||
&[_, _, .., _, x] => println!("{}", x),
|
||||
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
|
@ -166,25 +166,25 @@ fn main() {
|
|||
{
|
||||
let mut v = &[1, 2, 3, 4, 5];
|
||||
let x = &mut v;
|
||||
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
match v {
|
||||
&[x..] => println!("{:?}", x),
|
||||
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
_ => panic!("other case"),
|
||||
}
|
||||
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
match v {
|
||||
&[_, x..] => println!("{:?}", x),
|
||||
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
_ => panic!("other case"),
|
||||
}
|
||||
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
match v {
|
||||
&[x.., _] => println!("{:?}", x),
|
||||
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
_ => panic!("other case"),
|
||||
}
|
||||
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
match v {
|
||||
&[_, x.., _] => println!("{:?}", x),
|
||||
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
|
||||
|
@ -198,7 +198,7 @@ fn main() {
|
|||
|
||||
let mut e = E::A(3);
|
||||
let x = &mut e;
|
||||
match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
|
||||
match e {
|
||||
E::A(ref ax) =>
|
||||
//[ast]~^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable
|
||||
//[mir]~^^ ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable
|
||||
|
@ -217,14 +217,14 @@ fn main() {
|
|||
struct S { x: F, y: (u32, u32), };
|
||||
let mut s = S { x: F { x: 1, y: 2}, y: (999, 998) };
|
||||
let x = &mut s;
|
||||
match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
|
||||
match s {
|
||||
S { y: (ref y0, _), .. } =>
|
||||
//[ast]~^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable
|
||||
//[mir]~^^ ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable
|
||||
println!("y0: {:?}", y0),
|
||||
_ => panic!("other case"),
|
||||
}
|
||||
match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
|
||||
match s {
|
||||
S { x: F { y: ref x0, .. }, .. } =>
|
||||
//[ast]~^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable
|
||||
//[mir]~^^ ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable
|
||||
|
@ -279,7 +279,7 @@ fn main() {
|
|||
struct F {x: u32, y: u32};
|
||||
let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}];
|
||||
let x = &mut v;
|
||||
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
|
||||
match v {
|
||||
&[_, F {x: ref xf, ..}] => println!("{}", xf),
|
||||
//[mir]~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable
|
||||
// No errors in AST
|
||||
|
|
|
@ -1,20 +1,9 @@
|
|||
error[E0503]: cannot use `foo` because it was mutably borrowed
|
||||
--> $DIR/borrowck-match-already-borrowed.rs:22:19
|
||||
|
|
||||
LL | let p = &mut foo;
|
||||
| -------- borrow of `foo` occurs here
|
||||
LL | let _ = match foo { //[mir]~ ERROR [E0503]
|
||||
| ^^^ use of borrowed `foo`
|
||||
...
|
||||
LL | drop(p);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `foo` because it was mutably borrowed
|
||||
--> $DIR/borrowck-match-already-borrowed.rs:23:9
|
||||
|
|
||||
LL | let p = &mut foo;
|
||||
| -------- borrow of `foo` occurs here
|
||||
LL | let _ = match foo { //[mir]~ ERROR [E0503]
|
||||
LL | let _ = match foo {
|
||||
LL | Foo::B => 1, //[mir]~ ERROR [E0503]
|
||||
| ^^^^^^ use of borrowed `foo`
|
||||
...
|
||||
|
@ -33,23 +22,12 @@ LL | Foo::A(x) => x //[ast]~ ERROR [E0503]
|
|||
LL | drop(p);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `x` because it was mutably borrowed
|
||||
--> $DIR/borrowck-match-already-borrowed.rs:35:19
|
||||
|
|
||||
LL | let r = &mut x;
|
||||
| ------ borrow of `x` occurs here
|
||||
LL | let _ = match x { //[mir]~ ERROR [E0503]
|
||||
| ^ use of borrowed `x`
|
||||
...
|
||||
LL | drop(r);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `x` because it was mutably borrowed
|
||||
--> $DIR/borrowck-match-already-borrowed.rs:36:9
|
||||
|
|
||||
LL | let r = &mut x;
|
||||
| ------ borrow of `x` occurs here
|
||||
LL | let _ = match x { //[mir]~ ERROR [E0503]
|
||||
LL | let _ = match x {
|
||||
LL | x => x + 1, //[ast]~ ERROR [E0503]
|
||||
| ^ use of borrowed `x`
|
||||
...
|
||||
|
@ -68,6 +46,6 @@ LL | y => y + 2, //[ast]~ ERROR [E0503]
|
|||
LL | drop(r);
|
||||
| - borrow later used here
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0503`.
|
||||
|
|
|
@ -12,7 +12,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed
|
|||
|
|
||||
LL | let r = &mut x;
|
||||
| - borrow of `x` occurs here
|
||||
LL | let _ = match x { //[mir]~ ERROR [E0503]
|
||||
LL | let _ = match x {
|
||||
LL | x => x + 1, //[ast]~ ERROR [E0503]
|
||||
| ^ use of borrowed `x`
|
||||
|
||||
|
|
|
@ -1,20 +1,9 @@
|
|||
error[E0503]: cannot use `foo` because it was mutably borrowed
|
||||
--> $DIR/borrowck-match-already-borrowed.rs:22:19
|
||||
|
|
||||
LL | let p = &mut foo;
|
||||
| -------- borrow of `foo` occurs here
|
||||
LL | let _ = match foo { //[mir]~ ERROR [E0503]
|
||||
| ^^^ use of borrowed `foo`
|
||||
...
|
||||
LL | drop(p);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `foo` because it was mutably borrowed
|
||||
--> $DIR/borrowck-match-already-borrowed.rs:23:9
|
||||
|
|
||||
LL | let p = &mut foo;
|
||||
| -------- borrow of `foo` occurs here
|
||||
LL | let _ = match foo { //[mir]~ ERROR [E0503]
|
||||
LL | let _ = match foo {
|
||||
LL | Foo::B => 1, //[mir]~ ERROR [E0503]
|
||||
| ^^^^^^ use of borrowed `foo`
|
||||
...
|
||||
|
@ -33,23 +22,12 @@ LL | Foo::A(x) => x //[ast]~ ERROR [E0503]
|
|||
LL | drop(p);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `x` because it was mutably borrowed
|
||||
--> $DIR/borrowck-match-already-borrowed.rs:35:19
|
||||
|
|
||||
LL | let r = &mut x;
|
||||
| ------ borrow of `x` occurs here
|
||||
LL | let _ = match x { //[mir]~ ERROR [E0503]
|
||||
| ^ use of borrowed `x`
|
||||
...
|
||||
LL | drop(r);
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `x` because it was mutably borrowed
|
||||
--> $DIR/borrowck-match-already-borrowed.rs:36:9
|
||||
|
|
||||
LL | let r = &mut x;
|
||||
| ------ borrow of `x` occurs here
|
||||
LL | let _ = match x { //[mir]~ ERROR [E0503]
|
||||
LL | let _ = match x {
|
||||
LL | x => x + 1, //[ast]~ ERROR [E0503]
|
||||
| ^ use of borrowed `x`
|
||||
...
|
||||
|
@ -68,6 +46,6 @@ LL | y => y + 2, //[ast]~ ERROR [E0503]
|
|||
LL | drop(r);
|
||||
| - borrow later used here
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0503`.
|
||||
|
|
|
@ -19,7 +19,7 @@ enum Foo {
|
|||
fn match_enum() {
|
||||
let mut foo = Foo::B;
|
||||
let p = &mut foo;
|
||||
let _ = match foo { //[mir]~ ERROR [E0503]
|
||||
let _ = match foo {
|
||||
Foo::B => 1, //[mir]~ ERROR [E0503]
|
||||
_ => 2,
|
||||
Foo::A(x) => x //[ast]~ ERROR [E0503]
|
||||
|
@ -32,7 +32,7 @@ fn match_enum() {
|
|||
fn main() {
|
||||
let mut x = 1;
|
||||
let r = &mut x;
|
||||
let _ = match x { //[mir]~ ERROR [E0503]
|
||||
let _ = match x {
|
||||
x => x + 1, //[ast]~ ERROR [E0503]
|
||||
//[mir]~^ ERROR [E0503]
|
||||
y => y + 2, //[ast]~ ERROR [E0503]
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
warning: this constant cannot be used
|
||||
--> $DIR/conditional_array_execution.rs:15:1
|
||||
|
|
||||
LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
|
||||
| ^^^^^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| attempt to subtract with overflow
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/conditional_array_execution.rs:11:9
|
||||
|
|
||||
LL | #![warn(const_err)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0080]: referenced constant has errors
|
||||
--> $DIR/conditional_array_execution.rs:19:14
|
||||
|
|
||||
LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
|
||||
| ----- attempt to subtract with overflow
|
||||
...
|
||||
LL | println!("{}", FOO);
|
||||
| ^^^^
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/conditional_array_execution.rs:19:14
|
||||
|
|
||||
LL | println!("{}", FOO);
|
||||
| ^^^^ --- referenced constant has errors
|
||||
|
||||
error[E0080]: referenced constant has errors
|
||||
--> $DIR/conditional_array_execution.rs:19:20
|
||||
|
|
||||
LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
|
||||
| ----- attempt to subtract with overflow
|
||||
...
|
||||
LL | println!("{}", FOO);
|
||||
| ^^^
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/conditional_array_execution.rs:19:20
|
||||
|
|
||||
LL | println!("{}", FOO);
|
||||
| ^^^ referenced constant has errors
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
|
@ -1,70 +0,0 @@
|
|||
warning: this constant cannot be used
|
||||
--> $DIR/issue-43197.rs:20:5
|
||||
|
|
||||
LL | const X: u32 = 0-1;
|
||||
| ^^^^^^^^^^^^^^^---^
|
||||
| |
|
||||
| attempt to subtract with overflow
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/issue-43197.rs:11:9
|
||||
|
|
||||
LL | #![warn(const_err)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
warning: this constant cannot be used
|
||||
--> $DIR/issue-43197.rs:22:5
|
||||
|
|
||||
LL | const Y: u32 = foo(0-1);
|
||||
| ^^^^^^^^^^^^^^^^^^^---^^
|
||||
| |
|
||||
| attempt to subtract with overflow
|
||||
|
||||
error[E0080]: referenced constant has errors
|
||||
--> $DIR/issue-43197.rs:24:14
|
||||
|
|
||||
LL | const X: u32 = 0-1;
|
||||
| --- attempt to subtract with overflow
|
||||
...
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/issue-43197.rs:24:14
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^^^^^^^ - referenced constant has errors
|
||||
|
||||
error[E0080]: referenced constant has errors
|
||||
--> $DIR/issue-43197.rs:24:26
|
||||
|
|
||||
LL | const Y: u32 = foo(0-1);
|
||||
| --- attempt to subtract with overflow
|
||||
LL | //~^ WARN this constant cannot be used
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/issue-43197.rs:24:26
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error[E0080]: referenced constant has errors
|
||||
--> $DIR/issue-43197.rs:24:23
|
||||
|
|
||||
LL | const X: u32 = 0-1;
|
||||
| --- attempt to subtract with overflow
|
||||
...
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/issue-43197.rs:24:23
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
|
@ -1,33 +0,0 @@
|
|||
error[E0080]: referenced constant has errors
|
||||
--> $DIR/issue-44578.rs:35:14
|
||||
|
|
||||
LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
|
||||
| ------------------------------------ index out of bounds: the len is 1 but the index is 1
|
||||
...
|
||||
LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
|
||||
| ^^^^
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/issue-44578.rs:35:14
|
||||
|
|
||||
LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
|
||||
| ^^^^ -------------------------- referenced constant has errors
|
||||
|
||||
error[E0080]: referenced constant has errors
|
||||
--> $DIR/issue-44578.rs:35:20
|
||||
|
|
||||
LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
|
||||
| ------------------------------------ index out of bounds: the len is 1 but the index is 1
|
||||
...
|
||||
LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/issue-44578.rs:35:20
|
||||
|
|
||||
LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
|
@ -24,7 +24,6 @@ fn main() {
|
|||
match b {
|
||||
&mut false => {},
|
||||
_ if { (|| { let bar = b; *bar = false; })();
|
||||
//~^ ERROR cannot move out of `b` because it is borrowed [E0505]
|
||||
false } => { },
|
||||
&mut true => { println!("You might think we should get here"); },
|
||||
//~^ ERROR use of moved value: `*b` [E0382]
|
||||
|
|
|
@ -1,29 +1,14 @@
|
|||
error[E0505]: cannot move out of `b` because it is borrowed
|
||||
--> $DIR/issue-27282-move-match-input-into-guard.rs:26:17
|
||||
|
|
||||
LL | match b {
|
||||
| - borrow of `b` occurs here
|
||||
LL | &mut false => {},
|
||||
LL | _ if { (|| { let bar = b; *bar = false; })();
|
||||
| ^^ - move occurs due to use in closure
|
||||
| |
|
||||
| move out of `b` occurs here
|
||||
...
|
||||
LL | &mut true => { println!("You might think we should get here"); },
|
||||
| --------- borrow later used here
|
||||
|
||||
error[E0382]: use of moved value: `*b`
|
||||
--> $DIR/issue-27282-move-match-input-into-guard.rs:29:14
|
||||
--> $DIR/issue-27282-move-match-input-into-guard.rs:28:14
|
||||
|
|
||||
LL | _ if { (|| { let bar = b; *bar = false; })();
|
||||
| -- - variable moved due to use in closure
|
||||
| |
|
||||
| value moved into closure here
|
||||
...
|
||||
LL | false } => { },
|
||||
LL | &mut true => { println!("You might think we should get here"); },
|
||||
| ^^^^ value used here after move
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
Some errors occurred: E0382, E0505.
|
||||
For more information about an error, try `rustc --explain E0382`.
|
||||
For more information about this error, try `rustc --explain E0382`.
|
||||
|
|
|
@ -31,7 +31,7 @@ fn main() {
|
|||
&mut Some(&_) if {
|
||||
// ForceFnOnce needed to exploit #27282
|
||||
(|| { *x = None; drop(force_fn_once); })();
|
||||
//~^ ERROR closure requires unique access to `x` but it is already borrowed [E0500]
|
||||
//~^ ERROR cannot mutably borrow `x` in match guard [E0510]
|
||||
false
|
||||
} => {}
|
||||
&mut Some(&a) if { // this binds to garbage if we've corrupted discriminant
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
error[E0500]: closure requires unique access to `x` but it is already borrowed
|
||||
error[E0510]: cannot mutably borrow `x` in match guard
|
||||
--> $DIR/issue-27282-mutate-before-diverging-arm-1.rs:33:14
|
||||
|
|
||||
LL | match x {
|
||||
| - borrow occurs here
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | (|| { *x = None; drop(force_fn_once); })();
|
||||
| ^^ - second borrow occurs due to use of `x` in closure
|
||||
| ^^ - borrow occurs due to use of `x` in closure
|
||||
| |
|
||||
| closure construction occurs here
|
||||
...
|
||||
LL | &mut Some(&a) if { // this binds to garbage if we've corrupted discriminant
|
||||
| ------------- borrow later used here
|
||||
| cannot mutably borrow
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0500`.
|
||||
For more information about this error, try `rustc --explain E0510`.
|
||||
|
|
|
@ -36,7 +36,7 @@ fn main() {
|
|||
if {
|
||||
// ForceFnOnce needed to exploit #27282
|
||||
(|| { *x = None; drop(force_fn_once); })();
|
||||
//~^ ERROR closure requires unique access to `x` but it is already borrowed [E0500]
|
||||
//~^ ERROR cannot mutably borrow `x` in match guard [E0510]
|
||||
false
|
||||
} => {}
|
||||
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
error[E0500]: closure requires unique access to `x` but it is already borrowed
|
||||
error[E0510]: cannot mutably borrow `x` in match guard
|
||||
--> $DIR/issue-27282-mutate-before-diverging-arm-2.rs:38:18
|
||||
|
|
||||
LL | match x {
|
||||
| - borrow occurs here
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | (|| { *x = None; drop(force_fn_once); })();
|
||||
| ^^ - second borrow occurs due to use of `x` in closure
|
||||
| ^^ - borrow occurs due to use of `x` in closure
|
||||
| |
|
||||
| closure construction occurs here
|
||||
...
|
||||
LL | &mut Some(&2)
|
||||
| ------------- borrow later used here
|
||||
| cannot mutably borrow
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0500`.
|
||||
For more information about this error, try `rustc --explain E0510`.
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// This is testing an attempt to corrupt the discriminant of the match
|
||||
// arm in a guard, followed by an attempt to continue matching on that
|
||||
// corrupted discriminant in the remaining match arms.
|
||||
//
|
||||
// Basically this is testing that our new NLL feature of emitting a
|
||||
// fake read on each match arm is catching cases like this.
|
||||
//
|
||||
// This case is interesting because a borrow of **x is untracked, because **x is
|
||||
// immutable. However, for matches we care that **x refers to the same value
|
||||
// until we have chosen a match arm.
|
||||
#![feature(nll)]
|
||||
struct ForceFnOnce;
|
||||
fn main() {
|
||||
let mut x = &mut &Some(&2);
|
||||
let force_fn_once = ForceFnOnce;
|
||||
match **x {
|
||||
None => panic!("unreachable"),
|
||||
Some(&_) if {
|
||||
// ForceFnOnce needed to exploit #27282
|
||||
(|| { *x = &None; drop(force_fn_once); })();
|
||||
//~^ ERROR cannot mutably borrow `x` in match guard [E0510]
|
||||
false
|
||||
} => {}
|
||||
Some(&a) if { // this binds to garbage if we've corrupted discriminant
|
||||
println!("{}", a);
|
||||
panic!()
|
||||
} => {}
|
||||
_ => panic!("unreachable"),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
error[E0510]: cannot mutably borrow `x` in match guard
|
||||
--> $DIR/issue-27282-mutate-before-diverging-arm-3.rs:20:14
|
||||
|
|
||||
LL | match **x {
|
||||
| --- value is immutable in match guard
|
||||
...
|
||||
LL | (|| { *x = &None; drop(force_fn_once); })();
|
||||
| ^^ - borrow occurs due to use of `x` in closure
|
||||
| |
|
||||
| cannot mutably borrow
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0510`.
|
|
@ -21,7 +21,7 @@ fn main() {
|
|||
let mut e = Xyz::A;
|
||||
let f = &mut e;
|
||||
let g = f;
|
||||
match e { //~ cannot use `e` because it was mutably borrowed [E0503]
|
||||
match e {
|
||||
Xyz::A => println!("a"),
|
||||
//~^ cannot use `e` because it was mutably borrowed [E0503]
|
||||
Xyz::B => println!("b"),
|
||||
|
|
|
@ -1,15 +1,3 @@
|
|||
error[E0503]: cannot use `e` because it was mutably borrowed
|
||||
--> $DIR/borrowed-match-issue-45045.rs:24:11
|
||||
|
|
||||
LL | let f = &mut e;
|
||||
| ------ borrow of `e` occurs here
|
||||
LL | let g = f;
|
||||
LL | match e { //~ cannot use `e` because it was mutably borrowed [E0503]
|
||||
| ^ use of borrowed `e`
|
||||
...
|
||||
LL | *g = Xyz::B;
|
||||
| ----------- borrow later used here
|
||||
|
||||
error[E0503]: cannot use `e` because it was mutably borrowed
|
||||
--> $DIR/borrowed-match-issue-45045.rs:25:9
|
||||
|
|
||||
|
@ -22,6 +10,6 @@ LL | Xyz::A => println!("a"),
|
|||
LL | *g = Xyz::B;
|
||||
| ----------- borrow later used here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0503`.
|
||||
|
|
164
src/test/ui/nll/match-guards-partially-borrow.rs
Normal file
164
src/test/ui/nll/match-guards-partially-borrow.rs
Normal file
|
@ -0,0 +1,164 @@
|
|||
// Test that a (partially) mutably borrowed place can be matched on, so long as
|
||||
// we don't have to read any values that are mutably borrowed to determine
|
||||
// which arm to take.
|
||||
//
|
||||
// Test that we don't allow mutating the value being matched on in a way that
|
||||
// changes which patterns it matches, until we have chosen an arm.
|
||||
|
||||
// compile-flags: -Zdisable-ast-check-for-mutation-in-guard
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
fn ok_mutation_in_guard(mut q: i32) {
|
||||
match q {
|
||||
// OK, mutation doesn't change which patterns g matches
|
||||
_ if { q = 1; false } => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn ok_indirect_mutation_in_guard(mut p: &bool) {
|
||||
match *p {
|
||||
// OK, mutation doesn't change which patterns s matches
|
||||
_ if {
|
||||
p = &true;
|
||||
false
|
||||
} => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn mutation_invalidates_pattern_in_guard(mut q: bool) {
|
||||
match q {
|
||||
// s doesn't match the pattern with the guard by the end of the guard.
|
||||
false if {
|
||||
q = true; //~ ERROR
|
||||
true
|
||||
} => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) {
|
||||
match r {
|
||||
// s matches a previous pattern by the end of the guard.
|
||||
true => (),
|
||||
_ if {
|
||||
r = true; //~ ERROR
|
||||
true
|
||||
} => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn match_on_borrowed_early_end(mut s: bool) {
|
||||
let h = &mut s;
|
||||
match s { //~ ERROR
|
||||
// s changes value between the start of the match and when its value is checked.
|
||||
_ if {
|
||||
*h = !*h;
|
||||
false
|
||||
} => (),
|
||||
true => (),
|
||||
false => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_mutation_in_guard(mut t: bool) {
|
||||
match t {
|
||||
true => (),
|
||||
false if {
|
||||
t = true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
false => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_mutation_in_guard2(mut u: bool) {
|
||||
match u {
|
||||
// Guard changes the value bound in the last pattern.
|
||||
_ => (),
|
||||
_ if {
|
||||
u = true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
x => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bad_mutation_in_guard3(mut x: Option<Option<&i32>>) {
|
||||
// Check that nested patterns are checked.
|
||||
match x {
|
||||
None => (),
|
||||
Some(None) => (),
|
||||
_ if {
|
||||
match x {
|
||||
Some(ref mut r) => *r = None, //~ ERROR
|
||||
_ => return,
|
||||
};
|
||||
false
|
||||
} => (),
|
||||
Some(Some(r)) => println!("{}", r),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn bad_mutation_in_guard4(mut w: (&mut bool,)) {
|
||||
match w {
|
||||
// Guard changes the value bound in the last pattern.
|
||||
_ => (),
|
||||
_ if {
|
||||
*w.0 = true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
x => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_indirect_mutation_in_guard(mut y: &bool) {
|
||||
match *y {
|
||||
true => (),
|
||||
false if {
|
||||
y = &true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
false => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_indirect_mutation_in_guard2(mut z: &bool) {
|
||||
match z {
|
||||
&true => (),
|
||||
&false if {
|
||||
z = &true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
&false => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_indirect_mutation_in_guard3(mut a: &bool) {
|
||||
// Same as bad_indirect_mutation_in_guard2, but using match ergonomics
|
||||
match a {
|
||||
true => (),
|
||||
false if {
|
||||
a = &true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
false => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_indirect_mutation_in_guard4(mut b: &bool) {
|
||||
match b {
|
||||
&_ => (),
|
||||
&_ if {
|
||||
b = &true; //~ ERROR
|
||||
false
|
||||
} => (),
|
||||
&b => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
132
src/test/ui/nll/match-guards-partially-borrow.stderr
Normal file
132
src/test/ui/nll/match-guards-partially-borrow.stderr
Normal file
|
@ -0,0 +1,132 @@
|
|||
error[E0510]: cannot assign `q` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:35:13
|
||||
|
|
||||
LL | match q {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | q = true; //~ ERROR
|
||||
| ^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | _ => (),
|
||||
| - borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `r` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:47:13
|
||||
|
|
||||
LL | match r {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | r = true; //~ ERROR
|
||||
| ^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | _ => (),
|
||||
| - borrow later used here
|
||||
|
||||
error[E0503]: cannot use `s` because it was mutably borrowed
|
||||
--> $DIR/match-guards-partially-borrow.rs:56:11
|
||||
|
|
||||
LL | let h = &mut s;
|
||||
| ------ borrow of `s` occurs here
|
||||
LL | match s { //~ ERROR
|
||||
| ^ use of borrowed `s`
|
||||
...
|
||||
LL | *h = !*h;
|
||||
| -- borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `t` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:71:13
|
||||
|
|
||||
LL | match t {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | t = true; //~ ERROR
|
||||
| ^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | false => (),
|
||||
| ----- borrow later used here
|
||||
|
||||
error[E0506]: cannot assign to `u` because it is borrowed
|
||||
--> $DIR/match-guards-partially-borrow.rs:83:13
|
||||
|
|
||||
LL | match u {
|
||||
| - borrow of `u` occurs here
|
||||
...
|
||||
LL | u = true; //~ ERROR
|
||||
| ^^^^^^^^ assignment to borrowed `u` occurs here
|
||||
...
|
||||
LL | x => (),
|
||||
| - borrow later used here
|
||||
|
||||
error[E0510]: cannot mutably borrow `x.0` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:97:22
|
||||
|
|
||||
LL | match x {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | Some(ref mut r) => *r = None, //~ ERROR
|
||||
| ^^^^^^^^^ cannot mutably borrow
|
||||
|
||||
error[E0506]: cannot assign to `*w.0` because it is borrowed
|
||||
--> $DIR/match-guards-partially-borrow.rs:112:13
|
||||
|
|
||||
LL | match w {
|
||||
| - borrow of `*w.0` occurs here
|
||||
...
|
||||
LL | *w.0 = true; //~ ERROR
|
||||
| ^^^^^^^^^^^ assignment to borrowed `*w.0` occurs here
|
||||
...
|
||||
LL | x => (),
|
||||
| - borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `y` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:123:13
|
||||
|
|
||||
LL | match *y {
|
||||
| -- value is immutable in match guard
|
||||
...
|
||||
LL | y = &true; //~ ERROR
|
||||
| ^^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | false => (),
|
||||
| ----- borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `z` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:134:13
|
||||
|
|
||||
LL | match z {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | z = &true; //~ ERROR
|
||||
| ^^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | &false => (),
|
||||
| ------ borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `a` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:146:13
|
||||
|
|
||||
LL | match a {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | a = &true; //~ ERROR
|
||||
| ^^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | false => (),
|
||||
| ----- borrow later used here
|
||||
|
||||
error[E0510]: cannot assign `b` in match guard
|
||||
--> $DIR/match-guards-partially-borrow.rs:157:13
|
||||
|
|
||||
LL | match b {
|
||||
| - value is immutable in match guard
|
||||
...
|
||||
LL | b = &true; //~ ERROR
|
||||
| ^^^^^^^^^ cannot assign
|
||||
...
|
||||
LL | &b => (),
|
||||
| -- borrow later used here
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
Some errors occurred: E0503, E0506, E0510.
|
||||
For more information about an error, try `rustc --explain E0503`.
|
95
src/test/ui/nll/match-on-borrowed.rs
Normal file
95
src/test/ui/nll/match-on-borrowed.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Test that a (partially) mutably borrowed place can be matched on, so long as
|
||||
// we don't have to read any values that are mutably borrowed to determine
|
||||
// which arm to take.
|
||||
//
|
||||
// Test that we don't allow mutating the value being matched on in a way that
|
||||
// changes which patterns it matches, until we have chosen an arm.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
struct A(i32, i32);
|
||||
|
||||
fn struct_example(mut a: A) {
|
||||
let x = &mut a.0;
|
||||
match a { // OK, no access of borrowed data
|
||||
_ if false => (),
|
||||
A(_, r) => (),
|
||||
}
|
||||
x;
|
||||
}
|
||||
|
||||
fn indirect_struct_example(mut b: &mut A) {
|
||||
let x = &mut b.0;
|
||||
match *b { // OK, no access of borrowed data
|
||||
_ if false => (),
|
||||
A(_, r) => (),
|
||||
}
|
||||
x;
|
||||
}
|
||||
|
||||
fn underscore_example(mut c: i32) {
|
||||
let r = &mut c;
|
||||
match c { // OK, no access of borrowed data (or any data at all)
|
||||
_ if false => (),
|
||||
_ => (),
|
||||
}
|
||||
r;
|
||||
}
|
||||
|
||||
enum E {
|
||||
V(i32, i32),
|
||||
W,
|
||||
}
|
||||
|
||||
fn enum_example(mut e: E) {
|
||||
let x = match e {
|
||||
E::V(ref mut x, _) => x,
|
||||
E::W => panic!(),
|
||||
};
|
||||
match e { // OK, no access of borrowed data
|
||||
_ if false => (),
|
||||
E::V(_, r) => (),
|
||||
E::W => (),
|
||||
}
|
||||
x;
|
||||
}
|
||||
|
||||
fn indirect_enum_example(mut f: &mut E) {
|
||||
let x = match *f {
|
||||
E::V(ref mut x, _) => x,
|
||||
E::W => panic!(),
|
||||
};
|
||||
match f { // OK, no access of borrowed data
|
||||
_ if false => (),
|
||||
E::V(_, r) => (),
|
||||
E::W => (),
|
||||
}
|
||||
x;
|
||||
}
|
||||
|
||||
fn match_on_muatbly_borrowed_ref(mut p: &bool) {
|
||||
let r = &mut p;
|
||||
match *p { // OK, no access at all
|
||||
_ if false => (),
|
||||
_ => (),
|
||||
}
|
||||
r;
|
||||
}
|
||||
|
||||
fn match_on_borrowed(mut t: bool) {
|
||||
let x = &mut t;
|
||||
match t {
|
||||
true => (), //~ ERROR
|
||||
false => (),
|
||||
}
|
||||
x;
|
||||
}
|
||||
|
||||
enum Never {}
|
||||
|
||||
fn never_init() {
|
||||
let n: Never;
|
||||
match n {} //~ ERROR
|
||||
}
|
||||
|
||||
fn main() {}
|
22
src/test/ui/nll/match-on-borrowed.stderr
Normal file
22
src/test/ui/nll/match-on-borrowed.stderr
Normal file
|
@ -0,0 +1,22 @@
|
|||
error[E0503]: cannot use `t` because it was mutably borrowed
|
||||
--> $DIR/match-on-borrowed.rs:82:9
|
||||
|
|
||||
LL | let x = &mut t;
|
||||
| ------ borrow of `t` occurs here
|
||||
LL | match t {
|
||||
LL | true => (), //~ ERROR
|
||||
| ^^^^ use of borrowed `t`
|
||||
...
|
||||
LL | x;
|
||||
| - borrow later used here
|
||||
|
||||
error[E0381]: use of possibly uninitialized variable: `n`
|
||||
--> $DIR/match-on-borrowed.rs:92:11
|
||||
|
|
||||
LL | match n {} //~ ERROR
|
||||
| ^ use of possibly uninitialized `n`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors occurred: E0381, E0503.
|
||||
For more information about an error, try `rustc --explain E0381`.
|
Loading…
Add table
Add a link
Reference in a new issue