E4007
E4007 — A value moved while a borrow of it is still used afterwards:let r = &a; let b = a;followed by a use ofr. The borrow would point at a value that has moved away.
What the compiler reports
Error[E4007] at 96:11: `a` is moved while it is borrowed, and the borrow is used after the move
Error[E4008] at 105:11: this moves a value of type `S` out from behind a reference
7 error(s) emitted
The fragments the test suite holds the compiler to. An ellipsis marks text the test does not constrain; the emitted message also carries a source location.
A program that triggers it
//
// Part of the Vx Project, under the Apache License v2.0 with LLVM Exceptions.
// See LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// `S` is not `Copy`. A value moved inside a loop is used again on the next pass unless it is
// given a new value first (E4001, at the loop); a `continue` goes round again too, and a
// `break` carries the move out of the loop. A move in one `match` arm counts after the
// `match`. A value cannot move while a borrow of it is still used (E4007), and a reference
// cannot give away what it points at (E4008).
struct S {
v : i64,
}
fn take(s : S) -> i64 {
return s.v;
}
fn moved_in_a_while(n : i32) -> i32 {
let a = S {
v : 1i64
};
let mut i = 0;
while i < n {
take(a);
i = i + 1;
}
return 0;
}
fn moved_then_continue(n : i32) -> i32 {
let a = S {
v : 1i64
};
let mut i = 0;
while i < n {
i = i + 1;
if i == 2 {
take(a);
continue;
}
}
return 0;
}
fn moved_in_a_for(n : i32) -> i32 {
let a = S {
v : 1i64
};
for i in 0..n {
take(a);
}
return 0;
}
fn used_after_a_loop_that_moved_it(n : i32) -> i64 {
let a = S {
v : 1i64
};
let mut i = 0;
while i < n {
if i == 2 {
take(a);
break;
}
i = i + 1;
}
return take(a);
}
fn used_after_a_match_arm_moved_it(n : i32) -> i64 {
let a = S {
v : 1i64
};
match n {
0 => {
take(a);
}
_ => {
print(1);
}
}
return take(a);
}
fn moved_while_borrowed() -> i64 {
let a = S {
v : 1i64
};
let r = &a;
let b = a;
return r.v + take(b);
}
fn moved_out_of_a_reference() -> i64 {
let a = S {
v : 1i64
};
let r = &a;
let b = *r;
return take(b);
}
fn main() -> i32 {
return 0;
}
From tests/frontend/fail/moves_in_loops_and_under_borrows.vx, which asserts this diagnostic on every commit.
Related
Ownership and borrowingThe chapter covering the rule this code enforces.
All diagnosticsEvery code the compiler can emit, grouped by stage.
E4006An assignment through a shared reference:
*r = v, r.f = v or r[i] = v where r is a &T. A shared reference only reads; writing needs a &mut T.
E4008A value moved out from behind a reference: let b = *r; where r is a reference to a type that is not Copy. The reference does not own the value, so it cannot give it away; copy or clone it instead.