Skip to content

compiletest: Stricter parsing for diagnostic kinds #139485

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 9, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 39 additions & 33 deletions src/tools/compiletest/src/errors.rs
Original file line number Diff line number Diff line change
@@ -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"),
}
}
}
@@ -53,14 +61,18 @@ pub struct Error {
/// `None` if not specified or unknown message kind.
pub kind: Option<ErrorKind>,
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 {
pub fn render_for_expected(&self) -> String {
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(),
)
@@ -150,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 == "|" {
@@ -177,12 +183,12 @@ fn parse_expected(
debug!(
"line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}",
line_num,
whole_match.as_str(),
tag.as_str(),
follow_prev,
kind,
msg
);
Some((follow_prev, Error { line_num, kind, msg }))
Some((follow_prev, Error { line_num, kind, msg, require_annotation: true }))
}

#[cfg(test)]
116 changes: 56 additions & 60 deletions src/tools/compiletest/src/json.rs
Original file line number Diff line number Diff line change
@@ -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;
@@ -142,43 +141,34 @@ pub fn extract_rendered(output: &str) -> String {
}

pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
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<Error> {
// 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::<Diagnostic>(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::<FutureIncompatReport>(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::<Diagnostic>(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::<FutureIncompatReport>(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<Error>,
fn push_actual_errors(
errors: &mut Vec<Error>,
diagnostic: &Diagnostic,
default_spans: &[&DiagnosticSpan],
file_name: &str,
@@ -236,44 +226,47 @@ 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();
if let Some(first_line) = message_lines.next() {
let ignore = |s| {
static RE: OnceLock<Regex> = 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) {
let msg = with_code(None, first_line);
let kind = ErrorKind::from_str(&diagnostic.level).ok();
expected_errors.push(Error { line_num: None, kind, msg });
} 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 });
}
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();
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: diagnostic.level != "failure-note"
&& !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() {
expected_errors.push(Error {
errors.push(Error {
line_num: None,
kind: None,
kind,
msg: with_code(None, next_line),
require_annotation: false,
});
} else {
for span in primary_spans {
expected_errors.push(Error {
errors.push(Error {
line_num: Some(span.line_start),
kind: None,
kind,
msg: with_code(Some(span), next_line),
require_annotation: false,
});
}
}
@@ -283,10 +276,11 @@ 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(),
require_annotation: true,
});
}
}
@@ -295,39 +289,41 @@ 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(),
require_annotation: true,
});
}

// 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<Error>,
errors: &mut Vec<Error>,
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),
require_annotation: true,
});
}

if let Some(previous_expansion) = &expansion.span.expansion {
push_backtrace(expected_errors, previous_expansion, file_name);
push_backtrace(errors, previous_expansion, file_name);
}
}
2 changes: 1 addition & 1 deletion src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
@@ -810,7 +810,7 @@ impl<'test> TestCx<'test> {
expect_help: bool,
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,
1 change: 1 addition & 0 deletions tests/incremental/circular-dependencies.rs
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion tests/ui/async-await/issue-70818.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

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

2 changes: 1 addition & 1 deletion tests/ui/async-await/issue-71137.rs
Original file line number Diff line number Diff line change
@@ -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
}
10 changes: 5 additions & 5 deletions tests/ui/const-generics/defaults/mismatch.rs
Original file line number Diff line number Diff line change
@@ -5,18 +5,18 @@ pub struct Example4<const N: usize = 13, const M: usize = 4>;

fn main() {
let e: Example<13> = ();
//~^ Error: mismatched types
//~^ ERROR mismatched types
//~| expected struct `Example`
let e: Example2<u32, 13> = ();
//~^ 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>`
}
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ trait Foo {
[Adt; std::mem::size_of::<Self::Assoc>()]: ,
{
<[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
//~^ Error: the trait bound
//~^ ERROR the trait bound
}

fn bar() {}
Original file line number Diff line number Diff line change
@@ -15,15 +15,15 @@ where

// errors are bad but seems to be pre-existing issue #86198
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
//~^ Error: mismatched types
//~^^ Error: unconstrained generic constant
//~^ ERROR mismatched types
//~^^ ERROR unconstrained generic constant
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
//~^ Error: mismatched types
//~^^ Error: unconstrained generic constant
//~^ ERROR mismatched types
//~^^ ERROR unconstrained generic constant
assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
//~^ Error: mismatched types
//~^ ERROR mismatched types
assert_impl::<HasCastInTraitImpl<14, 13>>();
//~^ Error: mismatched types
//~^ ERROR mismatched types
}
pub fn use_trait_impl_2<const N: usize>()
where
@@ -33,15 +33,15 @@ where

// errors are bad but seems to be pre-existing issue #86198
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
//~^ Error: mismatched types
//~^^ Error: unconstrained generic constant
//~^ ERROR mismatched types
//~^^ ERROR unconstrained generic constant
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
//~^ Error: mismatched types
//~^^ Error: unconstrained generic constant
//~^ ERROR mismatched types
//~^^ ERROR unconstrained generic constant
assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
//~^ Error: mismatched types
//~^ ERROR mismatched types
assert_impl::<HasCastInTraitImpl<14, 13>>();
//~^ Error: mismatched types
//~^ ERROR mismatched types
}

fn main() {}
8 changes: 4 additions & 4 deletions tests/ui/const-generics/generic_const_exprs/issue-72787.rs
Original file line number Diff line number Diff line change
@@ -9,8 +9,8 @@ pub trait True {}

impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> 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<true> {}
@@ -21,8 +21,8 @@ where
IsLessOrEqual<I, 8>: True,
IsLessOrEqual<J, 8>: 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() {
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ trait Foo {
[(); std::mem::size_of::<Self::Assoc>()]: ,
{
Self::AssocInstance == [(); std::mem::size_of::<Self::Assoc>()];
//~^ Error: mismatched types
//~^ ERROR mismatched types
}
}

1 change: 1 addition & 0 deletions tests/ui/consts/const_in_pattern/reject_non_structural.rs
Original file line number Diff line number Diff line change
@@ -93,6 +93,7 @@ fn main() {
//~| NOTE constant of non-structural type

trait Trait: Sized { const ASSOC: Option<Self>; } //~ NOTE constant defined here
//~^ NOTE
impl Trait for NoDerive { const ASSOC: Option<NoDerive> = Some(NoDerive); }
match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
//~^ ERROR constant of non-structural type `NoDerive` in a pattern
8 changes: 4 additions & 4 deletions tests/ui/consts/const_in_pattern/reject_non_structural.stderr
Original file line number Diff line number Diff line change
@@ -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<Self>; }
| ------------------ ------------------------- constant defined here
LL | impl Trait for NoDerive { const ASSOC: Option<NoDerive> = 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
1 change: 1 addition & 0 deletions tests/ui/fn/param-mismatch-foreign.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
extern "C" {
fn foo(x: i32, y: u32, z: i32);
//~^ NOTE function defined here
//~| NOTE
}

fn main() {
2 changes: 1 addition & 1 deletion tests/ui/fn/param-mismatch-foreign.stderr
Original file line number Diff line number Diff line change
@@ -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
8 changes: 4 additions & 4 deletions tests/ui/impl-trait/impl-generic-mismatch.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ trait Foo {

impl Foo for () {
fn foo<U: Debug>(&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<T: Debug>(&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() {}
Original file line number Diff line number Diff line change
@@ -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`
}
3 changes: 2 additions & 1 deletion tests/ui/mismatched_types/similar_paths_primitive.rs
Original file line number Diff line number Diff line change
@@ -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]
6 changes: 3 additions & 3 deletions tests/ui/mismatched_types/similar_paths_primitive.stderr
Original file line number Diff line number Diff line change
@@ -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) {}
| ^^^ -------
2 changes: 1 addition & 1 deletion tests/ui/modules/issue-107649.rs
Original file line number Diff line number Diff line change
@@ -102,5 +102,5 @@ fn main() {
();
();
();
dbg!(lib::Dummy); //~ Error: `Dummy` doesn't implement `Debug`
dbg!(lib::Dummy); //~ ERROR `Dummy` doesn't implement `Debug`
}
6 changes: 5 additions & 1 deletion tests/ui/moves/nested-loop-moved-value-wrong-continue.rs
Original file line number Diff line number Diff line change
@@ -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);
12 changes: 6 additions & 6 deletions tests/ui/moves/nested-loop-moved-value-wrong-continue.stderr
Original file line number Diff line number Diff line change
@@ -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);
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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() {}
3 changes: 3 additions & 0 deletions tests/ui/proc-macro/issue-91800.rs
Original file line number Diff line number Diff line change
@@ -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() {}
8 changes: 4 additions & 4 deletions tests/ui/proc-macro/issue-91800.stderr
Original file line number Diff line number Diff line change
@@ -21,31 +21,31 @@ 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]
| ^^^^^^^^^^^^^^^^^^
|
= 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]
| ^^^^^^^^^^^^^^^^^^
|
= 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! {}
| ^^^^^^^^^^^^
|
= 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! {}
| ^^^^^^^^^^^^
Original file line number Diff line number Diff line change
@@ -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
}
}

2 changes: 1 addition & 1 deletion tests/ui/suggestions/issue-103646.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ trait Cat {
fn uwu<T: Cat>(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() {}
2 changes: 1 addition & 1 deletion tests/ui/type-alias-impl-trait/issue-53598.rs
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ impl Foo for S2 {
type Item = impl Debug;

fn foo<T: Debug>(_: 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::<T>(Default::default())
}
}