diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 30b5f9b34d099..0a218c2d25584 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -51,7 +51,7 @@ use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, InnerSpan, MultiSpan, Span};
 use rustc_target::abi::VariantIdx;
-use rustc_trait_selection::traits::misc::can_type_implement_copy;
+use rustc_trait_selection::traits::{self, misc::can_type_implement_copy};
 
 use crate::nonstandard_style::{method_context, MethodLateContext};
 
@@ -764,7 +764,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
         if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) {
             return;
         }
-        if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() {
+        if can_type_implement_copy(
+            cx.tcx,
+            param_env,
+            ty,
+            traits::ObligationCause::misc(item.span, item.hir_id()),
+        )
+        .is_ok()
+        {
             cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| {
                 lint.build(
                     "type could implement `Copy`; consider adding `impl \
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index b23dce8a58130..c293708dcc929 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -20,6 +20,7 @@ pub fn can_type_implement_copy<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     self_type: Ty<'tcx>,
+    cause: ObligationCause<'tcx>,
 ) -> Result<(), CopyImplementationError<'tcx>> {
     // FIXME: (@jroesch) float this code up
     tcx.infer_ctxt().enter(|infcx| {
@@ -49,7 +50,19 @@ pub fn can_type_implement_copy<'tcx>(
                     continue;
                 }
                 let span = tcx.def_span(field.did);
-                let cause = ObligationCause::dummy_with_span(span);
+                // FIXME(compiler-errors): This gives us better spans for bad
+                // projection types like in issue-50480.
+                // If the ADT has substs, point to the cause we are given.
+                // If it does not, then this field probably doesn't normalize
+                // to begin with, and point to the bad field's span instead.
+                let cause = if field
+                    .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did))
+                    .has_param_types_or_consts()
+                {
+                    cause.clone()
+                } else {
+                    ObligationCause::dummy_with_span(span)
+                };
                 let ctx = traits::FulfillmentContext::new();
                 match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) {
                     Ok(ty) => {
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index 401ba188728c1..a43f7f871167e 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -74,7 +74,8 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
 
     debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
 
-    match can_type_implement_copy(tcx, param_env, self_type) {
+    let cause = traits::ObligationCause::misc(span, impl_hir_id);
+    match can_type_implement_copy(tcx, param_env, self_type, cause) {
         Ok(()) => {}
         Err(CopyImplementationError::InfrigingFields(fields)) => {
             let item = tcx.hir().expect_item(impl_did);
diff --git a/src/test/ui/traits/copy-impl-cannot-normalize.rs b/src/test/ui/traits/copy-impl-cannot-normalize.rs
new file mode 100644
index 0000000000000..a78ff046e97f9
--- /dev/null
+++ b/src/test/ui/traits/copy-impl-cannot-normalize.rs
@@ -0,0 +1,25 @@
+trait TraitFoo {
+    type Bar;
+}
+
+struct Foo<T>
+where
+    T: TraitFoo,
+{
+    inner: T::Bar,
+}
+
+impl<T> Clone for Foo<T>
+where
+    T: TraitFoo,
+    T::Bar: Clone,
+{
+    fn clone(&self) -> Self {
+        Self { inner: self.inner.clone() }
+    }
+}
+
+impl<T> Copy for Foo<T> {}
+//~^ ERROR the trait bound `T: TraitFoo` is not satisfied
+
+fn main() {}
diff --git a/src/test/ui/traits/copy-impl-cannot-normalize.stderr b/src/test/ui/traits/copy-impl-cannot-normalize.stderr
new file mode 100644
index 0000000000000..cc540ea905a10
--- /dev/null
+++ b/src/test/ui/traits/copy-impl-cannot-normalize.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `T: TraitFoo` is not satisfied
+  --> $DIR/copy-impl-cannot-normalize.rs:22:1
+   |
+LL | impl<T> Copy for Foo<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitFoo` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: TraitFoo> Copy for Foo<T> {}
+   |       ++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index ebd4fb0bf51cc..d27e1383d012b 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -199,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                     let sugg = |diag: &mut DiagnosticBuilder<'_>| {
                         if let ty::Adt(def, ..) = ty.kind() {
                             if let Some(span) = cx.tcx.hir().span_if_local(def.did) {
-                                if can_type_implement_copy(cx.tcx, cx.param_env, ty).is_ok() {
+                                if can_type_implement_copy(cx.tcx, cx.param_env, ty, traits::ObligationCause::dummy_with_span(span)).is_ok() {
                                     diag.span_help(span, "consider marking this type as `Copy`");
                                 }
                             }