diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 388dd7ce81b14..085935b94df50 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -548,6 +548,15 @@ pub(crate) unsafe fn optimize( llvm::LLVMRustAddPass(fpm, find_pass("lint").unwrap()); continue; } + if pass_name == "insert-gcov-profiling" || pass_name == "instrprof" { + // Instrumentation must be inserted before optimization, + // otherwise LLVM may optimize some functions away which + // breaks llvm-cov. + // + // This mirrors what Clang does in lib/CodeGen/BackendUtil.cpp. + llvm::LLVMRustAddPass(mpm, find_pass(pass_name).unwrap()); + continue; + } if let Some(pass) = find_pass(pass_name) { extra_passes.push(pass); diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 0167655bee514..6c2468b9ffe0b 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -84,14 +84,7 @@ impl<'tcx> MonoItem<'tcx> { .debugging_opts .inline_in_all_cgus .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) - && !tcx.sess.link_dead_code() - && !tcx.sess.instrument_coverage(); - // Disabled for `-Z instrument-coverage` because some LLVM optimizations can sometimes - // break coverage results. A test that failed at certain optimization levels is now - // validated at that optimization level (via `compile-flags` directive): - // * `src/test/run-make-fulldeps/coverage/closure.rs` broke with `-C opt-level=2`, and - // also required disabling `internalize_symbols` in - // `rustc_mir/monomorphize/partitioning/mod.rs` + && !tcx.sess.link_dead_code(); match *self { MonoItem::Fn(ref instance) => { diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index 04f31ec3a33c7..dc2379fd92b83 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -196,13 +196,7 @@ pub fn partition<'tcx>( // Next we try to make as many symbols "internal" as possible, so LLVM has // more freedom to optimize. - if !tcx.sess.link_dead_code() && !tcx.sess.instrument_coverage() { - // Disabled for `-Z instrument-coverage` because some LLVM optimizations can sometimes - // break coverage results. Tests that failed at certain optimization levels are now - // validated at those optimization levels (via `compile-flags` directive); for example: - // * `src/test/run-make-fulldeps/coverage/async.rs` broke with `-C opt-level=1` - // * `src/test/run-make-fulldeps/coverage/closure.rs` broke with `-C opt-level=2`, and - // also required disabling `generate_gcu_internal_copies` in `rustc_middle/mir/mono.rs` + if !tcx.sess.link_dead_code() { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); partitioner.internalize_symbols(cx, &mut post_inlining); } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 631f2c7a69ad2..cb0eea1b7067c 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2889,17 +2889,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { .emit(); InlineAttr::None } else if list_contains_name(&items[..], sym::always) { - if tcx.sess.instrument_coverage() { - // Fixes Issue #82875. Forced inlining allows LLVM to discard functions - // marked with `#[inline(always)]`, which can break coverage reporting if - // that function was referenced from a coverage map. - // - // FIXME(#83429): Is there a better place, e.g., in codegen, to check and - // convert `Always` to `Hint`? - InlineAttr::Hint - } else { - InlineAttr::Always - } + InlineAttr::Always } else if list_contains_name(&items[..], sym::never) { InlineAttr::Never } else { diff --git a/src/test/run-make-fulldeps/coverage-llvmir/Makefile b/src/test/run-make-fulldeps/coverage-llvmir/Makefile index 86af7e41ae15b..7d9121ee2f834 100644 --- a/src/test/run-make-fulldeps/coverage-llvmir/Makefile +++ b/src/test/run-make-fulldeps/coverage-llvmir/Makefile @@ -17,7 +17,7 @@ else COMDAT_IF_SUPPORTED=, comdat endif -DEFINE_INTERNAL=define hidden +DEFINE_INTERNAL=define internal ifdef IS_WINDOWS LLVM_FILECHECK_OPTIONS=\ diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt index 6f28c08909387..7b38ffb87cba8 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt @@ -29,12 +29,12 @@ 18| 2| println!("BOOM times {}!!!", self.strength); 19| 2| } ------------------ - | as core::ops::drop::Drop>::drop: + | as core::ops::drop::Drop>::drop: | 17| 1| fn drop(&mut self) { | 18| 1| println!("BOOM times {}!!!", self.strength); | 19| 1| } ------------------ - | as core::ops::drop::Drop>::drop: + | as core::ops::drop::Drop>::drop: | 17| 1| fn drop(&mut self) { | 18| 1| println!("BOOM times {}!!!", self.strength); | 19| 1| } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index 380869d62a8b6..cdcbd8fca9482 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -36,12 +36,12 @@ 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); 23| 2|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::>: + | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | used_crate::used_only_from_this_lib_crate_generic_function::>: | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); | 23| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt index 0853dc9c014e5..cc98956e3073a 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt @@ -30,29 +30,12 @@ ^0 29| 1| use_this_lib_crate(); 30| 1|} - ------------------ - | used_inline_crate::used_inline_function: - | 20| 1|pub fn used_inline_function() { - | 21| | // Initialize test constants in a way that cannot be determined at compile time, to ensure - | 22| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - | 23| | // dependent conditions. - | 24| 1| let is_true = std::env::args().len() == 1; - | 25| 1| let mut countdown = 0; - | 26| 1| if is_true { - | 27| 1| countdown = 10; - | 28| 1| } - | ^0 - | 29| 1| use_this_lib_crate(); - | 30| 1|} - ------------------ - | Unexecuted instantiation: used_inline_crate::used_inline_function - ------------------ - 31| |// Expect for above function: - 32| |// - 33| |// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> - 34| |// - 35| |// With `#[inline(always)]` this function is instantiated twice, in both the library crate (which - 36| |// does not use it) and the `uses_inline_crate` binary (which does use/call it). + 31| | + 32| | + 33| | + 34| | + 35| | + 36| | 37| | 38| |#[inline(always)] 39| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { diff --git a/src/test/run-make-fulldeps/coverage/lib/used_inline_crate.rs b/src/test/run-make-fulldeps/coverage/lib/used_inline_crate.rs index f4c3dd46f7686..4a052756d4e27 100644 --- a/src/test/run-make-fulldeps/coverage/lib/used_inline_crate.rs +++ b/src/test/run-make-fulldeps/coverage/lib/used_inline_crate.rs @@ -28,12 +28,12 @@ pub fn used_inline_function() { } use_this_lib_crate(); } -// Expect for above function: -// -// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> -// -// With `#[inline(always)]` this function is instantiated twice, in both the library crate (which -// does not use it) and the `uses_inline_crate` binary (which does use/call it). + + + + + + #[inline(always)] pub fn used_only_from_bin_crate_generic_function(arg: T) {