From ea44f12f72888528ddb5b26492c3b72ad4b7bcb4 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 15 Aug 2025 21:47:39 +0800 Subject: [PATCH 1/9] Rename and move tuple index suffix regression test To make it more obvious what it's testing. This is its own commit to make git blame easier. --- src/tools/tidy/src/issues.txt | 1 - tests/ui/parser/{issues/issue-59418.rs => tuple-index-suffix.rs} | 0 .../{issues/issue-59418.stderr => tuple-index-suffix.stderr} | 0 3 files changed, 1 deletion(-) rename tests/ui/parser/{issues/issue-59418.rs => tuple-index-suffix.rs} (100%) rename tests/ui/parser/{issues/issue-59418.stderr => tuple-index-suffix.stderr} (100%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index ee06707415f59..849dcb9e88fb1 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2021,7 +2021,6 @@ ui/parser/issues/issue-5806.rs ui/parser/issues/issue-58094-missing-right-square-bracket.rs ui/parser/issues/issue-58856-1.rs ui/parser/issues/issue-58856-2.rs -ui/parser/issues/issue-59418.rs ui/parser/issues/issue-60075.rs ui/parser/issues/issue-61858.rs ui/parser/issues/issue-62524.rs diff --git a/tests/ui/parser/issues/issue-59418.rs b/tests/ui/parser/tuple-index-suffix.rs similarity index 100% rename from tests/ui/parser/issues/issue-59418.rs rename to tests/ui/parser/tuple-index-suffix.rs diff --git a/tests/ui/parser/issues/issue-59418.stderr b/tests/ui/parser/tuple-index-suffix.stderr similarity index 100% rename from tests/ui/parser/issues/issue-59418.stderr rename to tests/ui/parser/tuple-index-suffix.stderr From d7f7443a9540761c7cc2540c4b7b07b31b6120e5 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 15 Aug 2025 22:11:10 +0800 Subject: [PATCH 2/9] Expand `tuple-index-suffix` test coverage Actually, the accidentally accepted invalid suffixes also include tuple struct indexing positions, struct numeral field name positions. So before changing anything, first expand test coverage, so we can observe the effect of bumping the non-lint pseudo-FCW warning into a hard error. --- tests/ui/parser/tuple-index-suffix.rs | 75 ++++++++-- tests/ui/parser/tuple-index-suffix.stderr | 166 ++++++++++++++++++++-- 2 files changed, 222 insertions(+), 19 deletions(-) diff --git a/tests/ui/parser/tuple-index-suffix.rs b/tests/ui/parser/tuple-index-suffix.rs index 0fa191d4a7ef4..31c5bc25063dd 100644 --- a/tests/ui/parser/tuple-index-suffix.rs +++ b/tests/ui/parser/tuple-index-suffix.rs @@ -1,18 +1,77 @@ +//! See #60210. +//! +//! Check that we hard error on invalid suffixes in tuple indexing subexpressions and struct numeral +//! field names, modulo carve-outs for `{i,u}{32,usize}` at warning level to mitigate ecosystem +//! impact. + struct X(i32,i32,i32); fn main() { - let a = X(1, 2, 3); - let b = a.1suffix; + let tup_struct = X(1, 2, 3); + let invalid_tup_struct_suffix = tup_struct.0suffix; //~^ ERROR suffixes on a tuple index are invalid - println!("{}", b); - let c = (1, 2, 3); - let d = c.1suffix; + let carve_out_tup_struct_suffix = tup_struct.0i32; + //~^ WARN suffixes on a tuple index are invalid + + let tup = (1, 2, 3); + let invalid_tup_suffix = tup.0suffix; //~^ ERROR suffixes on a tuple index are invalid - println!("{}", d); - let s = X { 0suffix: 0, 1: 1, 2: 2 }; + let carve_out_tup_suffix = tup.0u32; + //~^ WARN suffixes on a tuple index are invalid + + numeral_struct_field_name_suffix_invalid(); + numeral_struct_field_name_suffix_carve_out(); +} + +// Very limited carve outs as a ecosystem impact mitigation implemented in #60186. *Only* +// `{i,u}{32,usize}` suffixes are temporarily accepted. +fn carve_outs() { + // Ok, only pseudo-FCW warnings. + + let carve_out_i32 = (42,).0i32; //~ WARN suffixes on a tuple index are invalid + let carve_out_i32 = (42,).0u32; //~ WARN suffixes on a tuple index are invalid + let carve_out_isize = (42,).0isize; //~ WARN suffixes on a tuple index are invalid + let carve_out_usize = (42,).0usize; //~ WARN suffixes on a tuple index are invalid + + // Not part of the carve outs! + let error_i8 = (42,).0i8; //~ ERROR suffixes on a tuple index are invalid + let error_u8 = (42,).0u8; //~ ERROR suffixes on a tuple index are invalid + let error_i16 = (42,).0i16; //~ ERROR suffixes on a tuple index are invalid + let error_u16 = (42,).0u16; //~ ERROR suffixes on a tuple index are invalid + let error_i64 = (42,).0i64; //~ ERROR suffixes on a tuple index are invalid + let error_u64 = (42,).0u64; //~ ERROR suffixes on a tuple index are invalid + let error_i128 = (42,).0i128; //~ ERROR suffixes on a tuple index are invalid + let error_u128 = (42,).0u128; //~ ERROR suffixes on a tuple index are invalid +} + +fn numeral_struct_field_name_suffix_invalid() { + let invalid_struct_name = X { 0suffix: 0, 1: 1, 2: 2 }; //~^ ERROR suffixes on a tuple index are invalid - match s { + match invalid_struct_name { X { 0suffix: _, .. } => {} //~^ ERROR suffixes on a tuple index are invalid } } + +fn numeral_struct_field_name_suffix_carve_out() { + let carve_out_struct_name = X { 0u32: 0, 1: 1, 2: 2 }; + //~^ WARN suffixes on a tuple index are invalid + match carve_out_struct_name { + X { 0u32: _, .. } => {} + //~^ WARN suffixes on a tuple index are invalid + } +} + +// Unfortunately, it turns out `std::mem::offset_of!` uses the same expect suffix code path. +fn offset_of_suffix() { + #[repr(C)] + pub struct Struct(u8, T); + + // Carve outs + assert_eq!(std::mem::offset_of!(Struct, 0usize), 0); + //~^ WARN suffixes on a tuple index are invalid + + // Not part of carve outs + assert_eq!(std::mem::offset_of!(Struct, 0u8), 0); + //~^ ERROR suffixes on a tuple index are invalid +} diff --git a/tests/ui/parser/tuple-index-suffix.stderr b/tests/ui/parser/tuple-index-suffix.stderr index 347051e9f921c..3a499dd6a8dff 100644 --- a/tests/ui/parser/tuple-index-suffix.stderr +++ b/tests/ui/parser/tuple-index-suffix.stderr @@ -1,26 +1,170 @@ error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:5:15 + --> $DIR/tuple-index-suffix.rs:11:48 | -LL | let b = a.1suffix; - | ^^^^^^^ invalid suffix `suffix` +LL | let invalid_tup_struct_suffix = tup_struct.0suffix; + | ^^^^^^^ invalid suffix `suffix` + +warning: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:13:50 + | +LL | let carve_out_tup_struct_suffix = tup_struct.0i32; + | ^^^^ invalid suffix `i32` + | + = help: `i32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + = help: see issue #60210 for more information + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:17:34 + | +LL | let invalid_tup_suffix = tup.0suffix; + | ^^^^^^^ invalid suffix `suffix` + +warning: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:19:36 + | +LL | let carve_out_tup_suffix = tup.0u32; + | ^^^^ invalid suffix `u32` + | + = help: `u32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + = help: see issue #60210 for more information + +warning: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:31:31 + | +LL | let carve_out_i32 = (42,).0i32; + | ^^^^ invalid suffix `i32` + | + = help: `i32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + = help: see issue #60210 for more information + +warning: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:32:31 + | +LL | let carve_out_i32 = (42,).0u32; + | ^^^^ invalid suffix `u32` + | + = help: `u32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + = help: see issue #60210 for more information + +warning: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:33:33 + | +LL | let carve_out_isize = (42,).0isize; + | ^^^^^^ invalid suffix `isize` + | + = help: `isize` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + = help: see issue #60210 for more information + +warning: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:34:33 + | +LL | let carve_out_usize = (42,).0usize; + | ^^^^^^ invalid suffix `usize` + | + = help: `usize` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + = help: see issue #60210 for more information + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:37:26 + | +LL | let error_i8 = (42,).0i8; + | ^^^ invalid suffix `i8` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:38:26 + | +LL | let error_u8 = (42,).0u8; + | ^^^ invalid suffix `u8` error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:9:15 + --> $DIR/tuple-index-suffix.rs:39:27 | -LL | let d = c.1suffix; - | ^^^^^^^ invalid suffix `suffix` +LL | let error_i16 = (42,).0i16; + | ^^^^ invalid suffix `i16` error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:12:17 + --> $DIR/tuple-index-suffix.rs:40:27 | -LL | let s = X { 0suffix: 0, 1: 1, 2: 2 }; - | ^^^^^^^ invalid suffix `suffix` +LL | let error_u16 = (42,).0u16; + | ^^^^ invalid suffix `u16` error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:15:13 + --> $DIR/tuple-index-suffix.rs:41:27 + | +LL | let error_i64 = (42,).0i64; + | ^^^^ invalid suffix `i64` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:42:27 + | +LL | let error_u64 = (42,).0u64; + | ^^^^ invalid suffix `u64` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:43:28 + | +LL | let error_i128 = (42,).0i128; + | ^^^^^ invalid suffix `i128` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:44:28 + | +LL | let error_u128 = (42,).0u128; + | ^^^^^ invalid suffix `u128` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:48:35 + | +LL | let invalid_struct_name = X { 0suffix: 0, 1: 1, 2: 2 }; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:51:13 | LL | X { 0suffix: _, .. } => {} | ^^^^^^^ invalid suffix `suffix` -error: aborting due to 4 previous errors +warning: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:57:37 + | +LL | let carve_out_struct_name = X { 0u32: 0, 1: 1, 2: 2 }; + | ^^^^ invalid suffix `u32` + | + = help: `u32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + = help: see issue #60210 for more information + +warning: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:60:13 + | +LL | X { 0u32: _, .. } => {} + | ^^^^ invalid suffix `u32` + | + = help: `u32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + = help: see issue #60210 for more information + +warning: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:71:50 + | +LL | assert_eq!(std::mem::offset_of!(Struct, 0usize), 0); + | ^^^^^^ invalid suffix `usize` + | + = help: `usize` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + = help: see issue #60210 for more information + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:75:50 + | +LL | assert_eq!(std::mem::offset_of!(Struct, 0u8), 0); + | ^^^ invalid suffix `u8` + +error: aborting due to 13 previous errors; 9 warnings emitted From eb3441b25a7acbce8cec0571b3f8ec87cca8c349 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 15 Aug 2025 22:41:43 +0800 Subject: [PATCH 3/9] Add test coverage for proc-macro invalid tup index suffixes --- .../tuple-index-suffix-proc-macro-aux.rs | 33 ++++++++++++++++++ .../parser/tuple-index-suffix-proc-macro.rs | 31 +++++++++++++++++ .../tuple-index-suffix-proc-macro.stderr | 34 +++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs create mode 100644 tests/ui/parser/tuple-index-suffix-proc-macro.rs create mode 100644 tests/ui/parser/tuple-index-suffix-proc-macro.stderr diff --git a/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs b/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs new file mode 100644 index 0000000000000..fa40ed948a623 --- /dev/null +++ b/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs @@ -0,0 +1,33 @@ +#![feature(proc_macro_quote, proc_macro_span)] + +extern crate proc_macro; + +use proc_macro::{Ident, Literal, Span, TokenStream, TokenTree, quote}; + +#[proc_macro] +pub fn bad_tup_indexing(input: TokenStream) -> TokenStream { + let tt = input.into_iter().next().unwrap(); + let TokenTree::Literal(indexing_expr) = tt else { + unreachable!(); + }; + quote! { (42,).$indexing_expr } +} + +// Expects {IDENT, COMMA, LITERAL} +#[proc_macro] +pub fn bad_tup_struct_indexing(input: TokenStream) -> TokenStream { + let mut input = input.into_iter(); + + let id_tt = input.next().unwrap(); + let _comma = input.next().unwrap(); + let tt = input.next().unwrap(); + + let TokenTree::Ident(ident) = id_tt else { + unreachable!("id"); + }; + let TokenTree::Literal(indexing_expr) = tt else { + unreachable!("lit"); + }; + + quote! { $ident.$indexing_expr } +} diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.rs b/tests/ui/parser/tuple-index-suffix-proc-macro.rs new file mode 100644 index 0000000000000..feca6f9cdfb06 --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.rs @@ -0,0 +1,31 @@ +//! See #59418. +//! +//! Like `tuple-index-suffix.rs`, but exercises the proc-macro interaction. + +//@ proc-macro: tuple-index-suffix-proc-macro-aux.rs + +extern crate tuple_index_suffix_proc_macro_aux; +use tuple_index_suffix_proc_macro_aux as aux; + +fn main() { + struct TupStruct(i32); + let tup_struct = TupStruct(42); + + // #60186 carve outs `{i,u}{32,usize}` as non-lint pseudo-FCW warnings. + + aux::bad_tup_indexing!(0usize); + //~^ WARN suffixes on a tuple index are invalid + aux::bad_tup_struct_indexing!(tup_struct, 0isize); + //~^ WARN suffixes on a tuple index are invalid + + // Not part of the #60186 carve outs. + + aux::bad_tup_indexing!(0u8); + //~^ ERROR suffixes on a tuple index are invalid + aux::bad_tup_struct_indexing!(tup_struct, 0u64); + //~^ ERROR suffixes on a tuple index are invalid + + // NOTE: didn't bother with trying to figure out how to generate `struct P { 0u32: u32 }` using + // *only* `proc_macro` without help with `syn`/`quote`, looks like you can't with just + // `proc_macro::quote`? +} diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.stderr b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr new file mode 100644 index 0000000000000..c8bc3a4576b40 --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr @@ -0,0 +1,34 @@ +warning: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:16:28 + | +LL | aux::bad_tup_indexing!(0usize); + | ^^^^^^ invalid suffix `usize` + | + = help: `usize` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + = help: see issue #60210 for more information + +warning: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:18:47 + | +LL | aux::bad_tup_struct_indexing!(tup_struct, 0isize); + | ^^^^^^ invalid suffix `isize` + | + = help: `isize` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases + = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access + = help: see issue #60210 for more information + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:23:28 + | +LL | aux::bad_tup_indexing!(0u8); + | ^^^ invalid suffix `u8` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:25:47 + | +LL | aux::bad_tup_struct_indexing!(tup_struct, 0u64); + | ^^^^ invalid suffix `u64` + +error: aborting due to 2 previous errors; 2 warnings emitted + From ddd99930f34b79f209c61cc25706a1dac1173762 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 15 Aug 2025 23:39:33 +0800 Subject: [PATCH 4/9] Turn invalid index suffixes into hard errors --- compiler/rustc_parse/messages.ftl | 3 - compiler/rustc_parse/src/errors.rs | 4 - compiler/rustc_parse/src/parser/expr.rs | 26 +--- compiler/rustc_parse/src/parser/mod.rs | 5 +- .../tuple-index-suffix-proc-macro-aux.rs | 8 +- .../parser/tuple-index-suffix-proc-macro.rs | 7 +- .../tuple-index-suffix-proc-macro.stderr | 22 +--- tests/ui/parser/tuple-index-suffix.rs | 44 ++++--- tests/ui/parser/tuple-index-suffix.stderr | 124 +++++++----------- 9 files changed, 92 insertions(+), 151 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 9e0075c21b9ed..0d1a3c783890a 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -473,9 +473,6 @@ parse_invalid_label = parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid .label = invalid suffix `{$suffix}` - .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - .tuple_exception_line_3 = see issue #60210 for more information parse_invalid_logical_operator = `{$incorrect}` is not a logical operator .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index a105dd1909e93..8a10e7d05ebeb 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1016,10 +1016,6 @@ pub(crate) struct InvalidLiteralSuffixOnTupleIndex { #[label] pub span: Span, pub suffix: Symbol, - #[help(parse_tuple_exception_line_1)] - #[help(parse_tuple_exception_line_2)] - #[help(parse_tuple_exception_line_3)] - pub exception: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index d0604f763171b..7d33f3de15cc4 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1163,7 +1163,10 @@ impl<'a> Parser<'a> { suffix, }) => { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(current.span, suffix); + self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { + span: current.span, + suffix, + }); } match self.break_up_float(symbol, current.span) { // 1e2 @@ -1239,7 +1242,8 @@ impl<'a> Parser<'a> { suffix: Option, ) -> Box { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(ident_span, suffix); + self.dcx() + .emit_err(errors::InvalidLiteralSuffixOnTupleIndex { span: ident_span, suffix }); } self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span))) } @@ -2225,24 +2229,6 @@ impl<'a> Parser<'a> { }) } - pub(super) fn expect_no_tuple_index_suffix(&self, span: Span, suffix: Symbol) { - if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) { - // #59553: warn instead of reject out of hand to allow the fix to percolate - // through the ecosystem when people fix their macros - self.dcx().emit_warn(errors::InvalidLiteralSuffixOnTupleIndex { - span, - suffix, - exception: true, - }); - } else { - self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { - span, - suffix, - exception: false, - }); - } - } - /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). /// Keep this in sync with `Token::can_begin_literal_maybe_minus`. pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, Box> { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 41ed1f95a010f..db72faf4ec7a7 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1333,7 +1333,10 @@ impl<'a> Parser<'a> { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(self.token.span, suffix); + self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { + span: self.token.span, + suffix, + }); } self.bump(); Ok(Ident::new(symbol, self.prev_token.span)) diff --git a/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs b/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs index fa40ed948a623..a5084b55aac79 100644 --- a/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs +++ b/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs @@ -18,14 +18,14 @@ pub fn bad_tup_indexing(input: TokenStream) -> TokenStream { pub fn bad_tup_struct_indexing(input: TokenStream) -> TokenStream { let mut input = input.into_iter(); - let id_tt = input.next().unwrap(); + let ident = input.next().unwrap(); let _comma = input.next().unwrap(); - let tt = input.next().unwrap(); + let lit = input.next().unwrap(); - let TokenTree::Ident(ident) = id_tt else { + let TokenTree::Ident(ident) = ident else { unreachable!("id"); }; - let TokenTree::Literal(indexing_expr) = tt else { + let TokenTree::Literal(indexing_expr) = lit else { unreachable!("lit"); }; diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.rs b/tests/ui/parser/tuple-index-suffix-proc-macro.rs index feca6f9cdfb06..557c67738d30f 100644 --- a/tests/ui/parser/tuple-index-suffix-proc-macro.rs +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.rs @@ -11,12 +11,13 @@ fn main() { struct TupStruct(i32); let tup_struct = TupStruct(42); - // #60186 carve outs `{i,u}{32,usize}` as non-lint pseudo-FCW warnings. + // Previously, #60186 had carve outs for `{i,u}{32,usize}` as non-lint pseudo-FCW warnings. Now, + // they all hard error. aux::bad_tup_indexing!(0usize); - //~^ WARN suffixes on a tuple index are invalid + //~^ ERROR suffixes on a tuple index are invalid aux::bad_tup_struct_indexing!(tup_struct, 0isize); - //~^ WARN suffixes on a tuple index are invalid + //~^ ERROR suffixes on a tuple index are invalid // Not part of the #60186 carve outs. diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.stderr b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr index c8bc3a4576b40..47d179d355513 100644 --- a/tests/ui/parser/tuple-index-suffix-proc-macro.stderr +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr @@ -1,34 +1,26 @@ -warning: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix-proc-macro.rs:16:28 +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:17:28 | LL | aux::bad_tup_indexing!(0usize); | ^^^^^^ invalid suffix `usize` - | - = help: `usize` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - = help: see issue #60210 for more information -warning: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix-proc-macro.rs:18:47 +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:19:47 | LL | aux::bad_tup_struct_indexing!(tup_struct, 0isize); | ^^^^^^ invalid suffix `isize` - | - = help: `isize` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - = help: see issue #60210 for more information error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix-proc-macro.rs:23:28 + --> $DIR/tuple-index-suffix-proc-macro.rs:24:28 | LL | aux::bad_tup_indexing!(0u8); | ^^^ invalid suffix `u8` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix-proc-macro.rs:25:47 + --> $DIR/tuple-index-suffix-proc-macro.rs:26:47 | LL | aux::bad_tup_struct_indexing!(tup_struct, 0u64); | ^^^^ invalid suffix `u64` -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to 4 previous errors diff --git a/tests/ui/parser/tuple-index-suffix.rs b/tests/ui/parser/tuple-index-suffix.rs index 31c5bc25063dd..c476950000545 100644 --- a/tests/ui/parser/tuple-index-suffix.rs +++ b/tests/ui/parser/tuple-index-suffix.rs @@ -1,8 +1,10 @@ -//! See #60210. +//! Regression test for both the original regression in #59418 where invalid suffixes in indexing +//! positions were accidentally accepted, and also for the removal of the temporary carve out that +//! mitigated ecosystem impact following trying to reject #59418 (this was implemented as a FCW +//! tracked in #60210). //! //! Check that we hard error on invalid suffixes in tuple indexing subexpressions and struct numeral -//! field names, modulo carve-outs for `{i,u}{32,usize}` at warning level to mitigate ecosystem -//! impact. +//! field names. struct X(i32,i32,i32); @@ -10,28 +12,28 @@ fn main() { let tup_struct = X(1, 2, 3); let invalid_tup_struct_suffix = tup_struct.0suffix; //~^ ERROR suffixes on a tuple index are invalid - let carve_out_tup_struct_suffix = tup_struct.0i32; - //~^ WARN suffixes on a tuple index are invalid + let previous_carve_out_tup_struct_suffix = tup_struct.0i32; + //~^ ERROR suffixes on a tuple index are invalid let tup = (1, 2, 3); let invalid_tup_suffix = tup.0suffix; //~^ ERROR suffixes on a tuple index are invalid - let carve_out_tup_suffix = tup.0u32; - //~^ WARN suffixes on a tuple index are invalid + let previous_carve_out_tup_suffix = tup.0u32; + //~^ ERROR suffixes on a tuple index are invalid numeral_struct_field_name_suffix_invalid(); - numeral_struct_field_name_suffix_carve_out(); + numeral_struct_field_name_suffix_previous_carve_out(); } -// Very limited carve outs as a ecosystem impact mitigation implemented in #60186. *Only* -// `{i,u}{32,usize}` suffixes are temporarily accepted. -fn carve_outs() { - // Ok, only pseudo-FCW warnings. +// Previously, there were very limited carve outs as a ecosystem impact mitigation implemented in +// #60186. *Only* `{i,u}{32,usize}` suffixes were temporarily accepted. Now, they all hard error. +fn previous_carve_outs() { + // Previously temporarily accepted by a pseudo-FCW (#60210), now hard error. - let carve_out_i32 = (42,).0i32; //~ WARN suffixes on a tuple index are invalid - let carve_out_i32 = (42,).0u32; //~ WARN suffixes on a tuple index are invalid - let carve_out_isize = (42,).0isize; //~ WARN suffixes on a tuple index are invalid - let carve_out_usize = (42,).0usize; //~ WARN suffixes on a tuple index are invalid + let previous_carve_out_i32 = (42,).0i32; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_i32 = (42,).0u32; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_isize = (42,).0isize; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_usize = (42,).0usize; //~ ERROR suffixes on a tuple index are invalid // Not part of the carve outs! let error_i8 = (42,).0i8; //~ ERROR suffixes on a tuple index are invalid @@ -53,12 +55,12 @@ fn numeral_struct_field_name_suffix_invalid() { } } -fn numeral_struct_field_name_suffix_carve_out() { +fn numeral_struct_field_name_suffix_previous_carve_out() { let carve_out_struct_name = X { 0u32: 0, 1: 1, 2: 2 }; - //~^ WARN suffixes on a tuple index are invalid + //~^ ERROR suffixes on a tuple index are invalid match carve_out_struct_name { X { 0u32: _, .. } => {} - //~^ WARN suffixes on a tuple index are invalid + //~^ ERROR suffixes on a tuple index are invalid } } @@ -67,9 +69,9 @@ fn offset_of_suffix() { #[repr(C)] pub struct Struct(u8, T); - // Carve outs + // Previous pseudo-FCW carve outs assert_eq!(std::mem::offset_of!(Struct, 0usize), 0); - //~^ WARN suffixes on a tuple index are invalid + //~^ ERROR suffixes on a tuple index are invalid // Not part of carve outs assert_eq!(std::mem::offset_of!(Struct, 0u8), 0); diff --git a/tests/ui/parser/tuple-index-suffix.stderr b/tests/ui/parser/tuple-index-suffix.stderr index 3a499dd6a8dff..6d96c6d3cbf88 100644 --- a/tests/ui/parser/tuple-index-suffix.stderr +++ b/tests/ui/parser/tuple-index-suffix.stderr @@ -1,170 +1,134 @@ error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:11:48 + --> $DIR/tuple-index-suffix.rs:13:48 | LL | let invalid_tup_struct_suffix = tup_struct.0suffix; | ^^^^^^^ invalid suffix `suffix` -warning: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:13:50 - | -LL | let carve_out_tup_struct_suffix = tup_struct.0i32; - | ^^^^ invalid suffix `i32` +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:15:59 | - = help: `i32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - = help: see issue #60210 for more information +LL | let previous_carve_out_tup_struct_suffix = tup_struct.0i32; + | ^^^^ invalid suffix `i32` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:17:34 + --> $DIR/tuple-index-suffix.rs:19:34 | LL | let invalid_tup_suffix = tup.0suffix; | ^^^^^^^ invalid suffix `suffix` -warning: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:19:36 - | -LL | let carve_out_tup_suffix = tup.0u32; - | ^^^^ invalid suffix `u32` +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:21:45 | - = help: `u32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - = help: see issue #60210 for more information +LL | let previous_carve_out_tup_suffix = tup.0u32; + | ^^^^ invalid suffix `u32` -warning: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:31:31 - | -LL | let carve_out_i32 = (42,).0i32; - | ^^^^ invalid suffix `i32` +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:33:40 | - = help: `i32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - = help: see issue #60210 for more information +LL | let previous_carve_out_i32 = (42,).0i32; + | ^^^^ invalid suffix `i32` -warning: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:32:31 - | -LL | let carve_out_i32 = (42,).0u32; - | ^^^^ invalid suffix `u32` +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:34:40 | - = help: `u32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - = help: see issue #60210 for more information +LL | let previous_carve_out_i32 = (42,).0u32; + | ^^^^ invalid suffix `u32` -warning: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:33:33 - | -LL | let carve_out_isize = (42,).0isize; - | ^^^^^^ invalid suffix `isize` +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:35:42 | - = help: `isize` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - = help: see issue #60210 for more information +LL | let previous_carve_out_isize = (42,).0isize; + | ^^^^^^ invalid suffix `isize` -warning: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:34:33 - | -LL | let carve_out_usize = (42,).0usize; - | ^^^^^^ invalid suffix `usize` +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:36:42 | - = help: `usize` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - = help: see issue #60210 for more information +LL | let previous_carve_out_usize = (42,).0usize; + | ^^^^^^ invalid suffix `usize` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:37:26 + --> $DIR/tuple-index-suffix.rs:39:26 | LL | let error_i8 = (42,).0i8; | ^^^ invalid suffix `i8` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:38:26 + --> $DIR/tuple-index-suffix.rs:40:26 | LL | let error_u8 = (42,).0u8; | ^^^ invalid suffix `u8` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:39:27 + --> $DIR/tuple-index-suffix.rs:41:27 | LL | let error_i16 = (42,).0i16; | ^^^^ invalid suffix `i16` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:40:27 + --> $DIR/tuple-index-suffix.rs:42:27 | LL | let error_u16 = (42,).0u16; | ^^^^ invalid suffix `u16` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:41:27 + --> $DIR/tuple-index-suffix.rs:43:27 | LL | let error_i64 = (42,).0i64; | ^^^^ invalid suffix `i64` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:42:27 + --> $DIR/tuple-index-suffix.rs:44:27 | LL | let error_u64 = (42,).0u64; | ^^^^ invalid suffix `u64` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:43:28 + --> $DIR/tuple-index-suffix.rs:45:28 | LL | let error_i128 = (42,).0i128; | ^^^^^ invalid suffix `i128` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:44:28 + --> $DIR/tuple-index-suffix.rs:46:28 | LL | let error_u128 = (42,).0u128; | ^^^^^ invalid suffix `u128` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:48:35 + --> $DIR/tuple-index-suffix.rs:50:35 | LL | let invalid_struct_name = X { 0suffix: 0, 1: 1, 2: 2 }; | ^^^^^^^ invalid suffix `suffix` error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:51:13 + --> $DIR/tuple-index-suffix.rs:53:13 | LL | X { 0suffix: _, .. } => {} | ^^^^^^^ invalid suffix `suffix` -warning: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:57:37 +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:59:37 | LL | let carve_out_struct_name = X { 0u32: 0, 1: 1, 2: 2 }; | ^^^^ invalid suffix `u32` - | - = help: `u32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - = help: see issue #60210 for more information -warning: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:60:13 +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:62:13 | LL | X { 0u32: _, .. } => {} | ^^^^ invalid suffix `u32` - | - = help: `u32` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - = help: see issue #60210 for more information -warning: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:71:50 +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:73:50 | LL | assert_eq!(std::mem::offset_of!(Struct, 0usize), 0); | ^^^^^^ invalid suffix `usize` - | - = help: `usize` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - = help: on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - = help: see issue #60210 for more information error: suffixes on a tuple index are invalid - --> $DIR/tuple-index-suffix.rs:75:50 + --> $DIR/tuple-index-suffix.rs:77:50 | LL | assert_eq!(std::mem::offset_of!(Struct, 0u8), 0); | ^^^ invalid suffix `u8` -error: aborting due to 13 previous errors; 9 warnings emitted +error: aborting due to 22 previous errors From b0897f31b998472d024a2e00a7b00c5fc875351e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 29 Aug 2025 15:06:54 +0000 Subject: [PATCH 5/9] Update getopts to remove unicode-width dependency --- Cargo.lock | 6 +++--- library/Cargo.lock | 15 ++------------- library/test/Cargo.toml | 2 +- src/tools/tidy/src/deps.rs | 1 - 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 91528a4135e32..82ba9ce178aad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -674,7 +674,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ "serde", "termcolor", - "unicode-width 0.2.1", + "unicode-width 0.1.14", ] [[package]] @@ -1470,9 +1470,9 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ "unicode-width 0.2.1", ] diff --git a/library/Cargo.lock b/library/Cargo.lock index f0ac9d259c0db..3fb6af2c59821 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -99,13 +99,12 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ "rustc-std-workspace-core", "rustc-std-workspace-std", - "unicode-width", ] [[package]] @@ -360,16 +359,6 @@ dependencies = [ "std", ] -[[package]] -name = "unicode-width" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" -dependencies = [ - "rustc-std-workspace-core", - "rustc-std-workspace-std", -] - [[package]] name = "unwind" version = "0.0.0" diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 2a32a7dd76eed..fe749847b7c00 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -6,7 +6,7 @@ version = "0.0.0" edition = "2024" [dependencies] -getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } +getopts = { version = "0.2.24", default-features = false, features = ['rustc-dep-of-std'] } std = { path = "../std", public = true } core = { path = "../core", public = true } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 80b6d54ce1c80..4efaf1fb77167 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -478,7 +478,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "rustc-demangle", "rustc-literal-escaper", "shlex", - "unicode-width", "unwinding", "wasi", "windows-sys", From 2f0c1035ed7a1ad2348565c8d3fc4c5c3e758a24 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Wed, 27 Aug 2025 10:04:05 -0400 Subject: [PATCH 6/9] fix APITIT being treated as a normal generic parameter in suggestions --- compiler/rustc_hir_analysis/src/check/mod.rs | 73 ++++++++++++------- .../apitit-unimplemented-method.rs | 12 +++ .../apitit-unimplemented-method.stderr | 12 +++ tests/ui/suggestions/auxiliary/dep.rs | 4 + 4 files changed, 74 insertions(+), 27 deletions(-) create mode 100644 tests/ui/suggestions/apitit-unimplemented-method.rs create mode 100644 tests/ui/suggestions/apitit-unimplemented-method.stderr create mode 100644 tests/ui/suggestions/auxiliary/dep.rs diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 85445cb3c004d..e4c1e304c4b3d 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -85,7 +85,9 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::print::with_types_for_signature; -use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{ + self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypingMode, +}; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; @@ -232,8 +234,7 @@ fn missing_items_err( }; // Obtain the level of indentation ending in `sugg_sp`. - let padding = - tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); + let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new); let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) = (Vec::new(), Vec::new(), Vec::new()); @@ -330,6 +331,7 @@ fn default_body_is_unstable( fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: impl IntoIterator, Span)>, + assoc: ty::AssocItem, ) -> (String, String) { let mut types: FxIndexMap, Vec> = FxIndexMap::default(); let mut projections = vec![]; @@ -353,34 +355,50 @@ fn bounds_from_generic_predicates<'tcx>( } let mut where_clauses = vec![]; - let mut types_str = vec![]; - for (ty, bounds) in types { - if let ty::Param(_) = ty.kind() { - let mut bounds_str = vec![]; - for bound in bounds { - let mut projections_str = vec![]; - for projection in &projections { - let p = projection.skip_binder(); - if bound == tcx.parent(p.projection_term.def_id) - && p.projection_term.self_ty() == ty - { - let name = tcx.item_name(p.projection_term.def_id); - projections_str.push(format!("{} = {}", name, p.term)); + let generics = tcx.generics_of(assoc.def_id); + let types_str = generics + .own_params + .iter() + .filter(|p| matches!(p.kind, GenericParamDefKind::Type { synthetic: false, .. })) + .map(|p| { + // we just checked that it's a type, so the unwrap can't fail + let ty = tcx.mk_param_from_def(p).as_type().unwrap(); + if let Some(bounds) = types.get(&ty) { + let mut bounds_str = vec![]; + for bound in bounds.iter().copied() { + let mut projections_str = vec![]; + for projection in &projections { + let p = projection.skip_binder(); + if bound == tcx.parent(p.projection_term.def_id) + && p.projection_term.self_ty() == ty + { + let name = tcx.item_name(p.projection_term.def_id); + projections_str.push(format!("{} = {}", name, p.term)); + } + } + let bound_def_path = tcx.def_path_str(bound); + if projections_str.is_empty() { + where_clauses.push(format!("{}: {}", ty, bound_def_path)); + } else { + bounds_str.push(format!( + "{}<{}>", + bound_def_path, + projections_str.join(", ") + )); } } - let bound_def_path = tcx.def_path_str(bound); - if projections_str.is_empty() { - where_clauses.push(format!("{}: {}", ty, bound_def_path)); + if bounds_str.is_empty() { + ty.to_string() } else { - bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", "))); + format!("{}: {}", ty, bounds_str.join(" + ")) } - } - if bounds_str.is_empty() { - types_str.push(ty.to_string()); } else { - types_str.push(format!("{}: {}", ty, bounds_str.join(" + "))); + ty.to_string() } - } else { + }) + .collect::>(); + for (ty, bounds) in types.into_iter() { + if !matches!(ty.kind(), ty::Param(_)) { // Avoid suggesting the following: // fn foo::Bar>(_: T) where T: Trait, ::Bar: Other {} where_clauses.extend( @@ -472,10 +490,10 @@ fn fn_sig_suggestion<'tcx>( let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() }; let safety = sig.safety.prefix_str(); - let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates); + let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates, assoc); // FIXME: this is not entirely correct, as the lifetimes from borrowed params will - // not be present in the `fn` definition, not will we account for renamed + // not be present in the `fn` definition, nor will we account for renamed // lifetimes between the `impl` and the `trait`, but this should be good enough to // fill in a significant portion of the missing code, and other subsequent // suggestions can help the user fix the code. @@ -511,6 +529,7 @@ fn suggestion_signature<'tcx>( let (generics, where_clauses) = bounds_from_generic_predicates( tcx, tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), + assoc, ); format!("type {}{generics} = /* Type */{where_clauses};", assoc.name()) } diff --git a/tests/ui/suggestions/apitit-unimplemented-method.rs b/tests/ui/suggestions/apitit-unimplemented-method.rs new file mode 100644 index 0000000000000..b182e1939b3e3 --- /dev/null +++ b/tests/ui/suggestions/apitit-unimplemented-method.rs @@ -0,0 +1,12 @@ +//@ aux-build:dep.rs + +extern crate dep; +use dep::*; + +struct Local; +impl Trait for Local {} +//~^ ERROR not all trait items implemented +//~| HELP implement the missing item: `fn foo(_: impl Sized) { todo!() }` +//~| HELP implement the missing item: `fn bar(_: impl Sized) { todo!() }` + +fn main() {} diff --git a/tests/ui/suggestions/apitit-unimplemented-method.stderr b/tests/ui/suggestions/apitit-unimplemented-method.stderr new file mode 100644 index 0000000000000..b309a64e95829 --- /dev/null +++ b/tests/ui/suggestions/apitit-unimplemented-method.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `foo`, `bar` + --> $DIR/apitit-unimplemented-method.rs:7:1 + | +LL | impl Trait for Local {} + | ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar` in implementation + | + = help: implement the missing item: `fn foo(_: impl Sized) { todo!() }` + = help: implement the missing item: `fn bar(_: impl Sized) { todo!() }` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/suggestions/auxiliary/dep.rs b/tests/ui/suggestions/auxiliary/dep.rs new file mode 100644 index 0000000000000..ac0de418313c0 --- /dev/null +++ b/tests/ui/suggestions/auxiliary/dep.rs @@ -0,0 +1,4 @@ +pub trait Trait { + fn foo(_: impl Sized); + fn bar(_: impl Sized); +} From c63e03490692c2e90e927bae35f51a1f59252868 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Sep 2025 08:31:52 +0200 Subject: [PATCH 7/9] triagebot: warn about #[rustc_intrinsic_const_stable_indirect]; make warnings a bit more noticeable --- triagebot.toml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index bf9bfee4306d0..2d58c616bc278 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1308,21 +1308,32 @@ cc = ["@m-ou-se"] [mentions."compiler/rustc_ast_lowering/src/format.rs"] cc = ["@m-ou-se"] +# Content-based mentions + [mentions."#[miri::intrinsic_fallback_is_spec]"] type = "content" message = """ -`#[miri::intrinsic_fallback_is_spec]` must only be used if the function actively checks for all UB cases, +⚠️ `#[miri::intrinsic_fallback_is_spec]` must only be used if the function actively checks for all UB cases, and explores the possible non-determinism of the intrinsic. """ cc = ["@rust-lang/miri"] + [mentions."#[rustc_allow_const_fn_unstable"] type = "content" message = """ -`#[rustc_allow_const_fn_unstable]` needs careful audit to avoid accidentally exposing unstable +⚠️ `#[rustc_allow_const_fn_unstable]` needs careful audit to avoid accidentally exposing unstable implementation details on stable. """ cc = ["@rust-lang/wg-const-eval"] +[mentions."#[rustc_intrinsic_const_stable_indirect]"] +type = "content" +message = """ +⚠️ `#[rustc_intrinsic_const_stable_indirect]` controls whether intrinsics can be exposed to stable const +code; adding it needs t-lang approval. +""" +cc = ["@rust-lang/wg-const-eval"] + # ------------------------------------------------------------------------------ # PR assignments From c4cbb54f3f01b1e2c1927049d04f98d677734c3a Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 9 Sep 2025 09:49:48 +0200 Subject: [PATCH 8/9] add approx_delta to all gamma tests --- library/std/tests/floats/f32.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs index c29d803b25e41..3acd067091415 100644 --- a/library/std/tests/floats/f32.rs +++ b/library/std/tests/floats/f32.rs @@ -193,13 +193,13 @@ fn test_atanh() { #[test] fn test_gamma() { // precision can differ between platforms - assert_approx_eq!(1.0f32.gamma(), 1.0f32); - assert_approx_eq!(2.0f32.gamma(), 1.0f32); - assert_approx_eq!(3.0f32.gamma(), 2.0f32); + assert_approx_eq!(1.0f32.gamma(), 1.0f32, APPROX_DELTA); + assert_approx_eq!(2.0f32.gamma(), 1.0f32, APPROX_DELTA); + assert_approx_eq!(3.0f32.gamma(), 2.0f32, APPROX_DELTA); assert_approx_eq!(4.0f32.gamma(), 6.0f32, APPROX_DELTA); assert_approx_eq!(5.0f32.gamma(), 24.0f32, APPROX_DELTA); - assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt()); - assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt()); + assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt(), APPROX_DELTA); + assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt(), APPROX_DELTA); assert_eq!(0.0f32.gamma(), f32::INFINITY); assert_eq!((-0.0f32).gamma(), f32::NEG_INFINITY); assert!((-1.0f32).gamma().is_nan()); From 7c20f9c5888ff8ebe66997c2eca504a521d49dd8 Mon Sep 17 00:00:00 2001 From: calvinhirsch Date: Tue, 9 Sep 2025 10:09:09 -0400 Subject: [PATCH 9/9] fix comments about trait solver cycle heads --- compiler/rustc_type_ir/src/search_graph/mod.rs | 4 ++-- compiler/rustc_type_ir/src/search_graph/stack.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index dbbc0c217d7d4..8f8f019510fe8 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -1262,7 +1262,7 @@ impl, X: Cx> SearchGraph { encountered_overflow |= stack_entry.encountered_overflow; debug_assert_eq!(stack_entry.input, input); - // If the current goal is not the root of a cycle, we are done. + // If the current goal is not a cycle head, we are done. // // There are no provisional cache entries which depend on this goal. let Some(usages) = stack_entry.usages else { @@ -1278,7 +1278,7 @@ impl, X: Cx> SearchGraph { // // Check whether we reached a fixpoint, either because the final result // is equal to the provisional result of the previous iteration, or because - // this was only the root of either coinductive or inductive cycles, and the + // this was only the head of either coinductive or inductive cycles, and the // final result is equal to the initial response for that case. if self.reached_fixpoint(cx, &stack_entry, usages, result) { self.rebase_provisional_cache_entries(&stack_entry, |_, result| result); diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs index 3fd8e2bd16e4e..8348666be412d 100644 --- a/compiler/rustc_type_ir/src/search_graph/stack.rs +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs @@ -13,7 +13,7 @@ rustc_index::newtype_index! { pub(super) struct StackDepth {} } -/// Stack entries of the evaluation stack. Its fields tend to be lazily +/// Stack entries of the evaluation stack. Its fields tend to be lazily updated /// when popping a child goal or completely immutable. #[derive_where(Debug; X: Cx)] pub(super) struct StackEntry { @@ -42,7 +42,7 @@ pub(super) struct StackEntry { /// Whether evaluating this goal encountered overflow. Lazily updated. pub encountered_overflow: bool, - /// Whether and how this goal has been used as the root of a cycle. Lazily updated. + /// Whether and how this goal has been used as a cycle head. Lazily updated. pub usages: Option, /// We want to be able to ignore head usages if they happen inside of candidates