From 42048ea12298da75415ce0c2b25a381bbe81eade Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 7 Apr 2025 14:32:56 +0300 Subject: [PATCH 1/4] compiletest: Cleanup collection of actual errors --- src/tools/compiletest/src/json.rs | 83 +++++++++++++------------------ 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 9bc26fedf8f4c..132e9070650d1 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -142,43 +142,34 @@ pub fn extract_rendered(output: &str) -> String { } pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec { - output.lines().flat_map(|line| parse_line(file_name, line, output, proc_res)).collect() -} - -fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec { - // The compiler sometimes intermingles non-JSON stuff into the - // output. This hack just skips over such lines. Yuck. - if line.starts_with('{') { - match serde_json::from_str::(line) { - Ok(diagnostic) => { - let mut expected_errors = vec![]; - push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name); - expected_errors - } - Err(error) => { - // Ignore the future compat report message - this is handled - // by `extract_rendered` - if serde_json::from_str::(line).is_ok() { - vec![] - } else { - proc_res.fatal( + let mut errors = Vec::new(); + for line in output.lines() { + // The compiler sometimes intermingles non-JSON stuff into the + // output. This hack just skips over such lines. Yuck. + if line.starts_with('{') { + match serde_json::from_str::(line) { + Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name), + Err(error) => { + // Ignore the future compat report message - this is handled + // by `extract_rendered` + if serde_json::from_str::(line).is_err() { + proc_res.fatal( Some(&format!( - "failed to decode compiler output as json: \ - `{}`\nline: {}\noutput: {}", + "failed to decode compiler output as json: `{}`\nline: {}\noutput: {}", error, line, output )), || (), ); + } } } } - } else { - vec![] } + errors } -fn push_expected_errors( - expected_errors: &mut Vec, +fn push_actual_errors( + errors: &mut Vec, diagnostic: &Diagnostic, default_spans: &[&DiagnosticSpan], file_name: &str, @@ -236,10 +227,10 @@ fn push_expected_errors( } }; - // Convert multi-line messages into multiple expected - // errors. We expect to replace these with something - // more structured shortly anyhow. + // 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(); if let Some(first_line) = message_lines.next() { let ignore = |s| { static RE: OnceLock = OnceLock::new(); @@ -250,27 +241,23 @@ fn push_expected_errors( }; if primary_spans.is_empty() && !ignore(first_line) { - let msg = with_code(None, first_line); - let kind = ErrorKind::from_str(&diagnostic.level).ok(); - expected_errors.push(Error { line_num: None, kind, msg }); + errors.push(Error { line_num: None, kind, msg: with_code(None, first_line) }); } else { for span in primary_spans { - let msg = with_code(Some(span), first_line); - let kind = ErrorKind::from_str(&diagnostic.level).ok(); - expected_errors.push(Error { line_num: Some(span.line_start), kind, msg }); + errors.push(Error { + line_num: Some(span.line_start), + kind, + msg: with_code(Some(span), first_line), + }); } } } for next_line in message_lines { if primary_spans.is_empty() { - expected_errors.push(Error { - line_num: None, - kind: None, - msg: with_code(None, next_line), - }); + errors.push(Error { line_num: None, kind: None, msg: with_code(None, next_line) }); } else { for span in primary_spans { - expected_errors.push(Error { + errors.push(Error { line_num: Some(span.line_start), kind: None, msg: with_code(Some(span), next_line), @@ -283,7 +270,7 @@ fn push_expected_errors( for span in primary_spans { if let Some(ref suggested_replacement) = span.suggested_replacement { for (index, line) in suggested_replacement.lines().enumerate() { - expected_errors.push(Error { + errors.push(Error { line_num: Some(span.line_start + index), kind: Some(ErrorKind::Suggestion), msg: line.to_string(), @@ -295,13 +282,13 @@ fn push_expected_errors( // Add notes for the backtrace for span in primary_spans { if let Some(frame) = &span.expansion { - push_backtrace(expected_errors, frame, file_name); + push_backtrace(errors, frame, file_name); } } // Add notes for any labels that appear in the message. for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) { - expected_errors.push(Error { + errors.push(Error { line_num: Some(span.line_start), kind: Some(ErrorKind::Note), msg: span.label.clone().unwrap(), @@ -310,17 +297,17 @@ fn push_expected_errors( // Flatten out the children. for child in &diagnostic.children { - push_expected_errors(expected_errors, child, primary_spans, file_name); + push_actual_errors(errors, child, primary_spans, file_name); } } fn push_backtrace( - expected_errors: &mut Vec, + errors: &mut Vec, expansion: &DiagnosticSpanMacroExpansion, file_name: &str, ) { if Path::new(&expansion.span.file_name) == Path::new(&file_name) { - expected_errors.push(Error { + errors.push(Error { line_num: Some(expansion.span.line_start), kind: Some(ErrorKind::Note), msg: format!("in this expansion of {}", expansion.macro_decl_name), @@ -328,6 +315,6 @@ fn push_backtrace( } if let Some(previous_expansion) = &expansion.span.expansion { - push_backtrace(expected_errors, previous_expansion, file_name); + push_backtrace(errors, previous_expansion, file_name); } } From b86b3fb640e4f914db9013872e8ff67b74ba286d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 7 Apr 2025 14:45:53 +0300 Subject: [PATCH 2/4] compiletest: Always preserve kind for compiler diagnostics Those that didn't previously preserved kind are now marked as not requiring annotations to keep the previous behavior. Also, do not lose diagnostics with an empty message. --- src/tools/compiletest/src/errors.rs | 6 ++- src/tools/compiletest/src/json.rs | 51 +++++++++++++++----------- src/tools/compiletest/src/runtest.rs | 1 + tests/ui/proc-macro/issue-91800.rs | 3 ++ tests/ui/proc-macro/issue-91800.stderr | 8 ++-- 5 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index b68f817146fd7..e1face32716c8 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -53,6 +53,10 @@ pub struct Error { /// `None` if not specified or unknown message kind. pub kind: Option, pub msg: String, + /// For some `Error`s, like secondary lines of multi-line diagnostics, line annotations + /// are not mandatory, even if they would otherwise be mandatory for primary errors. + /// Only makes sense for "actual" errors, not for "expected" errors. + pub require_annotation: bool, } impl Error { @@ -182,7 +186,7 @@ fn parse_expected( kind, msg ); - Some((follow_prev, Error { line_num, kind, msg })) + Some((follow_prev, Error { line_num, kind, msg, require_annotation: true })) } #[cfg(test)] diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 132e9070650d1..2a6fcd6cf81a8 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -231,36 +231,42 @@ fn push_actual_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(); - if let Some(first_line) = message_lines.next() { - let ignore = |s| { - static RE: OnceLock = OnceLock::new(); - RE.get_or_init(|| { - Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap() - }) - .is_match(s) - }; - - if primary_spans.is_empty() && !ignore(first_line) { - errors.push(Error { line_num: None, kind, msg: with_code(None, first_line) }); - } else { - for span in primary_spans { - errors.push(Error { - line_num: Some(span.line_start), - kind, - msg: with_code(Some(span), first_line), - }); - } + let first_line = message_lines.next().unwrap_or(&diagnostic.message); + if primary_spans.is_empty() { + static RE: OnceLock = OnceLock::new(); + let re_init = + || Regex::new(r"aborting due to \d+ previous errors?|\d+ warnings? emitted").unwrap(); + errors.push(Error { + line_num: None, + kind, + msg: with_code(None, first_line), + require_annotation: !RE.get_or_init(re_init).is_match(first_line), + }); + } else { + for span in primary_spans { + errors.push(Error { + line_num: Some(span.line_start), + kind, + msg: with_code(Some(span), first_line), + require_annotation: true, + }); } } for next_line in message_lines { if primary_spans.is_empty() { - errors.push(Error { line_num: None, kind: None, msg: with_code(None, next_line) }); + errors.push(Error { + line_num: None, + kind, + msg: with_code(None, next_line), + require_annotation: false, + }); } else { for span in primary_spans { errors.push(Error { line_num: Some(span.line_start), - kind: None, + kind, msg: with_code(Some(span), next_line), + require_annotation: false, }); } } @@ -274,6 +280,7 @@ fn push_actual_errors( line_num: Some(span.line_start + index), kind: Some(ErrorKind::Suggestion), msg: line.to_string(), + require_annotation: true, }); } } @@ -292,6 +299,7 @@ fn push_actual_errors( line_num: Some(span.line_start), kind: Some(ErrorKind::Note), msg: span.label.clone().unwrap(), + require_annotation: true, }); } @@ -311,6 +319,7 @@ fn push_backtrace( line_num: Some(expansion.span.line_start), kind: Some(ErrorKind::Note), msg: format!("in this expansion of {}", expansion.macro_decl_name), + require_annotation: true, }); } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index c8a60b68da8b2..1002c290b6036 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -811,6 +811,7 @@ impl<'test> TestCx<'test> { expect_note: bool, ) -> bool { !actual_error.msg.is_empty() + && actual_error.require_annotation && match actual_error.kind { Some(ErrorKind::Help) => expect_help, Some(ErrorKind::Note) => expect_note, diff --git a/tests/ui/proc-macro/issue-91800.rs b/tests/ui/proc-macro/issue-91800.rs index bc78bcacfd0f7..8cecfad32b55b 100644 --- a/tests/ui/proc-macro/issue-91800.rs +++ b/tests/ui/proc-macro/issue-91800.rs @@ -6,11 +6,14 @@ extern crate issue_91800_macro; #[derive(MyTrait)] //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon //~| ERROR proc-macro derive produced unparsable tokens +//~| ERROR #[attribute_macro] //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon +//~| ERROR struct MyStruct; fn_macro! {} //~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon +//~| ERROR fn main() {} diff --git a/tests/ui/proc-macro/issue-91800.stderr b/tests/ui/proc-macro/issue-91800.stderr index d831d62e919d2..63ebc0a552e33 100644 --- a/tests/ui/proc-macro/issue-91800.stderr +++ b/tests/ui/proc-macro/issue-91800.stderr @@ -21,7 +21,7 @@ LL | #[derive(MyTrait)] = note: this error originates in the derive macro `MyTrait` (in Nightly builds, run with -Z macro-backtrace for more info) error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/issue-91800.rs:9:1 + --> $DIR/issue-91800.rs:10:1 | LL | #[attribute_macro] | ^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | #[attribute_macro] = note: this error originates in the attribute macro `attribute_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: - --> $DIR/issue-91800.rs:9:1 + --> $DIR/issue-91800.rs:10:1 | LL | #[attribute_macro] | ^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | #[attribute_macro] = note: this error originates in the attribute macro `attribute_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/issue-91800.rs:13:1 + --> $DIR/issue-91800.rs:15:1 | LL | fn_macro! {} | ^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | fn_macro! {} = note: this error originates in the macro `fn_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: - --> $DIR/issue-91800.rs:13:1 + --> $DIR/issue-91800.rs:15:1 | LL | fn_macro! {} | ^^^^^^^^^^^^ From 5c160f511e321a89eef01fcf17c6cc4c0f4e5c00 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 7 Apr 2025 15:44:12 +0300 Subject: [PATCH 3/4] compiletest: Stricter parsing for diagnostic kinds --- src/tools/compiletest/src/errors.rs | 66 ++++++++++--------- src/tools/compiletest/src/json.rs | 6 +- tests/ui/async-await/issue-70818.rs | 2 +- tests/ui/async-await/issue-71137.rs | 2 +- tests/ui/const-generics/defaults/mismatch.rs | 10 +-- .../dont-evaluate-array-len-on-err-1.rs | 2 +- .../abstract-const-as-cast-3.rs | 24 +++---- .../generic_const_exprs/issue-72787.rs | 8 +-- ...9518-default_trait_method_normalization.rs | 2 +- tests/ui/impl-trait/impl-generic-mismatch.rs | 8 +-- .../assignment-operator-unimplemented.rs | 2 +- tests/ui/modules/issue-107649.rs | 2 +- .../cache-after-waiting-issue-111528.rs | 2 +- ...iable-with-name-similar-to-struct-field.rs | 6 +- tests/ui/suggestions/issue-103646.rs | 2 +- tests/ui/type-alias-impl-trait/issue-53598.rs | 2 +- 16 files changed, 74 insertions(+), 72 deletions(-) diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index e1face32716c8..9b59e4968a3dc 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 { - 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 { + 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::().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 2a6fcd6cf81a8..62fe538ee32ea 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 = 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 { diff --git a/tests/ui/async-await/issue-70818.rs b/tests/ui/async-await/issue-70818.rs index 36295a84e7ad7..bc181de8d925d 100644 --- a/tests/ui/async-await/issue-70818.rs +++ b/tests/ui/async-await/issue-70818.rs @@ -2,7 +2,7 @@ use std::future::Future; fn foo(ty: T, ty1: U) -> impl Future + Send { - //~^ Error future cannot be sent between threads safely + //~^ ERROR future cannot be sent between threads safely async { (ty, ty1) } } diff --git a/tests/ui/async-await/issue-71137.rs b/tests/ui/async-await/issue-71137.rs index 551cf85047cae..6fbf17ccf0d04 100644 --- a/tests/ui/async-await/issue-71137.rs +++ b/tests/ui/async-await/issue-71137.rs @@ -19,5 +19,5 @@ async fn wrong_mutex() { } fn main() { - fake_spawn(wrong_mutex()); //~ Error future cannot be sent between threads safely + fake_spawn(wrong_mutex()); //~ ERROR future cannot be sent between threads safely } diff --git a/tests/ui/const-generics/defaults/mismatch.rs b/tests/ui/const-generics/defaults/mismatch.rs index ec131505ed755..3e35c2060b1e0 100644 --- a/tests/ui/const-generics/defaults/mismatch.rs +++ b/tests/ui/const-generics/defaults/mismatch.rs @@ -5,18 +5,18 @@ pub struct Example4; fn main() { let e: Example<13> = (); - //~^ Error: mismatched types + //~^ ERROR mismatched types //~| expected struct `Example` let e: Example2 = (); - //~^ Error: mismatched types + //~^ ERROR mismatched types //~| expected struct `Example2` let e: Example3<13, u32> = (); - //~^ Error: mismatched types + //~^ ERROR mismatched types //~| expected struct `Example3` let e: Example3<7> = (); - //~^ Error: mismatched types + //~^ ERROR mismatched types //~| expected struct `Example3<7>` let e: Example4<7> = (); - //~^ Error: mismatched types + //~^ ERROR mismatched types //~| expected struct `Example4<7>` } diff --git a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs index 6c4ee1af210ba..e7f050dae3671 100644 --- a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs +++ b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs @@ -13,7 +13,7 @@ trait Foo { [Adt; std::mem::size_of::()]: , { <[Adt; std::mem::size_of::()] as Foo>::bar() - //~^ Error: the trait bound + //~^ ERROR the trait bound } fn bar() {} diff --git a/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs b/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs index 7561ae2febbdf..33872ce7f0f26 100644 --- a/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs +++ b/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs @@ -15,15 +15,15 @@ where // errors are bad but seems to be pre-existing issue #86198 assert_impl::>(); - //~^ Error: mismatched types - //~^^ Error: unconstrained generic constant + //~^ ERROR mismatched types + //~^^ ERROR unconstrained generic constant assert_impl::>(); - //~^ Error: mismatched types - //~^^ Error: unconstrained generic constant + //~^ ERROR mismatched types + //~^^ ERROR unconstrained generic constant assert_impl::>(); - //~^ Error: mismatched types + //~^ ERROR mismatched types assert_impl::>(); - //~^ Error: mismatched types + //~^ ERROR mismatched types } pub fn use_trait_impl_2() where @@ -33,15 +33,15 @@ where // errors are bad but seems to be pre-existing issue #86198 assert_impl::>(); - //~^ Error: mismatched types - //~^^ Error: unconstrained generic constant + //~^ ERROR mismatched types + //~^^ ERROR unconstrained generic constant assert_impl::>(); - //~^ Error: mismatched types - //~^^ Error: unconstrained generic constant + //~^ ERROR mismatched types + //~^^ ERROR unconstrained generic constant assert_impl::>(); - //~^ Error: mismatched types + //~^ ERROR mismatched types assert_impl::>(); - //~^ Error: mismatched types + //~^ ERROR mismatched types } fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72787.rs b/tests/ui/const-generics/generic_const_exprs/issue-72787.rs index c3208786708b5..ea65b6d3fdf26 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-72787.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-72787.rs @@ -9,8 +9,8 @@ pub trait True {} impl True for IsLessOrEqual where Condition<{ LHS <= RHS }>: True -//[min]~^ Error generic parameters may not be used in const operations -//[min]~| Error generic parameters may not be used in const operations +//[min]~^ ERROR generic parameters may not be used in const operations +//[min]~| ERROR generic parameters may not be used in const operations { } impl True for Condition {} @@ -21,8 +21,8 @@ where IsLessOrEqual: True, IsLessOrEqual: True, IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, -//[min]~^ Error generic parameters may not be used in const operations -//[min]~| Error generic parameters may not be used in const operations +//[min]~^ ERROR generic parameters may not be used in const operations +//[min]~| ERROR generic parameters may not be used in const operations // Condition<{ 8 - I <= 8 - J }>: True, { fn print() { diff --git a/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs b/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs index 2fa9a71fbb33c..f08b9ceffb966 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs @@ -14,7 +14,7 @@ trait Foo { [(); std::mem::size_of::()]: , { Self::AssocInstance == [(); std::mem::size_of::()]; - //~^ Error: mismatched types + //~^ ERROR mismatched types } } diff --git a/tests/ui/impl-trait/impl-generic-mismatch.rs b/tests/ui/impl-trait/impl-generic-mismatch.rs index fb8bde0d08131..f05e01716c312 100644 --- a/tests/ui/impl-trait/impl-generic-mismatch.rs +++ b/tests/ui/impl-trait/impl-generic-mismatch.rs @@ -6,7 +6,7 @@ trait Foo { impl Foo for () { fn foo(&self, _: &U) { } - //~^ Error method `foo` has incompatible signature for trait + //~^ ERROR method `foo` has incompatible signature for trait } trait Bar { @@ -15,7 +15,7 @@ trait Bar { impl Bar for () { fn bar(&self, _: &impl Debug) { } - //~^ Error method `bar` has incompatible signature for trait + //~^ ERROR method `bar` has incompatible signature for trait } trait Baz { @@ -24,7 +24,7 @@ trait Baz { impl Baz for () { fn baz(&self, _: &impl Debug, _: &T) { } - //~^ Error method `baz` has incompatible signature for trait + //~^ ERROR method `baz` has incompatible signature for trait } // With non-local trait (#49841): @@ -35,7 +35,7 @@ struct X; impl Hash for X { fn hash(&self, hasher: &mut impl Hasher) {} - //~^ Error method `hash` has incompatible signature for trait + //~^ ERROR method `hash` has incompatible signature for trait } fn main() {} diff --git a/tests/ui/mismatched_types/assignment-operator-unimplemented.rs b/tests/ui/mismatched_types/assignment-operator-unimplemented.rs index 21df464d5e450..04a379bbd0484 100644 --- a/tests/ui/mismatched_types/assignment-operator-unimplemented.rs +++ b/tests/ui/mismatched_types/assignment-operator-unimplemented.rs @@ -3,5 +3,5 @@ struct Foo; fn main() { let mut a = Foo; let ref b = Foo; - a += *b; //~ Error: binary assignment operation `+=` cannot be applied to type `Foo` + a += *b; //~ ERROR binary assignment operation `+=` cannot be applied to type `Foo` } diff --git a/tests/ui/modules/issue-107649.rs b/tests/ui/modules/issue-107649.rs index af5758d798588..f93fb07e17af0 100644 --- a/tests/ui/modules/issue-107649.rs +++ b/tests/ui/modules/issue-107649.rs @@ -102,5 +102,5 @@ fn main() { (); (); (); - dbg!(lib::Dummy); //~ Error: `Dummy` doesn't implement `Debug` + dbg!(lib::Dummy); //~ ERROR `Dummy` doesn't implement `Debug` } diff --git a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs index b23cb9ce917be..73d173022f6ac 100644 --- a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs +++ b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs @@ -10,7 +10,7 @@ pub fn a() { #[export_name="fail"] pub fn b() { -//~^ Error symbol `fail` is already defined +//~^ ERROR symbol `fail` is already defined } fn main() {} diff --git a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs index ecd3f58811904..7216b0294dcec 100644 --- a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs +++ b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs @@ -4,15 +4,15 @@ struct A { impl A { fn new(cofig: String) -> Self { - Self { config } //~ Error cannot find value `config` in this scope + Self { config } //~ ERROR cannot find value `config` in this scope } fn do_something(cofig: String) { - println!("{config}"); //~ Error cannot find value `config` in this scope + println!("{config}"); //~ ERROR cannot find value `config` in this scope } fn self_is_available(self, cofig: String) { - println!("{config}"); //~ Error cannot find value `config` in this scope + println!("{config}"); //~ ERROR cannot find value `config` in this scope } } diff --git a/tests/ui/suggestions/issue-103646.rs b/tests/ui/suggestions/issue-103646.rs index f679640c5dc90..d8b06d663affc 100644 --- a/tests/ui/suggestions/issue-103646.rs +++ b/tests/ui/suggestions/issue-103646.rs @@ -5,7 +5,7 @@ trait Cat { fn uwu(c: T) { c.nya(); //~^ ERROR no method named `nya` found for type parameter `T` in the current scope - //~| Suggestion T::nya() + //~| SUGGESTION T::nya() } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-53598.rs b/tests/ui/type-alias-impl-trait/issue-53598.rs index 3262c69cf5a4e..d8eee3218ed39 100644 --- a/tests/ui/type-alias-impl-trait/issue-53598.rs +++ b/tests/ui/type-alias-impl-trait/issue-53598.rs @@ -17,7 +17,7 @@ impl Foo for S2 { type Item = impl Debug; fn foo(_: T) -> Self::Item { - //~^ Error type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias S::(Default::default()) } } From fd854a772e12ee51c0028e9dbb9443d831e28327 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 7 Apr 2025 19:13:16 +0300 Subject: [PATCH 4/4] compiletest: Avoid ignoring empty diagnostics in one more place This catches some silly notes emitted by rustc, which should ideally be fixed --- src/tools/compiletest/src/runtest.rs | 3 +-- tests/incremental/circular-dependencies.rs | 1 + .../consts/const_in_pattern/reject_non_structural.rs | 1 + .../const_in_pattern/reject_non_structural.stderr | 8 ++++---- tests/ui/fn/param-mismatch-foreign.rs | 1 + tests/ui/fn/param-mismatch-foreign.stderr | 2 +- tests/ui/mismatched_types/similar_paths_primitive.rs | 3 ++- .../mismatched_types/similar_paths_primitive.stderr | 6 +++--- .../moves/nested-loop-moved-value-wrong-continue.rs | 6 +++++- .../nested-loop-moved-value-wrong-continue.stderr | 12 ++++++------ .../issue-87217-keyword-order/const-async-const.rs | 1 + .../issue-87217-keyword-order/several-kw-jump.rs | 1 + 12 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1002c290b6036..13f3479247a23 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -810,8 +810,7 @@ impl<'test> TestCx<'test> { expect_help: bool, expect_note: bool, ) -> bool { - !actual_error.msg.is_empty() - && actual_error.require_annotation + actual_error.require_annotation && match actual_error.kind { Some(ErrorKind::Help) => expect_help, Some(ErrorKind::Note) => expect_note, diff --git a/tests/incremental/circular-dependencies.rs b/tests/incremental/circular-dependencies.rs index c7b5b931fbbec..bd3b109b62c75 100644 --- a/tests/incremental/circular-dependencies.rs +++ b/tests/incremental/circular-dependencies.rs @@ -15,6 +15,7 @@ pub struct Foo; pub fn consume_foo(_: Foo) {} //[cfail2]~^ NOTE function defined here +//[cfail2]~| NOTE pub fn produce_foo() -> Foo { Foo diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs index 39e5f732a8985..6478bf9c6ee1c 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs @@ -93,6 +93,7 @@ fn main() { //~| NOTE constant of non-structural type trait Trait: Sized { const ASSOC: Option; } //~ NOTE constant defined here + //~^ NOTE impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; //~^ ERROR constant of non-structural type `NoDerive` in a pattern diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr index fa16d0b06a7fe..bf54d3d76aed3 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -118,14 +118,14 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:97:28 + --> $DIR/reject_non_structural.rs:98:28 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns ... LL | trait Trait: Sized { const ASSOC: Option; } | ------------------ ------------------------- constant defined here -LL | impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } +... LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ constant of non-structural type | @@ -136,7 +136,7 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:102:28 + --> $DIR/reject_non_structural.rs:103:28 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns @@ -153,7 +153,7 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:107:29 + --> $DIR/reject_non_structural.rs:108:29 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns diff --git a/tests/ui/fn/param-mismatch-foreign.rs b/tests/ui/fn/param-mismatch-foreign.rs index 2ab2bf95448a4..eebca29d6c933 100644 --- a/tests/ui/fn/param-mismatch-foreign.rs +++ b/tests/ui/fn/param-mismatch-foreign.rs @@ -1,6 +1,7 @@ extern "C" { fn foo(x: i32, y: u32, z: i32); //~^ NOTE function defined here + //~| NOTE } fn main() { diff --git a/tests/ui/fn/param-mismatch-foreign.stderr b/tests/ui/fn/param-mismatch-foreign.stderr index 835e0a3343e9a..fff3283cbb6ce 100644 --- a/tests/ui/fn/param-mismatch-foreign.stderr +++ b/tests/ui/fn/param-mismatch-foreign.stderr @@ -1,5 +1,5 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied - --> $DIR/param-mismatch-foreign.rs:7:5 + --> $DIR/param-mismatch-foreign.rs:8:5 | LL | foo(1i32, 2i32); | ^^^ ---- argument #2 of type `u32` is missing diff --git a/tests/ui/mismatched_types/similar_paths_primitive.rs b/tests/ui/mismatched_types/similar_paths_primitive.rs index a58fe68b86381..b20ca80ac0717 100644 --- a/tests/ui/mismatched_types/similar_paths_primitive.rs +++ b/tests/ui/mismatched_types/similar_paths_primitive.rs @@ -4,8 +4,9 @@ struct bool; //~ NOTE the other `bool` is defined in the current crate struct str; //~ NOTE the other `str` is defined in the current crate fn foo(_: bool) {} //~ NOTE function defined here + //~^ NOTE fn bar(_: &str) {} //~ NOTE function defined here - + //~^ NOTE fn main() { foo(true); //~^ ERROR mismatched types [E0308] diff --git a/tests/ui/mismatched_types/similar_paths_primitive.stderr b/tests/ui/mismatched_types/similar_paths_primitive.stderr index cf26234dba857..9c1aa0d7105b6 100644 --- a/tests/ui/mismatched_types/similar_paths_primitive.stderr +++ b/tests/ui/mismatched_types/similar_paths_primitive.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/similar_paths_primitive.rs:10:9 + --> $DIR/similar_paths_primitive.rs:11:9 | LL | foo(true); | --- ^^^^ expected `bool`, found a different `bool` @@ -20,7 +20,7 @@ LL | fn foo(_: bool) {} | ^^^ ------- error[E0308]: mismatched types - --> $DIR/similar_paths_primitive.rs:16:9 + --> $DIR/similar_paths_primitive.rs:17:9 | LL | bar("hello"); | --- ^^^^^^^ expected `str`, found a different `str` @@ -35,7 +35,7 @@ note: the other `str` is defined in the current crate LL | struct str; | ^^^^^^^^^^ note: function defined here - --> $DIR/similar_paths_primitive.rs:7:4 + --> $DIR/similar_paths_primitive.rs:8:4 | LL | fn bar(_: &str) {} | ^^^ ------- diff --git a/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs b/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs index 0235b291df540..87800d314ed50 100644 --- a/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs +++ b/tests/ui/moves/nested-loop-moved-value-wrong-continue.rs @@ -9,6 +9,8 @@ fn foo() { //~| NOTE inside of this loop //~| HELP consider moving the expression out of the loop //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE + //~| NOTE baz.push(foo); //~^ NOTE value moved here //~| HELP consider cloning the value @@ -30,17 +32,19 @@ fn main() { for foo in foos { //~^ NOTE this reinitialization might get skipped //~| NOTE move occurs because `foo` has type `String` + //~| NOTE for bar in &bars { //~^ NOTE inside of this loop //~| HELP consider moving the expression out of the loop //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE if foo == *bar { baz.push(foo); //~^ NOTE value moved here //~| HELP consider cloning the value continue; //~^ NOTE verify that your loop breaking logic is correct - //~| NOTE this `continue` advances the loop at line 33 + //~| NOTE this `continue` advances the loop at line 36 } } qux.push(foo); diff --git a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr index cf863ff8af148..6ef1a4193b1ae 100644 --- a/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr +++ b/tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `foo` - --> $DIR/nested-loop-moved-value-wrong-continue.rs:19:14 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:21:14 | LL | for foo in foos { for bar in &bars { if foo == *bar { | --- ---------------- inside of this loop @@ -14,13 +14,13 @@ LL | qux.push(foo); | ^^^ value used here after move | note: verify that your loop breaking logic is correct - --> $DIR/nested-loop-moved-value-wrong-continue.rs:15:9 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:17:9 | LL | for foo in foos { for bar in &bars { if foo == *bar { | --------------- ---------------- ... LL | continue; - | ^^^^^^^^ this `continue` advances the loop at $DIR/nested-loop-moved-value-wrong-continue.rs:6:23: 18:8 + | ^^^^^^^^ this `continue` advances the loop at $DIR/nested-loop-moved-value-wrong-continue.rs:6:23: 20:8 help: consider moving the expression out of the loop so it is only moved once | LL ~ for foo in foos { let mut value = baz.push(foo); @@ -36,7 +36,7 @@ LL | baz.push(foo.clone()); | ++++++++ error[E0382]: use of moved value: `foo` - --> $DIR/nested-loop-moved-value-wrong-continue.rs:46:18 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:50:18 | LL | for foo in foos { | --- @@ -54,7 +54,7 @@ LL | qux.push(foo); | ^^^ value used here after move | note: verify that your loop breaking logic is correct - --> $DIR/nested-loop-moved-value-wrong-continue.rs:41:17 + --> $DIR/nested-loop-moved-value-wrong-continue.rs:45:17 | LL | for foo in foos { | --------------- @@ -63,7 +63,7 @@ LL | for bar in &bars { | ---------------- ... LL | continue; - | ^^^^^^^^ this `continue` advances the loop at line 33 + | ^^^^^^^^ this `continue` advances the loop at line 36 help: consider moving the expression out of the loop so it is only moved once | LL ~ let mut value = baz.push(foo); diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs index e6235b1e8923f..c137e13633595 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs +++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs @@ -10,5 +10,6 @@ const async const fn test() {} //~| ERROR functions cannot be both `const` and `async` //~| NOTE `const` because of this //~| NOTE `async` because of this +//~| NOTE fn main() {} diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs index 40f993eafbb1e..49a49d337c477 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs +++ b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs @@ -15,5 +15,6 @@ async unsafe const fn test() {} //~| ERROR functions cannot be both `const` and `async` //~| NOTE `const` because of this //~| NOTE `async` because of this +//~| NOTE fn main() {}