@@ -24,6 +24,7 @@ use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_a
2424use  rustc_passes:: { self ,  hir_stats,  layout_test} ; 
2525use  rustc_plugin_impl as  plugin; 
2626use  rustc_resolve:: Resolver ; 
27+ use  rustc_session:: code_stats:: VTableSizeInfo ; 
2728use  rustc_session:: config:: { CrateType ,  Input ,  OutFileName ,  OutputFilenames ,  OutputType } ; 
2829use  rustc_session:: cstore:: { MetadataLoader ,  Untracked } ; 
2930use  rustc_session:: output:: filename_for_input; 
@@ -866,6 +867,92 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
866867 sess. time ( "check_lint_expectations" ,  || tcx. check_expectations ( None ) ) ; 
867868 } ) ; 
868869
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+ 
869956 Ok ( ( ) ) 
870957} 
871958
0 commit comments