about summary refs log tree commit diff
diff options
context:
space:
mode:
authorZalathar <Zalathar@users.noreply.github.com>2025-10-02 20:08:40 +1000
committerZalathar <Zalathar@users.noreply.github.com>2025-10-03 13:56:33 +1000
commitc368f9a89f38ef0226917a56d4361a23ac7150bb (patch)
tree1d24965ee6871493d8925937fb2869e494f91c83
parent181b302b661dcf4db45c1f99bef4cddefc497f44 (diff)
downloadrust-c368f9a89f38ef0226917a56d4361a23ac7150bb.tar.gz
rust-c368f9a89f38ef0226917a56d4361a23ac7150bb.zip
Allow easy extraction of name/value from a `DirectiveLine`
-rw-r--r--src/tools/compiletest/src/directives.rs10
-rw-r--r--src/tools/compiletest/src/directives/line.rs45
2 files changed, 50 insertions, 5 deletions
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index edb06dd7345..bbbeecc1b71 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -875,15 +875,17 @@ fn iter_directives(
     // FIXME(jieyouxu): I feel like there's a better way to do this, leaving for later.
     if mode == TestMode::CoverageRun {
         let extra_directives: &[&str] = &[
-            "needs-profiler-runtime",
+            "//@ needs-profiler-runtime",
             // FIXME(pietroalbini): this test currently does not work on cross-compiled targets
             // because remote-test is not capable of sending back the *.profraw files generated by
             // the LLVM instrumentation.
-            "ignore-cross-compile",
+            "//@ ignore-cross-compile",
         ];
         // Process the extra implied directives, with a dummy line number of 0.
-        for raw_directive in extra_directives {
-            it(DirectiveLine { line_number: 0, revision: None, raw_directive });
+        for directive_str in extra_directives {
+            let directive_line = line_directive(0, directive_str)
+                .unwrap_or_else(|| panic!("bad extra-directive line: {directive_str:?}"));
+            it(directive_line);
         }
     }
 
diff --git a/src/tools/compiletest/src/directives/line.rs b/src/tools/compiletest/src/directives/line.rs
index 5ad890fce44..9c07a6a18b2 100644
--- a/src/tools/compiletest/src/directives/line.rs
+++ b/src/tools/compiletest/src/directives/line.rs
@@ -1,3 +1,7 @@
+#![expect(dead_code)] // (removed later in this PR)
+
+use std::fmt;
+
 const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@";
 
 /// If the given line begins with the appropriate comment prefix for a directive,
@@ -28,7 +32,10 @@ pub(crate) fn line_directive<'line>(
         raw_directive = after_comment;
     };
 
-    Some(DirectiveLine { line_number, revision, raw_directive })
+    // The directive name ends at the first occurrence of colon, space, or end-of-string.
+    let name = raw_directive.split([':', ' ']).next().expect("split is never empty");
+
+    Some(DirectiveLine { line_number, revision, raw_directive, name })
 }
 
 /// The (partly) broken-down contents of a line containing a test directive,
@@ -39,10 +46,12 @@ pub(crate) fn line_directive<'line>(
 /// ```text
 /// //@ compile-flags: -O
 ///     ^^^^^^^^^^^^^^^^^ raw_directive
+///     ^^^^^^^^^^^^^     name
 ///
 /// //@ [foo] compile-flags: -O
 ///      ^^^                    revision
 ///           ^^^^^^^^^^^^^^^^^ raw_directive
+///           ^^^^^^^^^^^^^     name
 /// ```
 pub(crate) struct DirectiveLine<'ln> {
     pub(crate) line_number: usize,
@@ -58,10 +67,44 @@ pub(crate) struct DirectiveLine<'ln> {
     /// This is "raw" because the directive's name and colon-separated value
     /// (if present) have not yet been extracted or checked.
     pub(crate) raw_directive: &'ln str,
+
+    /// Name of the directive.
+    ///
+    /// Invariant: `self.raw_directive.starts_with(self.name)`
+    pub(crate) name: &'ln str,
 }
 
 impl<'ln> DirectiveLine<'ln> {
     pub(crate) fn applies_to_test_revision(&self, test_revision: Option<&str>) -> bool {
         self.revision.is_none() || self.revision == test_revision
     }
+
+    /// Helper method used by `value_after_colon` and `remark_after_space`.
+    /// Don't call this directly.
+    fn rest_after_separator(&self, separator: u8) -> Option<&'ln str> {
+        let n = self.name.len();
+        if self.raw_directive.as_bytes().get(n) != Some(&separator) {
+            return None;
+        }
+
+        Some(&self.raw_directive[n + 1..])
+    }
+
+    /// If this directive uses `name: value` syntax, returns the part after
+    /// the colon character.
+    pub(crate) fn value_after_colon(&self) -> Option<&'ln str> {
+        self.rest_after_separator(b':')
+    }
+
+    /// If this directive uses `name remark` syntax, returns the part after
+    /// the separating space.
+    pub(crate) fn remark_after_space(&self) -> Option<&'ln str> {
+        self.rest_after_separator(b' ')
+    }
+
+    /// Allows callers to print `raw_directive` if necessary,
+    /// without accessing the field directly.
+    pub(crate) fn display(&self) -> impl fmt::Display {
+        self.raw_directive
+    }
 }