Skip to content
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
19 changes: 16 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,16 @@ jobs:
"--extended-regex-tests",
"--test-successful-rustc --nb-parts 2 --current-part 0",
"--test-successful-rustc --nb-parts 2 --current-part 1",
"--projects --nb-parts 2 --current-part 0",
"--projects --nb-parts 2 --current-part 1",
"--librsvg-tests",
"--projects --nb-parts 3 --current-part 0",
"--projects --nb-parts 3 --current-part 1",
"--projects --nb-parts 3 --current-part 2",
"--gcc-asm-tests --test-release-libcore",
]
# The checks that don't depend on the test command only run in the fastest job.
include:
- commands: "--extended-rand-tests"
run_checks: true

steps:
- uses: actions/checkout@v4
Expand All @@ -57,7 +63,7 @@ jobs:
sudo apt-get install ninja-build ripgrep llvm-14-tools llvm

- name: Install the libraries needed to build librsvg
if: ${{ contains(matrix.commands, '--projects') }}
if: ${{ contains(matrix.commands, '--librsvg-tests') }}
run: sudo apt-get install libcairo2-dev libpango1.0-dev libfontconfig1-dev libfreetype-dev libharfbuzz-dev libxml2-dev libglib2.0-dev

- name: Download artifact
Expand Down Expand Up @@ -88,28 +94,35 @@ jobs:
#key: ${{ runner.os }}-packages-${{ hashFiles('rust/.git/HEAD') }}

- name: Prepare
if: ${{ matrix.run_checks }}
run: ./y.sh prepare --only-libcore

- name: Check formatting
if: ${{ matrix.run_checks }}
run: ./y.sh fmt --check

- name: Check todo
if: ${{ matrix.run_checks }}
run: ./y.sh check-todo

- name: Check lints
if: ${{ matrix.run_checks }}
run: ./y.sh clippy

- name: Build
if: ${{ matrix.run_checks }}
run: |
./y.sh build --sysroot
./y.sh test --cargo-tests
CARGO_TEST_FLAGS="-Zmir-preserve-ub" ./y.sh test --cargo-tests -- mir_preserve_ub_empty_switch

- name: Run y.sh cargo build
if: ${{ matrix.run_checks }}
run: |
CARGO_PROFILE_DEV_LTO=no ./y.sh cargo build --manifest-path tests/hello-world/Cargo.toml

- name: Clean
if: ${{ matrix.run_checks }}
run: |
./y.sh clean all

Expand Down
218 changes: 141 additions & 77 deletions build_system/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fn get_runners() -> Runners {
runners.insert("--test-failing-rustc", ("Run failing rustc tests", test_failing_rustc));
runners.insert("--run-ui-tests", ("Run specified rustc UI tests", run_ui_tests));
runners.insert("--projects", ("Run the tests of popular crates", test_projects));
runners.insert("--librsvg-tests", ("Run the librsvg tests", test_librsvg));
runners.insert("--test-libcore", ("Run libcore tests", test_libcore));
runners.insert("--test-release-libcore", ("Run libcore tests", test_release_libcore));
runners.insert("--test-libcore-doctests", ("Run libcore doc-tests", test_libcore_doctests));
Expand Down Expand Up @@ -758,95 +759,115 @@ impl Project {
}
}

fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> {
let projects = [
// The reference images assume the exact cairo, pango and freetype that librsvg pins in its
// own CI; this one renders text decorations a pixel off with the versions Ubuntu ships.
Project::new("https://gitlab.gnome.org/GNOME/librsvg")
.test_harness_arguments(&["--skip", "tests::svg1_1_text_text_03_b_svg", "--exact"])
// A debug build of librsvg needs about 5 MB of stack per `cargo test` thread to reach
// its maximum layer nesting depth; librsvg's own CI sets the same value.
.environment_variables(&[("RUST_MIN_STACK", "8388608")]),
Project::new("https://github.com/rust-random/getrandom"),
Project::new("https://github.com/BurntSushi/memchr"),
Project::new("https://github.com/dtolnay/itoa"),
Project::new("https://github.com/rust-lang/cfg-if"),
// The `ui` test compares against the diagnostics of the compiler it was blessed with, so it
// fails on the nightly we use no matter which backend produces the code.
Project::new("https://github.com/rust-lang-nursery/lazy-static.rs")
.test_harness_arguments(&["--skip", "ui", "--exact"]),
Project::new("https://github.com/marshallpierce/rust-base64"),
// The test suite refuses to build unless every feature is enabled; it otherwise spawns a
// nested `cargo test --all-features` which would not use this backend.
Project::new("https://github.com/time-rs/time").cargo_arguments(&["--all-features"]),
Project::new("https://github.com/rust-lang/log"),
Project::new("https://github.com/bitflags/bitflags"),
Project::new("https://github.com/serde-rs/serde"),
Project::new("https://github.com/rayon-rs/rayon"),
// FIXME: too slow to run in the CI: the release build alone takes 46 minutes and the
// `cargo` crate itself needs 5.4 GB of memory in a single rustc process.
//Project::new("https://github.com/rust-lang/cargo"),
];

let mut env = env.clone();
let rustflags =
format!("{} --cap-lints allow", env.get("RUSTFLAGS").cloned().unwrap_or_default());
env.insert("RUSTFLAGS".to_string(), rustflags);
let run_tests =
|projects_path, iter: &mut dyn Iterator<Item = &Project>| -> Result<(), String> {
for project in iter {
let clone_result = git_clone_root_dir(project.url, projects_path, true)?;
let repo_path = Path::new(&clone_result.repo_dir);

let mut project_environment = env.clone();
for (name, value) in project.environment_variables {
project_environment.insert(name.to_string(), value.to_string());
}
// The reference images assume the exact cairo, pango and freetype that librsvg pins in its own CI;
// this one renders text decorations a pixel off with the versions Ubuntu ships.
const LIBRSVG: Project = Project::new("https://gitlab.gnome.org/GNOME/librsvg")
.test_harness_arguments(&["--skip", "tests::svg1_1_text_text_03_b_svg", "--exact"])
// A debug build of librsvg needs about 5 MB of stack per `cargo test` thread to reach its
// maximum layer nesting depth; librsvg's own CI sets the same value.
.environment_variables(&[("RUST_MIN_STACK", "8388608")]);

/// Sorted from the slowest to the fastest in the CI, so that `projects_part` balances the parts.
const PROJECTS: &[Project] = &[
Project::new("https://github.com/marshallpierce/rust-base64"),
Project::new("https://github.com/serde-rs/serde"),
Project::new("https://github.com/rayon-rs/rayon"),
// The test suite refuses to build unless every feature is enabled; it otherwise spawns a
// nested `cargo test --all-features` which would not use this backend.
Project::new("https://github.com/time-rs/time").cargo_arguments(&["--all-features"]),
Project::new("https://github.com/bitflags/bitflags"),
Project::new("https://github.com/dtolnay/itoa"),
// The `ui` test compares against the diagnostics of the compiler it was blessed with, so it
// fails on the nightly we use no matter which backend produces the code.
Project::new("https://github.com/rust-lang-nursery/lazy-static.rs")
.test_harness_arguments(&["--skip", "ui", "--exact"]),
Project::new("https://github.com/BurntSushi/memchr"),
Project::new("https://github.com/rust-lang/log"),
Project::new("https://github.com/rust-random/getrandom"),
Project::new("https://github.com/rust-lang/cfg-if"),
// FIXME: too slow to run in the CI: the release build alone takes 46 minutes and the
// `cargo` crate itself needs 5.4 GB of memory in a single rustc process.
//Project::new("https://github.com/rust-lang/cargo"),
];

fn test_project(
project: &Project,
projects_path: &Path,
env: &Env,
args: &TestArg,
) -> Result<(), String> {
let clone_result = git_clone_root_dir(project.url, projects_path, true)?;
let repo_path = Path::new(&clone_result.repo_dir);

let mut build_command: Vec<&dyn AsRef<OsStr>> = vec![&"build", &"--release"];
build_command.extend(
project.cargo_arguments.iter().map(|argument| argument as &dyn AsRef<OsStr>),
);
run_cargo_command(&build_command, Some(repo_path), &project_environment, args)?;
let mut project_environment = env.clone();
let rustflags = format!(
"{} --cap-lints allow",
project_environment.get("RUSTFLAGS").cloned().unwrap_or_default()
);
project_environment.insert("RUSTFLAGS".to_string(), rustflags);
for (name, value) in project.environment_variables {
project_environment.insert(name.to_string(), value.to_string());
}

let mut test_command: Vec<&dyn AsRef<OsStr>> = vec![&"test"];
test_command.extend(
project.cargo_arguments.iter().map(|argument| argument as &dyn AsRef<OsStr>),
);
if !project.test_harness_arguments.is_empty() {
test_command.push(&"--");
test_command.extend(
project
.test_harness_arguments
.iter()
.map(|argument| argument as &dyn AsRef<OsStr>),
);
}
run_cargo_command(&test_command, Some(repo_path), &project_environment, args)?;
}
let mut build_command: Vec<&dyn AsRef<OsStr>> = vec![&"build", &"--release"];
build_command
.extend(project.cargo_arguments.iter().map(|argument| argument as &dyn AsRef<OsStr>));
run_cargo_command(&build_command, Some(repo_path), &project_environment, args)?;

let mut test_command: Vec<&dyn AsRef<OsStr>> = vec![&"test"];
test_command
.extend(project.cargo_arguments.iter().map(|argument| argument as &dyn AsRef<OsStr>));
if !project.test_harness_arguments.is_empty() {
test_command.push(&"--");
test_command.extend(
project.test_harness_arguments.iter().map(|argument| argument as &dyn AsRef<OsStr>),
);
}
run_cargo_command(&test_command, Some(repo_path), &project_environment, args)
}

Ok(())
};
/// Returns the projects of `current_part` when `projects` is dealt out to `nb_parts` parts back and
/// forth (0, 1, 2, 2, 1, 0, 0, ...), which spreads the slowest projects over different parts.
fn projects_part(projects: &[Project], nb_parts: usize, current_part: usize) -> Vec<&Project> {
projects
.iter()
.enumerate()
.filter(|(index, _)| {
let position = index % nb_parts;
let part = if (index / nb_parts).is_multiple_of(2) {
position
} else {
nb_parts - 1 - position
};
part == current_part
})
.map(|(_, project)| project)
.collect()
}

fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> {
let projects_path = Path::new("projects");
create_dir(projects_path)?;

let nb_parts = args.nb_parts.unwrap_or(0);
if let Some(count) = projects.len().checked_div(nb_parts) {
// We increment the number of tests by one because if this is an odd number, we would skip
// one test.
let count = count + 1;
let current_part = args.current_part.unwrap();
let start = current_part * count;
// We remove the projects we don't want to test.
run_tests(projects_path, &mut projects.iter().skip(start).take(count))?;
} else {
run_tests(projects_path, &mut projects.iter())?;
let projects = match (args.nb_parts, args.current_part) {
(Some(nb_parts), Some(current_part)) if nb_parts > 0 => {
projects_part(PROJECTS, nb_parts, current_part)
}
_ => PROJECTS.iter().collect(),
};
for project in projects {
test_project(project, projects_path, env, args)?;
}

Ok(())
}

fn test_librsvg(env: &Env, args: &TestArg) -> Result<(), String> {
let projects_path = Path::new("projects");
create_dir(projects_path)?;
test_project(&LIBRSVG, projects_path, env, args)
}

fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
test_libcore_inner(env, args, false)
}
Expand Down Expand Up @@ -1744,4 +1765,47 @@ mod tests {

remove_dir_all(&rust_path).unwrap();
}

#[test]
fn test_projects_parts_cover_every_project() {
let mut all_urls: Vec<&str> = PROJECTS.iter().map(|project| project.url).collect();
all_urls.sort_unstable();
for nb_parts in 1..=PROJECTS.len() + 1 {
let mut parts_urls: Vec<&str> = (0..nb_parts)
.flat_map(|current_part| projects_part(PROJECTS, nb_parts, current_part))
.map(|project| project.url)
.collect();
parts_urls.sort_unstable();
assert_eq!(parts_urls, all_urls, "splitting into {nb_parts} parts");
}
}

// Each round deals one project per part, every other round in reverse, so the slowest
// projects at the front of the list never share a part.
#[test]
fn test_projects_part_deals_back_and_forth() {
const PROJECTS: &[Project] = &[
Project::new("0"),
Project::new("1"),
Project::new("2"),
Project::new("3"),
Project::new("4"),
Project::new("5"),
Project::new("6"),
];
let part = |nb_parts, current_part| -> Vec<&str> {
projects_part(PROJECTS, nb_parts, current_part)
.iter()
.map(|project| project.url)
.collect()
};

assert_eq!(part(3, 0), ["0", "5", "6"]);
assert_eq!(part(3, 1), ["1", "4"]);
assert_eq!(part(3, 2), ["2", "3"]);

assert_eq!(part(1, 0), ["0", "1", "2", "3", "4", "5", "6"]);
assert_eq!(part(8, 6), ["6"]);
assert!(part(8, 7).is_empty());
}
}
2 changes: 1 addition & 1 deletion src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> {
let is_thread_local = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
let global = self.get_static_inner(def_id, val_llty);

debug_assert_eq!(
assert_eq!(
global.to_rvalue().get_type(),
val_llty,
"`predefine_static` declared this global with a type its initializer does not have"
Expand Down
Loading