11use std:: iter;
22
3- use itertools:: Itertools as _ ;
3+ use itertools:: Itertools ;
44use rustc_abi:: Align ;
55use rustc_codegen_ssa:: traits:: {
66 BaseTypeCodegenMethods , ConstCodegenMethods , StaticCodegenMethods ,
77} ;
88use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
99use rustc_hir:: def_id:: { DefId , LocalDefId } ;
1010use rustc_index:: IndexVec ;
11+ use rustc_middle:: mir;
1112use rustc_middle:: ty:: { self , TyCtxt } ;
12- use rustc_middle:: { bug, mir} ;
1313use rustc_session:: RemapFileNameExt ;
1414use rustc_session:: config:: RemapPathScopeComponents ;
1515use rustc_span:: def_id:: DefIdSet ;
@@ -67,25 +67,21 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
6767 return ;
6868 }
6969
70- let all_file_names = function_coverage_map
71- . iter ( )
72- . map ( |( _, fn_cov) | fn_cov. function_coverage_info . body_span )
73- . map ( |span| span_file_name ( tcx, span) ) ;
74- let global_file_table = GlobalFileTable :: new ( all_file_names) ;
75-
76- // Encode all filenames referenced by coverage mappings in this CGU.
77- let filenames_buffer = global_file_table. make_filenames_buffer ( tcx) ;
78- // The `llvm-cov` tool uses this hash to associate each covfun record with
79- // its corresponding filenames table, since the final binary will typically
80- // contain multiple covmap records from different compilation units.
81- let filenames_hash = llvm_cov:: hash_bytes ( & filenames_buffer) ;
82-
83- let mut unused_function_names = Vec :: new ( ) ;
70+ // The order of entries in this global file table needs to be deterministic,
71+ // and ideally should also be independent of the details of stable-hashing,
72+ // because coverage tests snapshots (`.cov-map`) can observe the order and
73+ // would need to be re-blessed if it changes. As long as those requirements
74+ // are satisfied, the order can be arbitrary.
75+ let mut global_file_table = GlobalFileTable :: new ( ) ;
8476
8577 let covfun_records = function_coverage_map
8678 . into_iter ( )
79+ // Sort by symbol name, so that the global file table is built in an
80+ // order that doesn't depend on the stable-hash-based order in which
81+ // instances were visited during codegen.
82+ . sorted_by_cached_key ( |& ( instance, _) | tcx. symbol_name ( instance) . name )
8783 . filter_map ( |( instance, function_coverage) | {
88- prepare_covfun_record ( tcx, & global_file_table, instance, & function_coverage)
84+ prepare_covfun_record ( tcx, & mut global_file_table, instance, & function_coverage)
8985 } )
9086 . collect :: < Vec < _ > > ( ) ;
9187
@@ -98,6 +94,15 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
9894 return ;
9995 }
10096
97+ // Encode all filenames referenced by coverage mappings in this CGU.
98+ let filenames_buffer = global_file_table. make_filenames_buffer ( tcx) ;
99+ // The `llvm-cov` tool uses this hash to associate each covfun record with
100+ // its corresponding filenames table, since the final binary will typically
101+ // contain multiple covmap records from different compilation units.
102+ let filenames_hash = llvm_cov:: hash_bytes ( & filenames_buffer) ;
103+
104+ let mut unused_function_names = vec ! [ ] ;
105+
101106 for covfun in & covfun_records {
102107 unused_function_names. extend ( covfun. mangled_function_name_if_unused ( ) ) ;
103108
@@ -137,22 +142,13 @@ struct GlobalFileTable {
137142}
138143
139144impl GlobalFileTable {
140- fn new ( all_file_names : impl IntoIterator < Item = Symbol > ) -> Self {
141- // Collect all of the filenames into a set. Filenames usually come in
142- // contiguous runs, so we can dedup adjacent ones to save work.
143- let mut raw_file_table = all_file_names. into_iter ( ) . dedup ( ) . collect :: < FxIndexSet < Symbol > > ( ) ;
144-
145- // Sort the file table by its actual string values, not the arbitrary
146- // ordering of its symbols.
147- raw_file_table. sort_unstable_by ( |a, b| a. as_str ( ) . cmp ( b. as_str ( ) ) ) ;
148-
149- Self { raw_file_table }
145+ fn new ( ) -> Self {
146+ Self { raw_file_table : FxIndexSet :: default ( ) }
150147 }
151148
152- fn global_file_id_for_file_name ( & self , file_name : Symbol ) -> GlobalFileId {
153- let raw_id = self . raw_file_table . get_index_of ( & file_name) . unwrap_or_else ( || {
154- bug ! ( "file name not found in prepared global file table: {file_name}" ) ;
155- } ) ;
149+ fn global_file_id_for_file_name ( & mut self , file_name : Symbol ) -> GlobalFileId {
150+ // Ensure the given file has a table entry, and get its index.
151+ let ( raw_id, _) = self . raw_file_table . insert_full ( file_name) ;
156152 // The raw file table doesn't include an entry for the working dir
157153 // (which has ID 0), so add 1 to get the correct ID.
158154 GlobalFileId :: from_usize ( raw_id + 1 )
0 commit comments