From d3299af26d8e884c484c5d06991b4cbf7fced590 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Mar 2024 13:29:15 +0100 Subject: [PATCH 01/24] transmute: caution against int2ptr transmutation --- library/core/src/intrinsics.rs | 37 ++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 86b9a39d68a67..ce498561eeb12 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1169,14 +1169,6 @@ extern "rust-intrinsic" { /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly /// unsafe**. `transmute` should be the absolute last resort. /// - /// Transmuting pointers *to* integers in a `const` context is [undefined behavior][ub], - /// unless the pointer was originally created *from* an integer. - /// (That includes this function specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::dangling], - /// but also semantically-equivalent conversions such as punning through `repr(C)` union fields.) - /// Any attempt to use the resulting value for integer operations will abort const-evaluation. - /// (And even outside `const`, such transmutation is touching on many unspecified aspects of the - /// Rust memory model and should be avoided. See below for alternatives.) - /// /// Because `transmute` is a by-value operation, alignment of the *transmuted values /// themselves* is not a concern. As with any other function, the compiler already ensures /// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point @@ -1187,6 +1179,35 @@ extern "rust-intrinsic" { /// /// [ub]: ../../reference/behavior-considered-undefined.html /// + /// # Transmutation between pointers and integers + /// + /// Special care has to be taken when transmuting between pointers and integers, e.g. + /// transmuting between `*const ()` and `usize`. + /// + /// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless + /// the pointer was originally created *from* an integer. (That includes this function + /// specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::dangling], + /// but also semantically-equivalent conversions such as punning through `repr(C)` union + /// fields.) Any attempt to use the resulting value for integer operations will abort + /// const-evaluation. (And even outside `const`, such transmutation is touching on many + /// unspecified aspects of the Rust memory model and should be avoided. See below for + /// alternatives.) + /// + /// Transmuting *integers to pointers* is a largely unspecified operation. It is likely *not* + /// equivalent to an `as` cast. Doing non-zero-sized memory accesses with a pointer constructed + /// this way is currently considered undefined behavior. + /// + /// All this also applies when the integer is nested inside an array, tuple, struct, or enum. + /// However, `MaybeUninit` is not considered an integer type for the purpose of this + /// section. Transmuting `*const ()` to `MaybeUninit` is fine---but then calling + /// `assume_init()` on that result is considered as completing the pointer-to-integer transmute + /// and thus runs into the issues discussed above. + /// + /// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a + /// lossless process. If you want to round-trip a pointer through an integer in a way that you + /// can get back the original pointer, you need to use `as` casts, or replace the integer type + /// by `MaybeUninit<$int>` (and never call `assume_init()`). + /// /// # Examples /// /// There are a few things that `transmute` is really useful for. From 982918f4935fd4677af06d42e0d0b298bfb1c243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 9 Mar 2024 00:35:57 +0000 Subject: [PATCH 02/24] Handle str literals written with `'` lexed as lifetime Given `'hello world'` and `'1 str', provide a structured suggestion for a valid string literal: ``` error[E0762]: unterminated character literal --> $DIR/lex-bad-str-literal-as-char-3.rs:2:26 | LL | println!('hello world'); | ^^^^ | help: if you meant to write a `str` literal, use double quotes | LL | println!("hello world"); | ~ ~ ``` ``` error[E0762]: unterminated character literal --> $DIR/lex-bad-str-literal-as-char-1.rs:2:20 | LL | println!('1 + 1'); | ^^^^ | help: if you meant to write a `str` literal, use double quotes | LL | println!("1 + 1"); | ~ ~ ``` Fix #119685. --- compiler/rustc_lexer/src/cursor.rs | 2 +- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 11 +++++ compiler/rustc_parse/src/lexer/mod.rs | 46 +++++++++++++++++-- .../lexer/lex-bad-str-literal-as-char-1.fixed | 6 +++ .../ui/lexer/lex-bad-str-literal-as-char-1.rs | 6 +++ .../lex-bad-str-literal-as-char-1.stderr | 20 ++++++++ .../lexer/lex-bad-str-literal-as-char-2.fixed | 4 ++ .../ui/lexer/lex-bad-str-literal-as-char-2.rs | 4 ++ .../lex-bad-str-literal-as-char-2.stderr | 13 ++++++ .../lexer/lex-bad-str-literal-as-char-3.fixed | 4 ++ .../ui/lexer/lex-bad-str-literal-as-char-3.rs | 4 ++ .../lex-bad-str-literal-as-char-3.stderr | 14 ++++++ 13 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-1.rs create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-2.rs create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.rs create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs index aba7f95487e9d..8d8cc9ecc3e9f 100644 --- a/compiler/rustc_lexer/src/cursor.rs +++ b/compiler/rustc_lexer/src/cursor.rs @@ -46,7 +46,7 @@ impl<'a> Cursor<'a> { /// If requested position doesn't exist, `EOF_CHAR` is returned. /// However, getting `EOF_CHAR` doesn't always mean actual end of file, /// it should be checked with `is_eof` method. - pub(crate) fn first(&self) -> char { + pub fn first(&self) -> char { // `.next()` optimizes better than `.nth(0)` self.chars.clone().next().unwrap_or(EOF_CHAR) } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index a100e2d47bbbb..888c621f02afd 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -835,6 +835,7 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown .label = unknown prefix .note = prefixed identifiers and literals are reserved since Rust 2021 .suggestion_br = use `br` for a raw byte string + .suggestion_str = if you meant to write a `str` literal, use double quotes .suggestion_whitespace = consider inserting whitespace here parse_unknown_start_of_token = unknown start of token: {$escaped} diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 32b56bb7e877e..140eb6cd18752 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1994,6 +1994,17 @@ pub enum UnknownPrefixSugg { style = "verbose" )] Whitespace(#[primary_span] Span), + #[multipart_suggestion( + parse_suggestion_str, + applicability = "maybe-incorrect", + style = "verbose" + )] + MeantStr { + #[suggestion_part(code = "\"")] + start: Span, + #[suggestion_part(code = "\"")] + end: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index f57945a52df37..659e0b63d2ed8 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -63,6 +63,7 @@ pub(crate) fn parse_token_trees<'psess, 'src>( cursor, override_span, nbsp_is_whitespace: false, + last_lifetime: None, }; let (stream, res, unmatched_delims) = tokentrees::TokenTreesReader::parse_all_token_trees(string_reader); @@ -105,6 +106,10 @@ struct StringReader<'psess, 'src> { /// in this file, it's safe to treat further occurrences of the non-breaking /// space character as whitespace. nbsp_is_whitespace: bool, + + /// Track the `Span` for the leading `'` of the last lifetime. Used for + /// diagnostics to detect possible typo where `"` was meant. + last_lifetime: Option, } impl<'psess, 'src> StringReader<'psess, 'src> { @@ -130,6 +135,18 @@ impl<'psess, 'src> StringReader<'psess, 'src> { debug!("next_token: {:?}({:?})", token.kind, self.str_from(start)); + if let rustc_lexer::TokenKind::Semi + | rustc_lexer::TokenKind::LineComment { .. } + | rustc_lexer::TokenKind::BlockComment { .. } + | rustc_lexer::TokenKind::CloseParen + | rustc_lexer::TokenKind::CloseBrace + | rustc_lexer::TokenKind::CloseBracket = token.kind + { + // Heuristic: we assume that it is unlikely we're dealing with an unterminated + // string surrounded by single quotes. + self.last_lifetime = None; + } + // Now "cook" the token, converting the simple `rustc_lexer::TokenKind` enum into a // rich `rustc_ast::TokenKind`. This turns strings into interned symbols and runs // additional validation. @@ -247,6 +264,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { // expansion purposes. See #12512 for the gory details of why // this is necessary. let lifetime_name = self.str_from(start); + self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); if starts_with_number { let span = self.mk_sp(start, self.pos); self.dcx().struct_err("lifetimes cannot start with a number") @@ -395,10 +413,21 @@ impl<'psess, 'src> StringReader<'psess, 'src> { match kind { rustc_lexer::LiteralKind::Char { terminated } => { if !terminated { - self.dcx() + let mut err = self + .dcx() .struct_span_fatal(self.mk_sp(start, end), "unterminated character literal") - .with_code(E0762) - .emit() + .with_code(E0762); + if let Some(lt_sp) = self.last_lifetime { + err.multipart_suggestion( + "if you meant to write a `str` literal, use double quotes", + vec![ + (lt_sp, "\"".to_string()), + (self.mk_sp(start, start + BytePos(1)), "\"".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } + err.emit() } self.cook_unicode(token::Char, Mode::Char, start, end, 1, 1) // ' ' } @@ -673,7 +702,16 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let sugg = if prefix == "rb" { Some(errors::UnknownPrefixSugg::UseBr(prefix_span)) } else if expn_data.is_root() { - Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi())) + if self.cursor.first() == '\'' + && let Some(start) = self.last_lifetime + { + Some(errors::UnknownPrefixSugg::MeantStr { + start, + end: self.mk_sp(self.pos, self.pos + BytePos(1)), + }) + } else { + Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi())) + } } else { None }; diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed new file mode 100644 index 0000000000000..b12139b0b40e9 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed @@ -0,0 +1,6 @@ +//@ run-rustfix +fn main() { + println!("1 + 1"); + //~^ ERROR unterminated character literal + //~| ERROR lifetimes cannot start with a number +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs new file mode 100644 index 0000000000000..6548792f33b4f --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs @@ -0,0 +1,6 @@ +//@ run-rustfix +fn main() { + println!('1 + 1'); + //~^ ERROR unterminated character literal + //~| ERROR lifetimes cannot start with a number +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr new file mode 100644 index 0000000000000..675624cfa9415 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr @@ -0,0 +1,20 @@ +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-1.rs:3:20 + | +LL | println!('1 + 1'); + | ^^^ + | +help: if you meant to write a `str` literal, use double quotes + | +LL | println!("1 + 1"); + | ~ ~ + +error: lifetimes cannot start with a number + --> $DIR/lex-bad-str-literal-as-char-1.rs:3:14 + | +LL | println!('1 + 1'); + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0762`. diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed new file mode 100644 index 0000000000000..3ccec537c6c34 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!(" 1 + 1"); //~ ERROR character literal may only contain one codepoint +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs new file mode 100644 index 0000000000000..8af72e47dbb4b --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!(' 1 + 1'); //~ ERROR character literal may only contain one codepoint +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr new file mode 100644 index 0000000000000..8445d0595f3ed --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr @@ -0,0 +1,13 @@ +error: character literal may only contain one codepoint + --> $DIR/lex-bad-str-literal-as-char-2.rs:3:14 + | +LL | println!(' 1 + 1'); + | ^^^^^^^^ + | +help: if you meant to write a `str` literal, use double quotes + | +LL | println!(" 1 + 1"); + | ~~~~~~~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed new file mode 100644 index 0000000000000..3fbe0ea1dabef --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!("hello world"); //~ ERROR unterminated character literal +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs new file mode 100644 index 0000000000000..289f3f1d6570f --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs @@ -0,0 +1,4 @@ +//@ run-rustfix +fn main() { + println!('hello world'); //~ ERROR unterminated character literal +} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr new file mode 100644 index 0000000000000..ebfbeac02600b --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr @@ -0,0 +1,14 @@ +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-3.rs:3:26 + | +LL | println!('hello world'); + | ^^^^ + | +help: if you meant to write a `str` literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0762`. From 4a10b01f9504f8ad2ffb9b357845341f4fba6bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 9 Mar 2024 01:07:23 +0000 Subject: [PATCH 03/24] Use shorter span for existing `'` -> `"` structured suggestion --- compiler/rustc_infer/src/errors/mod.rs | 13 +++++------- .../src/infer/error_reporting/mod.rs | 14 ++++--------- compiler/rustc_parse/src/errors.rs | 11 +++++++++- .../src/lexer/unescape_error_reporting.rs | 20 ++++++++++++++----- tests/ui/inference/str-as-char.stderr | 4 ++-- tests/ui/issues/issue-23589.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-2.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-3.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-5.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-6.stderr | 6 +++--- .../lex-bad-str-literal-as-char-2.stderr | 2 +- tests/ui/parser/issues/issue-64732.stderr | 4 ++-- .../parser/unicode-character-literal.stderr | 4 ++-- tests/ui/str/str-as-char.stderr | 2 +- 14 files changed, 51 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index a3cf0d8e5208a..d0b1f2848ff3f 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1339,15 +1339,12 @@ pub enum TypeErrorAdditionalDiags { span: Span, code: String, }, - #[suggestion( - infer_meant_str_literal, - code = "\"{code}\"", - applicability = "machine-applicable" - )] + #[multipart_suggestion(infer_meant_str_literal, applicability = "machine-applicable")] MeantStrLiteral { - #[primary_span] - span: Span, - code: String, + #[suggestion_part(code = "\"")] + start: Span, + #[suggestion_part(code = "\"")] + end: Span, }, #[suggestion( infer_consider_specifying_length, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 5d2a95593cd25..4b104756b181f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2078,16 +2078,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // If a string was expected and the found expression is a character literal, // perhaps the user meant to write `"s"` to specify a string literal. (ty::Ref(_, r, _), ty::Char) if r.is_str() => { - if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { - if let Some(code) = - code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) - { - suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { - span, - code: escape_literal(code), - }) - } - } + suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { + start: span.with_hi(span.lo() + BytePos(1)), + end: span.with_lo(span.hi() - BytePos(1)), + }) } // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`, // we try to suggest to add the missing `let` for `if let Some(..) = expr` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 140eb6cd18752..d12818444fc5f 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2216,12 +2216,21 @@ pub enum MoreThanOneCharSugg { ch: String, }, #[suggestion(parse_use_double_quotes, code = "{sugg}", applicability = "machine-applicable")] - Quotes { + QuotesFull { #[primary_span] span: Span, is_byte: bool, sugg: String, }, + #[multipart_suggestion(parse_use_double_quotes, applicability = "machine-applicable")] + Quotes { + #[suggestion_part(code = "{prefix}\"")] + start: Span, + #[suggestion_part(code = "\"")] + end: Span, + is_byte: bool, + prefix: &'static str, + }, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 3ebad6a9fd73e..1ac6b6fe11566 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -95,11 +95,21 @@ pub(crate) fn emit_unescape_error( } escaped.push(c); } - let sugg = format!("{prefix}\"{escaped}\""); - MoreThanOneCharSugg::Quotes { - span: full_lit_span, - is_byte: mode == Mode::Byte, - sugg, + if escaped.len() != lit.len() { + let sugg = format!("{prefix}\"{escaped}\""); + MoreThanOneCharSugg::QuotesFull { + span: full_lit_span, + is_byte: mode == Mode::Byte, + sugg, + } + } else { + MoreThanOneCharSugg::Quotes { + start: full_lit_span + .with_hi(full_lit_span.lo() + BytePos((prefix.len() + 1) as u32)), + end: full_lit_span.with_lo(full_lit_span.hi() - BytePos(1)), + is_byte: mode == Mode::Byte, + prefix, + } } }); dcx.emit_err(UnescapeError::MoreThanOneChar { diff --git a/tests/ui/inference/str-as-char.stderr b/tests/ui/inference/str-as-char.stderr index 216f4cda69888..42302435c91bf 100644 --- a/tests/ui/inference/str-as-char.stderr +++ b/tests/ui/inference/str-as-char.stderr @@ -18,7 +18,7 @@ LL | let _: &str = '\"\"\"'; help: if you meant to write a `str` literal, use double quotes | LL | let _: &str = "\"\"\""; - | ~~~~~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/str-as-char.rs:10:19 @@ -42,7 +42,7 @@ LL | let _: &str = 'a'; help: if you meant to write a `str` literal, use double quotes | LL | let _: &str = "a"; - | ~~~ + | ~ ~ error: aborting due to 4 previous errors diff --git a/tests/ui/issues/issue-23589.stderr b/tests/ui/issues/issue-23589.stderr index 1a91f5e04dbce..bf055a7e31c59 100644 --- a/tests/ui/issues/issue-23589.stderr +++ b/tests/ui/issues/issue-23589.stderr @@ -18,7 +18,7 @@ LL | let v: Vec(&str) = vec!['1', '2']; help: if you meant to write a `str` literal, use double quotes | LL | let v: Vec(&str) = vec!["1", '2']; - | ~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/lexer/lex-bad-char-literals-2.stderr b/tests/ui/lexer/lex-bad-char-literals-2.stderr index 1518a37ab53f3..af64e6efe45ff 100644 --- a/tests/ui/lexer/lex-bad-char-literals-2.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-2.stderr @@ -7,7 +7,7 @@ LL | 'nope' help: if you meant to write a `str` literal, use double quotes | LL | "nope" - | ~~~~~~ + | ~ ~ error: aborting due to 1 previous error diff --git a/tests/ui/lexer/lex-bad-char-literals-3.stderr b/tests/ui/lexer/lex-bad-char-literals-3.stderr index 62a5e424cb469..312b42fc83174 100644 --- a/tests/ui/lexer/lex-bad-char-literals-3.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-3.stderr @@ -7,7 +7,7 @@ LL | static c: char = '●●'; help: if you meant to write a `str` literal, use double quotes | LL | static c: char = "●●"; - | ~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-3.rs:5:20 @@ -18,7 +18,7 @@ LL | let ch: &str = '●●'; help: if you meant to write a `str` literal, use double quotes | LL | let ch: &str = "●●"; - | ~~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/lexer/lex-bad-char-literals-5.stderr b/tests/ui/lexer/lex-bad-char-literals-5.stderr index 184817a6579d0..185f460b10def 100644 --- a/tests/ui/lexer/lex-bad-char-literals-5.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-5.stderr @@ -7,7 +7,7 @@ LL | static c: char = '\x10\x10'; help: if you meant to write a `str` literal, use double quotes | LL | static c: char = "\x10\x10"; - | ~~~~~~~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-5.rs:5:20 @@ -18,7 +18,7 @@ LL | let ch: &str = '\x10\x10'; help: if you meant to write a `str` literal, use double quotes | LL | let ch: &str = "\x10\x10"; - | ~~~~~~~~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/lexer/lex-bad-char-literals-6.stderr b/tests/ui/lexer/lex-bad-char-literals-6.stderr index 2fe30304a50d6..f49e5a095b34a 100644 --- a/tests/ui/lexer/lex-bad-char-literals-6.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-6.stderr @@ -7,7 +7,7 @@ LL | let x: &str = 'ab'; help: if you meant to write a `str` literal, use double quotes | LL | let x: &str = "ab"; - | ~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-6.rs:4:19 @@ -18,7 +18,7 @@ LL | let y: char = 'cd'; help: if you meant to write a `str` literal, use double quotes | LL | let y: char = "cd"; - | ~~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-6.rs:6:13 @@ -29,7 +29,7 @@ LL | let z = 'ef'; help: if you meant to write a `str` literal, use double quotes | LL | let z = "ef"; - | ~~~~ + | ~ ~ error[E0308]: mismatched types --> $DIR/lex-bad-char-literals-6.rs:13:20 diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr index 8445d0595f3ed..06b38522ad2dd 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr @@ -7,7 +7,7 @@ LL | println!(' 1 + 1'); help: if you meant to write a `str` literal, use double quotes | LL | println!(" 1 + 1"); - | ~~~~~~~~ + | ~ ~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-64732.stderr b/tests/ui/parser/issues/issue-64732.stderr index 8046254937763..8893fa8aae239 100644 --- a/tests/ui/parser/issues/issue-64732.stderr +++ b/tests/ui/parser/issues/issue-64732.stderr @@ -7,7 +7,7 @@ LL | let _foo = b'hello\0'; help: if you meant to write a byte string literal, use double quotes | LL | let _foo = b"hello\0"; - | ~~~~~~~~~~ + | ~~ ~ error: character literal may only contain one codepoint --> $DIR/issue-64732.rs:6:16 @@ -18,7 +18,7 @@ LL | let _bar = 'hello'; help: if you meant to write a `str` literal, use double quotes | LL | let _bar = "hello"; - | ~~~~~~~ + | ~ ~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/unicode-character-literal.stderr b/tests/ui/parser/unicode-character-literal.stderr index 5cd3bd0fe69d7..1104eaeb8d478 100644 --- a/tests/ui/parser/unicode-character-literal.stderr +++ b/tests/ui/parser/unicode-character-literal.stderr @@ -12,7 +12,7 @@ LL | let _spade = '♠️'; help: if you meant to write a `str` literal, use double quotes | LL | let _spade = "♠️"; - | ~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/unicode-character-literal.rs:12:14 @@ -28,7 +28,7 @@ LL | let _s = 'ṩ̂̊'; help: if you meant to write a `str` literal, use double quotes | LL | let _s = "ṩ̂̊"; - | ~~~ + | ~ ~ error: character literal may only contain one codepoint --> $DIR/unicode-character-literal.rs:17:14 diff --git a/tests/ui/str/str-as-char.stderr b/tests/ui/str/str-as-char.stderr index 44ec079e92918..03b2309a3171a 100644 --- a/tests/ui/str/str-as-char.stderr +++ b/tests/ui/str/str-as-char.stderr @@ -7,7 +7,7 @@ LL | println!('●●'); help: if you meant to write a `str` literal, use double quotes | LL | println!("●●"); - | ~~~~ + | ~ ~ error: aborting due to 1 previous error From 999a0dc300b7f95eb7d83666514c4ceae76020f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Mar 2024 23:52:04 +0000 Subject: [PATCH 04/24] review comment: `str` -> string in messages --- compiler/rustc_infer/messages.ftl | 2 +- compiler/rustc_parse/messages.ftl | 4 ++-- compiler/rustc_parse/src/lexer/mod.rs | 2 +- tests/ui/inference/str-as-char.stderr | 8 ++++---- tests/ui/issues/issue-23589.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-2.stderr | 2 +- tests/ui/lexer/lex-bad-char-literals-3.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-5.stderr | 4 ++-- tests/ui/lexer/lex-bad-char-literals-6.stderr | 6 +++--- tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr | 2 +- tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr | 2 +- tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr | 2 +- tests/ui/parser/issues/issue-64732.rs | 2 +- tests/ui/parser/issues/issue-64732.stderr | 2 +- tests/ui/parser/unicode-character-literal.fixed | 4 ++-- tests/ui/parser/unicode-character-literal.rs | 4 ++-- tests/ui/parser/unicode-character-literal.stderr | 4 ++-- tests/ui/str/str-as-char.stderr | 2 +- 18 files changed, 29 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index e44a6ae3b3f2e..521c65c600918 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -169,7 +169,7 @@ infer_lifetime_param_suggestion_elided = each elided lifetime in input position infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b` infer_meant_char_literal = if you meant to write a `char` literal, use single quotes -infer_meant_str_literal = if you meant to write a `str` literal, use double quotes +infer_meant_str_literal = if you meant to write a string literal, use double quotes infer_mismatched_static_lifetime = incompatible lifetime on type infer_more_targeted = {$has_param_name -> [true] `{$param_name}` diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 888c621f02afd..7f828c0274361 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -570,7 +570,7 @@ parse_more_than_one_char = character literal may only contain one codepoint .remove_non = consider removing the non-printing characters .use_double_quotes = if you meant to write a {$is_byte -> [true] byte string - *[false] `str` + *[false] string } literal, use double quotes parse_multiple_skipped_lines = multiple lines skipped by escaped newline @@ -835,7 +835,7 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown .label = unknown prefix .note = prefixed identifiers and literals are reserved since Rust 2021 .suggestion_br = use `br` for a raw byte string - .suggestion_str = if you meant to write a `str` literal, use double quotes + .suggestion_str = if you meant to write a string literal, use double quotes .suggestion_whitespace = consider inserting whitespace here parse_unknown_start_of_token = unknown start of token: {$escaped} diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 659e0b63d2ed8..5583e49ba6011 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -419,7 +419,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { .with_code(E0762); if let Some(lt_sp) = self.last_lifetime { err.multipart_suggestion( - "if you meant to write a `str` literal, use double quotes", + "if you meant to write a string literal, use double quotes", vec![ (lt_sp, "\"".to_string()), (self.mk_sp(start, start + BytePos(1)), "\"".to_string()), diff --git a/tests/ui/inference/str-as-char.stderr b/tests/ui/inference/str-as-char.stderr index 42302435c91bf..4ca71c5f067fd 100644 --- a/tests/ui/inference/str-as-char.stderr +++ b/tests/ui/inference/str-as-char.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | let _: &str = '"""'; | ^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "\"\"\""; | ~~~~~~~~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let _: &str = '\"\"\"'; | ^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "\"\"\""; | ~ ~ @@ -26,7 +26,7 @@ error: character literal may only contain one codepoint LL | let _: &str = '"\"\"\\"\\"'; | ^^^^^^^^^^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "\"\"\\"\\"\\\""; | ~~~~~~~~~~~~~~~~~~~~ @@ -39,7 +39,7 @@ LL | let _: &str = 'a'; | | | expected due to this | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _: &str = "a"; | ~ ~ diff --git a/tests/ui/issues/issue-23589.stderr b/tests/ui/issues/issue-23589.stderr index bf055a7e31c59..21d383b0e8ce2 100644 --- a/tests/ui/issues/issue-23589.stderr +++ b/tests/ui/issues/issue-23589.stderr @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | let v: Vec(&str) = vec!['1', '2']; | ^^^ expected `&str`, found `char` | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let v: Vec(&str) = vec!["1", '2']; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-2.stderr b/tests/ui/lexer/lex-bad-char-literals-2.stderr index af64e6efe45ff..76cde00404a15 100644 --- a/tests/ui/lexer/lex-bad-char-literals-2.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-2.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | 'nope' | ^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | "nope" | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-3.stderr b/tests/ui/lexer/lex-bad-char-literals-3.stderr index 312b42fc83174..3f339b2ef7d93 100644 --- a/tests/ui/lexer/lex-bad-char-literals-3.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-3.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | static c: char = '●●'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | static c: char = "●●"; | ~ ~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let ch: &str = '●●'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let ch: &str = "●●"; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-5.stderr b/tests/ui/lexer/lex-bad-char-literals-5.stderr index 185f460b10def..8004157e87f7a 100644 --- a/tests/ui/lexer/lex-bad-char-literals-5.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-5.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | static c: char = '\x10\x10'; | ^^^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | static c: char = "\x10\x10"; | ~ ~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let ch: &str = '\x10\x10'; | ^^^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let ch: &str = "\x10\x10"; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-char-literals-6.stderr b/tests/ui/lexer/lex-bad-char-literals-6.stderr index f49e5a095b34a..96d409d59bb25 100644 --- a/tests/ui/lexer/lex-bad-char-literals-6.stderr +++ b/tests/ui/lexer/lex-bad-char-literals-6.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | let x: &str = 'ab'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let x: &str = "ab"; | ~ ~ @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let y: char = 'cd'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let y: char = "cd"; | ~ ~ @@ -26,7 +26,7 @@ error: character literal may only contain one codepoint LL | let z = 'ef'; | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let z = "ef"; | ~ ~ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr index 675624cfa9415..57c5f82704ec7 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr @@ -4,7 +4,7 @@ error[E0762]: unterminated character literal LL | println!('1 + 1'); | ^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!("1 + 1"); | ~ ~ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr index 06b38522ad2dd..f64761af64193 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | println!(' 1 + 1'); | ^^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!(" 1 + 1"); | ~ ~ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr index ebfbeac02600b..262f78569839d 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr @@ -4,7 +4,7 @@ error[E0762]: unterminated character literal LL | println!('hello world'); | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!("hello world"); | ~ ~ diff --git a/tests/ui/parser/issues/issue-64732.rs b/tests/ui/parser/issues/issue-64732.rs index 2db51ea6042aa..ff0f97ea211dc 100644 --- a/tests/ui/parser/issues/issue-64732.rs +++ b/tests/ui/parser/issues/issue-64732.rs @@ -5,5 +5,5 @@ fn main() { //~| HELP if you meant to write a byte string literal, use double quotes let _bar = 'hello'; //~^ ERROR character literal may only contain one codepoint - //~| HELP if you meant to write a `str` literal, use double quotes + //~| HELP if you meant to write a string literal, use double quotes } diff --git a/tests/ui/parser/issues/issue-64732.stderr b/tests/ui/parser/issues/issue-64732.stderr index 8893fa8aae239..7ec2df6d3bf7e 100644 --- a/tests/ui/parser/issues/issue-64732.stderr +++ b/tests/ui/parser/issues/issue-64732.stderr @@ -15,7 +15,7 @@ error: character literal may only contain one codepoint LL | let _bar = 'hello'; | ^^^^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _bar = "hello"; | ~ ~ diff --git a/tests/ui/parser/unicode-character-literal.fixed b/tests/ui/parser/unicode-character-literal.fixed index 9e31890151cc1..e401ecaf5da77 100644 --- a/tests/ui/parser/unicode-character-literal.fixed +++ b/tests/ui/parser/unicode-character-literal.fixed @@ -7,12 +7,12 @@ fn main() { let _spade = "♠️"; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `♠` is followed by the combining mark `\u{fe0f}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _s = "ṩ̂̊"; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _a = 'Å'; //~^ ERROR: character literal may only contain one codepoint diff --git a/tests/ui/parser/unicode-character-literal.rs b/tests/ui/parser/unicode-character-literal.rs index d886e5b26a56b..428e4e1ac5a08 100644 --- a/tests/ui/parser/unicode-character-literal.rs +++ b/tests/ui/parser/unicode-character-literal.rs @@ -7,12 +7,12 @@ fn main() { let _spade = '♠️'; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `♠` is followed by the combining mark `\u{fe0f}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _s = 'ṩ̂̊'; //~^ ERROR: character literal may only contain one codepoint //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` - //~| HELP: if you meant to write a `str` literal, use double quotes + //~| HELP: if you meant to write a string literal, use double quotes let _a = 'Å'; //~^ ERROR: character literal may only contain one codepoint diff --git a/tests/ui/parser/unicode-character-literal.stderr b/tests/ui/parser/unicode-character-literal.stderr index 1104eaeb8d478..726cde2b413e2 100644 --- a/tests/ui/parser/unicode-character-literal.stderr +++ b/tests/ui/parser/unicode-character-literal.stderr @@ -9,7 +9,7 @@ note: this `♠` is followed by the combining mark `\u{fe0f}` | LL | let _spade = '♠️'; | ^ -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _spade = "♠️"; | ~ ~ @@ -25,7 +25,7 @@ note: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}` | LL | let _s = 'ṩ̂̊'; | ^ -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | let _s = "ṩ̂̊"; | ~ ~ diff --git a/tests/ui/str/str-as-char.stderr b/tests/ui/str/str-as-char.stderr index 03b2309a3171a..0638d371c173b 100644 --- a/tests/ui/str/str-as-char.stderr +++ b/tests/ui/str/str-as-char.stderr @@ -4,7 +4,7 @@ error: character literal may only contain one codepoint LL | println!('●●'); | ^^^^ | -help: if you meant to write a `str` literal, use double quotes +help: if you meant to write a string literal, use double quotes | LL | println!("●●"); | ~ ~ From 6f388ef1fb3964fb83bae5c277f9c83bbde4c76b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Mar 2024 00:22:52 +0000 Subject: [PATCH 05/24] Extend test to trigger on 2015, 2018 and 2021 editions --- .../lexer/lex-bad-str-literal-as-char-3.fixed | 4 --- .../ui/lexer/lex-bad-str-literal-as-char-3.rs | 8 ++++-- ...bad-str-literal-as-char-3.rust2015.stderr} | 4 +-- ...-bad-str-literal-as-char-3.rust2018.stderr | 14 ++++++++++ ...-bad-str-literal-as-char-3.rust2021.stderr | 26 +++++++++++++++++++ 5 files changed, 48 insertions(+), 8 deletions(-) delete mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed rename tests/ui/lexer/{lex-bad-str-literal-as-char-3.stderr => lex-bad-str-literal-as-char-3.rust2015.stderr} (79%) create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr create mode 100644 tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed deleted file mode 100644 index 3fbe0ea1dabef..0000000000000 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.fixed +++ /dev/null @@ -1,4 +0,0 @@ -//@ run-rustfix -fn main() { - println!("hello world"); //~ ERROR unterminated character literal -} diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs index 289f3f1d6570f..2c0eda97853b0 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs @@ -1,4 +1,8 @@ -//@ run-rustfix +//@ revisions: rust2015 rust2018 rust2021 +//@[rust2018] edition:2018 +//@[rust2021] edition:2021 fn main() { - println!('hello world'); //~ ERROR unterminated character literal + println!('hello world'); + //[rust2015,rust2018,rust2021]~^ ERROR unterminated character literal + //[rust2021]~^^ ERROR prefix `world` is unknown } diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr similarity index 79% rename from tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr rename to tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr index 262f78569839d..06f127426679f 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr @@ -1,8 +1,8 @@ error[E0762]: unterminated character literal - --> $DIR/lex-bad-str-literal-as-char-3.rs:3:26 + --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 | LL | println!('hello world'); - | ^^^^ + | ^^^ | help: if you meant to write a string literal, use double quotes | diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr new file mode 100644 index 0000000000000..06f127426679f --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr @@ -0,0 +1,14 @@ +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 + | +LL | println!('hello world'); + | ^^^ + | +help: if you meant to write a string literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0762`. diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr new file mode 100644 index 0000000000000..4170560cfcb04 --- /dev/null +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr @@ -0,0 +1,26 @@ +error: prefix `world` is unknown + --> $DIR/lex-bad-str-literal-as-char-3.rs:5:21 + | +LL | println!('hello world'); + | ^^^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: if you meant to write a string literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error[E0762]: unterminated character literal + --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 + | +LL | println!('hello world'); + | ^^^ + | +help: if you meant to write a string literal, use double quotes + | +LL | println!("hello world"); + | ~ ~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0762`. From ea1883d7b2207d1a0f08046f11ca493803bc8a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Mar 2024 00:40:25 +0000 Subject: [PATCH 06/24] Silence redundant error on char literal that was meant to be a string in 2021 edition --- compiler/rustc_lexer/src/cursor.rs | 9 +++++++++ compiler/rustc_parse/src/lexer/mod.rs | 11 ++++++++++- tests/ui/lexer/lex-bad-str-literal-as-char-3.rs | 1 - .../lex-bad-str-literal-as-char-3.rust2021.stderr | 14 +------------- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs index 8d8cc9ecc3e9f..d173c3ac0327b 100644 --- a/compiler/rustc_lexer/src/cursor.rs +++ b/compiler/rustc_lexer/src/cursor.rs @@ -59,6 +59,15 @@ impl<'a> Cursor<'a> { iter.next().unwrap_or(EOF_CHAR) } + /// Peeks the third symbol from the input stream without consuming it. + pub fn third(&self) -> char { + // `.next()` optimizes better than `.nth(1)` + let mut iter = self.chars.clone(); + iter.next(); + iter.next(); + iter.next().unwrap_or(EOF_CHAR) + } + /// Checks if there is nothing more to consume. pub(crate) fn is_eof(&self) -> bool { self.chars.as_str().is_empty() diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 5583e49ba6011..63b2b47630b29 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -698,13 +698,17 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let expn_data = prefix_span.ctxt().outer_expn_data(); if expn_data.edition >= Edition::Edition2021 { + let mut silence = false; // In Rust 2021, this is a hard error. let sugg = if prefix == "rb" { Some(errors::UnknownPrefixSugg::UseBr(prefix_span)) } else if expn_data.is_root() { if self.cursor.first() == '\'' && let Some(start) = self.last_lifetime + && self.cursor.third() != '\'' { + // An "unclosed `char`" error will be emitted already, silence redundant error. + silence = true; Some(errors::UnknownPrefixSugg::MeantStr { start, end: self.mk_sp(self.pos, self.pos + BytePos(1)), @@ -715,7 +719,12 @@ impl<'psess, 'src> StringReader<'psess, 'src> { } else { None }; - self.dcx().emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg }); + let err = errors::UnknownPrefix { span: prefix_span, prefix, sugg }; + if silence { + self.dcx().create_err(err).delay_as_bug(); + } else { + self.dcx().emit_err(err); + } } else { // Before Rust 2021, only emit a lint for migration. self.psess.buffer_lint_with_diagnostic( diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs index 2c0eda97853b0..0ae227da5f1e6 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs @@ -4,5 +4,4 @@ fn main() { println!('hello world'); //[rust2015,rust2018,rust2021]~^ ERROR unterminated character literal - //[rust2021]~^^ ERROR prefix `world` is unknown } diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr index 4170560cfcb04..06f127426679f 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr @@ -1,15 +1,3 @@ -error: prefix `world` is unknown - --> $DIR/lex-bad-str-literal-as-char-3.rs:5:21 - | -LL | println!('hello world'); - | ^^^^^ unknown prefix - | - = note: prefixed identifiers and literals are reserved since Rust 2021 -help: if you meant to write a string literal, use double quotes - | -LL | println!("hello world"); - | ~ ~ - error[E0762]: unterminated character literal --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 | @@ -21,6 +9,6 @@ help: if you meant to write a string literal, use double quotes LL | println!("hello world"); | ~ ~ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0762`. From f4d30b156b2958ba01b59a1751e16b5f6e157fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 17 Mar 2024 23:46:39 +0000 Subject: [PATCH 07/24] fix rustdoc test --- compiler/rustc_parse/src/lexer/unescape_error_reporting.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 1ac6b6fe11566..fa242a32a1814 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -95,7 +95,7 @@ pub(crate) fn emit_unescape_error( } escaped.push(c); } - if escaped.len() != lit.len() { + if escaped.len() != lit.len() || full_lit_span.is_empty() { let sugg = format!("{prefix}\"{escaped}\""); MoreThanOneCharSugg::QuotesFull { span: full_lit_span, From f4adb1e6bdaef12d8b5776f74dadab0ddc11694d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Mar 2024 21:29:21 +0100 Subject: [PATCH 08/24] add notes on how to store 'ptr or int' --- library/core/src/intrinsics.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index ce498561eeb12..27ed26fdcf16d 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1186,7 +1186,7 @@ extern "rust-intrinsic" { /// /// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless /// the pointer was originally created *from* an integer. (That includes this function - /// specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::dangling], + /// specifically, integer-to-pointer casts, and helpers like [`dangling`][crate::ptr::dangling], /// but also semantically-equivalent conversions such as punning through `repr(C)` union /// fields.) Any attempt to use the resulting value for integer operations will abort /// const-evaluation. (And even outside `const`, such transmutation is touching on many @@ -1206,7 +1206,11 @@ extern "rust-intrinsic" { /// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a /// lossless process. If you want to round-trip a pointer through an integer in a way that you /// can get back the original pointer, you need to use `as` casts, or replace the integer type - /// by `MaybeUninit<$int>` (and never call `assume_init()`). + /// by `MaybeUninit<$int>` (and never call `assume_init()`). If you are looking for a way to + /// store data of arbitrary type, also use `MaybeUninit` (that will also handle uninitialized + /// memory due to padding). If you specifically need to store something that is "either an + /// integer or a pointer", use `*mut ()`: integers can be converted to pointers and back without + /// any loss (via `as` casts or via `transmute`). /// /// # Examples /// From 2624e9183d8f3587bac325d6f7a9777c36f2f45b Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Thu, 21 Sep 2023 00:06:22 +0000 Subject: [PATCH 09/24] Soft-destabilize `RustcEncodable`/`RustcDecodable` --- library/core/src/macros/mod.rs | 20 +++++++++++++------ library/core/src/prelude/v1.rs | 7 ++++++- library/std/src/prelude/v1.rs | 7 ++++++- .../pretty-expanded/input.rs | 16 ++++++--------- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index a78842c8f8d68..574a357b44abb 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1726,20 +1726,28 @@ pub(crate) mod builtin { builtin # deref($pat) } - /// Unstable implementation detail of the `rustc` compiler, do not use. + /// Derive macro for `rustc-serialize`. Should not be used in new code. #[rustc_builtin_macro] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics, libstd_sys_internals, rt)] + #[unstable( + feature = "rustc_encodable_decodable", + issue = "none", + soft, + reason = "derive macro for `rustc-serialize`; should not be used in new code" + )] #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. pub macro RustcDecodable($item:item) { /* compiler built-in */ } - /// Unstable implementation detail of the `rustc` compiler, do not use. + /// Derive macro for `rustc-serialize`. Should not be used in new code. #[rustc_builtin_macro] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics, rt)] + #[unstable( + feature = "rustc_encodable_decodable", + issue = "none", + soft, + reason = "derive macro for `rustc-serialize`; should not be used in new code" + )] #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. pub macro RustcEncodable($item:item) { diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 29f73bb4942aa..698aaa6bbcfd4 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -69,7 +69,12 @@ pub use crate::{ pub use crate::concat_bytes; // Do not `doc(inline)` these `doc(hidden)` items. -#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[unstable( + feature = "rustc_encodable_decodable", + issue = "none", + soft, + reason = "unstable implementation detail of the `rustc` compiler, do not use" +)] #[allow(deprecated)] pub use crate::macros::builtin::{RustcDecodable, RustcEncodable}; diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 36fa4e88b5bde..0559f34c1b4c7 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -53,7 +53,12 @@ pub use core::prelude::v1::{ pub use core::prelude::v1::concat_bytes; // Do not `doc(inline)` these `doc(hidden)` items. -#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] +#[unstable( + feature = "rustc_encodable_decodable", + issue = "none", + soft, + reason = "unstable implementation detail of the `rustc` compiler, do not use" +)] #[allow(deprecated)] pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; diff --git a/tests/run-make-fulldeps/pretty-expanded/input.rs b/tests/run-make-fulldeps/pretty-expanded/input.rs index af3d75b3bf216..02b235068a1d2 100644 --- a/tests/run-make-fulldeps/pretty-expanded/input.rs +++ b/tests/run-make-fulldeps/pretty-expanded/input.rs @@ -1,12 +1,8 @@ -#[crate_type="lib"] - // #13544 -extern crate rustc_serialize; - -#[derive(RustcEncodable)] pub struct A; -#[derive(RustcEncodable)] pub struct B(isize); -#[derive(RustcEncodable)] pub struct C { x: isize } -#[derive(RustcEncodable)] pub enum D {} -#[derive(RustcEncodable)] pub enum E { y } -#[derive(RustcEncodable)] pub enum F { z(isize) } +#[derive(Debug)] pub struct A; +#[derive(Debug)] pub struct B(isize); +#[derive(Debug)] pub struct C { x: isize } +#[derive(Debug)] pub enum D {} +#[derive(Debug)] pub enum E { y } +#[derive(Debug)] pub enum F { z(isize) } From fbf21c5763430d7acdfe9843d8bc7fc2253be334 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Thu, 21 Sep 2023 00:56:59 +0000 Subject: [PATCH 10/24] Remove RustcEncodable/Decodable from 2024 prelude --- library/core/src/prelude/{v1.rs => common.rs} | 14 +--- library/core/src/prelude/mod.rs | 34 ++++++++-- library/std/src/prelude/{v1.rs => common.rs} | 14 +--- library/std/src/prelude/mod.rs | 26 ++++++-- .../feature-gate-rustc_encodable_decodable.rs | 16 +++++ ...ture-gate-rustc_encodable_decodable.stderr | 66 +++++++++++++++++++ 6 files changed, 136 insertions(+), 34 deletions(-) rename library/core/src/prelude/{v1.rs => common.rs} (89%) rename library/std/src/prelude/{v1.rs => common.rs} (89%) create mode 100644 tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs create mode 100644 tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/common.rs similarity index 89% rename from library/core/src/prelude/v1.rs rename to library/core/src/prelude/common.rs index 698aaa6bbcfd4..b98f3a4659b10 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/common.rs @@ -1,9 +1,7 @@ -//! The first version of the core prelude. +//! Items common to the prelude of all editions. //! //! See the [module-level documentation](super) for more. -#![stable(feature = "core_prelude", since = "1.4.0")] - // Re-exported core operators #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] @@ -68,16 +66,6 @@ pub use crate::{ #[doc(no_inline)] pub use crate::concat_bytes; -// Do not `doc(inline)` these `doc(hidden)` items. -#[unstable( - feature = "rustc_encodable_decodable", - issue = "none", - soft, - reason = "unstable implementation detail of the `rustc` compiler, do not use" -)] -#[allow(deprecated)] -pub use crate::macros::builtin::{RustcDecodable, RustcEncodable}; - // Do not `doc(no_inline)` so that they become doc items on their own // (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index b4791c2c022ec..ca33ef160e88b 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -6,7 +6,26 @@ #![stable(feature = "core_prelude", since = "1.4.0")] -pub mod v1; +mod common; + +/// The first version of the prelude of The Rust Standard Library. +/// +/// See the [module-level documentation](self) for more. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod v1 { + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::common::*; + + // Do not `doc(inline)` these `doc(hidden)` items. + #[unstable( + feature = "rustc_encodable_decodable", + issue = "none", + soft, + reason = "derive macro for `rustc-serialize`; should not be used in new code" + )] + #[allow(deprecated)] + pub use crate::macros::builtin::{RustcDecodable, RustcEncodable}; +} /// The 2015 version of the core prelude. /// @@ -46,14 +65,21 @@ pub mod rust_2021 { pub use crate::convert::{TryFrom, TryInto}; } -/// The 2024 edition of the core prelude. +/// The 2024 version of the core prelude. /// /// See the [module-level documentation](self) for more. #[unstable(feature = "prelude_2024", issue = "121042")] pub mod rust_2024 { - #[unstable(feature = "prelude_2024", issue = "121042")] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::common::*; + + #[stable(feature = "prelude_2021", since = "1.55.0")] + #[doc(no_inline)] + pub use crate::iter::FromIterator; + + #[stable(feature = "prelude_2021", since = "1.55.0")] #[doc(no_inline)] - pub use super::rust_2021::*; + pub use crate::convert::{TryFrom, TryInto}; #[unstable(feature = "prelude_2024", issue = "121042")] #[doc(no_inline)] diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/common.rs similarity index 89% rename from library/std/src/prelude/v1.rs rename to library/std/src/prelude/common.rs index 0559f34c1b4c7..f61e04e02b666 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/common.rs @@ -1,9 +1,7 @@ -//! The first version of the prelude of The Rust Standard Library. +//! Items common to the prelude of all editions. //! //! See the [module-level documentation](super) for more. -#![stable(feature = "rust1", since = "1.0.0")] - // Re-exported core operators #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] @@ -52,16 +50,6 @@ pub use core::prelude::v1::{ #[doc(no_inline)] pub use core::prelude::v1::concat_bytes; -// Do not `doc(inline)` these `doc(hidden)` items. -#[unstable( - feature = "rustc_encodable_decodable", - issue = "none", - soft, - reason = "unstable implementation detail of the `rustc` compiler, do not use" -)] -#[allow(deprecated)] -pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; - // Do not `doc(no_inline)` so that they become doc items on their own // (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 7d44d2e4b5da9..0bdbab716adb4 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -93,7 +93,26 @@ #![stable(feature = "rust1", since = "1.0.0")] -pub mod v1; +mod common; + +/// The first version of the prelude of The Rust Standard Library. +/// +/// See the [module-level documentation](self) for more. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod v1 { + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::common::*; + + // Do not `doc(inline)` these `doc(hidden)` items. + #[unstable( + feature = "rustc_encodable_decodable", + issue = "none", + soft, + reason = "derive macro for `rustc-serialize`; should not be used in new code" + )] + #[allow(deprecated)] + pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; +} /// The 2015 version of the prelude of The Rust Standard Library. /// @@ -134,9 +153,8 @@ pub mod rust_2021 { /// See the [module-level documentation](self) for more. #[unstable(feature = "prelude_2024", issue = "121042")] pub mod rust_2024 { - #[unstable(feature = "prelude_2024", issue = "121042")] - #[doc(no_inline)] - pub use super::v1::*; + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::common::*; #[unstable(feature = "prelude_2024", issue = "121042")] #[doc(no_inline)] diff --git a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs new file mode 100644 index 0000000000000..13f8fd5fe22a0 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs @@ -0,0 +1,16 @@ +#![crate_type = "lib"] + +// This isn't intended to compile, so it's easiest to just ignore this error. +extern crate rustc_serialize; //~ERROR can't find crate for `rustc_serialize` + +#[derive( + RustcEncodable, + //~^ ERROR use of unstable library feature 'rustc_encodable_decodable' + //~^^ WARNING this was previously accepted by the compiler + //~^^^ WARNING use of deprecated macro `RustcEncodable` + RustcDecodable, + //~^ ERROR use of unstable library feature 'rustc_encodable_decodable' + //~^^ WARNING this was previously accepted by the compiler + //~^^^ WARNING use of deprecated macro `RustcDecodable` +)] +struct S; diff --git a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr new file mode 100644 index 0000000000000..02b74dacf4dac --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr @@ -0,0 +1,66 @@ +error[E0463]: can't find crate for `rustc_serialize` + --> $DIR/feature-gate-rustc_encodable_decodable.rs:4:1 + | +LL | extern crate rustc_serialize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate + | + = help: maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview` + +error: use of unstable library feature 'rustc_encodable_decodable': derive macro for `rustc-serialize`; should not be used in new code + --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5 + | +LL | RustcEncodable, + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 + = note: `#[deny(soft_unstable)]` on by default + +warning: use of deprecated macro `RustcEncodable`: rustc-serialize is deprecated and no longer supported + --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5 + | +LL | RustcEncodable, + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +error: use of unstable library feature 'rustc_encodable_decodable': derive macro for `rustc-serialize`; should not be used in new code + --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5 + | +LL | RustcDecodable, + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 + +warning: use of deprecated macro `RustcDecodable`: rustc-serialize is deprecated and no longer supported + --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5 + | +LL | RustcDecodable, + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0463`. +Future incompatibility report: Future breakage diagnostic: +error: use of unstable library feature 'rustc_encodable_decodable': derive macro for `rustc-serialize`; should not be used in new code + --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5 + | +LL | RustcEncodable, + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 + = note: `#[deny(soft_unstable)]` on by default + +Future breakage diagnostic: +error: use of unstable library feature 'rustc_encodable_decodable': derive macro for `rustc-serialize`; should not be used in new code + --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5 + | +LL | RustcDecodable, + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 + = note: `#[deny(soft_unstable)]` on by default + From 1fcf2eaa9f5ff9336e9b43f017eaf261acfdc2d3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 22 Mar 2024 16:35:44 -0400 Subject: [PATCH 11/24] Uniquify ReError on input mode in canonicalizer --- .../src/canonicalizer.rs | 3 +- .../next-solver/dont-canonicalize-re-error.rs | 28 +++++++++++++++++++ .../dont-canonicalize-re-error.stderr | 21 ++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 tests/ui/traits/next-solver/dont-canonicalize-re-error.rs create mode 100644 tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 95b3006666202..2dbb44bdee207 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -239,7 +239,7 @@ impl, I: Interner> TypeFolder // FIXME: We should investigate the perf implications of not uniquifying // `ReErased`. We may be able to short-circuit registering region // obligations if we encounter a `ReErased` on one side, for example. - ty::ReStatic | ty::ReErased => match self.canonicalize_mode { + ty::ReStatic | ty::ReErased | ty::ReError(_) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Response { .. } => return r, }, @@ -277,7 +277,6 @@ impl, I: Interner> TypeFolder } } } - ty::ReError(_) => return r, }; let existing_bound_var = match self.canonicalize_mode { diff --git a/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs b/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs new file mode 100644 index 0000000000000..57f814bc81ec2 --- /dev/null +++ b/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Znext-solver + +trait Tr<'a> {} + +// Fulfillment in the new solver relies on an invariant to hold: Either +// `has_changed` is true, or computing a goal's certainty is idempotent. +// This isn't true for `ReError`, which we used to pass through in the +// canonicalizer even on input mode, which can cause a goal to go from +// ambig => pass, but we don't consider `has_changed` when the response +// only contains region constraints (since we usually uniquify regions). +// +// In this test: +// Implicit negative coherence tries to prove `W: Constrain<'?1>`, +// which will then match with the impl below. This constrains `'?1` to +// `ReError`, but still bails w/ ambiguity bc we can't prove `?0: Sized`. +// Then, when we recompute the goal `W: Constrain<'error>`, when +// collecting ambiguities and overflows, we end up assembling a default +// error candidate w/o ambiguity, which causes the goal to pass, and ICE. +impl<'a, A: ?Sized> Tr<'a> for W {} +struct W(A); +impl<'a, A: ?Sized> Tr<'a> for A where A: Constrain<'a> {} +//~^ ERROR conflicting implementations of trait `Tr<'_>` for type `W<_>` + +trait Constrain<'a> {} +impl Constrain<'missing> for W {} +//~^ ERROR use of undeclared lifetime name `'missing` + +fn main() {} diff --git a/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr b/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr new file mode 100644 index 0000000000000..cf85c52fb42ee --- /dev/null +++ b/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr @@ -0,0 +1,21 @@ +error[E0261]: use of undeclared lifetime name `'missing` + --> $DIR/dont-canonicalize-re-error.rs:25:26 + | +LL | impl Constrain<'missing> for W {} + | - ^^^^^^^^ undeclared lifetime + | | + | help: consider introducing lifetime `'missing` here: `'missing,` + +error[E0119]: conflicting implementations of trait `Tr<'_>` for type `W<_>` + --> $DIR/dont-canonicalize-re-error.rs:21:1 + | +LL | impl<'a, A: ?Sized> Tr<'a> for W {} + | ----------------------------------- first implementation here +LL | struct W(A); +LL | impl<'a, A: ?Sized> Tr<'a> for A where A: Constrain<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0119, E0261. +For more information about an error, try `rustc --explain E0119`. From da8a39a9de150f6b63a0601b4295e4b5a4f74e12 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 8 Mar 2024 01:34:05 +0000 Subject: [PATCH 12/24] Failing test --- tests/mir-opt/inline_coroutine_body.rs | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/mir-opt/inline_coroutine_body.rs diff --git a/tests/mir-opt/inline_coroutine_body.rs b/tests/mir-opt/inline_coroutine_body.rs new file mode 100644 index 0000000000000..5c305c5510042 --- /dev/null +++ b/tests/mir-opt/inline_coroutine_body.rs @@ -0,0 +1,28 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// skip-filecheck +//@ unit-test: Inline +//@ edition: 2021 +//@ compile-flags: -Zinline-mir-hint-threshold=10000 -Zinline-mir-threshold=10000 --crate-type=lib + +pub async fn run(permit: ActionPermit<'_, ()>, ctx: &mut core::task::Context<'_>) { + run2(permit, ctx); +} + +// EMIT_MIR inline_coroutine_body.run2.Inline.diff +fn run2(permit: ActionPermit<'_, T>, ctx: &mut core::task::Context) { + _ = || { + let mut fut = ActionPermit::perform(permit); + let fut = unsafe { core::pin::Pin::new_unchecked(&mut fut) }; + _ = core::future::Future::poll(fut, ctx); + }; +} + +pub struct ActionPermit<'a, T> { + _guard: core::cell::Ref<'a, T>, +} + +impl<'a, T> ActionPermit<'a, T> { + async fn perform(self) { + core::future::ready(()).await + } +} From 78ebb939c1f7135bcc851ba9d4d091d40bb7fe64 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 19 Mar 2024 12:34:56 -0400 Subject: [PATCH 13/24] Fix validation on substituted callee bodies in MIR inliner --- .../src/transform/validate.rs | 19 +- .../src/coroutine/by_move_body.rs | 9 +- compiler/rustc_mir_transform/src/inline.rs | 1 + tests/mir-opt/inline_coroutine_body.rs | 2 +- ...y.run2-{closure#0}.Inline.panic-abort.diff | 281 +++++++++++++++ ....run2-{closure#0}.Inline.panic-unwind.diff | 341 ++++++++++++++++++ 6 files changed, 642 insertions(+), 11 deletions(-) create mode 100644 tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff create mode 100644 tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 4bc49f906070d..b6d65de8bc64f 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -85,7 +85,7 @@ impl<'tcx> MirPass<'tcx> for Validator { cfg_checker.check_cleanup_control_flow(); // Also run the TypeChecker. - for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body) { + for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body, body) { cfg_checker.fail(location, msg); } @@ -541,19 +541,25 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { /// A faster version of the validation pass that only checks those things which may break when /// instantiating any generic parameters. +/// +/// `caller_body` is used to detect cycles in MIR inlining and MIR validation before +/// `optimized_mir` is available. pub fn validate_types<'tcx>( tcx: TyCtxt<'tcx>, mir_phase: MirPhase, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, + caller_body: &Body<'tcx>, ) -> Vec<(Location, String)> { - let mut type_checker = TypeChecker { body, tcx, param_env, mir_phase, failures: Vec::new() }; + let mut type_checker = + TypeChecker { body, caller_body, tcx, param_env, mir_phase, failures: Vec::new() }; type_checker.visit_body(body); type_checker.failures } struct TypeChecker<'a, 'tcx> { body: &'a Body<'tcx>, + caller_body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, mir_phase: MirPhase, @@ -705,8 +711,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } &ty::Coroutine(def_id, args) => { let f_ty = if let Some(var) = parent_ty.variant_index { - let gen_body = if def_id == self.body.source.def_id() { - self.body + // If we're currently validating an inlined copy of this body, + // then it will no longer be parameterized over the original + // args of the coroutine. Otherwise, we prefer to use this body + // since we may be in the process of computing this MIR in the + // first place. + let gen_body = if def_id == self.caller_body.source.def_id() { + self.caller_body } else { self.tcx.optimized_mir(def_id) }; diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 000b96ee8016f..e0bbd582d88c2 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -64,12 +64,9 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { let mut by_move_body = body.clone(); MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body); dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(())); - by_move_body.source = mir::MirSource { - instance: InstanceDef::CoroutineKindShim { - coroutine_def_id: coroutine_def_id.to_def_id(), - }, - promoted: None, - }; + by_move_body.source = mir::MirSource::from_instance(InstanceDef::CoroutineKindShim { + coroutine_def_id: coroutine_def_id.to_def_id(), + }); body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body); } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 4ec76eec3a930..78c0615b1650e 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -213,6 +213,7 @@ impl<'tcx> Inliner<'tcx> { MirPhase::Runtime(RuntimePhase::Optimized), self.param_env, &callee_body, + &caller_body, ) .is_empty() { diff --git a/tests/mir-opt/inline_coroutine_body.rs b/tests/mir-opt/inline_coroutine_body.rs index 5c305c5510042..be73bc49de59e 100644 --- a/tests/mir-opt/inline_coroutine_body.rs +++ b/tests/mir-opt/inline_coroutine_body.rs @@ -8,7 +8,7 @@ pub async fn run(permit: ActionPermit<'_, ()>, ctx: &mut core::task::Context<'_> run2(permit, ctx); } -// EMIT_MIR inline_coroutine_body.run2.Inline.diff +// EMIT_MIR inline_coroutine_body.run2-{closure#0}.Inline.diff fn run2(permit: ActionPermit<'_, T>, ctx: &mut core::task::Context) { _ = || { let mut fut = ActionPermit::perform(permit); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff new file mode 100644 index 0000000000000..b189b4e73f405 --- /dev/null +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -0,0 +1,281 @@ +- // MIR for `run2::{closure#0}` before Inline ++ // MIR for `run2::{closure#0}` after Inline + + fn run2::{closure#0}(_1: {closure@$DIR/inline_coroutine_body.rs:13:9: 13:11}) -> () { + debug permit => (_1.0: ActionPermit<'_, T>); + debug ctx => (*(_1.1: &mut std::task::Context<'_>)); + let mut _0: (); + let mut _2: {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; + let mut _3: ActionPermit<'_, T>; + let mut _5: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; + let _6: (); + let mut _7: std::task::Poll<()>; + let mut _8: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>; + let mut _9: &mut std::task::Context<'_>; + let mut _10: &mut std::task::Context<'_>; + scope 1 { + debug fut => _2; + let _4: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>; + scope 2 { + debug fut => _4; + scope 4 { + } ++ scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) { ++ debug _task_context => _31; ++ debug self => ((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})).0: ActionPermit<'_, T>); ++ let _11: ActionPermit<'_, T>; ++ let mut _12: std::future::Ready<()>; ++ let mut _13: std::future::Ready<()>; ++ let mut _14: (); ++ let mut _16: (); ++ let _17: (); ++ let mut _18: std::task::Poll<()>; ++ let mut _19: std::pin::Pin<&mut std::future::Ready<()>>; ++ let mut _20: &mut std::future::Ready<()>; ++ let mut _21: &mut std::future::Ready<()>; ++ let mut _22: &mut std::task::Context<'_>; ++ let mut _23: &mut std::task::Context<'_>; ++ let mut _24: &mut std::task::Context<'_>; ++ let mut _25: isize; ++ let mut _27: !; ++ let mut _28: &mut std::task::Context<'_>; ++ let mut _29: (); ++ let mut _30: (); ++ let mut _31: &mut std::task::Context<'_>; ++ let mut _32: u32; ++ let mut _33: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _34: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _35: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _36: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _37: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _38: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _39: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _40: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ scope 8 { ++ debug self => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).0: ActionPermit<'_, T>); ++ let mut _15: std::future::Ready<()>; ++ scope 9 { ++ debug __awaitee => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).1: std::future::Ready<()>); ++ let _26: (); ++ scope 10 { ++ } ++ scope 11 { ++ debug result => _26; ++ } ++ } ++ scope 12 (inlined ready::<()>) { ++ debug t => _14; ++ let mut _41: std::option::Option<()>; ++ } ++ } ++ } + } + scope 3 { ++ scope 6 (inlined Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked) { ++ debug pointer => _5; ++ } + } + } ++ scope 5 (inlined ActionPermit::<'_, T>::perform) { ++ debug self => _3; ++ } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = move (_1.0: ActionPermit<'_, T>); +- _2 = ActionPermit::<'_, T>::perform(move _3) -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { ++ _2 = {coroutine@$DIR/inline_coroutine_body.rs:25:28: 27:6 (#0)} { self: move _3 }; + StorageDead(_3); + StorageLive(_4); + StorageLive(_5); + _5 = &mut _2; +- _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked(move _5) -> [return: bb2, unwind unreachable]; +- } +- +- bb2: { ++ _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}> { __pointer: _5 }; + StorageDead(_5); + StorageLive(_6); + StorageLive(_7); + StorageLive(_8); + _8 = move _4; + StorageLive(_9); + _10 = deref_copy (_1.1: &mut std::task::Context<'_>); + _9 = &mut (*_10); +- _7 = <{async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6} as Future>::poll(move _8, move _9) -> [return: bb3, unwind unreachable]; ++ StorageLive(_11); ++ StorageLive(_15); ++ StorageLive(_16); ++ StorageLive(_25); ++ StorageLive(_27); ++ StorageLive(_30); ++ StorageLive(_31); ++ StorageLive(_32); ++ StorageLive(_33); ++ StorageLive(_34); ++ StorageLive(_35); ++ StorageLive(_36); ++ StorageLive(_37); ++ StorageLive(_38); ++ StorageLive(_39); ++ StorageLive(_40); ++ _33 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _32 = discriminant((*_33)); ++ switchInt(move _32) -> [0: bb3, 1: bb13, 3: bb12, otherwise: bb8]; + } + +- bb3: { ++ bb1: { ++ StorageDead(_2); ++ return; ++ } ++ ++ bb2: { ++ StorageDead(_40); ++ StorageDead(_39); ++ StorageDead(_38); ++ StorageDead(_37); ++ StorageDead(_36); ++ StorageDead(_35); ++ StorageDead(_34); ++ StorageDead(_33); ++ StorageDead(_32); ++ StorageDead(_31); ++ StorageDead(_30); ++ StorageDead(_27); ++ StorageDead(_25); ++ StorageDead(_16); ++ StorageDead(_15); ++ StorageDead(_11); + StorageDead(_9); + StorageDead(_8); + StorageDead(_7); + _6 = const (); + StorageDead(_6); + _0 = const (); + StorageDead(_4); +- drop(_2) -> [return: bb4, unwind unreachable]; ++ drop(_2) -> [return: bb1, unwind unreachable]; + } + ++ bb3: { ++ _31 = move _9; ++ _34 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _35 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>); ++ StorageLive(_12); ++ StorageLive(_13); ++ StorageLive(_14); ++ _14 = (); ++ StorageLive(_41); ++ _41 = Option::<()>::Some(_14); ++ _13 = std::future::Ready::<()>(move _41); ++ StorageDead(_41); ++ StorageDead(_14); ++ _12 = as IntoFuture>::into_future(move _13) -> [return: bb4, unwind unreachable]; ++ } ++ + bb4: { +- StorageDead(_2); +- return; ++ StorageDead(_13); ++ _36 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ (((*_36) as variant#3).1: std::future::Ready<()>) = move _12; ++ goto -> bb5; ++ } ++ ++ bb5: { ++ StorageLive(_17); ++ StorageLive(_18); ++ StorageLive(_19); ++ StorageLive(_20); ++ StorageLive(_21); ++ _37 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>); ++ _20 = &mut (*_21); ++ _19 = Pin::<&mut std::future::Ready<()>>::new_unchecked(move _20) -> [return: bb6, unwind unreachable]; ++ } ++ ++ bb6: { ++ StorageDead(_20); ++ StorageLive(_22); ++ StorageLive(_23); ++ StorageLive(_24); ++ _24 = _31; ++ _23 = move _24; ++ _22 = &mut (*_23); ++ StorageDead(_24); ++ _18 = as Future>::poll(move _19, move _22) -> [return: bb7, unwind unreachable]; ++ } ++ ++ bb7: { ++ StorageDead(_22); ++ StorageDead(_19); ++ _25 = discriminant(_18); ++ switchInt(move _25) -> [0: bb10, 1: bb9, otherwise: bb8]; ++ } ++ ++ bb8: { ++ unreachable; ++ } ++ ++ bb9: { ++ _17 = const (); ++ StorageDead(_23); ++ StorageDead(_21); ++ StorageDead(_18); ++ StorageDead(_17); ++ StorageLive(_28); ++ StorageLive(_29); ++ _29 = (); ++ _7 = Poll::<()>::Pending; ++ StorageDead(_12); ++ StorageDead(_28); ++ StorageDead(_29); ++ _38 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ discriminant((*_38)) = 3; ++ goto -> bb2; ++ } ++ ++ bb10: { ++ StorageLive(_26); ++ _26 = ((_18 as Ready).0: ()); ++ _30 = _26; ++ StorageDead(_26); ++ StorageDead(_23); ++ StorageDead(_21); ++ StorageDead(_18); ++ StorageDead(_17); ++ StorageDead(_12); ++ _39 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb11, unwind unreachable]; ++ } ++ ++ bb11: { ++ _7 = Poll::<()>::Ready(move _30); ++ _40 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ discriminant((*_40)) = 1; ++ goto -> bb2; ++ } ++ ++ bb12: { ++ StorageLive(_12); ++ StorageLive(_28); ++ StorageLive(_29); ++ _28 = move _9; ++ StorageDead(_29); ++ _31 = move _28; ++ StorageDead(_28); ++ _16 = const (); ++ goto -> bb5; ++ } ++ ++ bb13: { ++ assert(const false, "`async fn` resumed after completion") -> [success: bb13, unwind unreachable]; + } + } + diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff new file mode 100644 index 0000000000000..ed18c0a3adb8c --- /dev/null +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -0,0 +1,341 @@ +- // MIR for `run2::{closure#0}` before Inline ++ // MIR for `run2::{closure#0}` after Inline + + fn run2::{closure#0}(_1: {closure@$DIR/inline_coroutine_body.rs:13:9: 13:11}) -> () { + debug permit => (_1.0: ActionPermit<'_, T>); + debug ctx => (*(_1.1: &mut std::task::Context<'_>)); + let mut _0: (); + let mut _2: {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; + let mut _3: ActionPermit<'_, T>; + let mut _5: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; + let _6: (); + let mut _7: std::task::Poll<()>; + let mut _8: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>; + let mut _9: &mut std::task::Context<'_>; + let mut _10: &mut std::task::Context<'_>; + scope 1 { + debug fut => _2; + let _4: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>; + scope 2 { + debug fut => _4; + scope 4 { + } ++ scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) { ++ debug _task_context => _31; ++ debug self => ((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})).0: ActionPermit<'_, T>); ++ let _11: ActionPermit<'_, T>; ++ let mut _12: std::future::Ready<()>; ++ let mut _13: std::future::Ready<()>; ++ let mut _14: (); ++ let mut _16: (); ++ let _17: (); ++ let mut _18: std::task::Poll<()>; ++ let mut _19: std::pin::Pin<&mut std::future::Ready<()>>; ++ let mut _20: &mut std::future::Ready<()>; ++ let mut _21: &mut std::future::Ready<()>; ++ let mut _22: &mut std::task::Context<'_>; ++ let mut _23: &mut std::task::Context<'_>; ++ let mut _24: &mut std::task::Context<'_>; ++ let mut _25: isize; ++ let mut _27: !; ++ let mut _28: &mut std::task::Context<'_>; ++ let mut _29: (); ++ let mut _30: (); ++ let mut _31: &mut std::task::Context<'_>; ++ let mut _32: u32; ++ let mut _33: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _34: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _35: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _36: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _37: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _38: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _39: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _40: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _41: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _42: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ scope 8 { ++ debug self => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).0: ActionPermit<'_, T>); ++ let mut _15: std::future::Ready<()>; ++ scope 9 { ++ debug __awaitee => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).1: std::future::Ready<()>); ++ let _26: (); ++ scope 10 { ++ } ++ scope 11 { ++ debug result => _26; ++ } ++ } ++ scope 12 (inlined ready::<()>) { ++ debug t => _14; ++ let mut _43: std::option::Option<()>; ++ } ++ } ++ } + } + scope 3 { ++ scope 6 (inlined Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked) { ++ debug pointer => _5; ++ } + } + } ++ scope 5 (inlined ActionPermit::<'_, T>::perform) { ++ debug self => _3; ++ } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = move (_1.0: ActionPermit<'_, T>); +- _2 = ActionPermit::<'_, T>::perform(move _3) -> [return: bb1, unwind: bb6]; +- } +- +- bb1: { ++ _2 = {coroutine@$DIR/inline_coroutine_body.rs:25:28: 27:6 (#0)} { self: move _3 }; + StorageDead(_3); + StorageLive(_4); + StorageLive(_5); + _5 = &mut _2; +- _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked(move _5) -> [return: bb2, unwind: bb5]; +- } +- +- bb2: { ++ _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}> { __pointer: _5 }; + StorageDead(_5); + StorageLive(_6); + StorageLive(_7); + StorageLive(_8); + _8 = move _4; + StorageLive(_9); + _10 = deref_copy (_1.1: &mut std::task::Context<'_>); + _9 = &mut (*_10); +- _7 = <{async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6} as Future>::poll(move _8, move _9) -> [return: bb3, unwind: bb5]; ++ StorageLive(_11); ++ StorageLive(_15); ++ StorageLive(_16); ++ StorageLive(_25); ++ StorageLive(_27); ++ StorageLive(_30); ++ StorageLive(_31); ++ StorageLive(_32); ++ StorageLive(_33); ++ StorageLive(_34); ++ StorageLive(_35); ++ StorageLive(_36); ++ StorageLive(_37); ++ StorageLive(_38); ++ StorageLive(_39); ++ StorageLive(_40); ++ StorageLive(_41); ++ StorageLive(_42); ++ _33 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _32 = discriminant((*_33)); ++ switchInt(move _32) -> [0: bb5, 1: bb22, 2: bb21, 3: bb20, otherwise: bb10]; + } + +- bb3: { ++ bb1: { ++ StorageDead(_2); ++ return; ++ } ++ ++ bb2 (cleanup): { ++ drop(_2) -> [return: bb3, unwind terminate(cleanup)]; ++ } ++ ++ bb3 (cleanup): { ++ resume; ++ } ++ ++ bb4: { ++ StorageDead(_42); ++ StorageDead(_41); ++ StorageDead(_40); ++ StorageDead(_39); ++ StorageDead(_38); ++ StorageDead(_37); ++ StorageDead(_36); ++ StorageDead(_35); ++ StorageDead(_34); ++ StorageDead(_33); ++ StorageDead(_32); ++ StorageDead(_31); ++ StorageDead(_30); ++ StorageDead(_27); ++ StorageDead(_25); ++ StorageDead(_16); ++ StorageDead(_15); ++ StorageDead(_11); + StorageDead(_9); + StorageDead(_8); + StorageDead(_7); + _6 = const (); + StorageDead(_6); + _0 = const (); + StorageDead(_4); +- drop(_2) -> [return: bb4, unwind: bb6]; ++ drop(_2) -> [return: bb1, unwind: bb3]; + } + +- bb4: { +- StorageDead(_2); +- return; ++ bb5: { ++ _31 = move _9; ++ _34 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _35 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>); ++ StorageLive(_12); ++ StorageLive(_13); ++ StorageLive(_14); ++ _14 = (); ++ StorageLive(_43); ++ _43 = Option::<()>::Some(_14); ++ _13 = std::future::Ready::<()>(move _43); ++ StorageDead(_43); ++ StorageDead(_14); ++ _12 = as IntoFuture>::into_future(move _13) -> [return: bb6, unwind: bb17]; + } + +- bb5 (cleanup): { +- drop(_2) -> [return: bb6, unwind terminate(cleanup)]; ++ bb6: { ++ StorageDead(_13); ++ _36 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ (((*_36) as variant#3).1: std::future::Ready<()>) = move _12; ++ goto -> bb7; + } + +- bb6 (cleanup): { +- resume; ++ bb7: { ++ StorageLive(_17); ++ StorageLive(_18); ++ StorageLive(_19); ++ StorageLive(_20); ++ StorageLive(_21); ++ _37 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>); ++ _20 = &mut (*_21); ++ _19 = Pin::<&mut std::future::Ready<()>>::new_unchecked(move _20) -> [return: bb8, unwind: bb15]; ++ } ++ ++ bb8: { ++ StorageDead(_20); ++ StorageLive(_22); ++ StorageLive(_23); ++ StorageLive(_24); ++ _24 = _31; ++ _23 = move _24; ++ _22 = &mut (*_23); ++ StorageDead(_24); ++ _18 = as Future>::poll(move _19, move _22) -> [return: bb9, unwind: bb14]; ++ } ++ ++ bb9: { ++ StorageDead(_22); ++ StorageDead(_19); ++ _25 = discriminant(_18); ++ switchInt(move _25) -> [0: bb12, 1: bb11, otherwise: bb10]; ++ } ++ ++ bb10: { ++ unreachable; ++ } ++ ++ bb11: { ++ _17 = const (); ++ StorageDead(_23); ++ StorageDead(_21); ++ StorageDead(_18); ++ StorageDead(_17); ++ StorageLive(_28); ++ StorageLive(_29); ++ _29 = (); ++ _7 = Poll::<()>::Pending; ++ StorageDead(_12); ++ StorageDead(_28); ++ StorageDead(_29); ++ _38 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ discriminant((*_38)) = 3; ++ goto -> bb4; ++ } ++ ++ bb12: { ++ StorageLive(_26); ++ _26 = ((_18 as Ready).0: ()); ++ _30 = _26; ++ StorageDead(_26); ++ StorageDead(_23); ++ StorageDead(_21); ++ StorageDead(_18); ++ StorageDead(_17); ++ StorageDead(_12); ++ _39 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb13, unwind: bb19]; ++ } ++ ++ bb13: { ++ _7 = Poll::<()>::Ready(move _30); ++ _40 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ discriminant((*_40)) = 1; ++ goto -> bb4; ++ } ++ ++ bb14 (cleanup): { ++ StorageDead(_22); ++ StorageDead(_19); ++ StorageDead(_23); ++ goto -> bb16; ++ } ++ ++ bb15 (cleanup): { ++ StorageDead(_20); ++ StorageDead(_19); ++ goto -> bb16; ++ } ++ ++ bb16 (cleanup): { ++ StorageDead(_21); ++ StorageDead(_18); ++ StorageDead(_17); ++ goto -> bb18; ++ } ++ ++ bb17 (cleanup): { ++ StorageDead(_13); ++ goto -> bb18; ++ } ++ ++ bb18 (cleanup): { ++ StorageDead(_12); ++ _41 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ drop((((*_41) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb19, unwind terminate(cleanup)]; ++ } ++ ++ bb19 (cleanup): { ++ _42 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ discriminant((*_42)) = 2; ++ goto -> bb2; ++ } ++ ++ bb20: { ++ StorageLive(_12); ++ StorageLive(_28); ++ StorageLive(_29); ++ _28 = move _9; ++ StorageDead(_29); ++ _31 = move _28; ++ StorageDead(_28); ++ _16 = const (); ++ goto -> bb7; ++ } ++ ++ bb21: { ++ assert(const false, "`async fn` resumed after panicking") -> [success: bb21, unwind: bb2]; ++ } ++ ++ bb22: { ++ assert(const false, "`async fn` resumed after completion") -> [success: bb22, unwind: bb2]; + } + } + From 12e362989b59469f8bbabe6b93f787b8127609a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 11:57:26 +0100 Subject: [PATCH 14/24] add test for #99945 Fixes #99945 --- .../failed-to-normalize-ice-99945.rs | 36 +++++++++++++++++++ .../failed-to-normalize-ice-99945.stderr | 25 +++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs create mode 100644 tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr diff --git a/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs new file mode 100644 index 0000000000000..023991c29d090 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs @@ -0,0 +1,36 @@ +// issue: rust-lang/rust#99945 +// ICE Failed to normalize + +#![feature(type_alias_impl_trait)] + +trait Widget { + type State; + + fn make_state(&self) -> Self::State; +} + +impl Widget for () { + type State = (); + + fn make_state(&self) -> Self::State {} +} + +struct StatefulWidget(F); + +type StateWidget<'a> = impl Widget<&'a ()>; + +impl Fn(&'a ()) -> StateWidget<'a>> Widget<()> for StatefulWidget { + type State = (); + + fn make_state(&self) -> Self::State {} +} + +fn new_stateful_widget Fn(&'a ()) -> StateWidget<'a>>(build: F) -> impl Widget<()> { + StatefulWidget(build) + //~^ ERROR expected generic lifetime parameter, found `'a` +} + +fn main() { + new_stateful_widget(|_| ()).make_state(); + //~^ ERROR mismatched types +} diff --git a/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr new file mode 100644 index 0000000000000..0c76feae198ba --- /dev/null +++ b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/failed-to-normalize-ice-99945.rs:34:29 + | +LL | type StateWidget<'a> = impl Widget<&'a ()>; + | ------------------- the expected opaque type +... +LL | new_stateful_widget(|_| ()).make_state(); + | ^^ expected opaque type, found `()` + | + = note: expected opaque type `StateWidget<'_>` + found unit type `()` + +error[E0792]: expected generic lifetime parameter, found `'a` + --> $DIR/failed-to-normalize-ice-99945.rs:29:5 + | +LL | type StateWidget<'a> = impl Widget<&'a ()>; + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | StatefulWidget(build) + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0792. +For more information about an error, try `rustc --explain E0308`. From 2f9a240b91f766f158b652f537b828c9909bfdd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:01:39 +0100 Subject: [PATCH 15/24] add test for opaque type with non-universal region substs #101852 Fixes #101852 --- tests/ui/impl-trait/recursive-ice-101862.rs | 12 ++++++++++ .../ui/impl-trait/recursive-ice-101862.stderr | 24 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/ui/impl-trait/recursive-ice-101862.rs create mode 100644 tests/ui/impl-trait/recursive-ice-101862.stderr diff --git a/tests/ui/impl-trait/recursive-ice-101862.rs b/tests/ui/impl-trait/recursive-ice-101862.rs new file mode 100644 index 0000000000000..02f95fe5604b2 --- /dev/null +++ b/tests/ui/impl-trait/recursive-ice-101862.rs @@ -0,0 +1,12 @@ +// issue: rust-lang/rust#101852 +// ICE opaque type with non-universal region substs + +pub fn ice(x: impl AsRef) -> impl IntoIterator { +//~^ WARN function cannot return without recursing + vec![].append(&mut ice(x.as_ref())); + //~^ ERROR expected generic type parameter, found `&str` + + Vec::new() +} + +fn main() {} diff --git a/tests/ui/impl-trait/recursive-ice-101862.stderr b/tests/ui/impl-trait/recursive-ice-101862.stderr new file mode 100644 index 0000000000000..f4148720c3331 --- /dev/null +++ b/tests/ui/impl-trait/recursive-ice-101862.stderr @@ -0,0 +1,24 @@ +warning: function cannot return without recursing + --> $DIR/recursive-ice-101862.rs:4:1 + | +LL | pub fn ice(x: impl AsRef) -> impl IntoIterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | +LL | vec![].append(&mut ice(x.as_ref())); + | --------------- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +error[E0792]: expected generic type parameter, found `&str` + --> $DIR/recursive-ice-101862.rs:6:5 + | +LL | pub fn ice(x: impl AsRef) -> impl IntoIterator { + | --------------- this generic parameter must be used with a generic type parameter +LL | +LL | vec![].append(&mut ice(x.as_ref())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0792`. From e54bff71091e7c3a16c96e2f79328eb73815d7cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:19:05 +0100 Subject: [PATCH 16/24] add test for #104779 opaque types, patterns and subtyping ICE: IndexMap: key not found Fixes #104779 --- ...que-types-patterns-subtyping-ice-104779.rs | 26 ++++++++++++ ...types-patterns-subtyping-ice-104779.stderr | 42 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs create mode 100644 tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr diff --git a/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs new file mode 100644 index 0000000000000..b9e729bff62a0 --- /dev/null +++ b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs @@ -0,0 +1,26 @@ +// issue: rust-lang/rust#104779 +// ICE region infer, IndexMap: key not found + +struct Inv<'a>(&'a mut &'a ()); +enum Foo { + Bar, + Var(T), +} +type Subtype = Foo fn(Inv<'a>, Inv<'b>)>; +type Supertype = Foo fn(Inv<'a>, Inv<'a>)>; + +fn foo() -> impl Sized { +//~^ WARN function cannot return without recursing + loop { + match foo() { + //~^ ERROR higher-ranked subtype error + //~^^ ERROR higher-ranked subtype error + Subtype::Bar => (), + //~^ ERROR higher-ranked subtype error + //~^^ ERROR higher-ranked subtype error + Supertype::Var(x) => {} + } + } +} + +pub fn main() {} diff --git a/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr new file mode 100644 index 0000000000000..887cb14a76935 --- /dev/null +++ b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr @@ -0,0 +1,42 @@ +warning: function cannot return without recursing + --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:12:1 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +... +LL | match foo() { + | ----- recursive call site + | + = help: a `loop` may express intention better if this is on purpose + = note: `#[warn(unconditional_recursion)]` on by default + +error: higher-ranked subtype error + --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:15:15 + | +LL | match foo() { + | ^^^^^ + +error: higher-ranked subtype error + --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:15:15 + | +LL | match foo() { + | ^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: higher-ranked subtype error + --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:18:13 + | +LL | Subtype::Bar => (), + | ^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:18:13 + | +LL | Subtype::Bar => (), + | ^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors; 1 warning emitted + From f1f287fadb91451b116ff00a2f8b9c32c5e1571b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:24:40 +0100 Subject: [PATCH 17/24] add test for ICE "raw ptr comparison should already be caught in the trait system" #105047 Fixes #105047 --- .../const-eval-compare-ice-105047.rs | 15 +++++++++ .../const-eval-compare-ice-105047.stderr | 31 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs create mode 100644 tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr diff --git a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs new file mode 100644 index 0000000000000..0a736a5a8e21b --- /dev/null +++ b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs @@ -0,0 +1,15 @@ +// issue: rust-lang/rust#105047 +// ICE raw ptr comparison should already be caught in the trait systems + +#![feature(raw_ref_op)] + +const RCZ: *const i32 = &raw const *&0; + +const fn f() { + if let RCZ = &raw const *&0 { } + //~^ WARN function pointers and raw pointers not derived from integers in patterns + //~^^ ERROR pointers cannot be reliably compared during const eval + //~^^^ WARN this was previously accepted by the compiler but is being phased out +} + +fn main() {} diff --git a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr new file mode 100644 index 0000000000000..9c472cda2442c --- /dev/null +++ b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr @@ -0,0 +1,31 @@ +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/const-eval-compare-ice-105047.rs:9:12 + | +LL | if let RCZ = &raw const *&0 { } + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + +error: pointers cannot be reliably compared during const eval + --> $DIR/const-eval-compare-ice-105047.rs:9:12 + | +LL | if let RCZ = &raw const *&0 { } + | ^^^ + | + = note: see issue #53020 for more information + +error: aborting due to 1 previous error; 1 warning emitted + +Future incompatibility report: Future breakage diagnostic: +warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/const-eval-compare-ice-105047.rs:9:12 + | +LL | if let RCZ = &raw const *&0 { } + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #120362 + = note: `#[warn(pointer_structural_match)]` on by default + From f8aeac8a3692b1a02002a1293c231de73149e676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:32:32 +0100 Subject: [PATCH 18/24] add test for #106423 Fixes #106423 --- .../poly-const-uneval-ice-106423.rs | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs diff --git a/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs b/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs new file mode 100644 index 0000000000000..ed5ba32b62105 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs @@ -0,0 +1,57 @@ +// issue: rust-lang/rust#106423 +// ICE collection encountered polymorphic constant: UnevaluatedConst {..} +//@ edition:2021 +//@ check-pass + +#![feature(generic_const_exprs, generic_arg_infer)] +#![allow(incomplete_features)] +#![allow(unused)] + +use core::mem::MaybeUninit; + +pub struct Arr { + v: [MaybeUninit; N], +} + +impl Arr { + const ELEM: MaybeUninit = MaybeUninit::uninit(); + const INIT: [MaybeUninit; N] = [Self::ELEM; N]; // important for optimization of `new` + + fn new() -> Self { + Arr { v: Self::INIT } + } +} + +pub struct BaFormatFilter {} + +pub enum DigitalFilter +where + [(); N * 2 + 1]: Sized, + [(); N * 2]: Sized, +{ + Ba(BaFormatFilter<{ N * 2 + 1 }>), +} + +pub fn iirfilter_st_copy(_: [f32; M]) -> DigitalFilter +where + [(); N * 2 + 1]: Sized, + [(); N * 2]: Sized, +{ + let zpk = zpk2tf_st(&Arr::::new(), &Arr::::new()); + DigitalFilter::Ba(zpk) +} + +pub fn zpk2tf_st( + _z: &Arr, + _p: &Arr, +) -> BaFormatFilter<{ N + 1 }> +where + [(); N + 1]: Sized, +{ + BaFormatFilter {} +} + + +fn main() { + iirfilter_st_copy::<4, 2>([10., 50.,]); +} From cc422cee97e53195ac75b25d221f192b6a3a200b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:38:50 +0100 Subject: [PATCH 19/24] add test for ICE #106444 Fixes #106444 --- tests/ui/drop/norm-ice-106444.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/ui/drop/norm-ice-106444.rs diff --git a/tests/ui/drop/norm-ice-106444.rs b/tests/ui/drop/norm-ice-106444.rs new file mode 100644 index 0000000000000..b248bc73bbefa --- /dev/null +++ b/tests/ui/drop/norm-ice-106444.rs @@ -0,0 +1,16 @@ +// issue: rust-lang/rust#106444 +// ICE failed to normalize +//@ compile-flags: -Zmir-opt-level=3 +//@ check-pass + +#![crate_type="lib"] + +pub trait A { + type B; +} + +pub struct S(T::B); + +pub fn foo(p: *mut S) { + unsafe { core::ptr::drop_in_place(p) }; +} From f2bc9c5997a3647a61cfb5045866314088c6befa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 12:50:21 +0100 Subject: [PATCH 20/24] add test for #106874 ICE BoundUniversalRegionError Fixes #106874 --- tests/ui/nll/ice-106874.rs | 48 ++++++++++++++++++ tests/ui/nll/ice-106874.stderr | 90 ++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 tests/ui/nll/ice-106874.rs create mode 100644 tests/ui/nll/ice-106874.stderr diff --git a/tests/ui/nll/ice-106874.rs b/tests/ui/nll/ice-106874.rs new file mode 100644 index 0000000000000..77a91d6d823a2 --- /dev/null +++ b/tests/ui/nll/ice-106874.rs @@ -0,0 +1,48 @@ +// issue: rust-lang/rust#106874 +// ICE BoundUniversalRegionError + +use std::marker::PhantomData; +use std::rc::Rc; + +pub fn func(f: F) -> A { + A(B(C::new(D::new(move |st| f(st))))) + //~^ ERROR implementation of `FnOnce` is not general enough + //~^^ ERROR implementation of `Fn` is not general enough + //~^^^ ERROR implementation of `FnOnce` is not general enough + //~^^^^ ERROR implementation of `FnOnce` is not general enough + //~^^^^^ ERROR implementation of `Fn` is not general enough + //~^^^^^^ ERROR implementation of `FnOnce` is not general enough + //~^^^^^^^ ERROR implementation of `Fn` is not general enough + //~^^^^^^^^ ERROR implementation of `FnOnce` is not general enough + //~^^^^^^^^^ ERROR higher-ranked subtype error + //~^^^^^^^^^^ ERROR higher-ranked subtype error +} + +trait X {} +trait Y { + type V; +} + +struct A(T); + +struct B(Rc); +impl X for B {} + +struct C(T::V); +impl C { + fn new(_: T) -> Rc { + todo!() + } +} +struct D(F, PhantomData); + +impl D { + fn new(_: F) -> Self { + todo!() + } +} +impl Y for D { + type V = V; +} + +pub fn main() {} diff --git a/tests/ui/nll/ice-106874.stderr b/tests/ui/nll/ice-106874.stderr new file mode 100644 index 0000000000000..ead4d490a6248 --- /dev/null +++ b/tests/ui/nll/ice-106874.stderr @@ -0,0 +1,90 @@ +error: implementation of `FnOnce` is not general enough + --> $DIR/ice-106874.rs:8:5 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... + = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` + +error: implementation of `FnOnce` is not general enough + --> $DIR/ice-106874.rs:8:5 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`... + = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: implementation of `Fn` is not general enough + --> $DIR/ice-106874.rs:8:7 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` + +error: implementation of `FnOnce` is not general enough + --> $DIR/ice-106874.rs:8:7 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` + +error: implementation of `Fn` is not general enough + --> $DIR/ice-106874.rs:8:7 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: implementation of `FnOnce` is not general enough + --> $DIR/ice-106874.rs:8:9 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` + +error: implementation of `Fn` is not general enough + --> $DIR/ice-106874.rs:8:9 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2` + +error: implementation of `FnOnce` is not general enough + --> $DIR/ice-106874.rs:8:9 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2` + +error: higher-ranked subtype error + --> $DIR/ice-106874.rs:8:41 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^ + +error: higher-ranked subtype error + --> $DIR/ice-106874.rs:8:41 + | +LL | A(B(C::new(D::new(move |st| f(st))))) + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 10 previous errors + From 368bfb2c10541129f9e6af98d88125d9bfc77820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 13:05:22 +0100 Subject: [PATCH 21/24] add test for #107228 Fixes #107228 --- .../broken-mir-drop-glue-107228.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/ui/specialization/broken-mir-drop-glue-107228.rs diff --git a/tests/ui/specialization/broken-mir-drop-glue-107228.rs b/tests/ui/specialization/broken-mir-drop-glue-107228.rs new file mode 100644 index 0000000000000..5a6dbf9ffc761 --- /dev/null +++ b/tests/ui/specialization/broken-mir-drop-glue-107228.rs @@ -0,0 +1,28 @@ +// issue: rust-lang/rust#107228 +// ICE broken MIR in DropGlue +//@ compile-flags: -Zvalidate-mir +//@ check-pass + +#![feature(specialization)] +#![crate_type="lib"] +#![allow(incomplete_features)] + +pub(crate) trait SpecTrait { + type Assoc; +} + +impl SpecTrait for C { + default type Assoc = Vec; +} + +pub(crate) struct AssocWrap { + _assoc: C::Assoc, +} + +fn instantiate() -> AssocWrap { + loop {} +} + +pub fn main() { + instantiate::<()>(); +} From 9aea37d3c114395219a85115f2fd19c249ccf105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 23 Mar 2024 16:14:42 +0100 Subject: [PATCH 22/24] address review feedback --- tests/ui/nll/ice-106874.rs | 18 +++++++++--------- .../const-eval-compare-ice-105047.rs | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/ui/nll/ice-106874.rs b/tests/ui/nll/ice-106874.rs index 77a91d6d823a2..9337eee961bfb 100644 --- a/tests/ui/nll/ice-106874.rs +++ b/tests/ui/nll/ice-106874.rs @@ -7,15 +7,15 @@ use std::rc::Rc; pub fn func(f: F) -> A { A(B(C::new(D::new(move |st| f(st))))) //~^ ERROR implementation of `FnOnce` is not general enough - //~^^ ERROR implementation of `Fn` is not general enough - //~^^^ ERROR implementation of `FnOnce` is not general enough - //~^^^^ ERROR implementation of `FnOnce` is not general enough - //~^^^^^ ERROR implementation of `Fn` is not general enough - //~^^^^^^ ERROR implementation of `FnOnce` is not general enough - //~^^^^^^^ ERROR implementation of `Fn` is not general enough - //~^^^^^^^^ ERROR implementation of `FnOnce` is not general enough - //~^^^^^^^^^ ERROR higher-ranked subtype error - //~^^^^^^^^^^ ERROR higher-ranked subtype error + //~| ERROR implementation of `Fn` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `Fn` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `Fn` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR higher-ranked subtype error + //~| ERROR higher-ranked subtype error } trait X {} diff --git a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs index 0a736a5a8e21b..87ce4f1e14d94 100644 --- a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs +++ b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs @@ -8,8 +8,8 @@ const RCZ: *const i32 = &raw const *&0; const fn f() { if let RCZ = &raw const *&0 { } //~^ WARN function pointers and raw pointers not derived from integers in patterns - //~^^ ERROR pointers cannot be reliably compared during const eval - //~^^^ WARN this was previously accepted by the compiler but is being phased out + //~| ERROR pointers cannot be reliably compared during const eval + //~| WARN this was previously accepted by the compiler but is being phased out } fn main() {} From 246f7465b35f827d200eba25a1c27fddd18d7962 Mon Sep 17 00:00:00 2001 From: Luv-Ray Date: Sat, 23 Mar 2024 23:33:43 +0800 Subject: [PATCH 23/24] Add test in `higher-ranked` --- .../structually-relate-aliases.rs | 17 ++++++++++++ .../structually-relate-aliases.stderr | 27 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/ui/higher-ranked/structually-relate-aliases.rs create mode 100644 tests/ui/higher-ranked/structually-relate-aliases.stderr diff --git a/tests/ui/higher-ranked/structually-relate-aliases.rs b/tests/ui/higher-ranked/structually-relate-aliases.rs new file mode 100644 index 0000000000000..8df24702811dd --- /dev/null +++ b/tests/ui/higher-ranked/structually-relate-aliases.rs @@ -0,0 +1,17 @@ +// regression test for issue #121649. + +trait ToUnit<'a> { + type Unit; +} + +trait Overlap {} + +type Assoc<'a, T> = >::Unit; + +impl Overlap for T {} + +impl Overlap fn(&'a (), Assoc<'a, T>)> for T {} +//~^ ERROR 13:17: 13:49: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied [E0277] +//~| ERROR 13:36: 13:48: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied [E0277] + +fn main() {} diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr new file mode 100644 index 0000000000000..59fab52b221e2 --- /dev/null +++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr @@ -0,0 +1,27 @@ +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) } +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) } +error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied + --> $DIR/structually-relate-aliases.rs:13:36 + | +LL | impl Overlap fn(&'a (), Assoc<'a, T>)> for T {} + | ^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl ToUnit<'a>> Overlap fn(&'a (), Assoc<'a, T>)> for T {} + | ++++++++++++++++++++ + +error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied + --> $DIR/structually-relate-aliases.rs:13:17 + | +LL | impl Overlap fn(&'a (), Assoc<'a, T>)> for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | impl ToUnit<'a>> Overlap fn(&'a (), Assoc<'a, T>)> for T {} + | ++++++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From 188c46a65e40b3a69b43874dc7fee72d986e9ca5 Mon Sep 17 00:00:00 2001 From: Kalle Wachsmuth Date: Mon, 19 Feb 2024 01:01:11 +0100 Subject: [PATCH 24/24] regression test for #103626 --- ...onicalize-fresh-infer-vars-issue-103626.rs | 15 +++++++++ ...alize-fresh-infer-vars-issue-103626.stderr | 33 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs create mode 100644 tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs new file mode 100644 index 0000000000000..3af299e5b115a --- /dev/null +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs @@ -0,0 +1,15 @@ +trait FromResidual::Residual> { + fn from_residual(residual: R) -> Self; +} + +trait Try { + type Residual; +} + +fn w<'a, T: 'a, F: Fn(&'a T)>() { + let b: &dyn FromResidual = &(); + //~^ ERROR: the trait `FromResidual` cannot be made into an object + //~| ERROR: the trait `FromResidual` cannot be made into an object +} + +fn main() {} diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr new file mode 100644 index 0000000000000..d5e9b1be63b0b --- /dev/null +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr @@ -0,0 +1,33 @@ +error[E0038]: the trait `FromResidual` cannot be made into an object + --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:17 + | +LL | let b: &dyn FromResidual = &(); + | ^^^^^^^^^^^^ + | + = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause + +error[E0038]: the trait `FromResidual` cannot be made into an object + --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:12 + | +LL | let b: &dyn FromResidual = &(); + | ^^^^^^^^^^^^^^^^^ `FromResidual` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8 + | +LL | trait FromResidual::Residual> { + | ------------ this trait cannot be made into an object... +LL | fn from_residual(residual: R) -> Self; + | ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter +help: consider turning `from_residual` into a method by giving it a `&self` argument + | +LL | fn from_residual(&self, residual: R) -> Self; + | ++++++ +help: alternatively, consider constraining `from_residual` so it does not apply to trait objects + | +LL | fn from_residual(residual: R) -> Self where Self: Sized; + | +++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`.