rustc_hir_analysis/coherence/
builtin.rs1use std::collections::BTreeMap;
5
6use rustc_data_structures::fx::FxHashSet;
7use rustc_errors::{ErrorGuaranteed, MultiSpan};
8use rustc_hir as hir;
9use rustc_hir::ItemKind;
10use rustc_hir::def_id::{DefId, LocalDefId};
11use rustc_hir::lang_items::LangItem;
12use rustc_infer::infer::{self, RegionResolutionError, SubregionOrigin, TyCtxtInferExt};
13use rustc_infer::traits::Obligation;
14use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
15use rustc_middle::ty::print::PrintTraitRefExt as _;
16use rustc_middle::ty::{
17 self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params,
18};
19use rustc_span::{DUMMY_SP, Span, sym};
20use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
21use rustc_trait_selection::traits::misc::{
22 ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
23 type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
24};
25use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
26use tracing::debug;
27
28use crate::errors;
29
30pub(super) fn check_trait<'tcx>(
31 tcx: TyCtxt<'tcx>,
32 trait_def_id: DefId,
33 impl_def_id: LocalDefId,
34 impl_header: ty::ImplTraitHeader<'tcx>,
35) -> Result<(), ErrorGuaranteed> {
36 let lang_items = tcx.lang_items();
37 let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
38 checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
39 checker.check(lang_items.async_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)
43 })?;
44 checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
45 checker
46 .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
47 checker.check(
48 lang_items.coerce_pointee_validated_trait(),
49 visit_implementation_of_coerce_pointee_validity,
50 )?;
51 Ok(())
52}
53
54struct Checker<'tcx> {
55 tcx: TyCtxt<'tcx>,
56 trait_def_id: DefId,
57 impl_def_id: LocalDefId,
58 impl_header: ty::ImplTraitHeader<'tcx>,
59}
60
61impl<'tcx> Checker<'tcx> {
62 fn check(
63 &self,
64 trait_def_id: Option<DefId>,
65 f: impl FnOnce(&Self) -> Result<(), ErrorGuaranteed>,
66 ) -> Result<(), ErrorGuaranteed> {
67 if Some(self.trait_def_id) == trait_def_id { f(self) } else { Ok(()) }
68 }
69}
70
71fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
72 let tcx = checker.tcx;
73 let impl_did = checker.impl_def_id;
74 match checker.impl_header.trait_ref.instantiate_identity().self_ty().kind() {
76 ty::Adt(def, _) if def.did().is_local() => return Ok(()),
77 ty::Error(_) => return Ok(()),
78 _ => {}
79 }
80
81 let impl_ = tcx.hir_expect_item(impl_did).expect_impl();
82
83 Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem {
84 span: impl_.self_ty.span,
85 trait_: tcx.item_name(checker.impl_header.trait_ref.skip_binder().def_id),
86 }))
87}
88
89fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
90 let tcx = checker.tcx;
91 let impl_header = checker.impl_header;
92 let impl_did = checker.impl_def_id;
93 debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
94
95 let self_type = impl_header.trait_ref.instantiate_identity().self_ty();
96 debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
97
98 let param_env = tcx.param_env(impl_did);
99 assert!(!self_type.has_escaping_bound_vars());
100
101 debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
102
103 if let ty::ImplPolarity::Negative = impl_header.polarity {
104 return Ok(());
105 }
106
107 let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
108 match type_allowed_to_implement_copy(tcx, param_env, self_type, cause, impl_header.safety) {
109 Ok(()) => Ok(()),
110 Err(CopyImplementationError::InfringingFields(fields)) => {
111 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
112 Err(infringing_fields_error(
113 tcx,
114 fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
115 LangItem::Copy,
116 impl_did,
117 span,
118 ))
119 }
120 Err(CopyImplementationError::NotAnAdt) => {
121 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
122 Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span }))
123 }
124 Err(CopyImplementationError::HasDestructor) => {
125 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
126 Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span }))
127 }
128 Err(CopyImplementationError::HasUnsafeFields) => {
129 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
130 Err(tcx
131 .dcx()
132 .span_delayed_bug(span, format!("cannot implement `Copy` for `{}`", self_type)))
133 }
134 }
135}
136
137fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
138 let tcx = checker.tcx;
139 let header = checker.impl_header;
140 let impl_did = checker.impl_def_id;
141 let self_type = header.trait_ref.instantiate_identity().self_ty();
142 assert!(!self_type.has_escaping_bound_vars());
143
144 let param_env = tcx.param_env(impl_did);
145
146 if let ty::ImplPolarity::Negative | ty::ImplPolarity::Reservation = header.polarity {
147 return Ok(());
148 }
149
150 let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
151 match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
152 Ok(()) => Ok(()),
153 Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
154 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
155 Err(infringing_fields_error(
156 tcx,
157 fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)),
158 LangItem::ConstParamTy,
159 impl_did,
160 span,
161 ))
162 }
163 Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
164 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
165 Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
166 }
167 Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => {
168 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
169 Err(infringing_fields_error(
170 tcx,
171 infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)),
172 LangItem::ConstParamTy,
173 impl_did,
174 span,
175 ))
176 }
177 Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => {
178 let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span;
179 Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span }))
180 }
181 }
182}
183
184fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
185 let tcx = checker.tcx;
186 let impl_did = checker.impl_def_id;
187 debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
188
189 tcx.ensure_ok().coerce_unsized_info(impl_did)
193}
194
195fn is_from_coerce_pointee_derive(tcx: TyCtxt<'_>, span: Span) -> bool {
196 span.ctxt()
197 .outer_expn_data()
198 .macro_def_id
199 .is_some_and(|def_id| tcx.is_diagnostic_item(sym::CoercePointee, def_id))
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 let trait_name = "DispatchFromDyn";
210
211 let source = trait_ref.self_ty();
212 let target = {
213 assert!(tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn));
214
215 trait_ref.args.type_at(1)
216 };
217
218 let mut res = Ok(());
221 tcx.for_each_relevant_impl(
222 tcx.require_lang_item(LangItem::CoerceUnsized, span),
223 source,
224 |impl_def_id| {
225 res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id));
226 },
227 );
228 res?;
229
230 debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
231
232 let param_env = tcx.param_env(impl_did);
233
234 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
235 let cause = ObligationCause::misc(span, impl_did);
236
237 match (source.kind(), target.kind()) {
246 (&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
247 if r_a == *r_b && mutbl_a == *mutbl_b =>
248 {
249 Ok(())
250 }
251 (&ty::RawPtr(_, a_mutbl), &ty::RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
252 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
253 if def_a.is_struct() && def_b.is_struct() =>
254 {
255 if def_a != def_b {
256 let source_path = tcx.def_path_str(def_a.did());
257 let target_path = tcx.def_path_str(def_b.did());
258 return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
259 span,
260 trait_name,
261 note: true,
262 source_path,
263 target_path,
264 }));
265 }
266
267 if def_a.repr().c() || def_a.repr().packed() {
268 return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
269 }
270
271 let fields = &def_a.non_enum_variant().fields;
272
273 let mut res = Ok(());
274 let coerced_fields = fields
275 .iter_enumerated()
276 .filter_map(|(i, field)| {
277 let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
279 if tcx
280 .try_normalize_erasing_regions(
281 ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
282 unnormalized_ty,
283 )
284 .unwrap_or(unnormalized_ty)
285 .is_phantom_data()
286 {
287 return None;
288 }
289
290 let ty_a = field.ty(tcx, args_a);
291 let ty_b = field.ty(tcx, args_b);
292
293 if ty_a == ty_b {
295 if let Ok(layout) =
300 tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
301 && layout.is_1zst()
302 && !ty_a.has_non_region_param()
303 {
304 return None;
306 }
307
308 res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
309 span,
310 name: field.ident(tcx),
311 ty: ty_a,
312 }));
313
314 None
315 } else {
316 Some((i, ty_a, ty_b, tcx.def_span(field.did)))
317 }
318 })
319 .collect::<Vec<_>>();
320 res?;
321
322 if coerced_fields.is_empty() {
323 return Err(tcx.dcx().emit_err(errors::CoerceNoField {
324 span,
325 trait_name,
326 note: true,
327 }));
328 } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {
329 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
330 ocx.register_obligation(Obligation::new(
331 tcx,
332 cause.clone(),
333 param_env,
334 ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]),
335 ));
336 let errors = ocx.evaluate_obligations_error_on_ambiguity();
337 if !errors.is_empty() {
338 if is_from_coerce_pointee_derive(tcx, span) {
339 return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
340 span,
341 trait_name,
342 ty: trait_ref.self_ty(),
343 field_span,
344 field_ty: ty_a,
345 }));
346 } else {
347 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
348 }
349 }
350
351 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
353
354 Ok(())
355 } else {
356 return Err(tcx.dcx().emit_err(errors::CoerceMulti {
357 span,
358 trait_name,
359 number: coerced_fields.len(),
360 fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
361 }));
362 }
363 }
364 _ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })),
365 }
366}
367
368pub(crate) fn coerce_unsized_info<'tcx>(
369 tcx: TyCtxt<'tcx>,
370 impl_did: LocalDefId,
371) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
372 debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
373 let span = tcx.def_span(impl_did);
374 let trait_name = "CoerceUnsized";
375
376 let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, span);
377 let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span);
378
379 let source = tcx.type_of(impl_did).instantiate_identity();
380 let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
381
382 assert_eq!(trait_ref.def_id, coerce_unsized_trait);
383 let target = trait_ref.args.type_at(1);
384 debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
385
386 let param_env = tcx.param_env(impl_did);
387 assert!(!source.has_escaping_bound_vars());
388
389 debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
390
391 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
392 let cause = ObligationCause::misc(span, impl_did);
393 let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
394 mt_b: ty::TypeAndMut<'tcx>,
395 mk_ptr: &dyn Fn(Ty<'tcx>) -> Ty<'tcx>| {
396 if mt_a.mutbl < mt_b.mutbl {
397 infcx
398 .err_ctxt()
399 .report_mismatched_types(
400 &cause,
401 param_env,
402 mk_ptr(mt_b.ty),
403 target,
404 ty::error::TypeError::Mutability,
405 )
406 .emit();
407 }
408 (mt_a.ty, mt_b.ty, unsize_trait, None, span)
409 };
410 let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
411 (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
412 infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a);
413 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
414 let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
415 check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
416 }
417
418 (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b))
419 | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => {
420 let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
421 let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
422 check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
423 }
424
425 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
426 if def_a.is_struct() && def_b.is_struct() =>
427 {
428 if def_a != def_b {
429 let source_path = tcx.def_path_str(def_a.did());
430 let target_path = tcx.def_path_str(def_b.did());
431 return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
432 span,
433 trait_name,
434 note: true,
435 source_path,
436 target_path,
437 }));
438 }
439
440 let fields = &def_a.non_enum_variant().fields;
480 let diff_fields = fields
481 .iter_enumerated()
482 .filter_map(|(i, f)| {
483 let (a, b) = (f.ty(tcx, args_a), f.ty(tcx, args_b));
484
485 let unnormalized_ty = tcx.type_of(f.did).instantiate_identity();
487 if tcx
488 .try_normalize_erasing_regions(
489 ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
490 unnormalized_ty,
491 )
492 .unwrap_or(unnormalized_ty)
493 .is_phantom_data()
494 {
495 return None;
496 }
497
498 if a == b {
508 return None;
509 }
510
511 Some((i, a, b, tcx.def_span(f.did)))
514 })
515 .collect::<Vec<_>>();
516
517 if diff_fields.is_empty() {
518 return Err(tcx.dcx().emit_err(errors::CoerceNoField {
519 span,
520 trait_name,
521 note: true,
522 }));
523 } else if diff_fields.len() > 1 {
524 let item = tcx.hir_expect_item(impl_did);
525 let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) =
526 &item.kind
527 {
528 of_trait.trait_ref.path.span
529 } else {
530 tcx.def_span(impl_did)
531 };
532
533 return Err(tcx.dcx().emit_err(errors::CoerceMulti {
534 span,
535 trait_name,
536 number: diff_fields.len(),
537 fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
538 }));
539 }
540
541 let (i, a, b, field_span) = diff_fields[0];
542 let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
543 (a, b, coerce_unsized_trait, Some(kind), field_span)
544 }
545
546 _ => {
547 return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
548 }
549 };
550
551 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
553 let cause = traits::ObligationCause::misc(span, impl_did);
554 let obligation = Obligation::new(
555 tcx,
556 cause,
557 param_env,
558 ty::TraitRef::new(tcx, trait_def_id, [source, target]),
559 );
560 ocx.register_obligation(obligation);
561 let errors = ocx.evaluate_obligations_error_on_ambiguity();
562
563 if !errors.is_empty() {
564 if is_from_coerce_pointee_derive(tcx, span) {
565 return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
566 span,
567 trait_name,
568 ty: trait_ref.self_ty(),
569 field_span,
570 field_ty: source,
571 }));
572 } else {
573 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
574 }
575 }
576
577 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
579
580 Ok(CoerceUnsizedInfo { custom_kind: kind })
581}
582
583fn infringing_fields_error<'tcx>(
584 tcx: TyCtxt<'tcx>,
585 infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>,
586 lang_item: LangItem,
587 impl_did: LocalDefId,
588 impl_span: Span,
589) -> ErrorGuaranteed {
590 let trait_did = tcx.require_lang_item(lang_item, impl_span);
591
592 let trait_name = tcx.def_path_str(trait_did);
593
594 let mut errors: BTreeMap<_, Vec<_>> = Default::default();
597 let mut bounds = vec![];
598
599 let mut seen_tys = FxHashSet::default();
600
601 let mut label_spans = Vec::new();
602
603 for (span, ty, reason) in infringing_tys {
604 if !seen_tys.insert(ty) {
606 continue;
607 }
608
609 label_spans.push(span);
610
611 match reason {
612 InfringingFieldsReason::Fulfill(fulfillment_errors) => {
613 for error in fulfillment_errors {
614 let error_predicate = error.obligation.predicate;
615 if error_predicate != error.root_obligation.predicate {
621 errors
622 .entry((ty.to_string(), error_predicate.to_string()))
623 .or_default()
624 .push(error.obligation.cause.span);
625 }
626 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
627 trait_ref,
628 polarity: ty::PredicatePolarity::Positive,
629 ..
630 })) = error_predicate.kind().skip_binder()
631 {
632 let ty = trait_ref.self_ty();
633 if let ty::Param(_) = ty.kind() {
634 bounds.push((
635 format!("{ty}"),
636 trait_ref.print_trait_sugared().to_string(),
637 Some(trait_ref.def_id),
638 ));
639 }
640 }
641 }
642 }
643 InfringingFieldsReason::Regions(region_errors) => {
644 for error in region_errors {
645 let ty = ty.to_string();
646 match error {
647 RegionResolutionError::ConcreteFailure(origin, a, b) => {
648 let predicate = format!("{b}: {a}");
649 errors
650 .entry((ty.clone(), predicate.clone()))
651 .or_default()
652 .push(origin.span());
653 if let ty::RegionKind::ReEarlyParam(ebr) = b.kind()
654 && ebr.is_named()
655 {
656 bounds.push((b.to_string(), a.to_string(), None));
657 }
658 }
659 RegionResolutionError::GenericBoundFailure(origin, a, b) => {
660 let predicate = format!("{a}: {b}");
661 errors
662 .entry((ty.clone(), predicate.clone()))
663 .or_default()
664 .push(origin.span());
665 if let infer::region_constraints::GenericKind::Param(_) = a {
666 bounds.push((a.to_string(), b.to_string(), None));
667 }
668 }
669 _ => continue,
670 }
671 }
672 }
673 }
674 }
675 let mut notes = Vec::new();
676 for ((ty, error_predicate), spans) in errors {
677 let span: MultiSpan = spans.into();
678 notes.push(errors::ImplForTyRequires {
679 span,
680 error_predicate,
681 trait_name: trait_name.clone(),
682 ty,
683 });
684 }
685
686 let mut err = tcx.dcx().create_err(errors::TraitCannotImplForTy {
687 span: impl_span,
688 trait_name,
689 label_spans,
690 notes,
691 });
692
693 suggest_constraining_type_params(
694 tcx,
695 tcx.hir_get_generics(impl_did).expect("impls always have generics"),
696 &mut err,
697 bounds
698 .iter()
699 .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
700 None,
701 );
702
703 err.emit()
704}
705
706fn visit_implementation_of_coerce_pointee_validity(
707 checker: &Checker<'_>,
708) -> Result<(), ErrorGuaranteed> {
709 let tcx = checker.tcx;
710 let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
711 let span = tcx.def_span(checker.impl_def_id);
712 if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
713 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
714 }
715 let ty::Adt(def, _args) = self_ty.kind() else {
716 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotConcreteType { span }));
717 };
718 let did = def.did();
719 let span = tcx.def_span(did);
721 if !def.is_struct() {
722 return Err(tcx
723 .dcx()
724 .emit_err(errors::CoercePointeeNotStruct { span, kind: def.descr().into() }));
725 }
726 if !def.repr().transparent() {
727 return Err(tcx.dcx().emit_err(errors::CoercePointeeNotTransparent { span }));
728 }
729 if def.all_fields().next().is_none() {
730 return Err(tcx.dcx().emit_err(errors::CoercePointeeNoField { span }));
731 }
732 Ok(())
733}