about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-02-19 19:10:01 +0000
committerMichael Goulet <michael@errs.io>2025-02-24 19:34:54 +0000
commit96d966b07aabbf0438489b848b8f039f88bb518e (patch)
treebb58368257607f249ec5e30ff9e44a33d8210afc
parentb6899ab9216d63762ba7f97c8a457dc9047e0a2b (diff)
downloadrust-96d966b07aabbf0438489b848b8f039f88bb518e.tar.gz
rust-96d966b07aabbf0438489b848b8f039f88bb518e.zip
Consolidate and rework CoercePointee and DispatchFromDyn errors
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0374.md53
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0375.md47
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0376.md38
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0377.md23
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl13
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs67
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs70
-rw-r--r--tests/ui/coercion/issue-26905.stderr13
-rw-r--r--tests/ui/error-codes/E0374.stderr2
-rw-r--r--tests/ui/error-codes/E0375.stderr13
-rw-r--r--tests/ui/error-codes/E0376.rs10
-rw-r--r--tests/ui/error-codes/E0376.stderr9
-rw-r--r--tests/ui/invalid_dispatch_from_dyn_impls.rs14
-rw-r--r--tests/ui/invalid_dispatch_from_dyn_impls.stderr28
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs2
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr13
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute.rs2
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute.stderr13
-rw-r--r--tests/ui/traits/issue-78372.stderr4
19 files changed, 158 insertions, 276 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0374.md b/compiler/rustc_error_codes/src/error_codes/E0374.md
index 6d7dc88823c..63c243b54ff 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0374.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0374.md
@@ -1,5 +1,5 @@
-`CoerceUnsized` was implemented on a struct which does not contain a field with
-an unsized type.
+`CoerceUnsized` or `DispatchFromDyn` was implemented on a struct which does not
+contain a field that is being unsized.
 
 Example of erroneous code:
 
@@ -11,47 +11,20 @@ struct Foo<T: ?Sized> {
     a: i32,
 }
 
-// error: Struct `Foo` has no unsized fields that need `CoerceUnsized`.
+// error: Struct `Foo` has no unsized fields that need to be coerced.
 impl<T, U> CoerceUnsized<Foo<U>> for Foo<T>
     where T: CoerceUnsized<U> {}
 ```
 
-An [unsized type][1] is any type where the compiler does not know the length or
-alignment of at compile time. Any struct containing an unsized type is also
-unsized.
+`CoerceUnsized` is used to coerce structs that have a field that can be unsized,
+like a custom `MyBox<T>` being unsized to `MyBox<dyn Trait>`. `DispatchFromDyn`
+is used to dispatch from `MyBox<dyn Trait>` to `MyBox<Self>` in a dyn-compatible
+trait.
 
-[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
+If the struct doesn't have any fields of unsized types then there is no
+meaningful way to implement `CoerceUnsized` or `DispatchFromDyn`, since
+there is no coercion taking place.
 
-`CoerceUnsized` is used to coerce one struct containing an unsized type
-into another struct containing a different unsized type. If the struct
-doesn't have any fields of unsized types then you don't need explicit
-coercion to get the types you want. To fix this you can either
-not try to implement `CoerceUnsized` or you can add a field that is
-unsized to the struct.
-
-Example:
-
-```
-#![feature(coerce_unsized)]
-use std::ops::CoerceUnsized;
-
-// We don't need to impl `CoerceUnsized` here.
-struct Foo {
-    a: i32,
-}
-
-// We add the unsized type field to the struct.
-struct Bar<T: ?Sized> {
-    a: i32,
-    b: T,
-}
-
-// The struct has an unsized field so we can implement
-// `CoerceUnsized` for it.
-impl<T, U> CoerceUnsized<Bar<U>> for Bar<T>
-    where T: CoerceUnsized<U> {}
-```
-
-Note that `CoerceUnsized` is mainly used by smart pointers like `Box`, `Rc`
-and `Arc` to be able to mark that they can coerce unsized types that they
-are pointing at.
+Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers
+like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types
+that they are pointing at.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0375.md b/compiler/rustc_error_codes/src/error_codes/E0375.md
index 71e53057165..7abb3b6afd0 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0375.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0375.md
@@ -1,5 +1,5 @@
-`CoerceUnsized` was implemented on a struct which contains more than one field
-with an unsized type.
+`CoerceUnsized` or `DispatchFromDyn` was implemented on a struct which contains
+more than one field that is being unsized.
 
 Erroneous code example:
 
@@ -17,39 +17,14 @@ struct Foo<T: ?Sized, U: ?Sized> {
 impl<T, U> CoerceUnsized<Foo<U, T>> for Foo<T, U> {}
 ```
 
-A struct with more than one field containing an unsized type cannot implement
-`CoerceUnsized`. This only occurs when you are trying to coerce one of the
-types in your struct to another type in the struct. In this case we try to
-impl `CoerceUnsized` from `T` to `U` which are both types that the struct
-takes. An [unsized type][1] is any type that the compiler doesn't know the
-length or alignment of at compile time. Any struct containing an unsized type
-is also unsized.
+`CoerceUnsized` is used to coerce structs that have a field that can be unsized,
+like a custom `MyBox<T>` being unsized to `MyBox<dyn Trait>`. `DispatchFromDyn`
+is used to dispatch from `MyBox<dyn Trait>` to `MyBox<Self>` in a dyn-compatible
+trait.
 
-`CoerceUnsized` only allows for coercion from a structure with a single
-unsized type field to another struct with a single unsized type field.
-In fact Rust only allows for a struct to have one unsized type in a struct
-and that unsized type must be the last field in the struct. So having two
-unsized types in a single struct is not allowed by the compiler. To fix this
-use only one field containing an unsized type in the struct and then use
-multiple structs to manage each unsized type field you need.
+If the struct has multiple fields that must be unsized, then the compiler has no
+way to generate a valid implementation of `CoerceUnsized` or `DispatchFromDyn`.
 
-Example:
-
-```
-#![feature(coerce_unsized)]
-use std::ops::CoerceUnsized;
-
-struct Foo<T: ?Sized> {
-    a: i32,
-    b: T,
-}
-
-impl <T, U> CoerceUnsized<Foo<U>> for Foo<T>
-    where T: CoerceUnsized<U> {}
-
-fn coerce_foo<T: CoerceUnsized<U>, U>(t: T) -> Foo<U> {
-    Foo { a: 12i32, b: t } // we use coercion to get the `Foo<U>` type we need
-}
-```
-
-[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
+Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers
+like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types
+that they are pointing at.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0376.md b/compiler/rustc_error_codes/src/error_codes/E0376.md
index 50de15bd30f..5b564ec22fc 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0376.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0376.md
@@ -1,8 +1,11 @@
-`CoerceUnsized` was implemented on something that isn't a struct.
+#### Note: this error code is no longer emitted by the compiler.
+
+`CoerceUnsized` or `DispatchFromDyn` was implemented between two types that
+are not structs.
 
 Erroneous code example:
 
-```compile_fail,E0376
+```compile_fail,E0377
 #![feature(coerce_unsized)]
 use std::ops::CoerceUnsized;
 
@@ -14,33 +17,4 @@ struct Foo<T: ?Sized> {
 impl<T, U> CoerceUnsized<U> for Foo<T> {}
 ```
 
-`CoerceUnsized` can only be implemented for a struct. Unsized types are
-already able to be coerced without an implementation of `CoerceUnsized`
-whereas a struct containing an unsized type needs to know the unsized type
-field it's containing is able to be coerced. An [unsized type][1]
-is any type that the compiler doesn't know the length or alignment of at
-compile time. Any struct containing an unsized type is also unsized.
-
-[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
-
-The `CoerceUnsized` trait takes a struct type. Make sure the type you are
-providing to `CoerceUnsized` is a struct with only the last field containing an
-unsized type.
-
-Example:
-
-```
-#![feature(coerce_unsized)]
-use std::ops::CoerceUnsized;
-
-struct Foo<T> {
-    a: T,
-}
-
-// The `Foo<U>` is a struct so `CoerceUnsized` can be implemented
-impl<T, U> CoerceUnsized<Foo<U>> for Foo<T> where T: CoerceUnsized<U> {}
-```
-
-Note that in Rust, structs can only contain an unsized type if the field
-containing the unsized type is the last and only unsized type field in the
-struct.
+`CoerceUnsized` or `DispatchFromDyn` can only be implemented between structs.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0377.md b/compiler/rustc_error_codes/src/error_codes/E0377.md
index b1d36406332..cd2b26260a8 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0377.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0377.md
@@ -1,5 +1,5 @@
-The trait `CoerceUnsized` may only be implemented for a coercion between
-structures with the same definition.
+`CoerceUnsized` or `DispatchFromDyn` may only be implemented between structs
+of the same type.
 
 Example of erroneous code:
 
@@ -20,10 +20,15 @@ pub struct Bar<T: ?Sized> {
 impl<T, U> CoerceUnsized<Bar<U>> for Foo<T> where T: CoerceUnsized<U> {}
 ```
 
-When attempting to implement `CoerceUnsized`, the `impl` signature must look
-like: `impl CoerceUnsized<Type<U>> for Type<T> where T: CoerceUnsized<U>`;
-the *implementer* and *`CoerceUnsized` type parameter* must be the same
-type. In this example, `Bar` and `Foo` (even though structurally identical)
-are *not* the same type and are rejected. Learn more about the `CoerceUnsized`
-trait and DST coercion in
-[the `CoerceUnsized` docs](../std/ops/trait.CoerceUnsized.html).
+`CoerceUnsized` is used to coerce structs that have a field that can be unsized,
+like a custom `MyBox<T>` being unsized to `MyBox<dyn Trait>`. `DispatchFromDyn`
+is used to dispatch from `MyBox<dyn Trait>` to `MyBox<Self>` in a dyn-compatible
+trait.
+
+The compiler cannot support coercions between structs of different types, so
+a valid implementation of `CoerceUnsized` or `DispatchFromDyn` should be
+implemented between the same struct with different generic parameters.
+
+Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers
+like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types
+that they are pointing at.
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 47d5976be09..98eb4f65e22 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -85,6 +85,10 @@ hir_analysis_cmse_output_stack_spill =
     .note1 = functions with the `{$abi}` ABI must pass their result via the available return registers
     .note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
 
+hir_analysis_coerce_multi = implementing `{$trait_name}` does not allow multiple fields to be coerced
+    .note = the trait `{$trait_name}` may only be implemented when a single field is being coerced
+    .label = these fields must be coerced for `{$trait_name}` to be valid
+
 hir_analysis_coerce_pointee_no_field = `CoercePointee` can only be derived on `struct`s with at least one field
 
 hir_analysis_coerce_pointee_no_user_validity_assertion = asserting applicability of `derive(CoercePointee)` on a target data is forbidden
@@ -97,10 +101,7 @@ hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only ap
 
 hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures
 
-hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions
-    .note = `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
-    .coercions_note = currently, {$number} fields need coercions: {$coercions}
-    .label = requires multiple coercions
+hir_analysis_coerce_zero = implementing `{$trait_name}` requires a field to be coerced
 
 hir_analysis_coercion_between_struct_same_note = expected coercion between the same definition; expected `{$source_path}`, found `{$target_path}`
 
@@ -139,10 +140,6 @@ hir_analysis_cross_crate_traits = cross-crate traits with a default impl, like `
 hir_analysis_cross_crate_traits_defined = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type defined in the current crate
     .label = can't implement cross-crate trait for type in another crate
 
-hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait requires multiple coercions
-    .note = the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
-    .coercions_note = currently, {$number} fields need coercions: {$coercions}
-
 hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
 
 hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 5d70d537505..dc9a5a3db5d 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -240,16 +240,17 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
         (&RawPtr(_, a_mutbl), &RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
         (&Adt(def_a, args_a), &Adt(def_b, args_b)) if def_a.is_struct() && def_b.is_struct() => {
             if def_a != def_b {
-                let source_path = tcx.def_path_str(def_a.did());
-                let target_path = tcx.def_path_str(def_b.did());
-
-                return Err(tcx.dcx().emit_err(errors::DispatchFromDynCoercion {
-                    span,
-                    trait_name: "DispatchFromDyn",
-                    note: true,
-                    source_path,
-                    target_path,
-                }));
+                if def_a != def_b {
+                    let source_path = tcx.def_path_str(def_a.did());
+                    let target_path = tcx.def_path_str(def_b.did());
+                    return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
+                        span,
+                        trait_name: "DispatchFromDyn",
+                        note: true,
+                        source_path,
+                        target_path,
+                    }));
+                }
             }
 
             if def_a.repr().c() || def_a.repr().packed() {
@@ -301,43 +302,33 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
 
                         None
                     } else {
-                        Some((i, ty_a, ty_b))
+                        Some((i, ty_a, ty_b, tcx.def_span(field.did)))
                     }
                 })
                 .collect::<Vec<_>>();
             res?;
 
             if coerced_fields.is_empty() {
-                return Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
+                return Err(tcx.dcx().emit_err(errors::CoerceNoField {
                     span,
                     trait_name: "DispatchFromDyn",
                     note: true,
                 }));
             } else if coerced_fields.len() > 1 {
-                return Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti {
+                return Err(tcx.dcx().emit_err(errors::CoerceMulti {
                     span,
-                    coercions_note: true,
+                    trait_name: "DispatchFromDyn",
                     number: coerced_fields.len(),
-                    coercions: coerced_fields
-                        .iter()
-                        .map(|&(i, ty_a, ty_b)| {
-                            format!("`{}` (`{}` to `{}`)", fields[i].name, ty_a, ty_b,)
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", "),
+                    fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
                 }));
             } else {
                 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
-                for (_, ty_a, ty_b) in coerced_fields {
+                for (_, ty_a, ty_b, _) in coerced_fields {
                     ocx.register_obligation(Obligation::new(
                         tcx,
                         cause.clone(),
                         param_env,
-                        ty::TraitRef::new(
-                            tcx,
-                            dispatch_from_dyn_trait,
-                            [ty_a, ty_b],
-                        ),
+                        ty::TraitRef::new(tcx, dispatch_from_dyn_trait, [ty_a, ty_b]),
                     ));
                 }
                 let errors = ocx.select_all_or_error();
@@ -353,7 +344,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
         }
         _ => Err(tcx
             .dcx()
-            .emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" })),
+            .emit_err(errors::CoerceUnsizedNonStruct { span, trait_name: "DispatchFromDyn" })),
     }
 }
 
@@ -419,7 +410,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
             if def_a != def_b {
                 let source_path = tcx.def_path_str(def_a.did());
                 let target_path = tcx.def_path_str(def_b.did());
-                return Err(tcx.dcx().emit_err(errors::DispatchFromDynSame {
+                return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
                     span,
                     trait_name: "CoerceUnsized",
                     note: true,
@@ -501,12 +492,12 @@ pub(crate) fn coerce_unsized_info<'tcx>(
 
                     // Collect up all fields that were significantly changed
                     // i.e., those that contain T in coerce_unsized T -> U
-                    Some((i, a, b))
+                    Some((i, a, b, tcx.def_span(f.did)))
                 })
                 .collect::<Vec<_>>();
 
             if diff_fields.is_empty() {
-                return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
+                return Err(tcx.dcx().emit_err(errors::CoerceNoField {
                     span,
                     trait_name: "CoerceUnsized",
                     note: true,
@@ -519,19 +510,15 @@ pub(crate) fn coerce_unsized_info<'tcx>(
                     tcx.def_span(impl_did)
                 };
 
-                return Err(tcx.dcx().emit_err(errors::CoerceUnsizedMulti {
+                return Err(tcx.dcx().emit_err(errors::CoerceMulti {
                     span,
-                    coercions_note: true,
+                    trait_name: "CoerceUnsized",
                     number: diff_fields.len(),
-                    coercions: diff_fields
-                        .iter()
-                        .map(|&(i, a, b)| format!("`{}` (`{}` to `{}`)", fields[i].name, a, b))
-                        .collect::<Vec<_>>()
-                        .join(", "),
+                    fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
                 }));
             }
 
-            let (i, a, b) = diff_fields[0];
+            let (i, a, b, _) = diff_fields[0];
             let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
             (a, b, coerce_unsized_trait, Some(kind))
         }
@@ -539,7 +526,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
         _ => {
             return Err(tcx
                 .dcx()
-                .emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" }));
+                .emit_err(errors::CoerceUnsizedNonStruct { span, trait_name: "CoerceUnsized" }));
         }
     };
 
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 1a0b0edb257..a74d9b95e0e 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1165,18 +1165,6 @@ pub(crate) struct InherentTyOutside {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_may, code = E0378)]
-pub(crate) struct DispatchFromDynCoercion<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub trait_name: &'a str,
-    #[note(hir_analysis_coercion_between_struct_same_note)]
-    pub note: bool,
-    pub source_path: String,
-    pub target_path: String,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_analysis_dispatch_from_dyn_repr, code = E0378)]
 pub(crate) struct DispatchFromDynRepr {
     #[primary_span]
@@ -1293,41 +1281,40 @@ pub(crate) struct DispatchFromDynZST<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_may, code = E0378)]
-pub(crate) struct DispatchFromDynSingle<'a> {
+#[diag(hir_analysis_coerce_zero, code = E0374)]
+pub(crate) struct CoerceNoField {
     #[primary_span]
     pub span: Span,
-    pub trait_name: &'a str,
+    pub trait_name: &'static str,
     #[note(hir_analysis_coercion_between_struct_single_note)]
     pub note: bool,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_dispatch_from_dyn_multi, code = E0378)]
-#[note]
-pub(crate) struct DispatchFromDynMulti {
+#[diag(hir_analysis_coerce_multi, code = E0375)]
+pub(crate) struct CoerceMulti {
+    pub trait_name: &'static str,
     #[primary_span]
     pub span: Span,
-    #[note(hir_analysis_coercions_note)]
-    pub coercions_note: bool,
     pub number: usize,
-    pub coercions: String,
+    #[note]
+    pub fields: MultiSpan,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_may, code = E0376)]
-pub(crate) struct DispatchFromDynStruct<'a> {
+#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
+pub(crate) struct CoerceUnsizedNonStruct {
     #[primary_span]
     pub span: Span,
-    pub trait_name: &'a str,
+    pub trait_name: &'static str,
 }
 
 #[derive(Diagnostic)]
 #[diag(hir_analysis_coerce_unsized_may, code = E0377)]
-pub(crate) struct DispatchFromDynSame<'a> {
+pub(crate) struct CoerceSameStruct {
     #[primary_span]
     pub span: Span,
-    pub trait_name: &'a str,
+    pub trait_name: &'static str,
     #[note(hir_analysis_coercion_between_struct_same_note)]
     pub note: bool,
     pub source_path: String,
@@ -1335,37 +1322,6 @@ pub(crate) struct DispatchFromDynSame<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_may, code = E0374)]
-pub(crate) struct CoerceUnsizedOneField<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub trait_name: &'a str,
-    #[note(hir_analysis_coercion_between_struct_single_note)]
-    pub note: bool,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_multi, code = E0375)]
-#[note]
-pub(crate) struct CoerceUnsizedMulti {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[note(hir_analysis_coercions_note)]
-    pub coercions_note: bool,
-    pub number: usize,
-    pub coercions: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_may, code = E0378)]
-pub(crate) struct CoerceUnsizedMay<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub trait_name: &'a str,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_analysis_trait_cannot_impl_for_ty, code = E0204)]
 pub(crate) struct TraitCannotImplForTy {
     #[primary_span]
diff --git a/tests/ui/coercion/issue-26905.stderr b/tests/ui/coercion/issue-26905.stderr
index 86f6a14cd10..17387ae992b 100644
--- a/tests/ui/coercion/issue-26905.stderr
+++ b/tests/ui/coercion/issue-26905.stderr
@@ -1,11 +1,16 @@
-error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions
+error[E0375]: implementing `CoerceUnsized` does not allow multiple fields to be coerced
   --> $DIR/issue-26905.rs:16:40
    |
 LL | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<MyRc<U>> for MyRc<T>{ }
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
-   = note: currently, 2 fields need coercions: `_ptr` (`*const T` to `*const U`), `_boo` (`NotPhantomData<T>` to `NotPhantomData<U>`)
+note: the trait `CoerceUnsized` may only be implemented when a single field is being coerced
+  --> $DIR/issue-26905.rs:12:5
+   |
+LL |     _ptr: *const T,
+   |     ^^^^^^^^^^^^^^
+LL |     _boo: NotPhantomData<T>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0374.stderr b/tests/ui/error-codes/E0374.stderr
index 71eec4c16fd..95e6b95e0d5 100644
--- a/tests/ui/error-codes/E0374.stderr
+++ b/tests/ui/error-codes/E0374.stderr
@@ -6,7 +6,7 @@ LL | struct Foo<T: ?Sized> {
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
 
-error[E0374]: the trait `CoerceUnsized` may only be implemented for a coercion between structures
+error[E0374]: implementing `CoerceUnsized` requires a field to be coerced
   --> $DIR/E0374.rs:8:1
    |
 LL | / impl<T, U> CoerceUnsized<Foo<U>> for Foo<T>
diff --git a/tests/ui/error-codes/E0375.stderr b/tests/ui/error-codes/E0375.stderr
index af720bd40e7..a797ba9d461 100644
--- a/tests/ui/error-codes/E0375.stderr
+++ b/tests/ui/error-codes/E0375.stderr
@@ -23,14 +23,19 @@ help: the `Box` type always has a statically known size and allocates its conten
 LL |     b: Box<T>,
    |        ++++ +
 
-error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions
+error[E0375]: implementing `CoerceUnsized` does not allow multiple fields to be coerced
   --> $DIR/E0375.rs:10:12
    |
 LL | impl<T, U> CoerceUnsized<Foo<U, T>> for Foo<T, U> {}
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
-   = note: currently, 2 fields need coercions: `b` (`T` to `U`), `c` (`U` to `T`)
+note: the trait `CoerceUnsized` may only be implemented when a single field is being coerced
+  --> $DIR/E0375.rs:6:5
+   |
+LL |     b: T,
+   |     ^^^^
+LL |     c: U,
+   |     ^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/error-codes/E0376.rs b/tests/ui/error-codes/E0376.rs
deleted file mode 100644
index f092eb02c2b..00000000000
--- a/tests/ui/error-codes/E0376.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(coerce_unsized)]
-use std::ops::CoerceUnsized;
-
-struct Foo<T: ?Sized> {
-    a: T,
-}
-
-impl<T, U> CoerceUnsized<U> for Foo<T> {} //~ ERROR E0376
-
-fn main() {}
diff --git a/tests/ui/error-codes/E0376.stderr b/tests/ui/error-codes/E0376.stderr
deleted file mode 100644
index 46668e05a42..00000000000
--- a/tests/ui/error-codes/E0376.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0376]: the trait `CoerceUnsized` may only be implemented for a coercion between structures
-  --> $DIR/E0376.rs:8:1
-   |
-LL | impl<T, U> CoerceUnsized<U> for Foo<T> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0376`.
diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.rs b/tests/ui/invalid_dispatch_from_dyn_impls.rs
index b7bc766fbe0..972465d7197 100644
--- a/tests/ui/invalid_dispatch_from_dyn_impls.rs
+++ b/tests/ui/invalid_dispatch_from_dyn_impls.rs
@@ -8,9 +8,10 @@ use std::{
 struct WrapperWithExtraField<T>(T, i32);
 
 impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
+//~^ ERROR [E0378]
 where
     T: DispatchFromDyn<U>,
-{} //~^^^ ERROR [E0378]
+{}
 
 
 struct MultiplePointers<T: ?Sized>{
@@ -19,9 +20,10 @@ struct MultiplePointers<T: ?Sized>{
 }
 
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
+//~^ implementing `DispatchFromDyn` does not allow multiple fields to be coerced
 where
     T: Unsize<U>,
-{} //~^^^ ERROR [E0378]
+{}
 
 
 struct NothingToCoerce<T: ?Sized> {
@@ -29,23 +31,25 @@ struct NothingToCoerce<T: ?Sized> {
 }
 
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
-//~^ ERROR [E0378]
+//~^ ERROR implementing `DispatchFromDyn` requires a field to be coerced
 
 #[repr(C)]
 struct HasReprC<T: ?Sized>(Box<T>);
 
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
+//~^ ERROR [E0378]
 where
     T: Unsize<U>,
-{} //~^^^ ERROR [E0378]
+{}
 
 #[repr(align(64))]
 struct OverAlignedZst;
 struct OverAligned<T: ?Sized>(Box<T>, OverAlignedZst);
 
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
+//~^ ERROR [E0378]
     where
         T: Unsize<U>,
-{} //~^^^ ERROR [E0378]
+{}
 
 fn main() {}
diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.stderr b/tests/ui/invalid_dispatch_from_dyn_impls.stderr
index 02718334c73..93ec6bbe089 100644
--- a/tests/ui/invalid_dispatch_from_dyn_impls.stderr
+++ b/tests/ui/invalid_dispatch_from_dyn_impls.stderr
@@ -2,25 +2,32 @@ error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs co
   --> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1
    |
 LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
+LL | |
 LL | | where
 LL | |     T: DispatchFromDyn<U>,
    | |__________________________^
    |
    = note: extra field `1` of type `i32` is not allowed
 
-error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
-  --> $DIR/invalid_dispatch_from_dyn_impls.rs:21:1
+error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced
+  --> $DIR/invalid_dispatch_from_dyn_impls.rs:22:1
    |
 LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
+LL | |
 LL | | where
 LL | |     T: Unsize<U>,
    | |_________________^
    |
-   = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
-   = note: currently, 2 fields need coercions: `ptr1` (`*const T` to `*const U`), `ptr2` (`*const T` to `*const U`)
+note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced
+  --> $DIR/invalid_dispatch_from_dyn_impls.rs:18:5
+   |
+LL |     ptr1: *const T,
+   |     ^^^^^^^^^^^^^^
+LL |     ptr2: *const T,
+   |     ^^^^^^^^^^^^^^
 
-error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
-  --> $DIR/invalid_dispatch_from_dyn_impls.rs:31:1
+error[E0374]: implementing `DispatchFromDyn` requires a field to be coerced
+  --> $DIR/invalid_dispatch_from_dyn_impls.rs:33:1
    |
 LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,17 +35,19 @@ LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingT
    = note: expected a single field to be coerced, none found
 
 error[E0378]: structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
-  --> $DIR/invalid_dispatch_from_dyn_impls.rs:37:1
+  --> $DIR/invalid_dispatch_from_dyn_impls.rs:39:1
    |
 LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
+LL | |
 LL | | where
 LL | |     T: Unsize<U>,
    | |_________________^
 
 error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
-  --> $DIR/invalid_dispatch_from_dyn_impls.rs:46:1
+  --> $DIR/invalid_dispatch_from_dyn_impls.rs:49:1
    |
 LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
+LL | |
 LL | |     where
 LL | |         T: Unsize<U>,
    | |_____________________^
@@ -47,4 +56,5 @@ LL | |         T: Unsize<U>,
 
 error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0378`.
+Some errors have detailed explanations: E0374, E0375, E0378.
+For more information about an error, try `rustc --explain E0374`.
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs
index 71f198f7dc7..94b76fe9685 100644
--- a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs
@@ -15,7 +15,7 @@ struct Dispatchable<T: ?Sized, Z> {
 }
 
 impl<T, U> DispatchFromDyn<Dispatchable<U, i32>> for Dispatchable<T, ()>
-//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions
+//~^ ERROR implementing `DispatchFromDyn` does not allow multiple fields to be coerced
 where
     T: Unsize<U> + ?Sized,
     U: ?Sized,
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr
index 1f13c51f679..91760b9e2ea 100644
--- a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr
@@ -1,4 +1,4 @@
-error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
+error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced
   --> $DIR/dispatch-from-dyn-zst-transmute-zst-nonzst.rs:17:1
    |
 LL | / impl<T, U> DispatchFromDyn<Dispatchable<U, i32>> for Dispatchable<T, ()>
@@ -8,9 +8,14 @@ LL | |     T: Unsize<U> + ?Sized,
 LL | |     U: ?Sized,
    | |______________^
    |
-   = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
-   = note: currently, 2 fields need coercions: `_ptr` (`Box<T>` to `Box<U>`), `z` (`()` to `i32`)
+note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced
+  --> $DIR/dispatch-from-dyn-zst-transmute-zst-nonzst.rs:13:5
+   |
+LL |     _ptr: Box<T>,
+   |     ^^^^^^^^^^^^
+LL |     z: Z,
+   |     ^^^^
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0378`.
+For more information about this error, try `rustc --explain E0375`.
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute.rs b/tests/ui/self/dispatch-from-dyn-zst-transmute.rs
index 57c255b4d7b..967958ab486 100644
--- a/tests/ui/self/dispatch-from-dyn-zst-transmute.rs
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute.rs
@@ -15,7 +15,7 @@ struct Foo<'a, U: ?Sized> {
 }
 
 impl<'a, T, U> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T>
-//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions
+//~^ ERROR implementing `DispatchFromDyn` does not allow multiple fields to be coerced
 where
     T: Unsize<U> + ?Sized,
     U: ?Sized {}
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr b/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr
index 5a8ae88b5f1..cc8be45e99d 100644
--- a/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr
@@ -1,4 +1,4 @@
-error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
+error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced
   --> $DIR/dispatch-from-dyn-zst-transmute.rs:17:1
    |
 LL | / impl<'a, T, U> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T>
@@ -8,9 +8,14 @@ LL | |     T: Unsize<U> + ?Sized,
 LL | |     U: ?Sized {}
    | |_____________^
    |
-   = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
-   = note: currently, 2 fields need coercions: `token` (`IsSendToken<T>` to `IsSendToken<U>`), `ptr` (`&'a T` to `&'a U`)
+note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced
+  --> $DIR/dispatch-from-dyn-zst-transmute.rs:13:5
+   |
+LL |     token: IsSendToken<U>,
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |     ptr: &'a U,
+   |     ^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0378`.
+For more information about this error, try `rustc --explain E0375`.
diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr
index d4dfba4f039..fbc60ce5d83 100644
--- a/tests/ui/traits/issue-78372.stderr
+++ b/tests/ui/traits/issue-78372.stderr
@@ -65,7 +65,7 @@ LL |     fn foo(self: Smaht<Self, T>);
    = note: type of `self` must be `Self` or a type that dereferences to it
    = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
-error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
+error[E0377]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
   --> $DIR/issue-78372.rs:3:1
    |
 LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
@@ -73,5 +73,5 @@ LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
 
 error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0307, E0378, E0412, E0658.
+Some errors have detailed explanations: E0307, E0377, E0412, E0658.
 For more information about an error, try `rustc --explain E0307`.