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: rust-lang/rust#60210 Closes rust-lang/rust#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 https://github.com/rust-lang/rust/issues/59418. - We tried to hard reject all invalid suffixes in https://github.com/rust-lang/rust/pull/59421, but unfortunately it turns out there were proc macros accidentally relying on it: https://github.com/rust-lang/rust/issues/60138. - We temporarily accepted `{i,u}{32,size}` in https://github.com/rust-lang/rust/pull/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 rust-lang/rust#60186 as an ecosystem impact mitigation measure (cf. rust-lang/rust#60138). Specifically, the following cases (particularly the construction of these forms in proc macros like reported in rust-lang/rust#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 rust-lang/rust#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 (https://github.com/rust-lang/rust/pull/145463#issuecomment-3194920383). -256af3c72f: 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 to256af3c72f/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 https://github.com/AmlingPalantir/r4/issues/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 - https://github.com/rust-lang/reference/pull/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 https://github.com/rust-lang/rust/pull/60186#issuecomment-485581694. [issue-60210]: https://github.com/rust-lang/rust/issues/60210
This commit is contained in:
@@ -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<Symbol>,
|
||||
) -> Box<Expr> {
|
||||
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<Expr>> {
|
||||
|
||||
Reference in New Issue
Block a user