From 2ed8618cd83973ba1079a7a68e20e1169842ee71 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 5 Nov 2022 17:55:05 +0000 Subject: [PATCH 1/3] Remove some unused .fixed files --- .../closure-immutable-outer-variable.rs.fixed | 10 ---------- .../ui/const-generics/unused_braces.full.fixed | 16 ---------------- .../ui/const-generics/unused_braces.min.fixed | 16 ---------------- 3 files changed, 42 deletions(-) delete mode 100644 src/test/ui/closures/closure-immutable-outer-variable.rs.fixed delete mode 100644 src/test/ui/const-generics/unused_braces.full.fixed delete mode 100644 src/test/ui/const-generics/unused_braces.min.fixed diff --git a/src/test/ui/closures/closure-immutable-outer-variable.rs.fixed b/src/test/ui/closures/closure-immutable-outer-variable.rs.fixed deleted file mode 100644 index 5c6358beb2487..0000000000000 --- a/src/test/ui/closures/closure-immutable-outer-variable.rs.fixed +++ /dev/null @@ -1,10 +0,0 @@ -// Point at the captured immutable outer variable - -fn foo(mut f: Box) { - f(); -} - -fn main() { - let mut y = true; - foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable -} diff --git a/src/test/ui/const-generics/unused_braces.full.fixed b/src/test/ui/const-generics/unused_braces.full.fixed deleted file mode 100644 index 46d57e0dcfca8..0000000000000 --- a/src/test/ui/const-generics/unused_braces.full.fixed +++ /dev/null @@ -1,16 +0,0 @@ -// check-pass -// run-rustfix -// revisions: full min - -#![cfg_attr(full, feature(const_generics))] -#![cfg_attr(full, allow(incomplete_features))] -#![warn(unused_braces)] - - -struct A; - -fn main() { - let _: A<7>; // ok - let _: A<7>; //~ WARN unnecessary braces - let _: A<{ 3 + 5 }>; // ok -} diff --git a/src/test/ui/const-generics/unused_braces.min.fixed b/src/test/ui/const-generics/unused_braces.min.fixed deleted file mode 100644 index 46d57e0dcfca8..0000000000000 --- a/src/test/ui/const-generics/unused_braces.min.fixed +++ /dev/null @@ -1,16 +0,0 @@ -// check-pass -// run-rustfix -// revisions: full min - -#![cfg_attr(full, feature(const_generics))] -#![cfg_attr(full, allow(incomplete_features))] -#![warn(unused_braces)] - - -struct A; - -fn main() { - let _: A<7>; // ok - let _: A<7>; //~ WARN unnecessary braces - let _: A<{ 3 + 5 }>; // ok -} From c4c7b30b57aba4df5f6b9f5f8525ab0d2ee09390 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 5 Nov 2022 17:55:05 +0000 Subject: [PATCH 2/3] Rename compiletest's main.rs to lib.rs --- src/tools/compiletest/src/{main.rs => lib.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/tools/compiletest/src/{main.rs => lib.rs} (100%) diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/lib.rs similarity index 100% rename from src/tools/compiletest/src/main.rs rename to src/tools/compiletest/src/lib.rs From ff5466348e7741e69c77da4c8fc4115d27746cc9 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sat, 5 Nov 2022 18:25:49 +0000 Subject: [PATCH 3/3] Expose compiletest as a library for use in Clippy --- src/bootstrap/test.rs | 1 + src/tools/compiletest/Cargo.toml | 3 + src/tools/compiletest/src/common.rs | 27 ++++++- src/tools/compiletest/src/header.rs | 13 +--- src/tools/compiletest/src/header/tests.rs | 1 + src/tools/compiletest/src/lib.rs | 95 ++++++----------------- src/tools/compiletest/src/main.rs | 65 ++++++++++++++++ src/tools/compiletest/src/runtest.rs | 55 +++++++------ 8 files changed, 154 insertions(+), 106 deletions(-) create mode 100644 src/tools/compiletest/src/main.rs diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 935ce5e7f84b3..760df7413a8c9 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1382,6 +1382,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--rust-demangler-path").arg(rust_demangler); } + cmd.arg("--source-root").arg(&builder.src); cmd.arg("--src-base").arg(builder.src.join("src/test").join(suite)); cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite)); cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target)); diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 1911f0f9c941c..64c537626b8fa 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -3,6 +3,9 @@ name = "compiletest" version = "0.0.0" edition = "2021" +[lib] +doctest = false + [dependencies] colored = "2" diff = "0.1.10" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 9a432f11f82ff..ec9886a460d19 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -6,10 +6,11 @@ use std::iter; use std::path::{Path, PathBuf}; use std::process::Command; use std::str::FromStr; +use std::sync::Arc; use crate::util::{add_dylib_path, PathBufExt}; use lazycell::LazyCell; -use test::ColorConfig; +pub use test::ColorConfig; #[derive(Clone, Copy, PartialEq, Debug)] pub enum Mode { @@ -177,6 +178,21 @@ pub enum PanicStrategy { Abort, } +#[derive(Clone, Default)] +pub struct Hooks { + /// Return `true` to exclude a given [Path] from being considered a test file + pub exclude_file: Option bool + Send + Sync>>, + + /// Modify a compiler [`Command`] just before it's executed + pub modify_compiler_command: Option>, +} + +impl fmt::Debug for Hooks { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.debug_struct("Hooks").finish_non_exhaustive() + } +} + /// Configuration for compiletest #[derive(Debug, Clone)] pub struct Config { @@ -224,6 +240,9 @@ pub struct Config { /// `None` then these tests will be ignored. pub run_clang_based_tests_with: Option, + /// The project root directory + pub source_root: PathBuf, + /// The directory containing the tests to run pub src_base: PathBuf, @@ -236,6 +255,9 @@ pub struct Config { /// The test mode, e.g. ui or debuginfo. pub mode: Mode, + /// Don't require compile-fail or build-fail tests to contain `//~ ERROR` style comments + pub no_expected_comments: bool, + /// The test suite (essentially which directory is running, but without the /// directory prefix such as src/test) pub suite: String, @@ -375,6 +397,9 @@ pub struct Config { pub force_rerun: bool, pub target_cfg: LazyCell, + + /// Contains callbacks to be invoked at certain points in the test, used by Clippy + pub hooks: Hooks, } impl Config { diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 0d9a629e179b8..ef593600333d4 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -736,17 +736,10 @@ impl Config { } } - pub fn find_rust_src_root(&self) -> Option { - let mut path = self.src_base.clone(); - let path_postfix = Path::new("src/etc/lldb_batchmode.py"); + pub fn find_rust_src_root(&self) -> &Path { + assert!(self.source_root.join("x.py").exists(), "Not running in Rust source root"); - while path.pop() { - if path.join(&path_postfix).is_file() { - return Some(path); - } - } - - None + &self.source_root } fn parse_edition(&self, line: &str) -> Option { diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index bcd222b5a9322..e901277682890 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -44,6 +44,7 @@ fn config() -> Config { "--run-lib-path=", "--python=", "--jsondocck-path=", + "--source-root=", "--src-base=", "--build-base=", "--stage-id=stage2", diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 19cf54780c1f9..82c621d5ccae5 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -7,7 +7,6 @@ extern crate test; use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, TestPaths}; -use crate::util::logv; use getopts::Options; use lazycell::LazyCell; use std::env; @@ -27,32 +26,15 @@ use self::header::{make_test_description, EarlyProps}; mod tests; pub mod common; -pub mod compute_diff; -pub mod errors; -pub mod header; +mod compute_diff; +mod errors; +mod header; mod json; mod raise_fd_limit; mod read2; -pub mod runtest; +mod runtest; pub mod util; -fn main() { - tracing_subscriber::fmt::init(); - - let config = parse_config(env::args().collect()); - - if config.valgrind_path.is_none() && config.force_valgrind { - panic!("Can't find Valgrind to run Valgrind tests"); - } - - if !config.has_tidy && config.mode == Mode::Rustdoc { - eprintln!("warning: `tidy` is not installed; diffs will not be generated"); - } - - log_config(&config); - run_tests(config); -} - pub fn parse_config(args: Vec) -> Config { let mut opts = Options::new(); opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") @@ -67,6 +49,7 @@ pub fn parse_config(args: Vec) -> Config { .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH") .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR") + .reqopt("", "source-root", "root directory of the project", "PATH") .reqopt("", "src-base", "directory to scan for test files", "PATH") .reqopt("", "build-base", "directory to deposit test outputs", "PATH") .reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET") @@ -232,10 +215,12 @@ pub fn parse_config(args: Vec) -> Config { run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from), llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from), + source_root: opt_path(matches, "source-root"), src_base, build_base: opt_path(matches, "build-base"), stage_id: matches.opt_str("stage-id").unwrap(), mode, + no_expected_comments: false, suite: matches.opt_str("suite").unwrap(), debugger: None, run_ignored, @@ -296,55 +281,12 @@ pub fn parse_config(args: Vec) -> Config { npm: matches.opt_str("npm"), force_rerun: matches.opt_present("force-rerun"), - target_cfg: LazyCell::new(), + hooks: Default::default(), } } -pub fn log_config(config: &Config) { - let c = config; - logv(c, "configuration:".to_string()); - logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); - logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); - logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); - logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); - logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path)); - logv(c, format!("src_base: {:?}", config.src_base.display())); - logv(c, format!("build_base: {:?}", config.build_base.display())); - logv(c, format!("stage_id: {}", config.stage_id)); - logv(c, format!("mode: {}", config.mode)); - logv(c, format!("run_ignored: {}", config.run_ignored)); - logv(c, format!("filters: {:?}", config.filters)); - logv(c, format!("skip: {:?}", config.skip)); - logv(c, format!("filter_exact: {}", config.filter_exact)); - logv( - c, - format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),), - ); - logv(c, format!("runtool: {}", opt_str(&config.runtool))); - logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags)); - logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags)); - logv(c, format!("target: {}", config.target)); - logv(c, format!("host: {}", config.host)); - logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display())); - logv(c, format!("adb_path: {:?}", config.adb_path)); - logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); - logv(c, format!("adb_device_status: {}", config.adb_device_status)); - logv(c, format!("ar: {}", config.ar)); - logv(c, format!("linker: {:?}", config.linker)); - logv(c, format!("verbose: {}", config.verbose)); - logv(c, format!("quiet: {}", config.quiet)); - logv(c, "\n".to_string()); -} - -pub fn opt_str(maybestr: &Option) -> &str { - match *maybestr { - None => "(none)", - Some(ref s) => s, - } -} - -pub fn opt_str2(maybestr: Option) -> String { +fn opt_str2(maybestr: Option) -> String { match maybestr { None => "(none)".to_owned(), Some(s) => s, @@ -524,7 +466,11 @@ pub fn make_tests(config: &Config, tests: &mut Vec) { /// Returns a stamp constructed from input files common to all test cases. fn common_inputs_stamp(config: &Config) -> Stamp { - let rust_src_dir = config.find_rust_src_root().expect("Could not find Rust source root"); + if config.force_rerun { + return Stamp { time: SystemTime::UNIX_EPOCH }; + } + + let rust_src_dir = config.find_rust_src_root(); let mut stamp = Stamp::from_path(&config.rustc_path); @@ -627,6 +573,12 @@ pub fn is_test(file_name: &OsString) -> bool { } fn make_test(config: &Config, testpaths: &TestPaths, inputs: &Stamp) -> Vec { + if let Some(hook) = &config.hooks.exclude_file { + if hook(&testpaths.file) { + return Vec::new(); + } + } + let test_path = if config.mode == Mode::RunMake { // Parse directives in the Makefile testpaths.file.join("Makefile") @@ -648,7 +600,7 @@ fn make_test(config: &Config, testpaths: &TestPaths, inputs: &Stamp) -> Vec, ) -> test::TestName { - // Print the name of the file, relative to the repository root. - // `src_base` looks like `/path/to/rust/src/test/ui` - let root_directory = config.src_base.parent().unwrap().parent().unwrap().parent().unwrap(); - let path = testpaths.file.strip_prefix(root_directory).unwrap(); + let path = testpaths.file.strip_prefix(&config.source_root).unwrap(); let debugger = match config.debugger { Some(d) => format!("-{}", d), None => String::new(), diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs new file mode 100644 index 0000000000000..04fa4908edd18 --- /dev/null +++ b/src/tools/compiletest/src/main.rs @@ -0,0 +1,65 @@ +use std::env; + +use compiletest::common::{Config, Mode}; +use compiletest::util::logv; +use compiletest::{parse_config, run_tests}; + +fn main() { + tracing_subscriber::fmt::init(); + + let config = parse_config(env::args().collect()); + + if config.valgrind_path.is_none() && config.force_valgrind { + panic!("Can't find Valgrind to run Valgrind tests"); + } + + if !config.has_tidy && config.mode == Mode::Rustdoc { + eprintln!("warning: `tidy` is not installed; diffs will not be generated"); + } + + log_config(&config); + run_tests(config); +} + +fn log_config(config: &Config) { + let c = config; + logv(c, "configuration:".to_string()); + logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); + logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); + logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); + logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); + logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path)); + logv(c, format!("src_base: {:?}", config.src_base.display())); + logv(c, format!("build_base: {:?}", config.build_base.display())); + logv(c, format!("stage_id: {}", config.stage_id)); + logv(c, format!("mode: {}", config.mode)); + logv(c, format!("run_ignored: {}", config.run_ignored)); + logv(c, format!("filters: {:?}", config.filters)); + logv(c, format!("skip: {:?}", config.skip)); + logv(c, format!("filter_exact: {}", config.filter_exact)); + logv( + c, + format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),), + ); + logv(c, format!("runtool: {}", opt_str(&config.runtool))); + logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags)); + logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags)); + logv(c, format!("target: {}", config.target)); + logv(c, format!("host: {}", config.host)); + logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display())); + logv(c, format!("adb_path: {:?}", config.adb_path)); + logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); + logv(c, format!("adb_device_status: {}", config.adb_device_status)); + logv(c, format!("ar: {}", config.ar)); + logv(c, format!("linker: {:?}", config.linker)); + logv(c, format!("verbose: {}", config.verbose)); + logv(c, format!("quiet: {}", config.quiet)); + logv(c, "\n".to_string()); +} + +fn opt_str(maybestr: &Option) -> &str { + match *maybestr { + None => "(none)", + Some(ref s) => s, + } +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 8d8ca101cd037..d0df25e1c699b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -898,8 +898,7 @@ impl<'test> TestCx<'test> { println!("Adb process is already finished."); } } else { - let rust_src_root = - self.config.find_rust_src_root().expect("Could not find Rust source root"); + let rust_src_root = self.config.find_rust_src_root(); let rust_pp_module_rel_path = Path::new("./src/etc"); let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path).to_str().unwrap().to_owned(); @@ -1064,8 +1063,7 @@ impl<'test> TestCx<'test> { script_str.push_str("version\n"); // Switch LLDB into "Rust mode" - let rust_src_root = - self.config.find_rust_src_root().expect("Could not find Rust source root"); + let rust_src_root = self.config.find_rust_src_root(); let rust_pp_module_rel_path = Path::new("./src/etc/lldb_lookup.py"); let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path).to_str().unwrap().to_owned(); @@ -1314,23 +1312,30 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("process did not return an error status", proc_res); } - if self.props.known_bug { + // On Windows, keep all '\' path separators to match the paths reported in the JSON output + // from the compiler + let os_file_name = self.testpaths.file.display().to_string(); + + // on windows, translate all '\' path separators to '/' + let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/"); + + if self.props.known_bug || self.config.no_expected_comments { + for expected in &expected_errors { + self.error(&format!( + "{file_name}:{}: found expectation comment `{}`", + expected.line_num, expected.msg, + )) + } + if !expected_errors.is_empty() { self.fatal_proc_rec( - "`known_bug` tests should not have an expected errors", + "`known_bug` or `--no-expected-comments` tests should not have an expected errors", proc_res, ); } return; } - // On Windows, keep all '\' path separators to match the paths reported in the JSON output - // from the compiler - let os_file_name = self.testpaths.file.display().to_string(); - - // on windows, translate all '\' path separators to '/' - let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/"); - // If the testcase being checked contains at least one expected "help" // message, then we'll ensure that all "help" messages are expected. // Otherwise, all "help" messages reported by the compiler will be ignored. @@ -1360,7 +1365,6 @@ impl<'test> TestCx<'test> { } None => { - // If the test is a known bug, don't require that the error is annotated if self.is_unexpected_compiler_message(actual_error, expect_help, expect_note) { self.error(&format!( "{}:{}: unexpected {}: '{}'", @@ -1683,6 +1687,11 @@ impl<'test> TestCx<'test> { let aux_dir = self.build_all_auxiliary(&mut rustc); self.props.unset_rustc_env.iter().fold(&mut rustc, Command::env_remove); rustc.envs(self.props.rustc_env.clone()); + + if let Some(hook) = &self.config.hooks.modify_compiler_command { + hook(&self.testpaths.file, &mut rustc); + } + self.compose_and_run( rustc, self.config.compile_lib_path.to_str().unwrap(), @@ -2347,7 +2356,7 @@ impl<'test> TestCx<'test> { if self.props.check_test_line_numbers_match { self.check_rustdoc_test_option(proc_res); } else { - let root = self.config.find_rust_src_root().unwrap(); + let root = self.config.find_rust_src_root(); let mut cmd = Command::new(&self.config.python); cmd.arg(root.join("src/etc/htmldocck.py")).arg(&out_dir).arg(&self.testpaths.file); if self.config.bless { @@ -2528,7 +2537,7 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("rustdoc failed!", &proc_res); } - let root = self.config.find_rust_src_root().unwrap(); + let root = self.config.find_rust_src_root(); let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); json_out.set_extension("json"); let res = self.cmd2procres( @@ -3087,7 +3096,7 @@ impl<'test> TestCx<'test> { self.document(&out_dir); - let root = self.config.find_rust_src_root().unwrap(); + let root = self.config.find_rust_src_root(); let file_stem = self.testpaths.file.file_stem().and_then(|f| f.to_str()).expect("no file stem"); let res = self.cmd2procres( @@ -3339,13 +3348,16 @@ impl<'test> TestCx<'test> { if self.props.run_rustfix && self.config.compare_mode.is_none() { // And finally, compile the fixed code and make sure it both // succeeds and has no diagnostics. - let rustc = self.make_compile_args( - &self.testpaths.file.with_extension(UI_FIXED), + let mut rustc = self.make_compile_args( + &self.expected_output_path(UI_FIXED), TargetLocation::ThisFile(self.make_exe_name()), emit_metadata, AllowUnused::No, LinkToAux::Yes, ); + // Set the crate name to avoid `file.revision.fixed` inferring the + // invalid name `file.revision` + rustc.arg("--crate-name=fixed"); let res = self.compose_and_run_compiler(rustc, None); if !res.status.success() { self.fatal_proc_rec("failed to compile fixed code", &res); @@ -3530,14 +3542,13 @@ impl<'test> TestCx<'test> { normalize_path(parent_dir, "$DIR"); // Paths into the libstd/libcore - let base_dir = self.config.src_base.parent().unwrap().parent().unwrap().parent().unwrap(); - let src_dir = base_dir.join("library"); + let src_dir = self.config.source_root.join("library"); normalize_path(&src_dir, "$SRC_DIR"); // `ui-fulldeps` tests can show paths to the compiler source when testing macros from // `rustc_macros` // eg. /home/user/rust/compiler - let compiler_src_dir = base_dir.join("compiler"); + let compiler_src_dir = self.config.source_root.join("compiler"); normalize_path(&compiler_src_dir, "$COMPILER_DIR"); if let Some(virtual_rust_source_base_dir) =