rustc_hir_analysis/coherence/
builtin.rs

1//! Check properties that are required by built-in traits and set
2//! up data structures required by type-checking/codegen.
3
4use std::assert_matches::assert_matches;
5use std::collections::BTreeMap;
6
7use rustc_data_structures::fx::FxHashSet;
8use rustc_errors::{ErrorGuaranteed, MultiSpan};
9use rustc_hir as hir;
10use rustc_hir::ItemKind;
11use rustc_hir::def_id::{DefId, LocalDefId};
12use rustc_hir::lang_items::LangItem;
13use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt};
14use rustc_infer::traits::Obligation;
15use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
16use rustc_middle::ty::print::PrintTraitRefExt as _;
17use rustc_middle::ty::{
18    self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params,
19};
20use rustc_span::{DUMMY_SP, Span, sym};
21use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
22use rustc_trait_selection::traits::misc::{
23    ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
24    type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
25};
26use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
27use tracing::debug;
28
29use crate::errors;
30
31pub(super) fn check_trait<'tcx>(
32    tcx: TyCtxt<'tcx>,
33    trait_def_id: DefId,
34    impl_def_id: LocalDefId,
35    impl_header: ty::ImplTraitHeader<'tcx>,
36) -> Result<(), ErrorGuaranteed> {
37    let lang_items = tcx.lang_items();
38    let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
39    checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
40    checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
41    checker.check(lang_items.const_param_ty_trait(), |checker| {
42        visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
43    })?;
44    checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
45        visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
46    })?;
47    checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
48    checker
49        .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
50    checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
51    checker.check(
52        lang_items.coerce_pointee_validated_trait(),
53        visit_implementation_of_coerce_pointee_validity,
54    )?;
55    Ok(())
56}
57
58struct Checker<'tcx> {
59    tcx: TyCtxt<'tcx>,
60    trait_def_id: DefId,
61    impl_def_id: LocalDefId,
62    impl_header: ty::ImplTraitHeader<'tcx>,
63}
64
65impl<'tcx> Checker<'tcx> {
66    fn check(
67        &self,
68        trait_def_id: Option<DefId>,
69        f: impl FnOnce(&Self) -> Result<(), ErrorGuaranteed>,
70    ) -> Result<(), ErrorGuaranteed> {
71        if Some(self.trait_def_id) == trait_def_id { f(self) } else { Ok(()) }
72    }
73}
74
75fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
76    let tcx = checker.tcx;
77    let impl_did = checker.impl_def_id;
78    // Destructors only work on local ADT types.
79    match checker.impl_header.trait_ref.instantiate_identity().self_ty().kind() {
80        ty::Adt(def, _) if def.did().is_local() => return Ok(()),
81        ty::Error(_) => return Ok(()),
82        _ => {}
83    }
84
85    let impl_ = tcx.hir_expect_item(impl_did).expect_impl();
86
87    Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span }))
88}
89
90fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
91    let tcx = checker.tcx;
92    let impl_header = checker.impl_header;
93    let impl_did = checker.impl_def_id;
94    debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
95
96    let self_type = impl_header.trait_ref.instantiate_identity().self_ty();
97    debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
98
99    let param_env = tcx.param_env(impl_did);
100    assert!(!self_type.has_escaping_bound_vars());
101
102    debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
103
104    if let ty::ImplPolarity::Negative = impl_header.polarity {
105        return Ok(());
106    }
107
108    let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
109    match type_allowed_to_implement_copy(tcx, param_env, self_type, cause, impl_header.safety) {
110        Ok(()) => Ok(()),
111        Err(CopyImplementationError::InfringingFields(fields)) => {
112            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
113            Err(infringing_fields_error(
114                tcx,
115                fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
116                LangItem::Copy,
117                impl_did,
118                span,
119            ))
120        }
121        Err(CopyImplementationError::NotAnAdt) => {
122            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
123            Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span }))
124        }
125        Err(CopyImplementationError::HasDestructor) => {
126            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
127            Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span }))
128        }
129        Err(CopyImplementationError::HasUnsafeFields) => {
130            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
131            Err(tcx
132                .dcx()
133                .span_delayed_bug(span, format!("cannot implement `Copy` for `{}`", self_type)))
134        }
135    }
136}
137
138fn visit_implementation_of_const_param_ty(
139    checker: &Checker<'_>,
140    kind: LangItem,
141) -> Result<(), ErrorGuaranteed> {
142    assert_matches!(kind, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy);
143
144    let tcx = checker.tcx;
145    let header = checker.impl_header;
146    let impl_did = checker.impl_def_id;
147    let self_type = header.trait_ref.instantiate_identity().self_ty();
148    assert!(!self_type.has_escaping_bound_vars());
149
150    let param_env = tcx.param_env(impl_did);
151
152    if let ty::ImplPolarity::Negative | ty::ImplPolarity::Reservation = header.polarity {
153        return Ok(());
154    }
155
156    let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
157    match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, kind, cause) {
158        Ok(()) => Ok(()),
159        Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
160            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
161            Err(infringing_fields_error(
162                tcx,
163                fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
164                LangItem::ConstParamTy,
165                impl_did,
166                span,
167            ))
168        }
169        Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
170            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
171            Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
172        }
173        Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => {
174            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
175            Err(infringing_fields_error(
176                tcx,
177                infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)),
178                LangItem::ConstParamTy,
179                impl_did,
180                span,
181            ))
182        }
183        Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {
184            let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
185            Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span }))
186        }
187    }
188}
189
190fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
191    let tcx = checker.tcx;
192    let impl_did = checker.impl_def_id;
193    debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
194
195    // Just compute this for the side-effects, in particular reporting
196    // errors; other parts of the code may demand it for the info of
197    // course.
198    tcx.ensure_ok().coerce_unsized_info(impl_did)
199}
200
201fn 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))
206}
207
208fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
209    let tcx = checker.tcx;
210    let impl_did = checker.impl_def_id;
211    let trait_ref = checker.impl_header.trait_ref.instantiate_identity();
212    debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
213
214    let span = tcx.def_span(impl_did);
215    let trait_name = "DispatchFromDyn";
216
217    let source = trait_ref.self_ty();
218    let target = {
219        assert!(tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn));
220
221        trait_ref.args.type_at(1)
222    };
223
224    // Check `CoercePointee` impl is WF -- if not, then there's no reason to report
225    // redundant errors for `DispatchFromDyn`. This is best effort, though.
226    let mut res = Ok(());
227    tcx.for_each_relevant_impl(
228        tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)),
229        source,
230        |impl_def_id| {
231            res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id));
232        },
233    );
234    res?;
235
236    debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
237
238    let param_env = tcx.param_env(impl_did);
239
240    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
241    let cause = ObligationCause::misc(span, impl_did);
242
243    // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw
244    // pointers. This is enforced here: we only allow impls for references, raw pointers, and things
245    // that are effectively repr(transparent) newtypes around types that already hav a
246    // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those types since some
247    // of them support an allocator, but we ensure that for the cases where the type implements this
248    // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
249    // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
250    // even if they do not carry that attribute.
251    match (source.kind(), target.kind()) {
252        (&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
253            if r_a == *r_b && mutbl_a == *mutbl_b =>
254        {
255            Ok(())
256        }
257        (&ty::RawPtr(_, a_mutbl), &ty::RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
258        (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
259            if def_a.is_struct() && def_b.is_struct() =>
260        {
261            if def_a != def_b {
262                let source_path = tcx.def_path_str(def_a.did());
263                let target_path = tcx.def_path_str(def_b.did());
264                return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
265                    span,
266                    trait_name,
267                    note: true,
268                    source_path,
269                    target_path,
270                }));
271            }
272
273            if def_a.repr().c() || def_a.repr().packed() {
274                return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
275            }
276
277            let fields = &def_a.non_enum_variant().fields;
278
279            let mut res = Ok(());
280            let coerced_fields = fields
281                .iter_enumerated()
282                .filter_map(|(i, field)| {
283                    // Ignore PhantomData fields
284                    let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
285                    if tcx
286                        .try_normalize_erasing_regions(
287                            ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
288                            unnormalized_ty,
289                        )
290                        .unwrap_or(unnormalized_ty)
291                        .is_phantom_data()
292                    {
293                        return None;
294                    }
295
296                    let ty_a = field.ty(tcx, args_a);
297                    let ty_b = field.ty(tcx, args_b);
298
299                    // FIXME: We could do normalization here, but is it really worth it?
300                    if ty_a == ty_b {
301                        // Allow 1-ZSTs that don't mention type params.
302                        //
303                        // Allowing type params here would allow us to possibly transmute
304                        // between ZSTs, which may be used to create library unsoundness.
305                        if let Ok(layout) =
306                            tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
307                            && layout.is_1zst()
308                            && !ty_a.has_non_region_param()
309                        {
310                            // ignore 1-ZST fields
311                            return None;
312                        }
313
314                        res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
315                            span,
316                            name: field.ident(tcx),
317                            ty: ty_a,
318                        }));
319
320                        None
321                    } else {
322                        Some((i, ty_a, ty_b, tcx.def_span(field.did)))
323                    }
324                })
325                .collect::<Vec<_>>();
326            res?;
327
328            if coerced_fields.is_empty() {
329                return Err(tcx.dcx().emit_err(errors::CoerceNoField {
330                    span,
331                    trait_name,
332                    note: true,
333                }));
334            } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {
335                let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
336                ocx.register_obligation(Obligation::new(
337                    tcx,
338                    cause.clone(),
339                    param_env,
340                    ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]),
341                ));
342                let errors = ocx.select_all_or_error();
343                if !errors.is_empty() {
344                    if is_from_coerce_pointee_derive(tcx, span) {
345                        return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
346                            span,
347                            trait_name,
348                            ty: trait_ref.self_ty(),
349                            field_span,
350                            field_ty: ty_a,
351                        }));
352                    } else {
353                        return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
354                    }
355                }
356
357                // Finally, resolve all regions.
358                ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
359
360                Ok(())
361            } else {
362                return Err(tcx.dcx().emit_err(errors::CoerceMulti {
363                    span,
364                    trait_name,
365                    number: coerced_fields.len(),
366                    fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
367                }));
368            }
369        }
370        _ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })),
371    }
372}
373
374pub(crate) fn coerce_unsized_info<'tcx>(
375    tcx: TyCtxt<'tcx>,
376    impl_did: LocalDefId,
377) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
378    debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
379    let span = tcx.def_span(impl_did);
380    let trait_name = "CoerceUnsized";
381
382    let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
383    let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
384
385    let source = tcx.type_of(impl_did).instantiate_identity();
386    let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
387
388    assert_eq!(trait_ref.def_id, coerce_unsized_trait);
389    let target = trait_ref.args.type_at(1);
390    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
391
392    let param_env = tcx.param_env(impl_did);
393    assert!(!source.has_escaping_bound_vars());
394
395    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
396
397    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
398    let cause = ObligationCause::misc(span, impl_did);
399    let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
400                       mt_b: ty::TypeAndMut<'tcx>,
401                       mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
402        if mt_a.mutbl < mt_b.mutbl {
403            infcx
404                .err_ctxt()
405                .report_mismatched_types(
406                    &cause,
407                    param_env,
408                    mk_ptr(mt_b.ty),
409                    target,
410                    ty::error::TypeError::Mutability,
411                )
412                .emit();
413        }
414        (mt_a.ty, mt_b.ty, unsize_trait, None, span)
415    };
416    let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
417        (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
418            infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
419            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
420            let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
421            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
422        }
423
424        (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b))
425        | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => {
426            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
427            let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
428            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
429        }
430
431        (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
432            if def_a.is_struct() && def_b.is_struct() =>
433        {
434            if def_a != def_b {
435                let source_path = tcx.def_path_str(def_a.did());
436                let target_path = tcx.def_path_str(def_b.did());
437                return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
438                    span,
439                    trait_name,
440                    note: true,
441                    source_path,
442                    target_path,
443                }));
444            }
445
446            // Here we are considering a case of converting
447            // `S<P0...Pn>` to `S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
448            // which acts like a pointer to `U`, but carries along some extra data of type `T`:
449            //
450            //     struct Foo<T, U> {
451            //         extra: T,
452            //         ptr: *mut U,
453            //     }
454            //
455            // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
456            // to `Foo<T, [i32]>`. That impl would look like:
457            //
458            //   impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
459            //
460            // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
461            // when this coercion occurs, we would be changing the
462            // field `ptr` from a thin pointer of type `*mut [i32;
463            // 3]` to a wide pointer of type `*mut [i32]` (with
464            // extra data `3`). **The purpose of this check is to
465            // make sure that we know how to do this conversion.**
466            //
467            // To check if this impl is legal, we would walk down
468            // the fields of `Foo` and consider their types with
469            // both generic parameters. We are looking to find that
470            // exactly one (non-phantom) field has changed its
471            // type, which we will expect to be the pointer that
472            // is becoming fat (we could probably generalize this
473            // to multiple thin pointers of the same type becoming
474            // fat, but we don't). In this case:
475            //
476            // - `extra` has type `T` before and type `T` after
477            // - `ptr` has type `*mut U` before and type `*mut V` after
478            //
479            // Since just one field changed, we would then check
480            // that `*mut U: CoerceUnsized<*mut V>` is implemented
481            // (in other words, that we know how to do this
482            // conversion). This will work out because `U:
483            // Unsize<V>`, and we have a builtin rule that `*mut
484            // U` can be coerced to `*mut V` if `U: Unsize<V>`.
485            let fields = &def_a.non_enum_variant().fields;
486            let diff_fields = fields
487                .iter_enumerated()
488                .filter_map(|(i, f)| {
489                    let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));
490
491                    // Ignore PhantomData fields
492                    let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
493                    if tcx
494                        .try_normalize_erasing_regions(
495                            ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
496                            unnormalized_ty,
497                        )
498                        .unwrap_or(unnormalized_ty)
499                        .is_phantom_data()
500                    {
501                        return None;
502                    }
503
504                    // Ignore fields that aren't changed; it may
505                    // be that we could get away with subtyping or
506                    // something more accepting, but we use
507                    // equality because we want to be able to
508                    // perform this check without computing
509                    // variance or constraining opaque types' hidden types.
510                    // (This is because we may have to evaluate constraint
511                    // expressions in the course of execution.)
512                    // See e.g., #41936.
513                    if a == b {
514                        return None;
515                    }
516
517                    // Collect up all fields that were significantly changed
518                    // i.e., those that contain T in coerce_unsized T -> U
519                    Some((i, a, b, tcx.def_span(f.did)))
520                })
521                .collect::<Vec<_>>();
522
523            if diff_fields.is_empty() {
524                return Err(tcx.dcx().emit_err(errors::CoerceNoField {
525                    span,
526                    trait_name,
527                    note: true,
528                }));
529            } else if diff_fields.len() > 1 {
530                let item = tcx.hir_expect_item(impl_did);
531                let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
532                    t.path.span
533                } else {
534                    tcx.def_span(impl_did)
535                };
536
537                return Err(tcx.dcx().emit_err(errors::CoerceMulti {
538                    span,
539                    trait_name,
540                    number: diff_fields.len(),
541                    fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
542                }));
543            }
544
545            let (i, a, b, field_span) = diff_fields[0];
546            let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
547            (a, b, coerce_unsized_trait, Some(kind), field_span)
548        }
549
550        _ => {
551            return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
552        }
553    };
554
555    // Register an obligation for `A: Trait<B>`.
556    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
557    let cause = traits::ObligationCause::misc(span, impl_did);
558    let obligation = Obligation::new(
559        tcx,
560        cause,
561        param_env,
562        ty::TraitRef::new(tcx, trait_def_id, [source, target]),
563    );
564    ocx.register_obligation(obligation);
565    let errors = ocx.select_all_or_error();
566
567    if !errors.is_empty() {
568        if is_from_coerce_pointee_derive(tcx, span) {
569            return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
570                span,
571                trait_name,
572                ty: trait_ref.self_ty(),
573                field_span,
574                field_ty: source,
575            }));
576        } else {
577            return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
578        }
579    }
580
581    // Finally, resolve all regions.
582    ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
583
584    Ok(CoerceUnsizedInfo { custom_kind: kind })
585}
586
587fn infringing_fields_error<'tcx>(
588    tcx: TyCtxt<'tcx>,
589    infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
590    lang_item: LangItem,
591    impl_did: LocalDefId,
592    impl_span: Span,
593) -> ErrorGuaranteed {
594    let trait_did = tcx.require_lang_item(lang_item, Some(impl_span));
595
596    let trait_name = tcx.def_path_str(trait_did);
597
598    // We'll try to suggest constraining type parameters to fulfill the requirements of
599    // their `Copy` implementation.
600    let mut errors: BTreeMap<_, Vec<_>> = Default::default();
601    let mut bounds = vec![];
602
603    let mut seen_tys = FxHashSet::default();
604
605    let mut label_spans = Vec::new();
606
607    for (span, ty, reason) in infringing_tys {
608        // Only report an error once per type.
609        if !seen_tys.insert(ty) {
610            continue;
611        }
612
613        label_spans.push(span);
614
615        match reason {
616            InfringingFieldsReason::Fulfill(fulfillment_errors) => {
617                for error in fulfillment_errors {
618                    let error_predicate = error.obligation.predicate;
619                    // Only note if it's not the root obligation, otherwise it's trivial and
620                    // should be self-explanatory (i.e. a field literally doesn't implement Copy).
621
622                    // FIXME: This error could be more descriptive, especially if the error_predicate
623                    // contains a foreign type or if it's a deeply nested type...
624                    if error_predicate != error.root_obligation.predicate {
625                        errors
626                            .entry((ty.to_string(), error_predicate.to_string()))
627                            .or_default()
628                            .push(error.obligation.cause.span);
629                    }
630                    if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
631                        trait_ref,
632                        polarity: ty::PredicatePolarity::Positive,
633                        ..
634                    })) = error_predicate.kind().skip_binder()
635                    {
636                        let ty = trait_ref.self_ty();
637                        if let ty::Param(_) = ty.kind() {
638                            bounds.push((
639                                format!("{ty}"),
640                                trait_ref.print_trait_sugared().to_string(),
641                                Some(trait_ref.def_id),
642                            ));
643                        }
644                    }
645                }
646            }
647            InfringingFieldsReason::Regions(region_errors) => {
648                for error in region_errors {
649                    let ty = ty.to_string();
650                    match error {
651                        RegionResolutionError::ConcreteFailure(origin, a, b) => {
652                            let predicate = format!("{b}: {a}");
653                            errors
654                                .entry((ty.clone(), predicate.clone()))
655                                .or_default()
656                                .push(origin.span());
657                            if let ty::RegionKind::ReEarlyParam(ebr) = b.kind()
658                                && ebr.has_name()
659                            {
660                                bounds.push((b.to_string(), a.to_string(), None));
661                            }
662                        }
663                        RegionResolutionError::GenericBoundFailure(origin, a, b) => {
664                            let predicate = format!("{a}: {b}");
665                            errors
666                                .entry((ty.clone(), predicate.clone()))
667                                .or_default()
668                                .push(origin.span());
669                            if let infer::region_constraints::GenericKind::Param(_) = a {
670                                bounds.push((a.to_string(), b.to_string(), None));
671                            }
672                        }
673                        _ => continue,
674                    }
675                }
676            }
677        }
678    }
679    let mut notes = Vec::new();
680    for ((ty, error_predicate), spans) in errors {
681        let span: MultiSpan = spans.into();
682        notes.push(errors::ImplForTyRequires {
683            span,
684            error_predicate,
685            trait_name: trait_name.clone(),
686            ty,
687        });
688    }
689
690    let mut err = tcx.dcx().create_err(errors::TraitCannotImplForTy {
691        span: impl_span,
692        trait_name,
693        label_spans,
694        notes,
695    });
696
697    suggest_constraining_type_params(
698        tcx,
699        tcx.hir_get_generics(impl_did).expect("impls always have generics"),
700        &mut err,
701        bounds
702            .iter()
703            .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
704        None,
705    );
706
707    err.emit()
708}
709
710fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
711    let tcx = checker.tcx;
712    let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id);
713    let impl_span = tcx.def_span(checker.impl_def_id);
714    let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
715
716    let is_permitted_primitive = match *self_ty.kind() {
717        ty::Adt(def, _) => def.is_box(),
718        ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
719        _ => false,
720    };
721
722    if is_permitted_primitive
723        && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
724        && layout.layout.is_pointer_like(&tcx.data_layout)
725    {
726        return Ok(());
727    }
728
729    let why_disqualified = match *self_ty.kind() {
730        // If an ADT is repr(transparent)
731        ty::Adt(self_ty_def, args) => {
732            if self_ty_def.repr().transparent() {
733                // FIXME(compiler-errors): This should and could be deduplicated into a query.
734                // Find the nontrivial field.
735                let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, self_ty_def.did());
736                let nontrivial_field = self_ty_def.all_fields().find(|field_def| {
737                    let field_ty = tcx.type_of(field_def.did).instantiate_identity();
738                    !tcx.layout_of(adt_typing_env.as_query_input(field_ty))
739                        .is_ok_and(|layout| layout.layout.is_1zst())
740                });
741
742                if let Some(nontrivial_field) = nontrivial_field {
743                    // Check that the nontrivial field implements `PointerLike`.
744                    let nontrivial_field_ty = nontrivial_field.ty(tcx, args);
745                    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
746                    let ocx = ObligationCtxt::new(&infcx);
747                    ocx.register_bound(
748                        ObligationCause::misc(impl_span, checker.impl_def_id),
749                        param_env,
750                        nontrivial_field_ty,
751                        tcx.require_lang_item(LangItem::PointerLike, Some(impl_span)),
752                    );
753                    // FIXME(dyn-star): We should regionck this implementation.
754                    if ocx.select_all_or_error().is_empty() {
755                        return Ok(());
756                    } else {
757                        format!(
758                            "the field `{field_name}` of {descr} `{self_ty}` \
759                    does not implement `PointerLike`",
760                            field_name = nontrivial_field.name,
761                            descr = self_ty_def.descr()
762                        )
763                    }
764                } else {
765                    format!(
766                        "the {descr} `{self_ty}` is `repr(transparent)`, \
767                but does not have a non-trivial field (it is zero-sized)",
768                        descr = self_ty_def.descr()
769                    )
770                }
771            } else if self_ty_def.is_box() {
772                // If we got here, then the `layout.is_pointer_like()` check failed
773                // and this box is not a thin pointer.
774
775                String::from("boxes of dynamically-sized types are too large to be `PointerLike`")
776            } else {
777                format!(
778                    "the {descr} `{self_ty}` is not `repr(transparent)`",
779                    descr = self_ty_def.descr()
780                )
781            }
782        }
783        ty::Ref(..) => {
784            // If we got here, then the `layout.is_pointer_like()` check failed
785            // and this reference is not a thin pointer.
786            String::from("references to dynamically-sized types are too large to be `PointerLike`")
787        }
788        ty::Dynamic(..) | ty::Foreign(..) => {
789            String::from("types of dynamic or unknown size may not implement `PointerLike`")
790        }
791        _ => {
792            // This is a white lie; it is true everywhere outside the standard library.
793            format!("only user-defined sized types are eligible for `impl PointerLike`")
794        }
795    };
796
797    Err(tcx
798        .dcx()
799        .struct_span_err(
800            impl_span,
801            "implementation must be applied to type that has the same ABI as a pointer, \
802            or is `repr(transparent)` and whose field is `PointerLike`",
803        )
804        .with_note(why_disqualified)
805        .emit())
806}
807
808fn visit_implementation_of_coerce_pointee_validity(
809    checker: &Checker<'_>,
810) -> Result<(), ErrorGuaranteed> {
811    let tcx = checker.tcx;
812    let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
813    let span = tcx.def_span(checker.impl_def_id);
814    if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
815        return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
816    }
817    let ty::Adt(def, _args) = self_ty.kind() else {
818        return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));
819    };
820    let did = def.did();
821    // Now get a more precise span of the `struct`.
822    let span = tcx.def_span(did);
823    if !def.is_struct() {
824        return Err(tcx
825            .dcx()
826            .emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() }));
827    }
828    if !def.repr().transparent() {
829        return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span }));
830    }
831    if def.all_fields().next().is_none() {
832        return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span }));
833    }
834    Ok(())
835}