diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index 00935ab57d1c3..51645eb3a3592 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -8,7 +8,7 @@ use crate::runtest::ProcRes; /// Representation of information to invoke a debugger and check its output pub(super) struct DebuggerCommands { - /// Commands for the debuuger + /// Commands for the debugger pub commands: Vec, /// Lines to insert breakpoints at pub breakpoint_lines: Vec, @@ -16,10 +16,16 @@ pub(super) struct DebuggerCommands { check_lines: Vec<(usize, String)>, /// Source file name file: Utf8PathBuf, + /// The revision being tested, if any + revision: Option, } impl DebuggerCommands { - pub fn parse_from(file: &Utf8Path, debugger_prefix: &str) -> Result { + pub fn parse_from( + file: &Utf8Path, + debugger_prefix: &str, + test_revision: Option<&str>, + ) -> Result { let command_directive = format!("{debugger_prefix}-command"); let check_directive = format!("{debugger_prefix}-check"); @@ -38,19 +44,59 @@ impl DebuggerCommands { continue; } - let Some(line) = line.trim_start().strip_prefix("//@").map(str::trim_start) else { + let Some(after_prefix) = line.trim_start().strip_prefix("//@").map(str::trim_start) + else { continue; }; - if let Some(command) = parse_name_value(&line, &command_directive) { + // Handle revision-specific directives like `//@ [revision] directive` + // by stripping the revision prefix if present + let (line_revision, directive_line) = + if let Some(after_open_bracket) = after_prefix.strip_prefix('[') { + if let Some((revision, after_close_bracket)) = + after_open_bracket.split_once(']') + { + (Some(revision), after_close_bracket.trim_start()) + } else { + // Malformed revision prefix, skip this line + continue; + } + } else { + (None, after_prefix) + }; + + // Only process directives that apply to the current revision: + // - Directives without a revision prefix apply to all revisions + // - Directives with a revision prefix only apply when it matches the test revision + let applies_to_revision = match (test_revision, line_revision) { + // Directives with a revision prefix only apply to that specific revision + (Some(test_rev), Some(line_rev)) => test_rev == line_rev, + // No test revision means we're not running a revisioned test, + // so directives with revision prefixes shouldn't be processed + (None, Some(_)) => false, + // If a directive has no revision prefix, it applies to all revisions + (_, None) => true, + }; + + if !applies_to_revision { + continue; + } + + if let Some(command) = parse_name_value(directive_line, &command_directive) { commands.push(command); } - if let Some(pattern) = parse_name_value(&line, &check_directive) { + if let Some(pattern) = parse_name_value(directive_line, &check_directive) { check_lines.push((line_no, pattern)); } } - Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_path_buf() }) + Ok(Self { + commands, + breakpoint_lines, + check_lines, + file: file.to_path_buf(), + revision: test_revision.map(str::to_owned), + }) } /// Given debugger output and lines to check, ensure that every line is @@ -82,9 +128,11 @@ impl DebuggerCommands { Ok(()) } else { let fname = self.file.file_name().unwrap(); + let revision_suffix = + self.revision.as_ref().map_or(String::new(), |r| format!("#{}", r)); let mut msg = format!( - "check directive(s) from `{}` not found in debugger output. errors:", - self.file + "check directive(s) from `{}{}` not found in debugger output. errors:", + self.file, revision_suffix ); for (src_lineno, err_line) in missing { @@ -150,3 +198,30 @@ fn check_single_line(line: &str, check_line: &str) -> bool { can_end_anywhere || rest.is_empty() } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_check_single_line_exact_match() { + assert!(check_single_line("$1 = 42", "$1 = 42")); + assert!(!check_single_line("$1 = 42", "$1 = 43")); + } + + #[test] + fn test_check_single_line_with_wildcard() { + assert!(check_single_line("$1 = 42 (some extra stuff)", "$1 = 42[...]")); + assert!(check_single_line("prefix $1 = 42 suffix", "[...]$1 = 42[...]")); + assert!(!check_single_line("$1 = 43", "$1 = 42[...]")); + } + + #[test] + fn test_parse_name_value() { + assert_eq!(parse_name_value("gdb-command:run", "gdb-command"), Some("run".to_string())); + assert_eq!(parse_name_value("gdb-command:", "gdb-command"), Some("".to_string())); + assert_eq!(parse_name_value("gdb-check:$1 = 42", "gdb-check"), Some("$1 = 42".to_string())); + assert_eq!(parse_name_value("lldb-command:run", "gdb-command"), None); + assert_eq!(parse_name_value("gdb-command run", "gdb-command"), None); + } +} diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 15e37cda7d965..c73cce1332e6d 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -46,7 +46,7 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb", self.revision) .unwrap_or_else(|e| self.fatal(&e)); // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands @@ -105,7 +105,7 @@ impl TestCx<'_> { } fn run_debuginfo_gdb_test(&self) { - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb", self.revision) .unwrap_or_else(|e| self.fatal(&e)); let mut cmds = dbg_cmds.commands.join("\n"); @@ -360,7 +360,7 @@ impl TestCx<'_> { } // Parse debugger commands etc from test files - let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb") + let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb", self.revision) .unwrap_or_else(|e| self.fatal(&e)); // Write debugger script: