summaryrefslogtreecommitdiffstats
path: root/src/tools/compiletest
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /src/tools/compiletest
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools/compiletest')
-rw-r--r--src/tools/compiletest/Cargo.toml2
-rw-r--r--src/tools/compiletest/src/header.rs47
-rw-r--r--src/tools/compiletest/src/header/cfg.rs4
-rw-r--r--src/tools/compiletest/src/lib.rs2
-rw-r--r--src/tools/compiletest/src/runtest.rs153
-rw-r--r--src/tools/compiletest/src/runtest/debugger.rs148
-rw-r--r--src/tools/compiletest/src/runtest/tests.rs8
7 files changed, 213 insertions, 151 deletions
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index d2f258320..ff1d5cecb 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -29,7 +29,7 @@ anyhow = "1"
libc = "0.2"
[target.'cfg(windows)'.dependencies]
-miow = "0.5"
+miow = "0.6"
[target.'cfg(windows)'.dependencies.windows]
version = "0.48.0"
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index c835962ad..269d93843 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -6,7 +6,6 @@ use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::process::Command;
-use build_helper::ci::CiEnv;
use tracing::*;
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
@@ -232,7 +231,7 @@ impl TestProps {
aux_builds: vec![],
aux_crates: vec![],
revisions: vec![],
- rustc_env: vec![],
+ rustc_env: vec![("RUSTC_ICE".to_string(), "0".to_string())],
unset_rustc_env: vec![],
exec_env: vec![],
unset_exec_env: vec![],
@@ -298,13 +297,6 @@ impl TestProps {
/// `//[foo]`), then the property is ignored unless `cfg` is
/// `Some("foo")`.
fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
- // In CI, we've sometimes encountered non-determinism related to truncating very long paths.
- // Set a consistent (short) prefix to avoid issues, but only in CI to avoid regressing the
- // contributor experience.
- if CiEnv::is_ci() {
- self.remap_src_base = config.mode == Mode::Ui && !config.suite.contains("rustdoc");
- }
-
let mut has_edition = false;
if !testfile.is_dir() {
let file = File::open(testfile).unwrap();
@@ -541,16 +533,15 @@ impl TestProps {
}
fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) {
- let check_no_run = |s| {
- if config.mode != Mode::Ui && config.mode != Mode::Incremental {
- panic!("`{}` header is only supported in UI and incremental tests", s);
- }
- if config.mode == Mode::Incremental
- && !revision.map_or(false, |r| r.starts_with("cfail"))
- && !self.revisions.iter().all(|r| r.starts_with("cfail"))
- {
- panic!("`{}` header is only supported in `cfail` incremental tests", s);
+ let check_no_run = |s| match (config.mode, s) {
+ (Mode::Ui, _) => (),
+ (Mode::Codegen, "build-pass") => (),
+ (Mode::Incremental, _) => {
+ if revision.is_some() && !self.revisions.iter().all(|r| r.starts_with("cfail")) {
+ panic!("`{s}` header is only supported in `cfail` incremental tests")
+ }
}
+ (mode, _) => panic!("`{s}` header is not supported in `{mode}` tests"),
};
let pass_mode = if config.parse_name_directive(ln, "check-pass") {
check_no_run("check-pass");
@@ -559,9 +550,7 @@ impl TestProps {
check_no_run("build-pass");
Some(PassMode::Build)
} else if config.parse_name_directive(ln, "run-pass") {
- if config.mode != Mode::Ui {
- panic!("`run-pass` header is only supported in UI tests")
- }
+ check_no_run("run-pass");
Some(PassMode::Run)
} else {
None
@@ -588,21 +577,25 @@ impl TestProps {
}
}
+/// Extract a `(Option<line_config>, directive)` directive from a line if comment is present.
pub fn line_directive<'line>(
comment: &str,
ln: &'line str,
) -> Option<(Option<&'line str>, &'line str)> {
+ let ln = ln.trim_start();
if ln.starts_with(comment) {
let ln = ln[comment.len()..].trim_start();
if ln.starts_with('[') {
// A comment like `//[foo]` is specific to revision `foo`
- if let Some(close_brace) = ln.find(']') {
- let lncfg = &ln[1..close_brace];
+ let Some(close_brace) = ln.find(']') else {
+ panic!(
+ "malformed condition directive: expected `{}[foo]`, found `{}`",
+ comment, ln
+ );
+ };
- Some((Some(lncfg), ln[(close_brace + 1)..].trim_start()))
- } else {
- panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln)
- }
+ let lncfg = &ln[1..close_brace];
+ Some((Some(lncfg), ln[(close_brace + 1)..].trim_start()))
} else {
Some((None, ln))
}
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs
index 86a749b93..77c2866b3 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/header/cfg.rs
@@ -112,7 +112,7 @@ pub(super) fn parse_cfg_name_directive<'a>(
(config.target == "wasm32-unknown-unknown").then_some("emscripten"),
],
allowed_names: &target_cfgs.all_oses,
- message: "when the operative system is {name}"
+ message: "when the operating system is {name}"
}
condition! {
name: &target_cfg.env,
@@ -122,7 +122,7 @@ pub(super) fn parse_cfg_name_directive<'a>(
condition! {
name: &target_cfg.os_and_env(),
allowed_names: &target_cfgs.all_oses_and_envs,
- message: "when the operative system and target environment are {name}"
+ message: "when the operating system and target environment are {name}"
}
condition! {
name: &target_cfg.abi,
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index fc48d0159..1a765477f 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -1119,7 +1119,7 @@ fn check_overlapping_tests(found_paths: &BTreeSet<PathBuf>) {
for path in found_paths {
for ancestor in path.ancestors().skip(1) {
if found_paths.contains(ancestor) {
- collisions.push((path, ancestor.clone()));
+ collisions.push((path, ancestor));
}
}
}
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 672779325..4ef79af31 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -18,6 +18,7 @@ use crate::ColorConfig;
use regex::{Captures, Regex};
use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
+use std::borrow::Cow;
use std::collections::hash_map::DefaultHasher;
use std::collections::{HashMap, HashSet};
use std::env;
@@ -41,7 +42,7 @@ use crate::extract_gdb_version;
use crate::is_android_gdb_target;
mod debugger;
-use debugger::{check_debugger_output, DebuggerCommands};
+use debugger::DebuggerCommands;
#[cfg(test)]
mod tests;
@@ -664,6 +665,7 @@ impl<'test> TestCx<'test> {
fn normalize_coverage_output(&self, coverage: &str) -> Result<String, String> {
let normalized = self.normalize_output(coverage, &[]);
+ let normalized = Self::anonymize_coverage_line_numbers(&normalized);
let mut lines = normalized.lines().collect::<Vec<_>>();
@@ -674,6 +676,21 @@ impl<'test> TestCx<'test> {
Ok(joined_lines)
}
+ /// Replace line numbers in coverage reports with the placeholder `LL`,
+ /// so that the tests are less sensitive to lines being added/removed.
+ fn anonymize_coverage_line_numbers(coverage: &str) -> Cow<'_, str> {
+ // The coverage reporter prints line numbers at the start of a line.
+ // They are truncated or left-padded to occupy exactly 5 columns.
+ // (`LineNumberColumnWidth` in `SourceCoverageViewText.cpp`.)
+ // A pipe character `|` appears immediately after the final digit.
+ //
+ // Line numbers that appear inside expansion/instantiation subviews
+ // have an additional prefix of ` |` for each nesting level.
+ static LINE_NUMBER_RE: Lazy<Regex> =
+ Lazy::new(|| Regex::new(r"(?m:^)(?<prefix>(?: \|)*) *[0-9]+\|").unwrap());
+ LINE_NUMBER_RE.replace_all(coverage, "$prefix LL|")
+ }
+
/// Coverage reports can describe multiple source files, separated by
/// blank lines. The order of these files is unpredictable (since it
/// depends on implementation details), so we need to sort the file
@@ -868,6 +885,8 @@ impl<'test> TestCx<'test> {
.args(&["--target", &self.config.target])
.arg("-L")
.arg(&aux_dir)
+ .arg("-A")
+ .arg("internal_features")
.args(&self.props.compile_flags)
.envs(self.props.rustc_env.clone());
self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
@@ -936,7 +955,9 @@ impl<'test> TestCx<'test> {
.arg("-L")
.arg(&self.config.build_base)
.arg("-L")
- .arg(aux_dir);
+ .arg(aux_dir)
+ .arg("-A")
+ .arg("internal_features");
self.set_revision_flags(&mut rustc);
self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
rustc.args(&self.props.compile_flags);
@@ -997,16 +1018,13 @@ impl<'test> TestCx<'test> {
};
// Parse debugger commands etc from test files
- let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
- match DebuggerCommands::parse_from(
- &self.testpaths.file,
- self.config,
- prefixes,
- self.revision,
- ) {
- Ok(cmds) => cmds,
- Err(e) => self.fatal(&e),
- };
+ let dbg_cmds = DebuggerCommands::parse_from(
+ &self.testpaths.file,
+ self.config,
+ prefixes,
+ self.revision,
+ )
+ .unwrap_or_else(|e| self.fatal(&e));
// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
let mut script_str = String::with_capacity(2048);
@@ -1023,12 +1041,12 @@ impl<'test> TestCx<'test> {
// Set breakpoints on every line that contains the string "#break"
let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
- for line in &breakpoint_lines {
+ for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(&format!("bp `{}:{}`\n", source_file_name, line));
}
// Append the other `cdb-command:`s
- for line in &commands {
+ for line in &dbg_cmds.commands {
script_str.push_str(line);
script_str.push_str("\n");
}
@@ -1058,7 +1076,7 @@ impl<'test> TestCx<'test> {
self.fatal_proc_rec("Error while running CDB", &debugger_run_result);
}
- if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
+ if let Err(e) = dbg_cmds.check_output(&debugger_run_result) {
self.fatal_proc_rec(&e, &debugger_run_result);
}
}
@@ -1088,17 +1106,14 @@ impl<'test> TestCx<'test> {
PREFIXES
};
- let DebuggerCommands { commands, check_lines, breakpoint_lines } =
- match DebuggerCommands::parse_from(
- &self.testpaths.file,
- self.config,
- prefixes,
- self.revision,
- ) {
- Ok(cmds) => cmds,
- Err(e) => self.fatal(&e),
- };
- let mut cmds = commands.join("\n");
+ let dbg_cmds = DebuggerCommands::parse_from(
+ &self.testpaths.file,
+ self.config,
+ prefixes,
+ self.revision,
+ )
+ .unwrap_or_else(|e| self.fatal(&e));
+ let mut cmds = dbg_cmds.commands.join("\n");
// compile test file (it should have 'compile-flags:-g' in the header)
let should_run = self.run_if_enabled();
@@ -1132,13 +1147,14 @@ impl<'test> TestCx<'test> {
./{}/stage2/lib/rustlib/{}/lib/\n",
self.config.host, self.config.target
));
- for line in &breakpoint_lines {
+ for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(
- &format!(
+ format!(
"break {:?}:{}\n",
self.testpaths.file.file_name().unwrap().to_string_lossy(),
*line
- )[..],
+ )
+ .as_str(),
);
}
script_str.push_str(&cmds);
@@ -1279,7 +1295,7 @@ impl<'test> TestCx<'test> {
}
// Add line breakpoints
- for line in &breakpoint_lines {
+ for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(&format!(
"break '{}':{}\n",
self.testpaths.file.file_name().unwrap().to_string_lossy(),
@@ -1315,7 +1331,7 @@ impl<'test> TestCx<'test> {
self.fatal_proc_rec("gdb failed to execute", &debugger_run_result);
}
- if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
+ if let Err(e) = dbg_cmds.check_output(&debugger_run_result) {
self.fatal_proc_rec(&e, &debugger_run_result);
}
}
@@ -1372,16 +1388,13 @@ impl<'test> TestCx<'test> {
};
// Parse debugger commands etc from test files
- let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
- match DebuggerCommands::parse_from(
- &self.testpaths.file,
- self.config,
- prefixes,
- self.revision,
- ) {
- Ok(cmds) => cmds,
- Err(e) => self.fatal(&e),
- };
+ let dbg_cmds = DebuggerCommands::parse_from(
+ &self.testpaths.file,
+ self.config,
+ prefixes,
+ self.revision,
+ )
+ .unwrap_or_else(|e| self.fatal(&e));
// Write debugger script:
// We don't want to hang when calling `quit` while the process is still running
@@ -1430,7 +1443,7 @@ impl<'test> TestCx<'test> {
// Set breakpoints on every line that contains the string "#break"
let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
- for line in &breakpoint_lines {
+ for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(&format!(
"breakpoint set --file '{}' --line {}\n",
source_file_name, line
@@ -1438,7 +1451,7 @@ impl<'test> TestCx<'test> {
}
// Append the other commands
- for line in &commands {
+ for line in &dbg_cmds.commands {
script_str.push_str(line);
script_str.push_str("\n");
}
@@ -1458,7 +1471,7 @@ impl<'test> TestCx<'test> {
self.fatal_proc_rec("Error while running LLDB", &debugger_run_result);
}
- if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
+ if let Err(e) = dbg_cmds.check_output(&debugger_run_result) {
self.fatal_proc_rec(&e, &debugger_run_result);
}
}
@@ -1649,7 +1662,7 @@ impl<'test> TestCx<'test> {
if self.props.known_bug {
if !expected_errors.is_empty() {
self.fatal_proc_rec(
- "`known_bug` tests should not have an expected errors",
+ "`known_bug` tests should not have an expected error",
proc_res,
);
}
@@ -1875,6 +1888,8 @@ impl<'test> TestCx<'test> {
.arg("--deny")
.arg("warnings")
.arg(&self.testpaths.file)
+ .arg("-A")
+ .arg("internal_features")
.args(&self.props.compile_flags);
if self.config.mode == RustdocJson {
@@ -1941,7 +1956,8 @@ impl<'test> TestCx<'test> {
let mut test_client =
Command::new(self.config.remote_test_client.as_ref().unwrap());
test_client
- .args(&["run", &support_libs.len().to_string(), &prog])
+ .args(&["run", &support_libs.len().to_string()])
+ .arg(&prog)
.args(support_libs)
.args(args);
@@ -2338,6 +2354,14 @@ impl<'test> TestCx<'test> {
// Hide line numbers to reduce churn
rustc.arg("-Zui-testing");
rustc.arg("-Zdeduplicate-diagnostics=no");
+ // #[cfg(not(bootstrap)] unconditionally pass flag after beta bump
+ // since `ui-fulldeps --stage=1` builds using the stage 0 compiler,
+ // which doesn't have this flag.
+ if !(self.config.stage_id.starts_with("stage1-")
+ && self.config.suite == "ui-fulldeps")
+ {
+ rustc.arg("-Zwrite-long-types-to-disk=no");
+ }
// FIXME: use this for other modes too, for perf?
rustc.arg("-Cstrip=debuginfo");
}
@@ -2459,6 +2483,14 @@ impl<'test> TestCx<'test> {
rustc.args(&["-A", "unused"]);
}
+ // #[cfg(not(bootstrap)] unconditionally pass flag after beta bump
+ // since `ui-fulldeps --stage=1` builds using the stage 0 compiler,
+ // which doesn't have this lint.
+ if !(self.config.stage_id.starts_with("stage1-") && self.config.suite == "ui-fulldeps") {
+ // Allow tests to use internal features.
+ rustc.args(&["-A", "internal_features"]);
+ }
+
if self.props.force_host {
self.maybe_add_external_args(&mut rustc, &self.config.host_rustcflags);
if !is_rustdoc {
@@ -2516,7 +2548,7 @@ impl<'test> TestCx<'test> {
// If this is emscripten, then run tests under nodejs
if self.config.target.contains("emscripten") {
if let Some(ref p) = self.config.nodejs {
- args.push(p.clone());
+ args.push(p.into());
} else {
self.fatal("emscripten target requested and no NodeJS binary found (--nodejs)");
}
@@ -2524,7 +2556,7 @@ impl<'test> TestCx<'test> {
// shim
} else if self.config.target.contains("wasm32") {
if let Some(ref p) = self.config.nodejs {
- args.push(p.clone());
+ args.push(p.into());
} else {
self.fatal("wasm32 target requested and no NodeJS binary found (--nodejs)");
}
@@ -2536,13 +2568,12 @@ impl<'test> TestCx<'test> {
.unwrap() // chop off `ui`
.parent()
.unwrap(); // chop off `tests`
- args.push(src.join("src/etc/wasm32-shim.js").display().to_string());
+ args.push(src.join("src/etc/wasm32-shim.js").into_os_string());
}
let exe_file = self.make_exe_name();
- // FIXME (#9639): This needs to handle non-utf8 paths
- args.push(exe_file.to_str().unwrap().to_owned());
+ args.push(exe_file.into_os_string());
// Add the arguments in the run_flags directive
args.extend(self.split_maybe_args(&self.props.run_flags));
@@ -2551,12 +2582,16 @@ impl<'test> TestCx<'test> {
ProcArgs { prog, args }
}
- fn split_maybe_args(&self, argstr: &Option<String>) -> Vec<String> {
+ fn split_maybe_args(&self, argstr: &Option<String>) -> Vec<OsString> {
match *argstr {
Some(ref s) => s
.split(' ')
.filter_map(|s| {
- if s.chars().all(|c| c.is_whitespace()) { None } else { Some(s.to_owned()) }
+ if s.chars().all(|c| c.is_whitespace()) {
+ None
+ } else {
+ Some(OsString::from(s))
+ }
})
.collect(),
None => Vec::new(),
@@ -2760,6 +2795,10 @@ impl<'test> TestCx<'test> {
self.fatal_proc_rec("compilation failed!", &proc_res);
}
+ if let Some(PassMode::Build) = self.pass_mode() {
+ return;
+ }
+
let output_path = self.output_base_name().with_extension("ll");
let proc_res = self.verify_with_filecheck(&output_path);
if !proc_res.status.success() {
@@ -4153,8 +4192,8 @@ impl<'test> TestCx<'test> {
# Match paths that don't include spaces.
(?:\\[\pL\pN\.\-_']+)+\.\pL+
|
- # If the path starts with a well-known root, then allow spaces.
- \$(?:DIR|SRC_DIR|TEST_BUILD_DIR|BUILD_DIR|LIB_DIR)(?:\\[\pL\pN\.\-_' ]+)+
+ # If the path starts with a well-known root, then allow spaces and no file extension.
+ \$(?:DIR|SRC_DIR|TEST_BUILD_DIR|BUILD_DIR|LIB_DIR)(?:\\[\pL\pN\.\-_'\ ]+)+
)"#,
)
.unwrap()
@@ -4359,8 +4398,8 @@ impl<'test> TestCx<'test> {
}
struct ProcArgs {
- prog: String,
- args: Vec<String>,
+ prog: OsString,
+ args: Vec<OsString>,
}
pub struct ProcRes {
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index 379ff0bab..eebe5f358 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -2,18 +2,25 @@ use crate::common::Config;
use crate::header::line_directive;
use crate::runtest::ProcRes;
+use std::fmt::Write;
use std::fs::File;
use std::io::{BufRead, BufReader};
-use std::path::Path;
+use std::path::{Path, PathBuf};
+/// Representation of information to invoke a debugger and check its output
pub(super) struct DebuggerCommands {
+ /// Commands for the debuuger
pub commands: Vec<String>,
- pub check_lines: Vec<String>,
+ /// Lines to insert breakpoints at
pub breakpoint_lines: Vec<usize>,
+ /// Contains the source line number to check and the line itself
+ check_lines: Vec<(usize, String)>,
+ /// Source file name
+ file: PathBuf,
}
impl DebuggerCommands {
- pub(super) fn parse_from(
+ pub fn parse_from(
file: &Path,
config: &Config,
debugger_prefixes: &[&str],
@@ -21,7 +28,7 @@ impl DebuggerCommands {
) -> Result<Self, String> {
let directives = debugger_prefixes
.iter()
- .map(|prefix| (format!("{}-command", prefix), format!("{}-check", prefix)))
+ .map(|prefix| (format!("{prefix}-command"), format!("{prefix}-check")))
.collect::<Vec<_>>();
let mut breakpoint_lines = vec![];
@@ -29,63 +36,88 @@ impl DebuggerCommands {
let mut check_lines = vec![];
let mut counter = 0;
let reader = BufReader::new(File::open(file).unwrap());
- for line in reader.lines() {
+ for (line_no, line) in reader.lines().enumerate() {
counter += 1;
- match line {
- Ok(line) => {
- let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line));
-
- // Skip any revision specific directive that doesn't match the current
- // revision being tested
- if lnrev.is_some() && lnrev != rev {
- continue;
- }
-
- if line.contains("#break") {
- breakpoint_lines.push(counter);
- }
-
- for &(ref command_directive, ref check_directive) in &directives {
- config
- .parse_name_value_directive(&line, command_directive)
- .map(|cmd| commands.push(cmd));
-
- config
- .parse_name_value_directive(&line, check_directive)
- .map(|cmd| check_lines.push(cmd));
- }
- }
- Err(e) => return Err(format!("Error while parsing debugger commands: {}", e)),
+ let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?;
+ let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line));
+
+ // Skip any revision specific directive that doesn't match the current
+ // revision being tested
+ if lnrev.is_some() && lnrev != rev {
+ continue;
+ }
+
+ if line.contains("#break") {
+ breakpoint_lines.push(counter);
+ }
+
+ for &(ref command_directive, ref check_directive) in &directives {
+ config
+ .parse_name_value_directive(&line, command_directive)
+ .map(|cmd| commands.push(cmd));
+
+ config
+ .parse_name_value_directive(&line, check_directive)
+ .map(|cmd| check_lines.push((line_no, cmd)));
}
}
- Ok(Self { commands, check_lines, breakpoint_lines })
+ Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_owned() })
}
-}
-pub(super) fn check_debugger_output(
- debugger_run_result: &ProcRes,
- check_lines: &[String],
-) -> Result<(), String> {
- let num_check_lines = check_lines.len();
-
- let mut check_line_index = 0;
- for line in debugger_run_result.stdout.lines() {
- if check_line_index >= num_check_lines {
- break;
+ /// Given debugger output and lines to check, ensure that every line is
+ /// contained in the debugger output. The check lines need to be found in
+ /// order, but there can be extra lines between.
+ pub fn check_output(&self, debugger_run_result: &ProcRes) -> Result<(), String> {
+ // (src_lineno, ck_line) that we did find
+ let mut found = vec![];
+ // (src_lineno, ck_line) that we couldn't find
+ let mut missing = vec![];
+ // We can find our any current match anywhere after our last match
+ let mut last_idx = 0;
+ let dbg_lines: Vec<&str> = debugger_run_result.stdout.lines().collect();
+
+ for (src_lineno, ck_line) in &self.check_lines {
+ if let Some(offset) = dbg_lines
+ .iter()
+ .skip(last_idx)
+ .position(|out_line| check_single_line(out_line, &ck_line))
+ {
+ last_idx += offset;
+ found.push((src_lineno, dbg_lines[last_idx]));
+ } else {
+ missing.push((src_lineno, ck_line));
+ }
}
- if check_single_line(line, &(check_lines[check_line_index])[..]) {
- check_line_index += 1;
+ if missing.is_empty() {
+ Ok(())
+ } else {
+ let fname = self.file.file_name().unwrap().to_string_lossy();
+ let mut msg = format!(
+ "check directive(s) from `{}` not found in debugger output. errors:",
+ self.file.display()
+ );
+
+ for (src_lineno, err_line) in missing {
+ write!(msg, "\n ({fname}:{num}) `{err_line}`", num = src_lineno + 1).unwrap();
+ }
+
+ if !found.is_empty() {
+ let init = "\nthe following subset of check directive(s) was found successfully:";
+ msg.push_str(init);
+ for (src_lineno, found_line) in found {
+ write!(msg, "\n ({fname}:{num}) `{found_line}`", num = src_lineno + 1)
+ .unwrap();
+ }
+ }
+
+ Err(msg)
}
}
- if check_line_index != num_check_lines && num_check_lines > 0 {
- Err(format!("line not found in debugger output: {}", check_lines[check_line_index]))
- } else {
- Ok(())
- }
}
+/// Check that the pattern in `check_line` applies to `line`. Returns `true` if they do match.
fn check_single_line(line: &str, check_line: &str) -> bool {
// Allow check lines to leave parts unspecified (e.g., uninitialized
// bits in the wrong case of an enum) with the notation "[...]".
@@ -101,21 +133,19 @@ fn check_single_line(line: &str, check_line: &str) -> bool {
}
let (mut rest, first_fragment) = if can_start_anywhere {
- match line.find(check_fragments[0]) {
- Some(pos) => (&line[pos + check_fragments[0].len()..], 1),
- None => return false,
- }
+ let Some(pos) = line.find(check_fragments[0]) else {
+ return false;
+ };
+ (&line[pos + check_fragments[0].len()..], 1)
} else {
(line, 0)
};
for current_fragment in &check_fragments[first_fragment..] {
- match rest.find(current_fragment) {
- Some(pos) => {
- rest = &rest[pos + current_fragment.len()..];
- }
- None => return false,
- }
+ let Some(pos) = rest.find(current_fragment) else {
+ return false;
+ };
+ rest = &rest[pos + current_fragment.len()..];
}
if !can_end_anywhere && !rest.is_empty() { false } else { true }
diff --git a/src/tools/compiletest/src/runtest/tests.rs b/src/tools/compiletest/src/runtest/tests.rs
index 511051111..fb3dd326a 100644
--- a/src/tools/compiletest/src/runtest/tests.rs
+++ b/src/tools/compiletest/src/runtest/tests.rs
@@ -8,8 +8,8 @@ fn normalize_platform_differences() {
"$BUILD_DIR/../parser.rs"
);
assert_eq!(
- TestCx::normalize_platform_differences(r"$DIR\bar.rs hello\nworld"),
- r"$DIR/bar.rs hello\nworld"
+ TestCx::normalize_platform_differences(r"$DIR\bar.rs: hello\nworld"),
+ r"$DIR/bar.rs: hello\nworld"
);
assert_eq!(
TestCx::normalize_platform_differences(r"either bar\baz.rs or bar\baz\mod.rs"),
@@ -27,8 +27,8 @@ fn normalize_platform_differences() {
);
assert_eq!(TestCx::normalize_platform_differences(r"$DIR\foo.rs:12:11"), "$DIR/foo.rs:12:11",);
assert_eq!(
- TestCx::normalize_platform_differences(r"$DIR\path with spaces 'n' quotes"),
- "$DIR/path with spaces 'n' quotes",
+ TestCx::normalize_platform_differences(r"$DIR\path with\spaces 'n' quotes"),
+ "$DIR/path with/spaces 'n' quotes",
);
assert_eq!(
TestCx::normalize_platform_differences(r"$DIR\file_with\no_extension"),