@@ -25,6 +25,7 @@ use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
2525use rustc_session:: lint:: builtin:: WHERE_CLAUSES_OBJECT_SAFETY ;
2626use rustc_span:: symbol:: Symbol ;
2727use rustc_span:: Span ;
28+ use rustc_target:: abi:: Abi ;
2829use smallvec:: SmallVec ;
2930
3031use std:: iter;
@@ -144,6 +145,14 @@ fn object_safety_violations_for_trait(
144145 violations. push ( ObjectSafetyViolation :: SupertraitNonLifetimeBinder ( spans) ) ;
145146 }
146147
148+ if violations. is_empty ( ) {
149+ for item in tcx. associated_items ( trait_def_id) . in_definition_order ( ) {
150+ if let ty:: AssocKind :: Fn = item. kind {
151+ check_receiver_correct ( tcx, trait_def_id, * item) ;
152+ }
153+ }
154+ }
155+
147156 debug ! (
148157 "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}" ,
149158 trait_def_id, violations
@@ -497,59 +506,8 @@ fn virtual_call_violations_for_method<'tcx>(
497506 } ;
498507 errors. push ( MethodViolationCode :: UndispatchableReceiver ( span) ) ;
499508 } else {
500- // Do sanity check to make sure the receiver actually has the layout of a pointer.
501-
502- use rustc_target:: abi:: Abi ;
503-
504- let param_env = tcx. param_env ( method. def_id ) ;
505-
506- let abi_of_ty = |ty : Ty < ' tcx > | -> Option < Abi > {
507- match tcx. layout_of ( param_env. and ( ty) ) {
508- Ok ( layout) => Some ( layout. abi ) ,
509- Err ( err) => {
510- // #78372
511- tcx. dcx ( ) . span_delayed_bug (
512- tcx. def_span ( method. def_id ) ,
513- format ! ( "error: {err}\n while computing layout for type {ty:?}" ) ,
514- ) ;
515- None
516- }
517- }
518- } ;
519-
520- // e.g., `Rc<()>`
521- let unit_receiver_ty =
522- receiver_for_self_ty ( tcx, receiver_ty, tcx. types . unit , method. def_id ) ;
523-
524- match abi_of_ty ( unit_receiver_ty) {
525- Some ( Abi :: Scalar ( ..) ) => ( ) ,
526- abi => {
527- tcx. dcx ( ) . span_delayed_bug (
528- tcx. def_span ( method. def_id ) ,
529- format ! (
530- "receiver when `Self = ()` should have a Scalar ABI; found {abi:?}"
531- ) ,
532- ) ;
533- }
534- }
535-
536- let trait_object_ty = object_ty_for_trait ( tcx, trait_def_id, tcx. lifetimes . re_static ) ;
537-
538- // e.g., `Rc<dyn Trait>`
539- let trait_object_receiver =
540- receiver_for_self_ty ( tcx, receiver_ty, trait_object_ty, method. def_id ) ;
541-
542- match abi_of_ty ( trait_object_receiver) {
543- Some ( Abi :: ScalarPair ( ..) ) => ( ) ,
544- abi => {
545- tcx. dcx ( ) . span_delayed_bug (
546- tcx. def_span ( method. def_id ) ,
547- format ! (
548- "receiver when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
549- ) ,
550- ) ;
551- }
552- }
509+ // We confirm that the `receiver_is_dispatchable` is accurate later,
510+ // see `check_receiver_correct`. It should be kept in sync with this code.
553511 }
554512 }
555513
@@ -610,6 +568,55 @@ fn virtual_call_violations_for_method<'tcx>(
610568 errors
611569}
612570
571+ /// This code checks that `receiver_is_dispatchable` is correctly implemented.
572+ ///
573+ /// This check is outlined from the object safety check to avoid cycles with
574+ /// layout computation, which relies on knowing whether methods are object safe.
575+ pub fn check_receiver_correct < ' tcx > ( tcx : TyCtxt < ' tcx > , trait_def_id : DefId , method : ty:: AssocItem ) {
576+ if !is_vtable_safe_method ( tcx, trait_def_id, method) {
577+ return ;
578+ }
579+
580+ let method_def_id = method. def_id ;
581+ let sig = tcx. fn_sig ( method_def_id) . instantiate_identity ( ) ;
582+ let param_env = tcx. param_env ( method_def_id) ;
583+ let receiver_ty = tcx. liberate_late_bound_regions ( method_def_id, sig. input ( 0 ) ) ;
584+
585+ if receiver_ty == tcx. types . self_param {
586+ // Assumed OK, may change later if unsized_locals permits `self: Self` as dispatchable.
587+ return ;
588+ }
589+
590+ // e.g., `Rc<()>`
591+ let unit_receiver_ty = receiver_for_self_ty ( tcx, receiver_ty, tcx. types . unit , method_def_id) ;
592+ match tcx. layout_of ( param_env. and ( unit_receiver_ty) ) . map ( |l| l. abi ) {
593+ Ok ( Abi :: Scalar ( ..) ) => ( ) ,
594+ abi => {
595+ tcx. dcx ( ) . span_delayed_bug (
596+ tcx. def_span ( method_def_id) ,
597+ format ! ( "receiver {unit_receiver_ty:?} when `Self = ()` should have a Scalar ABI; found {abi:?}" ) ,
598+ ) ;
599+ }
600+ }
601+
602+ let trait_object_ty = object_ty_for_trait ( tcx, trait_def_id, tcx. lifetimes . re_static ) ;
603+
604+ // e.g., `Rc<dyn Trait>`
605+ let trait_object_receiver =
606+ receiver_for_self_ty ( tcx, receiver_ty, trait_object_ty, method_def_id) ;
607+ match tcx. layout_of ( param_env. and ( trait_object_receiver) ) . map ( |l| l. abi ) {
608+ Ok ( Abi :: ScalarPair ( ..) ) => ( ) ,
609+ abi => {
610+ tcx. dcx ( ) . span_delayed_bug (
611+ tcx. def_span ( method_def_id) ,
612+ format ! (
613+ "receiver {trait_object_receiver:?} when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
614+ ) ,
615+ ) ;
616+ }
617+ }
618+ }
619+
613620/// Performs a type instantiation to produce the version of `receiver_ty` when `Self = self_ty`.
614621/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
615622fn receiver_for_self_ty < ' tcx > (
0 commit comments