Skip to content

Commit ee06320

Browse files
authored
Unrolled build for rust-lang#139485
Rollup merge of rust-lang#139485 - petrochenkov:errkind-light, r=oli-obk,jieyouxu compiletest: Stricter parsing for diagnostic kinds Non-controversial parts of rust-lang#139427 not requiring many changes in the test suite. r? ``@jieyouxu``
2 parents d4f880f + fd854a7 commit ee06320

30 files changed

+166
-151
lines changed

src/tools/compiletest/src/errors.rs

+39-33
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,39 @@ 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}`"),
3328
}
3429
}
30+
31+
/// Either the canonical uppercase string, or some additional versions for compatibility.
32+
/// FIXME: consider keeping only the canonical versions here.
33+
fn from_user_str(s: &str) -> Option<ErrorKind> {
34+
Some(match s {
35+
"HELP" | "help" => ErrorKind::Help,
36+
"ERROR" | "error" => ErrorKind::Error,
37+
"NOTE" | "note" => ErrorKind::Note,
38+
"SUGGESTION" => ErrorKind::Suggestion,
39+
"WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning,
40+
_ => return None,
41+
})
42+
}
3543
}
3644

3745
impl fmt::Display for ErrorKind {
3846
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3947
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"),
48+
ErrorKind::Help => write!(f, "HELP"),
49+
ErrorKind::Error => write!(f, "ERROR"),
50+
ErrorKind::Note => write!(f, "NOTE"),
51+
ErrorKind::Suggestion => write!(f, "SUGGESTION"),
52+
ErrorKind::Warning => write!(f, "WARN"),
4553
}
4654
}
4755
}
@@ -53,14 +61,18 @@ pub struct Error {
5361
/// `None` if not specified or unknown message kind.
5462
pub kind: Option<ErrorKind>,
5563
pub msg: String,
64+
/// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations
65+
/// are not mandatory, even if they would otherwise be mandatory for primary errors.
66+
/// Only makes sense for "actual" errors, not for "expected" errors.
67+
pub require_annotation: bool,
5668
}
5769

5870
impl Error {
5971
pub fn render_for_expected(&self) -> String {
6072
use colored::Colorize;
6173
format!(
6274
"{: <10}line {: >3}: {}",
63-
self.kind.map(|kind| kind.to_string()).unwrap_or_default().to_uppercase(),
75+
self.kind.map(|kind| kind.to_string()).unwrap_or_default(),
6476
self.line_num_str(),
6577
self.msg.cyan(),
6678
)
@@ -150,18 +162,12 @@ 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_str, _) = rest.split_once(|c: char| !c.is_ascii_alphabetic()).unwrap_or((rest, ""));
168+
let kind = ErrorKind::from_user_str(kind_str);
169+
let untrimmed_msg = if kind.is_some() { &rest[kind_str.len()..] } else { rest };
170+
let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned();
165171

166172
let line_num_adjust = &captures["adjust"];
167173
let (follow_prev, line_num) = if line_num_adjust == "|" {
@@ -177,12 +183,12 @@ fn parse_expected(
177183
debug!(
178184
"line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}",
179185
line_num,
180-
whole_match.as_str(),
186+
tag.as_str(),
181187
follow_prev,
182188
kind,
183189
msg
184190
);
185-
Some((follow_prev, Error { line_num, kind, msg }))
191+
Some((follow_prev, Error { line_num, kind, msg, require_annotation: true }))
186192
}
187193

188194
#[cfg(test)]

src/tools/compiletest/src/json.rs

+56-60
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;
@@ -142,43 +141,34 @@ pub fn extract_rendered(output: &str) -> String {
142141
}
143142

144143
pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
145-
output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect()
146-
}
147-
148-
fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
149-
// The compiler sometimes intermingles non-JSON stuff into the
150-
// output. This hack just skips over such lines. Yuck.
151-
if line.starts_with('{') {
152-
match serde_json::from_str::<Diagnostic>(line) {
153-
Ok(diagnostic) => {
154-
let mut expected_errors = vec![];
155-
push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name);
156-
expected_errors
157-
}
158-
Err(error) => {
159-
// Ignore the future compat report message - this is handled
160-
// by `extract_rendered`
161-
if serde_json::from_str::<FutureIncompatReport>(line).is_ok() {
162-
vec![]
163-
} else {
164-
proc_res.fatal(
144+
let mut errors = Vec::new();
145+
for line in output.lines() {
146+
// The compiler sometimes intermingles non-JSON stuff into the
147+
// output. This hack just skips over such lines. Yuck.
148+
if line.starts_with('{') {
149+
match serde_json::from_str::<Diagnostic>(line) {
150+
Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name),
151+
Err(error) => {
152+
// Ignore the future compat report message - this is handled
153+
// by `extract_rendered`
154+
if serde_json::from_str::<FutureIncompatReport>(line).is_err() {
155+
proc_res.fatal(
165156
Some(&format!(
166-
"failed to decode compiler output as json: \
167-
`{}`\nline: {}\noutput: {}",
157+
"failed to decode compiler output as json: `{}`\nline: {}\noutput: {}",
168158
error, line, output
169159
)),
170160
|| (),
171161
);
162+
}
172163
}
173164
}
174165
}
175-
} else {
176-
vec![]
177166
}
167+
errors
178168
}
179169

180-
fn push_expected_errors(
181-
expected_errors: &mut Vec<Error>,
170+
fn push_actual_errors(
171+
errors: &mut Vec<Error>,
182172
diagnostic: &Diagnostic,
183173
default_spans: &[&DiagnosticSpan],
184174
file_name: &str,
@@ -236,44 +226,47 @@ fn push_expected_errors(
236226
}
237227
};
238228

239-
// Convert multi-line messages into multiple expected
240-
// errors. We expect to replace these with something
241-
// more structured shortly anyhow.
229+
// Convert multi-line messages into multiple errors.
230+
// We expect to replace these with something more structured anyhow.
242231
let mut message_lines = diagnostic.message.lines();
243-
if let Some(first_line) = message_lines.next() {
244-
let ignore = |s| {
245-
static RE: OnceLock<Regex> = OnceLock::new();
246-
RE.get_or_init(|| {
247-
Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap()
248-
})
249-
.is_match(s)
250-
};
251-
252-
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 });
256-
} else {
257-
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 });
261-
}
232+
let kind = Some(ErrorKind::from_compiler_str(&diagnostic.level));
233+
let first_line = message_lines.next().unwrap_or(&diagnostic.message);
234+
if primary_spans.is_empty() {
235+
static RE: OnceLock<Regex> = OnceLock::new();
236+
let re_init =
237+
|| Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap();
238+
errors.push(Error {
239+
line_num: None,
240+
kind,
241+
msg: with_code(None, first_line),
242+
require_annotation: diagnostic.level != "failure-note"
243+
&& !RE.get_or_init(re_init).is_match(first_line),
244+
});
245+
} else {
246+
for span in primary_spans {
247+
errors.push(Error {
248+
line_num: Some(span.line_start),
249+
kind,
250+
msg: with_code(Some(span), first_line),
251+
require_annotation: true,
252+
});
262253
}
263254
}
264255
for next_line in message_lines {
265256
if primary_spans.is_empty() {
266-
expected_errors.push(Error {
257+
errors.push(Error {
267258
line_num: None,
268-
kind: None,
259+
kind,
269260
msg: with_code(None, next_line),
261+
require_annotation: false,
270262
});
271263
} else {
272264
for span in primary_spans {
273-
expected_errors.push(Error {
265+
errors.push(Error {
274266
line_num: Some(span.line_start),
275-
kind: None,
267+
kind,
276268
msg: with_code(Some(span), next_line),
269+
require_annotation: false,
277270
});
278271
}
279272
}
@@ -283,10 +276,11 @@ fn push_expected_errors(
283276
for span in primary_spans {
284277
if let Some(ref suggested_replacement) = span.suggested_replacement {
285278
for (index, line) in suggested_replacement.lines().enumerate() {
286-
expected_errors.push(Error {
279+
errors.push(Error {
287280
line_num: Some(span.line_start + index),
288281
kind: Some(ErrorKind::Suggestion),
289282
msg: line.to_string(),
283+
require_annotation: true,
290284
});
291285
}
292286
}
@@ -295,39 +289,41 @@ fn push_expected_errors(
295289
// Add notes for the backtrace
296290
for span in primary_spans {
297291
if let Some(frame) = &span.expansion {
298-
push_backtrace(expected_errors, frame, file_name);
292+
push_backtrace(errors, frame, file_name);
299293
}
300294
}
301295

302296
// Add notes for any labels that appear in the message.
303297
for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) {
304-
expected_errors.push(Error {
298+
errors.push(Error {
305299
line_num: Some(span.line_start),
306300
kind: Some(ErrorKind::Note),
307301
msg: span.label.clone().unwrap(),
302+
require_annotation: true,
308303
});
309304
}
310305

311306
// Flatten out the children.
312307
for child in &diagnostic.children {
313-
push_expected_errors(expected_errors, child, primary_spans, file_name);
308+
push_actual_errors(errors, child, primary_spans, file_name);
314309
}
315310
}
316311

317312
fn push_backtrace(
318-
expected_errors: &mut Vec<Error>,
313+
errors: &mut Vec<Error>,
319314
expansion: &DiagnosticSpanMacroExpansion,
320315
file_name: &str,
321316
) {
322317
if Path::new(&expansion.span.file_name) == Path::new(&file_name) {
323-
expected_errors.push(Error {
318+
errors.push(Error {
324319
line_num: Some(expansion.span.line_start),
325320
kind: Some(ErrorKind::Note),
326321
msg: format!("in this expansion of {}", expansion.macro_decl_name),
322+
require_annotation: true,
327323
});
328324
}
329325

330326
if let Some(previous_expansion) = &expansion.span.expansion {
331-
push_backtrace(expected_errors, previous_expansion, file_name);
327+
push_backtrace(errors, previous_expansion, file_name);
332328
}
333329
}

src/tools/compiletest/src/runtest.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,7 @@ impl<'test> TestCx<'test> {
810810
expect_help: bool,
811811
expect_note: bool,
812812
) -> bool {
813-
!actual_error.msg.is_empty()
813+
actual_error.require_annotation
814814
&& match actual_error.kind {
815815
Some(ErrorKind::Help) => expect_help,
816816
Some(ErrorKind::Note) => expect_note,

tests/incremental/circular-dependencies.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub struct Foo;
1515

1616
pub fn consume_foo(_: Foo) {}
1717
//[cfail2]~^ NOTE function defined here
18+
//[cfail2]~| NOTE
1819

1920
pub fn produce_foo() -> Foo {
2021
Foo

tests/ui/async-await/issue-70818.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use std::future::Future;
44
fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
5-
//~^ Error future cannot be sent between threads safely
5+
//~^ ERROR future cannot be sent between threads safely
66
async { (ty, ty1) }
77
}
88

tests/ui/async-await/issue-71137.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ async fn wrong_mutex() {
1919
}
2020

2121
fn main() {
22-
fake_spawn(wrong_mutex()); //~ Error future cannot be sent between threads safely
22+
fake_spawn(wrong_mutex()); //~ ERROR future cannot be sent between threads safely
2323
}

tests/ui/const-generics/defaults/mismatch.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ pub struct Example4<const N: usize = 13, const M: usize = 4>;
55

66
fn main() {
77
let e: Example<13> = ();
8-
//~^ Error: mismatched types
8+
//~^ ERROR mismatched types
99
//~| expected struct `Example`
1010
let e: Example2<u32, 13> = ();
11-
//~^ Error: mismatched types
11+
//~^ ERROR mismatched types
1212
//~| expected struct `Example2`
1313
let e: Example3<13, u32> = ();
14-
//~^ Error: mismatched types
14+
//~^ ERROR mismatched types
1515
//~| expected struct `Example3`
1616
let e: Example3<7> = ();
17-
//~^ Error: mismatched types
17+
//~^ ERROR mismatched types
1818
//~| expected struct `Example3<7>`
1919
let e: Example4<7> = ();
20-
//~^ Error: mismatched types
20+
//~^ ERROR mismatched types
2121
//~| expected struct `Example4<7>`
2222
}

tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ trait Foo {
1313
[Adt; std::mem::size_of::<Self::Assoc>()]: ,
1414
{
1515
<[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
16-
//~^ Error: the trait bound
16+
//~^ ERROR the trait bound
1717
}
1818

1919
fn bar() {}

0 commit comments

Comments
 (0)