@@ -107,6 +107,9 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
107107 . make_bcb_counters ( & self . basic_coverage_blocks , bcb_has_coverage_spans) ;
108108
109109 let mappings = self . create_mappings_and_inject_coverage_statements ( & coverage_spans) ;
110+ if mappings. is_empty ( ) {
111+ return ;
112+ }
110113
111114 self . mir_body . function_coverage_info = Some ( Box :: new ( FunctionCoverageInfo {
112115 function_source_hash : self . hir_info . function_source_hash ,
@@ -135,18 +138,24 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
135138
136139 // Process the counters and spans associated with BCB nodes.
137140 for ( bcb, counter_kind) in self . coverage_counters . bcb_node_counters ( ) {
138- let spans = coverage_spans. spans_for_bcb ( bcb) ;
139- let has_mappings = !spans. is_empty ( ) ;
140-
141141 // If this BCB has any coverage spans, add corresponding mappings to
142142 // the mappings table.
143- if has_mappings {
143+ let has_mappings = {
144144 let term = counter_kind. as_term ( ) ;
145- mappings. extend ( spans. iter ( ) . map ( |& span| {
146- let code_region = make_code_region ( source_map, file_name, span, body_span) ;
147- Mapping { code_region, term }
145+ let old_mappings_len = mappings. len ( ) ;
146+
147+ mappings. extend ( coverage_spans. spans_for_bcb ( bcb) . iter ( ) . filter_map ( |& span| {
148+ let Some ( code_region) =
149+ make_code_region ( source_map, file_name, span, body_span)
150+ else {
151+ debug ! ( ?span, "Couldn't convert span to code region" ) ;
152+ return None ;
153+ } ;
154+ Some ( Mapping { code_region, term } )
148155 } ) ) ;
149- }
156+
157+ mappings. len ( ) > old_mappings_len
158+ } ;
150159
151160 let do_inject = match counter_kind {
152161 // Counter-increment statements always need to be injected.
@@ -238,13 +247,19 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
238247 data. statements . insert ( 0 , statement) ;
239248}
240249
241- /// Convert the Span into its file name, start line and column, and end line and column
250+ /// Convert the Span into its file name, start line and column, and end line and column.
251+ ///
252+ /// Returns `None` if the conversion failed for some reason. There is no known example
253+ /// of code that would cause this to happen, but it's hard to rule out entirely
254+ /// (especially in the presence of complex macros or other expansions), and if it does
255+ /// happen then skipping a span or function is better than an ICE that the user might
256+ /// have no way to avoid.
242257fn make_code_region (
243258 source_map : & SourceMap ,
244259 file_name : Symbol ,
245260 span : Span ,
246261 body_span : Span ,
247- ) -> CodeRegion {
262+ ) -> Option < CodeRegion > {
248263 debug ! (
249264 "Called make_code_region(file_name={}, span={}, body_span={})" ,
250265 file_name,
@@ -266,13 +281,13 @@ fn make_code_region(
266281 start_line = source_map. doctest_offset_line ( & file. name , start_line) ;
267282 end_line = source_map. doctest_offset_line ( & file. name , end_line) ;
268283 }
269- CodeRegion {
284+ Some ( CodeRegion {
270285 file_name,
271286 start_line : start_line as u32 ,
272287 start_col : start_col as u32 ,
273288 end_line : end_line as u32 ,
274289 end_col : end_col as u32 ,
275- }
290+ } )
276291}
277292
278293fn is_eligible_for_coverage ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> bool {
0 commit comments