Skip to content

Commit 2627eed

Browse files
Avoid deleting temporary files on error
Previously if the compiler error'd, fatally, then temporary directories which should be preserved by -Csave-temps would be deleted due to fatal compiler errors being implemented as panics.
1 parent ceedf1d commit 2627eed

File tree

6 files changed

+54
-24
lines changed

6 files changed

+54
-24
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3363,6 +3363,7 @@ dependencies = [
33633363
"smallvec 1.4.0",
33643364
"stable_deref_trait",
33653365
"stacker",
3366+
"tempfile",
33663367
"tracing",
33673368
"winapi 0.3.8",
33683369
]

src/librustc_codegen_ssa/back/link.rs

+15-24
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_data_structures::fx::FxHashSet;
2+
use rustc_data_structures::temp_dir::MaybeTempDir;
23
use rustc_fs_util::fix_windows_verbatim_for_gcc;
34
use rustc_hir::def_id::CrateNum;
45
use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib};
@@ -23,7 +24,7 @@ use super::rpath::{self, RPathConfig};
2324
use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FILENAME};
2425

2526
use cc::windows_registry;
26-
use tempfile::{Builder as TempFileBuilder, TempDir};
27+
use tempfile::Builder as TempFileBuilder;
2728

2829
use std::ffi::OsString;
2930
use std::path::{Path, PathBuf};
@@ -70,35 +71,29 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
7071
}
7172
});
7273

73-
let tmpdir = TempFileBuilder::new()
74-
.prefix("rustc")
75-
.tempdir()
76-
.unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
77-
7874
if outputs.outputs.should_codegen() {
75+
let tmpdir = TempFileBuilder::new()
76+
.prefix("rustc")
77+
.tempdir()
78+
.unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
79+
let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
7980
let out_filename = out_filename(sess, crate_type, outputs, crate_name);
8081
match crate_type {
8182
CrateType::Rlib => {
8283
let _timer = sess.timer("link_rlib");
83-
link_rlib::<B>(
84-
sess,
85-
codegen_results,
86-
RlibFlavor::Normal,
87-
&out_filename,
88-
&tmpdir,
89-
)
90-
.build();
84+
link_rlib::<B>(sess, codegen_results, RlibFlavor::Normal, &out_filename, &path)
85+
.build();
9186
}
9287
CrateType::Staticlib => {
93-
link_staticlib::<B>(sess, codegen_results, &out_filename, &tmpdir);
88+
link_staticlib::<B>(sess, codegen_results, &out_filename, &path);
9489
}
9590
_ => {
9691
link_natively::<B>(
9792
sess,
9893
crate_type,
9994
&out_filename,
10095
codegen_results,
101-
tmpdir.path(),
96+
path.as_ref(),
10297
target_cpu,
10398
);
10499
}
@@ -107,10 +102,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
107102
sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename, "link");
108103
}
109104
}
110-
111-
if sess.opts.cg.save_temps {
112-
let _ = tmpdir.into_path();
113-
}
114105
}
115106

116107
// Remove the temporary object file and metadata if we aren't saving temps
@@ -279,8 +270,8 @@ pub fn each_linked_rlib(
279270
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
280271
/// directory being searched for `extern crate` (observing an incomplete file).
281272
/// The returned path is the temporary file containing the complete metadata.
282-
pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &TempDir) -> PathBuf {
283-
let out_filename = tmpdir.path().join(METADATA_FILENAME);
273+
pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &MaybeTempDir) -> PathBuf {
274+
let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
284275
let result = fs::write(&out_filename, &metadata.raw_data);
285276

286277
if let Err(e) = result {
@@ -301,7 +292,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
301292
codegen_results: &CodegenResults,
302293
flavor: RlibFlavor,
303294
out_filename: &Path,
304-
tmpdir: &TempDir,
295+
tmpdir: &MaybeTempDir,
305296
) -> B {
306297
info!("preparing rlib to {:?}", out_filename);
307298
let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None);
@@ -406,7 +397,7 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(
406397
sess: &'a Session,
407398
codegen_results: &CodegenResults,
408399
out_filename: &Path,
409-
tempdir: &TempDir,
400+
tempdir: &MaybeTempDir,
410401
) {
411402
let mut ab =
412403
link_rlib::<B>(sess, codegen_results, RlibFlavor::StaticlibBase, out_filename, tempdir);

src/librustc_data_structures/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ bitflags = "1.2.1"
3030
measureme = "0.7.1"
3131
libc = "0.2"
3232
stacker = "0.1.9"
33+
tempfile = "3.0.5"
3334

3435
[dependencies.parking_lot]
3536
version = "0.10"

src/librustc_data_structures/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ pub mod vec_linked_list;
9595
pub mod work_queue;
9696
pub use atomic_ref::AtomicRef;
9797
pub mod frozen;
98+
pub mod temp_dir;
9899

99100
pub struct OnDrop<F: Fn()>(pub F);
100101

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use std::mem::ManuallyDrop;
2+
use std::path::Path;
3+
use tempfile::TempDir;
4+
5+
/// This is used to avoid TempDir being dropped on error paths unintentionally.
6+
#[derive(Debug)]
7+
pub struct MaybeTempDir {
8+
dir: ManuallyDrop<TempDir>,
9+
// Whether the TempDir should be deleted on drop.
10+
keep: bool,
11+
}
12+
13+
impl Drop for MaybeTempDir {
14+
fn drop(&mut self) {
15+
// Safety: We are in the destructor, and no further access will
16+
// occur.
17+
let dir = unsafe { ManuallyDrop::take(&mut self.dir) };
18+
if self.keep {
19+
dir.into_path();
20+
}
21+
}
22+
}
23+
24+
impl AsRef<Path> for MaybeTempDir {
25+
fn as_ref(&self) -> &Path {
26+
self.dir.path()
27+
}
28+
}
29+
30+
impl MaybeTempDir {
31+
pub fn new(dir: TempDir, keep_on_drop: bool) -> MaybeTempDir {
32+
MaybeTempDir { dir: ManuallyDrop::new(dir), keep: keep_on_drop }
33+
}
34+
}

src/librustc_interface/passes.rs

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_ast::{self, ast, visit};
99
use rustc_codegen_ssa::back::link::emit_metadata;
1010
use rustc_codegen_ssa::traits::CodegenBackend;
1111
use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
12+
use rustc_data_structures::temp_dir::MaybeTempDir;
1213
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
1314
use rustc_errors::{ErrorReported, PResult};
1415
use rustc_expand::base::ExtCtxt;
@@ -974,6 +975,7 @@ fn encode_and_write_metadata(
974975
.prefix("rmeta")
975976
.tempdir_in(out_filename.parent().unwrap())
976977
.unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
978+
let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
977979
let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir);
978980
if let Err(e) = fs::rename(&metadata_filename, &out_filename) {
979981
tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));

0 commit comments

Comments
 (0)