Skip to content

Commit 3f95507

Browse files
authored
Unrolled build for #145463
Rollup merge of #145463 - jieyouxu:error-suffix, r=fmease Reject invalid literal suffixes in tuple indexing, tuple struct indexing, and struct field name position Tracking issue: #60210 Closes #60210 ## Summary Bump the ["suffixes on a tuple index are invalid" non-lint pseudo future-incompatibility warning (#60210)][issue-60210][^non-lint] to a **hard error** across all editions, rejecting the remaining carve outs from accidentally accepted invalid suffixes since Rust **1.27**. - We accidentally accepted invalid suffixes in tuple indexing positions in Rust **1.27**. Originally reported at #59418. - We tried to hard reject all invalid suffixes in #59421, but unfortunately it turns out there were proc macros accidentally relying on it: #60138. - We temporarily accepted `{i,u}{32,size}` in #60186 (the "*carve outs*") to mitigate *immediate* ecosystem impact, but it came with an FCW warning indicating that we wanted to reject it after a few Rust releases. - Now (1.89.0) is a few Rust releases later (1.35.0), thus I'm proposing to **also reject the carve outs**. - `std::mem::offset_of!` stabilized in Rust **1.77.0** happens to use the same "don't expect suffix" code path which has the carve outs, so it also accepted the carve out suffixes. I'm proposing to **reject this case as well**. ## What specifically breaks? Code that still relied on invalid `{i,u}{32,size}` suffixes being temporarily accepted by #60186 as an ecosystem impact mitigation measure (cf. #60138). Specifically, the following cases (particularly the construction of these forms in proc macros like reported in #60138): ### Position 1: Invalid `{i,u}{32,size}` suffixes in tuple indexing ```rs fn main() { let _x = (42,).0invalid; // Already error, already rejected by #59421 let _x = (42,).0i8; // Already error, not one of the #60186 carve outs. let _x = (42,).0usize; // warning: suffixes on a tuple index are invalid } ``` ### Position 2: Invalid `{i,u}{32,size}` suffixes in tuple struct indexing ```rs fn main() { struct X(i32); let _x = X(42); let _x = _x.0invalid; // Already error, already rejected by #59421 let _x = _x.0i8; // Already error, not one of the #60186 carve outs. let _x = _x.0usize; // warning: suffixes on a tuple index are invalid } ``` ### Position 3: Invalid `{i,u}{32,size}` suffixes in numeric struct field names ```rs fn main() { struct X(i32, i32, i32); let _x = X(1, 2, 3); let _y = X { 0usize: 42, 1: 42, 2: 42 }; // warning: suffixes on a tuple index are invalid match _x { X { 0usize: 1, 1: 2, 2: 3 } => todo!(), // warning: suffixes on a tuple index are invalid _ => {} } } ``` ### Position 4: Invalid `{i,u}{32,size}` suffixes in `std::mem::offset_of!` While investigating the warning, unfortunately I noticed `std::mem::offset_of!` also happens to use the "expect no suffix" code path which had the carve outs. So this was accepted since Rust **1.77.0** with the same FCW: ```rs fn main() { #[repr(C)] pub struct Struct<T>(u8, T); assert_eq!(std::mem::offset_of!(Struct<u32>, 0usize), 0); //~^ WARN suffixes on a tuple index are invalid } ``` ### The above forms in proc macros For instance, constructions like (see tracking issue #60210): ```rs let i = 0; quote! { foo.$i } ``` where the user needs to actually write ```rs let i = syn::Index::from(0); quote! { foo.$i } ``` ### Crater results Conducted a crater run (#145463 (comment)). - https://github.com/AmlingPalantir/r4/tree/256af3c72f094b298cd442097ef7c571d8001f29: genuine regression; "invalid suffix `usize`" in derive macro. Has a ton of other build warnings, last updated 6 years ago. - Exactly the kind of intended breakage. Minimized down to https://github.com/AmlingPalantir/r4/blob/256af3c72f094b298cd442097ef7c571d8001f29/validates_derive/src/lib.rs#L71-L75, where when interpolation uses `quote`'s `ToTokens` on a `usize` index (i.e. on tuple struct `Tup(())`), the generated suffix becomes `.0usize` (cf. Position 2). - Notified crate author of breakage in AmlingPalantir/r4#1. - Other failures are unrelated or spurious. ## Review remarks - Commits 1-3 expands the test coverage to better reflect the current situation before doing any functional changes. - Commit 4 is an intentional **breaking change**. We bump the non-lint "suffixes on a tuple index are invalid" warning into a hard error. Thus, this will need a crater run and a T-lang FCP. ## Tasks - [x] Run crater to check if anyone is still relying on this being not a hard error. Determine degree of ecosystem breakage. - [x] If degree of breakage seems acceptable, draft nomination report for T-lang for FCP. - [x] Determine hard error on Edition 2024+, or on all editions. ## Accompanying Reference update - rust-lang/reference#1966 [^non-lint]: The FCW was implemented as a *non-lint* warning (meaning it has no associated lint name, and you can't `#![deny(..)]` it) because spans coming from proc macros could not be distinguished from regular field access. This warning was also intentionally impossible to silence. See #60186 (comment). [issue-60210]: #60210
2 parents 364da5d + ddd9993 commit 3f95507

File tree

12 files changed

+314
-73
lines changed

12 files changed

+314
-73
lines changed

compiler/rustc_parse/messages.ftl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -479,9 +479,6 @@ parse_invalid_identifier_with_leading_number = identifiers cannot start with a n
479479
480480
parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
481481
.label = invalid suffix `{$suffix}`
482-
.tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
483-
.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
484-
.tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information
485482
486483
parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
487484
.note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators

compiler/rustc_parse/src/errors.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,10 +1017,6 @@ pub(crate) struct InvalidLiteralSuffixOnTupleIndex {
10171017
#[label]
10181018
pub span: Span,
10191019
pub suffix: Symbol,
1020-
#[help(parse_tuple_exception_line_1)]
1021-
#[help(parse_tuple_exception_line_2)]
1022-
#[help(parse_tuple_exception_line_3)]
1023-
pub exception: bool,
10241020
}
10251021

10261022
#[derive(Diagnostic)]

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,7 +1163,10 @@ impl<'a> Parser<'a> {
11631163
suffix,
11641164
}) => {
11651165
if let Some(suffix) = suffix {
1166-
self.expect_no_tuple_index_suffix(current.span, suffix);
1166+
self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex {
1167+
span: current.span,
1168+
suffix,
1169+
});
11671170
}
11681171
match self.break_up_float(symbol, current.span) {
11691172
// 1e2
@@ -1239,7 +1242,8 @@ impl<'a> Parser<'a> {
12391242
suffix: Option<Symbol>,
12401243
) -> Box<Expr> {
12411244
if let Some(suffix) = suffix {
1242-
self.expect_no_tuple_index_suffix(ident_span, suffix);
1245+
self.dcx()
1246+
.emit_err(errors::InvalidLiteralSuffixOnTupleIndex { span: ident_span, suffix });
12431247
}
12441248
self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span)))
12451249
}
@@ -2225,24 +2229,6 @@ impl<'a> Parser<'a> {
22252229
})
22262230
}
22272231

2228-
pub(super) fn expect_no_tuple_index_suffix(&self, span: Span, suffix: Symbol) {
2229-
if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) {
2230-
// #59553: warn instead of reject out of hand to allow the fix to percolate
2231-
// through the ecosystem when people fix their macros
2232-
self.dcx().emit_warn(errors::InvalidLiteralSuffixOnTupleIndex {
2233-
span,
2234-
suffix,
2235-
exception: true,
2236-
});
2237-
} else {
2238-
self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex {
2239-
span,
2240-
suffix,
2241-
exception: false,
2242-
});
2243-
}
2244-
}
2245-
22462232
/// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
22472233
/// Keep this in sync with `Token::can_begin_literal_maybe_minus`.
22482234
pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, Box<Expr>> {

compiler/rustc_parse/src/parser/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1335,7 +1335,10 @@ impl<'a> Parser<'a> {
13351335
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind
13361336
{
13371337
if let Some(suffix) = suffix {
1338-
self.expect_no_tuple_index_suffix(self.token.span, suffix);
1338+
self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex {
1339+
span: self.token.span,
1340+
suffix,
1341+
});
13391342
}
13401343
self.bump();
13411344
Ok(Ident::new(symbol, self.prev_token.span))

src/tools/tidy/src/issues.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2021,7 +2021,6 @@ ui/parser/issues/issue-5806.rs
20212021
ui/parser/issues/issue-58094-missing-right-square-bracket.rs
20222022
ui/parser/issues/issue-58856-1.rs
20232023
ui/parser/issues/issue-58856-2.rs
2024-
ui/parser/issues/issue-59418.rs
20252024
ui/parser/issues/issue-60075.rs
20262025
ui/parser/issues/issue-61858.rs
20272026
ui/parser/issues/issue-62524.rs
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#![feature(proc_macro_quote, proc_macro_span)]
2+
3+
extern crate proc_macro;
4+
5+
use proc_macro::{Ident, Literal, Span, TokenStream, TokenTree, quote};
6+
7+
#[proc_macro]
8+
pub fn bad_tup_indexing(input: TokenStream) -> TokenStream {
9+
let tt = input.into_iter().next().unwrap();
10+
let TokenTree::Literal(indexing_expr) = tt else {
11+
unreachable!();
12+
};
13+
quote! { (42,).$indexing_expr }
14+
}
15+
16+
// Expects {IDENT, COMMA, LITERAL}
17+
#[proc_macro]
18+
pub fn bad_tup_struct_indexing(input: TokenStream) -> TokenStream {
19+
let mut input = input.into_iter();
20+
21+
let ident = input.next().unwrap();
22+
let _comma = input.next().unwrap();
23+
let lit = input.next().unwrap();
24+
25+
let TokenTree::Ident(ident) = ident else {
26+
unreachable!("id");
27+
};
28+
let TokenTree::Literal(indexing_expr) = lit else {
29+
unreachable!("lit");
30+
};
31+
32+
quote! { $ident.$indexing_expr }
33+
}

tests/ui/parser/issues/issue-59418.rs

Lines changed: 0 additions & 18 deletions
This file was deleted.

tests/ui/parser/issues/issue-59418.stderr

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//! See #59418.
2+
//!
3+
//! Like `tuple-index-suffix.rs`, but exercises the proc-macro interaction.
4+
5+
//@ proc-macro: tuple-index-suffix-proc-macro-aux.rs
6+
7+
extern crate tuple_index_suffix_proc_macro_aux;
8+
use tuple_index_suffix_proc_macro_aux as aux;
9+
10+
fn main() {
11+
struct TupStruct(i32);
12+
let tup_struct = TupStruct(42);
13+
14+
// Previously, #60186 had carve outs for `{i,u}{32,usize}` as non-lint pseudo-FCW warnings. Now,
15+
// they all hard error.
16+
17+
aux::bad_tup_indexing!(0usize);
18+
//~^ ERROR suffixes on a tuple index are invalid
19+
aux::bad_tup_struct_indexing!(tup_struct, 0isize);
20+
//~^ ERROR suffixes on a tuple index are invalid
21+
22+
// Not part of the #60186 carve outs.
23+
24+
aux::bad_tup_indexing!(0u8);
25+
//~^ ERROR suffixes on a tuple index are invalid
26+
aux::bad_tup_struct_indexing!(tup_struct, 0u64);
27+
//~^ ERROR suffixes on a tuple index are invalid
28+
29+
// NOTE: didn't bother with trying to figure out how to generate `struct P { 0u32: u32 }` using
30+
// *only* `proc_macro` without help with `syn`/`quote`, looks like you can't with just
31+
// `proc_macro::quote`?
32+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: suffixes on a tuple index are invalid
2+
--> $DIR/tuple-index-suffix-proc-macro.rs:17:28
3+
|
4+
LL | aux::bad_tup_indexing!(0usize);
5+
| ^^^^^^ invalid suffix `usize`
6+
7+
error: suffixes on a tuple index are invalid
8+
--> $DIR/tuple-index-suffix-proc-macro.rs:19:47
9+
|
10+
LL | aux::bad_tup_struct_indexing!(tup_struct, 0isize);
11+
| ^^^^^^ invalid suffix `isize`
12+
13+
error: suffixes on a tuple index are invalid
14+
--> $DIR/tuple-index-suffix-proc-macro.rs:24:28
15+
|
16+
LL | aux::bad_tup_indexing!(0u8);
17+
| ^^^ invalid suffix `u8`
18+
19+
error: suffixes on a tuple index are invalid
20+
--> $DIR/tuple-index-suffix-proc-macro.rs:26:47
21+
|
22+
LL | aux::bad_tup_struct_indexing!(tup_struct, 0u64);
23+
| ^^^^ invalid suffix `u64`
24+
25+
error: aborting due to 4 previous errors
26+

0 commit comments

Comments
 (0)