| //! Regression test for rust-lang/rust#70924. Check that if we add the `rust-src` component in |
| //! between two incremental compiles, that the compiler doesn't ICE on the second invocation. |
| //! |
| //! This test uses symbolic links to save testing time. |
| //! |
| //! The way this test works is that, for every prefix in `root/lib/rustlib/src`, link all of prefix |
| //! parent content, then remove the prefix, then loop on the next prefix. This way, we basically |
| //! create a copy of the context around `root/lib/rustlib/src`, and can freely add/remove the src |
| //! component itself. |
| |
| //@ ignore-cross-compile |
| // Reason: test needs to run. |
| |
| //@ needs-symlink |
| // Reason: test needs symlink to create stub directories and files. |
| |
| use std::path::Path; |
| |
| use run_make_support::rfs::read_dir_entries; |
| use run_make_support::{bare_rustc, path, rfs, run}; |
| |
| #[derive(Debug, Copy, Clone)] |
| struct Symlink<'a, 'b> { |
| src_dir: &'a Path, |
| dst_dir: &'b Path, |
| } |
| |
| fn shallow_symlink_dir<'a, 'b>(Symlink { src_dir, dst_dir }: Symlink<'a, 'b>) { |
| eprintln!( |
| "shallow_symlink_dir: src_dir={} -> dst_dir={}", |
| src_dir.display(), |
| dst_dir.display() |
| ); |
| |
| read_dir_entries(src_dir, |src_path| { |
| let src_metadata = rfs::symlink_metadata(src_path); |
| let filename = src_path.file_name().unwrap(); |
| if src_metadata.is_dir() { |
| rfs::symlink_dir(src_path, dst_dir.join(filename)); |
| } else if src_metadata.is_file() { |
| rfs::symlink_file(src_path, dst_dir.join(filename)); |
| } else if src_metadata.is_symlink() { |
| rfs::copy_symlink(src_path, dst_dir.join(filename)); |
| } |
| }); |
| } |
| |
| fn recreate_dir(path: &Path) { |
| rfs::recursive_remove(path); |
| rfs::create_dir(path); |
| } |
| |
| fn main() { |
| let sysroot = bare_rustc().print("sysroot").run().stdout_utf8(); |
| let sysroot = sysroot.trim(); |
| let sysroot = path(sysroot); |
| |
| let incr = path("incr"); |
| |
| let fakeroot = path("fakeroot"); |
| rfs::create_dir(&fakeroot); |
| |
| shallow_symlink_dir(Symlink { src_dir: &sysroot, dst_dir: &fakeroot }); |
| recreate_dir(&fakeroot.join("lib")); |
| |
| shallow_symlink_dir(Symlink { src_dir: &sysroot.join("lib"), dst_dir: &fakeroot.join("lib") }); |
| recreate_dir(&fakeroot.join("lib").join("rustlib")); |
| |
| shallow_symlink_dir(Symlink { |
| src_dir: &sysroot.join("lib").join("rustlib"), |
| dst_dir: &fakeroot.join("lib").join("rustlib"), |
| }); |
| recreate_dir(&fakeroot.join("lib").join("rustlib").join("src")); |
| |
| shallow_symlink_dir(Symlink { |
| src_dir: &sysroot.join("lib").join("rustlib").join("src"), |
| dst_dir: &fakeroot.join("lib").join("rustlib").join("src"), |
| }); |
| |
| rfs::recursive_remove(&fakeroot.join("lib").join("rustlib").join("src").join("rust")); |
| |
| let run_incr_rustc = || { |
| bare_rustc() |
| .sysroot(&fakeroot) |
| .arg("-C") |
| .arg(format!("incremental={}", incr.to_str().unwrap())) |
| .input("main.rs") |
| .run(); |
| }; |
| |
| // Run rustc w/ incremental once... |
| run_incr_rustc(); |
| |
| // NOTE: the Makefile version of this used `$SYSROOT/lib/rustlib/src/rust/src/libstd/lib.rs`, |
| // but that actually got moved around and reorganized over the years. As of Dec 2024, the |
| // rust-src component is more like (specific for our purposes): |
| // |
| // ``` |
| // $SYSROOT/lib/rustlib/src/rust/ |
| // library/std/src/lib.rs |
| // src/ |
| // ``` |
| rfs::create_dir_all( |
| &fakeroot |
| .join("lib") |
| .join("rustlib") |
| .join("src") |
| .join("rust") |
| .join("library") |
| .join("std") |
| .join("src"), |
| ); |
| rfs::write( |
| &fakeroot |
| .join("lib") |
| .join("rustlib") |
| .join("src") |
| .join("rust") |
| .join("library") |
| .join("std") |
| .join("src") |
| .join("lib.rs"), |
| b"", |
| ); |
| |
| // ... and a second time. |
| run_incr_rustc(); |
| |
| // Basic sanity check that the compiled binary can run. |
| run("main"); |
| } |