@@ -26,6 +26,7 @@ use rustc_middle::ty::{TypeVisitableExt, Upcast};
2626use rustc_session:: lint:: builtin:: WHERE_CLAUSES_OBJECT_SAFETY ;
2727use rustc_span:: symbol:: Symbol ;
2828use rustc_span:: Span ;
29+ use rustc_target:: abi:: Abi ;
2930use smallvec:: SmallVec ;
3031
3132use std:: iter;
@@ -44,7 +45,8 @@ pub fn hir_ty_lowering_object_safety_violations(
4445 trait_def_id : DefId ,
4546) -> Vec < ObjectSafetyViolation > {
4647 debug_assert ! ( tcx. generics_of( trait_def_id) . has_self) ;
47- let violations = traits:: supertrait_def_ids ( tcx, trait_def_id)
48+ let violations = tcx
49+ . supertrait_def_ids ( trait_def_id)
4850 . map ( |def_id| predicates_reference_self ( tcx, def_id, true ) )
4951 . filter ( |spans| !spans. is_empty ( ) )
5052 . map ( ObjectSafetyViolation :: SupertraitSelf )
@@ -58,7 +60,7 @@ fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [Object
5860 debug ! ( "object_safety_violations: {:?}" , trait_def_id) ;
5961
6062 tcx. arena . alloc_from_iter (
61- traits :: supertrait_def_ids ( tcx , trait_def_id)
63+ tcx . supertrait_def_ids ( trait_def_id)
6264 . flat_map ( |def_id| object_safety_violations_for_trait ( tcx, def_id) ) ,
6365 )
6466}
@@ -145,6 +147,14 @@ fn object_safety_violations_for_trait(
145147 violations. push ( ObjectSafetyViolation :: SupertraitNonLifetimeBinder ( spans) ) ;
146148 }
147149
150+ if violations. is_empty ( ) {
151+ for item in tcx. associated_items ( trait_def_id) . in_definition_order ( ) {
152+ if let ty:: AssocKind :: Fn = item. kind {
153+ check_receiver_correct ( tcx, trait_def_id, * item) ;
154+ }
155+ }
156+ }
157+
148158 debug ! (
149159 "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}" ,
150160 trait_def_id, violations
@@ -493,59 +503,8 @@ fn virtual_call_violations_for_method<'tcx>(
493503 } ;
494504 errors. push ( MethodViolationCode :: UndispatchableReceiver ( span) ) ;
495505 } else {
496- // Do sanity check to make sure the receiver actually has the layout of a pointer.
497-
498- use rustc_target:: abi:: Abi ;
499-
500- let param_env = tcx. param_env ( method. def_id ) ;
501-
502- let abi_of_ty = |ty : Ty < ' tcx > | -> Option < Abi > {
503- match tcx. layout_of ( param_env. and ( ty) ) {
504- Ok ( layout) => Some ( layout. abi ) ,
505- Err ( err) => {
506- // #78372
507- tcx. dcx ( ) . span_delayed_bug (
508- tcx. def_span ( method. def_id ) ,
509- format ! ( "error: {err}\n while computing layout for type {ty:?}" ) ,
510- ) ;
511- None
512- }
513- }
514- } ;
515-
516- // e.g., `Rc<()>`
517- let unit_receiver_ty =
518- receiver_for_self_ty ( tcx, receiver_ty, tcx. types . unit , method. def_id ) ;
519-
520- match abi_of_ty ( unit_receiver_ty) {
521- Some ( Abi :: Scalar ( ..) ) => ( ) ,
522- abi => {
523- tcx. dcx ( ) . span_delayed_bug (
524- tcx. def_span ( method. def_id ) ,
525- format ! (
526- "receiver when `Self = ()` should have a Scalar ABI; found {abi:?}"
527- ) ,
528- ) ;
529- }
530- }
531-
532- let trait_object_ty = object_ty_for_trait ( tcx, trait_def_id, tcx. lifetimes . re_static ) ;
533-
534- // e.g., `Rc<dyn Trait>`
535- let trait_object_receiver =
536- receiver_for_self_ty ( tcx, receiver_ty, trait_object_ty, method. def_id ) ;
537-
538- match abi_of_ty ( trait_object_receiver) {
539- Some ( Abi :: ScalarPair ( ..) ) => ( ) ,
540- abi => {
541- tcx. dcx ( ) . span_delayed_bug (
542- tcx. def_span ( method. def_id ) ,
543- format ! (
544- "receiver when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
545- ) ,
546- ) ;
547- }
548- }
506+ // We confirm that the `receiver_is_dispatchable` is accurate later,
507+ // see `check_receiver_correct`. It should be kept in sync with this code.
549508 }
550509 }
551510
@@ -606,6 +565,55 @@ fn virtual_call_violations_for_method<'tcx>(
606565 errors
607566}
608567
568+ /// This code checks that `receiver_is_dispatchable` is correctly implemented.
569+ ///
570+ /// This check is outlined from the object safety check to avoid cycles with
571+ /// layout computation, which relies on knowing whether methods are object safe.
572+ pub fn check_receiver_correct < ' tcx > ( tcx : TyCtxt < ' tcx > , trait_def_id : DefId , method : ty:: AssocItem ) {
573+ if !is_vtable_safe_method ( tcx, trait_def_id, method) {
574+ return ;
575+ }
576+
577+ let method_def_id = method. def_id ;
578+ let sig = tcx. fn_sig ( method_def_id) . instantiate_identity ( ) ;
579+ let param_env = tcx. param_env ( method_def_id) ;
580+ let receiver_ty = tcx. liberate_late_bound_regions ( method_def_id, sig. input ( 0 ) ) ;
581+
582+ if receiver_ty == tcx. types . self_param {
583+ // Assumed OK, may change later if unsized_locals permits `self: Self` as dispatchable.
584+ return ;
585+ }
586+
587+ // e.g., `Rc<()>`
588+ let unit_receiver_ty = receiver_for_self_ty ( tcx, receiver_ty, tcx. types . unit , method_def_id) ;
589+ match tcx. layout_of ( param_env. and ( unit_receiver_ty) ) . map ( |l| l. abi ) {
590+ Ok ( Abi :: Scalar ( ..) ) => ( ) ,
591+ abi => {
592+ tcx. dcx ( ) . span_delayed_bug (
593+ tcx. def_span ( method_def_id) ,
594+ format ! ( "receiver {unit_receiver_ty:?} when `Self = ()` should have a Scalar ABI; found {abi:?}" ) ,
595+ ) ;
596+ }
597+ }
598+
599+ let trait_object_ty = object_ty_for_trait ( tcx, trait_def_id, tcx. lifetimes . re_static ) ;
600+
601+ // e.g., `Rc<dyn Trait>`
602+ let trait_object_receiver =
603+ receiver_for_self_ty ( tcx, receiver_ty, trait_object_ty, method_def_id) ;
604+ match tcx. layout_of ( param_env. and ( trait_object_receiver) ) . map ( |l| l. abi ) {
605+ Ok ( Abi :: ScalarPair ( ..) ) => ( ) ,
606+ abi => {
607+ tcx. dcx ( ) . span_delayed_bug (
608+ tcx. def_span ( method_def_id) ,
609+ format ! (
610+ "receiver {trait_object_receiver:?} when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
611+ ) ,
612+ ) ;
613+ }
614+ }
615+ }
616+
609617/// Performs a type instantiation to produce the version of `receiver_ty` when `Self = self_ty`.
610618/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
611619fn receiver_for_self_ty < ' tcx > (
0 commit comments