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, SubregionOrigin, 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.async_drop_trait(), visit_implementation_of_drop)?;
41 checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
42 checker.check(lang_items.const_param_ty_trait(), |checker| {
43 visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
44 })?;
45 checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
46 visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
47 })?;
48 checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
49 checker
50 .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
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 {
88 span: impl_.self_ty.span,
89 trait_: tcx.item_name(checker.impl_header.trait_ref.skip_binder().def_id),
90 }))
91}
92
93fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
94 let tcx = checker.tcx;
95 let impl_header = checker.impl_header;
96 let impl_did = checker.impl_def_id;
97 debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
98
99 let self_type = impl_header.trait_ref.instantiate_identity().self_ty();
100 debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
101
102 let param_env = tcx.param_env(impl_did);
103 assert!(!self_type.has_escaping_bound_vars());
104
105 debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
106
107 if let ty::ImplPolarity::Negative = impl_header.polarity {
108 return Ok(());
109 }
110
111 let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
112 match type_allowed_to_implement_copy(tcx, param_env, self_type, cause, impl_header.safety) {
113 Ok(()) => Ok(()),
114 Err(CopyImplementationError::InfringingFields(fields)) => {
115 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
116 Err(infringing_fields_error(
117 tcx,
118 fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
119 LangItem::Copy,
120 impl_did,
121 span,
122 ))
123 }
124 Err(CopyImplementationError::NotAnAdt) => {
125 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
126 Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span }))
127 }
128 Err(CopyImplementationError::HasDestructor) => {
129 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
130 Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span }))
131 }
132 Err(CopyImplementationError::HasUnsafeFields) => {
133 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
134 Err(tcx
135 .dcx()
136 .span_delayed_bug(span, format!("cannot implement `Copy` for `{}`", self_type)))
137 }
138 }
139}
140
141fn visit_implementation_of_const_param_ty(
142 checker: &Checker<'_>,
143 kind: LangItem,
144) -> Result<(), ErrorGuaranteed> {
145 assert_matches!(kind, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy);
146
147 let tcx = checker.tcx;
148 let header = checker.impl_header;
149 let impl_did = checker.impl_def_id;
150 let self_type = header.trait_ref.instantiate_identity().self_ty();
151 assert!(!self_type.has_escaping_bound_vars());
152
153 let param_env = tcx.param_env(impl_did);
154
155 if let ty::ImplPolarity::Negative | ty::ImplPolarity::Reservation = header.polarity {
156 return Ok(());
157 }
158
159 let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
160 match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, kind, cause) {
161 Ok(()) => Ok(()),
162 Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
163 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
164 Err(infringing_fields_error(
165 tcx,
166 fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
167 LangItem::ConstParamTy,
168 impl_did,
169 span,
170 ))
171 }
172 Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
173 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
174 Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
175 }
176 Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => {
177 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
178 Err(infringing_fields_error(
179 tcx,
180 infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)),
181 LangItem::ConstParamTy,
182 impl_did,
183 span,
184 ))
185 }
186 Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {
187 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
188 Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span }))
189 }
190 }
191}
192
193fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
194 let tcx = checker.tcx;
195 let impl_did = checker.impl_def_id;
196 debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
197
198 tcx.ensure_ok().coerce_unsized_info(impl_did)
202}
203
204fn is_from_coerce_pointee_derive(tcx: TyCtxt<'_>, span: Span) -> bool {
205 span.ctxt()
206 .outer_expn_data()
207 .macro_def_id
208 .is_some_and(|def_id| tcx.is_diagnostic_item(sym::CoercePointee, def_id))
209}
210
211fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
212 let tcx = checker.tcx;
213 let impl_did = checker.impl_def_id;
214 let trait_ref = checker.impl_header.trait_ref.instantiate_identity();
215 debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
216
217 let span = tcx.def_span(impl_did);
218 let trait_name = "DispatchFromDyn";
219
220 let source = trait_ref.self_ty();
221 let target = {
222 assert!(tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn));
223
224 trait_ref.args.type_at(1)
225 };
226
227 let mut res = Ok(());
230 tcx.for_each_relevant_impl(
231 tcx.require_lang_item(LangItem::CoerceUnsized, span),
232 source,
233 |impl_def_id| {
234 res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id));
235 },
236 );
237 res?;
238
239 debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
240
241 let param_env = tcx.param_env(impl_did);
242
243 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
244 let cause = ObligationCause::misc(span, impl_did);
245
246 match (source.kind(), target.kind()) {
255 (&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
256 if r_a == *r_b && mutbl_a == *mutbl_b =>
257 {
258 Ok(())
259 }
260 (&ty::RawPtr(_, a_mutbl), &ty::RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
261 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
262 if def_a.is_struct() && def_b.is_struct() =>
263 {
264 if def_a != def_b {
265 let source_path = tcx.def_path_str(def_a.did());
266 let target_path = tcx.def_path_str(def_b.did());
267 return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
268 span,
269 trait_name,
270 note: true,
271 source_path,
272 target_path,
273 }));
274 }
275
276 if def_a.repr().c() || def_a.repr().packed() {
277 return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
278 }
279
280 let fields = &def_a.non_enum_variant().fields;
281
282 let mut res = Ok(());
283 let coerced_fields = fields
284 .iter_enumerated()
285 .filter_map(|(i, field)| {
286 let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
288 if tcx
289 .try_normalize_erasing_regions(
290 ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
291 unnormalized_ty,
292 )
293 .unwrap_or(unnormalized_ty)
294 .is_phantom_data()
295 {
296 return None;
297 }
298
299 let ty_a = field.ty(tcx, args_a);
300 let ty_b = field.ty(tcx, args_b);
301
302 if ty_a == ty_b {
304 if let Ok(layout) =
309 tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
310 && layout.is_1zst()
311 && !ty_a.has_non_region_param()
312 {
313 return None;
315 }
316
317 res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
318 span,
319 name: field.ident(tcx),
320 ty: ty_a,
321 }));
322
323 None
324 } else {
325 Some((i, ty_a, ty_b, tcx.def_span(field.did)))
326 }
327 })
328 .collect::<Vec<_>>();
329 res?;
330
331 if coerced_fields.is_empty() {
332 return Err(tcx.dcx().emit_err(errors::CoerceNoField {
333 span,
334 trait_name,
335 note: true,
336 }));
337 } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {
338 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
339 ocx.register_obligation(Obligation::new(
340 tcx,
341 cause.clone(),
342 param_env,
343 ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]),
344 ));
345 let errors = ocx.select_all_or_error();
346 if !errors.is_empty() {
347 if is_from_coerce_pointee_derive(tcx, span) {
348 return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
349 span,
350 trait_name,
351 ty: trait_ref.self_ty(),
352 field_span,
353 field_ty: ty_a,
354 }));
355 } else {
356 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
357 }
358 }
359
360 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
362
363 Ok(())
364 } else {
365 return Err(tcx.dcx().emit_err(errors::CoerceMulti {
366 span,
367 trait_name,
368 number: coerced_fields.len(),
369 fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
370 }));
371 }
372 }
373 _ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })),
374 }
375}
376
377pub(crate) fn coerce_unsized_info<'tcx>(
378 tcx: TyCtxt<'tcx>,
379 impl_did: LocalDefId,
380) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
381 debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
382 let span = tcx.def_span(impl_did);
383 let trait_name = "CoerceUnsized";
384
385 let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, span);
386 let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span);
387
388 let source = tcx.type_of(impl_did).instantiate_identity();
389 let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
390
391 assert_eq!(trait_ref.def_id, coerce_unsized_trait);
392 let target = trait_ref.args.type_at(1);
393 debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
394
395 let param_env = tcx.param_env(impl_did);
396 assert!(!source.has_escaping_bound_vars());
397
398 debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
399
400 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
401 let cause = ObligationCause::misc(span, impl_did);
402 let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
403 mt_b: ty::TypeAndMut<'tcx>,
404 mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
405 if mt_a.mutbl < mt_b.mutbl {
406 infcx
407 .err_ctxt()
408 .report_mismatched_types(
409 &cause,
410 param_env,
411 mk_ptr(mt_b.ty),
412 target,
413 ty::error::TypeError::Mutability,
414 )
415 .emit();
416 }
417 (mt_a.ty, mt_b.ty, unsize_trait, None, span)
418 };
419 let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
420 (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
421 infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a);
422 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
423 let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
424 check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
425 }
426
427 (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b))
428 | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => {
429 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
430 let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
431 check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
432 }
433
434 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
435 if def_a.is_struct() && def_b.is_struct() =>
436 {
437 if def_a != def_b {
438 let source_path = tcx.def_path_str(def_a.did());
439 let target_path = tcx.def_path_str(def_b.did());
440 return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
441 span,
442 trait_name,
443 note: true,
444 source_path,
445 target_path,
446 }));
447 }
448
449 let fields = &def_a.non_enum_variant().fields;
489 let diff_fields = fields
490 .iter_enumerated()
491 .filter_map(|(i, f)| {
492 let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));
493
494 let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
496 if tcx
497 .try_normalize_erasing_regions(
498 ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
499 unnormalized_ty,
500 )
501 .unwrap_or(unnormalized_ty)
502 .is_phantom_data()
503 {
504 return None;
505 }
506
507 if a == b {
517 return None;
518 }
519
520 Some((i, a, b, tcx.def_span(f.did)))
523 })
524 .collect::<Vec<_>>();
525
526 if diff_fields.is_empty() {
527 return Err(tcx.dcx().emit_err(errors::CoerceNoField {
528 span,
529 trait_name,
530 note: true,
531 }));
532 } else if diff_fields.len() > 1 {
533 let item = tcx.hir_expect_item(impl_did);
534 let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
535 t.path.span
536 } else {
537 tcx.def_span(impl_did)
538 };
539
540 return Err(tcx.dcx().emit_err(errors::CoerceMulti {
541 span,
542 trait_name,
543 number: diff_fields.len(),
544 fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
545 }));
546 }
547
548 let (i, a, b, field_span) = diff_fields[0];
549 let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
550 (a, b, coerce_unsized_trait, Some(kind), field_span)
551 }
552
553 _ => {
554 return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
555 }
556 };
557
558 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
560 let cause = traits::ObligationCause::misc(span, impl_did);
561 let obligation = Obligation::new(
562 tcx,
563 cause,
564 param_env,
565 ty::TraitRef::new(tcx, trait_def_id, [source, target]),
566 );
567 ocx.register_obligation(obligation);
568 let errors = ocx.select_all_or_error();
569
570 if !errors.is_empty() {
571 if is_from_coerce_pointee_derive(tcx, span) {
572 return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
573 span,
574 trait_name,
575 ty: trait_ref.self_ty(),
576 field_span,
577 field_ty: source,
578 }));
579 } else {
580 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
581 }
582 }
583
584 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
586
587 Ok(CoerceUnsizedInfo { custom_kind: kind })
588}
589
590fn infringing_fields_error<'tcx>(
591 tcx: TyCtxt<'tcx>,
592 infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
593 lang_item: LangItem,
594 impl_did: LocalDefId,
595 impl_span: Span,
596) -> ErrorGuaranteed {
597 let trait_did = tcx.require_lang_item(lang_item, impl_span);
598
599 let trait_name = tcx.def_path_str(trait_did);
600
601 let mut errors: BTreeMap<_, Vec<_>> = Default::default();
604 let mut bounds = vec![];
605
606 let mut seen_tys = FxHashSet::default();
607
608 let mut label_spans = Vec::new();
609
610 for (span, ty, reason) in infringing_tys {
611 if !seen_tys.insert(ty) {
613 continue;
614 }
615
616 label_spans.push(span);
617
618 match reason {
619 InfringingFieldsReason::Fulfill(fulfillment_errors) => {
620 for error in fulfillment_errors {
621 let error_predicate = error.obligation.predicate;
622 if error_predicate != error.root_obligation.predicate {
628 errors
629 .entry((ty.to_string(), error_predicate.to_string()))
630 .or_default()
631 .push(error.obligation.cause.span);
632 }
633 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
634 trait_ref,
635 polarity: ty::PredicatePolarity::Positive,
636 ..
637 })) = error_predicate.kind().skip_binder()
638 {
639 let ty = trait_ref.self_ty();
640 if let ty::Param(_) = ty.kind() {
641 bounds.push((
642 format!("{ty}"),
643 trait_ref.print_trait_sugared().to_string(),
644 Some(trait_ref.def_id),
645 ));
646 }
647 }
648 }
649 }
650 InfringingFieldsReason::Regions(region_errors) => {
651 for error in region_errors {
652 let ty = ty.to_string();
653 match error {
654 RegionResolutionError::ConcreteFailure(origin, a, b) => {
655 let predicate = format!("{b}: {a}");
656 errors
657 .entry((ty.clone(), predicate.clone()))
658 .or_default()
659 .push(origin.span());
660 if let ty::RegionKind::ReEarlyParam(ebr) = b.kind()
661 && ebr.is_named()
662 {
663 bounds.push((b.to_string(), a.to_string(), None));
664 }
665 }
666 RegionResolutionError::GenericBoundFailure(origin, a, b) => {
667 let predicate = format!("{a}: {b}");
668 errors
669 .entry((ty.clone(), predicate.clone()))
670 .or_default()
671 .push(origin.span());
672 if let infer::region_constraints::GenericKind::Param(_) = a {
673 bounds.push((a.to_string(), b.to_string(), None));
674 }
675 }
676 _ => continue,
677 }
678 }
679 }
680 }
681 }
682 let mut notes = Vec::new();
683 for ((ty, error_predicate), spans) in errors {
684 let span: MultiSpan = spans.into();
685 notes.push(errors::ImplForTyRequires {
686 span,
687 error_predicate,
688 trait_name: trait_name.clone(),
689 ty,
690 });
691 }
692
693 let mut err = tcx.dcx().create_err(errors::TraitCannotImplForTy {
694 span: impl_span,
695 trait_name,
696 label_spans,
697 notes,
698 });
699
700 suggest_constraining_type_params(
701 tcx,
702 tcx.hir_get_generics(impl_did).expect("impls always have generics"),
703 &mut err,
704 bounds
705 .iter()
706 .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
707 None,
708 );
709
710 err.emit()
711}
712
713fn visit_implementation_of_coerce_pointee_validity(
714 checker: &Checker<'_>,
715) -> Result<(), ErrorGuaranteed> {
716 let tcx = checker.tcx;
717 let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
718 let span = tcx.def_span(checker.impl_def_id);
719 if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
720 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
721 }
722 let ty::Adt(def, _args) = self_ty.kind() else {
723 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));
724 };
725 let did = def.did();
726 let span = tcx.def_span(did);
728 if !def.is_struct() {
729 return Err(tcx
730 .dcx()
731 .emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() }));
732 }
733 if !def.repr().transparent() {
734 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span }));
735 }
736 if def.all_fields().next().is_none() {
737 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span }));
738 }
739 Ok(())
740}