@@ -97,6 +97,10 @@ fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
97
97
/// object. Note that object-safe traits can have some
98
98
/// non-vtable-safe methods, so long as they require `Self: Sized` or
99
99
/// otherwise ensure that they cannot be used when `Self = Trait`.
100
+ ///
101
+ /// [`MethodViolationCode::WhereClauseReferencesSelf`] is considered object safe due to backwards
102
+ /// compatibility, see <https://github.com/rust-lang/rust/issues/51443> and
103
+ /// [`WHERE_CLAUSES_OBJECT_SAFETY`].
100
104
pub fn is_vtable_safe_method ( tcx : TyCtxt < ' _ > , trait_def_id : DefId , method : ty:: AssocItem ) -> bool {
101
105
debug_assert ! ( tcx. generics_of( trait_def_id) . has_self) ;
102
106
debug ! ( "is_vtable_safe_method({:?}, {:?})" , trait_def_id, method) ;
@@ -105,10 +109,9 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A
105
109
return false ;
106
110
}
107
111
108
- match virtual_call_violation_for_method ( tcx, trait_def_id, method) {
109
- None | Some ( MethodViolationCode :: WhereClauseReferencesSelf ) => true ,
110
- Some ( _) => false ,
111
- }
112
+ virtual_call_violations_for_method ( tcx, trait_def_id, method)
113
+ . iter ( )
114
+ . all ( |v| matches ! ( v, MethodViolationCode :: WhereClauseReferencesSelf ) )
112
115
}
113
116
114
117
fn object_safety_violations_for_trait (
@@ -119,7 +122,7 @@ fn object_safety_violations_for_trait(
119
122
let mut violations: Vec < _ > = tcx
120
123
. associated_items ( trait_def_id)
121
124
. in_definition_order ( )
122
- . filter_map ( |& item| object_safety_violation_for_assoc_item ( tcx, trait_def_id, item) )
125
+ . flat_map ( |& item| object_safety_violations_for_assoc_item ( tcx, trait_def_id, item) )
123
126
. collect ( ) ;
124
127
125
128
// Check the trait itself.
@@ -357,49 +360,52 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
357
360
358
361
/// Returns `Some(_)` if this item makes the containing trait not object safe.
359
362
#[ instrument( level = "debug" , skip( tcx) , ret) ]
360
- fn object_safety_violation_for_assoc_item (
363
+ fn object_safety_violations_for_assoc_item (
361
364
tcx : TyCtxt < ' _ > ,
362
365
trait_def_id : DefId ,
363
366
item : ty:: AssocItem ,
364
- ) -> Option < ObjectSafetyViolation > {
367
+ ) -> Vec < ObjectSafetyViolation > {
365
368
// Any item that has a `Self : Sized` requisite is otherwise
366
369
// exempt from the regulations.
367
370
if tcx. generics_require_sized_self ( item. def_id ) {
368
- return None ;
371
+ return Vec :: new ( ) ;
369
372
}
370
373
371
374
match item. kind {
372
375
// Associated consts are never object safe, as they can't have `where` bounds yet at all,
373
376
// and associated const bounds in trait objects aren't a thing yet either.
374
377
ty:: AssocKind :: Const => {
375
- Some ( ObjectSafetyViolation :: AssocConst ( item. name , item. ident ( tcx) . span ) )
378
+ vec ! [ ObjectSafetyViolation :: AssocConst ( item. name, item. ident( tcx) . span) ]
376
379
}
377
- ty:: AssocKind :: Fn => virtual_call_violation_for_method ( tcx, trait_def_id, item) . map ( |v| {
378
- let node = tcx. hir ( ) . get_if_local ( item. def_id ) ;
379
- // Get an accurate span depending on the violation.
380
- let span = match ( & v, node) {
381
- ( MethodViolationCode :: ReferencesSelfInput ( Some ( span) ) , _) => * span,
382
- ( MethodViolationCode :: UndispatchableReceiver ( Some ( span) ) , _) => * span,
383
- ( MethodViolationCode :: ReferencesImplTraitInTrait ( span) , _) => * span,
384
- ( MethodViolationCode :: ReferencesSelfOutput , Some ( node) ) => {
385
- node. fn_decl ( ) . map_or ( item. ident ( tcx) . span , |decl| decl. output . span ( ) )
386
- }
387
- _ => item. ident ( tcx) . span ,
388
- } ;
380
+ ty:: AssocKind :: Fn => virtual_call_violations_for_method ( tcx, trait_def_id, item)
381
+ . into_iter ( )
382
+ . map ( |v| {
383
+ let node = tcx. hir ( ) . get_if_local ( item. def_id ) ;
384
+ // Get an accurate span depending on the violation.
385
+ let span = match ( & v, node) {
386
+ ( MethodViolationCode :: ReferencesSelfInput ( Some ( span) ) , _) => * span,
387
+ ( MethodViolationCode :: UndispatchableReceiver ( Some ( span) ) , _) => * span,
388
+ ( MethodViolationCode :: ReferencesImplTraitInTrait ( span) , _) => * span,
389
+ ( MethodViolationCode :: ReferencesSelfOutput , Some ( node) ) => {
390
+ node. fn_decl ( ) . map_or ( item. ident ( tcx) . span , |decl| decl. output . span ( ) )
391
+ }
392
+ _ => item. ident ( tcx) . span ,
393
+ } ;
389
394
390
- ObjectSafetyViolation :: Method ( item. name , v, span)
391
- } ) ,
395
+ ObjectSafetyViolation :: Method ( item. name , v, span)
396
+ } )
397
+ . collect ( ) ,
392
398
// Associated types can only be object safe if they have `Self: Sized` bounds.
393
399
ty:: AssocKind :: Type => {
394
400
if !tcx. features ( ) . generic_associated_types_extended
395
401
&& !tcx. generics_of ( item. def_id ) . params . is_empty ( )
396
402
&& !item. is_impl_trait_in_trait ( )
397
403
{
398
- Some ( ObjectSafetyViolation :: GAT ( item. name , item. ident ( tcx) . span ) )
404
+ vec ! [ ObjectSafetyViolation :: GAT ( item. name, item. ident( tcx) . span) ]
399
405
} else {
400
406
// We will permit associated types if they are explicitly mentioned in the trait object.
401
407
// We can't check this here, as here we only check if it is guaranteed to not be possible.
402
- None
408
+ Vec :: new ( )
403
409
}
404
410
}
405
411
}
@@ -409,11 +415,11 @@ fn object_safety_violation_for_assoc_item(
409
415
/// object; this does not necessarily imply that the enclosing trait
410
416
/// is not object safe, because the method might have a where clause
411
417
/// `Self:Sized`.
412
- fn virtual_call_violation_for_method < ' tcx > (
418
+ fn virtual_call_violations_for_method < ' tcx > (
413
419
tcx : TyCtxt < ' tcx > ,
414
420
trait_def_id : DefId ,
415
421
method : ty:: AssocItem ,
416
- ) -> Option < MethodViolationCode > {
422
+ ) -> Vec < MethodViolationCode > {
417
423
let sig = tcx. fn_sig ( method. def_id ) . instantiate_identity ( ) ;
418
424
419
425
// The method's first parameter must be named `self`
@@ -438,9 +444,14 @@ fn virtual_call_violation_for_method<'tcx>(
438
444
} else {
439
445
None
440
446
} ;
441
- return Some ( MethodViolationCode :: StaticMethod ( sugg) ) ;
447
+
448
+ // Not having `self` parameter messes up the later checks,
449
+ // so we need to return instead of pushing
450
+ return vec ! [ MethodViolationCode :: StaticMethod ( sugg) ] ;
442
451
}
443
452
453
+ let mut errors = Vec :: new ( ) ;
454
+
444
455
for ( i, & input_ty) in sig. skip_binder ( ) . inputs ( ) . iter ( ) . enumerate ( ) . skip ( 1 ) {
445
456
if contains_illegal_self_type_reference ( tcx, trait_def_id, sig. rebind ( input_ty) ) {
446
457
let span = if let Some ( hir:: Node :: TraitItem ( hir:: TraitItem {
@@ -452,20 +463,20 @@ fn virtual_call_violation_for_method<'tcx>(
452
463
} else {
453
464
None
454
465
} ;
455
- return Some ( MethodViolationCode :: ReferencesSelfInput ( span) ) ;
466
+ errors . push ( MethodViolationCode :: ReferencesSelfInput ( span) ) ;
456
467
}
457
468
}
458
469
if contains_illegal_self_type_reference ( tcx, trait_def_id, sig. output ( ) ) {
459
- return Some ( MethodViolationCode :: ReferencesSelfOutput ) ;
470
+ errors . push ( MethodViolationCode :: ReferencesSelfOutput ) ;
460
471
}
461
472
if let Some ( code) = contains_illegal_impl_trait_in_trait ( tcx, method. def_id , sig. output ( ) ) {
462
- return Some ( code) ;
473
+ errors . push ( code) ;
463
474
}
464
475
465
476
// We can't monomorphize things like `fn foo<A>(...)`.
466
477
let own_counts = tcx. generics_of ( method. def_id ) . own_counts ( ) ;
467
- if own_counts. types + own_counts. consts != 0 {
468
- return Some ( MethodViolationCode :: Generic ) ;
478
+ if own_counts. types > 0 || own_counts. consts > 0 {
479
+ errors . push ( MethodViolationCode :: Generic ) ;
469
480
}
470
481
471
482
let receiver_ty = tcx. liberate_late_bound_regions ( method. def_id , sig. input ( 0 ) ) ;
@@ -485,7 +496,7 @@ fn virtual_call_violation_for_method<'tcx>(
485
496
} else {
486
497
None
487
498
} ;
488
- return Some ( MethodViolationCode :: UndispatchableReceiver ( span) ) ;
499
+ errors . push ( MethodViolationCode :: UndispatchableReceiver ( span) ) ;
489
500
} else {
490
501
// Do sanity check to make sure the receiver actually has the layout of a pointer.
491
502
@@ -593,10 +604,10 @@ fn virtual_call_violation_for_method<'tcx>(
593
604
594
605
contains_illegal_self_type_reference ( tcx, trait_def_id, pred)
595
606
} ) {
596
- return Some ( MethodViolationCode :: WhereClauseReferencesSelf ) ;
607
+ errors . push ( MethodViolationCode :: WhereClauseReferencesSelf ) ;
597
608
}
598
609
599
- None
610
+ errors
600
611
}
601
612
602
613
/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
@@ -709,7 +720,6 @@ fn object_ty_for_trait<'tcx>(
709
720
// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
710
721
// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
711
722
// `self: Wrapper<Self>`.
712
- #[ allow( dead_code) ]
713
723
fn receiver_is_dispatchable < ' tcx > (
714
724
tcx : TyCtxt < ' tcx > ,
715
725
method : ty:: AssocItem ,
0 commit comments