Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Break up compiletest runtest.rs into smaller helper modules #130566

Merged
merged 1 commit into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,361 changes: 212 additions & 2,149 deletions src/tools/compiletest/src/runtest.rs
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark: I know this file is still really messy, further changes planned in future PRs.

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions src/tools/compiletest/src/runtest/assembly.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use super::TestCx;

impl TestCx<'_> {
pub(super) fn run_assembly_test(&self) {
if self.config.llvm_filecheck.is_none() {
self.fatal("missing --llvm-filecheck");
}

let (proc_res, output_path) = self.compile_test_and_save_assembly();
if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
}

let proc_res = self.verify_with_filecheck(&output_path);
if !proc_res.status.success() {
self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
}
}
}
22 changes: 22 additions & 0 deletions src/tools/compiletest/src/runtest/codegen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use super::{PassMode, TestCx};

impl TestCx<'_> {
pub(super) fn run_codegen_test(&self) {
if self.config.llvm_filecheck.is_none() {
self.fatal("missing --llvm-filecheck");
}

let (proc_res, output_path) = self.compile_test_and_save_ir();
if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
}

if let Some(PassMode::Build) = self.pass_mode() {
return;
}
let proc_res = self.verify_with_filecheck(&output_path);
if !proc_res.status.success() {
self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
}
}
}
191 changes: 191 additions & 0 deletions src/tools/compiletest/src/runtest/codegen_units.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
use std::collections::HashSet;

use super::{Emit, TestCx, WillExecute};
use crate::errors;
use crate::util::static_regex;

impl TestCx<'_> {
pub(super) fn run_codegen_units_test(&self) {
assert!(self.revision.is_none(), "revisions not relevant here");

let proc_res = self.compile_test(WillExecute::No, Emit::None);

if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
}

self.check_no_compiler_crash(&proc_res, self.props.should_ice);

const PREFIX: &str = "MONO_ITEM ";
const CGU_MARKER: &str = "@@";

// Some MonoItems can contain {closure@/path/to/checkout/tests/codgen-units/test.rs}
// To prevent the current dir from leaking, we just replace the entire path to the test
// file with TEST_PATH.
let actual: Vec<MonoItem> = proc_res
.stdout
.lines()
.filter(|line| line.starts_with(PREFIX))
.map(|line| {
line.replace(&self.testpaths.file.display().to_string(), "TEST_PATH").to_string()
})
.map(|line| str_to_mono_item(&line, true))
.collect();

let expected: Vec<MonoItem> = errors::load_errors(&self.testpaths.file, None)
.iter()
.map(|e| str_to_mono_item(&e.msg[..], false))
.collect();

let mut missing = Vec::new();
let mut wrong_cgus = Vec::new();

for expected_item in &expected {
let actual_item_with_same_name = actual.iter().find(|ti| ti.name == expected_item.name);

if let Some(actual_item) = actual_item_with_same_name {
if !expected_item.codegen_units.is_empty() &&
// Also check for codegen units
expected_item.codegen_units != actual_item.codegen_units
{
wrong_cgus.push((expected_item.clone(), actual_item.clone()));
}
} else {
missing.push(expected_item.string.clone());
}
}

let unexpected: Vec<_> = actual
.iter()
.filter(|acgu| !expected.iter().any(|ecgu| acgu.name == ecgu.name))
.map(|acgu| acgu.string.clone())
.collect();

if !missing.is_empty() {
missing.sort();

println!("\nThese items should have been contained but were not:\n");

for item in &missing {
println!("{}", item);
}

println!("\n");
}

if !unexpected.is_empty() {
let sorted = {
let mut sorted = unexpected.clone();
sorted.sort();
sorted
};

println!("\nThese items were contained but should not have been:\n");

for item in sorted {
println!("{}", item);
}

println!("\n");
}

if !wrong_cgus.is_empty() {
wrong_cgus.sort_by_key(|pair| pair.0.name.clone());
println!("\nThe following items were assigned to wrong codegen units:\n");

for &(ref expected_item, ref actual_item) in &wrong_cgus {
println!("{}", expected_item.name);
println!(" expected: {}", codegen_units_to_str(&expected_item.codegen_units));
println!(" actual: {}", codegen_units_to_str(&actual_item.codegen_units));
println!();
}
}

if !(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty()) {
panic!();
}

#[derive(Clone, Eq, PartialEq)]
struct MonoItem {
name: String,
codegen_units: HashSet<String>,
string: String,
}

// [MONO_ITEM] name [@@ (cgu)+]
fn str_to_mono_item(s: &str, cgu_has_crate_disambiguator: bool) -> MonoItem {
let s = if s.starts_with(PREFIX) { (&s[PREFIX.len()..]).trim() } else { s.trim() };

let full_string = format!("{}{}", PREFIX, s);

let parts: Vec<&str> =
s.split(CGU_MARKER).map(str::trim).filter(|s| !s.is_empty()).collect();

let name = parts[0].trim();

let cgus = if parts.len() > 1 {
let cgus_str = parts[1];

cgus_str
.split(' ')
.map(str::trim)
.filter(|s| !s.is_empty())
.map(|s| {
if cgu_has_crate_disambiguator {
remove_crate_disambiguators_from_set_of_cgu_names(s)
} else {
s.to_string()
}
})
.collect()
} else {
HashSet::new()
};

MonoItem { name: name.to_owned(), codegen_units: cgus, string: full_string }
}

fn codegen_units_to_str(cgus: &HashSet<String>) -> String {
let mut cgus: Vec<_> = cgus.iter().collect();
cgus.sort();

let mut string = String::new();
for cgu in cgus {
string.push_str(&cgu[..]);
string.push(' ');
}

string
}

// Given a cgu-name-prefix of the form <crate-name>.<crate-disambiguator> or
// the form <crate-name1>.<crate-disambiguator1>-in-<crate-name2>.<crate-disambiguator2>,
// remove all crate-disambiguators.
fn remove_crate_disambiguator_from_cgu(cgu: &str) -> String {
let Some(captures) =
static_regex!(r"^[^\.]+(?P<d1>\.[[:alnum:]]+)(-in-[^\.]+(?P<d2>\.[[:alnum:]]+))?")
.captures(cgu)
else {
panic!("invalid cgu name encountered: {cgu}");
};

let mut new_name = cgu.to_owned();

if let Some(d2) = captures.name("d2") {
new_name.replace_range(d2.start()..d2.end(), "");
}

let d1 = captures.name("d1").unwrap();
new_name.replace_range(d1.start()..d1.end(), "");

new_name
}

// The name of merged CGUs is constructed as the names of the original
// CGUs joined with "--". This function splits such composite CGU names
// and handles each component individually.
fn remove_crate_disambiguators_from_set_of_cgu_names(cgus: &str) -> String {
cgus.split("--").map(remove_crate_disambiguator_from_cgu).collect::<Vec<_>>().join("--")
}
}
}
4 changes: 2 additions & 2 deletions src/tools/compiletest/src/runtest/coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl<'test> TestCx<'test> {
.unwrap_or_else(|| self.fatal("missing --coverage-dump"))
}

pub(crate) fn run_coverage_map_test(&self) {
pub(super) fn run_coverage_map_test(&self) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark: changed visibility from pub(crate) -> pub(super) for consistency as it does not need to be visible outside of runtest.rs.

let coverage_dump_path = self.coverage_dump_path();

let (proc_res, llvm_ir_path) = self.compile_test_and_save_ir();
Expand Down Expand Up @@ -50,7 +50,7 @@ impl<'test> TestCx<'test> {
}
}

pub(crate) fn run_coverage_run_test(&self) {
pub(super) fn run_coverage_run_test(&self) {
let should_run = self.run_if_enabled();
let proc_res = self.compile_test(should_run, Emit::None);

Expand Down
25 changes: 25 additions & 0 deletions src/tools/compiletest/src/runtest/crash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use super::{TestCx, WillExecute};

impl TestCx<'_> {
pub(super) fn run_crash_test(&self) {
let pm = self.pass_mode();
let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm));

if std::env::var("COMPILETEST_VERBOSE_CRASHES").is_ok() {
eprintln!("{}", proc_res.status);
eprintln!("{}", proc_res.stdout);
eprintln!("{}", proc_res.stderr);
eprintln!("{}", proc_res.cmdline);
}

// if a test does not crash, consider it an error
if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) {
self.fatal(&format!(
"crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful name, \
add a doc-comment to the start of the test explaining why it exists and \
move it to tests/ui or wherever you see fit. Adding 'Fixes #<issueNr>' to your PR description \
ensures that the corresponding ticket is auto-closed upon merge."
));
}
}
}
Loading
Loading