Rollup merge of #143823 - jieyouxu:compiletest-maintenance-5, r=Kobzol

[COMPILETEST-UNTANGLE 5/N] Test mode adjustments and other assorted cleanups

This is part of a patch series to untangle `compiletest` to hopefully nudge it towards being more maintainable.

This PR should contain no functional changes modulo the removed debugger version warning.

- Commit 1: Removes a very outdated debugger version warning.
- Commit 2: Moves `string_enum` out of `common` into `util` module.
- Commit 3: Remove `#[derive(Default)` for `Mode` and `Config`. It is very important for correctness that we *don't* `#[derive(Default)]`, because there are no sensible defaults, so stop pretending there is.
- Commit 4: Rename `Mode` -> `TestMode`, because I would like to introduce a `TestSuite` enum to stop using stringly-typed test suite names where test mode names can be the same as test suite names, and we also have a bunch of other "modes" in compiletest. Make this as unambiguous as possible. A corollary is that now it's more natural to reference via intra-doc links as ``[`TestMode`]``.
- Commit 5: Ditto on `TestSuite`, stop glob-reexporting `TestMode::*` variants, and always use `EnumName::VariantName` form.
- Commit 6: Apparently, `src/tools/rustdoc-gui-test/` depends on `compiletest` for `//@ {compile,run}-paths` directive parsing and extraction, which involves creating a dummy `compiletest` config (hence the existence of the default impls removed in Commit 3). Make this a specific associated function with a FIXME pointing to rust-lang/rust#143827 as I think this setup is quite questionable.

Commits {4, 5} are also intended to help improve the self-consistency in nomenclature used within compiletest.

Best reviewed commit-by-commit.
This commit is contained in:
León Orell Valerian Liehr 2025-07-13 07:21:25 +02:00 committed by GitHub
commit bb330bbc50
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 253 additions and 168 deletions

View File

@ -1,63 +1,20 @@
use std::collections::{BTreeSet, HashMap, HashSet};
use std::iter;
use std::process::Command;
use std::str::FromStr;
use std::sync::OnceLock;
use std::{fmt, iter};
use build_helper::git::GitConfig;
use camino::{Utf8Path, Utf8PathBuf};
use semver::Version;
use serde::de::{Deserialize, Deserializer, Error as _};
pub use self::Mode::*;
use crate::executor::{ColorConfig, OutputFormat};
use crate::fatal;
use crate::util::{Utf8PathBufExt, add_dylib_path};
macro_rules! string_enum {
($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => {
$(#[$meta])*
$vis enum $name {
$($variant,)*
}
impl $name {
$vis const VARIANTS: &'static [Self] = &[$(Self::$variant,)*];
$vis const STR_VARIANTS: &'static [&'static str] = &[$(Self::$variant.to_str(),)*];
$vis const fn to_str(&self) -> &'static str {
match self {
$(Self::$variant => $repr,)*
}
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.to_str(), f)
}
}
impl FromStr for $name {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
$($repr => Ok(Self::$variant),)*
_ => Err(format!(concat!("unknown `", stringify!($name), "` variant: `{}`"), s)),
}
}
}
}
}
// Make the macro visible outside of this module, for tests.
#[cfg(test)]
pub(crate) use string_enum;
use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum};
string_enum! {
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Mode {
pub enum TestMode {
Pretty => "pretty",
DebugInfo => "debuginfo",
Codegen => "codegen",
@ -76,18 +33,12 @@ string_enum! {
}
}
impl Default for Mode {
fn default() -> Self {
Mode::Ui
}
}
impl Mode {
impl TestMode {
pub fn aux_dir_disambiguator(self) -> &'static str {
// Pretty-printing tests could run concurrently, and if they do,
// they need to keep their output segregated.
match self {
Pretty => ".pretty",
TestMode::Pretty => ".pretty",
_ => "",
}
}
@ -96,7 +47,7 @@ impl Mode {
// Coverage tests use the same test files for multiple test modes,
// so each mode should have a separate output directory.
match self {
CoverageMap | CoverageRun => self.to_str(),
TestMode::CoverageMap | TestMode::CoverageRun => self.to_str(),
_ => "",
}
}
@ -193,9 +144,9 @@ pub enum Sanitizer {
///
/// FIXME: audit these options to make sure we are not hashing less than necessary for build stamp
/// (for changed test detection).
#[derive(Debug, Default, Clone)]
#[derive(Debug, Clone)]
pub struct Config {
/// Some test [`Mode`]s support [snapshot testing], where a *reference snapshot* of outputs (of
/// Some [`TestMode`]s support [snapshot testing], where a *reference snapshot* of outputs (of
/// `stdout`, `stderr`, or other form of artifacts) can be compared to the *actual output*.
///
/// This option can be set to `true` to update the *reference snapshots* in-place, otherwise
@ -317,20 +268,20 @@ pub struct Config {
/// FIXME: reconsider this string; this is hashed for test build stamp.
pub stage_id: String,
/// The test [`Mode`]. E.g. [`Mode::Ui`]. Each test mode can correspond to one or more test
/// The [`TestMode`]. E.g. [`TestMode::Ui`]. Each test mode can correspond to one or more test
/// suites.
///
/// FIXME: stop using stringly-typed test suites!
pub mode: Mode,
pub mode: TestMode,
/// The test suite.
///
/// Example: `tests/ui/` is the "UI" test *suite*, which happens to also be of the [`Mode::Ui`]
/// test *mode*.
/// Example: `tests/ui/` is the "UI" test *suite*, which happens to also be of the
/// [`TestMode::Ui`] test *mode*.
///
/// Note that the same test directory (e.g. `tests/coverage/`) may correspond to multiple test
/// modes, e.g. `tests/coverage/` can be run under both [`Mode::CoverageRun`] and
/// [`Mode::CoverageMap`].
/// modes, e.g. `tests/coverage/` can be run under both [`TestMode::CoverageRun`] and
/// [`TestMode::CoverageMap`].
///
/// FIXME: stop using stringly-typed test suites!
pub suite: String,
@ -586,8 +537,8 @@ pub struct Config {
// Configuration for various run-make tests frobbing things like C compilers or querying about
// various LLVM component information.
//
// FIXME: this really should be better packaged together.
// FIXME: these need better docs, e.g. for *host*, or for *target*?
// FIXME: this really should be better packaged together. FIXME: these need better docs, e.g.
// for *host*, or for *target*?
pub cc: String,
pub cxx: String,
pub cflags: String,
@ -653,6 +604,107 @@ pub struct Config {
}
impl Config {
/// Incomplete config intended for `src/tools/rustdoc-gui-test` **only** as
/// `src/tools/rustdoc-gui-test` wants to reuse `compiletest`'s directive -> test property
/// handling for `//@ {compile,run}-flags`, do not use for any other purpose.
///
/// FIXME(#143827): this setup feels very hacky. It so happens that `tests/rustdoc-gui/`
/// **only** uses `//@ {compile,run}-flags` for now and not any directives that actually rely on
/// info that is assumed available in a fully populated [`Config`].
pub fn incomplete_for_rustdoc_gui_test() -> Config {
// FIXME(#143827): spelling this out intentionally, because this is questionable.
//
// For instance, `//@ ignore-stage1` will not work at all.
Config {
mode: TestMode::Rustdoc,
// Dummy values.
edition: Default::default(),
bless: Default::default(),
fail_fast: Default::default(),
compile_lib_path: Utf8PathBuf::default(),
run_lib_path: Utf8PathBuf::default(),
rustc_path: Utf8PathBuf::default(),
cargo_path: Default::default(),
stage0_rustc_path: Default::default(),
rustdoc_path: Default::default(),
coverage_dump_path: Default::default(),
python: Default::default(),
jsondocck_path: Default::default(),
jsondoclint_path: Default::default(),
llvm_filecheck: Default::default(),
llvm_bin_dir: Default::default(),
run_clang_based_tests_with: Default::default(),
src_root: Utf8PathBuf::default(),
src_test_suite_root: Utf8PathBuf::default(),
build_root: Utf8PathBuf::default(),
build_test_suite_root: Utf8PathBuf::default(),
sysroot_base: Utf8PathBuf::default(),
stage: Default::default(),
stage_id: String::default(),
suite: Default::default(),
debugger: Default::default(),
run_ignored: Default::default(),
with_rustc_debug_assertions: Default::default(),
with_std_debug_assertions: Default::default(),
filters: Default::default(),
skip: Default::default(),
filter_exact: Default::default(),
force_pass_mode: Default::default(),
run: Default::default(),
runner: Default::default(),
host_rustcflags: Default::default(),
target_rustcflags: Default::default(),
rust_randomized_layout: Default::default(),
optimize_tests: Default::default(),
target: Default::default(),
host: Default::default(),
cdb: Default::default(),
cdb_version: Default::default(),
gdb: Default::default(),
gdb_version: Default::default(),
lldb_version: Default::default(),
llvm_version: Default::default(),
system_llvm: Default::default(),
android_cross_path: Default::default(),
adb_path: Default::default(),
adb_test_dir: Default::default(),
adb_device_status: Default::default(),
lldb_python_dir: Default::default(),
verbose: Default::default(),
format: Default::default(),
color: Default::default(),
remote_test_client: Default::default(),
compare_mode: Default::default(),
rustfix_coverage: Default::default(),
has_html_tidy: Default::default(),
has_enzyme: Default::default(),
channel: Default::default(),
git_hash: Default::default(),
cc: Default::default(),
cxx: Default::default(),
cflags: Default::default(),
cxxflags: Default::default(),
ar: Default::default(),
target_linker: Default::default(),
host_linker: Default::default(),
llvm_components: Default::default(),
nodejs: Default::default(),
npm: Default::default(),
force_rerun: Default::default(),
only_modified: Default::default(),
target_cfgs: Default::default(),
builtin_cfg_names: Default::default(),
supported_crate_types: Default::default(),
nocapture: Default::default(),
nightly_branch: Default::default(),
git_merge_commit_email: Default::default(),
profiler_runtime: Default::default(),
diff_command: Default::default(),
minicore_path: Default::default(),
}
}
/// FIXME: this run scheme is... confusing.
pub fn run_enabled(&self) -> bool {
self.run.unwrap_or_else(|| {

View File

@ -51,17 +51,6 @@ pub(crate) fn configure_gdb(config: &Config) -> Option<Arc<Config>> {
pub(crate) fn configure_lldb(config: &Config) -> Option<Arc<Config>> {
config.lldb_python_dir.as_ref()?;
// FIXME: this is super old
if let Some(350) = config.lldb_version {
println!(
"WARNING: The used version of LLDB (350) has a \
known issue that breaks debuginfo tests. See \
issue #32520 for more information. Skipping all \
LLDB-based tests!",
);
return None;
}
Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() }))
}

View File

@ -9,7 +9,7 @@ use camino::{Utf8Path, Utf8PathBuf};
use semver::Version;
use tracing::*;
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
use crate::common::{Config, Debugger, FailMode, PassMode, TestMode};
use crate::debuggers::{extract_cdb_version, extract_gdb_version};
use crate::directives::auxiliary::{AuxProps, parse_and_update_aux};
use crate::directives::needs::CachedNeedsConditions;
@ -328,7 +328,7 @@ impl TestProps {
props.exec_env.push(("RUSTC".to_string(), config.rustc_path.to_string()));
match (props.pass_mode, props.fail_mode) {
(None, None) if config.mode == Mode::Ui => props.fail_mode = Some(FailMode::Check),
(None, None) if config.mode == TestMode::Ui => props.fail_mode = Some(FailMode::Check),
(Some(_), Some(_)) => panic!("cannot use a *-fail and *-pass mode together"),
_ => {}
}
@ -609,11 +609,11 @@ impl TestProps {
self.failure_status = Some(101);
}
if config.mode == Mode::Incremental {
if config.mode == TestMode::Incremental {
self.incremental = true;
}
if config.mode == Mode::Crashes {
if config.mode == TestMode::Crashes {
// we don't want to pollute anything with backtrace-files
// also turn off backtraces in order to save some execution
// time on the tests; we only need to know IF it crashes
@ -641,11 +641,11 @@ impl TestProps {
fn update_fail_mode(&mut self, ln: &str, config: &Config) {
let check_ui = |mode: &str| {
// Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows
if config.mode != Mode::Ui && config.mode != Mode::Crashes {
if config.mode != TestMode::Ui && config.mode != TestMode::Crashes {
panic!("`{}-fail` directive is only supported in UI tests", mode);
}
};
if config.mode == Mode::Ui && config.parse_name_directive(ln, "compile-fail") {
if config.mode == TestMode::Ui && config.parse_name_directive(ln, "compile-fail") {
panic!("`compile-fail` directive is useless in UI tests");
}
let fail_mode = if config.parse_name_directive(ln, "check-fail") {
@ -669,10 +669,10 @@ impl TestProps {
fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) {
let check_no_run = |s| match (config.mode, s) {
(Mode::Ui, _) => (),
(Mode::Crashes, _) => (),
(Mode::Codegen, "build-pass") => (),
(Mode::Incremental, _) => {
(TestMode::Ui, _) => (),
(TestMode::Crashes, _) => (),
(TestMode::Codegen, "build-pass") => (),
(TestMode::Incremental, _) => {
if revision.is_some() && !self.revisions.iter().all(|r| r.starts_with("cfail")) {
panic!("`{s}` directive is only supported in `cfail` incremental tests")
}
@ -715,7 +715,7 @@ impl TestProps {
pub fn update_add_core_stubs(&mut self, ln: &str, config: &Config) {
let add_core_stubs = config.parse_name_directive(ln, directives::ADD_CORE_STUBS);
if add_core_stubs {
if !matches!(config.mode, Mode::Ui | Mode::Codegen | Mode::Assembly) {
if !matches!(config.mode, TestMode::Ui | TestMode::Codegen | TestMode::Assembly) {
panic!(
"`add-core-stubs` is currently only supported for ui, codegen and assembly test modes"
);
@ -833,7 +833,7 @@ pub(crate) struct CheckDirectiveResult<'ln> {
pub(crate) fn check_directive<'a>(
directive_ln: &'a str,
mode: Mode,
mode: TestMode,
original_line: &str,
) -> CheckDirectiveResult<'a> {
let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));
@ -842,11 +842,11 @@ pub(crate) fn check_directive<'a>(
let is_known = |s: &str| {
KNOWN_DIRECTIVE_NAMES.contains(&s)
|| match mode {
Mode::Rustdoc | Mode::RustdocJson => {
TestMode::Rustdoc | TestMode::RustdocJson => {
original_line.starts_with("//@")
&& match mode {
Mode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES,
Mode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
TestMode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES,
TestMode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
_ => unreachable!(),
}
.contains(&s)
@ -868,7 +868,7 @@ pub(crate) fn check_directive<'a>(
const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@";
fn iter_directives(
mode: Mode,
mode: TestMode,
_suite: &str,
poisoned: &mut bool,
testfile: &Utf8Path,
@ -883,7 +883,7 @@ fn iter_directives(
// specify them manually in every test file.
//
// FIXME(jieyouxu): I feel like there's a better way to do this, leaving for later.
if mode == Mode::CoverageRun {
if mode == TestMode::CoverageRun {
let extra_directives: &[&str] = &[
"needs-profiler-runtime",
// FIXME(pietroalbini): this test currently does not work on cross-compiled targets
@ -964,7 +964,7 @@ impl Config {
["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"];
if let Some(raw) = self.parse_name_value_directive(line, "revisions") {
if self.mode == Mode::RunMake {
if self.mode == TestMode::RunMake {
panic!("`run-make` tests do not support revisions: {}", testfile);
}
@ -981,7 +981,7 @@ impl Config {
);
}
if matches!(self.mode, Mode::Assembly | Mode::Codegen | Mode::MirOpt)
if matches!(self.mode, TestMode::Assembly | TestMode::Codegen | TestMode::MirOpt)
&& FILECHECK_FORBIDDEN_REVISION_NAMES.contains(&revision)
{
panic!(
@ -1443,7 +1443,7 @@ pub(crate) fn make_test_description<R: Read>(
// since we run the pretty printer across all tests by default.
// If desired, we could add a `should-fail-pretty` annotation.
let should_panic = match config.mode {
crate::common::Pretty => ShouldPanic::No,
TestMode::Pretty => ShouldPanic::No,
_ if should_fail => ShouldPanic::Yes,
_ => ShouldPanic::No,
};

View File

@ -7,7 +7,7 @@ use super::{
DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives,
parse_normalize_rule,
};
use crate::common::{Config, Debugger, Mode};
use crate::common::{Config, Debugger, TestMode};
use crate::executor::{CollectedTestDesc, ShouldPanic};
fn make_test_description<R: Read>(
@ -785,7 +785,7 @@ fn threads_support() {
fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) {
let rdr = std::io::Cursor::new(&buf);
iter_directives(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
iter_directives(TestMode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
}
#[test]

View File

@ -39,8 +39,8 @@ use walkdir::WalkDir;
use self::directives::{EarlyProps, make_test_description};
use crate::common::{
CompareMode, Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path,
output_base_dir, output_relative_path,
CompareMode, Config, Debugger, PassMode, TestMode, TestPaths, UI_EXTENSIONS,
expected_output_path, output_base_dir, output_relative_path,
};
use crate::directives::DirectivesCache;
use crate::executor::{CollectedTest, ColorConfig, OutputFormat};
@ -268,7 +268,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions");
let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions");
let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode");
let has_html_tidy = if mode == Mode::Rustdoc {
let has_html_tidy = if mode == TestMode::Rustdoc {
Command::new("tidy")
.arg("--version")
.stdout(Stdio::null())
@ -279,7 +279,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
false
};
let has_enzyme = matches.opt_present("has-enzyme");
let filters = if mode == Mode::RunMake {
let filters = if mode == TestMode::RunMake {
matches
.free
.iter()
@ -545,7 +545,7 @@ pub fn run_tests(config: Arc<Config>) {
unsafe { env::set_var("TARGET", &config.target) };
let mut configs = Vec::new();
if let Mode::DebugInfo = config.mode {
if let TestMode::DebugInfo = config.mode {
// Debugging emscripten code doesn't make sense today
if !config.target.contains("emscripten") {
match config.debugger {
@ -783,7 +783,7 @@ fn collect_tests_from_dir(
}
// For run-make tests, a "test file" is actually a directory that contains an `rmake.rs`.
if cx.config.mode == Mode::RunMake {
if cx.config.mode == TestMode::RunMake {
let mut collector = TestCollector::new();
if dir.join("rmake.rs").exists() {
let paths = TestPaths {
@ -869,7 +869,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
// For run-make tests, each "test file" is actually a _directory_ containing an `rmake.rs`. But
// for the purposes of directive parsing, we want to look at that recipe file, not the directory
// itself.
let test_path = if cx.config.mode == Mode::RunMake {
let test_path = if cx.config.mode == TestMode::RunMake {
testpaths.file.join("rmake.rs")
} else {
testpaths.file.clone()
@ -884,7 +884,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
// - Incremental tests inherently can't run their revisions in parallel, so
// we treat them like non-revisioned tests here. Incremental revisions are
// handled internally by `runtest::run` instead.
let revisions = if early_props.revisions.is_empty() || cx.config.mode == Mode::Incremental {
let revisions = if early_props.revisions.is_empty() || cx.config.mode == TestMode::Incremental {
vec![None]
} else {
early_props.revisions.iter().map(|r| Some(r.as_str())).collect()
@ -1116,11 +1116,11 @@ fn check_for_overlapping_test_paths(found_path_stems: &HashSet<Utf8PathBuf>) {
}
pub fn early_config_check(config: &Config) {
if !config.has_html_tidy && config.mode == Mode::Rustdoc {
if !config.has_html_tidy && config.mode == TestMode::Rustdoc {
warning!("`tidy` (html-tidy.org) is not installed; diffs will not be generated");
}
if !config.profiler_runtime && config.mode == Mode::CoverageRun {
if !config.profiler_runtime && config.mode == TestMode::CoverageRun {
let actioned = if config.bless { "blessed" } else { "checked" };
warning!("profiler runtime is not available, so `.coverage` files won't be {actioned}");
help!("try setting `profiler = true` in the `[build]` section of `bootstrap.toml`");

View File

@ -16,11 +16,10 @@ use regex::{Captures, Regex};
use tracing::*;
use crate::common::{
Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap, CoverageRun, Crashes,
DebugInfo, Debugger, FailMode, Incremental, MirOpt, PassMode, Pretty, RunMake, Rustdoc,
RustdocJs, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT,
UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, incremental_dir,
output_base_dir, output_base_name, output_testname_unique,
CompareMode, Config, Debugger, FailMode, PassMode, TestMode, TestPaths, UI_EXTENSIONS,
UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG,
expected_output_path, incremental_dir, output_base_dir, output_base_name,
output_testname_unique,
};
use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
use crate::directives::TestProps;
@ -154,7 +153,7 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
cx.init_incremental_test();
}
if config.mode == Incremental {
if config.mode == TestMode::Incremental {
// Incremental tests are special because they cannot be run in
// parallel.
assert!(!props.revisions.is_empty(), "Incremental tests require revisions.");
@ -203,7 +202,7 @@ pub fn compute_stamp_hash(config: &Config) -> String {
None => {}
}
if let Ui = config.mode {
if config.mode == TestMode::Ui {
config.force_pass_mode.hash(&mut hash);
}
@ -251,25 +250,28 @@ impl<'test> TestCx<'test> {
/// Code executed for each revision in turn (or, if there are no
/// revisions, exactly once, with revision == None).
fn run_revision(&self) {
if self.props.should_ice && self.config.mode != Incremental && self.config.mode != Crashes {
if self.props.should_ice
&& self.config.mode != TestMode::Incremental
&& self.config.mode != TestMode::Crashes
{
self.fatal("cannot use should-ice in a test that is not cfail");
}
match self.config.mode {
Pretty => self.run_pretty_test(),
DebugInfo => self.run_debuginfo_test(),
Codegen => self.run_codegen_test(),
Rustdoc => self.run_rustdoc_test(),
RustdocJson => self.run_rustdoc_json_test(),
CodegenUnits => self.run_codegen_units_test(),
Incremental => self.run_incremental_test(),
RunMake => self.run_rmake_test(),
Ui => self.run_ui_test(),
MirOpt => self.run_mir_opt_test(),
Assembly => self.run_assembly_test(),
RustdocJs => self.run_rustdoc_js_test(),
CoverageMap => self.run_coverage_map_test(), // see self::coverage
CoverageRun => self.run_coverage_run_test(), // see self::coverage
Crashes => self.run_crash_test(),
TestMode::Pretty => self.run_pretty_test(),
TestMode::DebugInfo => self.run_debuginfo_test(),
TestMode::Codegen => self.run_codegen_test(),
TestMode::Rustdoc => self.run_rustdoc_test(),
TestMode::RustdocJson => self.run_rustdoc_json_test(),
TestMode::CodegenUnits => self.run_codegen_units_test(),
TestMode::Incremental => self.run_incremental_test(),
TestMode::RunMake => self.run_rmake_test(),
TestMode::Ui => self.run_ui_test(),
TestMode::MirOpt => self.run_mir_opt_test(),
TestMode::Assembly => self.run_assembly_test(),
TestMode::RustdocJs => self.run_rustdoc_js_test(),
TestMode::CoverageMap => self.run_coverage_map_test(), // see self::coverage
TestMode::CoverageRun => self.run_coverage_run_test(), // see self::coverage
TestMode::Crashes => self.run_crash_test(),
}
}
@ -279,9 +281,13 @@ impl<'test> TestCx<'test> {
fn should_run(&self, pm: Option<PassMode>) -> WillExecute {
let test_should_run = match self.config.mode {
Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => true,
MirOpt if pm == Some(PassMode::Run) => true,
Ui | MirOpt => false,
TestMode::Ui
if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) =>
{
true
}
TestMode::MirOpt if pm == Some(PassMode::Run) => true,
TestMode::Ui | TestMode::MirOpt => false,
mode => panic!("unimplemented for mode {:?}", mode),
};
if test_should_run { self.run_if_enabled() } else { WillExecute::No }
@ -293,17 +299,17 @@ impl<'test> TestCx<'test> {
fn should_run_successfully(&self, pm: Option<PassMode>) -> bool {
match self.config.mode {
Ui | MirOpt => pm == Some(PassMode::Run),
TestMode::Ui | TestMode::MirOpt => pm == Some(PassMode::Run),
mode => panic!("unimplemented for mode {:?}", mode),
}
}
fn should_compile_successfully(&self, pm: Option<PassMode>) -> bool {
match self.config.mode {
RustdocJs => true,
Ui => pm.is_some() || self.props.fail_mode > Some(FailMode::Build),
Crashes => false,
Incremental => {
TestMode::RustdocJs => true,
TestMode::Ui => pm.is_some() || self.props.fail_mode > Some(FailMode::Build),
TestMode::Crashes => false,
TestMode::Incremental => {
let revision =
self.revision.expect("incremental tests require a list of revisions");
if revision.starts_with("cpass")
@ -349,7 +355,7 @@ impl<'test> TestCx<'test> {
if proc_res.status.success() {
{
self.error(&format!("{} test did not emit an error", self.config.mode));
if self.config.mode == crate::common::Mode::Ui {
if self.config.mode == crate::common::TestMode::Ui {
println!("note: by default, ui tests are expected not to compile");
}
proc_res.fatal(None, || ());
@ -892,7 +898,9 @@ impl<'test> TestCx<'test> {
fn should_emit_metadata(&self, pm: Option<PassMode>) -> Emit {
match (pm, self.props.fail_mode, self.config.mode) {
(Some(PassMode::Check), ..) | (_, Some(FailMode::Check), Ui) => Emit::Metadata,
(Some(PassMode::Check), ..) | (_, Some(FailMode::Check), TestMode::Ui) => {
Emit::Metadata
}
_ => Emit::None,
}
}
@ -926,7 +934,7 @@ impl<'test> TestCx<'test> {
};
let allow_unused = match self.config.mode {
Ui => {
TestMode::Ui => {
// UI tests tend to have tons of unused code as
// it's just testing various pieces of the compile, but we don't
// want to actually assert warnings about all this code. Instead
@ -1021,7 +1029,7 @@ impl<'test> TestCx<'test> {
.args(&self.props.compile_flags)
.args(&self.props.doc_flags);
if self.config.mode == RustdocJson {
if self.config.mode == TestMode::RustdocJson {
rustdoc.arg("--output-format").arg("json").arg("-Zunstable-options");
}
@ -1372,7 +1380,7 @@ impl<'test> TestCx<'test> {
|| self.is_vxworks_pure_static()
|| self.config.target.contains("bpf")
|| !self.config.target_cfg().dynamic_linking
|| matches!(self.config.mode, CoverageMap | CoverageRun)
|| matches!(self.config.mode, TestMode::CoverageMap | TestMode::CoverageRun)
{
// We primarily compile all auxiliary libraries as dynamic libraries
// to avoid code size bloat and large binaries as much as possible
@ -1562,14 +1570,14 @@ impl<'test> TestCx<'test> {
rustc.args(&["-Z", "incremental-verify-ich"]);
}
if self.config.mode == CodegenUnits {
if self.config.mode == TestMode::CodegenUnits {
rustc.args(&["-Z", "human_readable_cgu_names"]);
}
}
if self.config.optimize_tests && !is_rustdoc {
match self.config.mode {
Ui => {
TestMode::Ui => {
// If optimize-tests is true we still only want to optimize tests that actually get
// executed and that don't specify their own optimization levels.
// Note: aux libs don't have a pass-mode, so they won't get optimized
@ -1585,8 +1593,8 @@ impl<'test> TestCx<'test> {
rustc.arg("-O");
}
}
DebugInfo => { /* debuginfo tests must be unoptimized */ }
CoverageMap | CoverageRun => {
TestMode::DebugInfo => { /* debuginfo tests must be unoptimized */ }
TestMode::CoverageMap | TestMode::CoverageRun => {
// Coverage mappings and coverage reports are affected by
// optimization level, so they ignore the optimize-tests
// setting and set an optimization level in their mode's
@ -1607,7 +1615,7 @@ impl<'test> TestCx<'test> {
};
match self.config.mode {
Incremental => {
TestMode::Incremental => {
// If we are extracting and matching errors in the new
// fashion, then you want JSON mode. Old-skool error
// patterns still match the raw compiler output.
@ -1620,7 +1628,7 @@ impl<'test> TestCx<'test> {
rustc.arg("-Zui-testing");
rustc.arg("-Zdeduplicate-diagnostics=no");
}
Ui => {
TestMode::Ui => {
if !self.props.compile_flags.iter().any(|s| s.starts_with("--error-format")) {
rustc.args(&["--error-format", "json"]);
rustc.args(&["--json", "future-incompat"]);
@ -1633,7 +1641,7 @@ impl<'test> TestCx<'test> {
// FIXME: use this for other modes too, for perf?
rustc.arg("-Cstrip=debuginfo");
}
MirOpt => {
TestMode::MirOpt => {
// We check passes under test to minimize the mir-opt test dump
// if files_for_miropt_test parses the passes, we dump only those passes
// otherwise we conservatively pass -Zdump-mir=all
@ -1663,7 +1671,7 @@ impl<'test> TestCx<'test> {
set_mir_dump_dir(&mut rustc);
}
CoverageMap => {
TestMode::CoverageMap => {
rustc.arg("-Cinstrument-coverage");
// These tests only compile to LLVM IR, so they don't need the
// profiler runtime to be present.
@ -1673,23 +1681,28 @@ impl<'test> TestCx<'test> {
// by `compile-flags`.
rustc.arg("-Copt-level=2");
}
CoverageRun => {
TestMode::CoverageRun => {
rustc.arg("-Cinstrument-coverage");
// Coverage reports are sometimes sensitive to optimizations,
// and the current snapshots assume `opt-level=2` unless
// overridden by `compile-flags`.
rustc.arg("-Copt-level=2");
}
Assembly | Codegen => {
TestMode::Assembly | TestMode::Codegen => {
rustc.arg("-Cdebug-assertions=no");
}
Crashes => {
TestMode::Crashes => {
set_mir_dump_dir(&mut rustc);
}
CodegenUnits => {
TestMode::CodegenUnits => {
rustc.arg("-Zprint-mono-items");
}
Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | RustdocJs => {
TestMode::Pretty
| TestMode::DebugInfo
| TestMode::Rustdoc
| TestMode::RustdocJson
| TestMode::RunMake
| TestMode::RustdocJs => {
// do not use JSON output
}
}
@ -1962,7 +1975,7 @@ impl<'test> TestCx<'test> {
/// The revision, ignored for incremental compilation since it wants all revisions in
/// the same directory.
fn safe_revision(&self) -> Option<&str> {
if self.config.mode == Incremental { None } else { self.revision }
if self.config.mode == TestMode::Incremental { None } else { self.revision }
}
/// Gets the absolute path to the directory where all output for the given

View File

@ -67,11 +67,7 @@ fn is_test_test() {
#[test]
fn string_enums() {
// These imports are needed for the macro-generated code
use std::fmt;
use std::str::FromStr;
crate::common::string_enum! {
crate::util::string_enum! {
#[derive(Clone, Copy, Debug, PartialEq)]
enum Animal {
Cat => "meow",

View File

@ -104,3 +104,42 @@ macro_rules! static_regex {
}};
}
pub(crate) use static_regex;
macro_rules! string_enum {
($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => {
$(#[$meta])*
$vis enum $name {
$($variant,)*
}
impl $name {
$vis const VARIANTS: &'static [Self] = &[$(Self::$variant,)*];
$vis const STR_VARIANTS: &'static [&'static str] = &[$(Self::$variant.to_str(),)*];
$vis const fn to_str(&self) -> &'static str {
match self {
$(Self::$variant => $repr,)*
}
}
}
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::std::fmt::Display::fmt(self.to_str(), f)
}
}
impl ::std::str::FromStr for $name {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
$($repr => Ok(Self::$variant),)*
_ => Err(format!(concat!("unknown `", stringify!($name), "` variant: `{}`"), s)),
}
}
}
}
}
pub(crate) use string_enum;

View File

@ -112,11 +112,7 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse
.current_dir(path);
if let Some(librs) = find_librs(entry.path()) {
let compiletest_c = compiletest::common::Config {
edition: None,
mode: compiletest::common::Mode::Rustdoc,
..Default::default()
};
let compiletest_c = compiletest::common::Config::incomplete_for_rustdoc_gui_test();
let test_props = TestProps::from_file(
&camino::Utf8PathBuf::try_from(librs).unwrap(),