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 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 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 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 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 if ty_a == ty_b {
301 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 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 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 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 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 if a == b {
514 return None;
515 }
516
517 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 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 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 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 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 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 ty::Adt(self_ty_def, args) => {
732 if self_ty_def.repr().transparent() {
733 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 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 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 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 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 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 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}