about summary refs log tree commit diff
path: root/src/tools/compiletest
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2025-04-07 17:28:58 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2025-04-09 09:51:39 +0300
commitcffc5c21fc49e86859ea5601a4f80d4446b594e9 (patch)
tree4933ae2a4ae569d463959100c0aeddcc138439dc /src/tools/compiletest
parentc1b8b7e86f6ca59929ce08471d0877f748f84901 (diff)
downloadrust-cffc5c21fc49e86859ea5601a4f80d4446b594e9.tar.gz
rust-cffc5c21fc49e86859ea5601a4f80d4446b594e9.zip
compiletest: Add directive `dont-require-annotations`
for making matching on specific diagnostic kinds non-exhaustive

Diffstat (limited to 'src/tools/compiletest')
-rw-r--r--src/tools/compiletest/src/directive-list.rs1
-rw-r--r--src/tools/compiletest/src/errors.rs11
-rw-r--r--src/tools/compiletest/src/header.rs20
-rw-r--r--src/tools/compiletest/src/runtest.rs24
4 files changed, 41 insertions, 15 deletions
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index b2ad5a3b3d0..44d9c0330f7 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -22,6 +22,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "dont-check-compiler-stderr",
     "dont-check-compiler-stdout",
     "dont-check-failure-status",
+    "dont-require-annotations",
     "edition",
     "error-pattern",
     "exact-llvm-major-version",
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index 9b59e4968a3..64d68eb7f23 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -8,7 +8,7 @@ use std::sync::OnceLock;
 use regex::Regex;
 use tracing::*;
 
-#[derive(Copy, Clone, Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum ErrorKind {
     Help,
     Error,
@@ -40,6 +40,15 @@ impl ErrorKind {
             _ => return None,
         })
     }
+
+    pub fn expect_from_user_str(s: &str) -> ErrorKind {
+        ErrorKind::from_user_str(s).unwrap_or_else(|| {
+            panic!(
+                "unexpected diagnostic kind `{s}`, expected \
+                 `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
+            )
+        })
+    }
 }
 
 impl fmt::Display for ErrorKind {
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index a0178f4bcc5..36a9e5df583 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -1,4 +1,4 @@
-use std::collections::HashSet;
+use std::collections::{HashMap, HashSet};
 use std::env;
 use std::fs::File;
 use std::io::BufReader;
@@ -11,6 +11,7 @@ use tracing::*;
 
 use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
 use crate::debuggers::{extract_cdb_version, extract_gdb_version};
+use crate::errors::ErrorKind;
 use crate::executor::{CollectedTestDesc, ShouldPanic};
 use crate::header::auxiliary::{AuxProps, parse_and_update_aux};
 use crate::header::needs::CachedNeedsConditions;
@@ -196,6 +197,8 @@ pub struct TestProps {
     /// Build and use `minicore` as `core` stub for `no_core` tests in cross-compilation scenarios
     /// that don't otherwise want/need `-Z build-std`.
     pub add_core_stubs: bool,
+    /// Whether line annotatins are required for the given error kind.
+    pub require_annotations: HashMap<ErrorKind, bool>,
 }
 
 mod directives {
@@ -212,6 +215,7 @@ mod directives {
     pub const CHECK_RUN_RESULTS: &'static str = "check-run-results";
     pub const DONT_CHECK_COMPILER_STDOUT: &'static str = "dont-check-compiler-stdout";
     pub const DONT_CHECK_COMPILER_STDERR: &'static str = "dont-check-compiler-stderr";
+    pub const DONT_REQUIRE_ANNOTATIONS: &'static str = "dont-require-annotations";
     pub const NO_PREFER_DYNAMIC: &'static str = "no-prefer-dynamic";
     pub const PRETTY_MODE: &'static str = "pretty-mode";
     pub const PRETTY_COMPARE_ONLY: &'static str = "pretty-compare-only";
@@ -297,6 +301,13 @@ impl TestProps {
             no_auto_check_cfg: false,
             has_enzyme: false,
             add_core_stubs: false,
+            require_annotations: HashMap::from([
+                (ErrorKind::Help, true),
+                (ErrorKind::Note, true),
+                (ErrorKind::Error, true),
+                (ErrorKind::Warning, true),
+                (ErrorKind::Suggestion, false),
+            ]),
         }
     }
 
@@ -570,6 +581,13 @@ impl TestProps {
                     config.set_name_directive(ln, NO_AUTO_CHECK_CFG, &mut self.no_auto_check_cfg);
 
                     self.update_add_core_stubs(ln, config);
+
+                    if let Some(err_kind) =
+                        config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
+                    {
+                        self.require_annotations
+                            .insert(ErrorKind::expect_from_user_str(&err_kind), false);
+                    }
                 },
             );
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 13f3479247a..872f5f6ce29 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -710,10 +710,6 @@ impl<'test> TestCx<'test> {
             self.testpaths.file.display().to_string()
         };
 
-        // 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.
-        // This logic also applies to "note" messages.
         let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help));
         let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note));
 
@@ -801,9 +797,7 @@ impl<'test> TestCx<'test> {
     }
 
     /// Returns `true` if we should report an error about `actual_error`,
-    /// which did not match any of the expected error. We always require
-    /// errors/warnings to be explicitly listed, but only require
-    /// helps/notes if there are explicit helps/notes given.
+    /// which did not match any of the expected error.
     fn is_unexpected_compiler_message(
         &self,
         actual_error: &Error,
@@ -811,12 +805,16 @@ impl<'test> TestCx<'test> {
         expect_note: bool,
     ) -> bool {
         actual_error.require_annotation
-            && match actual_error.kind {
-                Some(ErrorKind::Help) => expect_help,
-                Some(ErrorKind::Note) => expect_note,
-                Some(ErrorKind::Error) | Some(ErrorKind::Warning) => true,
-                Some(ErrorKind::Suggestion) | None => false,
-            }
+            && actual_error.kind.map_or(false, |err_kind| {
+                // If the test being checked doesn't contain any "help" or "note" annotations, then
+                // we don't require annotating "help" or "note" (respecively) diagnostics at all.
+                let default_require_annotations = self.props.require_annotations[&err_kind];
+                match err_kind {
+                    ErrorKind::Help => expect_help && default_require_annotations,
+                    ErrorKind::Note => expect_note && default_require_annotations,
+                    _ => default_require_annotations,
+                }
+            })
     }
 
     fn should_emit_metadata(&self, pm: Option<PassMode>) -> Emit {