test async closure reproducibility with the parallel frontend
diff --git a/tests/run-make/parallel-reproducible-by-move-body/by-move-body.rs b/tests/run-make/parallel-reproducible-by-move-body/by-move-body.rs new file mode 100644 index 0000000..5e9eff2 --- /dev/null +++ b/tests/run-make/parallel-reproducible-by-move-body/by-move-body.rs
@@ -0,0 +1,7 @@ +pub fn f1() { + let _ = async || {}; +} + +pub fn f2() { + let _ = async || {}; +}
diff --git a/tests/run-make/parallel-reproducible-by-move-body/rmake.rs b/tests/run-make/parallel-reproducible-by-move-body/rmake.rs new file mode 100644 index 0000000..3e464c2 --- /dev/null +++ b/tests/run-make/parallel-reproducible-by-move-body/rmake.rs
@@ -0,0 +1,65 @@ +//@ needs-target-std +//@ ignore-cross-compile +//@ ignore-windows-gnu +// GNU Linker for Windows is non-deterministic. (from `reproducible-build-2` test in this suite) + +use std::rc::Rc; + +use run_make_support::{rfs, run_in_tmpdir, rustc}; + +/// Test that parallel compiler produces identical metadata for the +/// `DefId`s synthesized on demand by `coroutine_by_move_body_def_id` +/// (`DefKind::SyntheticCoroutineBody`), across many async closures that +/// each need one. +fn main() { + const FILE_NAME: &str = "by-move-body"; + let rmeta_name = format!("{FILE_NAME}.rmeta"); + + let mut reference = None; + let mut reference_stderr = None; + + for _ in 0..10 { + // Tmp dir as previous runs affect output binary on windows. + run_in_tmpdir(|| { + let mut rustc = rustc(); + rustc + .input(format!("{FILE_NAME}.rs")) + .arg("--edition=2021") + .arg("-Zremap-cwd-prefix=reproducible_dir") + .arg("-Ccodegen-units=1") + .arg("-Zthreads=2") + .arg("--crate-type=lib") + .emit("metadata") + .output(&rmeta_name); + + let current_stderr = rustc.run().stderr_utf8(); + + let current = Rc::new(rfs::read(&rmeta_name)); + reference.get_or_insert(Rc::clone(¤t)); + let reference_stderr = reference_stderr.get_or_insert_with(|| current_stderr.clone()); + + if Some(current.clone()) != reference { + let reference_bytes = reference.as_ref().unwrap(); + let (pos, (left_byte, right_byte)) = current + .iter() + .zip(reference_bytes.iter()) + .enumerate() + .find(|(_, (c, r))| c != r) + .unwrap(); + let range_start = pos.saturating_sub(1); + let range_end = (pos + 3).min(current.len()).min(reference_bytes.len()); + panic!( + "left: {current:x?}\nright: {reference:x?}\n \ + differs at byte {pos}: left = {left_byte:#x}, right = {right_byte:#x}\n\ + left range [{range_start}..{range_end}]: {:x?}\n\ + right range [{range_start}..{range_end}]: {:x?}\n\ + left stderr:\n{current_stderr}\n\ + right stderr:\n{reference_stderr}", + ¤t[range_start..range_end], + &reference_bytes[range_start..range_end], + ) + } + assert_eq!(Some(current), reference); + }); + } +}