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};
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 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 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 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 if ty_a == ty_b {
283 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 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 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 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 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 if a == b {
502 return None;
503 }
504
505 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 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 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 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 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 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 ty::Adt(self_ty_def, args) => {
715 if self_ty_def.repr().transparent() {
716 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 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 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 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 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 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 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}