Skip to content

Commit 0bb00e2

Browse files
authoredFeb 25, 2025
Rollup merge of rust-lang#137289 - compiler-errors:coerce-unsized-errors, r=oli-obk
Consolidate and improve error messaging for `CoerceUnsized` and `DispatchFromDyn` Firstly, this PR consolidates and reworks the error diagnostics for `CoercePointee` and `DispatchFromDyn`. There was a ton of duplication for no reason -- this reworks both the errors and also the error codes, since they can be shared between both traits since they report the same thing. Secondly, when encountering a struct with multiple fields that must be coerced, point out the field spans, rather than mentioning the fields by name. This makes the error message clearer, but also means that we don't mention the `__S` dummy parameter for `derive(CoercePointee)`. Thirdly, emit a custom error message when we encounter a trait error that comes from the recursive field `CoerceUnsized`/`DispatchFromDyn` trait check. **Note:** This is the only one I'm not too satisfied with -- I think it could use some more refinement, but ideally it explains that the field must be an unsize-able pointer... Feedback welcome. Finally, don't emit `DispatchFromDyn` validity errors if we detect `CoerceUnsized` validity errors from an impl of the same ADT. This is best reviewed per commit. r? `@oli-obk` perhaps? cc `@dingxiangfei2009` -- sorry for making my own attempt at this PR, but I wanted to see if I could implement a fix for rust-lang#136796 in a less complicated way, since communicating over github review comments can be a bit slow. I'll leave comments inline to explain my thinking about the diagnostics changes.
2 parents 748af6b + b46acc0 commit 0bb00e2

22 files changed

+308
-310
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
`CoerceUnsized` was implemented on a struct which does not contain a field with
2-
an unsized type.
1+
`CoerceUnsized` or `DispatchFromDyn` was implemented on a struct which does not
2+
contain a field that is being unsized.
33

44
Example of erroneous code:
55

@@ -11,47 +11,20 @@ struct Foo<T: ?Sized> {
1111
a: i32,
1212
}
1313
14-
// error: Struct `Foo` has no unsized fields that need `CoerceUnsized`.
14+
// error: Struct `Foo` has no unsized fields that need to be coerced.
1515
impl<T, U> CoerceUnsized<Foo<U>> for Foo<T>
1616
where T: CoerceUnsized<U> {}
1717
```
1818

19-
An [unsized type][1] is any type where the compiler does not know the length or
20-
alignment of at compile time. Any struct containing an unsized type is also
21-
unsized.
19+
`CoerceUnsized` is used to coerce structs that have a field that can be unsized,
20+
like a custom `MyBox<T>` being unsized to `MyBox<dyn Trait>`. `DispatchFromDyn`
21+
is used to dispatch from `MyBox<dyn Trait>` to `MyBox<Self>` in a dyn-compatible
22+
trait.
2223

23-
[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
24+
If the struct doesn't have any fields of unsized types then there is no
25+
meaningful way to implement `CoerceUnsized` or `DispatchFromDyn`, since
26+
there is no coercion taking place.
2427

25-
`CoerceUnsized` is used to coerce one struct containing an unsized type
26-
into another struct containing a different unsized type. If the struct
27-
doesn't have any fields of unsized types then you don't need explicit
28-
coercion to get the types you want. To fix this you can either
29-
not try to implement `CoerceUnsized` or you can add a field that is
30-
unsized to the struct.
31-
32-
Example:
33-
34-
```
35-
#![feature(coerce_unsized)]
36-
use std::ops::CoerceUnsized;
37-
38-
// We don't need to impl `CoerceUnsized` here.
39-
struct Foo {
40-
a: i32,
41-
}
42-
43-
// We add the unsized type field to the struct.
44-
struct Bar<T: ?Sized> {
45-
a: i32,
46-
b: T,
47-
}
48-
49-
// The struct has an unsized field so we can implement
50-
// `CoerceUnsized` for it.
51-
impl<T, U> CoerceUnsized<Bar<U>> for Bar<T>
52-
where T: CoerceUnsized<U> {}
53-
```
54-
55-
Note that `CoerceUnsized` is mainly used by smart pointers like `Box`, `Rc`
56-
and `Arc` to be able to mark that they can coerce unsized types that they
57-
are pointing at.
28+
Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers
29+
like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types
30+
that they are pointing at.
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
`CoerceUnsized` was implemented on a struct which contains more than one field
2-
with an unsized type.
1+
`CoerceUnsized` or `DispatchFromDyn` was implemented on a struct which contains
2+
more than one field that is being unsized.
33

44
Erroneous code example:
55

@@ -17,39 +17,14 @@ struct Foo<T: ?Sized, U: ?Sized> {
1717
impl<T, U> CoerceUnsized<Foo<U, T>> for Foo<T, U> {}
1818
```
1919

20-
A struct with more than one field containing an unsized type cannot implement
21-
`CoerceUnsized`. This only occurs when you are trying to coerce one of the
22-
types in your struct to another type in the struct. In this case we try to
23-
impl `CoerceUnsized` from `T` to `U` which are both types that the struct
24-
takes. An [unsized type][1] is any type that the compiler doesn't know the
25-
length or alignment of at compile time. Any struct containing an unsized type
26-
is also unsized.
20+
`CoerceUnsized` is used to coerce structs that have a field that can be unsized,
21+
like a custom `MyBox<T>` being unsized to `MyBox<dyn Trait>`. `DispatchFromDyn`
22+
is used to dispatch from `MyBox<dyn Trait>` to `MyBox<Self>` in a dyn-compatible
23+
trait.
2724

28-
`CoerceUnsized` only allows for coercion from a structure with a single
29-
unsized type field to another struct with a single unsized type field.
30-
In fact Rust only allows for a struct to have one unsized type in a struct
31-
and that unsized type must be the last field in the struct. So having two
32-
unsized types in a single struct is not allowed by the compiler. To fix this
33-
use only one field containing an unsized type in the struct and then use
34-
multiple structs to manage each unsized type field you need.
25+
If the struct has multiple fields that must be unsized, then the compiler has no
26+
way to generate a valid implementation of `CoerceUnsized` or `DispatchFromDyn`.
3527

36-
Example:
37-
38-
```
39-
#![feature(coerce_unsized)]
40-
use std::ops::CoerceUnsized;
41-
42-
struct Foo<T: ?Sized> {
43-
a: i32,
44-
b: T,
45-
}
46-
47-
impl <T, U> CoerceUnsized<Foo<U>> for Foo<T>
48-
where T: CoerceUnsized<U> {}
49-
50-
fn coerce_foo<T: CoerceUnsized<U>, U>(t: T) -> Foo<U> {
51-
Foo { a: 12i32, b: t } // we use coercion to get the `Foo<U>` type we need
52-
}
53-
```
54-
55-
[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
28+
Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers
29+
like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types
30+
that they are pointing at.
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
`CoerceUnsized` was implemented on something that isn't a struct.
1+
#### Note: this error code is no longer emitted by the compiler.
2+
3+
`CoerceUnsized` or `DispatchFromDyn` was implemented between two types that
4+
are not structs.
25

36
Erroneous code example:
47

5-
```compile_fail,E0376
8+
```compile_fail,E0377
69
#![feature(coerce_unsized)]
710
use std::ops::CoerceUnsized;
811
@@ -14,33 +17,4 @@ struct Foo<T: ?Sized> {
1417
impl<T, U> CoerceUnsized<U> for Foo<T> {}
1518
```
1619

17-
`CoerceUnsized` can only be implemented for a struct. Unsized types are
18-
already able to be coerced without an implementation of `CoerceUnsized`
19-
whereas a struct containing an unsized type needs to know the unsized type
20-
field it's containing is able to be coerced. An [unsized type][1]
21-
is any type that the compiler doesn't know the length or alignment of at
22-
compile time. Any struct containing an unsized type is also unsized.
23-
24-
[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
25-
26-
The `CoerceUnsized` trait takes a struct type. Make sure the type you are
27-
providing to `CoerceUnsized` is a struct with only the last field containing an
28-
unsized type.
29-
30-
Example:
31-
32-
```
33-
#![feature(coerce_unsized)]
34-
use std::ops::CoerceUnsized;
35-
36-
struct Foo<T> {
37-
a: T,
38-
}
39-
40-
// The `Foo<U>` is a struct so `CoerceUnsized` can be implemented
41-
impl<T, U> CoerceUnsized<Foo<U>> for Foo<T> where T: CoerceUnsized<U> {}
42-
```
43-
44-
Note that in Rust, structs can only contain an unsized type if the field
45-
containing the unsized type is the last and only unsized type field in the
46-
struct.
20+
`CoerceUnsized` or `DispatchFromDyn` can only be implemented between structs.

‎compiler/rustc_error_codes/src/error_codes/E0377.md

+14-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
The trait `CoerceUnsized` may only be implemented for a coercion between
2-
structures with the same definition.
1+
`CoerceUnsized` or `DispatchFromDyn` may only be implemented between structs
2+
of the same type.
33

44
Example of erroneous code:
55

@@ -20,10 +20,15 @@ pub struct Bar<T: ?Sized> {
2020
impl<T, U> CoerceUnsized<Bar<U>> for Foo<T> where T: CoerceUnsized<U> {}
2121
```
2222

23-
When attempting to implement `CoerceUnsized`, the `impl` signature must look
24-
like: `impl CoerceUnsized<Type<U>> for Type<T> where T: CoerceUnsized<U>`;
25-
the *implementer* and *`CoerceUnsized` type parameter* must be the same
26-
type. In this example, `Bar` and `Foo` (even though structurally identical)
27-
are *not* the same type and are rejected. Learn more about the `CoerceUnsized`
28-
trait and DST coercion in
29-
[the `CoerceUnsized` docs](../std/ops/trait.CoerceUnsized.html).
23+
`CoerceUnsized` is used to coerce structs that have a field that can be unsized,
24+
like a custom `MyBox<T>` being unsized to `MyBox<dyn Trait>`. `DispatchFromDyn`
25+
is used to dispatch from `MyBox<dyn Trait>` to `MyBox<Self>` in a dyn-compatible
26+
trait.
27+
28+
The compiler cannot support coercions between structs of different types, so
29+
a valid implementation of `CoerceUnsized` or `DispatchFromDyn` should be
30+
implemented between the same struct with different generic parameters.
31+
32+
Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers
33+
like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types
34+
that they are pointing at.

‎compiler/rustc_hir_analysis/messages.ftl

+8-8
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ hir_analysis_cmse_output_stack_spill =
8585
.note1 = functions with the `{$abi}` ABI must pass their result via the available return registers
8686
.note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
8787
88+
hir_analysis_coerce_multi = implementing `{$trait_name}` does not allow multiple fields to be coerced
89+
.note = the trait `{$trait_name}` may only be implemented when a single field is being coerced
90+
.label = these fields must be coerced for `{$trait_name}` to be valid
91+
8892
hir_analysis_coerce_pointee_no_field = `CoercePointee` can only be derived on `struct`s with at least one field
8993
9094
hir_analysis_coerce_pointee_no_user_validity_assertion = asserting applicability of `derive(CoercePointee)` on a target data is forbidden
@@ -95,12 +99,12 @@ hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applica
9599
96100
hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout
97101
102+
hir_analysis_coerce_unsized_field_validity = for `{$ty}` to have a valid implementation of `{$trait_name}`, it must be possible to coerce the field of type `{$field_ty}`
103+
.label = `{$field_ty}` must be a pointer, reference, or smart pointer that is allowed to be unsized
104+
98105
hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures
99106
100-
hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions
101-
.note = `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
102-
.coercions_note = currently, {$number} fields need coercions: {$coercions}
103-
.label = requires multiple coercions
107+
hir_analysis_coerce_zero = implementing `{$trait_name}` requires a field to be coerced
104108
105109
hir_analysis_coercion_between_struct_same_note = expected coercion between the same definition; expected `{$source_path}`, found `{$target_path}`
106110
@@ -139,10 +143,6 @@ hir_analysis_cross_crate_traits = cross-crate traits with a default impl, like `
139143
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
140144
.label = can't implement cross-crate trait for type in another crate
141145
142-
hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait requires multiple coercions
143-
.note = the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
144-
.coercions_note = currently, {$number} fields need coercions: {$coercions}
145-
146146
hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
147147
148148
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

‎compiler/rustc_hir_analysis/src/coherence/builtin.rs

+93-77
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_middle::ty::print::PrintTraitRefExt as _;
1717
use rustc_middle::ty::{
1818
self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params,
1919
};
20-
use rustc_span::{DUMMY_SP, Span};
20+
use rustc_span::{DUMMY_SP, Span, sym};
2121
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
2222
use rustc_trait_selection::traits::misc::{
2323
ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
@@ -195,8 +195,14 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E
195195
// Just compute this for the side-effects, in particular reporting
196196
// errors; other parts of the code may demand it for the info of
197197
// course.
198-
let span = tcx.def_span(impl_did);
199-
tcx.at(span).ensure_ok().coerce_unsized_info(impl_did)
198+
tcx.ensure_ok().coerce_unsized_info(impl_did)
199+
}
200+
201+
fn is_from_coerce_pointee_derive(tcx: TyCtxt<'_>, span: Span) -> bool {
202+
span.ctxt()
203+
.outer_expn_data()
204+
.macro_def_id
205+
.is_some_and(|def_id| tcx.is_diagnostic_item(sym::CoercePointee, def_id))
200206
}
201207

202208
fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
@@ -206,17 +212,29 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
206212
debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
207213

208214
let span = tcx.def_span(impl_did);
215+
let trait_name = "DispatchFromDyn";
209216

210217
let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
211218

212219
let source = trait_ref.self_ty();
213-
assert!(!source.has_escaping_bound_vars());
214220
let target = {
215221
assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
216222

217223
trait_ref.args.type_at(1)
218224
};
219225

226+
// Check `CoercePointee` impl is WF -- if not, then there's no reason to report
227+
// redundant errors for `DispatchFromDyn`. This is best effort, though.
228+
let mut res = Ok(());
229+
tcx.for_each_relevant_impl(
230+
tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)),
231+
source,
232+
|impl_def_id| {
233+
res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id));
234+
},
235+
);
236+
res?;
237+
220238
debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
221239

222240
let param_env = tcx.param_env(impl_did);
@@ -242,26 +260,25 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
242260
if def_a != def_b {
243261
let source_path = tcx.def_path_str(def_a.did());
244262
let target_path = tcx.def_path_str(def_b.did());
245-
246-
return Err(tcx.dcx().emit_err(errors::DispatchFromDynCoercion {
263+
return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
247264
span,
248-
trait_name: "DispatchFromDyn",
265+
trait_name,
249266
note: true,
250267
source_path,
251268
target_path,
252269
}));
253270
}
254271

255-
let mut res = Ok(());
256272
if def_a.repr().c() || def_a.repr().packed() {
257-
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
273+
return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
258274
}
259275

260276
let fields = &def_a.non_enum_variant().fields;
261277

278+
let mut res = Ok(());
262279
let coerced_fields = fields
263-
.iter()
264-
.filter(|field| {
280+
.iter_enumerated()
281+
.filter_map(|(i, field)| {
265282
// Ignore PhantomData fields
266283
let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
267284
if tcx
@@ -272,7 +289,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
272289
.unwrap_or(unnormalized_ty)
273290
.is_phantom_data()
274291
{
275-
return false;
292+
return None;
276293
}
277294

278295
let ty_a = field.ty(tcx, args_a);
@@ -290,7 +307,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
290307
&& !ty_a.has_non_region_param()
291308
{
292309
// ignore 1-ZST fields
293-
return false;
310+
return None;
294311
}
295312

296313
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
@@ -299,64 +316,57 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
299316
ty: ty_a,
300317
}));
301318

302-
return false;
319+
None
320+
} else {
321+
Some((i, ty_a, ty_b, tcx.def_span(field.did)))
303322
}
304-
305-
true
306323
})
307324
.collect::<Vec<_>>();
325+
res?;
308326

309327
if coerced_fields.is_empty() {
310-
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
328+
return Err(tcx.dcx().emit_err(errors::CoerceNoField {
311329
span,
312-
trait_name: "DispatchFromDyn",
330+
trait_name,
313331
note: true,
314332
}));
315-
} else if coerced_fields.len() > 1 {
316-
res = Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti {
317-
span,
318-
coercions_note: true,
319-
number: coerced_fields.len(),
320-
coercions: coerced_fields
321-
.iter()
322-
.map(|field| {
323-
format!(
324-
"`{}` (`{}` to `{}`)",
325-
field.name,
326-
field.ty(tcx, args_a),
327-
field.ty(tcx, args_b),
328-
)
329-
})
330-
.collect::<Vec<_>>()
331-
.join(", "),
332-
}));
333-
} else {
333+
} else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {
334334
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
335-
for field in coerced_fields {
336-
ocx.register_obligation(Obligation::new(
337-
tcx,
338-
cause.clone(),
339-
param_env,
340-
ty::TraitRef::new(
341-
tcx,
342-
dispatch_from_dyn_trait,
343-
[field.ty(tcx, args_a), field.ty(tcx, args_b)],
344-
),
345-
));
346-
}
335+
ocx.register_obligation(Obligation::new(
336+
tcx,
337+
cause.clone(),
338+
param_env,
339+
ty::TraitRef::new(tcx, dispatch_from_dyn_trait, [ty_a, ty_b]),
340+
));
347341
let errors = ocx.select_all_or_error();
348342
if !errors.is_empty() {
349-
res = Err(infcx.err_ctxt().report_fulfillment_errors(errors));
343+
if is_from_coerce_pointee_derive(tcx, span) {
344+
return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
345+
span,
346+
trait_name,
347+
ty: trait_ref.self_ty(),
348+
field_span,
349+
field_ty: ty_a,
350+
}));
351+
} else {
352+
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
353+
}
350354
}
351355

352356
// Finally, resolve all regions.
353-
res = res.and(ocx.resolve_regions_and_report_errors(impl_did, param_env, []));
357+
ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
358+
359+
Ok(())
360+
} else {
361+
return Err(tcx.dcx().emit_err(errors::CoerceMulti {
362+
span,
363+
trait_name,
364+
number: coerced_fields.len(),
365+
fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
366+
}));
354367
}
355-
res
356368
}
357-
_ => Err(tcx
358-
.dcx()
359-
.emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" })),
369+
_ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })),
360370
}
361371
}
362372

@@ -366,13 +376,14 @@ pub(crate) fn coerce_unsized_info<'tcx>(
366376
) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
367377
debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
368378
let span = tcx.def_span(impl_did);
379+
let trait_name = "CoerceUnsized";
369380

370381
let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
371-
372382
let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
373383

374384
let source = tcx.type_of(impl_did).instantiate_identity();
375385
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
386+
376387
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
377388
let target = trait_ref.args.type_at(1);
378389
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
@@ -399,9 +410,9 @@ pub(crate) fn coerce_unsized_info<'tcx>(
399410
)
400411
.emit();
401412
}
402-
(mt_a.ty, mt_b.ty, unsize_trait, None)
413+
(mt_a.ty, mt_b.ty, unsize_trait, None, span)
403414
};
404-
let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
415+
let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
405416
(&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
406417
infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
407418
let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
@@ -422,9 +433,9 @@ pub(crate) fn coerce_unsized_info<'tcx>(
422433
if def_a != def_b {
423434
let source_path = tcx.def_path_str(def_a.did());
424435
let target_path = tcx.def_path_str(def_b.did());
425-
return Err(tcx.dcx().emit_err(errors::DispatchFromDynSame {
436+
return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
426437
span,
427-
trait_name: "CoerceUnsized",
438+
trait_name,
428439
note: true,
429440
source_path,
430441
target_path,
@@ -504,14 +515,14 @@ pub(crate) fn coerce_unsized_info<'tcx>(
504515

505516
// Collect up all fields that were significantly changed
506517
// i.e., those that contain T in coerce_unsized T -> U
507-
Some((i, a, b))
518+
Some((i, a, b, tcx.def_span(f.did)))
508519
})
509520
.collect::<Vec<_>>();
510521

511522
if diff_fields.is_empty() {
512-
return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
523+
return Err(tcx.dcx().emit_err(errors::CoerceNoField {
513524
span,
514-
trait_name: "CoerceUnsized",
525+
trait_name,
515526
note: true,
516527
}));
517528
} else if diff_fields.len() > 1 {
@@ -522,27 +533,21 @@ pub(crate) fn coerce_unsized_info<'tcx>(
522533
tcx.def_span(impl_did)
523534
};
524535

525-
return Err(tcx.dcx().emit_err(errors::CoerceUnsizedMulti {
536+
return Err(tcx.dcx().emit_err(errors::CoerceMulti {
526537
span,
527-
coercions_note: true,
538+
trait_name,
528539
number: diff_fields.len(),
529-
coercions: diff_fields
530-
.iter()
531-
.map(|&(i, a, b)| format!("`{}` (`{}` to `{}`)", fields[i].name, a, b))
532-
.collect::<Vec<_>>()
533-
.join(", "),
540+
fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
534541
}));
535542
}
536543

537-
let (i, a, b) = diff_fields[0];
544+
let (i, a, b, field_span) = diff_fields[0];
538545
let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
539-
(a, b, coerce_unsized_trait, Some(kind))
546+
(a, b, coerce_unsized_trait, Some(kind), field_span)
540547
}
541548

542549
_ => {
543-
return Err(tcx
544-
.dcx()
545-
.emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" }));
550+
return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
546551
}
547552
};
548553

@@ -557,12 +562,23 @@ pub(crate) fn coerce_unsized_info<'tcx>(
557562
);
558563
ocx.register_obligation(obligation);
559564
let errors = ocx.select_all_or_error();
565+
560566
if !errors.is_empty() {
561-
infcx.err_ctxt().report_fulfillment_errors(errors);
567+
if is_from_coerce_pointee_derive(tcx, span) {
568+
return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
569+
span,
570+
trait_name,
571+
ty: trait_ref.self_ty(),
572+
field_span,
573+
field_ty: source,
574+
}));
575+
} else {
576+
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
577+
}
562578
}
563579

564580
// Finally, resolve all regions.
565-
let _ = ocx.resolve_regions_and_report_errors(impl_did, param_env, []);
581+
ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
566582

567583
Ok(CoerceUnsizedInfo { custom_kind: kind })
568584
}

‎compiler/rustc_hir_analysis/src/errors.rs

+19-51
Original file line numberDiff line numberDiff line change
@@ -1164,18 +1164,6 @@ pub(crate) struct InherentTyOutside {
11641164
pub span: Span,
11651165
}
11661166

1167-
#[derive(Diagnostic)]
1168-
#[diag(hir_analysis_coerce_unsized_may, code = E0378)]
1169-
pub(crate) struct DispatchFromDynCoercion<'a> {
1170-
#[primary_span]
1171-
pub span: Span,
1172-
pub trait_name: &'a str,
1173-
#[note(hir_analysis_coercion_between_struct_same_note)]
1174-
pub note: bool,
1175-
pub source_path: String,
1176-
pub target_path: String,
1177-
}
1178-
11791167
#[derive(Diagnostic)]
11801168
#[diag(hir_analysis_dispatch_from_dyn_repr, code = E0378)]
11811169
pub(crate) struct DispatchFromDynRepr {
@@ -1293,76 +1281,56 @@ pub(crate) struct DispatchFromDynZST<'a> {
12931281
}
12941282

12951283
#[derive(Diagnostic)]
1296-
#[diag(hir_analysis_coerce_unsized_may, code = E0378)]
1297-
pub(crate) struct DispatchFromDynSingle<'a> {
1284+
#[diag(hir_analysis_coerce_zero, code = E0374)]
1285+
pub(crate) struct CoerceNoField {
12981286
#[primary_span]
12991287
pub span: Span,
1300-
pub trait_name: &'a str,
1288+
pub trait_name: &'static str,
13011289
#[note(hir_analysis_coercion_between_struct_single_note)]
13021290
pub note: bool,
13031291
}
13041292

13051293
#[derive(Diagnostic)]
1306-
#[diag(hir_analysis_dispatch_from_dyn_multi, code = E0378)]
1307-
#[note]
1308-
pub(crate) struct DispatchFromDynMulti {
1294+
#[diag(hir_analysis_coerce_multi, code = E0375)]
1295+
pub(crate) struct CoerceMulti {
1296+
pub trait_name: &'static str,
13091297
#[primary_span]
13101298
pub span: Span,
1311-
#[note(hir_analysis_coercions_note)]
1312-
pub coercions_note: bool,
13131299
pub number: usize,
1314-
pub coercions: String,
1300+
#[note]
1301+
pub fields: MultiSpan,
13151302
}
13161303

13171304
#[derive(Diagnostic)]
1318-
#[diag(hir_analysis_coerce_unsized_may, code = E0376)]
1319-
pub(crate) struct DispatchFromDynStruct<'a> {
1305+
#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
1306+
pub(crate) struct CoerceUnsizedNonStruct {
13201307
#[primary_span]
13211308
pub span: Span,
1322-
pub trait_name: &'a str,
1309+
pub trait_name: &'static str,
13231310
}
13241311

13251312
#[derive(Diagnostic)]
13261313
#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
1327-
pub(crate) struct DispatchFromDynSame<'a> {
1314+
pub(crate) struct CoerceSameStruct {
13281315
#[primary_span]
13291316
pub span: Span,
1330-
pub trait_name: &'a str,
1317+
pub trait_name: &'static str,
13311318
#[note(hir_analysis_coercion_between_struct_same_note)]
13321319
pub note: bool,
13331320
pub source_path: String,
13341321
pub target_path: String,
13351322
}
13361323

13371324
#[derive(Diagnostic)]
1338-
#[diag(hir_analysis_coerce_unsized_may, code = E0374)]
1339-
pub(crate) struct CoerceUnsizedOneField<'a> {
1325+
#[diag(hir_analysis_coerce_unsized_field_validity)]
1326+
pub(crate) struct CoerceFieldValidity<'tcx> {
13401327
#[primary_span]
13411328
pub span: Span,
1342-
pub trait_name: &'a str,
1343-
#[note(hir_analysis_coercion_between_struct_single_note)]
1344-
pub note: bool,
1345-
}
1346-
1347-
#[derive(Diagnostic)]
1348-
#[diag(hir_analysis_coerce_unsized_multi, code = E0375)]
1349-
#[note]
1350-
pub(crate) struct CoerceUnsizedMulti {
1351-
#[primary_span]
1329+
pub ty: Ty<'tcx>,
1330+
pub trait_name: &'static str,
13521331
#[label]
1353-
pub span: Span,
1354-
#[note(hir_analysis_coercions_note)]
1355-
pub coercions_note: bool,
1356-
pub number: usize,
1357-
pub coercions: String,
1358-
}
1359-
1360-
#[derive(Diagnostic)]
1361-
#[diag(hir_analysis_coerce_unsized_may, code = E0378)]
1362-
pub(crate) struct CoerceUnsizedMay<'a> {
1363-
#[primary_span]
1364-
pub span: Span,
1365-
pub trait_name: &'a str,
1332+
pub field_span: Span,
1333+
pub field_ty: Ty<'tcx>,
13661334
}
13671335

13681336
#[derive(Diagnostic)]

‎library/core/src/marker.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,7 @@ pub trait FnPtr: Copy + Clone {
13021302
/// ```
13031303
#[rustc_builtin_macro(CoercePointee, attributes(pointee))]
13041304
#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize, coerce_pointee_validated)]
1305+
#[cfg_attr(not(test), rustc_diagnostic_item = "CoercePointee")]
13051306
#[unstable(feature = "derive_coerce_pointee", issue = "123430")]
13061307
pub macro CoercePointee($item:item) {
13071308
/* compiler built-in */

‎tests/ui/coercion/issue-26905.stderr

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions
1+
error[E0375]: implementing `CoerceUnsized` does not allow multiple fields to be coerced
22
--> $DIR/issue-26905.rs:16:40
33
|
44
LL | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<MyRc<U>> for MyRc<T>{ }
5-
| ^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions
5+
| ^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
8-
= note: currently, 2 fields need coercions: `_ptr` (`*const T` to `*const U`), `_boo` (`NotPhantomData<T>` to `NotPhantomData<U>`)
7+
note: the trait `CoerceUnsized` may only be implemented when a single field is being coerced
8+
--> $DIR/issue-26905.rs:12:5
9+
|
10+
LL | _ptr: *const T,
11+
| ^^^^^^^^^^^^^^
12+
LL | _boo: NotPhantomData<T>,
13+
| ^^^^^^^^^^^^^^^^^^^^^^^
914

1015
error: aborting due to 1 previous error
1116

‎tests/ui/deriving/deriving-coerce-pointee-neg.rs

+23
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,27 @@ struct TryToWipeRepr<'a, #[pointee] T: ?Sized> {
142142
ptr: &'a T,
143143
}
144144

145+
#[repr(transparent)]
146+
#[derive(CoercePointee)]
147+
//~^ ERROR for `RcWithId<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `Rc<(i32, Box<T>)>`
148+
struct RcWithId<T: ?Sized> {
149+
inner: std::rc::Rc<(i32, Box<T>)>,
150+
}
151+
152+
#[repr(transparent)]
153+
#[derive(CoercePointee)]
154+
//~^ ERROR implementing `CoerceUnsized` does not allow multiple fields to be coerced
155+
struct MoreThanOneField<T: ?Sized> {
156+
//~^ ERROR transparent struct needs at most one field with non-trivial size or alignment, but has 2
157+
inner1: Box<T>,
158+
inner2: Box<T>,
159+
}
160+
161+
struct NotCoercePointeeData<T: ?Sized>(T);
162+
163+
#[repr(transparent)]
164+
#[derive(CoercePointee)]
165+
//~^ ERROR for `UsingNonCoercePointeeData<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `NotCoercePointeeData<T>`
166+
struct UsingNonCoercePointeeData<T: ?Sized>(NotCoercePointeeData<T>);
167+
145168
fn main() {}

‎tests/ui/deriving/deriving-coerce-pointee-neg.stderr

+51-3
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,55 @@ error[E0802]: `derive(CoercePointee)` is only applicable to `struct` with `repr(
118118
LL | struct TryToWipeRepr<'a, #[pointee] T: ?Sized> {
119119
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
120120

121-
error: aborting due to 17 previous errors
121+
error: for `RcWithId<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `Rc<(i32, Box<T>)>`
122+
--> $DIR/deriving-coerce-pointee-neg.rs:146:10
123+
|
124+
LL | #[derive(CoercePointee)]
125+
| ^^^^^^^^^^^^^
126+
...
127+
LL | inner: std::rc::Rc<(i32, Box<T>)>,
128+
| --------------------------------- `Rc<(i32, Box<T>)>` must be a pointer, reference, or smart pointer that is allowed to be unsized
129+
|
130+
= note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
131+
132+
error[E0375]: implementing `CoerceUnsized` does not allow multiple fields to be coerced
133+
--> $DIR/deriving-coerce-pointee-neg.rs:153:10
134+
|
135+
LL | #[derive(CoercePointee)]
136+
| ^^^^^^^^^^^^^
137+
|
138+
note: the trait `CoerceUnsized` may only be implemented when a single field is being coerced
139+
--> $DIR/deriving-coerce-pointee-neg.rs:157:5
140+
|
141+
LL | inner1: Box<T>,
142+
| ^^^^^^^^^^^^^^
143+
LL | inner2: Box<T>,
144+
| ^^^^^^^^^^^^^^
145+
= note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
146+
147+
error: for `UsingNonCoercePointeeData<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `NotCoercePointeeData<T>`
148+
--> $DIR/deriving-coerce-pointee-neg.rs:164:10
149+
|
150+
LL | #[derive(CoercePointee)]
151+
| ^^^^^^^^^^^^^
152+
LL |
153+
LL | struct UsingNonCoercePointeeData<T: ?Sized>(NotCoercePointeeData<T>);
154+
| ----------------------- `NotCoercePointeeData<T>` must be a pointer, reference, or smart pointer that is allowed to be unsized
155+
|
156+
= note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
157+
158+
error[E0690]: transparent struct needs at most one field with non-trivial size or alignment, but has 2
159+
--> $DIR/deriving-coerce-pointee-neg.rs:155:1
160+
|
161+
LL | struct MoreThanOneField<T: ?Sized> {
162+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs at most one field with non-trivial size or alignment, but has 2
163+
LL |
164+
LL | inner1: Box<T>,
165+
| -------------- this field has non-zero size or requires alignment
166+
LL | inner2: Box<T>,
167+
| -------------- this field has non-zero size or requires alignment
168+
169+
error: aborting due to 21 previous errors
122170

123-
Some errors have detailed explanations: E0392, E0802.
124-
For more information about an error, try `rustc --explain E0392`.
171+
Some errors have detailed explanations: E0375, E0392, E0690, E0802.
172+
For more information about an error, try `rustc --explain E0375`.

‎tests/ui/error-codes/E0374.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | struct Foo<T: ?Sized> {
66
|
77
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
88

9-
error[E0374]: the trait `CoerceUnsized` may only be implemented for a coercion between structures
9+
error[E0374]: implementing `CoerceUnsized` requires a field to be coerced
1010
--> $DIR/E0374.rs:8:1
1111
|
1212
LL | / impl<T, U> CoerceUnsized<Foo<U>> for Foo<T>

‎tests/ui/error-codes/E0375.stderr

+9-4
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,19 @@ help: the `Box` type always has a statically known size and allocates its conten
2323
LL | b: Box<T>,
2424
| ++++ +
2525

26-
error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions
26+
error[E0375]: implementing `CoerceUnsized` does not allow multiple fields to be coerced
2727
--> $DIR/E0375.rs:10:12
2828
|
2929
LL | impl<T, U> CoerceUnsized<Foo<U, T>> for Foo<T, U> {}
30-
| ^^^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^
3131
|
32-
= note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
33-
= note: currently, 2 fields need coercions: `b` (`T` to `U`), `c` (`U` to `T`)
32+
note: the trait `CoerceUnsized` may only be implemented when a single field is being coerced
33+
--> $DIR/E0375.rs:6:5
34+
|
35+
LL | b: T,
36+
| ^^^^
37+
LL | c: U,
38+
| ^^^^
3439

3540
error: aborting due to 2 previous errors
3641

‎tests/ui/error-codes/E0376.rs

-10
This file was deleted.

‎tests/ui/error-codes/E0376.stderr

-9
This file was deleted.

‎tests/ui/invalid_dispatch_from_dyn_impls.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ use std::{
88
struct WrapperWithExtraField<T>(T, i32);
99

1010
impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
11+
//~^ ERROR [E0378]
1112
where
1213
T: DispatchFromDyn<U>,
13-
{} //~^^^ ERROR [E0378]
14+
{}
1415

1516

1617
struct MultiplePointers<T: ?Sized>{
@@ -19,33 +20,36 @@ struct MultiplePointers<T: ?Sized>{
1920
}
2021

2122
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
23+
//~^ implementing `DispatchFromDyn` does not allow multiple fields to be coerced
2224
where
2325
T: Unsize<U>,
24-
{} //~^^^ ERROR [E0378]
26+
{}
2527

2628

2729
struct NothingToCoerce<T: ?Sized> {
2830
data: PhantomData<T>,
2931
}
3032

3133
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
32-
//~^ ERROR [E0378]
34+
//~^ ERROR implementing `DispatchFromDyn` requires a field to be coerced
3335

3436
#[repr(C)]
3537
struct HasReprC<T: ?Sized>(Box<T>);
3638

3739
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
40+
//~^ ERROR [E0378]
3841
where
3942
T: Unsize<U>,
40-
{} //~^^^ ERROR [E0378]
43+
{}
4144

4245
#[repr(align(64))]
4346
struct OverAlignedZst;
4447
struct OverAligned<T: ?Sized>(Box<T>, OverAlignedZst);
4548

4649
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
50+
//~^ ERROR [E0378]
4751
where
4852
T: Unsize<U>,
49-
{} //~^^^ ERROR [E0378]
53+
{}
5054

5155
fn main() {}

‎tests/ui/invalid_dispatch_from_dyn_impls.stderr

+19-9
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,52 @@ error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs co
22
--> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1
33
|
44
LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
5+
LL | |
56
LL | | where
67
LL | | T: DispatchFromDyn<U>,
78
| |__________________________^
89
|
910
= note: extra field `1` of type `i32` is not allowed
1011

11-
error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
12-
--> $DIR/invalid_dispatch_from_dyn_impls.rs:21:1
12+
error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced
13+
--> $DIR/invalid_dispatch_from_dyn_impls.rs:22:1
1314
|
1415
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
16+
LL | |
1517
LL | | where
1618
LL | | T: Unsize<U>,
1719
| |_________________^
1820
|
19-
= note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
20-
= note: currently, 2 fields need coercions: `ptr1` (`*const T` to `*const U`), `ptr2` (`*const T` to `*const U`)
21+
note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced
22+
--> $DIR/invalid_dispatch_from_dyn_impls.rs:18:5
23+
|
24+
LL | ptr1: *const T,
25+
| ^^^^^^^^^^^^^^
26+
LL | ptr2: *const T,
27+
| ^^^^^^^^^^^^^^
2128

22-
error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
23-
--> $DIR/invalid_dispatch_from_dyn_impls.rs:31:1
29+
error[E0374]: implementing `DispatchFromDyn` requires a field to be coerced
30+
--> $DIR/invalid_dispatch_from_dyn_impls.rs:33:1
2431
|
2532
LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
2633
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2734
|
2835
= note: expected a single field to be coerced, none found
2936

3037
error[E0378]: structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
31-
--> $DIR/invalid_dispatch_from_dyn_impls.rs:37:1
38+
--> $DIR/invalid_dispatch_from_dyn_impls.rs:39:1
3239
|
3340
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
41+
LL | |
3442
LL | | where
3543
LL | | T: Unsize<U>,
3644
| |_________________^
3745

3846
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
39-
--> $DIR/invalid_dispatch_from_dyn_impls.rs:46:1
47+
--> $DIR/invalid_dispatch_from_dyn_impls.rs:49:1
4048
|
4149
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
50+
LL | |
4251
LL | | where
4352
LL | | T: Unsize<U>,
4453
| |_____________________^
@@ -47,4 +56,5 @@ LL | | T: Unsize<U>,
4756

4857
error: aborting due to 5 previous errors
4958

50-
For more information about this error, try `rustc --explain E0378`.
59+
Some errors have detailed explanations: E0374, E0375, E0378.
60+
For more information about an error, try `rustc --explain E0374`.

‎tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct Dispatchable<T: ?Sized, Z> {
1515
}
1616

1717
impl<T, U> DispatchFromDyn<Dispatchable<U, i32>> for Dispatchable<T, ()>
18-
//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions
18+
//~^ ERROR implementing `DispatchFromDyn` does not allow multiple fields to be coerced
1919
where
2020
T: Unsize<U> + ?Sized,
2121
U: ?Sized,
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
1+
error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced
22
--> $DIR/dispatch-from-dyn-zst-transmute-zst-nonzst.rs:17:1
33
|
44
LL | / impl<T, U> DispatchFromDyn<Dispatchable<U, i32>> for Dispatchable<T, ()>
@@ -8,9 +8,14 @@ LL | | T: Unsize<U> + ?Sized,
88
LL | | U: ?Sized,
99
| |______________^
1010
|
11-
= note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
12-
= note: currently, 2 fields need coercions: `_ptr` (`Box<T>` to `Box<U>`), `z` (`()` to `i32`)
11+
note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced
12+
--> $DIR/dispatch-from-dyn-zst-transmute-zst-nonzst.rs:13:5
13+
|
14+
LL | _ptr: Box<T>,
15+
| ^^^^^^^^^^^^
16+
LL | z: Z,
17+
| ^^^^
1318

1419
error: aborting due to 1 previous error
1520

16-
For more information about this error, try `rustc --explain E0378`.
21+
For more information about this error, try `rustc --explain E0375`.

‎tests/ui/self/dispatch-from-dyn-zst-transmute.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct Foo<'a, U: ?Sized> {
1515
}
1616

1717
impl<'a, T, U> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T>
18-
//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions
18+
//~^ ERROR implementing `DispatchFromDyn` does not allow multiple fields to be coerced
1919
where
2020
T: Unsize<U> + ?Sized,
2121
U: ?Sized {}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
1+
error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced
22
--> $DIR/dispatch-from-dyn-zst-transmute.rs:17:1
33
|
44
LL | / impl<'a, T, U> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T>
@@ -8,9 +8,14 @@ LL | | T: Unsize<U> + ?Sized,
88
LL | | U: ?Sized {}
99
| |_____________^
1010
|
11-
= note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
12-
= note: currently, 2 fields need coercions: `token` (`IsSendToken<T>` to `IsSendToken<U>`), `ptr` (`&'a T` to `&'a U`)
11+
note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced
12+
--> $DIR/dispatch-from-dyn-zst-transmute.rs:13:5
13+
|
14+
LL | token: IsSendToken<U>,
15+
| ^^^^^^^^^^^^^^^^^^^^^
16+
LL | ptr: &'a U,
17+
| ^^^^^^^^^^
1318

1419
error: aborting due to 1 previous error
1520

16-
For more information about this error, try `rustc --explain E0378`.
21+
For more information about this error, try `rustc --explain E0375`.

‎tests/ui/traits/issue-78372.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ LL | fn foo(self: Smaht<Self, T>);
6565
= note: type of `self` must be `Self` or a type that dereferences to it
6666
= 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`)
6767

68-
error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
68+
error[E0377]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
6969
--> $DIR/issue-78372.rs:3:1
7070
|
7171
LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
7272
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7373

7474
error: aborting due to 7 previous errors
7575

76-
Some errors have detailed explanations: E0307, E0378, E0412, E0658.
76+
Some errors have detailed explanations: E0307, E0377, E0412, E0658.
7777
For more information about an error, try `rustc --explain E0307`.

0 commit comments

Comments
 (0)
Please sign in to comment.