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(of_trait), .. }) =
535 &item.kind
536 {
537 of_trait.trait_ref.path.span
538 } else {
539 tcx.def_span(impl_did)
540 };
541
542 return Err(tcx.dcx().emit_err(errors::CoerceMulti {
543 span,
544 trait_name,
545 number: diff_fields.len(),
546 fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
547 }));
548 }
549
550 let (i, a, b, field_span) = diff_fields[0];
551 let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
552 (a, b, coerce_unsized_trait, Some(kind), field_span)
553 }
554
555 _ => {
556 return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
557 }
558 };
559
560 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
562 let cause = traits::ObligationCause::misc(span, impl_did);
563 let obligation = Obligation::new(
564 tcx,
565 cause,
566 param_env,
567 ty::TraitRef::new(tcx, trait_def_id, [source, target]),
568 );
569 ocx.register_obligation(obligation);
570 let errors = ocx.select_all_or_error();
571
572 if !errors.is_empty() {
573 if is_from_coerce_pointee_derive(tcx, span) {
574 return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
575 span,
576 trait_name,
577 ty: trait_ref.self_ty(),
578 field_span,
579 field_ty: source,
580 }));
581 } else {
582 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
583 }
584 }
585
586 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
588
589 Ok(CoerceUnsizedInfo { custom_kind: kind })
590}
591
592fn infringing_fields_error<'tcx>(
593 tcx: TyCtxt<'tcx>,
594 infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
595 lang_item: LangItem,
596 impl_did: LocalDefId,
597 impl_span: Span,
598) -> ErrorGuaranteed {
599 let trait_did = tcx.require_lang_item(lang_item, impl_span);
600
601 let trait_name = tcx.def_path_str(trait_did);
602
603 let mut errors: BTreeMap<_, Vec<_>> = Default::default();
606 let mut bounds = vec![];
607
608 let mut seen_tys = FxHashSet::default();
609
610 let mut label_spans = Vec::new();
611
612 for (span, ty, reason) in infringing_tys {
613 if !seen_tys.insert(ty) {
615 continue;
616 }
617
618 label_spans.push(span);
619
620 match reason {
621 InfringingFieldsReason::Fulfill(fulfillment_errors) => {
622 for error in fulfillment_errors {
623 let error_predicate = error.obligation.predicate;
624 if error_predicate != error.root_obligation.predicate {
630 errors
631 .entry((ty.to_string(), error_predicate.to_string()))
632 .or_default()
633 .push(error.obligation.cause.span);
634 }
635 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
636 trait_ref,
637 polarity: ty::PredicatePolarity::Positive,
638 ..
639 })) = error_predicate.kind().skip_binder()
640 {
641 let ty = trait_ref.self_ty();
642 if let ty::Param(_) = ty.kind() {
643 bounds.push((
644 format!("{ty}"),
645 trait_ref.print_trait_sugared().to_string(),
646 Some(trait_ref.def_id),
647 ));
648 }
649 }
650 }
651 }
652 InfringingFieldsReason::Regions(region_errors) => {
653 for error in region_errors {
654 let ty = ty.to_string();
655 match error {
656 RegionResolutionError::ConcreteFailure(origin, a, b) => {
657 let predicate = format!("{b}: {a}");
658 errors
659 .entry((ty.clone(), predicate.clone()))
660 .or_default()
661 .push(origin.span());
662 if let ty::RegionKind::ReEarlyParam(ebr) = b.kind()
663 && ebr.is_named()
664 {
665 bounds.push((b.to_string(), a.to_string(), None));
666 }
667 }
668 RegionResolutionError::GenericBoundFailure(origin, a, b) => {
669 let predicate = format!("{a}: {b}");
670 errors
671 .entry((ty.clone(), predicate.clone()))
672 .or_default()
673 .push(origin.span());
674 if let infer::region_constraints::GenericKind::Param(_) = a {
675 bounds.push((a.to_string(), b.to_string(), None));
676 }
677 }
678 _ => continue,
679 }
680 }
681 }
682 }
683 }
684 let mut notes = Vec::new();
685 for ((ty, error_predicate), spans) in errors {
686 let span: MultiSpan = spans.into();
687 notes.push(errors::ImplForTyRequires {
688 span,
689 error_predicate,
690 trait_name: trait_name.clone(),
691 ty,
692 });
693 }
694
695 let mut err = tcx.dcx().create_err(errors::TraitCannotImplForTy {
696 span: impl_span,
697 trait_name,
698 label_spans,
699 notes,
700 });
701
702 suggest_constraining_type_params(
703 tcx,
704 tcx.hir_get_generics(impl_did).expect("impls always have generics"),
705 &mut err,
706 bounds
707 .iter()
708 .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
709 None,
710 );
711
712 err.emit()
713}
714
715fn visit_implementation_of_coerce_pointee_validity(
716 checker: &Checker<'_>,
717) -> Result<(), ErrorGuaranteed> {
718 let tcx = checker.tcx;
719 let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
720 let span = tcx.def_span(checker.impl_def_id);
721 if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
722 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
723 }
724 let ty::Adt(def, _args) = self_ty.kind() else {
725 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));
726 };
727 let did = def.did();
728 let span = tcx.def_span(did);
730 if !def.is_struct() {
731 return Err(tcx
732 .dcx()
733 .emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() }));
734 }
735 if !def.repr().transparent() {
736 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span }));
737 }
738 if def.all_fields().next().is_none() {
739 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span }));
740 }
741 Ok(())
742}