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};
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    let span = tcx.def_span(impl_did);
199    tcx.at(span).ensure_ok().coerce_unsized_info(impl_did)
200}
201
202fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
203    let tcx = checker.tcx;
204    let impl_did = checker.impl_def_id;
205    let trait_ref = checker.impl_header.trait_ref.instantiate_identity();
206    debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
207
208    let span = tcx.def_span(impl_did);
209
210    let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
211
212    let source = trait_ref.self_ty();
213    assert!(!source.has_escaping_bound_vars());
214    let target = {
215        assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
216
217        trait_ref.args.type_at(1)
218    };
219
220    debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
221
222    let param_env = tcx.param_env(impl_did);
223
224    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
225    let cause = ObligationCause::misc(span, impl_did);
226
227    // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw
228    // pointers. This is enforced here: we only allow impls for references, raw pointers, and things
229    // that are effectively repr(transparent) newtypes around types that already hav a
230    // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those types since some
231    // of them support an allocator, but we ensure that for the cases where the type implements this
232    // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
233    // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
234    // even if they do not carry that attribute.
235    use rustc_type_ir::TyKind::*;
236    match (source.kind(), target.kind()) {
237        (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) if r_a == *r_b && mutbl_a == *mutbl_b => {
238            Ok(())
239        }
240        (&RawPtr(_, a_mutbl), &RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
241        (&Adt(def_a, args_a), &Adt(def_b, args_b)) if def_a.is_struct() && def_b.is_struct() => {
242            if def_a != def_b {
243                let source_path = tcx.def_path_str(def_a.did());
244                let target_path = tcx.def_path_str(def_b.did());
245
246                return Err(tcx.dcx().emit_err(errors::DispatchFromDynCoercion {
247                    span,
248                    trait_name: "DispatchFromDyn",
249                    note: true,
250                    source_path,
251                    target_path,
252                }));
253            }
254
255            let mut res = Ok(());
256            if def_a.repr().c() || def_a.repr().packed() {
257                res = Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
258            }
259
260            let fields = &def_a.non_enum_variant().fields;
261
262            let coerced_fields = fields
263                .iter()
264                .filter(|field| {
265                    // Ignore PhantomData fields
266                    let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
267                    if tcx
268                        .try_normalize_erasing_regions(
269                            ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
270                            unnormalized_ty,
271                        )
272                        .unwrap_or(unnormalized_ty)
273                        .is_phantom_data()
274                    {
275                        return false;
276                    }
277
278                    let ty_a = field.ty(tcx, args_a);
279                    let ty_b = field.ty(tcx, args_b);
280
281                    // FIXME: We could do normalization here, but is it really worth it?
282                    if ty_a == ty_b {
283                        // Allow 1-ZSTs that don't mention type params.
284                        //
285                        // Allowing type params here would allow us to possibly transmute
286                        // between ZSTs, which may be used to create library unsoundness.
287                        if let Ok(layout) =
288                            tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
289                            && layout.is_1zst()
290                            && !ty_a.has_non_region_param()
291                        {
292                            // ignore 1-ZST fields
293                            return false;
294                        }
295
296                        res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
297                            span,
298                            name: field.ident(tcx),
299                            ty: ty_a,
300                        }));
301
302                        return false;
303                    }
304
305                    true
306                })
307                .collect::<Vec<_>>();
308
309            if coerced_fields.is_empty() {
310                res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
311                    span,
312                    trait_name: "DispatchFromDyn",
313                    note: true,
314                }));
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 {
334                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                }
347                let errors = ocx.select_all_or_error();
348                if !errors.is_empty() {
349                    res = Err(infcx.err_ctxt().report_fulfillment_errors(errors));
350                }
351
352                // Finally, resolve all regions.
353                res = res.and(ocx.resolve_regions_and_report_errors(impl_did, param_env, []));
354            }
355            res
356        }
357        _ => Err(tcx
358            .dcx()
359            .emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" })),
360    }
361}
362
363pub(crate) fn coerce_unsized_info<'tcx>(
364    tcx: TyCtxt<'tcx>,
365    impl_did: LocalDefId,
366) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
367    debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
368    let span = tcx.def_span(impl_did);
369
370    let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
371
372    let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
373
374    let source = tcx.type_of(impl_did).instantiate_identity();
375    let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
376    assert_eq!(trait_ref.def_id, coerce_unsized_trait);
377    let target = trait_ref.args.type_at(1);
378    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
379
380    let param_env = tcx.param_env(impl_did);
381    assert!(!source.has_escaping_bound_vars());
382
383    debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
384
385    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
386    let cause = ObligationCause::misc(span, impl_did);
387    let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
388                       mt_b: ty::TypeAndMut<'tcx>,
389                       mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
390        if mt_a.mutbl < mt_b.mutbl {
391            infcx
392                .err_ctxt()
393                .report_mismatched_types(
394                    &cause,
395                    param_env,
396                    mk_ptr(mt_b.ty),
397                    target,
398                    ty::error::TypeError::Mutability,
399                )
400                .emit();
401        }
402        (mt_a.ty, mt_b.ty, unsize_trait, None)
403    };
404    let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
405        (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
406            infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
407            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
408            let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
409            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
410        }
411
412        (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b))
413        | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => {
414            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
415            let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
416            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
417        }
418
419        (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
420            if def_a.is_struct() && def_b.is_struct() =>
421        {
422            if def_a != def_b {
423                let source_path = tcx.def_path_str(def_a.did());
424                let target_path = tcx.def_path_str(def_b.did());
425                return Err(tcx.dcx().emit_err(errors::DispatchFromDynSame {
426                    span,
427                    trait_name: "CoerceUnsized",
428                    note: true,
429                    source_path,
430                    target_path,
431                }));
432            }
433
434            // Here we are considering a case of converting
435            // `S<P0...Pn>` to `S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`,
436            // which acts like a pointer to `U`, but carries along some extra data of type `T`:
437            //
438            //     struct Foo<T, U> {
439            //         extra: T,
440            //         ptr: *mut U,
441            //     }
442            //
443            // We might have an impl that allows (e.g.) `Foo<T, [i32; 3]>` to be unsized
444            // to `Foo<T, [i32]>`. That impl would look like:
445            //
446            //   impl<T, U: Unsize<V>, V> CoerceUnsized<Foo<T, V>> for Foo<T, U> {}
447            //
448            // Here `U = [i32; 3]` and `V = [i32]`. At runtime,
449            // when this coercion occurs, we would be changing the
450            // field `ptr` from a thin pointer of type `*mut [i32;
451            // 3]` to a wide pointer of type `*mut [i32]` (with
452            // extra data `3`). **The purpose of this check is to
453            // make sure that we know how to do this conversion.**
454            //
455            // To check if this impl is legal, we would walk down
456            // the fields of `Foo` and consider their types with
457            // both generic parameters. We are looking to find that
458            // exactly one (non-phantom) field has changed its
459            // type, which we will expect to be the pointer that
460            // is becoming fat (we could probably generalize this
461            // to multiple thin pointers of the same type becoming
462            // fat, but we don't). In this case:
463            //
464            // - `extra` has type `T` before and type `T` after
465            // - `ptr` has type `*mut U` before and type `*mut V` after
466            //
467            // Since just one field changed, we would then check
468            // that `*mut U: CoerceUnsized<*mut V>` is implemented
469            // (in other words, that we know how to do this
470            // conversion). This will work out because `U:
471            // Unsize<V>`, and we have a builtin rule that `*mut
472            // U` can be coerced to `*mut V` if `U: Unsize<V>`.
473            let fields = &def_a.non_enum_variant().fields;
474            let diff_fields = fields
475                .iter_enumerated()
476                .filter_map(|(i, f)| {
477                    let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));
478
479                    // Ignore PhantomData fields
480                    let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
481                    if tcx
482                        .try_normalize_erasing_regions(
483                            ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
484                            unnormalized_ty,
485                        )
486                        .unwrap_or(unnormalized_ty)
487                        .is_phantom_data()
488                    {
489                        return None;
490                    }
491
492                    // Ignore fields that aren't changed; it may
493                    // be that we could get away with subtyping or
494                    // something more accepting, but we use
495                    // equality because we want to be able to
496                    // perform this check without computing
497                    // variance or constraining opaque types' hidden types.
498                    // (This is because we may have to evaluate constraint
499                    // expressions in the course of execution.)
500                    // See e.g., #41936.
501                    if a == b {
502                        return None;
503                    }
504
505                    // Collect up all fields that were significantly changed
506                    // i.e., those that contain T in coerce_unsized T -> U
507                    Some((i, a, b))
508                })
509                .collect::<Vec<_>>();
510
511            if diff_fields.is_empty() {
512                return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
513                    span,
514                    trait_name: "CoerceUnsized",
515                    note: true,
516                }));
517            } else if diff_fields.len() > 1 {
518                let item = tcx.hir().expect_item(impl_did);
519                let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
520                    t.path.span
521                } else {
522                    tcx.def_span(impl_did)
523                };
524
525                return Err(tcx.dcx().emit_err(errors::CoerceUnsizedMulti {
526                    span,
527                    coercions_note: true,
528                    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(", "),
534                }));
535            }
536
537            let (i, a, b) = diff_fields[0];
538            let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
539            (a, b, coerce_unsized_trait, Some(kind))
540        }
541
542        _ => {
543            return Err(tcx
544                .dcx()
545                .emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" }));
546        }
547    };
548
549    // Register an obligation for `A: Trait<B>`.
550    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
551    let cause = traits::ObligationCause::misc(span, impl_did);
552    let obligation = Obligation::new(
553        tcx,
554        cause,
555        param_env,
556        ty::TraitRef::new(tcx, trait_def_id, [source, target]),
557    );
558    ocx.register_obligation(obligation);
559    let errors = ocx.select_all_or_error();
560    if !errors.is_empty() {
561        infcx.err_ctxt().report_fulfillment_errors(errors);
562    }
563
564    // Finally, resolve all regions.
565    let _ = ocx.resolve_regions_and_report_errors(impl_did, param_env, []);
566
567    Ok(CoerceUnsizedInfo { custom_kind: kind })
568}
569
570fn infringing_fields_error<'tcx>(
571    tcx: TyCtxt<'tcx>,
572    infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
573    lang_item: LangItem,
574    impl_did: LocalDefId,
575    impl_span: Span,
576) -> ErrorGuaranteed {
577    let trait_did = tcx.require_lang_item(lang_item, Some(impl_span));
578
579    let trait_name = tcx.def_path_str(trait_did);
580
581    // We'll try to suggest constraining type parameters to fulfill the requirements of
582    // their `Copy` implementation.
583    let mut errors: BTreeMap<_, Vec<_>> = Default::default();
584    let mut bounds = vec![];
585
586    let mut seen_tys = FxHashSet::default();
587
588    let mut label_spans = Vec::new();
589
590    for (span, ty, reason) in infringing_tys {
591        // Only report an error once per type.
592        if !seen_tys.insert(ty) {
593            continue;
594        }
595
596        label_spans.push(span);
597
598        match reason {
599            InfringingFieldsReason::Fulfill(fulfillment_errors) => {
600                for error in fulfillment_errors {
601                    let error_predicate = error.obligation.predicate;
602                    // Only note if it's not the root obligation, otherwise it's trivial and
603                    // should be self-explanatory (i.e. a field literally doesn't implement Copy).
604
605                    // FIXME: This error could be more descriptive, especially if the error_predicate
606                    // contains a foreign type or if it's a deeply nested type...
607                    if error_predicate != error.root_obligation.predicate {
608                        errors
609                            .entry((ty.to_string(), error_predicate.to_string()))
610                            .or_default()
611                            .push(error.obligation.cause.span);
612                    }
613                    if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
614                        trait_ref,
615                        polarity: ty::PredicatePolarity::Positive,
616                        ..
617                    })) = error_predicate.kind().skip_binder()
618                    {
619                        let ty = trait_ref.self_ty();
620                        if let ty::Param(_) = ty.kind() {
621                            bounds.push((
622                                format!("{ty}"),
623                                trait_ref.print_trait_sugared().to_string(),
624                                Some(trait_ref.def_id),
625                            ));
626                        }
627                    }
628                }
629            }
630            InfringingFieldsReason::Regions(region_errors) => {
631                for error in region_errors {
632                    let ty = ty.to_string();
633                    match error {
634                        RegionResolutionError::ConcreteFailure(origin, a, b) => {
635                            let predicate = format!("{b}: {a}");
636                            errors
637                                .entry((ty.clone(), predicate.clone()))
638                                .or_default()
639                                .push(origin.span());
640                            if let ty::RegionKind::ReEarlyParam(ebr) = *b
641                                && ebr.has_name()
642                            {
643                                bounds.push((b.to_string(), a.to_string(), None));
644                            }
645                        }
646                        RegionResolutionError::GenericBoundFailure(origin, a, b) => {
647                            let predicate = format!("{a}: {b}");
648                            errors
649                                .entry((ty.clone(), predicate.clone()))
650                                .or_default()
651                                .push(origin.span());
652                            if let infer::region_constraints::GenericKind::Param(_) = a {
653                                bounds.push((a.to_string(), b.to_string(), None));
654                            }
655                        }
656                        _ => continue,
657                    }
658                }
659            }
660        }
661    }
662    let mut notes = Vec::new();
663    for ((ty, error_predicate), spans) in errors {
664        let span: MultiSpan = spans.into();
665        notes.push(errors::ImplForTyRequires {
666            span,
667            error_predicate,
668            trait_name: trait_name.clone(),
669            ty,
670        });
671    }
672
673    let mut err = tcx.dcx().create_err(errors::TraitCannotImplForTy {
674        span: impl_span,
675        trait_name,
676        label_spans,
677        notes,
678    });
679
680    suggest_constraining_type_params(
681        tcx,
682        tcx.hir().get_generics(impl_did).expect("impls always have generics"),
683        &mut err,
684        bounds
685            .iter()
686            .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
687        None,
688    );
689
690    err.emit()
691}
692
693fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
694    let tcx = checker.tcx;
695    let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id);
696    let impl_span = tcx.def_span(checker.impl_def_id);
697    let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
698
699    let is_permitted_primitive = match *self_ty.kind() {
700        ty::Adt(def, _) => def.is_box(),
701        ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
702        _ => false,
703    };
704
705    if is_permitted_primitive
706        && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
707        && layout.layout.is_pointer_like(&tcx.data_layout)
708    {
709        return Ok(());
710    }
711
712    let why_disqualified = match *self_ty.kind() {
713        // If an ADT is repr(transparent)
714        ty::Adt(self_ty_def, args) => {
715            if self_ty_def.repr().transparent() {
716                // FIXME(compiler-errors): This should and could be deduplicated into a query.
717                // Find the nontrivial field.
718                let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, self_ty_def.did());
719                let nontrivial_field = self_ty_def.all_fields().find(|field_def| {
720                    let field_ty = tcx.type_of(field_def.did).instantiate_identity();
721                    !tcx.layout_of(adt_typing_env.as_query_input(field_ty))
722                        .is_ok_and(|layout| layout.layout.is_1zst())
723                });
724
725                if let Some(nontrivial_field) = nontrivial_field {
726                    // Check that the nontrivial field implements `PointerLike`.
727                    let nontrivial_field_ty = nontrivial_field.ty(tcx, args);
728                    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
729                    let ocx = ObligationCtxt::new(&infcx);
730                    ocx.register_bound(
731                        ObligationCause::misc(impl_span, checker.impl_def_id),
732                        param_env,
733                        nontrivial_field_ty,
734                        tcx.lang_items().pointer_like().unwrap(),
735                    );
736                    // FIXME(dyn-star): We should regionck this implementation.
737                    if ocx.select_all_or_error().is_empty() {
738                        return Ok(());
739                    } else {
740                        format!(
741                            "the field `{field_name}` of {descr} `{self_ty}` \
742                    does not implement `PointerLike`",
743                            field_name = nontrivial_field.name,
744                            descr = self_ty_def.descr()
745                        )
746                    }
747                } else {
748                    format!(
749                        "the {descr} `{self_ty}` is `repr(transparent)`, \
750                but does not have a non-trivial field (it is zero-sized)",
751                        descr = self_ty_def.descr()
752                    )
753                }
754            } else if self_ty_def.is_box() {
755                // If we got here, then the `layout.is_pointer_like()` check failed
756                // and this box is not a thin pointer.
757
758                String::from("boxes of dynamically-sized types are too large to be `PointerLike`")
759            } else {
760                format!(
761                    "the {descr} `{self_ty}` is not `repr(transparent)`",
762                    descr = self_ty_def.descr()
763                )
764            }
765        }
766        ty::Ref(..) => {
767            // If we got here, then the `layout.is_pointer_like()` check failed
768            // and this reference is not a thin pointer.
769            String::from("references to dynamically-sized types are too large to be `PointerLike`")
770        }
771        ty::Dynamic(..) | ty::Foreign(..) => {
772            String::from("types of dynamic or unknown size may not implement `PointerLike`")
773        }
774        _ => {
775            // This is a white lie; it is true everywhere outside the standard library.
776            format!("only user-defined sized types are eligible for `impl PointerLike`")
777        }
778    };
779
780    Err(tcx
781        .dcx()
782        .struct_span_err(
783            impl_span,
784            "implementation must be applied to type that has the same ABI as a pointer, \
785            or is `repr(transparent)` and whose field is `PointerLike`",
786        )
787        .with_note(why_disqualified)
788        .emit())
789}
790
791fn visit_implementation_of_coerce_pointee_validity(
792    checker: &Checker<'_>,
793) -> Result<(), ErrorGuaranteed> {
794    let tcx = checker.tcx;
795    let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
796    let span = tcx.def_span(checker.impl_def_id);
797    if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
798        return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
799    }
800    let ty::Adt(def, _args) = self_ty.kind() else {
801        return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));
802    };
803    let did = def.did();
804    // Now get a more precise span of the `struct`.
805    let span = tcx.def_span(did);
806    if !def.is_struct() {
807        return Err(tcx
808            .dcx()
809            .emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() }));
810    }
811    if !def.repr().transparent() {
812        return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span }));
813    }
814    if def.all_fields().next().is_none() {
815        return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span }));
816    }
817    Ok(())
818}