]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/build_system/tests.rs
Auto merge of #106938 - GuillaumeGomez:normalize-projection-field-ty, r=oli-obk
[rust.git] / compiler / rustc_codegen_cranelift / build_system / tests.rs
1 use super::bench::SIMPLE_RAYTRACER;
2 use super::build_sysroot::{self, SYSROOT_SRC};
3 use super::config;
4 use super::path::{Dirs, RelPath};
5 use super::prepare::GitRepo;
6 use super::rustc_info::get_host_triple;
7 use super::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler};
8 use super::SysrootKind;
9 use std::env;
10 use std::ffi::OsStr;
11 use std::fs;
12 use std::path::Path;
13 use std::process::Command;
14
15 static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
16
17 struct TestCase {
18     config: &'static str,
19     cmd: TestCaseCmd,
20 }
21
22 enum TestCaseCmd {
23     Custom { func: &'static dyn Fn(&TestRunner) },
24     BuildLib { source: &'static str, crate_types: &'static str },
25     BuildBinAndRun { source: &'static str, args: &'static [&'static str] },
26     JitBin { source: &'static str, args: &'static str },
27 }
28
29 impl TestCase {
30     // FIXME reduce usage of custom test case commands
31     const fn custom(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
32         Self { config, cmd: TestCaseCmd::Custom { func } }
33     }
34
35     const fn build_lib(
36         config: &'static str,
37         source: &'static str,
38         crate_types: &'static str,
39     ) -> Self {
40         Self { config, cmd: TestCaseCmd::BuildLib { source, crate_types } }
41     }
42
43     const fn build_bin_and_run(
44         config: &'static str,
45         source: &'static str,
46         args: &'static [&'static str],
47     ) -> Self {
48         Self { config, cmd: TestCaseCmd::BuildBinAndRun { source, args } }
49     }
50
51     const fn jit_bin(config: &'static str, source: &'static str, args: &'static str) -> Self {
52         Self { config, cmd: TestCaseCmd::JitBin { source, args } }
53     }
54 }
55
56 const NO_SYSROOT_SUITE: &[TestCase] = &[
57     TestCase::build_lib("build.mini_core", "example/mini_core.rs", "lib,dylib"),
58     TestCase::build_lib("build.example", "example/example.rs", "lib"),
59     TestCase::jit_bin("jit.mini_core_hello_world", "example/mini_core_hello_world.rs", "abc bcd"),
60     TestCase::build_bin_and_run(
61         "aot.mini_core_hello_world",
62         "example/mini_core_hello_world.rs",
63         &["abc", "bcd"],
64     ),
65 ];
66
67 const BASE_SYSROOT_SUITE: &[TestCase] = &[
68     TestCase::build_bin_and_run(
69         "aot.arbitrary_self_types_pointers_and_wrappers",
70         "example/arbitrary_self_types_pointers_and_wrappers.rs",
71         &[],
72     ),
73     TestCase::build_bin_and_run(
74         "aot.issue_91827_extern_types",
75         "example/issue-91827-extern-types.rs",
76         &[],
77     ),
78     TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"),
79     TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]),
80     TestCase::jit_bin("jit.std_example", "example/std_example.rs", ""),
81     TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]),
82     TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]),
83     TestCase::build_bin_and_run(
84         "aot.subslice-patterns-const-eval",
85         "example/subslice-patterns-const-eval.rs",
86         &[],
87     ),
88     TestCase::build_bin_and_run(
89         "aot.track-caller-attribute",
90         "example/track-caller-attribute.rs",
91         &[],
92     ),
93     TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]),
94     TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]),
95     TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
96 ];
97
98 pub(crate) static RAND_REPO: GitRepo =
99     GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
100
101 pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
102
103 pub(crate) static REGEX_REPO: GitRepo =
104     GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
105
106 pub(crate) static REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir(), "regex");
107
108 pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
109     "rust-lang",
110     "portable-simd",
111     "582239ac3b32007613df04d7ffa78dc30f4c5645",
112     "portable-simd",
113 );
114
115 pub(crate) static PORTABLE_SIMD: CargoProject =
116     CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable_simd");
117
118 pub(crate) static LIBCORE_TESTS: CargoProject =
119     CargoProject::new(&SYSROOT_SRC.join("library/core/tests"), "core_tests");
120
121 const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
122     TestCase::custom("test.rust-random/rand", &|runner| {
123         RAND.clean(&runner.dirs);
124
125         if runner.is_native {
126             eprintln!("[TEST] rust-random/rand");
127             let mut test_cmd = RAND.test(&runner.target_compiler, &runner.dirs);
128             test_cmd.arg("--workspace");
129             spawn_and_wait(test_cmd);
130         } else {
131             eprintln!("[AOT] rust-random/rand");
132             let mut build_cmd = RAND.build(&runner.target_compiler, &runner.dirs);
133             build_cmd.arg("--workspace").arg("--tests");
134             spawn_and_wait(build_cmd);
135         }
136     }),
137     TestCase::custom("test.simple-raytracer", &|runner| {
138         SIMPLE_RAYTRACER.clean(&runner.dirs);
139         spawn_and_wait(SIMPLE_RAYTRACER.build(&runner.target_compiler, &runner.dirs));
140     }),
141     TestCase::custom("test.libcore", &|runner| {
142         LIBCORE_TESTS.clean(&runner.dirs);
143
144         if runner.is_native {
145             spawn_and_wait(LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs));
146         } else {
147             eprintln!("Cross-Compiling: Not running tests");
148             let mut build_cmd = LIBCORE_TESTS.build(&runner.target_compiler, &runner.dirs);
149             build_cmd.arg("--tests");
150             spawn_and_wait(build_cmd);
151         }
152     }),
153     TestCase::custom("test.regex-shootout-regex-dna", &|runner| {
154         REGEX.clean(&runner.dirs);
155
156         // newer aho_corasick versions throw a deprecation warning
157         let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
158
159         let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
160         build_cmd.arg("--example").arg("shootout-regex-dna");
161         build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
162         spawn_and_wait(build_cmd);
163
164         if runner.is_native {
165             let mut run_cmd = REGEX.run(&runner.target_compiler, &runner.dirs);
166             run_cmd.arg("--example").arg("shootout-regex-dna");
167             run_cmd.env("RUSTFLAGS", lint_rust_flags);
168
169             let input = fs::read_to_string(
170                 REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-input.txt"),
171             )
172             .unwrap();
173             let expected = fs::read_to_string(
174                 REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt"),
175             )
176             .unwrap();
177
178             let output = spawn_and_wait_with_input(run_cmd, input);
179             // Make sure `[codegen mono items] start` doesn't poison the diff
180             let output = output
181                 .lines()
182                 .filter(|line| !line.contains("codegen mono items"))
183                 .chain(Some("")) // This just adds the trailing newline
184                 .collect::<Vec<&str>>()
185                 .join("\r\n");
186
187             let output_matches = expected.lines().eq(output.lines());
188             if !output_matches {
189                 println!("Output files don't match!");
190                 println!("Expected Output:\n{}", expected);
191                 println!("Actual Output:\n{}", output);
192
193                 std::process::exit(1);
194             }
195         }
196     }),
197     TestCase::custom("test.regex", &|runner| {
198         REGEX.clean(&runner.dirs);
199
200         // newer aho_corasick versions throw a deprecation warning
201         let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
202
203         if runner.is_native {
204             let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs);
205             run_cmd.args([
206                 "--tests",
207                 "--",
208                 "--exclude-should-panic",
209                 "--test-threads",
210                 "1",
211                 "-Zunstable-options",
212                 "-q",
213             ]);
214             run_cmd.env("RUSTFLAGS", lint_rust_flags);
215             spawn_and_wait(run_cmd);
216         } else {
217             eprintln!("Cross-Compiling: Not running tests");
218             let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
219             build_cmd.arg("--tests");
220             build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
221             spawn_and_wait(build_cmd);
222         }
223     }),
224     TestCase::custom("test.portable-simd", &|runner| {
225         PORTABLE_SIMD.clean(&runner.dirs);
226
227         let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs);
228         build_cmd.arg("--all-targets");
229         spawn_and_wait(build_cmd);
230
231         if runner.is_native {
232             let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs);
233             test_cmd.arg("-q");
234             spawn_and_wait(test_cmd);
235         }
236     }),
237 ];
238
239 pub(crate) fn run_tests(
240     dirs: &Dirs,
241     channel: &str,
242     sysroot_kind: SysrootKind,
243     cg_clif_dylib: &Path,
244     bootstrap_host_compiler: &Compiler,
245     target_triple: String,
246 ) {
247     if config::get_bool("testsuite.no_sysroot") {
248         let target_compiler = build_sysroot::build_sysroot(
249             dirs,
250             channel,
251             SysrootKind::None,
252             cg_clif_dylib,
253             bootstrap_host_compiler,
254             target_triple.clone(),
255         );
256
257         let runner =
258             TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
259
260         BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
261         runner.run_testsuite(NO_SYSROOT_SUITE);
262     } else {
263         eprintln!("[SKIP] no_sysroot tests");
264     }
265
266     let run_base_sysroot = config::get_bool("testsuite.base_sysroot");
267     let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot");
268
269     if run_base_sysroot || run_extended_sysroot {
270         let target_compiler = build_sysroot::build_sysroot(
271             dirs,
272             channel,
273             sysroot_kind,
274             cg_clif_dylib,
275             bootstrap_host_compiler,
276             target_triple.clone(),
277         );
278
279         let runner =
280             TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
281
282         if run_base_sysroot {
283             runner.run_testsuite(BASE_SYSROOT_SUITE);
284         } else {
285             eprintln!("[SKIP] base_sysroot tests");
286         }
287
288         if run_extended_sysroot {
289             runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
290         } else {
291             eprintln!("[SKIP] extended_sysroot tests");
292         }
293     }
294 }
295
296 struct TestRunner {
297     is_native: bool,
298     jit_supported: bool,
299     dirs: Dirs,
300     target_compiler: Compiler,
301 }
302
303 impl TestRunner {
304     pub fn new(dirs: Dirs, mut target_compiler: Compiler, is_native: bool) -> Self {
305         if let Ok(rustflags) = env::var("RUSTFLAGS") {
306             target_compiler.rustflags.push(' ');
307             target_compiler.rustflags.push_str(&rustflags);
308         }
309         if let Ok(rustdocflags) = env::var("RUSTDOCFLAGS") {
310             target_compiler.rustdocflags.push(' ');
311             target_compiler.rustdocflags.push_str(&rustdocflags);
312         }
313
314         // FIXME fix `#[linkage = "extern_weak"]` without this
315         if target_compiler.triple.contains("darwin") {
316             target_compiler.rustflags.push_str(" -Clink-arg=-undefined -Clink-arg=dynamic_lookup");
317         }
318
319         let jit_supported = is_native
320             && target_compiler.triple.contains("x86_64")
321             && !target_compiler.triple.contains("windows");
322
323         Self { is_native, jit_supported, dirs, target_compiler }
324     }
325
326     pub fn run_testsuite(&self, tests: &[TestCase]) {
327         for TestCase { config, cmd } in tests {
328             let (tag, testname) = config.split_once('.').unwrap();
329             let tag = tag.to_uppercase();
330             let is_jit_test = tag == "JIT";
331
332             if !config::get_bool(config) || (is_jit_test && !self.jit_supported) {
333                 eprintln!("[{tag}] {testname} (skipped)");
334                 continue;
335             } else {
336                 eprintln!("[{tag}] {testname}");
337             }
338
339             match *cmd {
340                 TestCaseCmd::Custom { func } => func(self),
341                 TestCaseCmd::BuildLib { source, crate_types } => {
342                     self.run_rustc([source, "--crate-type", crate_types]);
343                 }
344                 TestCaseCmd::BuildBinAndRun { source, args } => {
345                     self.run_rustc([source]);
346                     self.run_out_command(
347                         source.split('/').last().unwrap().split('.').next().unwrap(),
348                         args,
349                     );
350                 }
351                 TestCaseCmd::JitBin { source, args } => {
352                     let mut jit_cmd = self.rustc_command([
353                         "-Zunstable-options",
354                         "-Cllvm-args=mode=jit",
355                         "-Cprefer-dynamic",
356                         source,
357                         "--cfg",
358                         "jit",
359                     ]);
360                     if !args.is_empty() {
361                         jit_cmd.env("CG_CLIF_JIT_ARGS", args);
362                     }
363                     spawn_and_wait(jit_cmd);
364
365                     eprintln!("[JIT-lazy] {testname}");
366                     let mut jit_cmd = self.rustc_command([
367                         "-Zunstable-options",
368                         "-Cllvm-args=mode=jit-lazy",
369                         "-Cprefer-dynamic",
370                         source,
371                         "--cfg",
372                         "jit",
373                     ]);
374                     if !args.is_empty() {
375                         jit_cmd.env("CG_CLIF_JIT_ARGS", args);
376                     }
377                     spawn_and_wait(jit_cmd);
378                 }
379             }
380         }
381     }
382
383     #[must_use]
384     fn rustc_command<I, S>(&self, args: I) -> Command
385     where
386         I: IntoIterator<Item = S>,
387         S: AsRef<OsStr>,
388     {
389         let mut cmd = Command::new(&self.target_compiler.rustc);
390         cmd.args(self.target_compiler.rustflags.split_whitespace());
391         cmd.arg("-L");
392         cmd.arg(format!("crate={}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
393         cmd.arg("--out-dir");
394         cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
395         cmd.arg("-Cdebuginfo=2");
396         cmd.arg("--target");
397         cmd.arg(&self.target_compiler.triple);
398         cmd.arg("-Cpanic=abort");
399         cmd.args(args);
400         cmd
401     }
402
403     fn run_rustc<I, S>(&self, args: I)
404     where
405         I: IntoIterator<Item = S>,
406         S: AsRef<OsStr>,
407     {
408         spawn_and_wait(self.rustc_command(args));
409     }
410
411     fn run_out_command<'a>(&self, name: &str, args: &[&str]) {
412         let mut full_cmd = vec![];
413
414         // Prepend the RUN_WRAPPER's
415         if !self.target_compiler.runner.is_empty() {
416             full_cmd.extend(self.target_compiler.runner.iter().cloned());
417         }
418
419         full_cmd.push(
420             BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(),
421         );
422
423         for arg in args {
424             full_cmd.push(arg.to_string());
425         }
426
427         let mut cmd_iter = full_cmd.into_iter();
428         let first = cmd_iter.next().unwrap();
429
430         let mut cmd = Command::new(first);
431         cmd.args(cmd_iter);
432
433         spawn_and_wait(cmd);
434     }
435 }