diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 2eea65125b038..3b98f358b1e95 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -673,37 +673,6 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
     let impl_span = tcx.def_span(checker.impl_def_id);
     let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
 
-    // If an ADT is repr(transparent)...
-    if let ty::Adt(def, args) = *self_ty.kind()
-        && def.repr().transparent()
-    {
-        // FIXME(compiler-errors): This should and could be deduplicated into a query.
-        // Find the nontrivial field.
-        let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, def.did());
-        let nontrivial_field = def.all_fields().find(|field_def| {
-            let field_ty = tcx.type_of(field_def.did).instantiate_identity();
-            !tcx.layout_of(adt_typing_env.as_query_input(field_ty))
-                .is_ok_and(|layout| layout.layout.is_1zst())
-        });
-
-        if let Some(nontrivial_field) = nontrivial_field {
-            // Check that the nontrivial field implements `PointerLike`.
-            let nontrivial_field = nontrivial_field.ty(tcx, args);
-            let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
-            let ocx = ObligationCtxt::new(&infcx);
-            ocx.register_bound(
-                ObligationCause::misc(impl_span, checker.impl_def_id),
-                param_env,
-                nontrivial_field,
-                tcx.lang_items().pointer_like().unwrap(),
-            );
-            // FIXME(dyn-star): We should regionck this implementation.
-            if ocx.select_all_or_error().is_empty() {
-                return Ok(());
-            }
-        }
-    }
-
     let is_permitted_primitive = match *self_ty.kind() {
         ty::Adt(def, _) => def.is_box(),
         ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
@@ -717,6 +686,74 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
         return Ok(());
     }
 
+    let why_disqualified = match *self_ty.kind() {
+        // If an ADT is repr(transparent)
+        ty::Adt(self_ty_def, args) => {
+            if self_ty_def.repr().transparent() {
+                // FIXME(compiler-errors): This should and could be deduplicated into a query.
+                // Find the nontrivial field.
+                let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, self_ty_def.did());
+                let nontrivial_field = self_ty_def.all_fields().find(|field_def| {
+                    let field_ty = tcx.type_of(field_def.did).instantiate_identity();
+                    !tcx.layout_of(adt_typing_env.as_query_input(field_ty))
+                        .is_ok_and(|layout| layout.layout.is_1zst())
+                });
+
+                if let Some(nontrivial_field) = nontrivial_field {
+                    // Check that the nontrivial field implements `PointerLike`.
+                    let nontrivial_field_ty = nontrivial_field.ty(tcx, args);
+                    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
+                    let ocx = ObligationCtxt::new(&infcx);
+                    ocx.register_bound(
+                        ObligationCause::misc(impl_span, checker.impl_def_id),
+                        param_env,
+                        nontrivial_field_ty,
+                        tcx.lang_items().pointer_like().unwrap(),
+                    );
+                    // FIXME(dyn-star): We should regionck this implementation.
+                    if ocx.select_all_or_error().is_empty() {
+                        return Ok(());
+                    } else {
+                        format!(
+                            "the field `{field_name}` of {descr} `{self_ty}` \
+                    does not implement `PointerLike`",
+                            field_name = nontrivial_field.name,
+                            descr = self_ty_def.descr()
+                        )
+                    }
+                } else {
+                    format!(
+                        "the {descr} `{self_ty}` is `repr(transparent)`, \
+                but does not have a non-trivial field (it is zero-sized)",
+                        descr = self_ty_def.descr()
+                    )
+                }
+            } else if self_ty_def.is_box() {
+                // If we got here, then the `layout.is_pointer_like()` check failed
+                // and this box is not a thin pointer.
+
+                String::from("boxes of dynamically-sized types are too large to be `PointerLike`")
+            } else {
+                format!(
+                    "the {descr} `{self_ty}` is not `repr(transparent)`",
+                    descr = self_ty_def.descr()
+                )
+            }
+        }
+        ty::Ref(..) => {
+            // If we got here, then the `layout.is_pointer_like()` check failed
+            // and this reference is not a thin pointer.
+            String::from("references to dynamically-sized types are too large to be `PointerLike`")
+        }
+        ty::Dynamic(..) | ty::Foreign(..) => {
+            String::from("types of dynamic or unknown size may not implement `PointerLike`")
+        }
+        _ => {
+            // This is a white lie; it is true everywhere outside the standard library.
+            format!("only user-defined sized types are eligible for `impl PointerLike`")
+        }
+    };
+
     Err(tcx
         .dcx()
         .struct_span_err(
@@ -724,5 +761,6 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
             "implementation must be applied to type that has the same ABI as a pointer, \
             or is `repr(transparent)` and whose field is `PointerLike`",
         )
+        .with_note(why_disqualified)
         .emit())
 }
diff --git a/tests/ui/dyn-star/pointer-like-impl-rules.rs b/tests/ui/dyn-star/pointer-like-impl-rules.rs
new file mode 100644
index 0000000000000..c234e86e09a84
--- /dev/null
+++ b/tests/ui/dyn-star/pointer-like-impl-rules.rs
@@ -0,0 +1,82 @@
+//@ check-fail
+
+#![feature(extern_types)]
+#![feature(pointer_like_trait)]
+
+use std::marker::PointerLike;
+
+struct NotReprTransparent;
+impl PointerLike for NotReprTransparent {}
+//~^ ERROR: implementation must be applied to type that
+//~| NOTE: the struct `NotReprTransparent` is not `repr(transparent)`
+
+#[repr(transparent)]
+struct FieldIsPl(usize);
+impl PointerLike for FieldIsPl {}
+
+#[repr(transparent)]
+struct FieldIsPlAndHasOtherField(usize, ());
+impl PointerLike for FieldIsPlAndHasOtherField {}
+
+#[repr(transparent)]
+struct FieldIsNotPl(u8);
+impl PointerLike for FieldIsNotPl {}
+//~^ ERROR: implementation must be applied to type that
+//~| NOTE: the field `0` of struct `FieldIsNotPl` does not implement `PointerLike`
+
+#[repr(transparent)]
+struct GenericFieldIsNotPl<T>(T);
+impl<T> PointerLike for GenericFieldIsNotPl<T> {}
+//~^ ERROR: implementation must be applied to type that
+//~| NOTE: the field `0` of struct `GenericFieldIsNotPl<T>` does not implement `PointerLike`
+
+#[repr(transparent)]
+struct GenericFieldIsPl<T>(T);
+impl<T: PointerLike> PointerLike for GenericFieldIsPl<T> {}
+
+#[repr(transparent)]
+struct IsZeroSized(());
+impl PointerLike for IsZeroSized {}
+//~^ ERROR: implementation must be applied to type that
+//~| NOTE: the struct `IsZeroSized` is `repr(transparent)`, but does not have a non-trivial field
+
+trait SomeTrait {}
+impl PointerLike for dyn SomeTrait {}
+//~^ ERROR: implementation must be applied to type that
+//~| NOTE: types of dynamic or unknown size
+
+extern "C" {
+    type ExternType;
+}
+impl PointerLike for ExternType {}
+//~^ ERROR: implementation must be applied to type that
+//~| NOTE: types of dynamic or unknown size
+
+struct LocalSizedType(&'static str);
+struct LocalUnsizedType(str);
+
+// This is not a special error but a normal coherence error,
+// which should still happen.
+impl PointerLike for &LocalSizedType {}
+//~^ ERROR: conflicting implementations of trait `PointerLike`
+//~| NOTE: conflicting implementation in crate `core`
+
+impl PointerLike for &LocalUnsizedType {}
+//~^ ERROR: implementation must be applied to type that
+//~| NOTE: references to dynamically-sized types are too large to be `PointerLike`
+
+impl PointerLike for Box<LocalSizedType> {}
+//~^ ERROR: conflicting implementations of trait `PointerLike`
+//~| NOTE: conflicting implementation in crate `alloc`
+
+impl PointerLike for Box<LocalUnsizedType> {}
+//~^ ERROR: implementation must be applied to type that
+//~| NOTE: boxes of dynamically-sized types are too large to be `PointerLike`
+
+fn expects_pointer_like(x: impl PointerLike) {}
+
+fn main() {
+    expects_pointer_like(FieldIsPl(1usize));
+    expects_pointer_like(FieldIsPlAndHasOtherField(1usize, ()));
+    expects_pointer_like(GenericFieldIsPl(1usize));
+}
diff --git a/tests/ui/dyn-star/pointer-like-impl-rules.stderr b/tests/ui/dyn-star/pointer-like-impl-rules.stderr
new file mode 100644
index 0000000000000..39f08f442c443
--- /dev/null
+++ b/tests/ui/dyn-star/pointer-like-impl-rules.stderr
@@ -0,0 +1,85 @@
+error[E0119]: conflicting implementations of trait `PointerLike` for type `&LocalSizedType`
+  --> $DIR/pointer-like-impl-rules.rs:60:1
+   |
+LL | impl PointerLike for &LocalSizedType {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `core`:
+           - impl<T> PointerLike for &T;
+
+error[E0119]: conflicting implementations of trait `PointerLike` for type `Box<LocalSizedType>`
+  --> $DIR/pointer-like-impl-rules.rs:68:1
+   |
+LL | impl PointerLike for Box<LocalSizedType> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `alloc`:
+           - impl<T> PointerLike for Box<T>;
+
+error: implementation must be applied to type that has the same ABI as a pointer, or is `repr(transparent)` and whose field is `PointerLike`
+  --> $DIR/pointer-like-impl-rules.rs:9:1
+   |
+LL | impl PointerLike for NotReprTransparent {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the struct `NotReprTransparent` is not `repr(transparent)`
+
+error: implementation must be applied to type that has the same ABI as a pointer, or is `repr(transparent)` and whose field is `PointerLike`
+  --> $DIR/pointer-like-impl-rules.rs:23:1
+   |
+LL | impl PointerLike for FieldIsNotPl {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the field `0` of struct `FieldIsNotPl` does not implement `PointerLike`
+
+error: implementation must be applied to type that has the same ABI as a pointer, or is `repr(transparent)` and whose field is `PointerLike`
+  --> $DIR/pointer-like-impl-rules.rs:29:1
+   |
+LL | impl<T> PointerLike for GenericFieldIsNotPl<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the field `0` of struct `GenericFieldIsNotPl<T>` does not implement `PointerLike`
+
+error: implementation must be applied to type that has the same ABI as a pointer, or is `repr(transparent)` and whose field is `PointerLike`
+  --> $DIR/pointer-like-impl-rules.rs:39:1
+   |
+LL | impl PointerLike for IsZeroSized {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the struct `IsZeroSized` is `repr(transparent)`, but does not have a non-trivial field (it is zero-sized)
+
+error: implementation must be applied to type that has the same ABI as a pointer, or is `repr(transparent)` and whose field is `PointerLike`
+  --> $DIR/pointer-like-impl-rules.rs:44:1
+   |
+LL | impl PointerLike for dyn SomeTrait {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: types of dynamic or unknown size may not implement `PointerLike`
+
+error: implementation must be applied to type that has the same ABI as a pointer, or is `repr(transparent)` and whose field is `PointerLike`
+  --> $DIR/pointer-like-impl-rules.rs:51:1
+   |
+LL | impl PointerLike for ExternType {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: types of dynamic or unknown size may not implement `PointerLike`
+
+error: implementation must be applied to type that has the same ABI as a pointer, or is `repr(transparent)` and whose field is `PointerLike`
+  --> $DIR/pointer-like-impl-rules.rs:64:1
+   |
+LL | impl PointerLike for &LocalUnsizedType {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: references to dynamically-sized types are too large to be `PointerLike`
+
+error: implementation must be applied to type that has the same ABI as a pointer, or is `repr(transparent)` and whose field is `PointerLike`
+  --> $DIR/pointer-like-impl-rules.rs:72:1
+   |
+LL | impl PointerLike for Box<LocalUnsizedType> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: boxes of dynamically-sized types are too large to be `PointerLike`
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0119`.