mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
0c05f6c478
The test needs proc-macros to function
107 lines
3.4 KiB
Rust
107 lines
3.4 KiB
Rust
//@ ignore-cross-compile
|
|
//@ needs-crate-type: proc-macro
|
|
|
|
//! Test that a failure to finalize the incremental compilation session directory
|
|
//! (i.e., the rename from "-working" to the SVH-based name) results in a
|
|
//! note, not an ICE, and that the compilation output is still produced.
|
|
//!
|
|
//! Strategy:
|
|
//! 1. Build the `poison` proc-macro crate
|
|
//! 2. Compile foo.rs with incremental compilation
|
|
//! The proc macro runs mid-compilation (after prepare_session_directory
|
|
//! but before finalize_session_directory) and sabotages the rename:
|
|
//! - On Unix: removes write permission from the crate directory,
|
|
//! so rename() fails with EACCES.
|
|
//! - On Windows: creates and leaks an open file handle inside the
|
|
//! -working directory, so rename() fails with ERROR_ACCESS_DENIED.
|
|
//! 3. Assert that stderr contains the finalize failure messages
|
|
|
|
use std::fs;
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use run_make_support::rustc;
|
|
|
|
/// Guard that restores permissions on the incremental directory on drop,
|
|
/// to ensure cleanup is possible
|
|
struct IncrDirCleanup;
|
|
|
|
fn main() {
|
|
let _cleanup = IncrDirCleanup;
|
|
|
|
// Build the poison proc-macro crate
|
|
rustc().input("poison/lib.rs").crate_name("poison").crate_type("proc-macro").run();
|
|
|
|
let poison_dylib = find_proc_macro_dylib("poison");
|
|
|
|
// Incremental compile with the poison macro active
|
|
let out = rustc()
|
|
.input("foo.rs")
|
|
.crate_type("rlib")
|
|
.incremental("incr")
|
|
.extern_("poison", &poison_dylib)
|
|
.env("POISON_INCR_DIR", "incr")
|
|
.run();
|
|
|
|
out.assert_stderr_contains("note: did not finalize incremental compilation session directory");
|
|
out.assert_stderr_contains(
|
|
"help: the next build will not be able to reuse work from this compilation",
|
|
);
|
|
out.assert_stderr_not_contains("internal compiler error");
|
|
}
|
|
|
|
impl Drop for IncrDirCleanup {
|
|
fn drop(&mut self) {
|
|
let incr = Path::new("incr");
|
|
if !incr.exists() {
|
|
return;
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
restore_permissions(incr);
|
|
}
|
|
}
|
|
|
|
/// Recursively restore write permissions so rm -rf works after the chmod trick
|
|
#[cfg(unix)]
|
|
fn restore_permissions(path: &Path) {
|
|
use std::os::unix::fs::PermissionsExt;
|
|
if let Ok(entries) = fs::read_dir(path) {
|
|
for entry in entries.filter_map(|e| e.ok()) {
|
|
if entry.file_type().map_or(false, |ft| ft.is_dir()) {
|
|
let mut perms = match fs::metadata(entry.path()) {
|
|
Ok(m) => m.permissions(),
|
|
Err(_) => continue,
|
|
};
|
|
perms.set_mode(0o755);
|
|
let _ = fs::set_permissions(entry.path(), perms);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Locate the compiled proc-macro dylib by scanning the current directory.
|
|
fn find_proc_macro_dylib(name: &str) -> PathBuf {
|
|
let prefix = if cfg!(target_os = "windows") { "" } else { "lib" };
|
|
|
|
let ext: &str = if cfg!(target_os = "macos") {
|
|
"dylib"
|
|
} else if cfg!(target_os = "windows") {
|
|
"dll"
|
|
} else {
|
|
"so"
|
|
};
|
|
|
|
let lib_name = format!("{prefix}{name}.{ext}");
|
|
|
|
for entry in fs::read_dir(".").unwrap() {
|
|
let entry = entry.unwrap();
|
|
let name = entry.file_name();
|
|
let name = name.to_str().unwrap();
|
|
if name == lib_name {
|
|
return entry.path();
|
|
}
|
|
}
|
|
|
|
panic!("could not find proc-macro dylib for `{name}`");
|
|
}
|