@@ -20,25 +20,21 @@ mod select;
20
20
mod specialize;
21
21
mod structural_match;
22
22
mod util;
23
+ mod vtable;
23
24
pub mod wf;
24
25
25
- use crate :: errors:: DumpVTableEntries ;
26
26
use crate :: infer:: outlives:: env:: OutlivesEnvironment ;
27
27
use crate :: infer:: { InferCtxt , TyCtxtInferExt } ;
28
28
use crate :: traits:: error_reporting:: TypeErrCtxtExt as _;
29
29
use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
30
30
use rustc_errors:: ErrorGuaranteed ;
31
31
use rustc_hir as hir;
32
32
use rustc_hir:: def_id:: DefId ;
33
- use rustc_hir:: lang_items:: LangItem ;
34
33
use rustc_middle:: ty:: fold:: TypeFoldable ;
35
34
use rustc_middle:: ty:: visit:: TypeVisitable ;
36
- use rustc_middle:: ty:: {
37
- self , DefIdTree , GenericParamDefKind , ToPredicate , Ty , TyCtxt , TypeSuperVisitable , VtblEntry ,
38
- } ;
35
+ use rustc_middle:: ty:: { self , DefIdTree , ToPredicate , Ty , TyCtxt , TypeSuperVisitable } ;
39
36
use rustc_middle:: ty:: { InternalSubsts , SubstsRef } ;
40
- use rustc_span:: { sym, Span } ;
41
- use smallvec:: SmallVec ;
37
+ use rustc_span:: Span ;
42
38
43
39
use std:: fmt:: Debug ;
44
40
use std:: ops:: ControlFlow ;
@@ -567,368 +563,13 @@ fn is_impossible_method<'tcx>(
567
563
false
568
564
}
569
565
570
- #[ derive( Clone , Debug ) ]
571
- enum VtblSegment < ' tcx > {
572
- MetadataDSA ,
573
- TraitOwnEntries { trait_ref : ty:: PolyTraitRef < ' tcx > , emit_vptr : bool } ,
574
- }
575
-
576
- /// Prepare the segments for a vtable
577
- fn prepare_vtable_segments < ' tcx , T > (
578
- tcx : TyCtxt < ' tcx > ,
579
- trait_ref : ty:: PolyTraitRef < ' tcx > ,
580
- mut segment_visitor : impl FnMut ( VtblSegment < ' tcx > ) -> ControlFlow < T > ,
581
- ) -> Option < T > {
582
- // The following constraints holds for the final arrangement.
583
- // 1. The whole virtual table of the first direct super trait is included as the
584
- // the prefix. If this trait doesn't have any super traits, then this step
585
- // consists of the dsa metadata.
586
- // 2. Then comes the proper pointer metadata(vptr) and all own methods for all
587
- // other super traits except those already included as part of the first
588
- // direct super trait virtual table.
589
- // 3. finally, the own methods of this trait.
590
-
591
- // This has the advantage that trait upcasting to the first direct super trait on each level
592
- // is zero cost, and to another trait includes only replacing the pointer with one level indirection,
593
- // while not using too much extra memory.
594
-
595
- // For a single inheritance relationship like this,
596
- // D --> C --> B --> A
597
- // The resulting vtable will consists of these segments:
598
- // DSA, A, B, C, D
599
-
600
- // For a multiple inheritance relationship like this,
601
- // D --> C --> A
602
- // \-> B
603
- // The resulting vtable will consists of these segments:
604
- // DSA, A, B, B-vptr, C, D
605
-
606
- // For a diamond inheritance relationship like this,
607
- // D --> B --> A
608
- // \-> C -/
609
- // The resulting vtable will consists of these segments:
610
- // DSA, A, B, C, C-vptr, D
611
-
612
- // For a more complex inheritance relationship like this:
613
- // O --> G --> C --> A
614
- // \ \ \-> B
615
- // | |-> F --> D
616
- // | \-> E
617
- // |-> N --> J --> H
618
- // \ \-> I
619
- // |-> M --> K
620
- // \-> L
621
- // The resulting vtable will consists of these segments:
622
- // DSA, A, B, B-vptr, C, D, D-vptr, E, E-vptr, F, F-vptr, G,
623
- // H, H-vptr, I, I-vptr, J, J-vptr, K, K-vptr, L, L-vptr, M, M-vptr,
624
- // N, N-vptr, O
625
-
626
- // emit dsa segment first.
627
- if let ControlFlow :: Break ( v) = ( segment_visitor) ( VtblSegment :: MetadataDSA ) {
628
- return Some ( v) ;
629
- }
630
-
631
- let mut emit_vptr_on_new_entry = false ;
632
- let mut visited = util:: PredicateSet :: new ( tcx) ;
633
- let predicate = trait_ref. without_const ( ) . to_predicate ( tcx) ;
634
- let mut stack: SmallVec < [ ( ty:: PolyTraitRef < ' tcx > , _ , _ ) ; 5 ] > =
635
- smallvec ! [ ( trait_ref, emit_vptr_on_new_entry, None ) ] ;
636
- visited. insert ( predicate) ;
637
-
638
- // the main traversal loop:
639
- // basically we want to cut the inheritance directed graph into a few non-overlapping slices of nodes
640
- // that each node is emitted after all its descendents have been emitted.
641
- // so we convert the directed graph into a tree by skipping all previously visited nodes using a visited set.
642
- // this is done on the fly.
643
- // Each loop run emits a slice - it starts by find a "childless" unvisited node, backtracking upwards, and it
644
- // stops after it finds a node that has a next-sibling node.
645
- // This next-sibling node will used as the starting point of next slice.
646
-
647
- // Example:
648
- // For a diamond inheritance relationship like this,
649
- // D#1 --> B#0 --> A#0
650
- // \-> C#1 -/
651
-
652
- // Starting point 0 stack [D]
653
- // Loop run #0: Stack after diving in is [D B A], A is "childless"
654
- // after this point, all newly visited nodes won't have a vtable that equals to a prefix of this one.
655
- // Loop run #0: Emitting the slice [B A] (in reverse order), B has a next-sibling node, so this slice stops here.
656
- // Loop run #0: Stack after exiting out is [D C], C is the next starting point.
657
- // Loop run #1: Stack after diving in is [D C], C is "childless", since its child A is skipped(already emitted).
658
- // Loop run #1: Emitting the slice [D C] (in reverse order). No one has a next-sibling node.
659
- // Loop run #1: Stack after exiting out is []. Now the function exits.
660
-
661
- loop {
662
- // dive deeper into the stack, recording the path
663
- ' diving_in: loop {
664
- if let Some ( ( inner_most_trait_ref, _, _) ) = stack. last ( ) {
665
- let inner_most_trait_ref = * inner_most_trait_ref;
666
- let mut direct_super_traits_iter = tcx
667
- . super_predicates_of ( inner_most_trait_ref. def_id ( ) )
668
- . predicates
669
- . into_iter ( )
670
- . filter_map ( move |( pred, _) | {
671
- pred. subst_supertrait ( tcx, & inner_most_trait_ref) . to_opt_poly_trait_pred ( )
672
- } ) ;
673
-
674
- ' diving_in_skip_visited_traits: loop {
675
- if let Some ( next_super_trait) = direct_super_traits_iter. next ( ) {
676
- if visited. insert ( next_super_trait. to_predicate ( tcx) ) {
677
- // We're throwing away potential constness of super traits here.
678
- // FIXME: handle ~const super traits
679
- let next_super_trait = next_super_trait. map_bound ( |t| t. trait_ref ) ;
680
- stack. push ( (
681
- next_super_trait,
682
- emit_vptr_on_new_entry,
683
- Some ( direct_super_traits_iter) ,
684
- ) ) ;
685
- break ' diving_in_skip_visited_traits;
686
- } else {
687
- continue ' diving_in_skip_visited_traits;
688
- }
689
- } else {
690
- break ' diving_in;
691
- }
692
- }
693
- }
694
- }
695
-
696
- // Other than the left-most path, vptr should be emitted for each trait.
697
- emit_vptr_on_new_entry = true ;
698
-
699
- // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
700
- ' exiting_out: loop {
701
- if let Some ( ( inner_most_trait_ref, emit_vptr, siblings_opt) ) = stack. last_mut ( ) {
702
- if let ControlFlow :: Break ( v) = ( segment_visitor) ( VtblSegment :: TraitOwnEntries {
703
- trait_ref : * inner_most_trait_ref,
704
- emit_vptr : * emit_vptr,
705
- } ) {
706
- return Some ( v) ;
707
- }
708
-
709
- ' exiting_out_skip_visited_traits: loop {
710
- if let Some ( siblings) = siblings_opt {
711
- if let Some ( next_inner_most_trait_ref) = siblings. next ( ) {
712
- if visited. insert ( next_inner_most_trait_ref. to_predicate ( tcx) ) {
713
- // We're throwing away potential constness of super traits here.
714
- // FIXME: handle ~const super traits
715
- let next_inner_most_trait_ref =
716
- next_inner_most_trait_ref. map_bound ( |t| t. trait_ref ) ;
717
- * inner_most_trait_ref = next_inner_most_trait_ref;
718
- * emit_vptr = emit_vptr_on_new_entry;
719
- break ' exiting_out;
720
- } else {
721
- continue ' exiting_out_skip_visited_traits;
722
- }
723
- }
724
- }
725
- stack. pop ( ) ;
726
- continue ' exiting_out;
727
- }
728
- }
729
- // all done
730
- return None ;
731
- }
732
- }
733
- }
734
-
735
- fn dump_vtable_entries < ' tcx > (
736
- tcx : TyCtxt < ' tcx > ,
737
- sp : Span ,
738
- trait_ref : ty:: PolyTraitRef < ' tcx > ,
739
- entries : & [ VtblEntry < ' tcx > ] ,
740
- ) {
741
- tcx. sess . emit_err ( DumpVTableEntries {
742
- span : sp,
743
- trait_ref,
744
- entries : format ! ( "{:#?}" , entries) ,
745
- } ) ;
746
- }
747
-
748
- fn own_existential_vtable_entries < ' tcx > ( tcx : TyCtxt < ' tcx > , trait_def_id : DefId ) -> & ' tcx [ DefId ] {
749
- let trait_methods = tcx
750
- . associated_items ( trait_def_id)
751
- . in_definition_order ( )
752
- . filter ( |item| item. kind == ty:: AssocKind :: Fn ) ;
753
- // Now list each method's DefId (for within its trait).
754
- let own_entries = trait_methods. filter_map ( move |trait_method| {
755
- debug ! ( "own_existential_vtable_entry: trait_method={:?}" , trait_method) ;
756
- let def_id = trait_method. def_id ;
757
-
758
- // Some methods cannot be called on an object; skip those.
759
- if !is_vtable_safe_method ( tcx, trait_def_id, & trait_method) {
760
- debug ! ( "own_existential_vtable_entry: not vtable safe" ) ;
761
- return None ;
762
- }
763
-
764
- Some ( def_id)
765
- } ) ;
766
-
767
- tcx. arena . alloc_from_iter ( own_entries. into_iter ( ) )
768
- }
769
-
770
- /// Given a trait `trait_ref`, iterates the vtable entries
771
- /// that come from `trait_ref`, including its supertraits.
772
- fn vtable_entries < ' tcx > (
773
- tcx : TyCtxt < ' tcx > ,
774
- trait_ref : ty:: PolyTraitRef < ' tcx > ,
775
- ) -> & ' tcx [ VtblEntry < ' tcx > ] {
776
- debug ! ( "vtable_entries({:?})" , trait_ref) ;
777
-
778
- let mut entries = vec ! [ ] ;
779
-
780
- let vtable_segment_callback = |segment| -> ControlFlow < ( ) > {
781
- match segment {
782
- VtblSegment :: MetadataDSA => {
783
- entries. extend ( TyCtxt :: COMMON_VTABLE_ENTRIES ) ;
784
- }
785
- VtblSegment :: TraitOwnEntries { trait_ref, emit_vptr } => {
786
- let existential_trait_ref = trait_ref
787
- . map_bound ( |trait_ref| ty:: ExistentialTraitRef :: erase_self_ty ( tcx, trait_ref) ) ;
788
-
789
- // Lookup the shape of vtable for the trait.
790
- let own_existential_entries =
791
- tcx. own_existential_vtable_entries ( existential_trait_ref. def_id ( ) ) ;
792
-
793
- let own_entries = own_existential_entries. iter ( ) . copied ( ) . map ( |def_id| {
794
- debug ! ( "vtable_entries: trait_method={:?}" , def_id) ;
795
-
796
- // The method may have some early-bound lifetimes; add regions for those.
797
- let substs = trait_ref. map_bound ( |trait_ref| {
798
- InternalSubsts :: for_item ( tcx, def_id, |param, _| match param. kind {
799
- GenericParamDefKind :: Lifetime => tcx. lifetimes . re_erased . into ( ) ,
800
- GenericParamDefKind :: Type { .. }
801
- | GenericParamDefKind :: Const { .. } => {
802
- trait_ref. substs [ param. index as usize ]
803
- }
804
- } )
805
- } ) ;
806
-
807
- // The trait type may have higher-ranked lifetimes in it;
808
- // erase them if they appear, so that we get the type
809
- // at some particular call site.
810
- let substs = tcx
811
- . normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , substs) ;
812
-
813
- // It's possible that the method relies on where-clauses that
814
- // do not hold for this particular set of type parameters.
815
- // Note that this method could then never be called, so we
816
- // do not want to try and codegen it, in that case (see #23435).
817
- let predicates = tcx. predicates_of ( def_id) . instantiate_own ( tcx, substs) ;
818
- if impossible_predicates ( tcx, predicates. predicates ) {
819
- debug ! ( "vtable_entries: predicates do not hold" ) ;
820
- return VtblEntry :: Vacant ;
821
- }
822
-
823
- let instance = ty:: Instance :: resolve_for_vtable (
824
- tcx,
825
- ty:: ParamEnv :: reveal_all ( ) ,
826
- def_id,
827
- substs,
828
- )
829
- . expect ( "resolution failed during building vtable representation" ) ;
830
- VtblEntry :: Method ( instance)
831
- } ) ;
832
-
833
- entries. extend ( own_entries) ;
834
-
835
- if emit_vptr {
836
- entries. push ( VtblEntry :: TraitVPtr ( trait_ref) ) ;
837
- }
838
- }
839
- }
840
-
841
- ControlFlow :: Continue ( ( ) )
842
- } ;
843
-
844
- let _ = prepare_vtable_segments ( tcx, trait_ref, vtable_segment_callback) ;
845
-
846
- if tcx. has_attr ( trait_ref. def_id ( ) , sym:: rustc_dump_vtable) {
847
- let sp = tcx. def_span ( trait_ref. def_id ( ) ) ;
848
- dump_vtable_entries ( tcx, sp, trait_ref, & entries) ;
849
- }
850
-
851
- tcx. arena . alloc_from_iter ( entries. into_iter ( ) )
852
- }
853
-
854
- /// Find slot base for trait methods within vtable entries of another trait
855
- fn vtable_trait_first_method_offset < ' tcx > (
856
- tcx : TyCtxt < ' tcx > ,
857
- key : (
858
- ty:: PolyTraitRef < ' tcx > , // trait_to_be_found
859
- ty:: PolyTraitRef < ' tcx > , // trait_owning_vtable
860
- ) ,
861
- ) -> usize {
862
- let ( trait_to_be_found, trait_owning_vtable) = key;
863
-
864
- // #90177
865
- let trait_to_be_found_erased = tcx. erase_regions ( trait_to_be_found) ;
866
-
867
- let vtable_segment_callback = {
868
- let mut vtable_base = 0 ;
869
-
870
- move |segment| {
871
- match segment {
872
- VtblSegment :: MetadataDSA => {
873
- vtable_base += TyCtxt :: COMMON_VTABLE_ENTRIES . len ( ) ;
874
- }
875
- VtblSegment :: TraitOwnEntries { trait_ref, emit_vptr } => {
876
- if tcx. erase_regions ( trait_ref) == trait_to_be_found_erased {
877
- return ControlFlow :: Break ( vtable_base) ;
878
- }
879
- vtable_base += util:: count_own_vtable_entries ( tcx, trait_ref) ;
880
- if emit_vptr {
881
- vtable_base += 1 ;
882
- }
883
- }
884
- }
885
- ControlFlow :: Continue ( ( ) )
886
- }
887
- } ;
888
-
889
- if let Some ( vtable_base) =
890
- prepare_vtable_segments ( tcx, trait_owning_vtable, vtable_segment_callback)
891
- {
892
- vtable_base
893
- } else {
894
- bug ! ( "Failed to find info for expected trait in vtable" ) ;
895
- }
896
- }
897
-
898
- /// Find slot offset for trait vptr within vtable entries of another trait
899
- pub fn vtable_trait_upcasting_coercion_new_vptr_slot < ' tcx > (
900
- tcx : TyCtxt < ' tcx > ,
901
- key : (
902
- Ty < ' tcx > , // trait object type whose trait owning vtable
903
- Ty < ' tcx > , // trait object for supertrait
904
- ) ,
905
- ) -> Option < usize > {
906
- let ( source, target) = key;
907
- assert ! ( matches!( & source. kind( ) , & ty:: Dynamic ( ..) ) && !source. needs_infer( ) ) ;
908
- assert ! ( matches!( & target. kind( ) , & ty:: Dynamic ( ..) ) && !target. needs_infer( ) ) ;
909
-
910
- // this has been typecked-before, so diagnostics is not really needed.
911
- let unsize_trait_did = tcx. require_lang_item ( LangItem :: Unsize , None ) ;
912
-
913
- let trait_ref = tcx. mk_trait_ref ( unsize_trait_did, [ source, target] ) ;
914
-
915
- match tcx. codegen_select_candidate ( ( ty:: ParamEnv :: reveal_all ( ) , ty:: Binder :: dummy ( trait_ref) ) ) {
916
- Ok ( ImplSource :: TraitUpcasting ( implsrc_traitcasting) ) => {
917
- implsrc_traitcasting. vtable_vptr_slot
918
- }
919
- otherwise => bug ! ( "expected TraitUpcasting candidate, got {otherwise:?}" ) ,
920
- }
921
- }
922
-
923
566
pub fn provide ( providers : & mut ty:: query:: Providers ) {
924
567
object_safety:: provide ( providers) ;
568
+ vtable:: provide ( providers) ;
925
569
* providers = ty:: query:: Providers {
926
570
specialization_graph_of : specialize:: specialization_graph_provider,
927
571
specializes : specialize:: specializes,
928
572
codegen_select_candidate : codegen:: codegen_select_candidate,
929
- own_existential_vtable_entries,
930
- vtable_entries,
931
- vtable_trait_upcasting_coercion_new_vptr_slot,
932
573
subst_and_check_impossible_predicates,
933
574
is_impossible_method,
934
575
..* providers
0 commit comments