Skip to content

Commit 0859cec

Browse files
committed
Changes from review comments
1 parent 94a3454 commit 0859cec

File tree

3 files changed

+33
-26
lines changed

3 files changed

+33
-26
lines changed

Diff for: compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,26 @@ impl CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
7373
}
7474
}
7575

76+
/// Functions with MIR-based coverage are normally codegenned _only_ if
77+
/// called. LLVM coverage tools typically expect every function to be
78+
/// defined (even if unused), with at least one call to LLVM intrinsic
79+
/// `instrprof.increment`.
80+
///
81+
/// Codegen a small function that will never be called, with one counter
82+
/// that will never be incremented.
83+
///
84+
/// For used/called functions, the coverageinfo was already added to the
85+
/// `function_coverage_map` (keyed by function `Instance`) during codegen.
86+
/// But in this case, since the unused function was _not_ previously
87+
/// codegenned, collect the coverage `CodeRegion`s from the MIR and add
88+
/// them. The first `CodeRegion` is used to add a single counter, with the
89+
/// same counter ID used in the injected `instrprof.increment` intrinsic
90+
/// call. Since the function is never called, all other `CodeRegion`s can be
91+
/// added as `unreachable_region`s.
7692
fn define_unused_fn(&self, def_id: DefId) {
7793
let instance = declare_unused_fn(self, &def_id);
7894
codegen_unused_fn_and_counter(self, instance);
79-
add_function_coverage(self, instance, def_id);
95+
add_unused_function_coverage(self, instance, def_id);
8096
}
8197
}
8298

@@ -200,7 +216,7 @@ fn declare_unused_fn(cx: &CodegenCx<'ll, 'tcx>, def_id: &DefId) -> Instance<'tcx
200216
llvm::set_linkage(llfn, llvm::Linkage::WeakAnyLinkage);
201217
llvm::set_visibility(llfn, llvm::Visibility::Hidden);
202218

203-
cx.instances.borrow_mut().insert(instance, llfn);
219+
assert!(cx.instances.borrow_mut().insert(instance, llfn).is_none());
204220

205221
instance
206222
}
@@ -221,7 +237,11 @@ fn codegen_unused_fn_and_counter(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'
221237
bx.ret_void();
222238
}
223239

224-
fn add_function_coverage(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>, def_id: DefId) {
240+
fn add_unused_function_coverage(
241+
cx: &CodegenCx<'ll, 'tcx>,
242+
instance: Instance<'tcx>,
243+
def_id: DefId,
244+
) {
225245
let tcx = cx.tcx;
226246

227247
let mut function_coverage = FunctionCoverage::unused(tcx, instance);

Diff for: compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs

+4-15
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,11 @@ use rustc_middle::ty::Instance;
66
pub trait CoverageInfoMethods<'tcx>: BackendTypes {
77
fn coverageinfo_finalize(&self);
88

9-
/// Functions with MIR-based coverage are normally codegenned _only_ if
10-
/// called. LLVM coverage tools typically expect every function to be
11-
/// defined (even if unused), with at least one call to LLVM intrinsic
12-
/// `instrprof.increment`.
13-
///
149
/// Codegen a small function that will never be called, with one counter
15-
/// that will never be incremented.
16-
///
17-
/// For used/called functions, the coverageinfo was already added to the
18-
/// `function_coverage_map` (keyed by function `Instance`) during codegen.
19-
/// But in this case, since the unused function was _not_ previously
20-
/// codegenned, collect the coverage `CodeRegion`s from the MIR and add
21-
/// them. The first `CodeRegion` is used to add a single counter, with the
22-
/// same counter ID used in the injected `instrprof.increment` intrinsic
23-
/// call. Since the function is never called, all other `CodeRegion`s can be
24-
/// added as `unreachable_region`s.
10+
/// that will never be incremented, that gives LLVM coverage tools a
11+
/// function definition it needs in order to resolve coverage map references
12+
/// to unused functions. This is necessary so unused functions will appear
13+
/// as uncovered (coverage execution count `0`) in LLVM coverage reports.
2514
fn define_unused_fn(&self, def_id: DefId);
2615

2716
/// For LLVM codegen, returns a function-specific `Value` for a global

Diff for: compiler/rustc_typeck/src/collect.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -2876,14 +2876,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
28762876
InlineAttr::None
28772877
} else if list_contains_name(&items[..], sym::always) {
28782878
if tcx.sess.instrument_coverage() {
2879-
// Forced inlining will discard functions marked with `#[inline(always)]`.
2880-
// If `-Z instrument-coverage` is enabled, the generated coverage map may
2881-
// hold references to functions that no longer exist, causing errors in
2882-
// coverage reports. (Note, this fixes #82875. I added some tests that
2883-
// also include `#[inline(always)]` functions, used and unused, and within
2884-
// and across crates, but could not reproduce the reported error in the
2885-
// `rustc` test suite. I am able to reproduce the error, following the steps
2886-
// described in #82875, and this change does fix that issue.)
2879+
// Fixes Issue #82875. Forced inlining allows LLVM to discard functions
2880+
// marked with `#[inline(always)]`, which can break coverage reporting if
2881+
// that function was referenced from a coverage map.
2882+
//
2883+
// FIXME(#83429): Is there a better place, e.g., in codegen, to check and
2884+
// convert `Always` to `Hint`?
28872885
InlineAttr::Hint
28882886
} else {
28892887
InlineAttr::Always

0 commit comments

Comments
 (0)