Auto merge of #57888 - Centril:rollup, r=Centril
Rollup of 5 pull requests Successful merges: - #56217 (Add grammar in docs for {f32,f64}::from_str, mention known bug.) - #57294 (When using value after move, point at span of local) - #57652 (Update/remove some old readmes) - #57802 (Print visible name for types as well as modules.) - #57865 (Don't ICE when logging unusual types) Failed merges: r? @ghost
This commit is contained in:
commit
a41ade7bc3
@ -8,7 +8,6 @@ For more information on how various parts of the compiler work, see the [rustc g
|
||||
There is also useful content in the following READMEs, which are gradually being moved over to the guide:
|
||||
- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/query
|
||||
- https://github.com/rust-lang/rust/tree/master/src/librustc/dep_graph
|
||||
- https://github.com/rust-lang/rust/blob/master/src/librustc/infer/region_constraints
|
||||
- https://github.com/rust-lang/rust/tree/master/src/librustc/infer/higher_ranked
|
||||
- https://github.com/rust-lang/rust/tree/master/src/librustc/infer/lexical_region_resolve
|
||||
|
||||
|
@ -112,11 +112,35 @@ macro_rules! from_str_float_impl {
|
||||
/// * '2.5E10', or equivalently, '2.5e10'
|
||||
/// * '2.5E-10'
|
||||
/// * '5.'
|
||||
/// * '.5', or, equivalently, '0.5'
|
||||
/// * '.5', or, equivalently, '0.5'
|
||||
/// * 'inf', '-inf', 'NaN'
|
||||
///
|
||||
/// Leading and trailing whitespace represent an error.
|
||||
///
|
||||
/// # Grammar
|
||||
///
|
||||
/// All strings that adhere to the following [EBNF] grammar
|
||||
/// will result in an [`Ok`] being returned:
|
||||
///
|
||||
/// ```txt
|
||||
/// Float ::= Sign? ( 'inf' | 'NaN' | Number )
|
||||
/// Number ::= ( Digit+ |
|
||||
/// Digit+ '.' Digit* |
|
||||
/// Digit* '.' Digit+ ) Exp?
|
||||
/// Exp ::= [eE] Sign? Digit+
|
||||
/// Sign ::= [+-]
|
||||
/// Digit ::= [0-9]
|
||||
/// ```
|
||||
///
|
||||
/// [EBNF]: https://www.w3.org/TR/REC-xml/#sec-notation
|
||||
///
|
||||
/// # Known bugs
|
||||
///
|
||||
/// In some situations, some strings that should create a valid float
|
||||
/// instead return an error. See [issue #31407] for details.
|
||||
///
|
||||
/// [issue #31407]: https://github.com/rust-lang/rust/issues/31407
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * src - A string
|
||||
|
@ -1,403 +1,8 @@
|
||||
# Skolemization and functions
|
||||
To learn more about how Higher-ranked trait bounds work in the _old_ trait
|
||||
solver, see [this chapter][oldhrtb] of the rustc-guide.
|
||||
|
||||
One of the trickiest and most subtle aspects of regions is dealing
|
||||
with higher-ranked things which include bound region variables, such
|
||||
as function types. I strongly suggest that if you want to understand
|
||||
the situation, you read this paper (which is, admittedly, very long,
|
||||
but you don't have to read the whole thing):
|
||||
To learn more about how they work in the _new_ trait solver, see [this
|
||||
chapter][newhrtb].
|
||||
|
||||
http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/
|
||||
|
||||
Although my explanation will never compete with SPJ's (for one thing,
|
||||
his is approximately 100 pages), I will attempt to explain the basic
|
||||
problem and also how we solve it. Note that the paper only discusses
|
||||
subtyping, not the computation of LUB/GLB.
|
||||
|
||||
The problem we are addressing is that there is a kind of subtyping
|
||||
between functions with bound region parameters. Consider, for
|
||||
example, whether the following relation holds:
|
||||
|
||||
for<'a> fn(&'a isize) <: for<'b> fn(&'b isize)? (Yes, a => b)
|
||||
|
||||
The answer is that of course it does. These two types are basically
|
||||
the same, except that in one we used the name `a` and one we used
|
||||
the name `b`.
|
||||
|
||||
In the examples that follow, it becomes very important to know whether
|
||||
a lifetime is bound in a function type (that is, is a lifetime
|
||||
parameter) or appears free (is defined in some outer scope).
|
||||
Therefore, from now on I will always write the bindings explicitly,
|
||||
using the Rust syntax `for<'a> fn(&'a isize)` to indicate that `a` is a
|
||||
lifetime parameter.
|
||||
|
||||
Now let's consider two more function types. Here, we assume that the
|
||||
`'b` lifetime is defined somewhere outside and hence is not a lifetime
|
||||
parameter bound by the function type (it "appears free"):
|
||||
|
||||
for<'a> fn(&'a isize) <: fn(&'b isize)? (Yes, a => b)
|
||||
|
||||
This subtyping relation does in fact hold. To see why, you have to
|
||||
consider what subtyping means. One way to look at `T1 <: T2` is to
|
||||
say that it means that it is always ok to treat an instance of `T1` as
|
||||
if it had the type `T2`. So, with our functions, it is always ok to
|
||||
treat a function that can take pointers with any lifetime as if it
|
||||
were a function that can only take a pointer with the specific
|
||||
lifetime `'b`. After all, `'b` is a lifetime, after all, and
|
||||
the function can take values of any lifetime.
|
||||
|
||||
You can also look at subtyping as the *is a* relationship. This amounts
|
||||
to the same thing: a function that accepts pointers with any lifetime
|
||||
*is a* function that accepts pointers with some specific lifetime.
|
||||
|
||||
So, what if we reverse the order of the two function types, like this:
|
||||
|
||||
fn(&'b isize) <: for<'a> fn(&'a isize)? (No)
|
||||
|
||||
Does the subtyping relationship still hold? The answer of course is
|
||||
no. In this case, the function accepts *only the lifetime `'b`*,
|
||||
so it is not reasonable to treat it as if it were a function that
|
||||
accepted any lifetime.
|
||||
|
||||
What about these two examples:
|
||||
|
||||
for<'a,'b> fn(&'a isize, &'b isize) <: for<'a> fn(&'a isize, &'a isize)? (Yes)
|
||||
for<'a> fn(&'a isize, &'a isize) <: for<'a,'b> fn(&'a isize, &'b isize)? (No)
|
||||
|
||||
Here, it is true that functions which take two pointers with any two
|
||||
lifetimes can be treated as if they only accepted two pointers with
|
||||
the same lifetime, but not the reverse.
|
||||
|
||||
## The algorithm
|
||||
|
||||
Here is the algorithm we use to perform the subtyping check:
|
||||
|
||||
1. Replace all bound regions in the subtype with new variables
|
||||
2. Replace all bound regions in the supertype with placeholder
|
||||
equivalents. A "placeholder" region is just a new fresh region
|
||||
name.
|
||||
3. Check that the parameter and return types match as normal
|
||||
4. Ensure that no placeholder regions 'leak' into region variables
|
||||
visible from "the outside"
|
||||
|
||||
Let's walk through some examples and see how this algorithm plays out.
|
||||
|
||||
#### First example
|
||||
|
||||
We'll start with the first example, which was:
|
||||
|
||||
1. for<'a> fn(&'a T) <: for<'b> fn(&'b T)? Yes: a -> b
|
||||
|
||||
After steps 1 and 2 of the algorithm we will have replaced the types
|
||||
like so:
|
||||
|
||||
1. fn(&'A T) <: fn(&'x T)?
|
||||
|
||||
Here the upper case `&A` indicates a *region variable*, that is, a
|
||||
region whose value is being inferred by the system. I also replaced
|
||||
`&b` with `&x`---I'll use letters late in the alphabet (`x`, `y`, `z`)
|
||||
to indicate placeholder region names. We can assume they don't appear
|
||||
elsewhere. Note that neither the sub- nor the supertype bind any
|
||||
region names anymore (as indicated by the absence of `<` and `>`).
|
||||
|
||||
The next step is to check that the parameter types match. Because
|
||||
parameters are contravariant, this means that we check whether:
|
||||
|
||||
&'x T <: &'A T
|
||||
|
||||
Region pointers are contravariant so this implies that
|
||||
|
||||
&A <= &x
|
||||
|
||||
must hold, where `<=` is the subregion relationship. Processing
|
||||
*this* constrain simply adds a constraint into our graph that `&A <=
|
||||
&x` and is considered successful (it can, for example, be satisfied by
|
||||
choosing the value `&x` for `&A`).
|
||||
|
||||
So far we have encountered no error, so the subtype check succeeds.
|
||||
|
||||
#### The third example
|
||||
|
||||
Now let's look first at the third example, which was:
|
||||
|
||||
3. fn(&'a T) <: for<'b> fn(&'b T)? No!
|
||||
|
||||
After steps 1 and 2 of the algorithm we will have replaced the types
|
||||
like so:
|
||||
|
||||
3. fn(&'a T) <: fn(&'x T)?
|
||||
|
||||
This looks pretty much the same as before, except that on the LHS
|
||||
`'a` was not bound, and hence was left as-is and not replaced with
|
||||
a variable. The next step is again to check that the parameter types
|
||||
match. This will ultimately require (as before) that `'a` <= `&x`
|
||||
must hold: but this does not hold. `self` and `x` are both distinct
|
||||
free regions. So the subtype check fails.
|
||||
|
||||
#### Checking for placeholder leaks
|
||||
|
||||
You may be wondering about that mysterious last step in the algorithm.
|
||||
So far it has not been relevant. The purpose of that last step is to
|
||||
catch something like *this*:
|
||||
|
||||
for<'a> fn() -> fn(&'a T) <: fn() -> for<'b> fn(&'b T)? No.
|
||||
|
||||
Here the function types are the same but for where the binding occurs.
|
||||
The subtype returns a function that expects a value in precisely one
|
||||
region. The supertype returns a function that expects a value in any
|
||||
region. If we allow an instance of the subtype to be used where the
|
||||
supertype is expected, then, someone could call the fn and think that
|
||||
the return value has type `fn<b>(&'b T)` when it really has type
|
||||
`fn(&'a T)` (this is case #3, above). Bad.
|
||||
|
||||
So let's step through what happens when we perform this subtype check.
|
||||
We first replace the bound regions in the subtype (the supertype has
|
||||
no bound regions). This gives us:
|
||||
|
||||
fn() -> fn(&'A T) <: fn() -> for<'b> fn(&'b T)?
|
||||
|
||||
Now we compare the return types, which are covariant, and hence we have:
|
||||
|
||||
fn(&'A T) <: for<'b> fn(&'b T)?
|
||||
|
||||
Here we replace the bound region in the supertype with a placeholder to yield:
|
||||
|
||||
fn(&'A T) <: fn(&'x T)?
|
||||
|
||||
And then proceed to compare the argument types:
|
||||
|
||||
&'x T <: &'A T
|
||||
'A <= 'x
|
||||
|
||||
Finally, this is where it gets interesting! This is where an error
|
||||
*should* be reported. But in fact this will not happen. The reason why
|
||||
is that `A` is a variable: we will infer that its value is the fresh
|
||||
region `x` and think that everything is happy. In fact, this behavior
|
||||
is *necessary*, it was key to the first example we walked through.
|
||||
|
||||
The difference between this example and the first one is that the variable
|
||||
`A` already existed at the point where the placeholders were added. In
|
||||
the first example, you had two functions:
|
||||
|
||||
for<'a> fn(&'a T) <: for<'b> fn(&'b T)
|
||||
|
||||
and hence `&A` and `&x` were created "together". In general, the
|
||||
intention of the placeholder names is that they are supposed to be
|
||||
fresh names that could never be equal to anything from the outside.
|
||||
But when inference comes into play, we might not be respecting this
|
||||
rule.
|
||||
|
||||
So the way we solve this is to add a fourth step that examines the
|
||||
constraints that refer to placeholder names. Basically, consider a
|
||||
non-directed version of the constraint graph. Let `Tainted(x)` be the
|
||||
set of all things reachable from a placeholder variable `x`.
|
||||
`Tainted(x)` should not contain any regions that existed before the
|
||||
step at which the placeholders were created. So this case here
|
||||
would fail because `&x` was created alone, but is relatable to `&A`.
|
||||
|
||||
## Computing the LUB and GLB
|
||||
|
||||
The paper I pointed you at is written for Haskell. It does not
|
||||
therefore considering subtyping and in particular does not consider
|
||||
LUB or GLB computation. We have to consider this. Here is the
|
||||
algorithm I implemented.
|
||||
|
||||
First though, let's discuss what we are trying to compute in more
|
||||
detail. The LUB is basically the "common supertype" and the GLB is
|
||||
"common subtype"; one catch is that the LUB should be the
|
||||
*most-specific* common supertype and the GLB should be *most general*
|
||||
common subtype (as opposed to any common supertype or any common
|
||||
subtype).
|
||||
|
||||
Anyway, to help clarify, here is a table containing some function
|
||||
pairs and their LUB/GLB (for conciseness, in this table, I'm just
|
||||
including the lifetimes here, not the rest of the types, and I'm
|
||||
writing `fn<>` instead of `for<> fn`):
|
||||
|
||||
```
|
||||
Type 1 Type 2 LUB GLB
|
||||
fn<'a>('a) fn('X) fn('X) fn<'a>('a)
|
||||
fn('a) fn('X) -- fn<'a>('a)
|
||||
fn<'a,'b>('a, 'b) fn<'x>('x, 'x) fn<'a>('a, 'a) fn<'a,'b>('a, 'b)
|
||||
fn<'a,'b>('a, 'b, 'a) fn<'x,'y>('x, 'y, 'y) fn<'a>('a, 'a, 'a) fn<'a,'b,'c>('a,'b,'c)
|
||||
```
|
||||
|
||||
### Conventions
|
||||
|
||||
I use lower-case letters (e.g., `&a`) for bound regions and upper-case
|
||||
letters for free regions (`&A`). Region variables written with a
|
||||
dollar-sign (e.g., `$a`). I will try to remember to enumerate the
|
||||
bound-regions on the fn type as well (e.g., `for<'a> fn(&a)`).
|
||||
|
||||
### High-level summary
|
||||
|
||||
Both the LUB and the GLB algorithms work in a similar fashion. They
|
||||
begin by replacing all bound regions (on both sides) with fresh region
|
||||
inference variables. Therefore, both functions are converted to types
|
||||
that contain only free regions. We can then compute the LUB/GLB in a
|
||||
straightforward way, as described in `combine.rs`. This results in an
|
||||
interim type T. The algorithms then examine the regions that appear
|
||||
in T and try to, in some cases, replace them with bound regions to
|
||||
yield the final result.
|
||||
|
||||
To decide whether to replace a region `R` that appears in `T` with
|
||||
a bound region, the algorithms make use of two bits of
|
||||
information. First is a set `V` that contains all region
|
||||
variables created as part of the LUB/GLB computation (roughly; see
|
||||
`region_vars_confined_to_snapshot()` for full details). `V` will
|
||||
contain the region variables created to replace the bound regions
|
||||
in the input types, but it also contains 'intermediate' variables
|
||||
created to represent the LUB/GLB of individual regions.
|
||||
Basically, when asked to compute the LUB/GLB of a region variable
|
||||
with another region, the inferencer cannot oblige immediately
|
||||
since the values of that variables are not known. Therefore, it
|
||||
creates a new variable that is related to the two regions. For
|
||||
example, the LUB of two variables `$x` and `$y` is a fresh
|
||||
variable `$z` that is constrained such that `$x <= $z` and `$y <=
|
||||
$z`. So `V` will contain these intermediate variables as well.
|
||||
|
||||
The other important factor in deciding how to replace a region in T is
|
||||
the function `Tainted($r)` which, for a region variable, identifies
|
||||
all regions that the region variable is related to in some way
|
||||
(`Tainted()` made an appearance in the subtype computation as well).
|
||||
|
||||
### LUB
|
||||
|
||||
The LUB algorithm proceeds in three steps:
|
||||
|
||||
1. Replace all bound regions (on both sides) with fresh region
|
||||
inference variables.
|
||||
2. Compute the LUB "as normal", meaning compute the GLB of each
|
||||
pair of argument types and the LUB of the return types and
|
||||
so forth. Combine those to a new function type `F`.
|
||||
3. Replace each region `R` that appears in `F` as follows:
|
||||
- Let `V` be the set of variables created during the LUB
|
||||
computational steps 1 and 2, as described in the previous section.
|
||||
- If `R` is not in `V`, replace `R` with itself.
|
||||
- If `Tainted(R)` contains a region that is not in `V`,
|
||||
replace `R` with itself.
|
||||
- Otherwise, select the earliest variable in `Tainted(R)` that originates
|
||||
from the left-hand side and replace `R` with the bound region that
|
||||
this variable was a replacement for.
|
||||
|
||||
So, let's work through the simplest example: `fn(&A)` and `for<'a> fn(&a)`.
|
||||
In this case, `&a` will be replaced with `$a` and the interim LUB type
|
||||
`fn($b)` will be computed, where `$b=GLB(&A,$a)`. Therefore, `V =
|
||||
{$a, $b}` and `Tainted($b) = { $b, $a, &A }`. When we go to replace
|
||||
`$b`, we find that since `&A \in Tainted($b)` is not a member of `V`,
|
||||
we leave `$b` as is. When region inference happens, `$b` will be
|
||||
resolved to `&A`, as we wanted.
|
||||
|
||||
Let's look at a more complex one: `fn(&a, &b)` and `fn(&x, &x)`. In
|
||||
this case, we'll end up with a (pre-replacement) LUB type of `fn(&g,
|
||||
&h)` and a graph that looks like:
|
||||
|
||||
```
|
||||
$a $b *--$x
|
||||
\ \ / /
|
||||
\ $h-* /
|
||||
$g-----------*
|
||||
```
|
||||
|
||||
Here `$g` and `$h` are fresh variables that are created to represent
|
||||
the LUB/GLB of things requiring inference. This means that `V` and
|
||||
`Tainted` will look like:
|
||||
|
||||
```
|
||||
V = {$a, $b, $g, $h, $x}
|
||||
Tainted($g) = Tainted($h) = { $a, $b, $h, $g, $x }
|
||||
```
|
||||
|
||||
Therefore we replace both `$g` and `$h` with `$a`, and end up
|
||||
with the type `fn(&a, &a)`.
|
||||
|
||||
### GLB
|
||||
|
||||
The procedure for computing the GLB is similar. The difference lies
|
||||
in computing the replacements for the various variables. For each
|
||||
region `R` that appears in the type `F`, we again compute `Tainted(R)`
|
||||
and examine the results:
|
||||
|
||||
1. If `R` is not in `V`, it is not replaced.
|
||||
2. Else, if `Tainted(R)` contains only variables in `V`, and it
|
||||
contains exactly one variable from the LHS and one variable from
|
||||
the RHS, then `R` can be mapped to the bound version of the
|
||||
variable from the LHS.
|
||||
3. Else, if `Tainted(R)` contains no variable from the LHS and no
|
||||
variable from the RHS, then `R` can be mapped to itself.
|
||||
4. Else, `R` is mapped to a fresh bound variable.
|
||||
|
||||
These rules are pretty complex. Let's look at some examples to see
|
||||
how they play out.
|
||||
|
||||
Out first example was `fn(&a)` and `fn(&X)`. In this case, `&a` will
|
||||
be replaced with `$a` and we will ultimately compute a
|
||||
(pre-replacement) GLB type of `fn($g)` where `$g=LUB($a,&X)`.
|
||||
Therefore, `V={$a,$g}` and `Tainted($g)={$g,$a,&X}. To find the
|
||||
replacement for `$g` we consult the rules above:
|
||||
- Rule (1) does not apply because `$g \in V`
|
||||
- Rule (2) does not apply because `&X \in Tainted($g)`
|
||||
- Rule (3) does not apply because `$a \in Tainted($g)`
|
||||
- Hence, by rule (4), we replace `$g` with a fresh bound variable `&z`.
|
||||
So our final result is `fn(&z)`, which is correct.
|
||||
|
||||
The next example is `fn(&A)` and `fn(&Z)`. In this case, we will again
|
||||
have a (pre-replacement) GLB of `fn(&g)`, where `$g = LUB(&A,&Z)`.
|
||||
Therefore, `V={$g}` and `Tainted($g) = {$g, &A, &Z}`. In this case,
|
||||
by rule (3), `$g` is mapped to itself, and hence the result is
|
||||
`fn($g)`. This result is correct (in this case, at least), but it is
|
||||
indicative of a case that *can* lead us into concluding that there is
|
||||
no GLB when in fact a GLB does exist. See the section "Questionable
|
||||
Results" below for more details.
|
||||
|
||||
The next example is `fn(&a, &b)` and `fn(&c, &c)`. In this case, as
|
||||
before, we'll end up with `F=fn($g, $h)` where `Tainted($g) =
|
||||
Tainted($h) = {$g, $h, $a, $b, $c}`. Only rule (4) applies and hence
|
||||
we'll select fresh bound variables `y` and `z` and wind up with
|
||||
`fn(&y, &z)`.
|
||||
|
||||
For the last example, let's consider what may seem trivial, but is
|
||||
not: `fn(&a, &a)` and `fn(&b, &b)`. In this case, we'll get `F=fn($g,
|
||||
$h)` where `Tainted($g) = {$g, $a, $x}` and `Tainted($h) = {$h, $a,
|
||||
$x}`. Both of these sets contain exactly one bound variable from each
|
||||
side, so we'll map them both to `&a`, resulting in `fn(&a, &a)`, which
|
||||
is the desired result.
|
||||
|
||||
### Shortcomings and correctness
|
||||
|
||||
You may be wondering whether this algorithm is correct. The answer is
|
||||
"sort of". There are definitely cases where they fail to compute a
|
||||
result even though a correct result exists. I believe, though, that
|
||||
if they succeed, then the result is valid, and I will attempt to
|
||||
convince you. The basic argument is that the "pre-replacement" step
|
||||
computes a set of constraints. The replacements, then, attempt to
|
||||
satisfy those constraints, using bound identifiers where needed.
|
||||
|
||||
For now I will briefly go over the cases for LUB/GLB and identify
|
||||
their intent:
|
||||
|
||||
- LUB:
|
||||
- The region variables that are substituted in place of bound regions
|
||||
are intended to collect constraints on those bound regions.
|
||||
- If Tainted(R) contains only values in V, then this region is unconstrained
|
||||
and can therefore be generalized, otherwise it cannot.
|
||||
- GLB:
|
||||
- The region variables that are substituted in place of bound regions
|
||||
are intended to collect constraints on those bound regions.
|
||||
- If Tainted(R) contains exactly one variable from each side, and
|
||||
only variables in V, that indicates that those two bound regions
|
||||
must be equated.
|
||||
- Otherwise, if Tainted(R) references any variables from left or right
|
||||
side, then it is trying to combine a bound region with a free one or
|
||||
multiple bound regions, so we need to select fresh bound regions.
|
||||
|
||||
Sorry this is more of a shorthand to myself. I will try to write up something
|
||||
more convincing in the future.
|
||||
|
||||
#### Where are the algorithms wrong?
|
||||
|
||||
- The pre-replacement computation can fail even though using a
|
||||
bound-region would have succeeded.
|
||||
- We will compute GLB(fn(fn($a)), fn(fn($b))) as fn($c) where $c is the
|
||||
GLB of $a and $b. But if inference finds that $a and $b must be mapped
|
||||
to regions without a GLB, then this is effectively a failure to compute
|
||||
the GLB. However, the result `fn<$c>(fn($c))` is a valid GLB.
|
||||
[oldhrtb]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html
|
||||
[newhrtb]: https://rust-lang.github.io/rustc-guide/borrow_check/region_inference.html#placeholders-and-universes
|
||||
|
@ -2,8 +2,12 @@
|
||||
|
||||
> WARNING: This README is obsolete and will be removed soon! For
|
||||
> more info on how the current borrowck works, see the [rustc guide].
|
||||
>
|
||||
> As of edition 2018, region inference is done using Non-lexical lifetimes,
|
||||
> which is described in the guide and [this RFC].
|
||||
|
||||
[rustc guide]: https://rust-lang.github.io/rustc-guide/mir/borrowck.html
|
||||
[this RFC]: https://github.com/rust-lang/rfcs/blob/master/text/2094-nll.md
|
||||
|
||||
## Terminology
|
||||
|
||||
|
@ -1,77 +1,3 @@
|
||||
# Region constraint collection
|
||||
|
||||
> WARNING: This README is obsolete and will be removed soon! For
|
||||
> more info on how the current borrowck works, see the [rustc guide].
|
||||
For info on how the current borrowck works, see the [rustc guide].
|
||||
|
||||
[rustc guide]: https://rust-lang.github.io/rustc-guide/mir/borrowck.html
|
||||
|
||||
## Terminology
|
||||
|
||||
Note that we use the terms region and lifetime interchangeably.
|
||||
|
||||
## Introduction
|
||||
|
||||
As described in the rustc guide [chapter on type inference][ti], and unlike
|
||||
normal type inference, which is similar in spirit to H-M and thus
|
||||
works progressively, the region type inference works by accumulating
|
||||
constraints over the course of a function. Finally, at the end of
|
||||
processing a function, we process and solve the constraints all at
|
||||
once.
|
||||
|
||||
[ti]: https://rust-lang.github.io/rustc-guide/type-inference.html
|
||||
|
||||
The constraints are always of one of three possible forms:
|
||||
|
||||
- `ConstrainVarSubVar(Ri, Rj)` states that region variable Ri must be
|
||||
a subregion of Rj
|
||||
- `ConstrainRegSubVar(R, Ri)` states that the concrete region R (which
|
||||
must not be a variable) must be a subregion of the variable Ri
|
||||
- `ConstrainVarSubReg(Ri, R)` states the variable Ri should be less
|
||||
than the concrete region R. This is kind of deprecated and ought to
|
||||
be replaced with a verify (they essentially play the same role).
|
||||
|
||||
In addition to constraints, we also gather up a set of "verifys"
|
||||
(what, you don't think Verify is a noun? Get used to it my
|
||||
friend!). These represent relations that must hold but which don't
|
||||
influence inference proper. These take the form of:
|
||||
|
||||
- `VerifyRegSubReg(Ri, Rj)` indicates that Ri <= Rj must hold,
|
||||
where Rj is not an inference variable (and Ri may or may not contain
|
||||
one). This doesn't influence inference because we will already have
|
||||
inferred Ri to be as small as possible, so then we just test whether
|
||||
that result was less than Rj or not.
|
||||
- `VerifyGenericBound(R, Vb)` is a more complex expression which tests
|
||||
that the region R must satisfy the bound `Vb`. The bounds themselves
|
||||
may have structure like "must outlive one of the following regions"
|
||||
or "must outlive ALL of the following regions. These bounds arise
|
||||
from constraints like `T: 'a` -- if we know that `T: 'b` and `T: 'c`
|
||||
(say, from where clauses), then we can conclude that `T: 'a` if `'b:
|
||||
'a` *or* `'c: 'a`.
|
||||
|
||||
## Building up the constraints
|
||||
|
||||
Variables and constraints are created using the following methods:
|
||||
|
||||
- `new_region_var()` creates a new, unconstrained region variable;
|
||||
- `make_subregion(Ri, Rj)` states that Ri is a subregion of Rj
|
||||
- `lub_regions(Ri, Rj) -> Rk` returns a region Rk which is
|
||||
the smallest region that is greater than both Ri and Rj
|
||||
- `glb_regions(Ri, Rj) -> Rk` returns a region Rk which is
|
||||
the greatest region that is smaller than both Ri and Rj
|
||||
|
||||
The actual region resolution algorithm is not entirely
|
||||
obvious, though it is also not overly complex.
|
||||
|
||||
## Snapshotting
|
||||
|
||||
It is also permitted to try (and rollback) changes to the graph. This
|
||||
is done by invoking `start_snapshot()`, which returns a value. Then
|
||||
later you can call `rollback_to()` which undoes the work.
|
||||
Alternatively, you can call `commit()` which ends all snapshots.
|
||||
Snapshots can be recursive---so you can start a snapshot when another
|
||||
is in progress, but only the root snapshot can "commit".
|
||||
|
||||
## Skolemization
|
||||
|
||||
For a discussion on skolemization and higher-ranked subtyping, please
|
||||
see the module `middle::infer::higher_ranked::doc`.
|
||||
|
@ -210,12 +210,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
|
||||
let visible_parent = visible_parent_map.get(&cur_def).cloned();
|
||||
let actual_parent = self.parent(cur_def);
|
||||
debug!(
|
||||
"try_push_visible_item_path: visible_parent={:?} actual_parent={:?}",
|
||||
visible_parent, actual_parent,
|
||||
);
|
||||
|
||||
let data = cur_def_key.disambiguated_data.data;
|
||||
debug!(
|
||||
"try_push_visible_item_path: data={:?} visible_parent={:?} actual_parent={:?}",
|
||||
data, visible_parent, actual_parent,
|
||||
);
|
||||
let symbol = match data {
|
||||
// In order to output a path that could actually be imported (valid and visible),
|
||||
// we need to handle re-exports correctly.
|
||||
@ -248,16 +248,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
// the children of the visible parent (as was done when computing
|
||||
// `visible_parent_map`), looking for the specific child we currently have and then
|
||||
// have access to the re-exported name.
|
||||
DefPathData::Module(module_name) if visible_parent != actual_parent => {
|
||||
let mut name: Option<ast::Ident> = None;
|
||||
if let Some(visible_parent) = visible_parent {
|
||||
for child in self.item_children(visible_parent).iter() {
|
||||
if child.def.def_id() == cur_def {
|
||||
name = Some(child.ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
name.map(|n| n.as_str()).unwrap_or(module_name.as_str())
|
||||
DefPathData::Module(actual_name) |
|
||||
DefPathData::TypeNs(actual_name) if visible_parent != actual_parent => {
|
||||
visible_parent
|
||||
.and_then(|parent| {
|
||||
self.item_children(parent)
|
||||
.iter()
|
||||
.find(|child| child.def.def_id() == cur_def)
|
||||
.map(|child| child.ident.as_str())
|
||||
})
|
||||
.unwrap_or_else(|| actual_name.as_str())
|
||||
},
|
||||
_ => {
|
||||
data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
|
||||
|
@ -1,302 +1,3 @@
|
||||
# The Rust Compiler Query System
|
||||
|
||||
The Compiler Query System is the key to our new demand-driven
|
||||
organization. The idea is pretty simple. You have various queries
|
||||
that compute things about the input -- for example, there is a query
|
||||
called `type_of(def_id)` that, given the def-id of some item, will
|
||||
compute the type of that item and return it to you.
|
||||
|
||||
Query execution is **memoized** -- so the first time you invoke a
|
||||
query, it will go do the computation, but the next time, the result is
|
||||
returned from a hashtable. Moreover, query execution fits nicely into
|
||||
**incremental computation**; the idea is roughly that, when you do a
|
||||
query, the result **may** be returned to you by loading stored data
|
||||
from disk (but that's a separate topic we won't discuss further here).
|
||||
|
||||
The overall vision is that, eventually, the entire compiler
|
||||
control-flow will be query driven. There will effectively be one
|
||||
top-level query ("compile") that will run compilation on a crate; this
|
||||
will in turn demand information about that crate, starting from the
|
||||
*end*. For example:
|
||||
|
||||
- This "compile" query might demand to get a list of codegen-units
|
||||
(i.e., modules that need to be compiled by LLVM).
|
||||
- But computing the list of codegen-units would invoke some subquery
|
||||
that returns the list of all modules defined in the Rust source.
|
||||
- That query in turn would invoke something asking for the HIR.
|
||||
- This keeps going further and further back until we wind up doing the
|
||||
actual parsing.
|
||||
|
||||
However, that vision is not fully realized. Still, big chunks of the
|
||||
compiler (for example, generating MIR) work exactly like this.
|
||||
|
||||
### Invoking queries
|
||||
|
||||
To invoke a query is simple. The tcx ("type context") offers a method
|
||||
for each defined query. So, for example, to invoke the `type_of`
|
||||
query, you would just do this:
|
||||
|
||||
```rust
|
||||
let ty = tcx.type_of(some_def_id);
|
||||
```
|
||||
|
||||
### Cycles between queries
|
||||
|
||||
Currently, cycles during query execution should always result in a
|
||||
compilation error. Typically, they arise because of illegal programs
|
||||
that contain cyclic references they shouldn't (though sometimes they
|
||||
arise because of compiler bugs, in which case we need to factor our
|
||||
queries in a more fine-grained fashion to avoid them).
|
||||
|
||||
However, it is nonetheless often useful to *recover* from a cycle
|
||||
(after reporting an error, say) and try to soldier on, so as to give a
|
||||
better user experience. In order to recover from a cycle, you don't
|
||||
get to use the nice method-call-style syntax. Instead, you invoke
|
||||
using the `try_get` method, which looks roughly like this:
|
||||
|
||||
```rust
|
||||
use ty::query::queries;
|
||||
...
|
||||
match queries::type_of::try_get(tcx, DUMMY_SP, self.did) {
|
||||
Ok(result) => {
|
||||
// no cycle occurred! You can use `result`
|
||||
}
|
||||
Err(err) => {
|
||||
// A cycle occurred! The error value `err` is a `DiagnosticBuilder`,
|
||||
// meaning essentially an "in-progress", not-yet-reported error message.
|
||||
// See below for more details on what to do here.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
So, if you get back an `Err` from `try_get`, then a cycle *did* occur. This means that
|
||||
you must ensure that a compiler error message is reported. You can do that in two ways:
|
||||
|
||||
The simplest is to invoke `err.emit()`. This will emit the cycle error to the user.
|
||||
|
||||
However, often cycles happen because of an illegal program, and you
|
||||
know at that point that an error either already has been reported or
|
||||
will be reported due to this cycle by some other bit of code. In that
|
||||
case, you can invoke `err.cancel()` to not emit any error. It is
|
||||
traditional to then invoke:
|
||||
|
||||
```
|
||||
tcx.sess.delay_span_bug(some_span, "some message")
|
||||
```
|
||||
|
||||
`delay_span_bug()` is a helper that says: we expect a compilation
|
||||
error to have happened or to happen in the future; so, if compilation
|
||||
ultimately succeeds, make an ICE with the message `"some
|
||||
message"`. This is basically just a precaution in case you are wrong.
|
||||
|
||||
### How the compiler executes a query
|
||||
|
||||
So you may be wondering what happens when you invoke a query
|
||||
method. The answer is that, for each query, the compiler maintains a
|
||||
cache -- if your query has already been executed, then, the answer is
|
||||
simple: we clone the return value out of the cache and return it
|
||||
(therefore, you should try to ensure that the return types of queries
|
||||
are cheaply cloneable; insert a `Rc` if necessary).
|
||||
|
||||
#### Providers
|
||||
|
||||
If, however, the query is *not* in the cache, then the compiler will
|
||||
try to find a suitable **provider**. A provider is a function that has
|
||||
been defined and linked into the compiler somewhere that contains the
|
||||
code to compute the result of the query.
|
||||
|
||||
**Providers are defined per-crate.** The compiler maintains,
|
||||
internally, a table of providers for every crate, at least
|
||||
conceptually. Right now, there are really two sets: the providers for
|
||||
queries about the **local crate** (that is, the one being compiled)
|
||||
and providers for queries about **external crates** (that is,
|
||||
dependencies of the local crate). Note that what determines the crate
|
||||
that a query is targeting is not the *kind* of query, but the *key*.
|
||||
For example, when you invoke `tcx.type_of(def_id)`, that could be a
|
||||
local query or an external query, depending on what crate the `def_id`
|
||||
is referring to (see the `self::keys::Key` trait for more information
|
||||
on how that works).
|
||||
|
||||
Providers always have the same signature:
|
||||
|
||||
```rust
|
||||
fn provider<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
||||
key: QUERY_KEY)
|
||||
-> QUERY_RESULT
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Providers take two arguments: the `tcx` and the query key. Note also
|
||||
that they take the *global* tcx (i.e., they use the `'tcx` lifetime
|
||||
twice), rather than taking a tcx with some active inference context.
|
||||
They return the result of the query.
|
||||
|
||||
#### How providers are setup
|
||||
|
||||
When the tcx is created, it is given the providers by its creator using
|
||||
the `Providers` struct. This struct is generate by the macros here, but it
|
||||
is basically a big list of function pointers:
|
||||
|
||||
```rust
|
||||
struct Providers {
|
||||
type_of: for<'cx, 'tcx> fn(TyCtxt<'cx, 'tcx, 'tcx>, DefId) -> Ty<'tcx>,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
At present, we have one copy of the struct for local crates, and one
|
||||
for external crates, though the plan is that we may eventually have
|
||||
one per crate.
|
||||
|
||||
These `Provider` structs are ultimately created and populated by
|
||||
`librustc_driver`, but it does this by distributing the work
|
||||
throughout the other `rustc_*` crates. This is done by invoking
|
||||
various `provide` functions. These functions tend to look something
|
||||
like this:
|
||||
|
||||
```rust
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
type_of,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
That is, they take an `&mut Providers` and mutate it in place. Usually
|
||||
we use the formulation above just because it looks nice, but you could
|
||||
as well do `providers.type_of = type_of`, which would be equivalent.
|
||||
(Here, `type_of` would be a top-level function, defined as we saw
|
||||
before.) So, if we want to add a provider for some other query,
|
||||
let's call it `fubar`, into the crate above, we might modify the `provide()`
|
||||
function like so:
|
||||
|
||||
```rust
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
type_of,
|
||||
fubar,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
||||
fn fubar<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx>, key: DefId) -> Fubar<'tcx> { .. }
|
||||
```
|
||||
|
||||
NB. Most of the `rustc_*` crates only provide **local
|
||||
providers**. Almost all **extern providers** wind up going through the
|
||||
`rustc_metadata` crate, which loads the information from the crate
|
||||
metadata. But in some cases there are crates that provide queries for
|
||||
*both* local and external crates, in which case they define both a
|
||||
`provide` and a `provide_extern` function that `rustc_driver` can
|
||||
invoke.
|
||||
|
||||
### Adding a new kind of query
|
||||
|
||||
So suppose you want to add a new kind of query, how do you do so?
|
||||
Well, defining a query takes place in two steps:
|
||||
|
||||
1. first, you have to specify the query name and arguments; and then,
|
||||
2. you have to supply query providers where needed.
|
||||
|
||||
To specify the query name and arguments, you simply add an entry
|
||||
to the big macro invocation in `mod.rs`. This will probably have changed
|
||||
by the time you read this README, but at present it looks something
|
||||
like:
|
||||
|
||||
```
|
||||
define_queries! { <'tcx>
|
||||
/// Records the type of every item.
|
||||
[] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>,
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Each line of the macro defines one query. The name is broken up like this:
|
||||
|
||||
```
|
||||
[] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>,
|
||||
^^ ^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^
|
||||
| | | | |
|
||||
| | | | result type of query
|
||||
| | | query key type
|
||||
| | dep-node constructor
|
||||
| name of query
|
||||
query flags
|
||||
```
|
||||
|
||||
Let's go over them one by one:
|
||||
|
||||
- **Query flags:** these are largely unused right now, but the intention
|
||||
is that we'll be able to customize various aspects of how the query is
|
||||
processed.
|
||||
- **Name of query:** the name of the query method
|
||||
(`tcx.type_of(..)`). Also used as the name of a struct
|
||||
(`ty::query::queries::type_of`) that will be generated to represent
|
||||
this query.
|
||||
- **Dep-node constructor:** indicates the constructor function that
|
||||
connects this query to incremental compilation. Typically, this is a
|
||||
`DepNode` variant, which can be added by modifying the
|
||||
`define_dep_nodes!` macro invocation in
|
||||
`librustc/dep_graph/dep_node.rs`.
|
||||
- However, sometimes we use a custom function, in which case the
|
||||
name will be in snake case and the function will be defined at the
|
||||
bottom of the file. This is typically used when the query key is
|
||||
not a def-id, or just not the type that the dep-node expects.
|
||||
- **Query key type:** the type of the argument to this query.
|
||||
This type must implement the `ty::query::keys::Key` trait, which
|
||||
defines (for example) how to map it to a crate, and so forth.
|
||||
- **Result type of query:** the type produced by this query. This type
|
||||
should (a) not use `RefCell` or other interior mutability and (b) be
|
||||
cheaply cloneable. Interning or using `Rc` or `Arc` is recommended for
|
||||
non-trivial data types.
|
||||
- The one exception to those rules is the `ty::steal::Steal` type,
|
||||
which is used to cheaply modify MIR in place. See the definition
|
||||
of `Steal` for more details. New uses of `Steal` should **not** be
|
||||
added without alerting `@rust-lang/compiler`.
|
||||
|
||||
So, to add a query:
|
||||
|
||||
- Add an entry to `define_queries!` using the format above.
|
||||
- Possibly add a corresponding entry to the dep-node macro.
|
||||
- Link the provider by modifying the appropriate `provide` method;
|
||||
or add a new one if needed and ensure that `rustc_driver` is invoking it.
|
||||
|
||||
#### Query structs and descriptions
|
||||
|
||||
For each kind, the `define_queries` macro will generate a "query struct"
|
||||
named after the query. This struct is a kind of a place-holder
|
||||
describing the query. Each such struct implements the
|
||||
`self::config::QueryConfig` trait, which has associated types for the
|
||||
key/value of that particular query. Basically the code generated looks something
|
||||
like this:
|
||||
|
||||
```rust
|
||||
// Dummy struct representing a particular kind of query:
|
||||
pub struct type_of<'tcx> { phantom: PhantomData<&'tcx ()> }
|
||||
|
||||
impl<'tcx> QueryConfig for type_of<'tcx> {
|
||||
type Key = DefId;
|
||||
type Value = Ty<'tcx>;
|
||||
}
|
||||
```
|
||||
|
||||
There is an additional trait that you may wish to implement called
|
||||
`self::config::QueryDescription`. This trait is used during cycle
|
||||
errors to give a "human readable" name for the query, so that we can
|
||||
summarize what was happening when the cycle occurred. Implementing
|
||||
this trait is optional if the query key is `DefId`, but if you *don't*
|
||||
implement it, you get a pretty generic error ("processing `foo`...").
|
||||
You can put new impls into the `config` module. They look something like this:
|
||||
|
||||
```rust
|
||||
impl<'tcx> QueryDescription for queries::type_of<'tcx> {
|
||||
fn describe(tcx: TyCtxt<'_, '_, '_>, key: DefId) -> String {
|
||||
format!("computing the type of `{}`", tcx.item_path_str(key))
|
||||
}
|
||||
}
|
||||
```
|
||||
For more information about how the query system works, see the [rustc guide].
|
||||
|
||||
[rustc guide]: https://rust-lang.github.io/rustc-guide/query.html
|
||||
|
@ -55,7 +55,7 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
ty::Str => {
|
||||
let mut name = String::with_capacity(32);
|
||||
let printer = DefPathBasedNames::new(cx.tcx, true, true);
|
||||
printer.push_type_name(layout.ty, &mut name);
|
||||
printer.push_type_name(layout.ty, &mut name, false);
|
||||
if let (&ty::Adt(def, _), &layout::Variants::Single { index })
|
||||
= (&layout.ty.sty, &layout.variants)
|
||||
{
|
||||
|
@ -13,7 +13,7 @@ pub use rustc_mir::monomorphize::item::MonoItemExt as BaseMonoItemExt;
|
||||
pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
|
||||
fn define<Bx: BuilderMethods<'a, 'tcx>>(&self, cx: &'a Bx::CodegenCx) {
|
||||
debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}",
|
||||
self.to_string(cx.tcx()),
|
||||
self.to_string(cx.tcx(), true),
|
||||
self.to_raw_string(),
|
||||
cx.codegen_unit().name());
|
||||
|
||||
@ -45,7 +45,7 @@ pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
debug!("END IMPLEMENTING '{} ({})' in cgu {}",
|
||||
self.to_string(cx.tcx()),
|
||||
self.to_string(cx.tcx(), true),
|
||||
self.to_raw_string(),
|
||||
cx.codegen_unit().name());
|
||||
}
|
||||
@ -57,7 +57,7 @@ pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
|
||||
visibility: Visibility
|
||||
) {
|
||||
debug!("BEGIN PREDEFINING '{} ({})' in cgu {}",
|
||||
self.to_string(cx.tcx()),
|
||||
self.to_string(cx.tcx(), true),
|
||||
self.to_raw_string(),
|
||||
cx.codegen_unit().name());
|
||||
|
||||
@ -76,7 +76,7 @@ pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
debug!("END PREDEFINING '{} ({})' in cgu {}",
|
||||
self.to_string(cx.tcx()),
|
||||
self.to_string(cx.tcx(), true),
|
||||
self.to_raw_string(),
|
||||
cx.codegen_unit().name());
|
||||
}
|
||||
|
@ -1,81 +0,0 @@
|
||||
The `ObligationForest` is a utility data structure used in trait
|
||||
matching to track the set of outstanding obligations (those not yet
|
||||
resolved to success or error). It also tracks the "backtrace" of each
|
||||
pending obligation (why we are trying to figure this out in the first
|
||||
place).
|
||||
|
||||
### External view
|
||||
|
||||
`ObligationForest` supports two main public operations (there are a
|
||||
few others not discussed here):
|
||||
|
||||
1. Add a new root obligations (`push_tree`).
|
||||
2. Process the pending obligations (`process_obligations`).
|
||||
|
||||
When a new obligation `N` is added, it becomes the root of an
|
||||
obligation tree. This tree can also carry some per-tree state `T`,
|
||||
which is given at the same time. This tree is a singleton to start, so
|
||||
`N` is both the root and the only leaf. Each time the
|
||||
`process_obligations` method is called, it will invoke its callback
|
||||
with every pending obligation (so that will include `N`, the first
|
||||
time). The callback also receives a (mutable) reference to the
|
||||
per-tree state `T`. The callback should process the obligation `O`
|
||||
that it is given and return one of three results:
|
||||
|
||||
- `Ok(None)` -> ambiguous result. Obligation was neither a success
|
||||
nor a failure. It is assumed that further attempts to process the
|
||||
obligation will yield the same result unless something in the
|
||||
surrounding environment changes.
|
||||
- `Ok(Some(C))` - the obligation was *shallowly successful*. The
|
||||
vector `C` is a list of subobligations. The meaning of this is that
|
||||
`O` was successful on the assumption that all the obligations in `C`
|
||||
are also successful. Therefore, `O` is only considered a "true"
|
||||
success if `C` is empty. Otherwise, `O` is put into a suspended
|
||||
state and the obligations in `C` become the new pending
|
||||
obligations. They will be processed the next time you call
|
||||
`process_obligations`.
|
||||
- `Err(E)` -> obligation failed with error `E`. We will collect this
|
||||
error and return it from `process_obligations`, along with the
|
||||
"backtrace" of obligations (that is, the list of obligations up to
|
||||
and including the root of the failed obligation). No further
|
||||
obligations from that same tree will be processed, since the tree is
|
||||
now considered to be in error.
|
||||
|
||||
When the call to `process_obligations` completes, you get back an `Outcome`,
|
||||
which includes three bits of information:
|
||||
|
||||
- `completed`: a list of obligations where processing was fully
|
||||
completed without error (meaning that all transitive subobligations
|
||||
have also been completed). So, for example, if the callback from
|
||||
`process_obligations` returns `Ok(Some(C))` for some obligation `O`,
|
||||
then `O` will be considered completed right away if `C` is the
|
||||
empty vector. Otherwise it will only be considered completed once
|
||||
all the obligations in `C` have been found completed.
|
||||
- `errors`: a list of errors that occurred and associated backtraces
|
||||
at the time of error, which can be used to give context to the user.
|
||||
- `stalled`: if true, then none of the existing obligations were
|
||||
*shallowly successful* (that is, no callback returned `Ok(Some(_))`).
|
||||
This implies that all obligations were either errors or returned an
|
||||
ambiguous result, which means that any further calls to
|
||||
`process_obligations` would simply yield back further ambiguous
|
||||
results. This is used by the `FulfillmentContext` to decide when it
|
||||
has reached a steady state.
|
||||
|
||||
#### Snapshots
|
||||
|
||||
The `ObligationForest` supports a limited form of snapshots; see
|
||||
`start_snapshot`; `commit_snapshot`; and `rollback_snapshot`. In
|
||||
particular, you can use a snapshot to roll back new root
|
||||
obligations. However, it is an error to attempt to
|
||||
`process_obligations` during a snapshot.
|
||||
|
||||
### Implementation details
|
||||
|
||||
For the most part, comments specific to the implementation are in the
|
||||
code. This file only contains a very high-level overview. Basically,
|
||||
the forest is stored in a vector. Each element of the vector is a node
|
||||
in some tree. Each node in the vector has the index of an (optional)
|
||||
parent and (for convenience) its root (which may be itself). It also
|
||||
has a current state, described by `NodeState`. After each
|
||||
processing step, we compress the vector to remove completed and error
|
||||
nodes, which aren't needed anymore.
|
@ -1,9 +1,84 @@
|
||||
//! The `ObligationForest` is a utility data structure used in trait
|
||||
//! matching to track the set of outstanding obligations (those not
|
||||
//! yet resolved to success or error). It also tracks the "backtrace"
|
||||
//! of each pending obligation (why we are trying to figure this out
|
||||
//! in the first place). See README.md for a general overview of how
|
||||
//! to use this class.
|
||||
//! matching to track the set of outstanding obligations (those not yet
|
||||
//! resolved to success or error). It also tracks the "backtrace" of each
|
||||
//! pending obligation (why we are trying to figure this out in the first
|
||||
//! place).
|
||||
//!
|
||||
//! ### External view
|
||||
//!
|
||||
//! `ObligationForest` supports two main public operations (there are a
|
||||
//! few others not discussed here):
|
||||
//!
|
||||
//! 1. Add a new root obligations (`push_tree`).
|
||||
//! 2. Process the pending obligations (`process_obligations`).
|
||||
//!
|
||||
//! When a new obligation `N` is added, it becomes the root of an
|
||||
//! obligation tree. This tree can also carry some per-tree state `T`,
|
||||
//! which is given at the same time. This tree is a singleton to start, so
|
||||
//! `N` is both the root and the only leaf. Each time the
|
||||
//! `process_obligations` method is called, it will invoke its callback
|
||||
//! with every pending obligation (so that will include `N`, the first
|
||||
//! time). The callback also receives a (mutable) reference to the
|
||||
//! per-tree state `T`. The callback should process the obligation `O`
|
||||
//! that it is given and return one of three results:
|
||||
//!
|
||||
//! - `Ok(None)` -> ambiguous result. Obligation was neither a success
|
||||
//! nor a failure. It is assumed that further attempts to process the
|
||||
//! obligation will yield the same result unless something in the
|
||||
//! surrounding environment changes.
|
||||
//! - `Ok(Some(C))` - the obligation was *shallowly successful*. The
|
||||
//! vector `C` is a list of subobligations. The meaning of this is that
|
||||
//! `O` was successful on the assumption that all the obligations in `C`
|
||||
//! are also successful. Therefore, `O` is only considered a "true"
|
||||
//! success if `C` is empty. Otherwise, `O` is put into a suspended
|
||||
//! state and the obligations in `C` become the new pending
|
||||
//! obligations. They will be processed the next time you call
|
||||
//! `process_obligations`.
|
||||
//! - `Err(E)` -> obligation failed with error `E`. We will collect this
|
||||
//! error and return it from `process_obligations`, along with the
|
||||
//! "backtrace" of obligations (that is, the list of obligations up to
|
||||
//! and including the root of the failed obligation). No further
|
||||
//! obligations from that same tree will be processed, since the tree is
|
||||
//! now considered to be in error.
|
||||
//!
|
||||
//! When the call to `process_obligations` completes, you get back an `Outcome`,
|
||||
//! which includes three bits of information:
|
||||
//!
|
||||
//! - `completed`: a list of obligations where processing was fully
|
||||
//! completed without error (meaning that all transitive subobligations
|
||||
//! have also been completed). So, for example, if the callback from
|
||||
//! `process_obligations` returns `Ok(Some(C))` for some obligation `O`,
|
||||
//! then `O` will be considered completed right away if `C` is the
|
||||
//! empty vector. Otherwise it will only be considered completed once
|
||||
//! all the obligations in `C` have been found completed.
|
||||
//! - `errors`: a list of errors that occurred and associated backtraces
|
||||
//! at the time of error, which can be used to give context to the user.
|
||||
//! - `stalled`: if true, then none of the existing obligations were
|
||||
//! *shallowly successful* (that is, no callback returned `Ok(Some(_))`).
|
||||
//! This implies that all obligations were either errors or returned an
|
||||
//! ambiguous result, which means that any further calls to
|
||||
//! `process_obligations` would simply yield back further ambiguous
|
||||
//! results. This is used by the `FulfillmentContext` to decide when it
|
||||
//! has reached a steady state.
|
||||
//!
|
||||
//! #### Snapshots
|
||||
//!
|
||||
//! The `ObligationForest` supports a limited form of snapshots; see
|
||||
//! `start_snapshot`; `commit_snapshot`; and `rollback_snapshot`. In
|
||||
//! particular, you can use a snapshot to roll back new root
|
||||
//! obligations. However, it is an error to attempt to
|
||||
//! `process_obligations` during a snapshot.
|
||||
//!
|
||||
//! ### Implementation details
|
||||
//!
|
||||
//! For the most part, comments specific to the implementation are in the
|
||||
//! code. This file only contains a very high-level overview. Basically,
|
||||
//! the forest is stored in a vector. Each element of the vector is a node
|
||||
//! in some tree. Each node in the vector has the index of an (optional)
|
||||
//! parent and (for convenience) its root (which may be itself). It also
|
||||
//! has a current state, described by `NodeState`. After each
|
||||
//! processing step, we compress the vector to remove completed and error
|
||||
//! nodes, which aren't needed anymore.
|
||||
|
||||
use fx::{FxHashMap, FxHashSet};
|
||||
|
||||
|
@ -198,19 +198,38 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
let place = &self.move_data.move_paths[mpi].place;
|
||||
|
||||
let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
|
||||
let note_msg = match self.describe_place_with_options(
|
||||
place,
|
||||
IncludingDowncast(true),
|
||||
) {
|
||||
Some(name) => format!("`{}`", name),
|
||||
let opt_name = self.describe_place_with_options(place, IncludingDowncast(true));
|
||||
let note_msg = match opt_name {
|
||||
Some(ref name) => format!("`{}`", name),
|
||||
None => "value".to_owned(),
|
||||
};
|
||||
|
||||
err.note(&format!(
|
||||
"move occurs because {} has type `{}`, \
|
||||
which does not implement the `Copy` trait",
|
||||
note_msg, ty
|
||||
));
|
||||
if let ty::TyKind::Param(param_ty) = ty.sty {
|
||||
let tcx = self.infcx.tcx;
|
||||
let generics = tcx.generics_of(self.mir_def_id);
|
||||
let def_id = generics.type_param(¶m_ty, tcx).def_id;
|
||||
if let Some(sp) = tcx.hir().span_if_local(def_id) {
|
||||
err.span_label(
|
||||
sp,
|
||||
"consider adding a `Copy` constraint to this type argument",
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Place::Local(local) = place {
|
||||
let decl = &self.mir.local_decls[*local];
|
||||
err.span_label(
|
||||
decl.source_info.span,
|
||||
format!(
|
||||
"move occurs because {} has type `{}`, \
|
||||
which does not implement the `Copy` trait",
|
||||
note_msg, ty,
|
||||
));
|
||||
} else {
|
||||
err.note(&format!(
|
||||
"move occurs because {} has type `{}`, \
|
||||
which does not implement the `Copy` trait",
|
||||
note_msg, ty
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((_, mut old_err)) = self.move_error_reported
|
||||
|
@ -355,7 +355,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
// We've been here already, no need to search again.
|
||||
return;
|
||||
}
|
||||
debug!("BEGIN collect_items_rec({})", starting_point.to_string(tcx));
|
||||
debug!("BEGIN collect_items_rec({})", starting_point.to_string(tcx, true));
|
||||
|
||||
let mut neighbors = Vec::new();
|
||||
let recursion_depth_reset;
|
||||
@ -409,7 +409,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
recursion_depths.insert(def_id, depth);
|
||||
}
|
||||
|
||||
debug!("END collect_items_rec({})", starting_point.to_string(tcx));
|
||||
debug!("END collect_items_rec({})", starting_point.to_string(tcx, true));
|
||||
}
|
||||
|
||||
fn record_accesses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
@ -159,14 +159,14 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
|
||||
tcx.substitute_normalize_and_test_predicates((def_id, &substs))
|
||||
}
|
||||
|
||||
fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
|
||||
fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, debug: bool) -> String {
|
||||
return match *self.as_mono_item() {
|
||||
MonoItem::Fn(instance) => {
|
||||
to_string_internal(tcx, "fn ", instance)
|
||||
to_string_internal(tcx, "fn ", instance, debug)
|
||||
},
|
||||
MonoItem::Static(def_id) => {
|
||||
let instance = Instance::new(def_id, tcx.intern_substs(&[]));
|
||||
to_string_internal(tcx, "static ", instance)
|
||||
to_string_internal(tcx, "static ", instance, debug)
|
||||
},
|
||||
MonoItem::GlobalAsm(..) => {
|
||||
"global_asm".to_string()
|
||||
@ -175,12 +175,13 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
|
||||
|
||||
fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
prefix: &str,
|
||||
instance: Instance<'tcx>)
|
||||
instance: Instance<'tcx>,
|
||||
debug: bool)
|
||||
-> String {
|
||||
let mut result = String::with_capacity(32);
|
||||
result.push_str(prefix);
|
||||
let printer = DefPathBasedNames::new(tcx, false, false);
|
||||
printer.push_instance_as_string(instance, &mut result);
|
||||
printer.push_instance_as_string(instance, &mut result, debug);
|
||||
result
|
||||
}
|
||||
}
|
||||
@ -238,7 +239,13 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) {
|
||||
// Pushes the type name of the specified type to the provided string.
|
||||
// If 'debug' is true, printing normally unprintable types is allowed
|
||||
// (e.g. ty::GeneratorWitness). This parameter should only be set when
|
||||
// this method is being used for logging purposes (e.g. with debug! or info!)
|
||||
// When being used for codegen purposes, 'debug' should be set to 'false'
|
||||
// in order to catch unexpected types that should never end up in a type name
|
||||
pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
|
||||
match t.sty {
|
||||
ty::Bool => output.push_str("bool"),
|
||||
ty::Char => output.push_str("char"),
|
||||
@ -260,12 +267,12 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
ty::Float(ast::FloatTy::F64) => output.push_str("f64"),
|
||||
ty::Adt(adt_def, substs) => {
|
||||
self.push_def_path(adt_def.did, output);
|
||||
self.push_type_params(substs, iter::empty(), output);
|
||||
self.push_type_params(substs, iter::empty(), output, debug);
|
||||
},
|
||||
ty::Tuple(component_types) => {
|
||||
output.push('(');
|
||||
for &component_type in component_types {
|
||||
self.push_type_name(component_type, output);
|
||||
self.push_type_name(component_type, output, debug);
|
||||
output.push_str(", ");
|
||||
}
|
||||
if !component_types.is_empty() {
|
||||
@ -281,7 +288,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
hir::MutMutable => output.push_str("mut "),
|
||||
}
|
||||
|
||||
self.push_type_name(inner_type, output);
|
||||
self.push_type_name(inner_type, output, debug);
|
||||
},
|
||||
ty::Ref(_, inner_type, mutbl) => {
|
||||
output.push('&');
|
||||
@ -289,17 +296,17 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
output.push_str("mut ");
|
||||
}
|
||||
|
||||
self.push_type_name(inner_type, output);
|
||||
self.push_type_name(inner_type, output, debug);
|
||||
},
|
||||
ty::Array(inner_type, len) => {
|
||||
output.push('[');
|
||||
self.push_type_name(inner_type, output);
|
||||
self.push_type_name(inner_type, output, debug);
|
||||
write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
|
||||
output.push(']');
|
||||
},
|
||||
ty::Slice(inner_type) => {
|
||||
output.push('[');
|
||||
self.push_type_name(inner_type, output);
|
||||
self.push_type_name(inner_type, output, debug);
|
||||
output.push(']');
|
||||
},
|
||||
ty::Dynamic(ref trait_data, ..) => {
|
||||
@ -309,6 +316,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
principal.skip_binder().substs,
|
||||
trait_data.projection_bounds(),
|
||||
output,
|
||||
debug
|
||||
);
|
||||
} else {
|
||||
output.push_str("dyn '_");
|
||||
@ -338,7 +346,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
|
||||
if !sig.inputs().is_empty() {
|
||||
for ¶meter_type in sig.inputs() {
|
||||
self.push_type_name(parameter_type, output);
|
||||
self.push_type_name(parameter_type, output, debug);
|
||||
output.push_str(", ");
|
||||
}
|
||||
output.pop();
|
||||
@ -357,7 +365,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
|
||||
if !sig.output().is_unit() {
|
||||
output.push_str(" -> ");
|
||||
self.push_type_name(sig.output(), output);
|
||||
self.push_type_name(sig.output(), output, debug);
|
||||
}
|
||||
},
|
||||
ty::Generator(def_id, GeneratorSubsts { ref substs }, _) |
|
||||
@ -365,7 +373,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
self.push_def_path(def_id, output);
|
||||
let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
|
||||
let substs = substs.truncate_to(self.tcx, generics);
|
||||
self.push_type_params(substs, iter::empty(), output);
|
||||
self.push_type_params(substs, iter::empty(), output, debug);
|
||||
}
|
||||
ty::Error |
|
||||
ty::Bound(..) |
|
||||
@ -376,8 +384,12 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
ty::Param(_) |
|
||||
ty::GeneratorWitness(_) |
|
||||
ty::Opaque(..) => {
|
||||
bug!("DefPathBasedNames: Trying to create type name for \
|
||||
if debug {
|
||||
output.push_str(&format!("`{:?}`", t));
|
||||
} else {
|
||||
bug!("DefPathBasedNames: Trying to create type name for \
|
||||
unexpected type: {:?}", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -412,7 +424,8 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
fn push_type_params<I>(&self,
|
||||
substs: &Substs<'tcx>,
|
||||
projections: I,
|
||||
output: &mut String)
|
||||
output: &mut String,
|
||||
debug: bool)
|
||||
where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>>
|
||||
{
|
||||
let mut projections = projections.peekable();
|
||||
@ -423,7 +436,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
output.push('<');
|
||||
|
||||
for type_parameter in substs.types() {
|
||||
self.push_type_name(type_parameter, output);
|
||||
self.push_type_name(type_parameter, output, debug);
|
||||
output.push_str(", ");
|
||||
}
|
||||
|
||||
@ -432,7 +445,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str();
|
||||
output.push_str(name);
|
||||
output.push_str("=");
|
||||
self.push_type_name(projection.ty, output);
|
||||
self.push_type_name(projection.ty, output, debug);
|
||||
output.push_str(", ");
|
||||
}
|
||||
|
||||
@ -444,8 +457,9 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
|
||||
pub fn push_instance_as_string(&self,
|
||||
instance: Instance<'tcx>,
|
||||
output: &mut String) {
|
||||
output: &mut String,
|
||||
debug: bool) {
|
||||
self.push_def_path(instance.def_id(), output);
|
||||
self.push_type_params(instance.substs, iter::empty(), output);
|
||||
self.push_type_params(instance.substs, iter::empty(), output, debug);
|
||||
}
|
||||
}
|
||||
|
@ -879,7 +879,7 @@ fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
.unwrap_or("<no hash>");
|
||||
|
||||
debug!(" - {} [{:?}] [{}]",
|
||||
mono_item.to_string(tcx),
|
||||
mono_item.to_string(tcx, true),
|
||||
linkage,
|
||||
symbol_hash);
|
||||
}
|
||||
@ -971,7 +971,7 @@ fn collect_and_partition_mono_items<'a, 'tcx>(
|
||||
let mut item_keys: Vec<_> = items
|
||||
.iter()
|
||||
.map(|i| {
|
||||
let mut output = i.to_string(tcx);
|
||||
let mut output = i.to_string(tcx, false);
|
||||
output.push_str(" @@");
|
||||
let mut empty = Vec::new();
|
||||
let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
|
||||
|
253
src/test/ui/binop/binop-consume-args.nll.stderr
Normal file
253
src/test/ui/binop/binop-consume-args.nll.stderr
Normal file
@ -0,0 +1,253 @@
|
||||
error[E0382]: use of moved value: `lhs`
|
||||
--> $DIR/binop-consume-args.rs:7:10
|
||||
|
|
||||
LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs + rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `rhs`
|
||||
--> $DIR/binop-consume-args.rs:8:10
|
||||
|
|
||||
LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs + rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
LL | drop(rhs); //~ ERROR use of moved value: `rhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `lhs`
|
||||
--> $DIR/binop-consume-args.rs:13:10
|
||||
|
|
||||
LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs - rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `rhs`
|
||||
--> $DIR/binop-consume-args.rs:14:10
|
||||
|
|
||||
LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs - rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
LL | drop(rhs); //~ ERROR use of moved value: `rhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `lhs`
|
||||
--> $DIR/binop-consume-args.rs:19:10
|
||||
|
|
||||
LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs * rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `rhs`
|
||||
--> $DIR/binop-consume-args.rs:20:10
|
||||
|
|
||||
LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs * rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
LL | drop(rhs); //~ ERROR use of moved value: `rhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `lhs`
|
||||
--> $DIR/binop-consume-args.rs:25:10
|
||||
|
|
||||
LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs / rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `rhs`
|
||||
--> $DIR/binop-consume-args.rs:26:10
|
||||
|
|
||||
LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs / rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
LL | drop(rhs); //~ ERROR use of moved value: `rhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `lhs`
|
||||
--> $DIR/binop-consume-args.rs:31:10
|
||||
|
|
||||
LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs % rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `rhs`
|
||||
--> $DIR/binop-consume-args.rs:32:10
|
||||
|
|
||||
LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs % rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
LL | drop(rhs); //~ ERROR use of moved value: `rhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `lhs`
|
||||
--> $DIR/binop-consume-args.rs:37:10
|
||||
|
|
||||
LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs & rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `rhs`
|
||||
--> $DIR/binop-consume-args.rs:38:10
|
||||
|
|
||||
LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs & rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
LL | drop(rhs); //~ ERROR use of moved value: `rhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `lhs`
|
||||
--> $DIR/binop-consume-args.rs:43:10
|
||||
|
|
||||
LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs | rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `rhs`
|
||||
--> $DIR/binop-consume-args.rs:44:10
|
||||
|
|
||||
LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs | rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
LL | drop(rhs); //~ ERROR use of moved value: `rhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `lhs`
|
||||
--> $DIR/binop-consume-args.rs:49:10
|
||||
|
|
||||
LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs ^ rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `rhs`
|
||||
--> $DIR/binop-consume-args.rs:50:10
|
||||
|
|
||||
LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs ^ rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
LL | drop(rhs); //~ ERROR use of moved value: `rhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `lhs`
|
||||
--> $DIR/binop-consume-args.rs:55:10
|
||||
|
|
||||
LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs << rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `rhs`
|
||||
--> $DIR/binop-consume-args.rs:56:10
|
||||
|
|
||||
LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs << rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
LL | drop(rhs); //~ ERROR use of moved value: `rhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `lhs`
|
||||
--> $DIR/binop-consume-args.rs:61:10
|
||||
|
|
||||
LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs >> rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error[E0382]: use of moved value: `rhs`
|
||||
--> $DIR/binop-consume-args.rs:62:10
|
||||
|
|
||||
LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
|
||||
| - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | lhs >> rhs;
|
||||
| --- value moved here
|
||||
LL | drop(lhs); //~ ERROR use of moved value: `lhs`
|
||||
LL | drop(rhs); //~ ERROR use of moved value: `rhs`
|
||||
| ^^^ value used here after move
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
@ -1,24 +1,28 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/binop-move-semantics.rs:8:5
|
||||
|
|
||||
LL | fn double_move<T: Add<Output=()>>(x: T) {
|
||||
| - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | x
|
||||
| - value moved here
|
||||
LL | +
|
||||
LL | x; //~ ERROR: use of moved value
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `T`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/binop-move-semantics.rs:14:5
|
||||
|
|
||||
LL | fn move_then_borrow<T: Add<Output=()> + Clone>(x: T) {
|
||||
| - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | x
|
||||
| - value moved here
|
||||
LL | +
|
||||
LL | x.clone(); //~ ERROR: use of moved value
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `T`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0505]: cannot move out of `x` because it is borrowed
|
||||
--> $DIR/binop-move-semantics.rs:21:5
|
||||
|
@ -1,13 +1,14 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/borrowck-asm.rs:27:17
|
||||
|
|
||||
LL | let x = &mut 0isize;
|
||||
| - move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait
|
||||
LL | unsafe {
|
||||
LL | asm!("nop" : : "r"(x));
|
||||
| - value moved here
|
||||
LL | }
|
||||
LL | let z = x; //[ast]~ ERROR use of moved value: `x`
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0503]: cannot use `x` because it was mutably borrowed
|
||||
--> $DIR/borrowck-asm.rs:35:32
|
||||
@ -66,12 +67,13 @@ LL | let z = y;
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/borrowck-asm.rs:86:40
|
||||
|
|
||||
LL | let x = &mut 2;
|
||||
| - move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
|
||||
LL | unsafe {
|
||||
LL | asm!("nop" : : "r"(x), "r"(x) ); //[ast]~ ERROR use of moved value
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
= note: move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/borrowck-asm.rs:27:17
|
||||
|
|
||||
LL | let x = &mut 0isize;
|
||||
| - move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait
|
||||
LL | unsafe {
|
||||
LL | asm!("nop" : : "r"(x));
|
||||
| - value moved here
|
||||
LL | }
|
||||
LL | let z = x; //[ast]~ ERROR use of moved value: `x`
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0503]: cannot use `x` because it was mutably borrowed
|
||||
--> $DIR/borrowck-asm.rs:35:32
|
||||
@ -66,12 +67,13 @@ LL | let z = y;
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/borrowck-asm.rs:86:40
|
||||
|
|
||||
LL | let x = &mut 2;
|
||||
| - move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
|
||||
LL | unsafe {
|
||||
LL | asm!("nop" : : "r"(x), "r"(x) ); //[ast]~ ERROR use of moved value
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
= note: move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
13
src/test/ui/borrowck/borrowck-consume-unsize-vec.nll.stderr
Normal file
13
src/test/ui/borrowck/borrowck-consume-unsize-vec.nll.stderr
Normal file
@ -0,0 +1,13 @@
|
||||
error[E0382]: use of moved value: `b`
|
||||
--> $DIR/borrowck-consume-unsize-vec.rs:8:13
|
||||
|
|
||||
LL | fn foo(b: Box<[i32;5]>) {
|
||||
| - move occurs because `b` has type `std::boxed::Box<[i32; 5]>`, which does not implement the `Copy` trait
|
||||
LL | consume(b);
|
||||
| - value moved here
|
||||
LL | consume(b); //~ ERROR use of moved value
|
||||
| ^ value used here after move
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: use of moved value: `b`
|
||||
--> $DIR/borrowck-consume-upcast-box.rs:10:13
|
||||
|
|
||||
LL | fn foo(b: Box<Foo+Send>) {
|
||||
| - move occurs because `b` has type `std::boxed::Box<dyn Foo + std::marker::Send>`, which does not implement the `Copy` trait
|
||||
LL | consume(b);
|
||||
| - value moved here
|
||||
LL | consume(b); //~ ERROR use of moved value
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `b` has type `std::boxed::Box<dyn Foo + std::marker::Send>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
error[E0382]: use of moved value: `my_str`
|
||||
--> $DIR/borrowck-drop-from-guard.rs:11:23
|
||||
|
|
||||
LL | let my_str = "hello".to_owned();
|
||||
| ------ move occurs because `my_str` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | match Some(42) {
|
||||
LL | Some(_) if { drop(my_str); false } => {}
|
||||
| ------ value moved here
|
||||
LL | Some(_) => {}
|
||||
LL | None => { foo(my_str); } //~ ERROR [E0382]
|
||||
| ^^^^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `my_str` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,22 +1,22 @@
|
||||
error[E0382]: use of moved value: `src`
|
||||
--> $DIR/borrowck-issue-48962.rs:16:5
|
||||
|
|
||||
LL | let mut src = &mut node;
|
||||
| ------- move occurs because `src` has type `&mut Node`, which does not implement the `Copy` trait
|
||||
LL | {src};
|
||||
| --- value moved here
|
||||
LL | src.next = None; //~ ERROR use of moved value: `src` [E0382]
|
||||
| ^^^^^^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `src` has type `&mut Node`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `src`
|
||||
--> $DIR/borrowck-issue-48962.rs:22:5
|
||||
|
|
||||
LL | let mut src = &mut (22, 44);
|
||||
| ------- move occurs because `src` has type `&mut (i32, i32)`, which does not implement the `Copy` trait
|
||||
LL | {src};
|
||||
| --- value moved here
|
||||
LL | src.0 = 66; //~ ERROR use of moved value: `src` [E0382]
|
||||
| ^^^^^^^^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `src` has type `&mut (i32, i32)`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/borrowck-loan-in-overloaded-op.rs:21:20
|
||||
|
|
||||
LL | let x = Foo(box 3);
|
||||
| - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
|
||||
LL | let _y = {x} + x.clone(); // the `{x}` forces a move to occur
|
||||
| - ^ value borrowed here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
= note: move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/borrowck-move-moved-value-into-closure.rs:14:12
|
||||
|
|
||||
LL | let t: Box<_> = box 3;
|
||||
| - move occurs because `t` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
LL |
|
||||
LL | call_f(move|| { *t + 1 });
|
||||
| ------ - variable moved due to use in closure
|
||||
| |
|
||||
@ -9,8 +12,6 @@ LL | call_f(move|| { *t + 1 }); //[ast]~ ERROR capture of moved value
|
||||
| ^^^^^^ - use occurs due to use in closure
|
||||
| |
|
||||
| value used here after move
|
||||
|
|
||||
= note: move occurs because `t` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/borrowck-move-moved-value-into-closure.rs:14:12
|
||||
|
|
||||
LL | let t: Box<_> = box 3;
|
||||
| - move occurs because `t` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
LL |
|
||||
LL | call_f(move|| { *t + 1 });
|
||||
| ------ - variable moved due to use in closure
|
||||
| |
|
||||
@ -9,8 +12,6 @@ LL | call_f(move|| { *t + 1 }); //[ast]~ ERROR capture of moved value
|
||||
| ^^^^^^ - use occurs due to use in closure
|
||||
| |
|
||||
| value used here after move
|
||||
|
|
||||
= note: move occurs because `t` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -29,6 +29,8 @@ LL | borrow(&*p2);
|
||||
error[E0382]: use of moved value: `x1`
|
||||
--> $DIR/borrowck-multiple-captures.rs:25:19
|
||||
|
|
||||
LL | let x1: Box<_> = box 1;
|
||||
| -- move occurs because `x1` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
LL | drop(x1);
|
||||
| -- value moved here
|
||||
...
|
||||
@ -36,12 +38,12 @@ LL | thread::spawn(move|| {
|
||||
| ^^^^^^ value used here after move
|
||||
LL | drop(x1); //~ ERROR capture of moved value: `x1`
|
||||
| -- use occurs due to use in closure
|
||||
|
|
||||
= note: move occurs because `x1` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `x2`
|
||||
--> $DIR/borrowck-multiple-captures.rs:25:19
|
||||
|
|
||||
LL | let x2: Box<_> = box 2;
|
||||
| -- move occurs because `x2` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
LL | drop(x2);
|
||||
| -- value moved here
|
||||
LL | thread::spawn(move|| {
|
||||
@ -49,8 +51,6 @@ LL | thread::spawn(move|| {
|
||||
LL | drop(x1); //~ ERROR capture of moved value: `x1`
|
||||
LL | drop(x2); //~ ERROR capture of moved value: `x2`
|
||||
| -- use occurs due to use in closure
|
||||
|
|
||||
= note: move occurs because `x2` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/borrowck-multiple-captures.rs:36:14
|
||||
@ -88,14 +88,14 @@ LL | drop(x); //~ ERROR use of moved value: `x`
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/borrowck-multiple-captures.rs:44:19
|
||||
|
|
||||
LL | let x: Box<_> = box 1;
|
||||
| - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
LL | drop(x);
|
||||
| - value moved here
|
||||
LL | thread::spawn(move|| {
|
||||
| ^^^^^^ value used here after move
|
||||
LL | drop(x); //~ ERROR capture of moved value: `x`
|
||||
| - use occurs due to use in closure
|
||||
|
|
||||
= note: move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
@ -20,12 +20,13 @@ LL | s(3); //~ ERROR cannot borrow immutable local variable `s` as mutable
|
||||
error[E0382]: use of moved value: `s`
|
||||
--> $DIR/borrowck-overloaded-call.rs:75:5
|
||||
|
|
||||
LL | let s = SFnOnce {
|
||||
| - move occurs because `s` has type `SFnOnce`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | s(" world".to_string());
|
||||
| - value moved here
|
||||
LL | s(" world".to_string()); //~ ERROR use of moved value: `s`
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `s` has type `SFnOnce`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -25,13 +25,14 @@ LL | use_mut(rs);
|
||||
error[E0382]: use of moved value: `s`
|
||||
--> $DIR/borrowck-overloaded-index-move-index.rs:53:7
|
||||
|
|
||||
LL | let mut s = "hello".to_string();
|
||||
| ----- move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | println!("{}", f[s]);
|
||||
| - value moved here
|
||||
...
|
||||
LL | f[s] = 10;
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -1,22 +1,24 @@
|
||||
error[E0382]: assign of moved value: `t`
|
||||
--> $DIR/borrowck-partial-reinit-1.rs:27:5
|
||||
|
|
||||
LL | let mut t = Test2 { b: None };
|
||||
| ----- move occurs because `t` has type `Test2`, which does not implement the `Copy` trait
|
||||
LL | let u = Test;
|
||||
LL | drop(t);
|
||||
| - value moved here
|
||||
LL | t.b = Some(u);
|
||||
| ^^^ value assigned here after move
|
||||
|
|
||||
= note: move occurs because `t` has type `Test2`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: assign of moved value: `t`
|
||||
--> $DIR/borrowck-partial-reinit-1.rs:33:5
|
||||
|
|
||||
LL | let mut t = Test3(None);
|
||||
| ----- move occurs because `t` has type `Test3`, which does not implement the `Copy` trait
|
||||
LL | let u = Test;
|
||||
LL | drop(t);
|
||||
| - value moved here
|
||||
LL | t.0 = Some(u);
|
||||
| ^^^ value assigned here after move
|
||||
|
|
||||
= note: move occurs because `t` has type `Test3`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: assign of moved value: `t`
|
||||
--> $DIR/borrowck-partial-reinit-2.rs:15:5
|
||||
|
|
||||
LL | let mut t = Test { a: 1, b: None};
|
||||
| ----- move occurs because `t` has type `Test`, which does not implement the `Copy` trait
|
||||
LL | let mut u = Test { a: 2, b: Some(Box::new(t))};
|
||||
| - value moved here
|
||||
LL | t.b = Some(Box::new(u));
|
||||
| ^^^ value assigned here after move
|
||||
|
|
||||
= note: move occurs because `t` has type `Test`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -11,12 +11,13 @@ LL | let _ = (1,x); //~ ERROR use of moved value: `x` (Ast)
|
||||
error[E0382]: use of moved value: `x` (Mir)
|
||||
--> $DIR/borrowck-reinit.rs:8:16
|
||||
|
|
||||
LL | let mut x = Box::new(0);
|
||||
| ----- move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | drop(x);
|
||||
| - value moved here
|
||||
LL | let _ = (1,x); //~ ERROR use of moved value: `x` (Ast)
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -19,12 +19,14 @@ LL | f(1, 2); //~ ERROR cannot borrow immutable argument
|
||||
error[E0382]: use of moved value: `f`
|
||||
--> $DIR/borrowck-unboxed-closures.rs:12:5
|
||||
|
|
||||
LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
|
||||
| - - move occurs because `f` has type `F`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | f(1, 2);
|
||||
| - value moved here
|
||||
LL | f(1, 2); //~ ERROR use of moved value
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `f` has type `F`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: use of moved value: `u`
|
||||
--> $DIR/borrowck-union-move-assign.rs:17:21
|
||||
|
|
||||
LL | let mut u = U { a: A };
|
||||
| ----- move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
||||
LL | let a = u.a;
|
||||
| --- value moved here
|
||||
LL | let a = u.a; //~ ERROR use of moved value: `u.a`
|
||||
| ^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,62 +1,62 @@
|
||||
error[E0382]: use of moved value: `u`
|
||||
--> $DIR/borrowck-union-move.rs:26:21
|
||||
|
|
||||
LL | let mut u = Unn { n1: NonCopy };
|
||||
| ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
|
||||
LL | let a = u.n1;
|
||||
| ---- value moved here
|
||||
LL | let a = u.n1; //~ ERROR use of moved value: `u.n1`
|
||||
| ^^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `u`
|
||||
--> $DIR/borrowck-union-move.rs:31:21
|
||||
|
|
||||
LL | let mut u = Unn { n1: NonCopy };
|
||||
| ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
|
||||
LL | let a = u.n1;
|
||||
| ---- value moved here
|
||||
LL | let a = u; //~ ERROR use of partially moved value: `u`
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `u`
|
||||
--> $DIR/borrowck-union-move.rs:36:21
|
||||
|
|
||||
LL | let mut u = Unn { n1: NonCopy };
|
||||
| ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
|
||||
LL | let a = u.n1;
|
||||
| ---- value moved here
|
||||
LL | let a = u.n2; //~ ERROR use of moved value: `u.n2`
|
||||
| ^^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `u`
|
||||
--> $DIR/borrowck-union-move.rs:63:21
|
||||
|
|
||||
LL | let mut u = Ucn { c: Copy };
|
||||
| ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
|
||||
LL | let a = u.n;
|
||||
| --- value moved here
|
||||
LL | let a = u.n; //~ ERROR use of moved value: `u.n`
|
||||
| ^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `u`
|
||||
--> $DIR/borrowck-union-move.rs:68:21
|
||||
|
|
||||
LL | let mut u = Ucn { c: Copy };
|
||||
| ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
|
||||
LL | let a = u.n;
|
||||
| --- value moved here
|
||||
LL | let a = u.c; //~ ERROR use of moved value: `u.c`
|
||||
| ^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `u`
|
||||
--> $DIR/borrowck-union-move.rs:83:21
|
||||
|
|
||||
LL | let mut u = Ucn { c: Copy };
|
||||
| ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
|
||||
LL | let a = u.n;
|
||||
| --- value moved here
|
||||
LL | let a = u; //~ ERROR use of partially moved value: `u`
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
@ -1,32 +1,32 @@
|
||||
error[E0382]: assign to part of moved value: `t`
|
||||
--> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:23:9
|
||||
|
|
||||
LL | let mut t: Tuple = (S(0), 0);
|
||||
| ----- move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
|
||||
LL | drop(t);
|
||||
| - value moved here
|
||||
LL | t.0 = S(1);
|
||||
| ^^^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: assign to part of moved value: `u`
|
||||
--> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:34:9
|
||||
|
|
||||
LL | let mut u: Tpair = Tpair(S(0), 0);
|
||||
| ----- move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
|
||||
LL | drop(u);
|
||||
| - value moved here
|
||||
LL | u.0 = S(1);
|
||||
| ^^^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: assign to part of moved value: `v`
|
||||
--> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:45:9
|
||||
|
|
||||
LL | let mut v: Spair = Spair { x: S(0), y: 0 };
|
||||
| ----- move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
|
||||
LL | drop(v);
|
||||
| - value moved here
|
||||
LL | v.x = S(1);
|
||||
| ^^^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -10,12 +10,12 @@ LL | t.0 = S(1);
|
||||
error[E0382]: assign to part of moved value: `t`
|
||||
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:23:9
|
||||
|
|
||||
LL | let t: Tuple = (S(0), 0);
|
||||
| - move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
|
||||
LL | drop(t);
|
||||
| - value moved here
|
||||
LL | t.0 = S(1);
|
||||
| ^^^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0594]: cannot assign to `t.1`, as `t` is not declared as mutable
|
||||
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9
|
||||
@ -38,12 +38,12 @@ LL | u.0 = S(1);
|
||||
error[E0382]: assign to part of moved value: `u`
|
||||
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9
|
||||
|
|
||||
LL | let u: Tpair = Tpair(S(0), 0);
|
||||
| - move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
|
||||
LL | drop(u);
|
||||
| - value moved here
|
||||
LL | u.0 = S(1);
|
||||
| ^^^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable
|
||||
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:42:9
|
||||
@ -66,12 +66,12 @@ LL | v.x = S(1);
|
||||
error[E0382]: assign to part of moved value: `v`
|
||||
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:53:9
|
||||
|
|
||||
LL | let v: Spair = Spair { x: S(0), y: 0 };
|
||||
| - move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
|
||||
LL | drop(v);
|
||||
| - value moved here
|
||||
LL | v.x = S(1);
|
||||
| ^^^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable
|
||||
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:57:9
|
||||
|
@ -10,6 +10,8 @@ LL | f(f(10));
|
||||
error[E0382]: use of moved value: `*f`
|
||||
--> $DIR/two-phase-nonrecv-autoref.rs:69:11
|
||||
|
|
||||
LL | fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
|
||||
| - consider adding a `Copy` constraint to this type argument
|
||||
LL | f(f(10));
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
|
@ -10,6 +10,8 @@ LL | f(f(10));
|
||||
error[E0382]: use of moved value: `*f`
|
||||
--> $DIR/two-phase-nonrecv-autoref.rs:69:11
|
||||
|
|
||||
LL | fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
|
||||
| - consider adding a `Copy` constraint to this type argument
|
||||
LL | f(f(10));
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
|
@ -1,13 +1,13 @@
|
||||
error[E0382]: borrow of moved value: `some_vec`
|
||||
--> $DIR/tab_3.rs:7:20
|
||||
|
|
||||
LL | let some_vec = vec!["hi"];
|
||||
| -------- move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait
|
||||
LL | some_vec.into_iter();
|
||||
| -------- value moved here
|
||||
LL | {
|
||||
LL | println!("{:?}", some_vec); //~ ERROR use of moved
|
||||
| ^^^^^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
3
src/test/ui/issues/auxiliary/issue-56943.rs
Normal file
3
src/test/ui/issues/auxiliary/issue-56943.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub struct S;
|
||||
mod m { pub struct S; }
|
||||
pub use crate::m::S as S2;
|
@ -1,23 +1,23 @@
|
||||
error[E0382]: use of moved value: `foo`
|
||||
--> $DIR/issue-17385.rs:19:11
|
||||
|
|
||||
LL | let foo = X(1);
|
||||
| --- move occurs because `foo` has type `X`, which does not implement the `Copy` trait
|
||||
LL | drop(foo);
|
||||
| --- value moved here
|
||||
LL | match foo { //~ ERROR use of moved value
|
||||
LL | X(1) => (),
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `foo` has type `X`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `e`
|
||||
--> $DIR/issue-17385.rs:25:11
|
||||
|
|
||||
LL | let e = Enum::Variant2;
|
||||
| - move occurs because `e` has type `Enum`, which does not implement the `Copy` trait
|
||||
LL | drop(e);
|
||||
| - value moved here
|
||||
LL | match e { //~ ERROR use of moved value
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/issue-24357.rs:6:12
|
||||
|
|
||||
LL | let x = NoCopy;
|
||||
| - move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait
|
||||
LL | let f = move || { let y = x; };
|
||||
| ------- - variable moved due to use in closure
|
||||
| |
|
||||
@ -8,8 +10,6 @@ LL | let f = move || { let y = x; };
|
||||
LL | //~^ NOTE value moved (into closure) here
|
||||
LL | let z = x;
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
13
src/test/ui/issues/issue-25700.nll.stderr
Normal file
13
src/test/ui/issues/issue-25700.nll.stderr
Normal file
@ -0,0 +1,13 @@
|
||||
error[E0382]: use of moved value: `t`
|
||||
--> $DIR/issue-25700.rs:13:10
|
||||
|
|
||||
LL | let t = S::<()>(None);
|
||||
| - move occurs because `t` has type `S<()>`, which does not implement the `Copy` trait
|
||||
LL | drop(t);
|
||||
| - value moved here
|
||||
LL | drop(t); //~ ERROR use of moved value
|
||||
| ^ value used here after move
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
@ -1,6 +1,9 @@
|
||||
error[E0382]: use of moved value: `b`
|
||||
--> $DIR/issue-27282-move-match-input-into-guard.rs:18:14
|
||||
|
|
||||
LL | let b = &mut true;
|
||||
| - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | _ if { (|| { let bar = b; *bar = false; })();
|
||||
| -- - variable moved due to use in closure
|
||||
| |
|
||||
@ -8,8 +11,6 @@ LL | _ if { (|| { let bar = b; *bar = false; })();
|
||||
LL | false } => { },
|
||||
LL | &mut true => { println!("You might think we should get here"); },
|
||||
| ^^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
error[E0382]: use of moved value: `s`
|
||||
--> $DIR/issue-29723.rs:12:13
|
||||
|
|
||||
LL | let s = String::new();
|
||||
| - move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let _s = match 0 {
|
||||
LL | 0 if { drop(s); false } => String::from("oops"),
|
||||
| - value moved here
|
||||
...
|
||||
LL | s
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
34
src/test/ui/issues/issue-34721.rs
Normal file
34
src/test/ui/issues/issue-34721.rs
Normal file
@ -0,0 +1,34 @@
|
||||
#![feature(nll)]
|
||||
|
||||
pub trait Foo {
|
||||
fn zero(self) -> Self;
|
||||
}
|
||||
|
||||
impl Foo for u32 {
|
||||
fn zero(self) -> u32 { 0u32 }
|
||||
}
|
||||
|
||||
pub mod bar {
|
||||
pub use Foo;
|
||||
pub fn bar<T: Foo>(x: T) -> T {
|
||||
x.zero()
|
||||
}
|
||||
}
|
||||
|
||||
mod baz {
|
||||
use bar;
|
||||
use Foo;
|
||||
pub fn baz<T: Foo>(x: T) -> T {
|
||||
if 0 == 1 {
|
||||
bar::bar(x.zero())
|
||||
} else {
|
||||
x.zero()
|
||||
};
|
||||
x.zero()
|
||||
//~^ ERROR use of moved value
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = baz::baz(0u32);
|
||||
}
|
20
src/test/ui/issues/issue-34721.stderr
Normal file
20
src/test/ui/issues/issue-34721.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/issue-34721.rs:27:9
|
||||
|
|
||||
LL | pub fn baz<T: Foo>(x: T) -> T {
|
||||
| - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | if 0 == 1 {
|
||||
LL | bar::bar(x.zero())
|
||||
| - value moved here
|
||||
LL | } else {
|
||||
LL | x.zero()
|
||||
| - value moved here
|
||||
LL | };
|
||||
LL | x.zero()
|
||||
| ^ value used here after move
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
@ -1,13 +1,13 @@
|
||||
error[E0382]: borrow of moved value: `s`
|
||||
--> $DIR/issue-42796.rs:18:20
|
||||
|
|
||||
LL | let s = "Hello!".to_owned();
|
||||
| - move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let mut s_copy = s;
|
||||
| - value moved here
|
||||
...
|
||||
LL | println!("{}", s); //~ ERROR use of moved value
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
8
src/test/ui/issues/issue-56943.rs
Normal file
8
src/test/ui/issues/issue-56943.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// aux-build:issue-56943.rs
|
||||
|
||||
extern crate issue_56943;
|
||||
|
||||
fn main() {
|
||||
let _: issue_56943::S = issue_56943::S2;
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
}
|
12
src/test/ui/issues/issue-56943.stderr
Normal file
12
src/test/ui/issues/issue-56943.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-56943.rs:6:29
|
||||
|
|
||||
LL | let _: issue_56943::S = issue_56943::S2;
|
||||
| ^^^^^^^^^^^^^^^ expected struct `issue_56943::S`, found struct `issue_56943::S2`
|
||||
|
|
||||
= note: expected type `issue_56943::S`
|
||||
found type `issue_56943::S2`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -1,10 +1,11 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/liveness-move-call-arg.rs:9:14
|
||||
|
|
||||
LL | let x: Box<isize> = box 25;
|
||||
| - move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
LL | loop {
|
||||
LL | take(x); //~ ERROR use of moved value: `x`
|
||||
| ^ value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
error[E0382]: use of moved value: `y`
|
||||
--> $DIR/liveness-move-in-loop.rs:11:25
|
||||
|
|
||||
LL | let y: Box<isize> = box 42;
|
||||
| - move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | x = y; //~ ERROR use of moved value
|
||||
| ^ value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
error[E0382]: borrow of moved value: `y`
|
||||
--> $DIR/liveness-move-in-while.rs:7:24
|
||||
|
|
||||
LL | let y: Box<isize> = box 42;
|
||||
| - move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | println!("{}", y); //~ ERROR use of moved value: `y`
|
||||
| ^ value borrowed here after move
|
||||
LL | while true { while true { while true { x = y; x.clone(); } } }
|
||||
| - value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/liveness-use-after-move.rs:6:20
|
||||
|
|
||||
LL | let x: Box<_> = box 5;
|
||||
| - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
LL | let y = x;
|
||||
| - value moved here
|
||||
LL | println!("{}", *x); //~ ERROR use of moved value: `*x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: borrow of moved value: `message`
|
||||
--> $DIR/liveness-use-after-send.rs:16:20
|
||||
|
|
||||
LL | fn test00_start(ch: Chan<Box<isize>>, message: Box<isize>, _count: Box<isize>) {
|
||||
| ------- move occurs because `message` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
LL | send(ch, message);
|
||||
| ------- value moved here
|
||||
LL | println!("{}", message); //~ ERROR use of moved value: `message`
|
||||
| ^^^^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `message` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
14
src/test/ui/moves/move-guard-same-consts.nll.stderr
Normal file
14
src/test/ui/moves/move-guard-same-consts.nll.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/move-guard-same-consts.rs:20:24
|
||||
|
|
||||
LL | let x: Box<_> = box 1;
|
||||
| - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | (1, 2) if take(x) => (),
|
||||
| - value moved here
|
||||
LL | (1, 2) if take(x) => (), //~ ERROR use of moved value: `x`
|
||||
| ^ value used here after move
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
14
src/test/ui/moves/move-in-guard-1.nll.stderr
Normal file
14
src/test/ui/moves/move-in-guard-1.nll.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/move-in-guard-1.rs:10:24
|
||||
|
|
||||
LL | let x: Box<_> = box 1;
|
||||
| - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | (1, _) if take(x) => (),
|
||||
| - value moved here
|
||||
LL | (_, 2) if take(x) => (), //~ ERROR use of moved value: `x`
|
||||
| ^ value used here after move
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
@ -1,10 +1,11 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/move-in-guard-2.rs:10:24
|
||||
|
|
||||
LL | let x: Box<_> = box 1;
|
||||
| - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | (_, 2) if take(x) => (), //~ ERROR use of moved value: `x`
|
||||
| ^ value moved here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/move-into-dead-array-2.rs:14:5
|
||||
|
|
||||
LL | fn foo(mut a: [D; 4], i: usize) {
|
||||
| ----- move occurs because `a` has type `[D; 4]`, which does not implement the `Copy` trait
|
||||
LL | drop(a);
|
||||
| - value moved here
|
||||
LL | a[i] = d(); //~ ERROR use of moved value: `a`
|
||||
| ^^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `a` has type `[D; 4]`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-access-to-field.rs:11:12
|
||||
|
|
||||
LL | let x = vec!["hi".to_string()];
|
||||
| - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
|
||||
LL | consume(x.into_iter().next().unwrap());
|
||||
| - value moved here
|
||||
LL | touch(&x[0]); //~ ERROR use of moved value: `x`
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-capture-clause-bad.rs:8:20
|
||||
|
|
||||
LL | let x = "Hello world!".to_string();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | thread::spawn(move|| {
|
||||
| ------ value moved into closure here
|
||||
LL | println!("{}", x);
|
||||
@ -8,8 +10,6 @@ LL | println!("{}", x);
|
||||
LL | });
|
||||
LL | println!("{}", x); //~ ERROR use of moved value
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,24 +1,24 @@
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:11:11
|
||||
|
|
||||
LL | let x = "hi".to_string();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let _y = Foo { f:x };
|
||||
| - value moved here
|
||||
LL | //~^ NOTE value moved here
|
||||
LL | touch(&x); //~ ERROR use of moved value: `x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:20:11
|
||||
|
|
||||
LL | let x = "hi".to_string();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let _y = Foo { f:(((x))) };
|
||||
| ------- value moved here
|
||||
LL | //~^ NOTE value moved here
|
||||
LL | touch(&x); //~ ERROR use of moved value: `x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -1,117 +1,122 @@
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-exprs.rs:12:11
|
||||
|
|
||||
LL | let x = "hi".to_string();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let _y = Foo { f:x };
|
||||
| - value moved here
|
||||
LL | touch(&x); //~ ERROR use of moved value: `x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-exprs.rs:18:11
|
||||
|
|
||||
LL | let x = "hi".to_string();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let _y = (x, 3);
|
||||
| - value moved here
|
||||
LL | touch(&x); //~ ERROR use of moved value: `x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-exprs.rs:35:11
|
||||
|
|
||||
LL | let x = "hi".to_string();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | x
|
||||
| - value moved here
|
||||
...
|
||||
LL | touch(&x); //~ ERROR use of moved value: `x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `y`
|
||||
--> $DIR/moves-based-on-type-exprs.rs:36:11
|
||||
|
|
||||
LL | let y = "ho".to_string();
|
||||
| - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | y
|
||||
| - value moved here
|
||||
...
|
||||
LL | touch(&y); //~ ERROR use of moved value: `y`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-exprs.rs:46:11
|
||||
|
|
||||
LL | let x = "hi".to_string();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | true => x,
|
||||
| - value moved here
|
||||
...
|
||||
LL | touch(&x); //~ ERROR use of moved value: `x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `y`
|
||||
--> $DIR/moves-based-on-type-exprs.rs:47:11
|
||||
|
|
||||
LL | let y = "ho".to_string();
|
||||
| - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | false => y
|
||||
| - value moved here
|
||||
...
|
||||
LL | touch(&y); //~ ERROR use of moved value: `y`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-exprs.rs:58:11
|
||||
|
|
||||
LL | let x = "hi".to_string();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | _ if guard(x) => 10,
|
||||
| - value moved here
|
||||
...
|
||||
LL | touch(&x); //~ ERROR use of moved value: `x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-exprs.rs:65:11
|
||||
|
|
||||
LL | let x = "hi".to_string();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let _y = [x];
|
||||
| - value moved here
|
||||
LL | touch(&x); //~ ERROR use of moved value: `x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-exprs.rs:71:11
|
||||
|
|
||||
LL | let x = "hi".to_string();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let _y = vec![x];
|
||||
| - value moved here
|
||||
LL | touch(&x); //~ ERROR use of moved value: `x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-exprs.rs:77:11
|
||||
|
|
||||
LL | let x = vec!["hi".to_string()];
|
||||
| - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
|
||||
LL | let _y = x.into_iter().next().unwrap();
|
||||
| - value moved here
|
||||
LL | touch(&x); //~ ERROR use of moved value: `x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/moves-based-on-type-exprs.rs:83:11
|
||||
|
|
||||
LL | let x = vec!["hi".to_string()];
|
||||
| - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
|
||||
LL | let _y = [x.into_iter().next().unwrap(); 1];
|
||||
| - value moved here
|
||||
LL | touch(&x); //~ ERROR use of moved value: `x`
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
|
@ -10,12 +10,14 @@ LL | (f.c)(f, true);
|
||||
error[E0382]: borrow of moved value: `f`
|
||||
--> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:32:5
|
||||
|
|
||||
LL | fn conspirator<F>(mut f: F) where F: FnMut(&mut R, bool) {
|
||||
| - ----- move occurs because `f` has type `F`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | let mut r = R {c: Box::new(f)};
|
||||
| - value moved here
|
||||
LL | f(&mut r, false) //~ ERROR use of moved value
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `f` has type `F`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -11,12 +11,12 @@ LL | box (x, x)
|
||||
error[E0382]: use of moved value: `x` (Mir)
|
||||
--> $DIR/moves-based-on-type-tuple.rs:6:13
|
||||
|
|
||||
LL | fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> {
|
||||
| - move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
LL | box (x, x)
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
= note: move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -59,50 +59,50 @@ LL | r.use_ref();
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/closure-access-spans.rs:37:5
|
||||
|
|
||||
LL | fn closure_imm_capture_moved(mut x: String) {
|
||||
| ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let r = x;
|
||||
| - value moved here
|
||||
LL | || x.len(); //~ ERROR
|
||||
| ^^ - borrow occurs due to use in closure
|
||||
| |
|
||||
| value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/closure-access-spans.rs:42:5
|
||||
|
|
||||
LL | fn closure_mut_capture_moved(mut x: String) {
|
||||
| ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let r = x;
|
||||
| - value moved here
|
||||
LL | || x = String::new(); //~ ERROR
|
||||
| ^^ - borrow occurs due to use in closure
|
||||
| |
|
||||
| value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/closure-access-spans.rs:47:5
|
||||
|
|
||||
LL | fn closure_unique_capture_moved(x: &mut String) {
|
||||
| - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let r = x;
|
||||
| - value moved here
|
||||
LL | || *x = String::new(); //~ ERROR
|
||||
| ^^ - borrow occurs due to use in closure
|
||||
| |
|
||||
| value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/closure-access-spans.rs:52:5
|
||||
|
|
||||
LL | fn closure_move_capture_moved(x: &mut String) {
|
||||
| - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let r = x;
|
||||
| - value moved here
|
||||
LL | || x; //~ ERROR
|
||||
| ^^ - use occurs due to use in closure
|
||||
| |
|
||||
| value used here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
@ -1,38 +1,38 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/closure-move-spans.rs:7:13
|
||||
|
|
||||
LL | fn move_after_move(x: String) {
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | || x;
|
||||
| -- - variable moved due to use in closure
|
||||
| |
|
||||
| value moved into closure here
|
||||
LL | let y = x; //~ ERROR
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/closure-move-spans.rs:12:13
|
||||
|
|
||||
LL | fn borrow_after_move(x: String) {
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | || x;
|
||||
| -- - variable moved due to use in closure
|
||||
| |
|
||||
| value moved into closure here
|
||||
LL | let y = &x; //~ ERROR
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/closure-move-spans.rs:17:13
|
||||
|
|
||||
LL | fn borrow_mut_after_move(mut x: String) {
|
||||
| ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | || x;
|
||||
| -- - variable moved due to use in closure
|
||||
| |
|
||||
| value moved into closure here
|
||||
LL | let y = &mut x; //~ ERROR
|
||||
| ^^^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/closures-in-loops.rs:8:9
|
||||
|
|
||||
LL | fn repreated_move(x: String) {
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | for i in 0..10 {
|
||||
LL | || x; //~ ERROR
|
||||
| ^^ - use occurs due to use in closure
|
||||
| |
|
||||
| value moved into closure here, in previous iteration of loop
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0499]: cannot borrow `x` as mutable more than once at a time
|
||||
--> $DIR/closures-in-loops.rs:15:16
|
||||
|
@ -13,12 +13,12 @@ LL | d.x = 10;
|
||||
error[E0382]: assign of moved value: `d`
|
||||
--> $DIR/issue-21232-partial-init-and-erroneous-use.rs:43:5
|
||||
|
|
||||
LL | let mut d = D { x: 0, s: S{ y: 0, z: 0 } };
|
||||
| ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
|
||||
LL | drop(d);
|
||||
| - value moved here
|
||||
LL | d.x = 10;
|
||||
| ^^^^^^^^ value assigned here after move
|
||||
|
|
||||
= note: move occurs because `d` has type `D`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0381]: assign to part of possibly uninitialized variable: `d`
|
||||
--> $DIR/issue-21232-partial-init-and-erroneous-use.rs:49:5
|
||||
@ -35,12 +35,12 @@ LL | d.s.y = 20;
|
||||
error[E0382]: assign to part of moved value: `d`
|
||||
--> $DIR/issue-21232-partial-init-and-erroneous-use.rs:62:5
|
||||
|
|
||||
LL | let mut d = D { x: 0, s: S{ y: 0, z: 0} };
|
||||
| ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
|
||||
LL | drop(d);
|
||||
| - value moved here
|
||||
LL | d.s.y = 20;
|
||||
| ^^^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `d` has type `D`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
@ -14,21 +14,21 @@ error[E0382]: assign to part of moved value: `s`
|
||||
--> $DIR/issue-21232-partial-init-and-use.rs:113:5
|
||||
|
|
||||
LL | let mut s: S<B> = S::new(); drop(s);
|
||||
| - value moved here
|
||||
| ----- - value moved here
|
||||
| |
|
||||
| move occurs because `s` has type `S<std::boxed::Box<u32>>`, which does not implement the `Copy` trait
|
||||
LL | s.x = 10; s.y = Box::new(20);
|
||||
| ^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `s` has type `S<std::boxed::Box<u32>>`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: assign to part of moved value: `t`
|
||||
--> $DIR/issue-21232-partial-init-and-use.rs:120:5
|
||||
|
|
||||
LL | let mut t: T = (0, Box::new(0)); drop(t);
|
||||
| - value moved here
|
||||
| ----- - value moved here
|
||||
| |
|
||||
| move occurs because `t` has type `(u32, std::boxed::Box<u32>)`, which does not implement the `Copy` trait
|
||||
LL | t.0 = 10; t.1 = Box::new(20);
|
||||
| ^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `t` has type `(u32, std::boxed::Box<u32>)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0381]: assign to part of possibly uninitialized variable: `s`
|
||||
--> $DIR/issue-21232-partial-init-and-use.rs:127:5
|
||||
@ -46,21 +46,21 @@ error[E0382]: assign to part of moved value: `s`
|
||||
--> $DIR/issue-21232-partial-init-and-use.rs:141:5
|
||||
|
|
||||
LL | let mut s: S<B> = S::new(); drop(s);
|
||||
| - value moved here
|
||||
| ----- - value moved here
|
||||
| |
|
||||
| move occurs because `s` has type `S<std::boxed::Box<u32>>`, which does not implement the `Copy` trait
|
||||
LL | s.x = 10;
|
||||
| ^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `s` has type `S<std::boxed::Box<u32>>`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: assign to part of moved value: `t`
|
||||
--> $DIR/issue-21232-partial-init-and-use.rs:148:5
|
||||
|
|
||||
LL | let mut t: T = (0, Box::new(0)); drop(t);
|
||||
| - value moved here
|
||||
| ----- - value moved here
|
||||
| |
|
||||
| move occurs because `t` has type `(u32, std::boxed::Box<u32>)`, which does not implement the `Copy` trait
|
||||
LL | t.0 = 10;
|
||||
| ^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `t` has type `(u32, std::boxed::Box<u32>)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0381]: assign to part of possibly uninitialized variable: `s`
|
||||
--> $DIR/issue-21232-partial-init-and-use.rs:155:5
|
||||
@ -153,22 +153,24 @@ LL | q.r.f.0 = 10;
|
||||
error[E0382]: assign to part of moved value: `c`
|
||||
--> $DIR/issue-21232-partial-init-and-use.rs:259:13
|
||||
|
|
||||
LL | let mut c = (1, "".to_owned());
|
||||
| ----- move occurs because `c` has type `(i32, std::string::String)`, which does not implement the `Copy` trait
|
||||
LL | match c {
|
||||
LL | c2 => {
|
||||
| -- value moved here
|
||||
LL | c.0 = 2; //~ ERROR assign to part of moved value
|
||||
| ^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `c` has type `(i32, std::string::String)`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: assign to part of moved value: `c`
|
||||
--> $DIR/issue-21232-partial-init-and-use.rs:269:13
|
||||
|
|
||||
LL | let mut c = (1, (1, "".to_owned()));
|
||||
| ----- move occurs because `c` has type `(i32, (i32, std::string::String))`, which does not implement the `Copy` trait
|
||||
LL | match c {
|
||||
LL | c2 => {
|
||||
| -- value moved here
|
||||
LL | (c.1).0 = 2; //~ ERROR assign to part of moved value
|
||||
| ^^^^^^^^^^^ value partially assigned here after move
|
||||
|
|
||||
= note: move occurs because `c` has type `(i32, (i32, std::string::String))`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: assign to part of moved value: `c.1`
|
||||
--> $DIR/issue-21232-partial-init-and-use.rs:277:13
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: use of moved value: `range`
|
||||
--> $DIR/issue-51512.rs:7:13
|
||||
|
|
||||
LL | let range = 0..1;
|
||||
| ----- move occurs because `range` has type `std::ops::Range<i32>`, which does not implement the `Copy` trait
|
||||
LL | let r = range;
|
||||
| ----- value moved here
|
||||
LL | let x = range.start;
|
||||
| ^^^^^^^^^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `range` has type `std::ops::Range<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
error[E0382]: borrow of moved value: `a.b`
|
||||
--> $DIR/issue-52669.rs:15:5
|
||||
|
|
||||
LL | fn bar(mut a: A) -> B {
|
||||
| ----- move occurs because `a` has type `A`, which does not implement the `Copy` trait
|
||||
LL | a.b = B;
|
||||
LL | foo(a);
|
||||
| - value moved here
|
||||
LL | a.b.clone()
|
||||
| ^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `a` has type `A`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
error[E0382]: borrow of moved value: `arc_v`
|
||||
--> $DIR/no-capture-arc.rs:14:18
|
||||
|
|
||||
LL | let arc_v = Arc::new(v);
|
||||
| ----- move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
|
||||
LL |
|
||||
LL | thread::spawn(move|| {
|
||||
| ------ value moved into closure here
|
||||
LL | assert_eq!((*arc_v)[3], 4);
|
||||
@ -8,8 +11,6 @@ LL | assert_eq!((*arc_v)[3], 4);
|
||||
...
|
||||
LL | assert_eq!((*arc_v)[2], 3);
|
||||
| ^^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
error[E0382]: borrow of moved value: `arc_v`
|
||||
--> $DIR/no-reuse-move-arc.rs:12:18
|
||||
|
|
||||
LL | let arc_v = Arc::new(v);
|
||||
| ----- move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
|
||||
LL |
|
||||
LL | thread::spawn(move|| {
|
||||
| ------ value moved into closure here
|
||||
LL | assert_eq!((*arc_v)[3], 4);
|
||||
@ -8,8 +11,6 @@ LL | assert_eq!((*arc_v)[3], 4);
|
||||
...
|
||||
LL | assert_eq!((*arc_v)[2], 3); //~ ERROR use of moved value: `arc_v`
|
||||
| ^^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
15
src/test/ui/once-cant-call-twice-on-heap.nll.stderr
Normal file
15
src/test/ui/once-cant-call-twice-on-heap.nll.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error[E0382]: use of moved value: `blk`
|
||||
--> $DIR/once-cant-call-twice-on-heap.rs:9:5
|
||||
|
|
||||
LL | fn foo<F:FnOnce()>(blk: F) {
|
||||
| - --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | blk();
|
||||
| --- value moved here
|
||||
LL | blk(); //~ ERROR use of moved value
|
||||
| ^^^ value used here after move
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
@ -1,22 +1,22 @@
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/ref-suggestion.rs:4:5
|
||||
|
|
||||
LL | let x = vec![1];
|
||||
| - move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
|
||||
LL | let y = x;
|
||||
| - value moved here
|
||||
LL | x; //~ ERROR use of moved value
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/ref-suggestion.rs:8:5
|
||||
|
|
||||
LL | let x = vec![1];
|
||||
| - move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
|
||||
LL | let mut y = x;
|
||||
| - value moved here
|
||||
LL | x; //~ ERROR use of moved value
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/ref-suggestion.rs:16:5
|
||||
|
@ -1,12 +1,13 @@
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/dbg-macro-move-semantics.rs:9:18
|
||||
|
|
||||
LL | let a = NoCopy(0);
|
||||
| - move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait
|
||||
LL | let _ = dbg!(a);
|
||||
| ------- value moved here
|
||||
LL | let _ = dbg!(a); //~ ERROR use of moved value
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -25,13 +25,14 @@ LL | ::std::mem::drop(k); //~ ERROR use of moved value: `k`
|
||||
error[E0382]: use of moved value: `k`
|
||||
--> $DIR/try-block-bad-lifetime.rs:31:26
|
||||
|
|
||||
LL | let k = &mut i;
|
||||
| - move occurs because `k` has type `&mut i32`, which does not implement the `Copy` trait
|
||||
LL | let mut j: Result<(), &mut i32> = try {
|
||||
LL | Err(k) ?;
|
||||
| - value moved here
|
||||
...
|
||||
LL | ::std::mem::drop(k); //~ ERROR use of moved value: `k`
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `k` has type `&mut i32`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0506]: cannot assign to `i` because it is borrowed
|
||||
--> $DIR/try-block-bad-lifetime.rs:32:9
|
||||
|
@ -13,13 +13,14 @@ LL | do_something_with(x);
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/try-block-maybe-bad-lifetime.rs:28:24
|
||||
|
|
||||
LL | let x = String::new();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | ::std::mem::drop(x);
|
||||
| - value moved here
|
||||
LL | };
|
||||
LL | println!("{}", x); //~ ERROR borrow of moved value: `x`
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0506]: cannot assign to `i` because it is borrowed
|
||||
--> $DIR/try-block-maybe-bad-lifetime.rs:40:9
|
||||
|
@ -13,12 +13,12 @@ LL | use_borrow(a);
|
||||
error[E0382]: use of moved value: `u`
|
||||
--> $DIR/union-borrow-move-parent-sibling.rs:22:13
|
||||
|
|
||||
LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
|
||||
| - move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
||||
LL | let a = u.x.0;
|
||||
| ----- value moved here
|
||||
LL | let b = u.y; //~ ERROR use of moved value: `u.y`
|
||||
| ^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`)
|
||||
--> $DIR/union-borrow-move-parent-sibling.rs:28:13
|
||||
@ -35,12 +35,12 @@ LL | use_borrow(a);
|
||||
error[E0382]: use of moved value: `u`
|
||||
--> $DIR/union-borrow-move-parent-sibling.rs:35:13
|
||||
|
|
||||
LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
|
||||
| - move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
||||
LL | let a = (u.x.0).0;
|
||||
| --------- value moved here
|
||||
LL | let b = u.y; //~ ERROR use of moved value: `u.y`
|
||||
| ^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `*u.y`)
|
||||
--> $DIR/union-borrow-move-parent-sibling.rs:41:13
|
||||
@ -57,12 +57,12 @@ LL | use_borrow(a);
|
||||
error[E0382]: use of moved value: `u`
|
||||
--> $DIR/union-borrow-move-parent-sibling.rs:48:13
|
||||
|
|
||||
LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
|
||||
| - move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
||||
LL | let a = *u.y;
|
||||
| ---- value moved here
|
||||
LL | let b = u.x; //~ ERROR use of moved value: `u.x`
|
||||
| ^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
@ -1,13 +1,15 @@
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/unop-move-semantics.rs:8:5
|
||||
|
|
||||
LL | fn move_then_borrow<T: Not<Output=T> + Clone>(x: T) {
|
||||
| - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
|
||||
| |
|
||||
| consider adding a `Copy` constraint to this type argument
|
||||
LL | !x;
|
||||
| - value moved here
|
||||
LL |
|
||||
LL | x.clone(); //~ ERROR: use of moved value
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `T`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0505]: cannot move out of `x` because it is borrowed
|
||||
--> $DIR/unop-move-semantics.rs:15:6
|
||||
|
@ -12,13 +12,13 @@ LL | println!("{}", &x);
|
||||
error[E0382]: borrow of moved value: `y`
|
||||
--> $DIR/borrow-after-move.rs:22:24
|
||||
|
|
||||
LL | let y = *x;
|
||||
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
|
||||
LL | drop_unsized(y);
|
||||
| - value moved here
|
||||
...
|
||||
LL | println!("{}", &y);
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/borrow-after-move.rs:30:24
|
||||
@ -34,13 +34,13 @@ LL | println!("{}", &x);
|
||||
error[E0382]: borrow of moved value: `y`
|
||||
--> $DIR/borrow-after-move.rs:32:24
|
||||
|
|
||||
LL | let y = *x;
|
||||
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
|
||||
LL | y.foo();
|
||||
| - value moved here
|
||||
...
|
||||
LL | println!("{}", &y);
|
||||
| ^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/borrow-after-move.rs:39:24
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: use of moved value: `y`
|
||||
--> $DIR/double-move.rs:20:22
|
||||
|
|
||||
LL | let y = *x;
|
||||
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
|
||||
LL | drop_unsized(y);
|
||||
| - value moved here
|
||||
LL | drop_unsized(y); //~ERROR use of moved value
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `x`
|
||||
--> $DIR/double-move.rs:26:22
|
||||
@ -21,22 +21,22 @@ LL | drop_unsized(x); //~ERROR use of moved value
|
||||
error[E0382]: use of moved value: `*x`
|
||||
--> $DIR/double-move.rs:32:18
|
||||
|
|
||||
LL | let x = "hello".to_owned().into_boxed_str();
|
||||
| - move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait
|
||||
LL | drop_unsized(x);
|
||||
| - value moved here
|
||||
LL | let _y = *x; //~ERROR use of moved value
|
||||
| ^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `y`
|
||||
--> $DIR/double-move.rs:39:9
|
||||
|
|
||||
LL | let y = *x;
|
||||
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
|
||||
LL | y.foo();
|
||||
| - value moved here
|
||||
LL | y.foo(); //~ERROR use of moved value
|
||||
| ^ value used here after move
|
||||
|
|
||||
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
|
||||
|
||||
error[E0382]: use of moved value: `*x`
|
||||
--> $DIR/double-move.rs:45:9
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: borrow of moved value: `x`
|
||||
--> $DIR/use-after-move-based-on-type.rs:4:20
|
||||
|
|
||||
LL | let x = "Hello!".to_string();
|
||||
| - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
LL | let _y = x;
|
||||
| - value moved here
|
||||
LL | println!("{}", x); //~ ERROR use of moved value
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
error[E0382]: borrow of moved value: `n`
|
||||
--> $DIR/use-after-move-implicity-coerced-object.rs:28:13
|
||||
|
|
||||
LL | let n: Box<_> = box Number { n: 42 };
|
||||
| - move occurs because `n` has type `std::boxed::Box<Number>`, which does not implement the `Copy` trait
|
||||
LL | let mut l: Box<_> = box List { list: Vec::new() };
|
||||
LL | l.push(n);
|
||||
| - value moved here
|
||||
LL | let x = n.to_string();
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `n` has type `std::boxed::Box<Number>`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: use of moved value: `self`
|
||||
--> $DIR/use-after-move-self-based-on-type.rs:12:16
|
||||
|
|
||||
LL | pub fn foo(self) -> isize {
|
||||
| ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait
|
||||
LL | self.bar();
|
||||
| ---- value moved here
|
||||
LL | return self.x; //~ ERROR use of moved value: `self.x`
|
||||
| ^^^^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `self` has type `S`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: use of moved value: `self`
|
||||
--> $DIR/use-after-move-self.rs:10:16
|
||||
|
|
||||
LL | pub fn foo(self) -> isize {
|
||||
| ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait
|
||||
LL | self.bar();
|
||||
| ---- value moved here
|
||||
LL | return *self.x; //~ ERROR use of moved value: `*self.x`
|
||||
| ^^^^^^^ value used here after move
|
||||
|
|
||||
= note: move occurs because `self` has type `S`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0382]: borrow of moved value: `start`
|
||||
--> $DIR/walk-struct-literal-with.rs:16:20
|
||||
|
|
||||
LL | let start = Mine{test:"Foo".to_string(), other_val:0};
|
||||
| ----- move occurs because `start` has type `Mine`, which does not implement the `Copy` trait
|
||||
LL | let end = Mine{other_val:1, ..start.make_string_bar()};
|
||||
| ----- value moved here
|
||||
LL | println!("{}", start.test); //~ ERROR use of moved value: `start.test`
|
||||
| ^^^^^^^^^^ value borrowed here after move
|
||||
|
|
||||
= note: move occurs because `start` has type `Mine`, which does not implement the `Copy` trait
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user