@@ -24,6 +24,7 @@ use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_a
24
24
use rustc_passes:: { self , hir_stats, layout_test} ;
25
25
use rustc_plugin_impl as plugin;
26
26
use rustc_resolve:: Resolver ;
27
+ use rustc_session:: code_stats:: VTableSizeInfo ;
27
28
use rustc_session:: config:: { CrateType , Input , OutFileName , OutputFilenames , OutputType } ;
28
29
use rustc_session:: cstore:: { MetadataLoader , Untracked } ;
29
30
use rustc_session:: output:: filename_for_input;
@@ -866,6 +867,92 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
866
867
sess. time ( "check_lint_expectations" , || tcx. check_expectations ( None ) ) ;
867
868
} ) ;
868
869
870
+ if sess. opts . unstable_opts . print_vtable_sizes {
871
+ let traits = tcx. traits ( LOCAL_CRATE ) ;
872
+
873
+ for & tr in traits {
874
+ if !tcx. check_is_object_safe ( tr) {
875
+ continue ;
876
+ }
877
+
878
+ let name = ty:: print:: with_no_trimmed_paths!( tcx. def_path_str( tr) ) ;
879
+
880
+ let mut first_dsa = true ;
881
+
882
+ // Number of vtable entries, if we didn't have upcasting
883
+ let mut entries_ignoring_upcasting = 0 ;
884
+ // Number of vtable entries needed solely for upcasting
885
+ let mut entries_for_upcasting = 0 ;
886
+
887
+ let trait_ref = ty:: Binder :: dummy ( ty:: TraitRef :: identity ( tcx, tr) ) ;
888
+
889
+ // A slightly edited version of the code in `rustc_trait_selection::traits::vtable::vtable_entries`,
890
+ // that works without self type and just counts number of entries.
891
+ //
892
+ // Note that this is technically wrong, for traits which have associated types in supertraits:
893
+ //
894
+ // trait A: AsRef<Self::T> + AsRef<()> { type T; }
895
+ //
896
+ // Without self type we can't normalize `Self::T`, so we can't know if `AsRef<Self::T>` and
897
+ // `AsRef<()>` are the same trait, thus we assume that those are different, and potentially
898
+ // over-estimate how many vtable entries there are.
899
+ //
900
+ // Similarly this is wrong for traits that have methods with possibly-impossible bounds.
901
+ // For example:
902
+ //
903
+ // trait B<T> { fn f(&self) where T: Copy; }
904
+ //
905
+ // Here `dyn B<u8>` will have 4 entries, while `dyn B<String>` will only have 3.
906
+ // However, since we don't know `T`, we can't know if `T: Copy` holds or not,
907
+ // thus we lean on the bigger side and say it has 4 entries.
908
+ traits:: vtable:: prepare_vtable_segments ( tcx, trait_ref, |segment| {
909
+ match segment {
910
+ traits:: vtable:: VtblSegment :: MetadataDSA => {
911
+ // If this is the first dsa, it would be included either way,
912
+ // otherwise it's needed for upcasting
913
+ if std:: mem:: take ( & mut first_dsa) {
914
+ entries_ignoring_upcasting += 3 ;
915
+ } else {
916
+ entries_for_upcasting += 3 ;
917
+ }
918
+ }
919
+
920
+ traits:: vtable:: VtblSegment :: TraitOwnEntries { trait_ref, emit_vptr } => {
921
+ // Lookup the shape of vtable for the trait.
922
+ let own_existential_entries =
923
+ tcx. own_existential_vtable_entries ( trait_ref. def_id ( ) ) ;
924
+
925
+ // The original code here ignores the method if its predicates are impossible.
926
+ // We can't really do that as, for example, all not trivial bounds on generic
927
+ // parameters are impossible (since we don't know the parameters...),
928
+ // see the comment above.
929
+ entries_ignoring_upcasting += own_existential_entries. len ( ) ;
930
+
931
+ if emit_vptr {
932
+ entries_for_upcasting += 1 ;
933
+ }
934
+ }
935
+ }
936
+
937
+ std:: ops:: ControlFlow :: Continue :: < std:: convert:: Infallible > ( ( ) )
938
+ } ) ;
939
+
940
+ sess. code_stats . record_vtable_size (
941
+ tr,
942
+ & name,
943
+ VTableSizeInfo {
944
+ trait_name : name. clone ( ) ,
945
+ entries : entries_ignoring_upcasting + entries_for_upcasting,
946
+ entries_ignoring_upcasting,
947
+ entries_for_upcasting,
948
+ upcasting_cost_percent : entries_for_upcasting as f64
949
+ / entries_ignoring_upcasting as f64
950
+ * 100. ,
951
+ } ,
952
+ )
953
+ }
954
+ }
955
+
869
956
Ok ( ( ) )
870
957
}
871
958
0 commit comments