@@ -26,6 +26,7 @@ use rustc_middle::ty::{TypeVisitableExt, Upcast};
26
26
use rustc_session:: lint:: builtin:: WHERE_CLAUSES_OBJECT_SAFETY ;
27
27
use rustc_span:: symbol:: Symbol ;
28
28
use rustc_span:: Span ;
29
+ use rustc_target:: abi:: Abi ;
29
30
use smallvec:: SmallVec ;
30
31
31
32
use std:: iter;
@@ -44,7 +45,8 @@ pub fn hir_ty_lowering_object_safety_violations(
44
45
trait_def_id : DefId ,
45
46
) -> Vec < ObjectSafetyViolation > {
46
47
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)
48
50
. map ( |def_id| predicates_reference_self ( tcx, def_id, true ) )
49
51
. filter ( |spans| !spans. is_empty ( ) )
50
52
. map ( ObjectSafetyViolation :: SupertraitSelf )
@@ -58,7 +60,7 @@ fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [Object
58
60
debug ! ( "object_safety_violations: {:?}" , trait_def_id) ;
59
61
60
62
tcx. arena . alloc_from_iter (
61
- traits :: supertrait_def_ids ( tcx , trait_def_id)
63
+ tcx . supertrait_def_ids ( trait_def_id)
62
64
. flat_map ( |def_id| object_safety_violations_for_trait ( tcx, def_id) ) ,
63
65
)
64
66
}
@@ -145,6 +147,14 @@ fn object_safety_violations_for_trait(
145
147
violations. push ( ObjectSafetyViolation :: SupertraitNonLifetimeBinder ( spans) ) ;
146
148
}
147
149
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
+
148
158
debug ! (
149
159
"object_safety_violations_for_trait(trait_def_id={:?}) = {:?}" ,
150
160
trait_def_id, violations
@@ -498,59 +508,8 @@ fn virtual_call_violations_for_method<'tcx>(
498
508
} ;
499
509
errors. push ( MethodViolationCode :: UndispatchableReceiver ( span) ) ;
500
510
} else {
501
- // Do sanity check to make sure the receiver actually has the layout of a pointer.
502
-
503
- use rustc_target:: abi:: Abi ;
504
-
505
- let param_env = tcx. param_env ( method. def_id ) ;
506
-
507
- let abi_of_ty = |ty : Ty < ' tcx > | -> Option < Abi > {
508
- match tcx. layout_of ( param_env. and ( ty) ) {
509
- Ok ( layout) => Some ( layout. abi ) ,
510
- Err ( err) => {
511
- // #78372
512
- tcx. dcx ( ) . span_delayed_bug (
513
- tcx. def_span ( method. def_id ) ,
514
- format ! ( "error: {err}\n while computing layout for type {ty:?}" ) ,
515
- ) ;
516
- None
517
- }
518
- }
519
- } ;
520
-
521
- // e.g., `Rc<()>`
522
- let unit_receiver_ty =
523
- receiver_for_self_ty ( tcx, receiver_ty, tcx. types . unit , method. def_id ) ;
524
-
525
- match abi_of_ty ( unit_receiver_ty) {
526
- Some ( Abi :: Scalar ( ..) ) => ( ) ,
527
- abi => {
528
- tcx. dcx ( ) . span_delayed_bug (
529
- tcx. def_span ( method. def_id ) ,
530
- format ! (
531
- "receiver when `Self = ()` should have a Scalar ABI; found {abi:?}"
532
- ) ,
533
- ) ;
534
- }
535
- }
536
-
537
- let trait_object_ty = object_ty_for_trait ( tcx, trait_def_id, tcx. lifetimes . re_static ) ;
538
-
539
- // e.g., `Rc<dyn Trait>`
540
- let trait_object_receiver =
541
- receiver_for_self_ty ( tcx, receiver_ty, trait_object_ty, method. def_id ) ;
542
-
543
- match abi_of_ty ( trait_object_receiver) {
544
- Some ( Abi :: ScalarPair ( ..) ) => ( ) ,
545
- abi => {
546
- tcx. dcx ( ) . span_delayed_bug (
547
- tcx. def_span ( method. def_id ) ,
548
- format ! (
549
- "receiver when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
550
- ) ,
551
- ) ;
552
- }
553
- }
511
+ // We confirm that the `receiver_is_dispatchable` is accurate later,
512
+ // see `check_receiver_correct`. It should be kept in sync with this code.
554
513
}
555
514
}
556
515
@@ -611,6 +570,55 @@ fn virtual_call_violations_for_method<'tcx>(
611
570
errors
612
571
}
613
572
573
+ /// This code checks that `receiver_is_dispatchable` is correctly implemented.
574
+ ///
575
+ /// This check is outlined from the object safety check to avoid cycles with
576
+ /// layout computation, which relies on knowing whether methods are object safe.
577
+ pub fn check_receiver_correct < ' tcx > ( tcx : TyCtxt < ' tcx > , trait_def_id : DefId , method : ty:: AssocItem ) {
578
+ if !is_vtable_safe_method ( tcx, trait_def_id, method) {
579
+ return ;
580
+ }
581
+
582
+ let method_def_id = method. def_id ;
583
+ let sig = tcx. fn_sig ( method_def_id) . instantiate_identity ( ) ;
584
+ let param_env = tcx. param_env ( method_def_id) ;
585
+ let receiver_ty = tcx. liberate_late_bound_regions ( method_def_id, sig. input ( 0 ) ) ;
586
+
587
+ if receiver_ty == tcx. types . self_param {
588
+ // Assumed OK, may change later if unsized_locals permits `self: Self` as dispatchable.
589
+ return ;
590
+ }
591
+
592
+ // e.g., `Rc<()>`
593
+ let unit_receiver_ty = receiver_for_self_ty ( tcx, receiver_ty, tcx. types . unit , method_def_id) ;
594
+ match tcx. layout_of ( param_env. and ( unit_receiver_ty) ) . map ( |l| l. abi ) {
595
+ Ok ( Abi :: Scalar ( ..) ) => ( ) ,
596
+ abi => {
597
+ tcx. dcx ( ) . span_delayed_bug (
598
+ tcx. def_span ( method_def_id) ,
599
+ format ! ( "receiver {unit_receiver_ty:?} when `Self = ()` should have a Scalar ABI; found {abi:?}" ) ,
600
+ ) ;
601
+ }
602
+ }
603
+
604
+ let trait_object_ty = object_ty_for_trait ( tcx, trait_def_id, tcx. lifetimes . re_static ) ;
605
+
606
+ // e.g., `Rc<dyn Trait>`
607
+ let trait_object_receiver =
608
+ receiver_for_self_ty ( tcx, receiver_ty, trait_object_ty, method_def_id) ;
609
+ match tcx. layout_of ( param_env. and ( trait_object_receiver) ) . map ( |l| l. abi ) {
610
+ Ok ( Abi :: ScalarPair ( ..) ) => ( ) ,
611
+ abi => {
612
+ tcx. dcx ( ) . span_delayed_bug (
613
+ tcx. def_span ( method_def_id) ,
614
+ format ! (
615
+ "receiver {trait_object_receiver:?} when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
616
+ ) ,
617
+ ) ;
618
+ }
619
+ }
620
+ }
621
+
614
622
/// Performs a type instantiation to produce the version of `receiver_ty` when `Self = self_ty`.
615
623
/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
616
624
fn receiver_for_self_ty < ' tcx > (
0 commit comments