1use 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 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 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 dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
218
219 let source = trait_ref.self_ty();
220 let target = {
221 assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
222
223 trait_ref.args.type_at(1)
224 };
225
226 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
238 debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
239
240 let param_env = tcx.param_env(impl_did);
241
242 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
243 let cause = ObligationCause::misc(span, impl_did);
244
245 match (source.kind(), target.kind()) {
254 (&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
255 if r_a == *r_b && mutbl_a == *mutbl_b =>
256 {
257 Ok(())
258 }
259 (&ty::RawPtr(_, a_mutbl), &ty::RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
260 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
261 if def_a.is_struct() && def_b.is_struct() =>
262 {
263 if def_a != def_b {
264 let source_path = tcx.def_path_str(def_a.did());
265 let target_path = tcx.def_path_str(def_b.did());
266 return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
267 span,
268 trait_name,
269 note: true,
270 source_path,
271 target_path,
272 }));
273 }
274
275 if def_a.repr().c() || def_a.repr().packed() {
276 return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
277 }
278
279 let fields = &def_a.non_enum_variant().fields;
280
281 let mut res = Ok(());
282 let coerced_fields = fields
283 .iter_enumerated()
284 .filter_map(|(i, field)| {
285 let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
287 if tcx
288 .try_normalize_erasing_regions(
289 ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
290 unnormalized_ty,
291 )
292 .unwrap_or(unnormalized_ty)
293 .is_phantom_data()
294 {
295 return None;
296 }
297
298 let ty_a = field.ty(tcx, args_a);
299 let ty_b = field.ty(tcx, args_b);
300
301 if ty_a == ty_b {
303 if let Ok(layout) =
308 tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
309 && layout.is_1zst()
310 && !ty_a.has_non_region_param()
311 {
312 return None;
314 }
315
316 res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
317 span,
318 name: field.ident(tcx),
319 ty: ty_a,
320 }));
321
322 None
323 } else {
324 Some((i, ty_a, ty_b, tcx.def_span(field.did)))
325 }
326 })
327 .collect::<Vec<_>>();
328 res?;
329
330 if coerced_fields.is_empty() {
331 return Err(tcx.dcx().emit_err(errors::CoerceNoField {
332 span,
333 trait_name,
334 note: true,
335 }));
336 } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {
337 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
338 ocx.register_obligation(Obligation::new(
339 tcx,
340 cause.clone(),
341 param_env,
342 ty::TraitRef::new(tcx, dispatch_from_dyn_trait, [ty_a, ty_b]),
343 ));
344 let errors = ocx.select_all_or_error();
345 if !errors.is_empty() {
346 if is_from_coerce_pointee_derive(tcx, span) {
347 return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
348 span,
349 trait_name,
350 ty: trait_ref.self_ty(),
351 field_span,
352 field_ty: ty_a,
353 }));
354 } else {
355 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
356 }
357 }
358
359 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
361
362 Ok(())
363 } else {
364 return Err(tcx.dcx().emit_err(errors::CoerceMulti {
365 span,
366 trait_name,
367 number: coerced_fields.len(),
368 fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
369 }));
370 }
371 }
372 _ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })),
373 }
374}
375
376pub(crate) fn coerce_unsized_info<'tcx>(
377 tcx: TyCtxt<'tcx>,
378 impl_did: LocalDefId,
379) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
380 debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
381 let span = tcx.def_span(impl_did);
382 let trait_name = "CoerceUnsized";
383
384 let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
385 let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
386
387 let source = tcx.type_of(impl_did).instantiate_identity();
388 let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
389
390 assert_eq!(trait_ref.def_id, coerce_unsized_trait);
391 let target = trait_ref.args.type_at(1);
392 debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
393
394 let param_env = tcx.param_env(impl_did);
395 assert!(!source.has_escaping_bound_vars());
396
397 debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
398
399 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
400 let cause = ObligationCause::misc(span, impl_did);
401 let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
402 mt_b: ty::TypeAndMut<'tcx>,
403 mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
404 if mt_a.mutbl < mt_b.mutbl {
405 infcx
406 .err_ctxt()
407 .report_mismatched_types(
408 &cause,
409 param_env,
410 mk_ptr(mt_b.ty),
411 target,
412 ty::error::TypeError::Mutability,
413 )
414 .emit();
415 }
416 (mt_a.ty, mt_b.ty, unsize_trait, None, span)
417 };
418 let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
419 (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
420 infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
421 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
422 let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
423 check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
424 }
425
426 (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b))
427 | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => {
428 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
429 let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
430 check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
431 }
432
433 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
434 if def_a.is_struct() && def_b.is_struct() =>
435 {
436 if def_a != def_b {
437 let source_path = tcx.def_path_str(def_a.did());
438 let target_path = tcx.def_path_str(def_b.did());
439 return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
440 span,
441 trait_name,
442 note: true,
443 source_path,
444 target_path,
445 }));
446 }
447
448 let fields = &def_a.non_enum_variant().fields;
488 let diff_fields = fields
489 .iter_enumerated()
490 .filter_map(|(i, f)| {
491 let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));
492
493 let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
495 if tcx
496 .try_normalize_erasing_regions(
497 ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
498 unnormalized_ty,
499 )
500 .unwrap_or(unnormalized_ty)
501 .is_phantom_data()
502 {
503 return None;
504 }
505
506 if a == b {
516 return None;
517 }
518
519 Some((i, a, b, tcx.def_span(f.did)))
522 })
523 .collect::<Vec<_>>();
524
525 if diff_fields.is_empty() {
526 return Err(tcx.dcx().emit_err(errors::CoerceNoField {
527 span,
528 trait_name,
529 note: true,
530 }));
531 } else if diff_fields.len() > 1 {
532 let item = tcx.hir_expect_item(impl_did);
533 let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
534 t.path.span
535 } else {
536 tcx.def_span(impl_did)
537 };
538
539 return Err(tcx.dcx().emit_err(errors::CoerceMulti {
540 span,
541 trait_name,
542 number: diff_fields.len(),
543 fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
544 }));
545 }
546
547 let (i, a, b, field_span) = diff_fields[0];
548 let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
549 (a, b, coerce_unsized_trait, Some(kind), field_span)
550 }
551
552 _ => {
553 return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
554 }
555 };
556
557 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
559 let cause = traits::ObligationCause::misc(span, impl_did);
560 let obligation = Obligation::new(
561 tcx,
562 cause,
563 param_env,
564 ty::TraitRef::new(tcx, trait_def_id, [source, target]),
565 );
566 ocx.register_obligation(obligation);
567 let errors = ocx.select_all_or_error();
568
569 if !errors.is_empty() {
570 if is_from_coerce_pointee_derive(tcx, span) {
571 return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
572 span,
573 trait_name,
574 ty: trait_ref.self_ty(),
575 field_span,
576 field_ty: source,
577 }));
578 } else {
579 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
580 }
581 }
582
583 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
585
586 Ok(CoerceUnsizedInfo { custom_kind: kind })
587}
588
589fn infringing_fields_error<'tcx>(
590 tcx: TyCtxt<'tcx>,
591 infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
592 lang_item: LangItem,
593 impl_did: LocalDefId,
594 impl_span: Span,
595) -> ErrorGuaranteed {
596 let trait_did = tcx.require_lang_item(lang_item, Some(impl_span));
597
598 let trait_name = tcx.def_path_str(trait_did);
599
600 let mut errors: BTreeMap<_, Vec<_>> = Default::default();
603 let mut bounds = vec![];
604
605 let mut seen_tys = FxHashSet::default();
606
607 let mut label_spans = Vec::new();
608
609 for (span, ty, reason) in infringing_tys {
610 if !seen_tys.insert(ty) {
612 continue;
613 }
614
615 label_spans.push(span);
616
617 match reason {
618 InfringingFieldsReason::Fulfill(fulfillment_errors) => {
619 for error in fulfillment_errors {
620 let error_predicate = error.obligation.predicate;
621 if error_predicate != error.root_obligation.predicate {
627 errors
628 .entry((ty.to_string(), error_predicate.to_string()))
629 .or_default()
630 .push(error.obligation.cause.span);
631 }
632 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
633 trait_ref,
634 polarity: ty::PredicatePolarity::Positive,
635 ..
636 })) = error_predicate.kind().skip_binder()
637 {
638 let ty = trait_ref.self_ty();
639 if let ty::Param(_) = ty.kind() {
640 bounds.push((
641 format!("{ty}"),
642 trait_ref.print_trait_sugared().to_string(),
643 Some(trait_ref.def_id),
644 ));
645 }
646 }
647 }
648 }
649 InfringingFieldsReason::Regions(region_errors) => {
650 for error in region_errors {
651 let ty = ty.to_string();
652 match error {
653 RegionResolutionError::ConcreteFailure(origin, a, b) => {
654 let predicate = format!("{b}: {a}");
655 errors
656 .entry((ty.clone(), predicate.clone()))
657 .or_default()
658 .push(origin.span());
659 if let ty::RegionKind::ReEarlyParam(ebr) = *b
660 && ebr.has_name()
661 {
662 bounds.push((b.to_string(), a.to_string(), None));
663 }
664 }
665 RegionResolutionError::GenericBoundFailure(origin, a, b) => {
666 let predicate = format!("{a}: {b}");
667 errors
668 .entry((ty.clone(), predicate.clone()))
669 .or_default()
670 .push(origin.span());
671 if let infer::region_constraints::GenericKind::Param(_) = a {
672 bounds.push((a.to_string(), b.to_string(), None));
673 }
674 }
675 _ => continue,
676 }
677 }
678 }
679 }
680 }
681 let mut notes = Vec::new();
682 for ((ty, error_predicate), spans) in errors {
683 let span: MultiSpan = spans.into();
684 notes.push(errors::ImplForTyRequires {
685 span,
686 error_predicate,
687 trait_name: trait_name.clone(),
688 ty,
689 });
690 }
691
692 let mut err = tcx.dcx().create_err(errors::TraitCannotImplForTy {
693 span: impl_span,
694 trait_name,
695 label_spans,
696 notes,
697 });
698
699 suggest_constraining_type_params(
700 tcx,
701 tcx.hir_get_generics(impl_did).expect("impls always have generics"),
702 &mut err,
703 bounds
704 .iter()
705 .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
706 None,
707 );
708
709 err.emit()
710}
711
712fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
713 let tcx = checker.tcx;
714 let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id);
715 let impl_span = tcx.def_span(checker.impl_def_id);
716 let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
717
718 let is_permitted_primitive = match *self_ty.kind() {
719 ty::Adt(def, _) => def.is_box(),
720 ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
721 _ => false,
722 };
723
724 if is_permitted_primitive
725 && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
726 && layout.layout.is_pointer_like(&tcx.data_layout)
727 {
728 return Ok(());
729 }
730
731 let why_disqualified = match *self_ty.kind() {
732 ty::Adt(self_ty_def, args) => {
734 if self_ty_def.repr().transparent() {
735 let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, self_ty_def.did());
738 let nontrivial_field = self_ty_def.all_fields().find(|field_def| {
739 let field_ty = tcx.type_of(field_def.did).instantiate_identity();
740 !tcx.layout_of(adt_typing_env.as_query_input(field_ty))
741 .is_ok_and(|layout| layout.layout.is_1zst())
742 });
743
744 if let Some(nontrivial_field) = nontrivial_field {
745 let nontrivial_field_ty = nontrivial_field.ty(tcx, args);
747 let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
748 let ocx = ObligationCtxt::new(&infcx);
749 ocx.register_bound(
750 ObligationCause::misc(impl_span, checker.impl_def_id),
751 param_env,
752 nontrivial_field_ty,
753 tcx.lang_items().pointer_like().unwrap(),
754 );
755 if ocx.select_all_or_error().is_empty() {
757 return Ok(());
758 } else {
759 format!(
760 "the field `{field_name}` of {descr} `{self_ty}` \
761 does not implement `PointerLike`",
762 field_name = nontrivial_field.name,
763 descr = self_ty_def.descr()
764 )
765 }
766 } else {
767 format!(
768 "the {descr} `{self_ty}` is `repr(transparent)`, \
769 but does not have a non-trivial field (it is zero-sized)",
770 descr = self_ty_def.descr()
771 )
772 }
773 } else if self_ty_def.is_box() {
774 String::from("boxes of dynamically-sized types are too large to be `PointerLike`")
778 } else {
779 format!(
780 "the {descr} `{self_ty}` is not `repr(transparent)`",
781 descr = self_ty_def.descr()
782 )
783 }
784 }
785 ty::Ref(..) => {
786 String::from("references to dynamically-sized types are too large to be `PointerLike`")
789 }
790 ty::Dynamic(..) | ty::Foreign(..) => {
791 String::from("types of dynamic or unknown size may not implement `PointerLike`")
792 }
793 _ => {
794 format!("only user-defined sized types are eligible for `impl PointerLike`")
796 }
797 };
798
799 Err(tcx
800 .dcx()
801 .struct_span_err(
802 impl_span,
803 "implementation must be applied to type that has the same ABI as a pointer, \
804 or is `repr(transparent)` and whose field is `PointerLike`",
805 )
806 .with_note(why_disqualified)
807 .emit())
808}
809
810fn visit_implementation_of_coerce_pointee_validity(
811 checker: &Checker<'_>,
812) -> Result<(), ErrorGuaranteed> {
813 let tcx = checker.tcx;
814 let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
815 let span = tcx.def_span(checker.impl_def_id);
816 if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
817 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
818 }
819 let ty::Adt(def, _args) = self_ty.kind() else {
820 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));
821 };
822 let did = def.did();
823 let span = tcx.def_span(did);
825 if !def.is_struct() {
826 return Err(tcx
827 .dcx()
828 .emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() }));
829 }
830 if !def.repr().transparent() {
831 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span }));
832 }
833 if def.all_fields().next().is_none() {
834 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span }));
835 }
836 Ok(())
837}