tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 86dc5318b583376277f455a1468b7f2508a6dbf1
parent 4e7e6856b97324421e332a86578697a8f0c78093
Author: Mike Hommey <mh+mozilla@glandium.org>
Date:   Tue,  9 Dec 2025 21:39:10 +0000

Bug 2002890 - Upgrade rustc-dev to the same version as the rust compiler we normally use. r=firefox-build-system-reviewers,sergesanspaille

We patch back support for -Zprofile because this compiler is also used
for some coverage builds that still use gcov-style coverage, and we're
not quite ready to switch to source-based coverage just yet.

Differential Revision: https://phabricator.services.mozilla.com/D275160

Diffstat:
Abuild/build-rust/Zprofile-1.92.patch | 381+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abuild/build-rust/Zprofile.patch | 381+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbuild/build-rust/rust-vendor-std.patch | 12++++--------
Mtaskcluster/kinds/fetch/toolchains.yml | 6+++---
Mtaskcluster/kinds/toolchain/rust.yml | 16++++++++++++----
5 files changed, 781 insertions(+), 15 deletions(-)

diff --git a/build/build-rust/Zprofile-1.92.patch b/build/build-rust/Zprofile-1.92.patch @@ -0,0 +1,381 @@ +This reverts +https://github.com/rust-lang/rust/commit/659e20fa7524f8fd217476daf5ecbbe366b2ae61 +and +https://github.com/rust-lang/rust/pull/131829 + +to restore support for -Zprofile (gcov-style coverage) that was removed from +rustc 1.84.0 + +diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs +index a25ce9e5a90..5fb2f7d7e7b 100644 +--- a/compiler/rustc_codegen_llvm/src/attributes.rs ++++ b/compiler/rustc_codegen_llvm/src/attributes.rs +@@ -269,6 +269,11 @@ fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<& + return None; + } + ++ // probestack doesn't play nice either with gcov profiling. ++ if tcx.sess.opts.unstable_opts.profile { ++ return None; ++ } ++ + let attr_value = match tcx.sess.target.stack_probes { + StackProbeType::None => return None, + // Request LLVM to generate the probes inline. If the given LLVM version does not support +diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs +index c0c01b80372..1f34e442fc2 100644 +--- a/compiler/rustc_codegen_llvm/src/back/write.rs ++++ b/compiler/rustc_codegen_llvm/src/back/write.rs +@@ -761,6 +761,7 @@ fn handle_offload<'ll>(cx: &'ll SimpleCx<'_>, old_fn: &llvm::Value) { + pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + config.instrument_coverage, + instr_profile_output_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), ++ config.instrument_gcov, + pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + config.debug_info_for_profiling, + llvm_selfprofiler, +diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +index 5535ebe6585..13ae40b3724 100644 +--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs ++++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +@@ -9,6 +9,7 @@ + use rustc_abi::{Align, Size}; + use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo}; + use rustc_codegen_ssa::traits::*; ++use rustc_fs_util::path_to_c_string; + use rustc_hir::def::{CtorKind, DefKind}; + use rustc_hir::def_id::{DefId, LOCAL_CRATE}; + use rustc_middle::bug; +@@ -988,8 +989,33 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( + debug_name_table_kind, + ); + ++ if tcx.sess.opts.unstable_opts.profile { ++ let default_gcda_path = &output_filenames.with_extension("gcda"); ++ let gcda_path = ++ tcx.sess.opts.unstable_opts.profile_emit.as_ref().unwrap_or(default_gcda_path); ++ ++ let gcov_cu_info = [ ++ path_to_mdstring(debug_context.llcontext, &output_filenames.with_extension("gcno")), ++ path_to_mdstring(debug_context.llcontext, gcda_path), ++ unit_metadata, ++ ]; ++ let gcov_metadata = llvm::LLVMMDNodeInContext2( ++ debug_context.llcontext, ++ gcov_cu_info.as_ptr(), ++ gcov_cu_info.len(), ++ ); ++ let val = llvm::LLVMMetadataAsValue(debug_context.llcontext, gcov_metadata); ++ ++ llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, c"llvm.gcov".as_ptr(), val); ++ } ++ + return unit_metadata; + }; ++ ++ fn path_to_mdstring<'ll>(llcx: &'ll llvm::Context, path: &Path) -> &'ll llvm::Metadata { ++ let path_str = path_to_c_string(path); ++ unsafe { llvm::LLVMMDStringInContext2(llcx, path_str.as_ptr(), path_str.as_bytes().len()) } ++ } + } + + /// Creates a `DW_TAG_member` entry inside the DIE represented by the given `type_di_node`. +diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +index c2c55ee2b64..f09c904d421 100644 +--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs ++++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +@@ -54,6 +54,7 @@ + + /// A context object for maintaining all state needed by the debuginfo module. + pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> { ++ llcontext: &'ll llvm::Context, + llmod: &'ll llvm::Module, + builder: DIBuilderBox<'ll>, + created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>, +@@ -69,7 +70,9 @@ pub(crate) fn new(llmod: &'ll llvm::Module) -> Self { + debug!("CodegenUnitDebugContext::new"); + let builder = DIBuilderBox::new(llmod); + // DIBuilder inherits context from the module, so we'd better use the same one ++ let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; + CodegenUnitDebugContext { ++ llcontext, + llmod, + builder, + created_files: Default::default(), +diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +index 53b9a2bda89..b6841a93684 100644 +--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs ++++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +@@ -933,6 +933,7 @@ pub(crate) fn LLVMModuleCreateWithNameInContext( + ModuleID: *const c_char, + C: &Context, + ) -> &Module; ++ pub(crate) fn LLVMGetModuleContext(M: &Module) -> &Context; + pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module; + + /// Data layout. See Module::getDataLayout. +@@ -2419,6 +2420,7 @@ pub(crate) fn LLVMRustOptimize<'a>( + PGOUsePath: *const c_char, + InstrumentCoverage: bool, + InstrProfileOutput: *const c_char, ++ InstrumentGCOV: bool, + PGOSampleUsePath: *const c_char, + DebugInfoForProfiling: bool, + llvm_selfprofiler: *mut c_void, +diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs +index 3e36bd8552b..e64a0110a08 100644 +--- a/compiler/rustc_codegen_ssa/src/back/write.rs ++++ b/compiler/rustc_codegen_ssa/src/back/write.rs +@@ -84,6 +84,7 @@ pub struct ModuleConfig { + pub pgo_sample_use: Option<PathBuf>, + pub debug_info_for_profiling: bool, + pub instrument_coverage: bool, ++ pub instrument_gcov: bool, + + pub sanitizer: SanitizerSet, + pub sanitizer_recover: SanitizerSet, +@@ -116,7 +117,12 @@ pub struct ModuleConfig { + } + + impl ModuleConfig { +- fn new(kind: ModuleKind, tcx: TyCtxt<'_>, no_builtins: bool) -> ModuleConfig { ++ fn new( ++ kind: ModuleKind, ++ tcx: TyCtxt<'_>, ++ no_builtins: bool, ++ is_compiler_builtins: bool, ++ ) -> ModuleConfig { + // If it's a regular module, use `$regular`, otherwise use `$other`. + // `$regular` and `$other` are evaluated lazily. + macro_rules! if_regular { +@@ -175,6 +181,13 @@ macro_rules! if_regular { + pgo_sample_use: if_regular!(sess.opts.unstable_opts.profile_sample_use.clone(), None), + debug_info_for_profiling: sess.opts.unstable_opts.debug_info_for_profiling, + instrument_coverage: if_regular!(sess.instrument_coverage(), false), ++ instrument_gcov: if_regular!( ++ // compiler_builtins overrides the codegen-units settings, ++ // which is incompatible with -Zprofile which requires that ++ // only a single codegen unit is used per crate. ++ sess.opts.unstable_opts.profile && !is_compiler_builtins, ++ false ++ ), + + sanitizer: if_regular!(sess.sanitizers(), SanitizerSet::empty()), + sanitizer_dataflow_abilist: if_regular!( +@@ -436,11 +449,14 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( + + let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID); + let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); ++ let is_compiler_builtins = attr::contains_name(crate_attrs, sym::compiler_builtins); + + let crate_info = CrateInfo::new(tcx, target_cpu); + +- let regular_config = ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins); +- let allocator_config = ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins); ++ let regular_config = ++ ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins, is_compiler_builtins); ++ let allocator_config = ++ ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins, is_compiler_builtins); + + let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); + let (codegen_worker_send, codegen_worker_receive) = channel(); +diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs +index 8bf9f8420c0..e09bdccb42a 100644 +--- a/compiler/rustc_interface/src/tests.rs ++++ b/compiler/rustc_interface/src/tests.rs +@@ -852,6 +852,8 @@ macro_rules! tracked { + tracked!(plt, Some(true)); + tracked!(polonius, Polonius::Legacy); + tracked!(precise_enum_drop_elaboration, false); ++ tracked!(profile, true); ++ tracked!(profile_emit, Some(PathBuf::from("abc"))); + tracked!(profile_sample_use, Some(PathBuf::from("abc"))); + tracked!(profiler_runtime, "abc".to_string()); + tracked!(reg_struct_return, true); +diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +index 143cc947908..22cb72f8497 100644 +--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp ++++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +@@ -35,6 +35,7 @@ + #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" + #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" + #include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h" ++#include "llvm/Transforms/Instrumentation/GCOVProfiler.h" + #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" + #include "llvm/Transforms/Instrumentation/InstrProfiling.h" + #include "llvm/Transforms/Instrumentation/MemorySanitizer.h" +@@ -563,8 +564,9 @@ extern "C" LLVMRustResult LLVMRustOptimize( + bool PrintAfterEnzyme, bool PrintPasses, + LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath, + const char *PGOUsePath, bool InstrumentCoverage, +- const char *InstrProfileOutput, const char *PGOSampleUsePath, +- bool DebugInfoForProfiling, void *LlvmSelfProfiler, ++ const char *InstrProfileOutput, bool InstrumentGCOV, ++ const char *PGOSampleUsePath, bool DebugInfoForProfiling, ++ void *LlvmSelfProfiler, + LLVMRustSelfProfileBeforePassCallback BeforePassCallback, + LLVMRustSelfProfileAfterPassCallback AfterPassCallback, + const char *ExtraPasses, size_t ExtraPassesLen, const char *LLVMPlugins, +@@ -706,6 +708,13 @@ extern "C" LLVMRustResult LLVMRustOptimize( + }); + } + ++ if (InstrumentGCOV) { ++ PipelineStartEPCallbacks.push_back( ++ [](ModulePassManager &MPM, OptimizationLevel Level) { ++ MPM.addPass(GCOVProfilerPass(GCOVOptions::getDefault())); ++ }); ++ } ++ + if (InstrumentCoverage) { + PipelineStartEPCallbacks.push_back( + [InstrProfileOutput](ModulePassManager &MPM, OptimizationLevel Level) { +diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs +index 95862ce0168..489888480be 100644 +--- a/compiler/rustc_metadata/src/creader.rs ++++ b/compiler/rustc_metadata/src/creader.rs +@@ -1055,7 +1055,7 @@ fn inject_panic_runtime(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) { + + fn inject_profiler_runtime(&mut self, tcx: TyCtxt<'_>) { + let needs_profiler_runtime = +- tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled(); ++ tcx.sess.instrument_coverage() || txc.sess.opts.unstable_opts.profile || tcx.sess.opts.cg.profile_generate.enabled(); + if !needs_profiler_runtime || tcx.sess.opts.unstable_opts.no_profiler_runtime { + return; + } +diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs +index f97a29e064b..6063a1f1b37 100644 +--- a/compiler/rustc_session/src/config.rs ++++ b/compiler/rustc_session/src/config.rs +@@ -2524,7 +2524,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M + let output_types = parse_output_types(early_dcx, &unstable_opts, matches); + + let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers); +- let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto( ++ let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto( + early_dcx, + &output_types, + matches, +@@ -2543,6 +2543,18 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M + + let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state); + ++ if unstable_opts.profile && incremental.is_some() { ++ early_dcx.early_fatal("can't instrument with gcov profiling when compiling incrementally"); ++ } ++ if unstable_opts.profile { ++ match codegen_units { ++ Some(1) => {} ++ None => codegen_units = Some(1), ++ Some(_) => early_dcx ++ .early_fatal("can't instrument with gcov profiling with multiple codegen units"), ++ } ++ } ++ + if cg.profile_generate.enabled() && cg.profile_use.is_some() { + early_dcx.early_fatal("options `-C profile-generate` and `-C profile-use` are exclusive"); + } +diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs +index 7c7e9118d59..5f0c00061e3 100644 +--- a/compiler/rustc_session/src/options.rs ++++ b/compiler/rustc_session/src/options.rs +@@ -2572,8 +2572,13 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool { + proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread, + parse_proc_macro_execution_strategy, [UNTRACKED], + "how to run proc-macro code (default: same-thread)"), ++ profile: bool = (false, parse_bool, [TRACKED], ++ "insert profiling code (default: no)"), + profile_closures: bool = (false, parse_no_value, [UNTRACKED], + "profile size of closures"), ++ profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], ++ "file path to emit profiling data at runtime when using 'profile' \ ++ (default based on relative source path)"), + profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], + "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"), + profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED], +diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md +index 57679f82f48..0f88bec2c71 100644 +--- a/src/doc/rustc/src/instrument-coverage.md ++++ b/src/doc/rustc/src/instrument-coverage.md +@@ -2,8 +2,12 @@ + + ## Introduction + +-This document describes how to enable and use LLVM instrumentation-based coverage, +-via the `-C instrument-coverage` compiler flag. ++The Rust compiler includes two code coverage implementations: ++ ++- A GCC-compatible, gcov-based coverage implementation, enabled with `-Z profile`, which derives coverage data based on DebugInfo. ++- A source-based code coverage implementation, enabled with `-C instrument-coverage`, which uses LLVM's native, efficient coverage instrumentation to generate very precise coverage data. ++ ++This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-C instrument-coverage` compiler flag. + + ## How it works + +diff --git a/src/doc/unstable-book/src/compiler-flags/profile.md b/src/doc/unstable-book/src/compiler-flags/profile.md +new file mode 100644 +index 00000000000..71303bfaff2 +--- /dev/null ++++ b/src/doc/unstable-book/src/compiler-flags/profile.md +@@ -0,0 +1,27 @@ ++# `profile` ++ ++The tracking issue for this feature is: [#42524](https://github.com/rust-lang/rust/issues/42524). ++ ++------------------------ ++ ++This feature allows the generation of code coverage reports. ++ ++Set the `-Zprofile` compiler flag in order to enable gcov profiling. ++ ++For example: ++```Bash ++cargo new testgcov --bin ++cd testgcov ++export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" ++export CARGO_INCREMENTAL=0 ++cargo build ++cargo run ++``` ++ ++Once you've built and run your program, files with the `gcno` (after build) and `gcda` (after execution) extensions will be created. ++You can parse them with [llvm-cov gcov](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) or [grcov](https://github.com/mozilla/grcov). ++ ++Please note that `RUSTFLAGS` by default applies to everything that cargo builds and runs during a build! ++When the `--target` flag is explicitly passed to cargo, the `RUSTFLAGS` no longer apply to build scripts and procedural macros. ++For more fine-grained control consider passing a `RUSTC_WRAPPER` program to cargo that only adds the profiling flags to ++rustc for the specific crates you want to profile. +diff --git a/tests/run-make/profile/rmake.rs b/tests/run-make/profile/rmake.rs +new file mode 100644 +index 00000000000..58a1b53c040 +--- /dev/null ++++ b/tests/run-make/profile/rmake.rs +@@ -0,0 +1,21 @@ ++// This test revolves around the rustc flag -Z profile, which should ++// generate a .gcno file (initial profiling information) as well ++// as a .gcda file (branch counters). The path where these are emitted ++// should also be configurable with -Z profile-emit. This test checks ++// that the files are produced, and then that the latter flag is respected. ++// See https://github.com/rust-lang/rust/pull/42433 ++ ++//@ ignore-cross-compile ++//@ needs-profiler-runtime ++ ++use run_make_support::{path, run, rustc}; ++ ++fn main() { ++ rustc().arg("-g").arg("-Zprofile").input("test.rs").run(); ++ run("test"); ++ assert!(path("test.gcno").exists(), "no .gcno file"); ++ assert!(path("test.gcda").exists(), "no .gcda file"); ++ rustc().arg("-g").arg("-Zprofile").arg("-Zprofile-emit=abc/abc.gcda").input("test.rs").run(); ++ run("test"); ++ assert!(path("abc/abc.gcda").exists(), "gcda file not emitted to defined path"); ++} +diff --git a/tests/run-make/profile/test.rs b/tests/run-make/profile/test.rs +new file mode 100644 +index 00000000000..f328e4d9d04 +--- /dev/null ++++ b/tests/run-make/profile/test.rs +@@ -0,0 +1 @@ ++fn main() {} diff --git a/build/build-rust/Zprofile.patch b/build/build-rust/Zprofile.patch @@ -0,0 +1,381 @@ +This reverts +https://github.com/rust-lang/rust/commit/659e20fa7524f8fd217476daf5ecbbe366b2ae61 +and +https://github.com/rust-lang/rust/pull/131829 + +to restore support for -Zprofile (gcov-style coverage) that was removed from +rustc 1.84.0 + +diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs +index c548f467583..61bac4fbdab 100644 +--- a/compiler/rustc_codegen_llvm/src/attributes.rs ++++ b/compiler/rustc_codegen_llvm/src/attributes.rs +@@ -250,6 +250,11 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { + return None; + } + ++ // probestack doesn't play nice either with gcov profiling. ++ if cx.sess().opts.unstable_opts.profile { ++ return None; ++ } ++ + let attr_value = match cx.sess().target.stack_probes { + StackProbeType::None => return None, + // Request LLVM to generate the probes inline. If the given LLVM version does not support +diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs +index 85a06f457eb..aa199a8fb26 100644 +--- a/compiler/rustc_codegen_llvm/src/back/write.rs ++++ b/compiler/rustc_codegen_llvm/src/back/write.rs +@@ -693,6 +693,7 @@ pub(crate) unsafe fn llvm_optimize( + pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + config.instrument_coverage, + instr_profile_output_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), ++ config.instrument_gcov, + pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + config.debug_info_for_profiling, + llvm_selfprofiler, +diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +index 0e9dbfba658..af3e145f016 100644 +--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs ++++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +@@ -9,6 +9,7 @@ + use rustc_abi::{Align, Size}; + use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo}; + use rustc_codegen_ssa::traits::*; ++use rustc_fs_util::path_to_c_string; + use rustc_hir::def::{CtorKind, DefKind}; + use rustc_hir::def_id::{DefId, LOCAL_CRATE}; + use rustc_middle::bug; +@@ -968,8 +969,33 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( + debug_name_table_kind, + ); + ++ if tcx.sess.opts.unstable_opts.profile { ++ let default_gcda_path = &output_filenames.with_extension("gcda"); ++ let gcda_path = ++ tcx.sess.opts.unstable_opts.profile_emit.as_ref().unwrap_or(default_gcda_path); ++ ++ let gcov_cu_info = [ ++ path_to_mdstring(debug_context.llcontext, &output_filenames.with_extension("gcno")), ++ path_to_mdstring(debug_context.llcontext, gcda_path), ++ unit_metadata, ++ ]; ++ let gcov_metadata = llvm::LLVMMDNodeInContext2( ++ debug_context.llcontext, ++ gcov_cu_info.as_ptr(), ++ gcov_cu_info.len(), ++ ); ++ let val = llvm::LLVMMetadataAsValue(debug_context.llcontext, gcov_metadata); ++ ++ llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, c"llvm.gcov".as_ptr(), val); ++ } ++ + return unit_metadata; + }; ++ ++ fn path_to_mdstring<'ll>(llcx: &'ll llvm::Context, path: &Path) -> &'ll llvm::Metadata { ++ let path_str = path_to_c_string(path); ++ unsafe { llvm::LLVMMDStringInContext2(llcx, path_str.as_ptr(), path_str.as_bytes().len()) } ++ } + } + + /// Creates a `DW_TAG_member` entry inside the DIE represented by the given `type_di_node`. +diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +index 6cbf2dbf7d3..2aa628efae5 100644 +--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs ++++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +@@ -61,6 +61,7 @@ + + /// A context object for maintaining all state needed by the debuginfo module. + pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> { ++ llcontext: &'ll llvm::Context, + llmod: &'ll llvm::Module, + builder: DIBuilderBox<'ll>, + created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>, +@@ -76,7 +77,9 @@ pub(crate) fn new(llmod: &'ll llvm::Module) -> Self { + debug!("CodegenUnitDebugContext::new"); + let builder = DIBuilderBox::new(llmod); + // DIBuilder inherits context from the module, so we'd better use the same one ++ let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; + CodegenUnitDebugContext { ++ llcontext, + llmod, + builder, + created_files: Default::default(), +diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +index 2443194ff48..e380af246a4 100644 +--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs ++++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +@@ -1019,6 +1019,7 @@ pub(crate) fn LLVMModuleCreateWithNameInContext( + ModuleID: *const c_char, + C: &Context, + ) -> &Module; ++ pub(crate) fn LLVMGetModuleContext(M: &Module) -> &Context; + pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module; + + /// Data layout. See Module::getDataLayout. +@@ -2488,6 +2489,7 @@ pub(crate) fn LLVMRustOptimize<'a>( + PGOUsePath: *const c_char, + InstrumentCoverage: bool, + InstrProfileOutput: *const c_char, ++ InstrumentGCOV: bool, + PGOSampleUsePath: *const c_char, + DebugInfoForProfiling: bool, + llvm_selfprofiler: *mut c_void, +diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs +index aa29afb7f5b..1fee2e45ebf 100644 +--- a/compiler/rustc_codegen_ssa/src/back/write.rs ++++ b/compiler/rustc_codegen_ssa/src/back/write.rs +@@ -87,6 +87,7 @@ pub struct ModuleConfig { + pub pgo_sample_use: Option<PathBuf>, + pub debug_info_for_profiling: bool, + pub instrument_coverage: bool, ++ pub instrument_gcov: bool, + + pub sanitizer: SanitizerSet, + pub sanitizer_recover: SanitizerSet, +@@ -121,7 +122,12 @@ pub struct ModuleConfig { + } + + impl ModuleConfig { +- fn new(kind: ModuleKind, tcx: TyCtxt<'_>, no_builtins: bool) -> ModuleConfig { ++ fn new( ++ kind: ModuleKind, ++ tcx: TyCtxt<'_>, ++ no_builtins: bool, ++ is_compiler_builtins: bool, ++ ) -> ModuleConfig { + // If it's a regular module, use `$regular`, otherwise use `$other`. + // `$regular` and `$other` are evaluated lazily. + macro_rules! if_regular { +@@ -181,6 +187,13 @@ macro_rules! if_regular { + pgo_sample_use: if_regular!(sess.opts.unstable_opts.profile_sample_use.clone(), None), + debug_info_for_profiling: sess.opts.unstable_opts.debug_info_for_profiling, + instrument_coverage: if_regular!(sess.instrument_coverage(), false), ++ instrument_gcov: if_regular!( ++ // compiler_builtins overrides the codegen-units settings, ++ // which is incompatible with -Zprofile which requires that ++ // only a single codegen unit is used per crate. ++ sess.opts.unstable_opts.profile && !is_compiler_builtins, ++ false ++ ), + + sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()), + sanitizer_dataflow_abilist: if_regular!( +@@ -460,11 +473,14 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( + + let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID); + let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); ++ let is_compiler_builtins = attr::contains_name(crate_attrs, sym::compiler_builtins); + + let crate_info = CrateInfo::new(tcx, target_cpu); + +- let regular_config = ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins); +- let allocator_config = ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins); ++ let regular_config = ++ ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins, is_compiler_builtins); ++ let allocator_config = ++ ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins, is_compiler_builtins); + + let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); + let (codegen_worker_send, codegen_worker_receive) = channel(); +diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs +index 8771bb44050..f82a4d6ce19 100644 +--- a/compiler/rustc_interface/src/tests.rs ++++ b/compiler/rustc_interface/src/tests.rs +@@ -848,6 +848,8 @@ macro_rules! tracked { + tracked!(plt, Some(true)); + tracked!(polonius, Polonius::Legacy); + tracked!(precise_enum_drop_elaboration, false); ++ tracked!(profile, true); ++ tracked!(profile_emit, Some(PathBuf::from("abc"))); + tracked!(profile_sample_use, Some(PathBuf::from("abc"))); + tracked!(profiler_runtime, "abc".to_string()); + tracked!(reg_struct_return, true); +diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +index 8c34052770e..d807abfa9b5 100644 +--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp ++++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +@@ -35,6 +35,7 @@ + #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" + #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" + #include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h" ++#include "llvm/Transforms/Instrumentation/GCOVProfiler.h" + #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" + #include "llvm/Transforms/Instrumentation/InstrProfiling.h" + #include "llvm/Transforms/Instrumentation/MemorySanitizer.h" +@@ -720,8 +721,9 @@ extern "C" LLVMRustResult LLVMRustOptimize( + bool PrintAfterEnzyme, bool PrintPasses, + LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath, + const char *PGOUsePath, bool InstrumentCoverage, +- const char *InstrProfileOutput, const char *PGOSampleUsePath, +- bool DebugInfoForProfiling, void *LlvmSelfProfiler, ++ const char *InstrProfileOutput, bool InstrumentGCOV, ++ const char *PGOSampleUsePath, bool DebugInfoForProfiling, ++ void *LlvmSelfProfiler, + LLVMRustSelfProfileBeforePassCallback BeforePassCallback, + LLVMRustSelfProfileAfterPassCallback AfterPassCallback, + const char *ExtraPasses, size_t ExtraPassesLen, const char *LLVMPlugins, +@@ -850,6 +852,13 @@ extern "C" LLVMRustResult LLVMRustOptimize( + }); + } + ++ if (InstrumentGCOV) { ++ PipelineStartEPCallbacks.push_back( ++ [](ModulePassManager &MPM, OptimizationLevel Level) { ++ MPM.addPass(GCOVProfilerPass(GCOVOptions::getDefault())); ++ }); ++ } ++ + if (InstrumentCoverage) { + PipelineStartEPCallbacks.push_back( + [InstrProfileOutput](ModulePassManager &MPM, OptimizationLevel Level) { +diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs +index 6bfb3769f24..14700bea72b 100644 +--- a/compiler/rustc_metadata/src/creader.rs ++++ b/compiler/rustc_metadata/src/creader.rs +@@ -1039,7 +1039,7 @@ fn inject_panic_runtime(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) { + + fn inject_profiler_runtime(&mut self, tcx: TyCtxt<'_>) { + let needs_profiler_runtime = +- tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled(); ++ tcx.sess.instrument_coverage() || tcx.sess.opts.unstable_opts.profile || tcx.sess.opts.cg.profile_generate.enabled(); + if !needs_profiler_runtime || tcx.sess.opts.unstable_opts.no_profiler_runtime { + return; + } +diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs +index 8f624e0fb2f..9d6e376c16f 100644 +--- a/compiler/rustc_session/src/config.rs ++++ b/compiler/rustc_session/src/config.rs +@@ -2606,7 +2606,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M + let output_types = parse_output_types(early_dcx, &unstable_opts, matches); + + let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers); +- let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto( ++ let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto( + early_dcx, + &output_types, + matches, +@@ -2625,6 +2625,18 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M + + let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state); + ++ if unstable_opts.profile && incremental.is_some() { ++ early_dcx.early_fatal("can't instrument with gcov profiling when compiling incrementally"); ++ } ++ if unstable_opts.profile { ++ match codegen_units { ++ Some(1) => {} ++ None => codegen_units = Some(1), ++ Some(_) => early_dcx ++ .early_fatal("can't instrument with gcov profiling with multiple codegen units"), ++ } ++ } ++ + if cg.profile_generate.enabled() && cg.profile_use.is_some() { + early_dcx.early_fatal("options `-C profile-generate` and `-C profile-use` are exclusive"); + } +diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs +index 44b35e8921e..235e04fa5b0 100644 +--- a/compiler/rustc_session/src/options.rs ++++ b/compiler/rustc_session/src/options.rs +@@ -2471,8 +2471,13 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool { + proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread, + parse_proc_macro_execution_strategy, [UNTRACKED], + "how to run proc-macro code (default: same-thread)"), ++ profile: bool = (false, parse_bool, [TRACKED], ++ "insert profiling code (default: no)"), + profile_closures: bool = (false, parse_no_value, [UNTRACKED], + "profile size of closures"), ++ profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], ++ "file path to emit profiling data at runtime when using 'profile' \ ++ (default based on relative source path)"), + profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], + "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"), + profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED], +diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md +index 57679f82f48..0f88bec2c71 100644 +--- a/src/doc/rustc/src/instrument-coverage.md ++++ b/src/doc/rustc/src/instrument-coverage.md +@@ -2,8 +2,12 @@ + + ## Introduction + +-This document describes how to enable and use LLVM instrumentation-based coverage, +-via the `-C instrument-coverage` compiler flag. ++The Rust compiler includes two code coverage implementations: ++ ++- A GCC-compatible, gcov-based coverage implementation, enabled with `-Z profile`, which derives coverage data based on DebugInfo. ++- A source-based code coverage implementation, enabled with `-C instrument-coverage`, which uses LLVM's native, efficient coverage instrumentation to generate very precise coverage data. ++ ++This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-C instrument-coverage` compiler flag. + + ## How it works + +diff --git a/src/doc/unstable-book/src/compiler-flags/profile.md b/src/doc/unstable-book/src/compiler-flags/profile.md +new file mode 100644 +index 00000000000..71303bfaff2 +--- /dev/null ++++ b/src/doc/unstable-book/src/compiler-flags/profile.md +@@ -0,0 +1,27 @@ ++# `profile` ++ ++The tracking issue for this feature is: [#42524](https://github.com/rust-lang/rust/issues/42524). ++ ++------------------------ ++ ++This feature allows the generation of code coverage reports. ++ ++Set the `-Zprofile` compiler flag in order to enable gcov profiling. ++ ++For example: ++```Bash ++cargo new testgcov --bin ++cd testgcov ++export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" ++export CARGO_INCREMENTAL=0 ++cargo build ++cargo run ++``` ++ ++Once you've built and run your program, files with the `gcno` (after build) and `gcda` (after execution) extensions will be created. ++You can parse them with [llvm-cov gcov](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) or [grcov](https://github.com/mozilla/grcov). ++ ++Please note that `RUSTFLAGS` by default applies to everything that cargo builds and runs during a build! ++When the `--target` flag is explicitly passed to cargo, the `RUSTFLAGS` no longer apply to build scripts and procedural macros. ++For more fine-grained control consider passing a `RUSTC_WRAPPER` program to cargo that only adds the profiling flags to ++rustc for the specific crates you want to profile. +diff --git a/tests/run-make/profile/rmake.rs b/tests/run-make/profile/rmake.rs +new file mode 100644 +index 00000000000..58a1b53c040 +--- /dev/null ++++ b/tests/run-make/profile/rmake.rs +@@ -0,0 +1,21 @@ ++// This test revolves around the rustc flag -Z profile, which should ++// generate a .gcno file (initial profiling information) as well ++// as a .gcda file (branch counters). The path where these are emitted ++// should also be configurable with -Z profile-emit. This test checks ++// that the files are produced, and then that the latter flag is respected. ++// See https://github.com/rust-lang/rust/pull/42433 ++ ++//@ ignore-cross-compile ++//@ needs-profiler-runtime ++ ++use run_make_support::{path, run, rustc}; ++ ++fn main() { ++ rustc().arg("-g").arg("-Zprofile").input("test.rs").run(); ++ run("test"); ++ assert!(path("test.gcno").exists(), "no .gcno file"); ++ assert!(path("test.gcda").exists(), "no .gcda file"); ++ rustc().arg("-g").arg("-Zprofile").arg("-Zprofile-emit=abc/abc.gcda").input("test.rs").run(); ++ run("test"); ++ assert!(path("abc/abc.gcda").exists(), "gcda file not emitted to defined path"); ++} +diff --git a/tests/run-make/profile/test.rs b/tests/run-make/profile/test.rs +new file mode 100644 +index 00000000000..f328e4d9d04 +--- /dev/null ++++ b/tests/run-make/profile/test.rs +@@ -0,0 +1 @@ ++fn main() {} diff --git a/build/build-rust/rust-vendor-std.patch b/build/build-rust/rust-vendor-std.patch @@ -9,10 +9,10 @@ Since then, things have changed in cargo, such that it is now possible to use a simpler approach that only relies on tweaking what is shipped in rust. diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs -index 4957de2e1b7..b903e1be4aa 100644 +index 5cfaa6a7c77..65c8abcb4f8 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs -@@ -941,6 +941,101 @@ fn run(self, builder: &Builder<'_>) -> GeneratedTarball { +@@ -1016,6 +1016,97 @@ fn run(self, builder: &Builder<'_>) -> GeneratedTarball { &dst_src, ); @@ -36,11 +36,7 @@ index 4957de2e1b7..b903e1be4aa 100644 + cmd.env("RUSTC_BOOTSTRAP", "1"); + builder.info("Dist src"); + let _time = timeit(builder); -+ builder.run( -+ &mut cmd, -+ crate::utils::exec::OutputMode::Print, -+ crate::utils::exec::OutputMode::Print, -+ ); ++ cmd.run(builder); + + // Ideally, we would add the .cargo/config.toml that `cargo vendor` outputs, + // but cargo doesn't read it when building libstd. So instead, we add @@ -113,4 +109,4 @@ index 4957de2e1b7..b903e1be4aa 100644 + tarball.generate() } - } + diff --git a/taskcluster/kinds/fetch/toolchains.yml b/taskcluster/kinds/fetch/toolchains.yml @@ -410,13 +410,13 @@ clang-trunk: # We build stable rust from source so the resulting compiler acts as a nightly # rust compiler, allowing to use unstable features like -Zbuild-std and # sanitizers. -rust-1.83.0: - description: Rust 1.83.0 source code +rust-1.90.0: + description: Rust 1.90.0 source code fetch: type: git include-dot-git: true repo: https://github.com/rust-lang/rust/ - revision: 90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf + revision: 1159e78c4747b02ef996e55082b704c09b970588 rust-nightly: description: Rust nightly source code diff --git a/taskcluster/kinds/toolchain/rust.yml b/taskcluster/kinds/toolchain/rust.yml @@ -88,7 +88,7 @@ linux64-rust-1.90: # A patched rust toolchain that allows us to use sanitizers in our vendored # build environment. See the rust fetch's comments for more details. -linux64-rust-1.83-dev: +linux64-rust-1.90-dev: description: "build rust from source" worker-type: b-linux-docker-large-amd treeherder: @@ -101,24 +101,26 @@ linux64-rust-1.83-dev: run: arguments: [ '--patch', 'rust-vendor-std.patch', + '--patch', 'Zprofile.patch', '--channel', 'dev', '--host', 'x86_64-unknown-linux-gnu', '--target', 'x86_64-unknown-linux-gnu', ] resources: - build/build-rust/rust-vendor-std.patch + - build/build-rust/Zprofile.patch toolchain-alias: by-project: toolchains: null default: linux64-rust-dev fetches: fetch: - - rust-1.83.0 + - rust-1.90.0 toolchain: - linux64-clang-toolchain - linux64-toolchain-sysroot -win64-rust-1.83-dev: +win64-rust-1.90-dev: description: "build rust from source" worker-type: b-win2022 treeherder: @@ -126,19 +128,21 @@ win64-rust-1.83-dev: run: arguments: [ '--patch', 'rust-vendor-std.patch', + '--patch', 'Zprofile.patch', '--channel', 'dev', '--host', 'x86_64-pc-windows-msvc', '--target', 'x86_64-pc-windows-msvc', ] resources: - build/build-rust/rust-vendor-std.patch + - build/build-rust/Zprofile.patch toolchain-alias: by-project: toolchains: null default: win64-rust-dev fetches: fetch: - - rust-1.83.0 + - rust-1.90.0 - win64-ninja toolchain: - win64-clang-toolchain @@ -345,12 +349,14 @@ linux64-rust-nightly-dev: run: arguments: [ '--patch', 'rust-vendor-std.patch', + '--patch', 'Zprofile-1.92.patch', '--channel', 'dev', '--host', 'x86_64-unknown-linux-gnu', '--target', 'x86_64-unknown-linux-gnu', ] resources: - build/build-rust/rust-vendor-std.patch + - build/build-rust/Zprofile-1.92.patch toolchain-alias: by-project: toolchains: linux64-rust-dev @@ -372,12 +378,14 @@ win64-rust-nightly-dev: run: arguments: [ '--patch', 'rust-vendor-std.patch', + '--patch', 'Zprofile-1.92.patch', '--channel', 'dev', '--host', 'x86_64-pc-windows-msvc', '--target', 'x86_64-pc-windows-msvc', ] resources: - build/build-rust/rust-vendor-std.patch + - build/build-rust/Zprofile-1.92.patch toolchain-alias: by-project: toolchains: win64-rust-dev