|
| 1 | +//@ ignore-cross-compile |
| 2 | +//@ needs-crate-type: proc-macro |
| 3 | + |
| 4 | +//! Test that a failure to finalize the incremental compilation session directory |
| 5 | +//! (i.e., the rename from "-working" to the SVH-based name) results in a |
| 6 | +//! note, not an ICE, and that the compilation output is still produced. |
| 7 | +//! |
| 8 | +//! Strategy: |
| 9 | +//! 1. Build the `poison` proc-macro crate |
| 10 | +//! 2. Compile foo.rs with incremental compilation |
| 11 | +//! The proc macro runs mid-compilation (after prepare_session_directory |
| 12 | +//! but before finalize_session_directory) and sabotages the rename: |
| 13 | +//! - On Unix: removes write permission from the crate directory, |
| 14 | +//! so rename() fails with EACCES. |
| 15 | +//! - On Windows: creates and leaks an open file handle inside the |
| 16 | +//! -working directory, so rename() fails with ERROR_ACCESS_DENIED. |
| 17 | +//! 3. Assert that stderr contains the finalize failure messages |
| 18 | +
|
| 19 | +use std::fs; |
| 20 | +use std::path::{Path, PathBuf}; |
| 21 | + |
| 22 | +use run_make_support::rustc; |
| 23 | + |
| 24 | +/// Guard that restores permissions on the incremental directory on drop, |
| 25 | +/// to ensure cleanup is possible |
| 26 | +struct IncrDirCleanup; |
| 27 | + |
| 28 | +fn main() { |
| 29 | + let _cleanup = IncrDirCleanup; |
| 30 | + |
| 31 | + // Build the poison proc-macro crate |
| 32 | + rustc().input("poison/lib.rs").crate_name("poison").crate_type("proc-macro").run(); |
| 33 | + |
| 34 | + let poison_dylib = find_proc_macro_dylib("poison"); |
| 35 | + |
| 36 | + // Incremental compile with the poison macro active |
| 37 | + let out = rustc() |
| 38 | + .input("foo.rs") |
| 39 | + .crate_type("rlib") |
| 40 | + .incremental("incr") |
| 41 | + .extern_("poison", &poison_dylib) |
| 42 | + .env("POISON_INCR_DIR", "incr") |
| 43 | + .run(); |
| 44 | + |
| 45 | + out.assert_stderr_contains("note: did not finalize incremental compilation session directory"); |
| 46 | + out.assert_stderr_contains( |
| 47 | + "help: the next build will not be able to reuse work from this compilation", |
| 48 | + ); |
| 49 | + out.assert_stderr_not_contains("internal compiler error"); |
| 50 | +} |
| 51 | + |
| 52 | +impl Drop for IncrDirCleanup { |
| 53 | + fn drop(&mut self) { |
| 54 | + let incr = Path::new("incr"); |
| 55 | + if !incr.exists() { |
| 56 | + return; |
| 57 | + } |
| 58 | + |
| 59 | + #[cfg(unix)] |
| 60 | + restore_permissions(incr); |
| 61 | + } |
| 62 | +} |
| 63 | + |
| 64 | +/// Recursively restore write permissions so rm -rf works after the chmod trick |
| 65 | +#[cfg(unix)] |
| 66 | +fn restore_permissions(path: &Path) { |
| 67 | + use std::os::unix::fs::PermissionsExt; |
| 68 | + if let Ok(entries) = fs::read_dir(path) { |
| 69 | + for entry in entries.filter_map(|e| e.ok()) { |
| 70 | + if entry.file_type().map_or(false, |ft| ft.is_dir()) { |
| 71 | + let mut perms = match fs::metadata(entry.path()) { |
| 72 | + Ok(m) => m.permissions(), |
| 73 | + Err(_) => continue, |
| 74 | + }; |
| 75 | + perms.set_mode(0o755); |
| 76 | + let _ = fs::set_permissions(entry.path(), perms); |
| 77 | + } |
| 78 | + } |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +/// Locate the compiled proc-macro dylib by scanning the current directory. |
| 83 | +fn find_proc_macro_dylib(name: &str) -> PathBuf { |
| 84 | + let prefix = if cfg!(target_os = "windows") { "" } else { "lib" }; |
| 85 | + |
| 86 | + let ext: &str = if cfg!(target_os = "macos") { |
| 87 | + "dylib" |
| 88 | + } else if cfg!(target_os = "windows") { |
| 89 | + "dll" |
| 90 | + } else { |
| 91 | + "so" |
| 92 | + }; |
| 93 | + |
| 94 | + let lib_name = format!("{prefix}{name}.{ext}"); |
| 95 | + |
| 96 | + for entry in fs::read_dir(".").unwrap() { |
| 97 | + let entry = entry.unwrap(); |
| 98 | + let name = entry.file_name(); |
| 99 | + let name = name.to_str().unwrap(); |
| 100 | + if name == lib_name { |
| 101 | + return entry.path(); |
| 102 | + } |
| 103 | + } |
| 104 | + |
| 105 | + panic!("could not find proc-macro dylib for `{name}`"); |
| 106 | +} |
0 commit comments