@@ -20,25 +20,21 @@ mod select;
2020mod specialize;
2121mod structural_match;
2222mod util;
23+ mod vtable;
2324pub mod wf;
2425
25- use crate :: errors:: DumpVTableEntries ;
2626use crate :: infer:: outlives:: env:: OutlivesEnvironment ;
2727use crate :: infer:: { InferCtxt , TyCtxtInferExt } ;
2828use crate :: traits:: error_reporting:: TypeErrCtxtExt as _;
2929use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
3030use rustc_errors:: ErrorGuaranteed ;
3131use rustc_hir as hir;
3232use rustc_hir:: def_id:: DefId ;
33- use rustc_hir:: lang_items:: LangItem ;
3433use rustc_middle:: ty:: fold:: TypeFoldable ;
3534use 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 } ;
3936use rustc_middle:: ty:: { InternalSubsts , SubstsRef } ;
40- use rustc_span:: { sym, Span } ;
41- use smallvec:: SmallVec ;
37+ use rustc_span:: Span ;
4238
4339use std:: fmt:: Debug ;
4440use std:: ops:: ControlFlow ;
@@ -567,368 +563,13 @@ fn is_impossible_method<'tcx>(
567563 false
568564}
569565
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-
923566pub fn provide ( providers : & mut ty:: query:: Providers ) {
924567 object_safety:: provide ( providers) ;
568+ vtable:: provide ( providers) ;
925569 * providers = ty:: query:: Providers {
926570 specialization_graph_of : specialize:: specialization_graph_provider,
927571 specializes : specialize:: specializes,
928572 codegen_select_candidate : codegen:: codegen_select_candidate,
929- own_existential_vtable_entries,
930- vtable_entries,
931- vtable_trait_upcasting_coercion_new_vptr_slot,
932573 subst_and_check_impossible_predicates,
933574 is_impossible_method,
934575 ..* providers
0 commit comments