Skip to content

Commit 6990d46

Browse files
committed
compiletest: Support matching on non-json lines in compiler output
and migrate most of remaining `error-pattern`s to it.
1 parent 2ad5f86 commit 6990d46

File tree

61 files changed

+211
-218
lines changed

Some content is hidden

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

61 files changed

+211
-218
lines changed

src/doc/rustc-dev-guide/src/tests/ui.md

+3
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,12 @@ The diagnostic kinds that you can have are:
356356
- `NOTE`
357357
- `HELP`
358358
- `SUGGESTION`
359+
- `RAW`
359360

360361
The `SUGGESTION` kind is used for specifying what the expected replacement text
361362
should be for a diagnostic suggestion.
363+
The `RAW` kind can be used for matching on lines from non-structured output sometimes emitted
364+
by the compiler instead of or in addition to structured json.
362365

363366
`ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations
364367
`//~` by default.

src/tools/compiletest/src/errors.rs

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub enum ErrorKind {
1515
Note,
1616
Suggestion,
1717
Warning,
18+
Raw,
1819
}
1920

2021
impl ErrorKind {
@@ -39,6 +40,7 @@ impl ErrorKind {
3940
"NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note,
4041
"SUGGESTION" => ErrorKind::Suggestion,
4142
"WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning,
43+
"RAW" => ErrorKind::Raw,
4244
_ => panic!(
4345
"unexpected diagnostic kind `{s}`, expected \
4446
`ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`"
@@ -55,6 +57,7 @@ impl fmt::Display for ErrorKind {
5557
ErrorKind::Note => write!(f, "NOTE"),
5658
ErrorKind::Suggestion => write!(f, "SUGGESTION"),
5759
ErrorKind::Warning => write!(f, "WARN"),
60+
ErrorKind::Raw => write!(f, "RAW"),
5861
}
5962
}
6063
}

src/tools/compiletest/src/json.rs

+9-21
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use regex::Regex;
77
use serde::Deserialize;
88

99
use crate::errors::{Error, ErrorKind};
10-
use crate::runtest::ProcRes;
1110

1211
#[derive(Deserialize)]
1312
struct Diagnostic {
@@ -140,28 +139,17 @@ pub fn extract_rendered(output: &str) -> String {
140139
.collect()
141140
}
142141

143-
pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
142+
pub fn parse_output(file_name: &str, output: &str) -> Vec<Error> {
144143
let mut errors = Vec::new();
145144
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(
156-
Some(&format!(
157-
"failed to decode compiler output as json: `{}`\nline: {}\noutput: {}",
158-
error, line, output
159-
)),
160-
|| (),
161-
);
162-
}
163-
}
164-
}
145+
match serde_json::from_str::<Diagnostic>(line) {
146+
Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name),
147+
Err(_) => errors.push(Error {
148+
line_num: None,
149+
kind: ErrorKind::Raw,
150+
msg: line.to_string(),
151+
require_annotation: false,
152+
}),
165153
}
166154
}
167155
errors

src/tools/compiletest/src/runtest.rs

+22-21
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::common::{
2323
output_base_dir, output_base_name, output_testname_unique,
2424
};
2525
use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
26-
use crate::errors::{Error, ErrorKind};
26+
use crate::errors::{Error, ErrorKind, load_errors};
2727
use crate::header::TestProps;
2828
use crate::read2::{Truncated, read2_abbreviated};
2929
use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex};
@@ -577,23 +577,9 @@ impl<'test> TestCx<'test> {
577577
}
578578
}
579579

580-
fn check_all_error_patterns(
581-
&self,
582-
output_to_check: &str,
583-
proc_res: &ProcRes,
584-
pm: Option<PassMode>,
585-
) {
586-
if self.props.error_patterns.is_empty() && self.props.regex_error_patterns.is_empty() {
587-
if pm.is_some() {
588-
// FIXME(#65865)
589-
return;
590-
} else {
591-
self.fatal(&format!("no error pattern specified in {}", self.testpaths.file));
592-
}
593-
}
594-
580+
/// Check `error-pattern` and `regex-error-pattern` directives.
581+
fn check_all_error_patterns(&self, output_to_check: &str, proc_res: &ProcRes) {
595582
let mut missing_patterns: Vec<String> = Vec::new();
596-
597583
self.check_error_patterns(output_to_check, &mut missing_patterns);
598584
self.check_regex_error_patterns(output_to_check, proc_res, &mut missing_patterns);
599585

@@ -670,7 +656,9 @@ impl<'test> TestCx<'test> {
670656
}
671657
}
672658

673-
fn check_expected_errors(&self, expected_errors: Vec<Error>, proc_res: &ProcRes) {
659+
/// Check `//~ KIND message` annotations.
660+
fn check_expected_errors(&self, proc_res: &ProcRes) {
661+
let expected_errors = load_errors(&self.testpaths.file, self.revision);
674662
debug!(
675663
"check_expected_errors: expected_errors={:?} proc_res.status={:?}",
676664
expected_errors, proc_res.status
@@ -711,11 +699,24 @@ impl<'test> TestCx<'test> {
711699
.collect();
712700

713701
// Parse the JSON output from the compiler and extract out the messages.
714-
let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res);
702+
let actual_errors = json::parse_output(&diagnostic_file_name, &self.get_output(proc_res))
703+
.into_iter()
704+
.map(|e| Error { msg: self.normalize_output(&e.msg, &[]), ..e });
705+
715706
let mut unexpected = Vec::new();
716707
let mut found = vec![false; expected_errors.len()];
717-
for mut actual_error in actual_errors {
718-
actual_error.msg = self.normalize_output(&actual_error.msg, &[]);
708+
for actual_error in actual_errors {
709+
for pattern in &self.props.error_patterns {
710+
let pattern = pattern.trim();
711+
if actual_error.msg.contains(pattern) {
712+
let q = if actual_error.line_num.is_none() { "?" } else { "" };
713+
self.fatal(&format!(
714+
"error pattern '{pattern}' is found in structured \
715+
diagnostics, use `//~{q} {} {pattern}` instead",
716+
actual_error.kind,
717+
));
718+
}
719+
}
719720

720721
let opt_index =
721722
expected_errors.iter().enumerate().position(|(index, expected_error)| {

src/tools/compiletest/src/runtest/incremental.rs

+3-11
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,8 @@ impl TestCx<'_> {
100100
self.check_no_compiler_crash(&proc_res, self.props.should_ice);
101101

102102
let output_to_check = self.get_output(&proc_res);
103-
let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
104-
if !expected_errors.is_empty() {
105-
if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty()
106-
{
107-
self.fatal("both error pattern and expected errors specified");
108-
}
109-
self.check_expected_errors(expected_errors, &proc_res);
110-
} else {
111-
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
112-
}
103+
self.check_expected_errors(&proc_res);
104+
self.check_all_error_patterns(&output_to_check, &proc_res);
113105
if self.props.should_ice {
114106
match proc_res.status.code() {
115107
Some(101) => (),
@@ -137,6 +129,6 @@ impl TestCx<'_> {
137129

138130
let output_to_check = self.get_output(&proc_res);
139131
self.check_correct_failure_status(&proc_res);
140-
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
132+
self.check_all_error_patterns(&output_to_check, &proc_res);
141133
}
142134
}

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

+10-37
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use super::{
99
AllowUnused, Emit, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, TestOutput,
1010
Truncated, UI_FIXED, WillExecute,
1111
};
12-
use crate::{errors, json};
12+
use crate::json;
1313

1414
impl TestCx<'_> {
1515
pub(super) fn run_ui_test(&self) {
@@ -127,9 +127,7 @@ impl TestCx<'_> {
127127
);
128128
}
129129

130-
let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
131-
132-
if let WillExecute::Yes = should_run {
130+
let output_to_check = if let WillExecute::Yes = should_run {
133131
let proc_res = self.exec_compiled_test();
134132
let run_output_errors = if self.props.check_run_results {
135133
self.load_compare_outputs(&proc_res, TestOutput::Run, explicit)
@@ -150,44 +148,19 @@ impl TestCx<'_> {
150148
self.fatal_proc_rec("test run succeeded!", &proc_res);
151149
}
152150

153-
let output_to_check = self.get_output(&proc_res);
154-
if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty()
155-
{
156-
// "// error-pattern" comments
157-
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
158-
}
159-
self.check_forbid_output(&output_to_check, &proc_res)
160-
}
151+
self.get_output(&proc_res)
152+
} else {
153+
self.get_output(&proc_res)
154+
};
161155

162156
debug!(
163-
"run_ui_test: explicit={:?} config.compare_mode={:?} expected_errors={:?} \
157+
"run_ui_test: explicit={:?} config.compare_mode={:?} \
164158
proc_res.status={:?} props.error_patterns={:?}",
165-
explicit,
166-
self.config.compare_mode,
167-
expected_errors,
168-
proc_res.status,
169-
self.props.error_patterns
159+
explicit, self.config.compare_mode, proc_res.status, self.props.error_patterns
170160
);
171161

172-
if !explicit && self.config.compare_mode.is_none() {
173-
// "//~ERROR comments"
174-
self.check_expected_errors(expected_errors, &proc_res);
175-
} else if explicit && !expected_errors.is_empty() {
176-
let msg = format!(
177-
"line {}: cannot combine `--error-format` with {} annotations; use `error-pattern` instead",
178-
expected_errors[0].line_num_str(),
179-
expected_errors[0].kind,
180-
);
181-
self.fatal(&msg);
182-
}
183-
let output_to_check = self.get_output(&proc_res);
184-
if should_run == WillExecute::No
185-
&& (!self.props.error_patterns.is_empty()
186-
|| !self.props.regex_error_patterns.is_empty())
187-
{
188-
// "// error-pattern" comments
189-
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
190-
}
162+
self.check_expected_errors(&proc_res);
163+
self.check_all_error_patterns(&output_to_check, &proc_res);
191164
self.check_forbid_output(&output_to_check, &proc_res);
192165

193166
if self.props.run_rustfix && self.config.compare_mode.is_none() {

tests/incremental/ich_nested_items.rs

+4
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@
1212
pub fn foo() {
1313
#[cfg(cfail1)]
1414
pub fn baz() {} // order is different...
15+
//[cfail1]~^ WARN function `baz` is never used
1516

1617
#[rustc_clean(cfg = "cfail2")]
1718
pub fn bar() {} // but that doesn't matter.
19+
//~^ WARN function `bar` is never used
1820

1921
#[cfg(cfail2)]
2022
pub fn baz() {} // order is different...
23+
//[cfail2]~^ WARN function `baz` is never used
2124

2225
pub fn bap() {} // neither does adding a new item
26+
//~^ WARN function `bap` is never used
2327
}

tests/incremental/incremental_proc_macro.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ extern crate incremental_proc_macro_aux;
1212

1313
#[derive(IncrementalMacro)]
1414
pub struct Foo {
15-
x: u32
15+
x: u32 //~ WARN field `x` is never read
1616
}

tests/incremental/issue-49595/issue-49595.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
mod tests {
1212
#[cfg_attr(not(cfail1), test)]
13-
fn test() {
13+
fn test() { //[cfail1]~ WARN function `test` is never used
1414
}
1515
}
1616

tests/incremental/issue-85360-eval-obligation-ice.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,16 @@ impl<T: 'static> Component for GenericComp<T> {
4242
type Storage = VecStorage;
4343
}
4444
struct ReadData {
45-
pos_interpdata: ReadStorage<GenericComp<Pos>>,
45+
pos_interpdata: ReadStorage<GenericComp<Pos>>, //~ WARN field `pos_interpdata` is never read
4646
}
4747

48-
trait System {
48+
trait System { //~ WARN trait `System` is never used
4949
type SystemData;
5050

5151
fn run(data: Self::SystemData, any: Box<dyn Any>);
5252
}
5353

54-
struct Sys;
54+
struct Sys; //~ WARN struct `Sys` is never constructed
5555

5656
impl System for Sys {
5757
type SystemData = (ReadData, ReadStorage<Pos>);
@@ -63,7 +63,7 @@ impl System for Sys {
6363
}
6464
}
6565

66-
trait ParJoin {
66+
trait ParJoin { //~ WARN trait `ParJoin` is never used
6767
fn par_join(self)
6868
where
6969
Self: Sized,

tests/incremental/thinlto/cgu_keeps_identical_fn.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@
3333
mod foo {
3434

3535
// Trivial functions like this one are imported very reliably by ThinLTO.
36-
#[cfg(any(cfail1, cfail4))]
36+
#[cfg(any(cfail1, cfail4))] //~ WARN unexpected `cfg` condition name: `cfail4`
3737
pub fn inlined_fn() -> u32 {
3838
1234
3939
}
4040

41-
#[cfg(not(any(cfail1, cfail4)))]
41+
#[cfg(not(any(cfail1, cfail4)))] //~ WARN unexpected `cfg` condition name: `cfail4`
4242
pub fn inlined_fn() -> u32 {
4343
1234
4444
}

tests/incremental/unrecoverable_query.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ impl P for S {
2020

2121
struct T<D: P>(D::A, Z<D>);
2222

23-
struct Z<D: P>(D::A, String);
23+
struct Z<D: P>(D::A, String); //~ WARN field `1` is never read
24+
//[cfail2]~| WARN field `1` is never read
2425

2526
impl<D: P> T<D> {
2627
pub fn i() -> Self {
@@ -30,9 +31,9 @@ impl<D: P> T<D> {
3031

3132
enum C {
3233
#[cfg(cfail1)]
33-
Up(()),
34+
Up(()), //[cfail1]~ WARN variant `Up` is never constructed
3435
#[cfg(cfail2)]
35-
Lorry(()),
36+
Lorry(()), //[cfail2]~ WARN variant `Lorry` is never constructed
3637
}
3738

3839
pub fn m() {

tests/rustdoc-ui/ice-bug-report-url.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
//@ compile-flags: -Ztreat-err-as-bug
22
//@ rustc-env:RUSTC_ICE=0
33
//@ failure-status: 101
4-
//@ error-pattern: aborting due to
5-
//@ error-pattern: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md
64

75
//@ normalize-stderr: "note: compiler flags.*\n\n" -> ""
86
//@ normalize-stderr: "note: rustc.*running on.*" -> "note: rustc {version} running on {platform}"
@@ -13,3 +11,6 @@
1311

1412
fn wrong()
1513
//~^ ERROR expected one of
14+
15+
//~? RAW aborting due to
16+
//~? RAW we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md

tests/rustdoc-ui/ice-bug-report-url.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: internal compiler error: expected one of `->`, `where`, or `{`, found `<eof>`
2-
--> $DIR/ice-bug-report-url.rs:14:10
2+
--> $DIR/ice-bug-report-url.rs:12:10
33
|
44
LL | fn wrong()
55
| ^ expected one of `->`, `where`, or `{`

tests/rustdoc-ui/issues/issue-81662-shortness.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//@ compile-flags:--test --error-format=short
22
//@ check-stdout
3-
//@ error-pattern:cannot find function `foo`
43
//@ normalize-stdout: "tests/rustdoc-ui/issues" -> "$$DIR"
54
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
65
//@ failure-status: 101
@@ -11,3 +10,5 @@
1110
fn foo() {
1211
println!("Hello, world!");
1312
}
13+
14+
//~? RAW cannot find function `foo`

0 commit comments

Comments
 (0)