diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs
index 4a0a2720fe441..35790324a2f62 100644
--- a/src/libcore/ops/function.rs
+++ b/src/libcore/ops/function.rs
@@ -137,10 +137,6 @@ pub trait Fn<Args> : FnMut<Args> {
 #[rustc_paren_sugar]
 #[rustc_on_unimplemented(
     on(Args="()", note="wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}"),
-    on(
-        all(Args="(char,)", _Self="std::string::String"),
-        note="borrowing the `{Self}` might fix the problem"
-    ),
     message="expected a `{FnMut}<{Args}>` closure, found `{Self}`",
     label="expected an `FnMut<{Args}>` closure, found `{Self}`",
 )]
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index c7e51ff321771..ea29cc0d93f53 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -33,7 +33,7 @@ use crate::ty::subst::Subst;
 use crate::ty::SubtypePredicate;
 use crate::util::nodemap::{FxHashMap, FxHashSet};
 
-use errors::{Applicability, DiagnosticBuilder, pluralize};
+use errors::{Applicability, DiagnosticBuilder, pluralize, Style};
 use std::fmt;
 use syntax::ast;
 use syntax::symbol::{sym, kw};
@@ -713,20 +713,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 }
                 match obligation.predicate {
                     ty::Predicate::Trait(ref trait_predicate) => {
-                        let trait_predicate =
-                            self.resolve_vars_if_possible(trait_predicate);
+                        let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
 
                         if self.tcx.sess.has_errors() && trait_predicate.references_error() {
                             return;
                         }
                         let trait_ref = trait_predicate.to_poly_trait_ref();
-                        let (post_message, pre_message) =
-                            self.get_parent_trait_ref(&obligation.cause.code)
-                                .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
+                        let (
+                            post_message,
+                            pre_message,
+                        ) = self.get_parent_trait_ref(&obligation.cause.code)
+                            .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
                             .unwrap_or_default();
 
-                        let OnUnimplementedNote { message, label, note }
-                            = self.on_unimplemented_note(trait_ref, obligation);
+                        let OnUnimplementedNote {
+                            message,
+                            label,
+                            note,
+                        } = self.on_unimplemented_note(trait_ref, obligation);
                         let have_alt_message = message.is_some() || label.is_some();
                         let is_try = self.tcx.sess.source_map().span_to_snippet(span)
                             .map(|s| &s == "?")
@@ -767,6 +771,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                 )
                             };
 
+                        if self.suggest_add_reference_to_arg(
+                            &obligation,
+                            &mut err,
+                            &trait_ref,
+                            points_at_arg,
+                            have_alt_message,
+                        ) {
+                            self.note_obligation_cause(&mut err, obligation);
+                            err.emit();
+                            return;
+                        }
                         if let Some(ref s) = label {
                             // If it has a custom `#[rustc_on_unimplemented]`
                             // error message, let's display it as the label!
@@ -1298,6 +1313,73 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
+    fn suggest_add_reference_to_arg(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        err: &mut DiagnosticBuilder<'tcx>,
+        trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+        points_at_arg: bool,
+        has_custom_message: bool,
+    ) -> bool {
+        if !points_at_arg {
+            return false;
+        }
+
+        let span = obligation.cause.span;
+        let param_env = obligation.param_env;
+        let trait_ref = trait_ref.skip_binder();
+
+        if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code {
+            // Try to apply the original trait binding obligation by borrowing.
+            let self_ty = trait_ref.self_ty();
+            let found = self_ty.to_string();
+            let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty);
+            let substs = self.tcx.mk_substs_trait(new_self_ty, &[]);
+            let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs);
+            let new_obligation = Obligation::new(
+                ObligationCause::dummy(),
+                param_env,
+                new_trait_ref.to_predicate(),
+            );
+            if self.predicate_must_hold_modulo_regions(&new_obligation) {
+                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+                    // We have a very specific type of error, where just borrowing this argument
+                    // might solve the problem. In cases like this, the important part is the
+                    // original type obligation, not the last one that failed, which is arbitrary.
+                    // Because of this, we modify the error to refer to the original obligation and
+                    // return early in the caller.
+                    let msg = format!(
+                        "the trait bound `{}: {}` is not satisfied",
+                        found,
+                        obligation.parent_trait_ref.skip_binder(),
+                    );
+                    if has_custom_message {
+                        err.note(&msg);
+                    } else {
+                        err.message = vec![(msg, Style::NoStyle)];
+                    }
+                    if snippet.starts_with('&') {
+                        // This is already a literal borrow and the obligation is failing
+                        // somewhere else in the obligation chain. Do not suggest non-sense.
+                        return false;
+                    }
+                    err.span_label(span, &format!(
+                        "expected an implementor of trait `{}`",
+                        obligation.parent_trait_ref.skip_binder(),
+                    ));
+                    err.span_suggestion(
+                        span,
+                        "consider borrowing here",
+                        format!("&{}", snippet),
+                        Applicability::MaybeIncorrect,
+                    );
+                    return true;
+                }
+            }
+        }
+        false
+    }
+
     /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
     /// suggest removing these references until we reach a type that implements the trait.
     fn suggest_remove_reference(
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index 17765ef9deefa..fb34d844fdafb 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -38,6 +38,7 @@ pub mod registry;
 mod styled_buffer;
 mod lock;
 pub mod json;
+pub use snippet::Style;
 
 pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
 
diff --git a/src/test/ui/derives/deriving-copyclone.rs b/src/test/ui/derives/deriving-copyclone.rs
index 4565412bff7f3..06b3157a77a84 100644
--- a/src/test/ui/derives/deriving-copyclone.rs
+++ b/src/test/ui/derives/deriving-copyclone.rs
@@ -28,10 +28,10 @@ fn main() {
     is_clone(B { a: 1, b: 2 });
 
     // B<C> cannot be copied or cloned
-    is_copy(B { a: 1, b: C }); //~ERROR Copy
-    is_clone(B { a: 1, b: C }); //~ERROR Clone
+    is_copy(B { a: 1, b: C }); //~ ERROR Copy
+    is_clone(B { a: 1, b: C }); //~ ERROR Clone
 
     // B<D> can be cloned but not copied
-    is_copy(B { a: 1, b: D }); //~ERROR Copy
+    is_copy(B { a: 1, b: D }); //~ ERROR Copy
     is_clone(B { a: 1, b: D });
 }
diff --git a/src/test/ui/derives/deriving-copyclone.stderr b/src/test/ui/derives/deriving-copyclone.stderr
index 4cca14ae089e9..e23d48ca6304b 100644
--- a/src/test/ui/derives/deriving-copyclone.stderr
+++ b/src/test/ui/derives/deriving-copyclone.stderr
@@ -5,7 +5,10 @@ LL | fn is_copy<T: Copy>(_: T) {}
    |    -------    ---- required by this bound in `is_copy`
 ...
 LL |     is_copy(B { a: 1, b: C });
-   |             ^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `C`
+   |             ^^^^^^^^^^^^^^^^
+   |             |
+   |             expected an implementor of trait `std::marker::Copy`
+   |             help: consider borrowing here: `&B { a: 1, b: C }`
    |
    = note: required because of the requirements on the impl of `std::marker::Copy` for `B<C>`
 
@@ -16,7 +19,10 @@ LL | fn is_clone<T: Clone>(_: T) {}
    |    --------    ----- required by this bound in `is_clone`
 ...
 LL |     is_clone(B { a: 1, b: C });
-   |              ^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `C`
+   |              ^^^^^^^^^^^^^^^^
+   |              |
+   |              expected an implementor of trait `std::clone::Clone`
+   |              help: consider borrowing here: `&B { a: 1, b: C }`
    |
    = note: required because of the requirements on the impl of `std::clone::Clone` for `B<C>`
 
@@ -27,7 +33,10 @@ LL | fn is_copy<T: Copy>(_: T) {}
    |    -------    ---- required by this bound in `is_copy`
 ...
 LL |     is_copy(B { a: 1, b: D });
-   |             ^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `D`
+   |             ^^^^^^^^^^^^^^^^
+   |             |
+   |             expected an implementor of trait `std::marker::Copy`
+   |             help: consider borrowing here: `&B { a: 1, b: D }`
    |
    = note: required because of the requirements on the impl of `std::marker::Copy` for `B<D>`
 
diff --git a/src/test/ui/kindck/kindck-impl-type-params-2.rs b/src/test/ui/kindck/kindck-impl-type-params-2.rs
index ac9cc1a08f33d..d5fcc68a759cb 100644
--- a/src/test/ui/kindck/kindck-impl-type-params-2.rs
+++ b/src/test/ui/kindck/kindck-impl-type-params-2.rs
@@ -11,5 +11,5 @@ fn take_param<T:Foo>(foo: &T) { }
 fn main() {
     let x: Box<_> = box 3;
     take_param(&x);
-    //~^ ERROR `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied
+    //~^ ERROR the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied
 }
diff --git a/src/test/ui/kindck/kindck-impl-type-params-2.stderr b/src/test/ui/kindck/kindck-impl-type-params-2.stderr
index 8e98911324411..318b7b0f10a0a 100644
--- a/src/test/ui/kindck/kindck-impl-type-params-2.stderr
+++ b/src/test/ui/kindck/kindck-impl-type-params-2.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied
+error[E0277]: the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied
   --> $DIR/kindck-impl-type-params-2.rs:13:16
    |
 LL | fn take_param<T:Foo>(foo: &T) { }
diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr
index a93f4686496ac..da1a7a7520e07 100644
--- a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr
+++ b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied
+error[E0277]: the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied
   --> $DIR/kindck-inherited-copy-bound.rs:21:16
    |
 LL | fn take_param<T:Foo>(foo: &T) { }
diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr
index 7c67c5f9e9596..f272f829ba600 100644
--- a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr
+++ b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied
+error[E0277]: the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied
   --> $DIR/kindck-inherited-copy-bound.rs:21:16
    |
 LL | fn take_param<T:Foo>(foo: &T) { }
diff --git a/src/test/ui/suggestions/issue-62843.stderr b/src/test/ui/suggestions/issue-62843.stderr
index b5801e9162fb3..3b7f85c56689e 100644
--- a/src/test/ui/suggestions/issue-62843.stderr
+++ b/src/test/ui/suggestions/issue-62843.stderr
@@ -2,10 +2,12 @@ error[E0277]: expected a `std::ops::FnMut<(char,)>` closure, found `std::string:
   --> $DIR/issue-62843.rs:4:32
    |
 LL |     println!("{:?}", line.find(pattern));
-   |                                ^^^^^^^ expected an `FnMut<(char,)>` closure, found `std::string::String`
+   |                                ^^^^^^^
+   |                                |
+   |                                expected an implementor of trait `std::str::pattern::Pattern<'_>`
+   |                                help: consider borrowing here: `&pattern`
    |
-   = help: the trait `std::ops::FnMut<(char,)>` is not implemented for `std::string::String`
-   = note: borrowing the `std::string::String` might fix the problem
+   = note: the trait bound `std::string::String: std::str::pattern::Pattern<'_>` is not satisfied
    = note: required because of the requirements on the impl of `std::str::pattern::Pattern<'_>` for `std::string::String`
 
 error: aborting due to previous error
diff --git a/src/test/ui/traits/traits-negative-impls.stderr b/src/test/ui/traits/traits-negative-impls.stderr
index 22b6d2a0c4e98..599bbfe222546 100644
--- a/src/test/ui/traits/traits-negative-impls.stderr
+++ b/src/test/ui/traits/traits-negative-impls.stderr
@@ -50,9 +50,12 @@ LL | fn is_send<T: Send>(_: T) {}
    |    -------    ---- required by this bound in `is_send`
 ...
 LL |     is_send(Box::new(TestType));
-   |             ^^^^^^^^^^^^^^^^^^ `dummy2::TestType` cannot be sent between threads safely
+   |             ^^^^^^^^^^^^^^^^^^
+   |             |
+   |             expected an implementor of trait `std::marker::Send`
+   |             help: consider borrowing here: `&Box::new(TestType)`
    |
-   = help: the trait `std::marker::Send` is not implemented for `dummy2::TestType`
+   = note: the trait bound `dummy2::TestType: std::marker::Send` is not satisfied
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<dummy2::TestType>`
    = note: required because it appears within the type `std::boxed::Box<dummy2::TestType>`
 
@@ -77,9 +80,12 @@ LL | fn is_sync<T: Sync>(_: T) {}
    |    -------    ---- required by this bound in `is_sync`
 ...
 LL |     is_sync(Outer2(TestType));
-   |             ^^^^^^^^^^^^^^^^ `main::TestType` cannot be sent between threads safely
+   |             ^^^^^^^^^^^^^^^^
+   |             |
+   |             expected an implementor of trait `std::marker::Sync`
+   |             help: consider borrowing here: `&Outer2(TestType)`
    |
-   = help: the trait `std::marker::Send` is not implemented for `main::TestType`
+   = note: the trait bound `main::TestType: std::marker::Sync` is not satisfied
    = note: required because of the requirements on the impl of `std::marker::Sync` for `Outer2<main::TestType>`
 
 error: aborting due to 7 previous errors