Skip to content

Commit 23a4bcc

Browse files
committed
compiletest: Make diagnostic kind mandatory on line annotations
1 parent 5e17a2a commit 23a4bcc

File tree

927 files changed

+3426
-3402
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

927 files changed

+3426
-3402
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ dependencies = [
694694
"serde_json",
695695
"tracing",
696696
"tracing-subscriber",
697+
"unicode-xid",
697698
"unified-diff",
698699
"walkdir",
699700
"windows 0.59.0",

src/tools/compiletest/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ walkdir = "2"
2626
glob = "0.3.0"
2727
anyhow = "1"
2828
home = "0.5.5"
29+
unicode-xid = "0.2"
2930

3031
[target.'cfg(unix)'.dependencies]
3132
libc = "0.2"

src/tools/compiletest/src/errors.rs

+47-40
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::fs::File;
33
use std::io::BufReader;
44
use std::io::prelude::*;
55
use std::path::Path;
6-
use std::str::FromStr;
76
use std::sync::OnceLock;
87

98
use regex::Regex;
@@ -18,30 +17,42 @@ pub enum ErrorKind {
1817
Warning,
1918
}
2019

21-
impl FromStr for ErrorKind {
22-
type Err = ();
23-
fn from_str(s: &str) -> Result<Self, Self::Err> {
24-
let s = s.to_uppercase();
25-
let part0: &str = s.split(':').next().unwrap();
26-
match part0 {
27-
"HELP" => Ok(ErrorKind::Help),
28-
"ERROR" => Ok(ErrorKind::Error),
29-
"NOTE" => Ok(ErrorKind::Note),
30-
"SUGGESTION" => Ok(ErrorKind::Suggestion),
31-
"WARN" | "WARNING" => Ok(ErrorKind::Warning),
32-
_ => Err(()),
20+
impl ErrorKind {
21+
pub fn from_compiler_str(s: &str) -> ErrorKind {
22+
match s {
23+
"help" => ErrorKind::Help,
24+
"error" | "error: internal compiler error" => ErrorKind::Error,
25+
"note" | "failure-note" => ErrorKind::Note,
26+
"warning" => ErrorKind::Warning,
27+
_ => panic!("unexpected compiler diagnostic kind `{s}`"),
28+
}
29+
}
30+
31+
fn from_user_str(s: &str) -> ErrorKind {
32+
match s {
33+
"HELP" => ErrorKind::Help,
34+
"HELP_NONVIRAL" => ErrorKind::Help,
35+
"ERROR" => ErrorKind::Error,
36+
"NOTE" => ErrorKind::Note,
37+
"NOTE_NONVIRAL" => ErrorKind::Note,
38+
"SUGGESTION" => ErrorKind::Suggestion,
39+
"WARN" | "WARNING" => ErrorKind::Warning,
40+
_ => panic!(
41+
"unexpected diagnostic kind `{s}`, expected \
42+
`ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
43+
),
3344
}
3445
}
3546
}
3647

3748
impl fmt::Display for ErrorKind {
3849
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3950
match *self {
40-
ErrorKind::Help => write!(f, "help message"),
41-
ErrorKind::Error => write!(f, "error"),
42-
ErrorKind::Note => write!(f, "note"),
43-
ErrorKind::Suggestion => write!(f, "suggestion"),
44-
ErrorKind::Warning => write!(f, "warning"),
51+
ErrorKind::Help => write!(f, "HELP"),
52+
ErrorKind::Error => write!(f, "ERROR"),
53+
ErrorKind::Note => write!(f, "NOTE"),
54+
ErrorKind::Suggestion => write!(f, "SUGGESTION"),
55+
ErrorKind::Warning => write!(f, "WARN"),
4556
}
4657
}
4758
}
@@ -50,20 +61,21 @@ impl fmt::Display for ErrorKind {
5061
pub struct Error {
5162
pub line_num: Option<usize>,
5263
/// What kind of message we expect (e.g., warning, error, suggestion).
53-
/// `None` if not specified or unknown message kind.
54-
pub kind: Option<ErrorKind>,
64+
pub kind: ErrorKind,
5565
pub msg: String,
66+
/// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations
67+
/// are not mandatory, even if they would otherwise be mandatory for primary errors.
68+
/// Only makes sense for "found" errors, not for "expected" errors.
69+
pub should_annotate: bool,
70+
/// A temporary measure to avoid adding too many `NOTE` and `HELP` annotations in #NNNNNN.
71+
/// Only makes sense for "expected" errors, not for "found" errors.
72+
pub viral: bool,
5673
}
5774

5875
impl Error {
5976
pub fn render_for_expected(&self) -> String {
6077
use colored::Colorize;
61-
format!(
62-
"{: <10}line {: >3}: {}",
63-
self.kind.map(|kind| kind.to_string()).unwrap_or_default().to_uppercase(),
64-
self.line_num_str(),
65-
self.msg.cyan(),
66-
)
78+
format!("{: <10}line {: >3}: {}", self.kind, self.line_num_str(), self.msg.cyan())
6779
}
6880

6981
pub fn line_num_str(&self) -> String {
@@ -150,18 +162,13 @@ fn parse_expected(
150162
}
151163

152164
// Get the part of the comment after the sigil (e.g. `~^^` or ~|).
153-
let whole_match = captures.get(0).unwrap();
154-
let (_, mut msg) = line.split_at(whole_match.end());
155-
156-
let first_word = msg.split_whitespace().next().expect("Encountered unexpected empty comment");
157-
158-
// If we find `//~ ERROR foo` or something like that, skip the first word.
159-
let kind = first_word.parse::<ErrorKind>().ok();
160-
if kind.is_some() {
161-
msg = &msg.trim_start().split_at(first_word.len()).1;
162-
}
163-
164-
let msg = msg.trim().to_owned();
165+
let tag = captures.get(0).unwrap();
166+
let rest = line[tag.end()..].trim_start();
167+
let (kind, _) =
168+
rest.split_once(|c| !unicode_xid::UnicodeXID::is_xid_continue(c)).unwrap_or((rest, ""));
169+
let msg = rest[kind.len()..].trim().to_owned();
170+
let viral = kind != "NOTE_NONVIRAL" && kind != "HELP_NONVIRAL";
171+
let kind = ErrorKind::from_user_str(kind);
165172

166173
let line_num_adjust = &captures["adjust"];
167174
let (follow_prev, line_num) = if line_num_adjust == "|" {
@@ -177,12 +184,12 @@ fn parse_expected(
177184
debug!(
178185
"line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}",
179186
line_num,
180-
whole_match.as_str(),
187+
tag.as_str(),
181188
follow_prev,
182189
kind,
183190
msg
184191
);
185-
Some((follow_prev, Error { line_num, kind, msg }))
192+
Some((follow_prev, Error { line_num, kind, msg, should_annotate: true, viral }))
186193
}
187194

188195
#[cfg(test)]

src/tools/compiletest/src/json.rs

+30-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! These structs are a subset of the ones found in `rustc_errors::json`.
22
33
use std::path::{Path, PathBuf};
4-
use std::str::FromStr;
54
use std::sync::OnceLock;
65

76
use regex::Regex;
@@ -239,6 +238,7 @@ fn push_expected_errors(
239238
// Convert multi-line messages into multiple expected
240239
// errors. We expect to replace these with something
241240
// more structured shortly anyhow.
241+
let kind = ErrorKind::from_compiler_str(&diagnostic.level);
242242
let mut message_lines = diagnostic.message.lines();
243243
if let Some(first_line) = message_lines.next() {
244244
let ignore = |s| {
@@ -250,30 +250,42 @@ fn push_expected_errors(
250250
};
251251

252252
if primary_spans.is_empty() && !ignore(first_line) {
253-
let msg = with_code(None, first_line);
254-
let kind = ErrorKind::from_str(&diagnostic.level).ok();
255-
expected_errors.push(Error { line_num: None, kind, msg });
253+
expected_errors.push(Error {
254+
line_num: None,
255+
kind,
256+
msg: with_code(None, first_line),
257+
should_annotate: diagnostic.level != "failure-note",
258+
viral: true,
259+
});
256260
} else {
257261
for span in primary_spans {
258-
let msg = with_code(Some(span), first_line);
259-
let kind = ErrorKind::from_str(&diagnostic.level).ok();
260-
expected_errors.push(Error { line_num: Some(span.line_start), kind, msg });
262+
expected_errors.push(Error {
263+
line_num: Some(span.line_start),
264+
kind,
265+
msg: with_code(Some(span), first_line),
266+
should_annotate: diagnostic.level != "failure-note",
267+
viral: true,
268+
});
261269
}
262270
}
263271
}
264272
for next_line in message_lines {
265273
if primary_spans.is_empty() {
266274
expected_errors.push(Error {
267275
line_num: None,
268-
kind: None,
276+
kind,
269277
msg: with_code(None, next_line),
278+
should_annotate: false,
279+
viral: true,
270280
});
271281
} else {
272282
for span in primary_spans {
273283
expected_errors.push(Error {
274284
line_num: Some(span.line_start),
275-
kind: None,
285+
kind,
276286
msg: with_code(Some(span), next_line),
287+
should_annotate: false,
288+
viral: true,
277289
});
278290
}
279291
}
@@ -285,8 +297,10 @@ fn push_expected_errors(
285297
for (index, line) in suggested_replacement.lines().enumerate() {
286298
expected_errors.push(Error {
287299
line_num: Some(span.line_start + index),
288-
kind: Some(ErrorKind::Suggestion),
300+
kind: ErrorKind::Suggestion,
289301
msg: line.to_string(),
302+
should_annotate: true,
303+
viral: true,
290304
});
291305
}
292306
}
@@ -303,8 +317,10 @@ fn push_expected_errors(
303317
for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
304318
expected_errors.push(Error {
305319
line_num: Some(span.line_start),
306-
kind: Some(ErrorKind::Note),
320+
kind: ErrorKind::Note,
307321
msg: span.label.clone().unwrap(),
322+
should_annotate: true,
323+
viral: true,
308324
});
309325
}
310326

@@ -322,8 +338,10 @@ fn push_backtrace(
322338
if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
323339
expected_errors.push(Error {
324340
line_num: Some(expansion.span.line_start),
325-
kind: Some(ErrorKind::Note),
341+
kind: ErrorKind::Note,
326342
msg: format!("in this expansion of {}", expansion.macro_decl_name),
343+
should_annotate: true,
344+
viral: true,
327345
});
328346
}
329347

src/tools/compiletest/src/runtest.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -680,9 +680,7 @@ impl<'test> TestCx<'test> {
680680
"check_expected_errors: expected_errors={:?} proc_res.status={:?}",
681681
expected_errors, proc_res.status
682682
);
683-
if proc_res.status.success()
684-
&& expected_errors.iter().any(|x| x.kind == Some(ErrorKind::Error))
685-
{
683+
if proc_res.status.success() && expected_errors.iter().any(|x| x.kind == ErrorKind::Error) {
686684
self.fatal_proc_rec("process did not return an error status", proc_res);
687685
}
688686

@@ -714,8 +712,8 @@ impl<'test> TestCx<'test> {
714712
// message, then we'll ensure that all "help" messages are expected.
715713
// Otherwise, all "help" messages reported by the compiler will be ignored.
716714
// This logic also applies to "note" messages.
717-
let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help));
718-
let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note));
715+
let expect_help = expected_errors.iter().any(|ee| ee.kind == ErrorKind::Help && ee.viral);
716+
let expect_note = expected_errors.iter().any(|ee| ee.kind == ErrorKind::Note && ee.viral);
719717

720718
// Parse the JSON output from the compiler and extract out the messages.
721719
let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res);
@@ -728,8 +726,7 @@ impl<'test> TestCx<'test> {
728726
expected_errors.iter().enumerate().position(|(index, expected_error)| {
729727
!found[index]
730728
&& actual_error.line_num == expected_error.line_num
731-
&& (expected_error.kind.is_none()
732-
|| actual_error.kind == expected_error.kind)
729+
&& actual_error.kind == expected_error.kind
733730
&& actual_error.msg.contains(&expected_error.msg)
734731
});
735732

@@ -748,10 +745,7 @@ impl<'test> TestCx<'test> {
748745
"{}:{}: unexpected {}: '{}'",
749746
file_name,
750747
actual_error.line_num_str(),
751-
actual_error
752-
.kind
753-
.as_ref()
754-
.map_or(String::from("message"), |k| k.to_string()),
748+
actual_error.kind,
755749
actual_error.msg
756750
));
757751
unexpected.push(actual_error);
@@ -768,7 +762,7 @@ impl<'test> TestCx<'test> {
768762
"{}:{}: expected {} not found: {}",
769763
file_name,
770764
expected_error.line_num_str(),
771-
expected_error.kind.as_ref().map_or("message".into(), |k| k.to_string()),
765+
expected_error.kind,
772766
expected_error.msg
773767
));
774768
not_found.push(expected_error);
@@ -811,11 +805,12 @@ impl<'test> TestCx<'test> {
811805
expect_note: bool,
812806
) -> bool {
813807
!actual_error.msg.is_empty()
808+
&& actual_error.should_annotate
814809
&& match actual_error.kind {
815-
Some(ErrorKind::Help) => expect_help,
816-
Some(ErrorKind::Note) => expect_note,
817-
Some(ErrorKind::Error) | Some(ErrorKind::Warning) => true,
818-
Some(ErrorKind::Suggestion) | None => false,
810+
ErrorKind::Help => expect_help,
811+
ErrorKind::Note => expect_note,
812+
ErrorKind::Error | ErrorKind::Warning => true,
813+
ErrorKind::Suggestion => false,
819814
}
820815
}
821816

src/tools/compiletest/src/runtest/ui.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use rustfix::{Filter, apply_suggestions, get_suggestions_from_json};
66
use tracing::debug;
77

88
use super::{
9-
AllowUnused, Emit, ErrorKind, FailMode, LinkToAux, PassMode, TargetLocation, TestCx,
10-
TestOutput, Truncated, UI_FIXED, WillExecute,
9+
AllowUnused, Emit, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, TestOutput,
10+
Truncated, UI_FIXED, WillExecute,
1111
};
1212
use crate::{errors, json};
1313

@@ -176,7 +176,7 @@ impl TestCx<'_> {
176176
let msg = format!(
177177
"line {}: cannot combine `--error-format` with {} annotations; use `error-pattern` instead",
178178
expected_errors[0].line_num_str(),
179-
expected_errors[0].kind.unwrap_or(ErrorKind::Error),
179+
expected_errors[0].kind,
180180
);
181181
self.fatal(&msg);
182182
}

tests/incremental/const-generics/hash-tyvid-regression-1.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ where
2020
{
2121
use std::convert::TryFrom;
2222
<[T; N.get()]>::try_from(())
23-
//~^ error: the trait bound
24-
//~| error: the trait bound
25-
//~| error: mismatched types
23+
//~^ ERROR the trait bound
24+
//~| ERROR the trait bound
25+
//~| ERROR mismatched types
2626
}
2727

2828
fn main() {}

tests/incremental/const-generics/hash-tyvid-regression-2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ where
2323
{
2424
fn eq(&self, other: &&'a [A]) -> bool {
2525
self.0 == other
26-
//~^ error: can't compare
26+
//~^ ERROR can't compare
2727
}
2828
}
2929

tests/incremental/const-generics/hash-tyvid-regression-3.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ where
1616
fn new() -> Self {
1717
let mut node = Node::new();
1818
node.keys.some_function();
19-
//~^ error: no method named
19+
//~^ ERROR no method named
2020
node
2121
}
2222
}

tests/incremental/const-generics/hash-tyvid-regression-4.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ where
2222
fn split(&mut self, i: usize, k: K, right: bool) -> Node<K, D> {
2323
let mut node = Node::new();
2424
node.keys.push(k);
25-
//~^ error: no method named
25+
//~^ ERROR no method named
2626
node
2727
}
2828
}

tests/incremental/const-generics/try_unify_abstract_const_regression_tests/issue-77708-1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ where
1111
C: Delegates<FileCap<{ false }>>,
1212
{
1313
writes_to_specific_path(&cap);
14-
//~^ error: the trait bound
14+
//~^ ERROR the trait bound
1515
}
1616

1717
fn writes_to_specific_path<C>(cap: &C)

0 commit comments

Comments
 (0)