about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/traits/select.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-rw-r--r--library/std/src/io/buffered/bufreader.rs11
-rw-r--r--library/std/src/sys/windows/fs.rs4
-rw-r--r--library/std/src/sys/windows/stack_overflow.rs8
-rw-r--r--library/std/src/sys_common/backtrace.rs6
-rw-r--r--src/librustdoc/clean/blanket_impl.rs2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css6
-rw-r--r--src/test/rustdoc-gui/docblock-big-code-mobile.goml9
-rw-r--r--src/test/rustdoc-gui/src/test_docs/lib.rs3
-rw-r--r--src/test/ui/wasm/simd-to-array-80108.rs15
-rw-r--r--src/tools/compiletest/src/runtest.rs161
-rw-r--r--src/tools/compiletest/src/runtest/debugger.rs115
15 files changed, 203 insertions, 151 deletions
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 87495a2d5b3..6720493cd3c 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -264,14 +264,14 @@ impl EvaluationResult {
 /// Indicates that trait evaluation caused overflow and in which pass.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
 pub enum OverflowError {
-    Cannonical,
+    Canonical,
     ErrorReporting,
 }
 
 impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
     fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
         match overflow_error {
-            OverflowError::Cannonical => SelectionError::Overflow,
+            OverflowError::Canonical => SelectionError::Overflow,
             OverflowError::ErrorReporting => SelectionError::ErrorReporting,
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 31254a0534d..2fa6c0c0259 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -83,10 +83,10 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
     ) -> EvaluationResult {
         match self.evaluate_obligation(obligation) {
             Ok(result) => result,
-            Err(OverflowError::Cannonical) => {
+            Err(OverflowError::Canonical) => {
                 let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
                 selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r {
-                    OverflowError::Cannonical => {
+                    OverflowError::Canonical => {
                         span_bug!(
                             obligation.cause.span,
                             "Overflow should be caught earlier in standard query mode: {:?}, {:?}",
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index d68ae079077..0f6e2e0be52 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -161,7 +161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
                 }
                 Ok(_) => Ok(None),
-                Err(OverflowError::Cannonical) => Err(Overflow),
+                Err(OverflowError::Canonical) => Err(Overflow),
                 Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
             })
             .flat_map(Result::transpose)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 3818e75a1de..85502a399de 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -900,7 +900,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         match self.candidate_from_obligation(stack) {
             Ok(Some(c)) => self.evaluate_candidate(stack, &c),
             Ok(None) => Ok(EvaluatedToAmbig),
-            Err(Overflow) => Err(OverflowError::Cannonical),
+            Err(Overflow) => Err(OverflowError::Canonical),
             Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
             Err(..) => Ok(EvaluatedToErr),
         }
@@ -1064,7 +1064,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     self.infcx.report_overflow_error(error_obligation, true);
                 }
                 TraitQueryMode::Canonical => {
-                    return Err(OverflowError::Cannonical);
+                    return Err(OverflowError::Canonical);
                 }
             }
         }
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 243207a6065..2864e94f60f 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -242,14 +242,13 @@ impl<R: Seek> BufReader<R> {
                 self.pos = new_pos as usize;
                 return Ok(());
             }
-        } else {
-            if let Some(new_pos) = pos.checked_add(offset as u64) {
-                if new_pos <= self.cap as u64 {
-                    self.pos = new_pos as usize;
-                    return Ok(());
-                }
+        } else if let Some(new_pos) = pos.checked_add(offset as u64) {
+            if new_pos <= self.cap as u64 {
+                self.pos = new_pos as usize;
+                return Ok(());
             }
         }
+
         self.seek(SeekFrom::Current(offset)).map(drop)
     }
 }
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index cc137771bb8..ad550a823ae 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -558,7 +558,7 @@ impl IntoInner<Handle> for File {
 
 impl FromInner<Handle> for File {
     fn from_inner(handle: Handle) -> File {
-        File { handle: handle }
+        File { handle }
     }
 }
 
@@ -672,7 +672,7 @@ impl FilePermissions {
 
 impl FileType {
     fn new(attrs: c::DWORD, reparse_tag: c::DWORD) -> FileType {
-        FileType { attributes: attrs, reparse_tag: reparse_tag }
+        FileType { attributes: attrs, reparse_tag }
     }
     pub fn is_dir(&self) -> bool {
         !self.is_symlink() && self.is_directory()
diff --git a/library/std/src/sys/windows/stack_overflow.rs b/library/std/src/sys/windows/stack_overflow.rs
index 755dc0a6c8b..18a2a36ad25 100644
--- a/library/std/src/sys/windows/stack_overflow.rs
+++ b/library/std/src/sys/windows/stack_overflow.rs
@@ -9,10 +9,10 @@ impl Handler {
     pub unsafe fn new() -> Handler {
         // This API isn't available on XP, so don't panic in that case and just
         // pray it works out ok.
-        if c::SetThreadStackGuarantee(&mut 0x5000) == 0 {
-            if c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32 {
-                panic!("failed to reserve stack space for exception handling");
-            }
+        if c::SetThreadStackGuarantee(&mut 0x5000) == 0
+            && c::GetLastError() as u32 != c::ERROR_CALL_NOT_IMPLEMENTED as u32
+        {
+            panic!("failed to reserve stack space for exception handling");
         }
         Handler
     }
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index e6a099f0e81..d5e8f12414f 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -93,10 +93,8 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
         if stop {
             return false;
         }
-        if !hit {
-            if start {
-                res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
-            }
+        if !hit && start {
+            res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
         }
 
         idx += 1;
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index dd0cbb1b952..843dda324da 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -78,7 +78,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                             );
                             match infcx.evaluate_obligation(&obligation) {
                                 Ok(eval_result) if eval_result.may_apply() => {}
-                                Err(traits::OverflowError::Cannonical) => {}
+                                Err(traits::OverflowError::Canonical) => {}
                                 Err(traits::OverflowError::ErrorReporting) => {}
                                 _ => {
                                     return false;
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 5d33681847a..cea3452780e 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -773,8 +773,6 @@ h2.small-section-header > .anchor {
 
 .item-table {
 	display: table-row;
-	/* align content left */
-	justify-items: start;
 }
 .item-row {
 	display: table-row;
@@ -1969,4 +1967,8 @@ details.undocumented[open] > summary::before {
 	.docblock {
 		margin-left: 12px;
 	}
+
+	.docblock code {
+		overflow-wrap: anywhere;
+	}
 }
diff --git a/src/test/rustdoc-gui/docblock-big-code-mobile.goml b/src/test/rustdoc-gui/docblock-big-code-mobile.goml
new file mode 100644
index 00000000000..12677a5648a
--- /dev/null
+++ b/src/test/rustdoc-gui/docblock-big-code-mobile.goml
@@ -0,0 +1,9 @@
+// If we have a long `<code>`, we need to ensure that it'll be fully displayed on mobile, meaning
+// that it'll be on two lines.
+emulate: "iPhone 8" // it has the following size: (375, 667)
+goto: file://|DOC_PATH|/test_docs/long_code_block/index.html
+// We now check that the block is on two lines:
+show-text: true // We need to enable text draw to be able to have the "real" size
+// Little explanations for this test: if the text wasn't displayed on two lines, it would take
+// around 20px (which is the font size).
+assert-property: (".docblock p > code", {"offsetHeight": "42"})
diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs
index 0aa1426a36a..2a147e64d8b 100644
--- a/src/test/rustdoc-gui/src/test_docs/lib.rs
+++ b/src/test/rustdoc-gui/src/test_docs/lib.rs
@@ -120,3 +120,6 @@ pub type SomeType = u32;
 pub mod huge_amount_of_consts {
     include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs"));
 }
+
+/// Very long code text `hereIgoWithLongTextBecauseWhyNotAndWhyWouldntI`.
+pub mod long_code_block {}
diff --git a/src/test/ui/wasm/simd-to-array-80108.rs b/src/test/ui/wasm/simd-to-array-80108.rs
new file mode 100644
index 00000000000..0576c2e6be1
--- /dev/null
+++ b/src/test/ui/wasm/simd-to-array-80108.rs
@@ -0,0 +1,15 @@
+// only-wasm32
+// compile-flags: --crate-type=lib -Copt-level=2
+// build-pass
+#![feature(repr_simd)]
+
+// Regression test for #80108
+
+#[repr(simd)]
+pub struct Vector([i32; 4]);
+
+impl Vector {
+    pub const fn to_array(self) -> [i32; 4] {
+        self.0
+    }
+}
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 934839bbd60..4470272a9f8 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -38,6 +38,9 @@ use tracing::*;
 use crate::extract_gdb_version;
 use crate::is_android_gdb_target;
 
+mod debugger;
+use debugger::{check_debugger_output, DebuggerCommands};
+
 #[cfg(test)]
 mod tests;
 
@@ -200,12 +203,6 @@ struct TestCx<'test> {
     revision: Option<&'test str>,
 }
 
-struct DebuggerCommands {
-    commands: Vec<String>,
-    check_lines: Vec<String>,
-    breakpoint_lines: Vec<usize>,
-}
-
 enum ReadFrom {
     Path,
     Stdin(String),
@@ -235,10 +232,8 @@ 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 {
-            if self.config.mode != Incremental {
-                self.fatal("cannot use should-ice in a test that is not cfail");
-            }
+        if self.props.should_ice && self.config.mode != Incremental {
+            self.fatal("cannot use should-ice in a test that is not cfail");
         }
         match self.config.mode {
             RunPassValgrind => self.run_valgrind_test(),
@@ -674,7 +669,10 @@ impl<'test> TestCx<'test> {
 
         // Parse debugger commands etc from test files
         let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
-            self.parse_debugger_commands(prefixes);
+            match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
+                Ok(cmds) => cmds,
+                Err(e) => self.fatal(&e),
+            };
 
         // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
         let mut script_str = String::with_capacity(2048);
@@ -726,7 +724,9 @@ impl<'test> TestCx<'test> {
             self.fatal_proc_rec("Error while running CDB", &debugger_run_result);
         }
 
-        self.check_debugger_output(&debugger_run_result, &check_lines);
+        if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
+            self.fatal_proc_rec(&e, &debugger_run_result);
+        }
     }
 
     fn run_debuginfo_gdb_test(&self) {
@@ -757,7 +757,10 @@ impl<'test> TestCx<'test> {
         };
 
         let DebuggerCommands { commands, check_lines, breakpoint_lines } =
-            self.parse_debugger_commands(prefixes);
+            match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
+                Ok(cmds) => cmds,
+                Err(e) => self.fatal(&e),
+            };
         let mut cmds = commands.join("\n");
 
         // compile test file (it should have 'compile-flags:-g' in the header)
@@ -960,7 +963,9 @@ impl<'test> TestCx<'test> {
             self.fatal_proc_rec("gdb failed to execute", &debugger_run_result);
         }
 
-        self.check_debugger_output(&debugger_run_result, &check_lines);
+        if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
+            self.fatal_proc_rec(&e, &debugger_run_result);
+        }
     }
 
     fn run_debuginfo_lldb_test(&self) {
@@ -1018,7 +1023,10 @@ impl<'test> TestCx<'test> {
 
         // Parse debugger commands etc from test files
         let DebuggerCommands { commands, check_lines, breakpoint_lines, .. } =
-            self.parse_debugger_commands(prefixes);
+            match DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes) {
+                Ok(cmds) => cmds,
+                Err(e) => self.fatal(&e),
+            };
 
         // Write debugger script:
         // We don't want to hang when calling `quit` while the process is still running
@@ -1094,7 +1102,9 @@ impl<'test> TestCx<'test> {
             self.fatal_proc_rec("Error while running LLDB", &debugger_run_result);
         }
 
-        self.check_debugger_output(&debugger_run_result, &check_lines);
+        if let Err(e) = check_debugger_output(&debugger_run_result, &check_lines) {
+            self.fatal_proc_rec(&e, &debugger_run_result);
+        }
     }
 
     fn run_lldb(
@@ -1131,45 +1141,6 @@ impl<'test> TestCx<'test> {
         ProcRes { status, stdout: out, stderr: err, cmdline: format!("{:?}", cmd) }
     }
 
-    fn parse_debugger_commands(&self, debugger_prefixes: &[&str]) -> DebuggerCommands {
-        let directives = debugger_prefixes
-            .iter()
-            .map(|prefix| (format!("{}-command", prefix), format!("{}-check", prefix)))
-            .collect::<Vec<_>>();
-
-        let mut breakpoint_lines = vec![];
-        let mut commands = vec![];
-        let mut check_lines = vec![];
-        let mut counter = 1;
-        let reader = BufReader::new(File::open(&self.testpaths.file).unwrap());
-        for line in reader.lines() {
-            match line {
-                Ok(line) => {
-                    let line =
-                        if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() };
-
-                    if line.contains("#break") {
-                        breakpoint_lines.push(counter);
-                    }
-
-                    for &(ref command_directive, ref check_directive) in &directives {
-                        self.config
-                            .parse_name_value_directive(&line, command_directive)
-                            .map(|cmd| commands.push(cmd));
-
-                        self.config
-                            .parse_name_value_directive(&line, check_directive)
-                            .map(|cmd| check_lines.push(cmd));
-                    }
-                }
-                Err(e) => self.fatal(&format!("Error while parsing debugger commands: {}", e)),
-            }
-            counter += 1;
-        }
-
-        DebuggerCommands { commands, check_lines, breakpoint_lines }
-    }
-
     fn cleanup_debug_info_options(&self, options: &Option<String>) -> Option<String> {
         if options.is_none() {
             return None;
@@ -1216,66 +1187,6 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn check_debugger_output(&self, debugger_run_result: &ProcRes, check_lines: &[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;
-            }
-
-            if check_single_line(line, &(check_lines[check_line_index])[..]) {
-                check_line_index += 1;
-            }
-        }
-        if check_line_index != num_check_lines && num_check_lines > 0 {
-            self.fatal_proc_rec(
-                &format!("line not found in debugger output: {}", check_lines[check_line_index]),
-                debugger_run_result,
-            );
-        }
-
-        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 "[...]".
-            let line = line.trim();
-            let check_line = check_line.trim();
-            let can_start_anywhere = check_line.starts_with("[...]");
-            let can_end_anywhere = check_line.ends_with("[...]");
-
-            let check_fragments: Vec<&str> =
-                check_line.split("[...]").filter(|frag| !frag.is_empty()).collect();
-            if check_fragments.is_empty() {
-                return true;
-            }
-
-            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,
-                }
-            } 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,
-                }
-            }
-
-            if !can_end_anywhere && !rest.is_empty() {
-                return false;
-            }
-
-            true
-        }
-    }
-
     fn check_error_patterns(
         &self,
         output_to_check: &str,
@@ -2154,9 +2065,9 @@ impl<'test> TestCx<'test> {
 
     fn maybe_dump_to_stdout(&self, out: &str, err: &str) {
         if self.config.verbose {
-            println!("------{}------------------------------", "stdout");
+            println!("------stdout------------------------------");
             println!("{}", out);
-            println!("------{}------------------------------", "stderr");
+            println!("------stderr------------------------------");
             println!("{}", err);
             println!("------------------------------------------");
         }
@@ -3249,11 +3160,10 @@ impl<'test> TestCx<'test> {
                 if !proc_res.status.success() {
                     self.fatal_proc_rec("test run failed!", &proc_res);
                 }
-            } else {
-                if proc_res.status.success() {
-                    self.fatal_proc_rec("test run succeeded!", &proc_res);
-                }
+            } else if proc_res.status.success() {
+                self.fatal_proc_rec("test run succeeded!", &proc_res);
             }
+
             if !self.props.error_patterns.is_empty() {
                 // "// error-pattern" comments
                 self.check_error_patterns(&proc_res.stderr, &proc_res, pm);
@@ -3300,10 +3210,11 @@ impl<'test> TestCx<'test> {
             if !res.status.success() {
                 self.fatal_proc_rec("failed to compile fixed code", &res);
             }
-            if !res.stderr.is_empty() && !self.props.rustfix_only_machine_applicable {
-                if !json::rustfix_diagnostics_only(&res.stderr).is_empty() {
-                    self.fatal_proc_rec("fixed code is still producing diagnostics", &res);
-                }
+            if !res.stderr.is_empty()
+                && !self.props.rustfix_only_machine_applicable
+                && !json::rustfix_diagnostics_only(&res.stderr).is_empty()
+            {
+                self.fatal_proc_rec("fixed code is still producing diagnostics", &res);
             }
         }
     }
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
new file mode 100644
index 00000000000..cbd5e4c431f
--- /dev/null
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -0,0 +1,115 @@
+use crate::common::Config;
+use crate::runtest::ProcRes;
+
+use std::fs::File;
+use std::io::{BufRead, BufReader};
+use std::path::Path;
+
+pub(super) struct DebuggerCommands {
+    pub commands: Vec<String>,
+    pub check_lines: Vec<String>,
+    pub breakpoint_lines: Vec<usize>,
+}
+
+impl DebuggerCommands {
+    pub(super) fn parse_from(
+        file: &Path,
+        config: &Config,
+        debugger_prefixes: &[&str],
+    ) -> Result<Self, String> {
+        let directives = debugger_prefixes
+            .iter()
+            .map(|prefix| (format!("{}-command", prefix), format!("{}-check", prefix)))
+            .collect::<Vec<_>>();
+
+        let mut breakpoint_lines = vec![];
+        let mut commands = vec![];
+        let mut check_lines = vec![];
+        let mut counter = 1;
+        let reader = BufReader::new(File::open(file).unwrap());
+        for line in reader.lines() {
+            match line {
+                Ok(line) => {
+                    let line =
+                        if line.starts_with("//") { line[2..].trim_start() } else { line.as_str() };
+
+                    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)),
+            }
+            counter += 1;
+        }
+
+        Ok(Self { commands, check_lines, breakpoint_lines })
+    }
+}
+
+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;
+        }
+
+        if check_single_line(line, &(check_lines[check_line_index])[..]) {
+            check_line_index += 1;
+        }
+    }
+    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(())
+    }
+}
+
+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 "[...]".
+    let line = line.trim();
+    let check_line = check_line.trim();
+    let can_start_anywhere = check_line.starts_with("[...]");
+    let can_end_anywhere = check_line.ends_with("[...]");
+
+    let check_fragments: Vec<&str> =
+        check_line.split("[...]").filter(|frag| !frag.is_empty()).collect();
+    if check_fragments.is_empty() {
+        return true;
+    }
+
+    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,
+        }
+    } 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,
+        }
+    }
+
+    if !can_end_anywhere && !rest.is_empty() { false } else { true }
+}