about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-01-25 01:18:13 +0000
committerbors <bors@rust-lang.org>2019-01-25 01:18:13 +0000
commita41ade7bc37360db40ab3111ce95acdfd9d0bcb3 (patch)
treeed703bb2e268afcba45781c78f06fce045a0c086 /src
parent278067d34d1535a840cf9c99bcb8b538bf5b109a (diff)
parenta6fa7de8e7e06b132ecda6945746a416a972c763 (diff)
downloadrust-a41ade7bc37360db40ab3111ce95acdfd9d0bcb3.tar.gz
rust-a41ade7bc37360db40ab3111ce95acdfd9d0bcb3.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/README.md1
-rw-r--r--src/libcore/num/dec2flt/mod.rs26
-rw-r--r--src/librustc/infer/higher_ranked/README.md407
-rw-r--r--src/librustc/infer/lexical_region_resolve/README.md4
-rw-r--r--src/librustc/infer/region_constraints/README.md76
-rw-r--r--src/librustc/ty/item_path.rs28
-rw-r--r--src/librustc/ty/query/README.md303
-rw-r--r--src/librustc_codegen_llvm/type_of.rs2
-rw-r--r--src/librustc_codegen_ssa/mono_item.rs8
-rw-r--r--src/librustc_data_structures/obligation_forest/README.md81
-rw-r--r--src/librustc_data_structures/obligation_forest/mod.rs85
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs41
-rw-r--r--src/librustc_mir/monomorphize/collector.rs4
-rw-r--r--src/librustc_mir/monomorphize/item.rs56
-rw-r--r--src/librustc_mir/monomorphize/partitioning.rs4
-rw-r--r--src/test/ui/binop/binop-consume-args.nll.stderr253
-rw-r--r--src/test/ui/binop/binop-move-semantics.nll.stderr12
-rw-r--r--src/test/ui/borrowck/borrowck-asm.ast.nll.stderr10
-rw-r--r--src/test/ui/borrowck/borrowck-asm.mir.stderr10
-rw-r--r--src/test/ui/borrowck/borrowck-consume-unsize-vec.nll.stderr13
-rw-r--r--src/test/ui/borrowck/borrowck-consume-upcast-box.nll.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-drop-from-guard.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-issue-48962.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-loan-in-overloaded-op.nll.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-move-moved-value-into-closure.ast.nll.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-move-moved-value-into-closure.mir.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr12
-rw-r--r--src/test/ui/borrowck/borrowck-overloaded-call.nll.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-overloaded-index-move-index.nll.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-partial-reinit-1.nll.stderr10
-rw-r--r--src/test/ui/borrowck/borrowck-partial-reinit-2.nll.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-reinit.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-unboxed-closures.nll.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-union-move-assign.nll.stderr4
-rw-r--r--src/test/ui/borrowck/borrowck-union-move.nll.stderr24
-rw-r--r--src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.nll.stderr12
-rw-r--r--src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.nll.stderr12
-rw-r--r--src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr2
-rw-r--r--src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr2
-rw-r--r--src/test/ui/codemap_tests/tab_3.nll.stderr4
-rw-r--r--src/test/ui/issues/auxiliary/issue-56943.rs3
-rw-r--r--src/test/ui/issues/issue-17385.nll.stderr8
-rw-r--r--src/test/ui/issues/issue-24357.nll.stderr4
-rw-r--r--src/test/ui/issues/issue-25700.nll.stderr13
-rw-r--r--src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr5
-rw-r--r--src/test/ui/issues/issue-29723.stderr5
-rw-r--r--src/test/ui/issues/issue-34721.rs34
-rw-r--r--src/test/ui/issues/issue-34721.stderr20
-rw-r--r--src/test/ui/issues/issue-42796.nll.stderr4
-rw-r--r--src/test/ui/issues/issue-56943.rs8
-rw-r--r--src/test/ui/issues/issue-56943.stderr12
-rw-r--r--src/test/ui/liveness/liveness-move-call-arg.nll.stderr5
-rw-r--r--src/test/ui/liveness/liveness-move-in-loop.nll.stderr5
-rw-r--r--src/test/ui/liveness/liveness-move-in-while.nll.stderr5
-rw-r--r--src/test/ui/liveness/liveness-use-after-move.nll.stderr4
-rw-r--r--src/test/ui/liveness/liveness-use-after-send.nll.stderr4
-rw-r--r--src/test/ui/moves/move-guard-same-consts.nll.stderr14
-rw-r--r--src/test/ui/moves/move-in-guard-1.nll.stderr14
-rw-r--r--src/test/ui/moves/move-in-guard-2.nll.stderr5
-rw-r--r--src/test/ui/moves/move-into-dead-array-2.nll.stderr4
-rw-r--r--src/test/ui/moves/moves-based-on-type-access-to-field.nll.stderr4
-rw-r--r--src/test/ui/moves/moves-based-on-type-capture-clause-bad.nll.stderr4
-rw-r--r--src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.nll.stderr8
-rw-r--r--src/test/ui/moves/moves-based-on-type-exprs.nll.stderr49
-rw-r--r--src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.nll.stderr6
-rw-r--r--src/test/ui/moves/moves-based-on-type-tuple.stderr4
-rw-r--r--src/test/ui/nll/closure-access-spans.stderr16
-rw-r--r--src/test/ui/nll/closure-move-spans.stderr12
-rw-r--r--src/test/ui/nll/closures-in-loops.stderr5
-rw-r--r--src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr8
-rw-r--r--src/test/ui/nll/issue-21232-partial-init-and-use.stderr34
-rw-r--r--src/test/ui/nll/issue-51512.stderr4
-rw-r--r--src/test/ui/nll/issue-52669.stderr5
-rw-r--r--src/test/ui/no-capture-arc.nll.stderr5
-rw-r--r--src/test/ui/no-reuse-move-arc.nll.stderr5
-rw-r--r--src/test/ui/once-cant-call-twice-on-heap.nll.stderr15
-rw-r--r--src/test/ui/ref-suggestion.nll.stderr8
-rw-r--r--src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.nll.stderr3
-rw-r--r--src/test/ui/try-block/try-block-bad-lifetime.stderr5
-rw-r--r--src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr5
-rw-r--r--src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr12
-rw-r--r--src/test/ui/unop-move-semantics.nll.stderr6
-rw-r--r--src/test/ui/unsized-locals/borrow-after-move.nll.stderr8
-rw-r--r--src/test/ui/unsized-locals/double-move.nll.stderr12
-rw-r--r--src/test/ui/use/use-after-move-based-on-type.nll.stderr4
-rw-r--r--src/test/ui/use/use-after-move-implicity-coerced-object.nll.stderr5
-rw-r--r--src/test/ui/use/use-after-move-self-based-on-type.nll.stderr4
-rw-r--r--src/test/ui/use/use-after-move-self.nll.stderr4
-rw-r--r--src/test/ui/walk-struct-literal-with.nll.stderr4
89 files changed, 867 insertions, 1135 deletions
diff --git a/src/README.md b/src/README.md
index 65228915866..14e773286bc 100644
--- a/src/README.md
+++ b/src/README.md
@@ -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
 
diff --git a/src/libcore/num/dec2flt/mod.rs b/src/libcore/num/dec2flt/mod.rs
index 58b196a6eac..14a912872be 100644
--- a/src/libcore/num/dec2flt/mod.rs
+++ b/src/libcore/num/dec2flt/mod.rs
@@ -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
diff --git a/src/librustc/infer/higher_ranked/README.md b/src/librustc/infer/higher_ranked/README.md
index b1ac8bae4fb..e7afaa5beb0 100644
--- a/src/librustc/infer/higher_ranked/README.md
+++ b/src/librustc/infer/higher_ranked/README.md
@@ -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
diff --git a/src/librustc/infer/lexical_region_resolve/README.md b/src/librustc/infer/lexical_region_resolve/README.md
index 4483e522f3a..56320636a67 100644
--- a/src/librustc/infer/lexical_region_resolve/README.md
+++ b/src/librustc/infer/lexical_region_resolve/README.md
@@ -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
 
diff --git a/src/librustc/infer/region_constraints/README.md b/src/librustc/infer/region_constraints/README.md
index 775bbf955b8..ea7fffe9dc1 100644
--- a/src/librustc/infer/region_constraints/README.md
+++ b/src/librustc/infer/region_constraints/README.md
@@ -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`.
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index 9328de4f6a0..0ddc5ae8720 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -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(|| {
diff --git a/src/librustc/ty/query/README.md b/src/librustc/ty/query/README.md
index 0fcaef5de54..4b5e08cecd9 100644
--- a/src/librustc/ty/query/README.md
+++ b/src/librustc/ty/query/README.md
@@ -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
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index 97128c2d2a2..afaeb352cd9 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -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)
             {
diff --git a/src/librustc_codegen_ssa/mono_item.rs b/src/librustc_codegen_ssa/mono_item.rs
index 21e0044759a..8488ab2ae86 100644
--- a/src/librustc_codegen_ssa/mono_item.rs
+++ b/src/librustc_codegen_ssa/mono_item.rs
@@ -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());
     }
diff --git a/src/librustc_data_structures/obligation_forest/README.md b/src/librustc_data_structures/obligation_forest/README.md
deleted file mode 100644
index 982a2bacce1..00000000000
--- a/src/librustc_data_structures/obligation_forest/README.md
+++ /dev/null
@@ -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.
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 59497f0df18..9dd7d204f03 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -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};
 
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 233db12b030..56b87feb82b 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -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(&param_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
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index eb49547e9bf..bc63f8b6ac8 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -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>,
diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs
index c831cbd9829..431cc0d52b4 100644
--- a/src/librustc_mir/monomorphize/item.rs
+++ b/src/librustc_mir/monomorphize/item.rs
@@ -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 &parameter_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);
     }
 }
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index c3613fbf04c..569e4c828f6 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -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);
diff --git a/src/test/ui/binop/binop-consume-args.nll.stderr b/src/test/ui/binop/binop-consume-args.nll.stderr
new file mode 100644
index 00000000000..59b5aba93ca
--- /dev/null
+++ b/src/test/ui/binop/binop-consume-args.nll.stderr
@@ -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`.
diff --git a/src/test/ui/binop/binop-move-semantics.nll.stderr b/src/test/ui/binop/binop-move-semantics.nll.stderr
index 950772dc75c..7c84e8833a9 100644
--- a/src/test/ui/binop/binop-move-semantics.nll.stderr
+++ b/src/test/ui/binop/binop-move-semantics.nll.stderr
@@ -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
diff --git a/src/test/ui/borrowck/borrowck-asm.ast.nll.stderr b/src/test/ui/borrowck/borrowck-asm.ast.nll.stderr
index 9c47845a528..86e4832b387 100644
--- a/src/test/ui/borrowck/borrowck-asm.ast.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-asm.ast.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-asm.mir.stderr b/src/test/ui/borrowck/borrowck-asm.mir.stderr
index 9c47845a528..86e4832b387 100644
--- a/src/test/ui/borrowck/borrowck-asm.mir.stderr
+++ b/src/test/ui/borrowck/borrowck-asm.mir.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-consume-unsize-vec.nll.stderr b/src/test/ui/borrowck/borrowck-consume-unsize-vec.nll.stderr
new file mode 100644
index 00000000000..ea7683a91ad
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-consume-unsize-vec.nll.stderr
@@ -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`.
diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.nll.stderr b/src/test/ui/borrowck/borrowck-consume-upcast-box.nll.stderr
index 7357d0973db..15cf359326b 100644
--- a/src/test/ui/borrowck/borrowck-consume-upcast-box.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-consume-upcast-box.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
index d395b7734f9..07b597f480f 100644
--- a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
+++ b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-issue-48962.stderr b/src/test/ui/borrowck/borrowck-issue-48962.stderr
index 9d53d82265e..de4894d5b52 100644
--- a/src/test/ui/borrowck/borrowck-issue-48962.stderr
+++ b/src/test/ui/borrowck/borrowck-issue-48962.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.nll.stderr b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.nll.stderr
index 72d2d1fe59f..095ae7f56b2 100644
--- a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.ast.nll.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.ast.nll.stderr
index 24b9b4338a5..0789926563c 100644
--- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.ast.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.ast.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.mir.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.mir.stderr
index 24b9b4338a5..0789926563c 100644
--- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.mir.stderr
+++ b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.mir.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr
index 6f4cad2a01e..d0065a2e7dc 100644
--- a/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-multiple-captures.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-overloaded-call.nll.stderr b/src/test/ui/borrowck/borrowck-overloaded-call.nll.stderr
index 1b4a6610ab1..c5a4c4e005a 100644
--- a/src/test/ui/borrowck/borrowck-overloaded-call.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-overloaded-call.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.nll.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.nll.stderr
index a19baa167de..de60067f1a6 100644
--- a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-1.nll.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-1.nll.stderr
index 09a85bd7c13..65f2bd6cfbd 100644
--- a/src/test/ui/borrowck/borrowck-partial-reinit-1.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-partial-reinit-1.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-2.nll.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-2.nll.stderr
index 03608a1b99d..36a871fbb12 100644
--- a/src/test/ui/borrowck/borrowck-partial-reinit-2.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-partial-reinit-2.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-reinit.stderr b/src/test/ui/borrowck/borrowck-reinit.stderr
index 918452726a0..96f3981ac2f 100644
--- a/src/test/ui/borrowck/borrowck-reinit.stderr
+++ b/src/test/ui/borrowck/borrowck-reinit.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-unboxed-closures.nll.stderr b/src/test/ui/borrowck/borrowck-unboxed-closures.nll.stderr
index 86baa0db961..363a5a69a07 100644
--- a/src/test/ui/borrowck/borrowck-unboxed-closures.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-unboxed-closures.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-union-move-assign.nll.stderr b/src/test/ui/borrowck/borrowck-union-move-assign.nll.stderr
index bf0d0a45fcf..e59fef2dc0d 100644
--- a/src/test/ui/borrowck/borrowck-union-move-assign.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-union-move-assign.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/borrowck-union-move.nll.stderr b/src/test/ui/borrowck/borrowck-union-move.nll.stderr
index fd90fc47a21..1392a7931c3 100644
--- a/src/test/ui/borrowck/borrowck-union-move.nll.stderr
+++ b/src/test/ui/borrowck/borrowck-union-move.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.nll.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.nll.stderr
index 7861087ad02..42aa0381702 100644
--- a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.nll.stderr
+++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.nll.stderr
@@ -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
 
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.nll.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.nll.stderr
index d35d0058027..1184907f307 100644
--- a/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.nll.stderr
+++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-moved-out.nll.stderr
@@ -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
diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr
index 0e99e158eda..d026f81b7aa 100644
--- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr
+++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr
@@ -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
    |         |
diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr
index 0e99e158eda..d026f81b7aa 100644
--- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr
+++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr
@@ -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
    |         |
diff --git a/src/test/ui/codemap_tests/tab_3.nll.stderr b/src/test/ui/codemap_tests/tab_3.nll.stderr
index 55117ff2b18..3b8507a067d 100644
--- a/src/test/ui/codemap_tests/tab_3.nll.stderr
+++ b/src/test/ui/codemap_tests/tab_3.nll.stderr
@@ -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
 
diff --git a/src/test/ui/issues/auxiliary/issue-56943.rs b/src/test/ui/issues/auxiliary/issue-56943.rs
new file mode 100644
index 00000000000..65b9beb91f9
--- /dev/null
+++ b/src/test/ui/issues/auxiliary/issue-56943.rs
@@ -0,0 +1,3 @@
+pub struct S;
+mod m { pub struct S; }
+pub use crate::m::S as S2;
diff --git a/src/test/ui/issues/issue-17385.nll.stderr b/src/test/ui/issues/issue-17385.nll.stderr
index 24080a3b387..20198f19dd5 100644
--- a/src/test/ui/issues/issue-17385.nll.stderr
+++ b/src/test/ui/issues/issue-17385.nll.stderr
@@ -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
 
diff --git a/src/test/ui/issues/issue-24357.nll.stderr b/src/test/ui/issues/issue-24357.nll.stderr
index 06de9537af0..310535434cd 100644
--- a/src/test/ui/issues/issue-24357.nll.stderr
+++ b/src/test/ui/issues/issue-24357.nll.stderr
@@ -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
 
diff --git a/src/test/ui/issues/issue-25700.nll.stderr b/src/test/ui/issues/issue-25700.nll.stderr
new file mode 100644
index 00000000000..ba5403cca4d
--- /dev/null
+++ b/src/test/ui/issues/issue-25700.nll.stderr
@@ -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`.
diff --git a/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr b/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr
index 8ea2bdb693d..6993419326c 100644
--- a/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr
+++ b/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr
@@ -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
 
diff --git a/src/test/ui/issues/issue-29723.stderr b/src/test/ui/issues/issue-29723.stderr
index de858aec881..7928af5d5a5 100644
--- a/src/test/ui/issues/issue-29723.stderr
+++ b/src/test/ui/issues/issue-29723.stderr
@@ -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
 
diff --git a/src/test/ui/issues/issue-34721.rs b/src/test/ui/issues/issue-34721.rs
new file mode 100644
index 00000000000..226c21446b1
--- /dev/null
+++ b/src/test/ui/issues/issue-34721.rs
@@ -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);
+}
diff --git a/src/test/ui/issues/issue-34721.stderr b/src/test/ui/issues/issue-34721.stderr
new file mode 100644
index 00000000000..2ed7b543e71
--- /dev/null
+++ b/src/test/ui/issues/issue-34721.stderr
@@ -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`.
diff --git a/src/test/ui/issues/issue-42796.nll.stderr b/src/test/ui/issues/issue-42796.nll.stderr
index 19c6a1fd557..23cc88bab52 100644
--- a/src/test/ui/issues/issue-42796.nll.stderr
+++ b/src/test/ui/issues/issue-42796.nll.stderr
@@ -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
 
diff --git a/src/test/ui/issues/issue-56943.rs b/src/test/ui/issues/issue-56943.rs
new file mode 100644
index 00000000000..8fc77abdbf5
--- /dev/null
+++ b/src/test/ui/issues/issue-56943.rs
@@ -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]
+}
diff --git a/src/test/ui/issues/issue-56943.stderr b/src/test/ui/issues/issue-56943.stderr
new file mode 100644
index 00000000000..27202051524
--- /dev/null
+++ b/src/test/ui/issues/issue-56943.stderr
@@ -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`.
diff --git a/src/test/ui/liveness/liveness-move-call-arg.nll.stderr b/src/test/ui/liveness/liveness-move-call-arg.nll.stderr
index 3aa89ac8a9b..521304d5605 100644
--- a/src/test/ui/liveness/liveness-move-call-arg.nll.stderr
+++ b/src/test/ui/liveness/liveness-move-call-arg.nll.stderr
@@ -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
 
diff --git a/src/test/ui/liveness/liveness-move-in-loop.nll.stderr b/src/test/ui/liveness/liveness-move-in-loop.nll.stderr
index 8a5a18f3316..b7e973bc914 100644
--- a/src/test/ui/liveness/liveness-move-in-loop.nll.stderr
+++ b/src/test/ui/liveness/liveness-move-in-loop.nll.stderr
@@ -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
 
diff --git a/src/test/ui/liveness/liveness-move-in-while.nll.stderr b/src/test/ui/liveness/liveness-move-in-while.nll.stderr
index 081983d8bf0..167dcc6b643 100644
--- a/src/test/ui/liveness/liveness-move-in-while.nll.stderr
+++ b/src/test/ui/liveness/liveness-move-in-while.nll.stderr
@@ -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
 
diff --git a/src/test/ui/liveness/liveness-use-after-move.nll.stderr b/src/test/ui/liveness/liveness-use-after-move.nll.stderr
index 45fd43687f3..36c25882ccd 100644
--- a/src/test/ui/liveness/liveness-use-after-move.nll.stderr
+++ b/src/test/ui/liveness/liveness-use-after-move.nll.stderr
@@ -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
 
diff --git a/src/test/ui/liveness/liveness-use-after-send.nll.stderr b/src/test/ui/liveness/liveness-use-after-send.nll.stderr
index 2b55b5d5973..d9367c87116 100644
--- a/src/test/ui/liveness/liveness-use-after-send.nll.stderr
+++ b/src/test/ui/liveness/liveness-use-after-send.nll.stderr
@@ -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
 
diff --git a/src/test/ui/moves/move-guard-same-consts.nll.stderr b/src/test/ui/moves/move-guard-same-consts.nll.stderr
new file mode 100644
index 00000000000..43f99cabcae
--- /dev/null
+++ b/src/test/ui/moves/move-guard-same-consts.nll.stderr
@@ -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`.
diff --git a/src/test/ui/moves/move-in-guard-1.nll.stderr b/src/test/ui/moves/move-in-guard-1.nll.stderr
new file mode 100644
index 00000000000..41abe6fa72a
--- /dev/null
+++ b/src/test/ui/moves/move-in-guard-1.nll.stderr
@@ -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`.
diff --git a/src/test/ui/moves/move-in-guard-2.nll.stderr b/src/test/ui/moves/move-in-guard-2.nll.stderr
index 2d939443846..0b14c1620d3 100644
--- a/src/test/ui/moves/move-in-guard-2.nll.stderr
+++ b/src/test/ui/moves/move-in-guard-2.nll.stderr
@@ -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
 
diff --git a/src/test/ui/moves/move-into-dead-array-2.nll.stderr b/src/test/ui/moves/move-into-dead-array-2.nll.stderr
index 5b2e1bed0c7..20bfdc2bbac 100644
--- a/src/test/ui/moves/move-into-dead-array-2.nll.stderr
+++ b/src/test/ui/moves/move-into-dead-array-2.nll.stderr
@@ -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
 
diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.nll.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.nll.stderr
index 22968b32969..6ad9a2d414c 100644
--- a/src/test/ui/moves/moves-based-on-type-access-to-field.nll.stderr
+++ b/src/test/ui/moves/moves-based-on-type-access-to-field.nll.stderr
@@ -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
 
diff --git a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.nll.stderr b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.nll.stderr
index 061e871c78a..bed0ae7275c 100644
--- a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.nll.stderr
+++ b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.nll.stderr
@@ -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
 
diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.nll.stderr b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.nll.stderr
index 10593a6078e..07f40274f9e 100644
--- a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.nll.stderr
+++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.nll.stderr
@@ -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
 
diff --git a/src/test/ui/moves/moves-based-on-type-exprs.nll.stderr b/src/test/ui/moves/moves-based-on-type-exprs.nll.stderr
index fe44803e273..162aec45f5f 100644
--- a/src/test/ui/moves/moves-based-on-type-exprs.nll.stderr
+++ b/src/test/ui/moves/moves-based-on-type-exprs.nll.stderr
@@ -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
 
diff --git a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.nll.stderr b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.nll.stderr
index 03a23420bbc..391dd67dbf6 100644
--- a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.nll.stderr
+++ b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.nll.stderr
@@ -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
 
diff --git a/src/test/ui/moves/moves-based-on-type-tuple.stderr b/src/test/ui/moves/moves-based-on-type-tuple.stderr
index 2d2c0a15a00..c49dbdab402 100644
--- a/src/test/ui/moves/moves-based-on-type-tuple.stderr
+++ b/src/test/ui/moves/moves-based-on-type-tuple.stderr
@@ -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
 
diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr
index efe4c15240d..3ca0aefb592 100644
--- a/src/test/ui/nll/closure-access-spans.stderr
+++ b/src/test/ui/nll/closure-access-spans.stderr
@@ -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
 
diff --git a/src/test/ui/nll/closure-move-spans.stderr b/src/test/ui/nll/closure-move-spans.stderr
index 3ae1912eb10..6750c404760 100644
--- a/src/test/ui/nll/closure-move-spans.stderr
+++ b/src/test/ui/nll/closure-move-spans.stderr
@@ -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
 
diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr
index 93e095d663c..6c9e1639f88 100644
--- a/src/test/ui/nll/closures-in-loops.stderr
+++ b/src/test/ui/nll/closures-in-loops.stderr
@@ -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
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
index e29c44760a9..54c728e3d27 100644
--- a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
+++ b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
@@ -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
 
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
index aec7f676fce..23da533252c 100644
--- a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
+++ b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
@@ -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
diff --git a/src/test/ui/nll/issue-51512.stderr b/src/test/ui/nll/issue-51512.stderr
index 4717935e4b9..a84a236ca77 100644
--- a/src/test/ui/nll/issue-51512.stderr
+++ b/src/test/ui/nll/issue-51512.stderr
@@ -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
 
diff --git a/src/test/ui/nll/issue-52669.stderr b/src/test/ui/nll/issue-52669.stderr
index e1fb76c6bc2..f51768c3859 100644
--- a/src/test/ui/nll/issue-52669.stderr
+++ b/src/test/ui/nll/issue-52669.stderr
@@ -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
 
diff --git a/src/test/ui/no-capture-arc.nll.stderr b/src/test/ui/no-capture-arc.nll.stderr
index a3bb56024c4..476b6f75abb 100644
--- a/src/test/ui/no-capture-arc.nll.stderr
+++ b/src/test/ui/no-capture-arc.nll.stderr
@@ -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
 
diff --git a/src/test/ui/no-reuse-move-arc.nll.stderr b/src/test/ui/no-reuse-move-arc.nll.stderr
index e24edc5e8e3..0b14f65a770 100644
--- a/src/test/ui/no-reuse-move-arc.nll.stderr
+++ b/src/test/ui/no-reuse-move-arc.nll.stderr
@@ -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
 
diff --git a/src/test/ui/once-cant-call-twice-on-heap.nll.stderr b/src/test/ui/once-cant-call-twice-on-heap.nll.stderr
new file mode 100644
index 00000000000..ea53abc1b0f
--- /dev/null
+++ b/src/test/ui/once-cant-call-twice-on-heap.nll.stderr
@@ -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`.
diff --git a/src/test/ui/ref-suggestion.nll.stderr b/src/test/ui/ref-suggestion.nll.stderr
index 7c00461c900..bef8dcca921 100644
--- a/src/test/ui/ref-suggestion.nll.stderr
+++ b/src/test/ui/ref-suggestion.nll.stderr
@@ -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
diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.nll.stderr b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.nll.stderr
index 0b3f59fd7e4..5a730ad2be4 100644
--- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.nll.stderr
+++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.nll.stderr
@@ -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
diff --git a/src/test/ui/try-block/try-block-bad-lifetime.stderr b/src/test/ui/try-block/try-block-bad-lifetime.stderr
index 5bb0b099b97..b1b925d694f 100644
--- a/src/test/ui/try-block/try-block-bad-lifetime.stderr
+++ b/src/test/ui/try-block/try-block-bad-lifetime.stderr
@@ -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
diff --git a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
index f96c7146d18..dafbde6a515 100644
--- a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
+++ b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
@@ -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
diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr
index 848c3d9bdb0..29d161fe150 100644
--- a/src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr
+++ b/src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr
@@ -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
 
diff --git a/src/test/ui/unop-move-semantics.nll.stderr b/src/test/ui/unop-move-semantics.nll.stderr
index 333a4734a4e..58953d55b1f 100644
--- a/src/test/ui/unop-move-semantics.nll.stderr
+++ b/src/test/ui/unop-move-semantics.nll.stderr
@@ -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
diff --git a/src/test/ui/unsized-locals/borrow-after-move.nll.stderr b/src/test/ui/unsized-locals/borrow-after-move.nll.stderr
index 18cba204735..0e6a6f6369a 100644
--- a/src/test/ui/unsized-locals/borrow-after-move.nll.stderr
+++ b/src/test/ui/unsized-locals/borrow-after-move.nll.stderr
@@ -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
diff --git a/src/test/ui/unsized-locals/double-move.nll.stderr b/src/test/ui/unsized-locals/double-move.nll.stderr
index bbe6da70fb1..e40289af5ad 100644
--- a/src/test/ui/unsized-locals/double-move.nll.stderr
+++ b/src/test/ui/unsized-locals/double-move.nll.stderr
@@ -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
diff --git a/src/test/ui/use/use-after-move-based-on-type.nll.stderr b/src/test/ui/use/use-after-move-based-on-type.nll.stderr
index 6f5b23b2013..8160ada9d62 100644
--- a/src/test/ui/use/use-after-move-based-on-type.nll.stderr
+++ b/src/test/ui/use/use-after-move-based-on-type.nll.stderr
@@ -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
 
diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.nll.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.nll.stderr
index 308134774ef..e16bca38067 100644
--- a/src/test/ui/use/use-after-move-implicity-coerced-object.nll.stderr
+++ b/src/test/ui/use/use-after-move-implicity-coerced-object.nll.stderr
@@ -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
 
diff --git a/src/test/ui/use/use-after-move-self-based-on-type.nll.stderr b/src/test/ui/use/use-after-move-self-based-on-type.nll.stderr
index d7f7c3c30f6..4119741d805 100644
--- a/src/test/ui/use/use-after-move-self-based-on-type.nll.stderr
+++ b/src/test/ui/use/use-after-move-self-based-on-type.nll.stderr
@@ -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
 
diff --git a/src/test/ui/use/use-after-move-self.nll.stderr b/src/test/ui/use/use-after-move-self.nll.stderr
index 3e11e94e993..e2ce3690cb9 100644
--- a/src/test/ui/use/use-after-move-self.nll.stderr
+++ b/src/test/ui/use/use-after-move-self.nll.stderr
@@ -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
 
diff --git a/src/test/ui/walk-struct-literal-with.nll.stderr b/src/test/ui/walk-struct-literal-with.nll.stderr
index 22ad3b1e2f2..2263747607b 100644
--- a/src/test/ui/walk-struct-literal-with.nll.stderr
+++ b/src/test/ui/walk-struct-literal-with.nll.stderr
@@ -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