diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2025-04-07 15:44:12 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2025-04-07 19:13:31 +0300 |
| commit | 5c160f511e321a89eef01fcf17c6cc4c0f4e5c00 (patch) | |
| tree | 016abaa173e463d7a708e6def26c9b41a18d0a32 /src | |
| parent | b86b3fb640e4f914db9013872e8ff67b74ba286d (diff) | |
| download | rust-5c160f511e321a89eef01fcf17c6cc4c0f4e5c00.tar.gz rust-5c160f511e321a89eef01fcf17c6cc4c0f4e5c00.zip | |
compiletest: Stricter parsing for diagnostic kinds
Diffstat (limited to 'src')
| -rw-r--r-- | src/tools/compiletest/src/errors.rs | 66 | ||||
| -rw-r--r-- | src/tools/compiletest/src/json.rs | 6 |
2 files changed, 37 insertions, 35 deletions
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index e1face32716..9b59e4968a3 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -3,7 +3,6 @@ use std::fs::File; use std::io::BufReader; use std::io::prelude::*; use std::path::Path; -use std::str::FromStr; use std::sync::OnceLock; use regex::Regex; @@ -18,30 +17,39 @@ pub enum ErrorKind { Warning, } -impl FromStr for ErrorKind { - type Err = (); - fn from_str(s: &str) -> Result<Self, Self::Err> { - let s = s.to_uppercase(); - let part0: &str = s.split(':').next().unwrap(); - match part0 { - "HELP" => Ok(ErrorKind::Help), - "ERROR" => Ok(ErrorKind::Error), - "NOTE" => Ok(ErrorKind::Note), - "SUGGESTION" => Ok(ErrorKind::Suggestion), - "WARN" | "WARNING" => Ok(ErrorKind::Warning), - _ => Err(()), +impl ErrorKind { + pub fn from_compiler_str(s: &str) -> ErrorKind { + match s { + "help" => ErrorKind::Help, + "error" | "error: internal compiler error" => ErrorKind::Error, + "note" | "failure-note" => ErrorKind::Note, + "warning" => ErrorKind::Warning, + _ => panic!("unexpected compiler diagnostic kind `{s}`"), } } + + /// Either the canonical uppercase string, or some additional versions for compatibility. + /// FIXME: consider keeping only the canonical versions here. + fn from_user_str(s: &str) -> Option<ErrorKind> { + Some(match s { + "HELP" | "help" => ErrorKind::Help, + "ERROR" | "error" => ErrorKind::Error, + "NOTE" | "note" => ErrorKind::Note, + "SUGGESTION" => ErrorKind::Suggestion, + "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning, + _ => return None, + }) + } } impl fmt::Display for ErrorKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ErrorKind::Help => write!(f, "help message"), - ErrorKind::Error => write!(f, "error"), - ErrorKind::Note => write!(f, "note"), - ErrorKind::Suggestion => write!(f, "suggestion"), - ErrorKind::Warning => write!(f, "warning"), + ErrorKind::Help => write!(f, "HELP"), + ErrorKind::Error => write!(f, "ERROR"), + ErrorKind::Note => write!(f, "NOTE"), + ErrorKind::Suggestion => write!(f, "SUGGESTION"), + ErrorKind::Warning => write!(f, "WARN"), } } } @@ -64,7 +72,7 @@ impl Error { use colored::Colorize; format!( "{: <10}line {: >3}: {}", - self.kind.map(|kind| kind.to_string()).unwrap_or_default().to_uppercase(), + self.kind.map(|kind| kind.to_string()).unwrap_or_default(), self.line_num_str(), self.msg.cyan(), ) @@ -154,18 +162,12 @@ fn parse_expected( } // Get the part of the comment after the sigil (e.g. `~^^` or ~|). - let whole_match = captures.get(0).unwrap(); - let (_, mut msg) = line.split_at(whole_match.end()); - - let first_word = msg.split_whitespace().next().expect("Encountered unexpected empty comment"); - - // If we find `//~ ERROR foo` or something like that, skip the first word. - let kind = first_word.parse::<ErrorKind>().ok(); - if kind.is_some() { - msg = &msg.trim_start().split_at(first_word.len()).1; - } - - let msg = msg.trim().to_owned(); + let tag = captures.get(0).unwrap(); + let rest = line[tag.end()..].trim_start(); + let (kind_str, _) = rest.split_once(|c: char| !c.is_ascii_alphabetic()).unwrap_or((rest, "")); + let kind = ErrorKind::from_user_str(kind_str); + let untrimmed_msg = if kind.is_some() { &rest[kind_str.len()..] } else { rest }; + let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned(); let line_num_adjust = &captures["adjust"]; let (follow_prev, line_num) = if line_num_adjust == "|" { @@ -181,7 +183,7 @@ fn parse_expected( debug!( "line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}", line_num, - whole_match.as_str(), + tag.as_str(), follow_prev, kind, msg diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 2a6fcd6cf81..62fe538ee32 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -1,7 +1,6 @@ //! These structs are a subset of the ones found in `rustc_errors::json`. use std::path::{Path, PathBuf}; -use std::str::FromStr; use std::sync::OnceLock; use regex::Regex; @@ -230,7 +229,7 @@ fn push_actual_errors( // Convert multi-line messages into multiple errors. // We expect to replace these with something more structured anyhow. let mut message_lines = diagnostic.message.lines(); - let kind = ErrorKind::from_str(&diagnostic.level).ok(); + let kind = Some(ErrorKind::from_compiler_str(&diagnostic.level)); let first_line = message_lines.next().unwrap_or(&diagnostic.message); if primary_spans.is_empty() { static RE: OnceLock<Regex> = OnceLock::new(); @@ -240,7 +239,8 @@ fn push_actual_errors( line_num: None, kind, msg: with_code(None, first_line), - require_annotation: !RE.get_or_init(re_init).is_match(first_line), + require_annotation: diagnostic.level != "failure-note" + && !RE.get_or_init(re_init).is_match(first_line), }); } else { for span in primary_spans { |
