diff --git a/Cargo.lock b/Cargo.lock index 52c9269fa87..4654b99960f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4407,6 +4407,7 @@ dependencies = [ "bitflags", "getopts", "libc", + "rand 0.9.0", "rustc_abi", "rustc_ast", "rustc_data_structures", diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 4ac7b86f085..0ea0dbfc44b 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -169,8 +169,11 @@ fn produce_final_output_artifacts( if codegen_results.modules.len() == 1 { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - let path = - crate_output.temp_path_for_cgu(output_type, &codegen_results.modules[0].name); + let path = crate_output.temp_path_for_cgu( + output_type, + &codegen_results.modules[0].name, + sess.invocation_temp.as_deref(), + ); let output = crate_output.path(output_type); if !output_type.is_text_output() && output.is_tty() { sess.dcx() @@ -345,6 +348,7 @@ fn make_module(sess: &Session, name: String) -> UnwindModule { fn emit_cgu( output_filenames: &OutputFilenames, + invocation_temp: Option<&str>, prof: &SelfProfilerRef, name: String, module: UnwindModule, @@ -360,6 +364,7 @@ fn emit_cgu( let module_regular = emit_module( output_filenames, + invocation_temp, prof, product.object, ModuleKind::Regular, @@ -385,6 +390,7 @@ fn emit_cgu( fn emit_module( output_filenames: &OutputFilenames, + invocation_temp: Option<&str>, prof: &SelfProfilerRef, mut object: cranelift_object::object::write::Object<'_>, kind: ModuleKind, @@ -403,7 +409,7 @@ fn emit_module( object.set_section_data(comment_section, producer, 1); } - let tmp_file = output_filenames.temp_path_for_cgu(OutputType::Object, &name); + let tmp_file = output_filenames.temp_path_for_cgu(OutputType::Object, &name, invocation_temp); let file = match File::create(&tmp_file) { Ok(file) => file, Err(err) => return Err(format!("error creating object file: {}", err)), @@ -443,8 +449,11 @@ fn reuse_workproduct_for_cgu( cgu: &CodegenUnit<'_>, ) -> Result { let work_product = cgu.previous_work_product(tcx); - let obj_out_regular = - tcx.output_filenames(()).temp_path_for_cgu(OutputType::Object, cgu.name().as_str()); + let obj_out_regular = tcx.output_filenames(()).temp_path_for_cgu( + OutputType::Object, + cgu.name().as_str(), + tcx.sess.invocation_temp.as_deref(), + ); let source_file_regular = rustc_incremental::in_incr_comp_dir_sess( &tcx.sess, &work_product.saved_files.get("o").expect("no saved object file in work product"), @@ -589,13 +598,19 @@ fn module_codegen( let global_asm_object_file = profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| { - crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, &cx.global_asm) + crate::global_asm::compile_global_asm( + &global_asm_config, + &cgu_name, + &cx.global_asm, + cx.invocation_temp.as_deref(), + ) })?; let codegen_result = profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| { emit_cgu( &global_asm_config.output_filenames, + cx.invocation_temp.as_deref(), &profiler, cgu_name, module, @@ -620,8 +635,11 @@ fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> Compiled .as_str() .to_string(); - let tmp_file = - tcx.output_filenames(()).temp_path_for_cgu(OutputType::Metadata, &metadata_cgu_name); + let tmp_file = tcx.output_filenames(()).temp_path_for_cgu( + OutputType::Metadata, + &metadata_cgu_name, + tcx.sess.invocation_temp.as_deref(), + ); let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx); let obj = create_compressed_metadata_file(tcx.sess, metadata, &symbol_name); @@ -651,6 +669,7 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option { match emit_module( tcx.output_filenames(()), + tcx.sess.invocation_temp.as_deref(), &tcx.sess.prof, product.object, ModuleKind::Allocator, diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 6e3b3677a7f..79cefb05de3 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -132,6 +132,7 @@ pub(crate) fn compile_global_asm( config: &GlobalAsmConfig, cgu_name: &str, global_asm: &str, + invocation_temp: Option<&str>, ) -> Result, String> { if global_asm.is_empty() { return Ok(None); @@ -146,7 +147,7 @@ pub(crate) fn compile_global_asm( global_asm.push('\n'); let global_asm_object_file = add_file_stem_postfix( - config.output_filenames.temp_path_for_cgu(OutputType::Object, cgu_name), + config.output_filenames.temp_path_for_cgu(OutputType::Object, cgu_name, invocation_temp), ".asm", ); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index e7afaff3b42..9d9e790289c 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -124,6 +124,7 @@ impl String> Drop for PrintOnPanic { /// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module). struct CodegenCx { output_filenames: Arc, + invocation_temp: Option, should_write_ir: bool, global_asm: String, inline_asm_index: usize, @@ -142,6 +143,7 @@ impl CodegenCx { }; CodegenCx { output_filenames: tcx.output_filenames(()).clone(), + invocation_temp: tcx.sess.invocation_temp.clone(), should_write_ir: crate::pretty_clif::should_write_ir(tcx), global_asm: String::new(), inline_asm_index: 0, diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 3427b38ce83..16c895322e8 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -31,8 +31,16 @@ pub(crate) unsafe fn codegen( // TODO(antoyo): remove this environment variable. let fat_lto = env::var("EMBED_LTO_BITCODE").as_deref() == Ok("1"); - let bc_out = cgcx.output_filenames.temp_path_for_cgu(OutputType::Bitcode, &module.name); - let obj_out = cgcx.output_filenames.temp_path_for_cgu(OutputType::Object, &module.name); + let bc_out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Bitcode, + &module.name, + cgcx.invocation_temp.as_deref(), + ); + let obj_out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Object, + &module.name, + cgcx.invocation_temp.as_deref(), + ); if config.bitcode_needed() { if fat_lto { @@ -113,15 +121,22 @@ pub(crate) unsafe fn codegen( } if config.emit_ir { - let out = - cgcx.output_filenames.temp_path_for_cgu(OutputType::LlvmAssembly, &module.name); + let out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::LlvmAssembly, + &module.name, + cgcx.invocation_temp.as_deref(), + ); std::fs::write(out, "").expect("write file"); } if config.emit_asm { let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen_emit_asm", &*module.name); - let path = cgcx.output_filenames.temp_path_for_cgu(OutputType::Assembly, &module.name); + let path = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Assembly, + &module.name, + cgcx.invocation_temp.as_deref(), + ); context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str")); } @@ -235,6 +250,7 @@ pub(crate) unsafe fn codegen( config.emit_asm, config.emit_ir, &cgcx.output_filenames, + cgcx.invocation_temp.as_deref(), )) } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index c8921794711..18d221d232e 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -120,13 +120,17 @@ pub(crate) fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTar tcx.sess.split_debuginfo(), tcx.sess.opts.unstable_opts.split_dwarf_kind, mod_name, + tcx.sess.invocation_temp.as_deref(), ) } else { None }; - let output_obj_file = - Some(tcx.output_filenames(()).temp_path_for_cgu(OutputType::Object, mod_name)); + let output_obj_file = Some(tcx.output_filenames(()).temp_path_for_cgu( + OutputType::Object, + mod_name, + tcx.sess.invocation_temp.as_deref(), + )); let config = TargetMachineFactoryConfig { split_dwarf_file, output_obj_file }; target_machine_factory( @@ -330,7 +334,11 @@ pub(crate) fn save_temp_bitcode( return; } let ext = format!("{name}.bc"); - let path = cgcx.output_filenames.temp_path_ext_for_cgu(&ext, &module.name); + let path = cgcx.output_filenames.temp_path_ext_for_cgu( + &ext, + &module.name, + cgcx.invocation_temp.as_deref(), + ); write_bitcode_to_file(module, &path) } @@ -694,7 +702,11 @@ pub(crate) unsafe fn optimize( let _handlers = DiagnosticHandlers::new(cgcx, dcx, llcx, module, CodegenDiagnosticsStage::Opt); if config.emit_no_opt_bc { - let out = cgcx.output_filenames.temp_path_ext_for_cgu("no-opt.bc", &module.name); + let out = cgcx.output_filenames.temp_path_ext_for_cgu( + "no-opt.bc", + &module.name, + cgcx.invocation_temp.as_deref(), + ); write_bitcode_to_file(module, &out) } @@ -739,8 +751,11 @@ pub(crate) unsafe fn optimize( if let Some(thin_lto_buffer) = thin_lto_buffer { let thin_lto_buffer = unsafe { ThinBuffer::from_raw_ptr(thin_lto_buffer) }; module.thin_lto_buffer = Some(thin_lto_buffer.data().to_vec()); - let bc_summary_out = - cgcx.output_filenames.temp_path_for_cgu(OutputType::ThinLinkBitcode, &module.name); + let bc_summary_out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::ThinLinkBitcode, + &module.name, + cgcx.invocation_temp.as_deref(), + ); if config.emit_thin_lto_summary && let Some(thin_link_bitcode_filename) = bc_summary_out.file_name() { @@ -808,8 +823,16 @@ pub(crate) unsafe fn codegen( // copy it to the .o file, and delete the bitcode if it wasn't // otherwise requested. - let bc_out = cgcx.output_filenames.temp_path_for_cgu(OutputType::Bitcode, &module.name); - let obj_out = cgcx.output_filenames.temp_path_for_cgu(OutputType::Object, &module.name); + let bc_out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Bitcode, + &module.name, + cgcx.invocation_temp.as_deref(), + ); + let obj_out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Object, + &module.name, + cgcx.invocation_temp.as_deref(), + ); if config.bitcode_needed() { if config.emit_bc || config.emit_obj == EmitObj::Bitcode { @@ -851,8 +874,11 @@ pub(crate) unsafe fn codegen( if config.emit_ir { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen_emit_ir", &*module.name); - let out = - cgcx.output_filenames.temp_path_for_cgu(OutputType::LlvmAssembly, &module.name); + let out = cgcx.output_filenames.temp_path_for_cgu( + OutputType::LlvmAssembly, + &module.name, + cgcx.invocation_temp.as_deref(), + ); let out_c = path_to_c_string(&out); extern "C" fn demangle_callback( @@ -894,7 +920,11 @@ pub(crate) unsafe fn codegen( if config.emit_asm { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen_emit_asm", &*module.name); - let path = cgcx.output_filenames.temp_path_for_cgu(OutputType::Assembly, &module.name); + let path = cgcx.output_filenames.temp_path_for_cgu( + OutputType::Assembly, + &module.name, + cgcx.invocation_temp.as_deref(), + ); // We can't use the same module for asm and object code output, // because that triggers various errors like invalid IR or broken @@ -924,7 +954,9 @@ pub(crate) unsafe fn codegen( .prof .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name); - let dwo_out = cgcx.output_filenames.temp_path_dwo_for_cgu(&module.name); + let dwo_out = cgcx + .output_filenames + .temp_path_dwo_for_cgu(&module.name, cgcx.invocation_temp.as_deref()); let dwo_out = match (cgcx.split_debuginfo, cgcx.split_dwarf_kind) { // Don't change how DWARF is emitted when disabled. (SplitDebuginfo::Off, _) => None, @@ -989,6 +1021,7 @@ pub(crate) unsafe fn codegen( config.emit_asm, config.emit_ir, &cgcx.output_filenames, + cgcx.invocation_temp.as_deref(), )) } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 4b0ec4a6415..1eb8f367c54 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -911,6 +911,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( tcx.sess.split_debuginfo(), tcx.sess.opts.unstable_opts.split_dwarf_kind, codegen_unit_name, + tcx.sess.invocation_temp.as_deref(), ) { // We get a path relative to the working directory from split_dwarf_path Some(tcx.sess.source_map().path_mapping().to_real_filename(f)) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 2785664595f..8de68925cab 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -112,7 +112,12 @@ pub fn link_binary( codegen_results.crate_info.local_crate_name, ); let crate_name = format!("{}", codegen_results.crate_info.local_crate_name); - let out_filename = output.file_for_writing(outputs, OutputType::Exe, &crate_name); + let out_filename = output.file_for_writing( + outputs, + OutputType::Exe, + &crate_name, + sess.invocation_temp.as_deref(), + ); match crate_type { CrateType::Rlib => { let _timer = sess.timer("link_rlib"); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index fa698ff59a2..0fd4ed8475b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -307,13 +307,17 @@ impl TargetMachineFactoryConfig { cgcx.split_debuginfo, cgcx.split_dwarf_kind, module_name, + cgcx.invocation_temp.as_deref(), ) } else { None }; - let output_obj_file = - Some(cgcx.output_filenames.temp_path_for_cgu(OutputType::Object, module_name)); + let output_obj_file = Some(cgcx.output_filenames.temp_path_for_cgu( + OutputType::Object, + module_name, + cgcx.invocation_temp.as_deref(), + )); TargetMachineFactoryConfig { split_dwarf_file, output_obj_file } } } @@ -344,6 +348,7 @@ pub struct CodegenContext { pub crate_types: Vec, pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>, pub output_filenames: Arc, + pub invocation_temp: Option, pub regular_module_config: Arc, pub metadata_module_config: Arc, pub allocator_module_config: Arc, @@ -582,7 +587,11 @@ fn produce_final_output_artifacts( if let [module] = &compiled_modules.modules[..] { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - let path = crate_output.temp_path_for_cgu(output_type, &module.name); + let path = crate_output.temp_path_for_cgu( + output_type, + &module.name, + sess.invocation_temp.as_deref(), + ); let output = crate_output.path(output_type); if !output_type.is_text_output() && output.is_tty() { sess.dcx() @@ -959,7 +968,12 @@ fn execute_copy_from_cache_work_item( module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| { let dwarf_obj_out = cgcx .output_filenames - .split_dwarf_path(cgcx.split_debuginfo, cgcx.split_dwarf_kind, &module.name) + .split_dwarf_path( + cgcx.split_debuginfo, + cgcx.split_dwarf_kind, + &module.name, + cgcx.invocation_temp.as_deref(), + ) .expect( "saved dwarf object in work product but `split_dwarf_path` returned `None`", ); @@ -969,7 +983,11 @@ fn execute_copy_from_cache_work_item( let mut load_from_incr_cache = |perform, output_type: OutputType| { if perform { let saved_file = module.source.saved_files.get(output_type.extension())?; - let output_path = cgcx.output_filenames.temp_path_for_cgu(output_type, &module.name); + let output_path = cgcx.output_filenames.temp_path_for_cgu( + output_type, + &module.name, + cgcx.invocation_temp.as_deref(), + ); load_from_incr_comp_dir(output_path, &saved_file) } else { None @@ -1214,6 +1232,7 @@ fn start_executing_work( split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend, pointer_size: tcx.data_layout.pointer_size, + invocation_temp: sess.invocation_temp.clone(), }; // This is the "main loop" of parallel work happening for parallel codegen. diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 511c79c93a2..597d2340116 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -640,9 +640,11 @@ pub fn codegen_crate( let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string(); tcx.sess.time("write_compressed_metadata", || { - let file_name = tcx - .output_filenames(()) - .temp_path_for_cgu(OutputType::Metadata, &metadata_cgu_name); + let file_name = tcx.output_filenames(()).temp_path_for_cgu( + OutputType::Metadata, + &metadata_cgu_name, + tcx.sess.invocation_temp.as_deref(), + ); let data = create_compressed_metadata_file( tcx.sess, &metadata, diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 491fe4a57a4..153935f2531 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -105,14 +105,19 @@ impl ModuleCodegen { emit_asm: bool, emit_ir: bool, outputs: &OutputFilenames, + invocation_temp: Option<&str>, ) -> CompiledModule { - let object = emit_obj.then(|| outputs.temp_path_for_cgu(OutputType::Object, &self.name)); - let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo_for_cgu(&self.name)); - let bytecode = emit_bc.then(|| outputs.temp_path_for_cgu(OutputType::Bitcode, &self.name)); - let assembly = - emit_asm.then(|| outputs.temp_path_for_cgu(OutputType::Assembly, &self.name)); - let llvm_ir = - emit_ir.then(|| outputs.temp_path_for_cgu(OutputType::LlvmAssembly, &self.name)); + let object = emit_obj + .then(|| outputs.temp_path_for_cgu(OutputType::Object, &self.name, invocation_temp)); + let dwarf_object = + emit_dwarf_obj.then(|| outputs.temp_path_dwo_for_cgu(&self.name, invocation_temp)); + let bytecode = emit_bc + .then(|| outputs.temp_path_for_cgu(OutputType::Bitcode, &self.name, invocation_temp)); + let assembly = emit_asm + .then(|| outputs.temp_path_for_cgu(OutputType::Assembly, &self.name, invocation_temp)); + let llvm_ir = emit_ir.then(|| { + outputs.temp_path_for_cgu(OutputType::LlvmAssembly, &self.name, invocation_temp) + }); CompiledModule { name: self.name.clone(), diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 747e36b6a1a..ad7fb1ad05f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -800,6 +800,7 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( sess.opts.cg.metadata.clone(), sess.cfg_version, ); + let outputs = util::build_output_filenames(&pre_configured_attrs, sess); let dep_type = DepsType { dep_names: rustc_query_impl::dep_kind_names() }; diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index a087725d34d..63772a32222 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" # tidy-alphabetical-start bitflags = "2.4.1" getopts = "0.2" +rand = "0.9.0" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 946b1201e05..bdd54a15147 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1016,10 +1016,13 @@ impl OutFileName { outputs: &OutputFilenames, flavor: OutputType, codegen_unit_name: &str, + invocation_temp: Option<&str>, ) -> PathBuf { match *self { OutFileName::Real(ref path) => path.clone(), - OutFileName::Stdout => outputs.temp_path_for_cgu(flavor, codegen_unit_name), + OutFileName::Stdout => { + outputs.temp_path_for_cgu(flavor, codegen_unit_name, invocation_temp) + } } } @@ -1094,21 +1097,41 @@ impl OutputFilenames { /// Gets the path where a compilation artifact of the given type for the /// given codegen unit should be placed on disk. If codegen_unit_name is /// None, a path distinct from those of any codegen unit will be generated. - pub fn temp_path_for_cgu(&self, flavor: OutputType, codegen_unit_name: &str) -> PathBuf { + pub fn temp_path_for_cgu( + &self, + flavor: OutputType, + codegen_unit_name: &str, + invocation_temp: Option<&str>, + ) -> PathBuf { let extension = flavor.extension(); - self.temp_path_ext_for_cgu(extension, codegen_unit_name) + self.temp_path_ext_for_cgu(extension, codegen_unit_name, invocation_temp) } /// Like `temp_path`, but specifically for dwarf objects. - pub fn temp_path_dwo_for_cgu(&self, codegen_unit_name: &str) -> PathBuf { - self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name) + pub fn temp_path_dwo_for_cgu( + &self, + codegen_unit_name: &str, + invocation_temp: Option<&str>, + ) -> PathBuf { + self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp) } /// Like `temp_path`, but also supports things where there is no corresponding /// OutputType, like noopt-bitcode or lto-bitcode. - pub fn temp_path_ext_for_cgu(&self, ext: &str, codegen_unit_name: &str) -> PathBuf { + pub fn temp_path_ext_for_cgu( + &self, + ext: &str, + codegen_unit_name: &str, + invocation_temp: Option<&str>, + ) -> PathBuf { let mut extension = codegen_unit_name.to_string(); + // Append `.{invocation_temp}` to ensure temporary files are unique. + if let Some(rng) = invocation_temp { + extension.push('.'); + extension.push_str(rng); + } + // FIXME: This is sketchy that we're not appending `.rcgu` when the ext is empty. // Append `.rcgu.{ext}`. if !ext.is_empty() { @@ -1144,9 +1167,10 @@ impl OutputFilenames { split_debuginfo_kind: SplitDebuginfo, split_dwarf_kind: SplitDwarfKind, cgu_name: &str, + invocation_temp: Option<&str>, ) -> Option { - let obj_out = self.temp_path_for_cgu(OutputType::Object, cgu_name); - let dwo_out = self.temp_path_dwo_for_cgu(cgu_name); + let obj_out = self.temp_path_for_cgu(OutputType::Object, cgu_name, invocation_temp); + let dwo_out = self.temp_path_dwo_for_cgu(cgu_name, invocation_temp); match (split_debuginfo_kind, split_dwarf_kind) { (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None, // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index fb4a437a487..1359f7eb7bb 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -6,6 +6,8 @@ use std::sync::Arc; use std::sync::atomic::AtomicBool; use std::{env, fmt, io}; +use rand::{RngCore, rng}; +use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; @@ -203,6 +205,14 @@ pub struct Session { target_filesearch: FileSearch, host_filesearch: FileSearch, + + /// A random string generated per invocation of rustc. + /// + /// This is prepended to all temporary files so that they do not collide + /// during concurrent invocations of rustc, or past invocations that were + /// preserved with a flag like `-C save-temps`, since these files may be + /// hard linked. + pub invocation_temp: Option, } #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -1117,6 +1127,12 @@ pub fn build_session( let target_filesearch = filesearch::FileSearch::new(&sopts.search_paths, &target_tlib_path, &target); let host_filesearch = filesearch::FileSearch::new(&sopts.search_paths, &host_tlib_path, &host); + + let invocation_temp = sopts + .incremental + .as_ref() + .map(|_| rng().next_u32().to_base_fixed_len(CASE_INSENSITIVE).to_string()); + let sess = Session { target, host, @@ -1140,6 +1156,7 @@ pub fn build_session( expanded_args, target_filesearch, host_filesearch, + invocation_temp, }; validate_commandline_args_with_session_available(&sess); diff --git a/tests/run-make/dirty-incr-due-to-hard-link/rmake.rs b/tests/run-make/dirty-incr-due-to-hard-link/rmake.rs new file mode 100644 index 00000000000..942b667814a --- /dev/null +++ b/tests/run-make/dirty-incr-due-to-hard-link/rmake.rs @@ -0,0 +1,32 @@ +//@ only-x86_64-unknown-linux-gnu + +// Regression test for the incremental bug in . +// +// A detailed explanation is described in , +// however the gist of the issue is that hard-linking temporary files can interact strangely +// across incremental sessions that are not finalized due to errors originating from the +// codegen backend. + +use run_make_support::{run, rustc}; + +fn main() { + let mk_rustc = || { + let mut rustc = rustc(); + rustc.input("test.rs").incremental("incr").arg("-Csave-temps").output("test"); + rustc + }; + + // Revision 1 + mk_rustc().cfg("rpass1").run(); + + run("test"); + + // Revision 2 + mk_rustc().cfg("cfail2").run_fail(); + // Expected to fail. + + // Revision 3 + mk_rustc().cfg("rpass3").run(); + + run("test"); +} diff --git a/tests/run-make/dirty-incr-due-to-hard-link/test.rs b/tests/run-make/dirty-incr-due-to-hard-link/test.rs new file mode 100644 index 00000000000..dba5a6bbc82 --- /dev/null +++ b/tests/run-make/dirty-incr-due-to-hard-link/test.rs @@ -0,0 +1,31 @@ +#[inline(never)] +#[cfg(any(rpass1, rpass3))] +fn a() -> i32 { + 0 +} + +#[cfg(any(cfail2))] +fn a() -> i32 { + 1 +} + +fn main() { + evil::evil(); + assert_eq!(a(), 0); +} + +mod evil { + #[cfg(any(rpass1, rpass3))] + pub fn evil() { + unsafe { + std::arch::asm!("/* */"); + } + } + + #[cfg(any(cfail2))] + pub fn evil() { + unsafe { + std::arch::asm!("missing"); + } + } +}