about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-11-29 00:23:23 +0000
committerbors <bors@rust-lang.org>2019-11-29 00:23:23 +0000
commit861e96f2e9fabe04965899f30598115dd3a163e9 (patch)
tree64fe4b9d6878c3faca37a817cff7c1f708625ad5
parent61e1c3d343ea0deb1164eb812ad7c2b8de68c5a9 (diff)
parent0f530ecb6875540f5cf5032ea7df54a38d01ab1c (diff)
Auto merge of #66567 - estebank:suggest-copy, r=Centril
Use structured suggestion when requiring `Copy` constraint in type param
-rw-r--r--src/librustc/traits/error_reporting.rs156
-rw-r--r--src/librustc_mir/borrow_check/conflict_errors.rs18
-rw-r--r--src/test/ui/binop/binop-consume-args.stderr60
-rw-r--r--src/test/ui/binop/binop-move-semantics.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-unboxed-closures.stderr4
-rw-r--r--src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr2
-rw-r--r--src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr4
-rw-r--r--src/test/ui/issues/issue-34721.fixed34
-rw-r--r--src/test/ui/issues/issue-34721.rs2
-rw-r--r--src/test/ui/issues/issue-34721.stderr6
-rw-r--r--src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr6
-rw-r--r--src/test/ui/once-cant-call-twice-on-heap.stderr4
-rw-r--r--src/test/ui/unop-move-semantics.stderr4
13 files changed, 187 insertions, 121 deletions
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 65d08ab03aa..6e723cdc999 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -39,6 +39,7 @@ use syntax::ast;
 use syntax::symbol::{sym, kw};
 use syntax_pos::{DUMMY_SP, Span, ExpnKind, MultiSpan};
 use rustc::hir::def_id::LOCAL_CRATE;
+use syntax_pos::source_map::SourceMap;
 
 use rustc_error_codes::*;
 
@@ -1091,7 +1092,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
     fn suggest_restricting_param_bound(
         &self,
-        err: &mut DiagnosticBuilder<'_>,
+        mut err: &mut DiagnosticBuilder<'_>,
         trait_ref: &ty::PolyTraitRef<'_>,
         body_id: hir::HirId,
     ) {
@@ -1102,7 +1103,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             _ => return,
         };
 
-        let mut suggest_restriction = |generics: &hir::Generics, msg| {
+        let suggest_restriction = |
+            generics: &hir::Generics,
+            msg,
+            err: &mut DiagnosticBuilder<'_>,
+        | {
             let span = generics.where_clause.span_for_predicates_or_empty_place();
             if !span.from_expansion() && span.desugaring_kind().is_none() {
                 err.span_suggestion(
@@ -1132,7 +1137,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     kind: hir::TraitItemKind::Method(..), ..
                 }) if param_ty && self_ty == self.tcx.types.self_param => {
                     // Restricting `Self` for a single method.
-                    suggest_restriction(&generics, "`Self`");
+                    suggest_restriction(&generics, "`Self`", err);
                     return;
                 }
 
@@ -1154,7 +1159,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     kind: hir::ItemKind::Impl(_, _, _, generics, ..), ..
                 }) if projection.is_some() => {
                     // Missing associated type bound.
-                    suggest_restriction(&generics, "the associated type");
+                    suggest_restriction(&generics, "the associated type", err);
                     return;
                 }
 
@@ -1183,68 +1188,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 hir::Node::ImplItem(hir::ImplItem { generics, span, .. })
                 if param_ty => {
                     // Missing generic type parameter bound.
-                    let restrict_msg = "consider further restricting this bound";
                     let param_name = self_ty.to_string();
-                    for param in generics.params.iter().filter(|p| {
-                        p.name.ident().as_str() == param_name
-                    }) {
-                        if param_name.starts_with("impl ") {
-                            // `impl Trait` in argument:
-                            // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
-                            err.span_suggestion(
-                                param.span,
-                                restrict_msg,
-                                // `impl CurrentTrait + MissingTrait`
-                                format!("{} + {}", param.name.ident(), trait_ref),
-                                Applicability::MachineApplicable,
-                            );
-                        } else if generics.where_clause.predicates.is_empty() &&
-                                param.bounds.is_empty()
-                        {
-                            // If there are no bounds whatsoever, suggest adding a constraint
-                            // to the type parameter:
-                            // `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
-                            err.span_suggestion(
-                                param.span,
-                                "consider restricting this bound",
-                                format!("{}", trait_ref.to_predicate()),
-                                Applicability::MachineApplicable,
-                            );
-                        } else if !generics.where_clause.predicates.is_empty() {
-                            // There is a `where` clause, so suggest expanding it:
-                            // `fn foo<T>(t: T) where T: Debug {}` →
-                            // `fn foo<T>(t: T) where T: Debug, T: Trait {}`
-                            err.span_suggestion(
-                                generics.where_clause.span().unwrap().shrink_to_hi(),
-                                &format!(
-                                    "consider further restricting type parameter `{}`",
-                                    param_name,
-                                ),
-                                format!(", {}", trait_ref.to_predicate()),
-                                Applicability::MachineApplicable,
-                            );
-                        } else {
-                            // If there is no `where` clause lean towards constraining to the
-                            // type parameter:
-                            // `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
-                            // `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
-                            let sp = param.span.with_hi(span.hi());
-                            let span = self.tcx.sess.source_map()
-                                .span_through_char(sp, ':');
-                            if sp != param.span && sp != span {
-                                // Only suggest if we have high certainty that the span
-                                // covers the colon in `foo<T: Trait>`.
-                                err.span_suggestion(span, restrict_msg, format!(
-                                    "{} + ",
-                                    trait_ref.to_predicate(),
-                                ), Applicability::MachineApplicable);
-                            } else {
-                                err.span_label(param.span, &format!(
-                                    "consider adding a `where {}` bound",
-                                    trait_ref.to_predicate(),
-                                ));
-                            }
-                        }
+                    let constraint = trait_ref.to_string();
+                    if suggest_constraining_type_param(
+                        generics,
+                        &mut err,
+                        &param_name,
+                        &constraint,
+                        self.tcx.sess.source_map(),
+                        *span,
+                    ) {
                         return;
                     }
                 }
@@ -2546,3 +2499,76 @@ impl ArgKind {
         }
     }
 }
+
+/// Suggest restricting a type param with a new bound.
+pub fn suggest_constraining_type_param(
+    generics: &hir::Generics,
+    err: &mut DiagnosticBuilder<'_>,
+    param_name: &str,
+    constraint: &str,
+    source_map: &SourceMap,
+    span: Span,
+) -> bool {
+    let restrict_msg = "consider further restricting this bound";
+    if let Some(param) = generics.params.iter().filter(|p| {
+        p.name.ident().as_str() == param_name
+    }).next() {
+        if param_name.starts_with("impl ") {
+            // `impl Trait` in argument:
+            // `fn foo(x: impl Trait) {}` → `fn foo(t: impl Trait + Trait2) {}`
+            err.span_suggestion(
+                param.span,
+                restrict_msg,
+                // `impl CurrentTrait + MissingTrait`
+                format!("{} + {}", param_name, constraint),
+                Applicability::MachineApplicable,
+            );
+        } else if generics.where_clause.predicates.is_empty() &&
+                param.bounds.is_empty()
+        {
+            // If there are no bounds whatsoever, suggest adding a constraint
+            // to the type parameter:
+            // `fn foo<T>(t: T) {}` → `fn foo<T: Trait>(t: T) {}`
+            err.span_suggestion(
+                param.span,
+                "consider restricting this bound",
+                format!("{}: {}", param_name, constraint),
+                Applicability::MachineApplicable,
+            );
+        } else if !generics.where_clause.predicates.is_empty() {
+            // There is a `where` clause, so suggest expanding it:
+            // `fn foo<T>(t: T) where T: Debug {}` →
+            // `fn foo<T>(t: T) where T: Debug, T: Trait {}`
+            err.span_suggestion(
+                generics.where_clause.span().unwrap().shrink_to_hi(),
+                &format!("consider further restricting type parameter `{}`", param_name),
+                format!(", {}: {}", param_name, constraint),
+                Applicability::MachineApplicable,
+            );
+        } else {
+            // If there is no `where` clause lean towards constraining to the
+            // type parameter:
+            // `fn foo<X: Bar, T>(t: T, x: X) {}` → `fn foo<T: Trait>(t: T) {}`
+            // `fn foo<T: Bar>(t: T) {}` → `fn foo<T: Bar + Trait>(t: T) {}`
+            let sp = param.span.with_hi(span.hi());
+            let span = source_map.span_through_char(sp, ':');
+            if sp != param.span && sp != span {
+                // Only suggest if we have high certainty that the span
+                // covers the colon in `foo<T: Trait>`.
+                err.span_suggestion(
+                    span,
+                    restrict_msg,
+                    format!("{}: {} + ", param_name, constraint),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                err.span_label(
+                    param.span,
+                    &format!("consider adding a `where {}: {}` bound", param_name, constraint),
+                );
+            }
+        }
+        return true;
+    }
+    false
+}
diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs
index 8508bf62d8f..48f8ad9bbd8 100644
--- a/src/librustc_mir/borrow_check/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/conflict_errors.rs
@@ -7,6 +7,7 @@ use rustc::mir::{
     PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
 };
 use rustc::ty::{self, Ty};
+use rustc::traits::error_reporting::suggest_constraining_type_param;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::vec::Idx;
 use rustc_errors::{Applicability, DiagnosticBuilder};
@@ -231,13 +232,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 if let ty::Param(param_ty) = ty.kind {
                     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",
-                        );
-                    }
+                    let param = generics.type_param(&param_ty, tcx);
+                    let generics = tcx.hir().get_generics(self.mir_def_id).unwrap();
+                    suggest_constraining_type_param(
+                        generics,
+                        &mut err,
+                        &param.name.as_str(),
+                        "Copy",
+                        tcx.sess.source_map(),
+                        span,
+                    );
                 }
                 let span = if let Some(local) = place.as_local() {
                     let decl = &self.body.local_decls[local];
diff --git a/src/test/ui/binop/binop-consume-args.stderr b/src/test/ui/binop/binop-consume-args.stderr
index 5751af27fcb..876e984ecb0 100644
--- a/src/test/ui/binop/binop-consume-args.stderr
+++ b/src/test/ui/binop/binop-consume-args.stderr
@@ -2,9 +2,9 @@ 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
+   |        --                       --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
    |        |
-   |        consider adding a `Copy` constraint to this type argument
+   |        help: consider further restricting this bound: `A: Copy +`
 LL |     lhs + rhs;
    |     --- value moved here
 LL |     drop(lhs);
@@ -16,7 +16,7 @@ error[E0382]: use of moved value: `rhs`
 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
+   |                              help: consider restricting this bound: `B: Copy`
 LL |     lhs + rhs;
    |           --- value moved here
 LL |     drop(lhs);
@@ -27,9 +27,9 @@ 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
+   |        --                       --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
    |        |
-   |        consider adding a `Copy` constraint to this type argument
+   |        help: consider further restricting this bound: `A: Copy +`
 LL |     lhs - rhs;
    |     --- value moved here
 LL |     drop(lhs);
@@ -41,7 +41,7 @@ error[E0382]: use of moved value: `rhs`
 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
+   |                              help: consider restricting this bound: `B: Copy`
 LL |     lhs - rhs;
    |           --- value moved here
 LL |     drop(lhs);
@@ -52,9 +52,9 @@ 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
+   |        --                       --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
    |        |
-   |        consider adding a `Copy` constraint to this type argument
+   |        help: consider further restricting this bound: `A: Copy +`
 LL |     lhs * rhs;
    |     --- value moved here
 LL |     drop(lhs);
@@ -66,7 +66,7 @@ error[E0382]: use of moved value: `rhs`
 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
+   |                              help: consider restricting this bound: `B: Copy`
 LL |     lhs * rhs;
    |           --- value moved here
 LL |     drop(lhs);
@@ -77,9 +77,9 @@ 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
+   |        --                       --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
    |        |
-   |        consider adding a `Copy` constraint to this type argument
+   |        help: consider further restricting this bound: `A: Copy +`
 LL |     lhs / rhs;
    |     --- value moved here
 LL |     drop(lhs);
@@ -91,7 +91,7 @@ error[E0382]: use of moved value: `rhs`
 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
+   |                              help: consider restricting this bound: `B: Copy`
 LL |     lhs / rhs;
    |           --- value moved here
 LL |     drop(lhs);
@@ -102,9 +102,9 @@ 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
+   |        --                       --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
    |        |
-   |        consider adding a `Copy` constraint to this type argument
+   |        help: consider further restricting this bound: `A: Copy +`
 LL |     lhs % rhs;
    |     --- value moved here
 LL |     drop(lhs);
@@ -116,7 +116,7 @@ error[E0382]: use of moved value: `rhs`
 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
+   |                              help: consider restricting this bound: `B: Copy`
 LL |     lhs % rhs;
    |           --- value moved here
 LL |     drop(lhs);
@@ -127,9 +127,9 @@ 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
+   |           --                          --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
    |           |
-   |           consider adding a `Copy` constraint to this type argument
+   |           help: consider further restricting this bound: `A: Copy +`
 LL |     lhs & rhs;
    |     --- value moved here
 LL |     drop(lhs);
@@ -141,7 +141,7 @@ error[E0382]: use of moved value: `rhs`
 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
+   |                                    help: consider restricting this bound: `B: Copy`
 LL |     lhs & rhs;
    |           --- value moved here
 LL |     drop(lhs);
@@ -152,9 +152,9 @@ 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
+   |          --                         --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
    |          |
-   |          consider adding a `Copy` constraint to this type argument
+   |          help: consider further restricting this bound: `A: Copy +`
 LL |     lhs | rhs;
    |     --- value moved here
 LL |     drop(lhs);
@@ -166,7 +166,7 @@ error[E0382]: use of moved value: `rhs`
 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
+   |                                  help: consider restricting this bound: `B: Copy`
 LL |     lhs | rhs;
    |           --- value moved here
 LL |     drop(lhs);
@@ -177,9 +177,9 @@ 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
+   |           --                          --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
    |           |
-   |           consider adding a `Copy` constraint to this type argument
+   |           help: consider further restricting this bound: `A: Copy +`
 LL |     lhs ^ rhs;
    |     --- value moved here
 LL |     drop(lhs);
@@ -191,7 +191,7 @@ error[E0382]: use of moved value: `rhs`
 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
+   |                                    help: consider restricting this bound: `B: Copy`
 LL |     lhs ^ rhs;
    |           --- value moved here
 LL |     drop(lhs);
@@ -202,9 +202,9 @@ 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
+   |        --                       --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
    |        |
-   |        consider adding a `Copy` constraint to this type argument
+   |        help: consider further restricting this bound: `A: Copy +`
 LL |     lhs << rhs;
    |     --- value moved here
 LL |     drop(lhs);
@@ -216,7 +216,7 @@ error[E0382]: use of moved value: `rhs`
 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
+   |                              help: consider restricting this bound: `B: Copy`
 LL |     lhs << rhs;
    |            --- value moved here
 LL |     drop(lhs);
@@ -227,9 +227,9 @@ 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
+   |        --                       --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
    |        |
-   |        consider adding a `Copy` constraint to this type argument
+   |        help: consider further restricting this bound: `A: Copy +`
 LL |     lhs >> rhs;
    |     --- value moved here
 LL |     drop(lhs);
@@ -241,7 +241,7 @@ error[E0382]: use of moved value: `rhs`
 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
+   |                              help: consider restricting this bound: `B: Copy`
 LL |     lhs >> rhs;
    |            --- value moved here
 LL |     drop(lhs);
diff --git a/src/test/ui/binop/binop-move-semantics.stderr b/src/test/ui/binop/binop-move-semantics.stderr
index 897607dc2d8..7552dc66974 100644
--- a/src/test/ui/binop/binop-move-semantics.stderr
+++ b/src/test/ui/binop/binop-move-semantics.stderr
@@ -2,9 +2,9 @@ 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
+   |                --                 - move occurs because `x` has type `T`, which does not implement the `Copy` trait
    |                |
-   |                consider adding a `Copy` constraint to this type argument
+   |                help: consider further restricting this bound: `T: Copy +`
 LL |     x
    |     - value moved here
 LL |     +
@@ -15,9 +15,9 @@ 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
+   |                     --                         - move occurs because `x` has type `T`, which does not implement the `Copy` trait
    |                     |
-   |                     consider adding a `Copy` constraint to this type argument
+   |                     help: consider further restricting this bound: `T: Copy +`
 LL |     x
    |     - value moved here
 LL |     +
diff --git a/src/test/ui/borrowck/borrowck-unboxed-closures.stderr b/src/test/ui/borrowck/borrowck-unboxed-closures.stderr
index 40b8e313484..5cd0471cd0d 100644
--- a/src/test/ui/borrowck/borrowck-unboxed-closures.stderr
+++ b/src/test/ui/borrowck/borrowck-unboxed-closures.stderr
@@ -20,9 +20,9 @@ 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
+   |      --                               - move occurs because `f` has type `F`, which does not implement the `Copy` trait
    |      |
-   |      consider adding a `Copy` constraint to this type argument
+   |      help: consider further restricting this bound: `F: Copy +`
 LL |     f(1, 2);
    |     - value moved here
 LL |     f(1, 2);
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
index afcb467ad47..5c38f47b363 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
@@ -7,7 +7,7 @@ LL |     where B : for<'ccx> Bar<'ccx>
    |               ------------------- required by this bound in `want_bar_for_any_ccx`
 ...
 LL |     where B : Qux
-   |                  - help: consider further restricting type parameter `B`: `, for<'ccx> B: Bar<'ccx>`
+   |                  - help: consider further restricting type parameter `B`: `, B: for<'ccx> Bar<'ccx>`
 ...
 LL |     want_bar_for_any_ccx(b);
    |                          ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
index 20913b4f28c..768bc6c7184 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits.rs:18:26
    |
 LL |     where F : Foo<'x>
-   |                      - help: consider further restricting type parameter `F`: `, for<'tcx> F: Foo<'tcx>`
+   |                      - help: consider further restricting type parameter `F`: `, F: for<'tcx> Foo<'tcx>`
 ...
 LL |     want_foo_for_any_tcx(f);
    |                          ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
@@ -16,7 +16,7 @@ error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits.rs:35:26
    |
 LL |     where B : Bar<'x>
-   |                      - help: consider further restricting type parameter `B`: `, for<'ccx> B: Bar<'ccx>`
+   |                      - help: consider further restricting type parameter `B`: `, B: for<'ccx> Bar<'ccx>`
 ...
 LL |     want_bar_for_any_ccx(b);
    |                          ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
diff --git a/src/test/ui/issues/issue-34721.fixed b/src/test/ui/issues/issue-34721.fixed
new file mode 100644
index 00000000000..ba2810ee3d7
--- /dev/null
+++ b/src/test/ui/issues/issue-34721.fixed
@@ -0,0 +1,34 @@
+// run-rustfix
+
+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: Copy +  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.rs b/src/test/ui/issues/issue-34721.rs
index bdc9fe43a8b..14dd01766aa 100644
--- a/src/test/ui/issues/issue-34721.rs
+++ b/src/test/ui/issues/issue-34721.rs
@@ -1,3 +1,5 @@
+// run-rustfix
+
 pub trait Foo {
     fn zero(self) -> Self;
 }
diff --git a/src/test/ui/issues/issue-34721.stderr b/src/test/ui/issues/issue-34721.stderr
index d5cede990a3..3002b07e8c9 100644
--- a/src/test/ui/issues/issue-34721.stderr
+++ b/src/test/ui/issues/issue-34721.stderr
@@ -1,10 +1,10 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/issue-34721.rs:25:9
+  --> $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
+   |                --      - move occurs because `x` has type `T`, which does not implement the `Copy` trait
    |                |
-   |                consider adding a `Copy` constraint to this type argument
+   |                help: consider further restricting this bound: `T: Copy +`
 LL |         if 0 == 1 {
 LL |             bar::bar(x.zero())
    |                      - value moved here
diff --git a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr
index 483c364752b..ead2cceebf8 100644
--- a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr
+++ b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr
@@ -11,9 +11,9 @@ 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
+   |                   -----                                 - help: consider further restricting type parameter `F`: `, F: Copy`
+   |                   |
+   |                   move occurs because `f` has type `F`, which does not implement the `Copy` trait
 LL |     let mut r = R {c: Box::new(f)};
    |                                - value moved here
 LL |     f(&mut r, false)
diff --git a/src/test/ui/once-cant-call-twice-on-heap.stderr b/src/test/ui/once-cant-call-twice-on-heap.stderr
index f98d3d83845..fd998060218 100644
--- a/src/test/ui/once-cant-call-twice-on-heap.stderr
+++ b/src/test/ui/once-cant-call-twice-on-heap.stderr
@@ -2,9 +2,9 @@ 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
+   |        --          --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
    |        |
-   |        consider adding a `Copy` constraint to this type argument
+   |        help: consider further restricting this bound: `F: Copy +`
 LL |     blk();
    |     --- value moved here
 LL |     blk();
diff --git a/src/test/ui/unop-move-semantics.stderr b/src/test/ui/unop-move-semantics.stderr
index 6aa3d0b0989..092c419d7cb 100644
--- a/src/test/ui/unop-move-semantics.stderr
+++ b/src/test/ui/unop-move-semantics.stderr
@@ -2,9 +2,9 @@ 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
+   |                     --                        - move occurs because `x` has type `T`, which does not implement the `Copy` trait
    |                     |
-   |                     consider adding a `Copy` constraint to this type argument
+   |                     help: consider further restricting this bound: `T: Copy +`
 LL |     !x;
    |      - value moved here
 LL |