Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e5a2a6a

Browse files
committedMay 19, 2025·
Auto merge of rust-lang#141243 - Zalathar:rollup-x5xt80l, r=Zalathar
Rollup of 5 pull requests Successful merges: - rust-lang#140847 (coverage: Detect unused local file IDs to avoid an LLVM assertion) - rust-lang#141117 (opt-dist: fix deprecated BOLT -icf=1 option) - rust-lang#141225 (more ice tests) - rust-lang#141239 (dladdr cannot leave dli_fname to be null) - rust-lang#141242 (in `tests/ui/asm/aarch64/parse-error.rs`, only test cases specific to that target) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 7068c8b + 315874c commit e5a2a6a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+563
-540
lines changed
 

‎compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,20 @@ pub(crate) struct Regions {
155155
impl Regions {
156156
/// Returns true if none of this structure's tables contain any regions.
157157
pub(crate) fn has_no_regions(&self) -> bool {
158+
// Every region has a span, so if there are no spans then there are no regions.
159+
self.all_cov_spans().next().is_none()
160+
}
161+
162+
pub(crate) fn all_cov_spans(&self) -> impl Iterator<Item = &CoverageSpan> {
163+
macro_rules! iter_cov_spans {
164+
( $( $regions:expr ),* $(,)? ) => {
165+
std::iter::empty()
166+
$(
167+
.chain( $regions.iter().map(|region| &region.cov_span) )
168+
)*
169+
}
170+
}
171+
158172
let Self {
159173
code_regions,
160174
expansion_regions,
@@ -163,11 +177,13 @@ impl Regions {
163177
mcdc_decision_regions,
164178
} = self;
165179

166-
code_regions.is_empty()
167-
&& expansion_regions.is_empty()
168-
&& branch_regions.is_empty()
169-
&& mcdc_branch_regions.is_empty()
170-
&& mcdc_decision_regions.is_empty()
180+
iter_cov_spans!(
181+
code_regions,
182+
expansion_regions,
183+
branch_regions,
184+
mcdc_branch_regions,
185+
mcdc_decision_regions,
186+
)
171187
}
172188
}
173189

‎compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_abi::Align;
1111
use rustc_codegen_ssa::traits::{
1212
BaseTypeCodegenMethods as _, ConstCodegenMethods, StaticCodegenMethods,
1313
};
14+
use rustc_index::IndexVec;
1415
use rustc_middle::mir::coverage::{
1516
BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping,
1617
MappingKind, Op,
@@ -104,6 +105,16 @@ fn fill_region_tables<'tcx>(
104105
ids_info: &'tcx CoverageIdsInfo,
105106
covfun: &mut CovfunRecord<'tcx>,
106107
) {
108+
// If this function is unused, replace all counters with zero.
109+
let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
110+
let term = if covfun.is_used {
111+
ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
112+
} else {
113+
CovTerm::Zero
114+
};
115+
ffi::Counter::from_term(term)
116+
};
117+
107118
// Currently a function's mappings must all be in the same file, so use the
108119
// first mapping's span to determine the file.
109120
let source_map = tcx.sess.source_map();
@@ -115,6 +126,12 @@ fn fill_region_tables<'tcx>(
115126

116127
let local_file_id = covfun.virtual_file_mapping.push_file(&source_file);
117128

129+
// If this testing flag is set, add an extra unused entry to the local
130+
// file table, to help test the code for detecting unused file IDs.
131+
if tcx.sess.coverage_inject_unused_local_file() {
132+
covfun.virtual_file_mapping.push_file(&source_file);
133+
}
134+
118135
// In rare cases, _all_ of a function's spans are discarded, and coverage
119136
// codegen needs to handle that gracefully to avoid #133606.
120137
// It's hard for tests to trigger this organically, so instead we set
@@ -135,16 +152,6 @@ fn fill_region_tables<'tcx>(
135152
// For each counter/region pair in this function+file, convert it to a
136153
// form suitable for FFI.
137154
for &Mapping { ref kind, span } in &fn_cov_info.mappings {
138-
// If this function is unused, replace all counters with zero.
139-
let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
140-
let term = if covfun.is_used {
141-
ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
142-
} else {
143-
CovTerm::Zero
144-
};
145-
ffi::Counter::from_term(term)
146-
};
147-
148155
let Some(coords) = make_coords(span) else { continue };
149156
let cov_span = coords.make_coverage_span(local_file_id);
150157

@@ -177,6 +184,19 @@ fn fill_region_tables<'tcx>(
177184
}
178185
}
179186

187+
/// LLVM requires all local file IDs to have at least one mapping region.
188+
/// If that's not the case, skip this function, to avoid an assertion failure
189+
/// (or worse) in LLVM.
190+
fn check_local_file_table(covfun: &CovfunRecord<'_>) -> bool {
191+
let mut local_file_id_seen =
192+
IndexVec::<u32, _>::from_elem_n(false, covfun.virtual_file_mapping.local_file_table.len());
193+
for cov_span in covfun.regions.all_cov_spans() {
194+
local_file_id_seen[cov_span.file_id] = true;
195+
}
196+
197+
local_file_id_seen.into_iter().all(|seen| seen)
198+
}
199+
180200
/// Generates the contents of the covfun record for this function, which
181201
/// contains the function's coverage mapping data. The record is then stored
182202
/// as a global variable in the `__llvm_covfun` section.
@@ -185,6 +205,10 @@ pub(crate) fn generate_covfun_record<'tcx>(
185205
global_file_table: &GlobalFileTable,
186206
covfun: &CovfunRecord<'tcx>,
187207
) {
208+
if !check_local_file_table(covfun) {
209+
return;
210+
}
211+
188212
let &CovfunRecord {
189213
mangled_function_name,
190214
source_hash,

0 commit comments

Comments
 (0)
This repository has been archived.