From d74ec96e8d334c765e35707f7b7f3c6499a1b43c Mon Sep 17 00:00:00 2001
From: est31 <MTest31@outlook.com>
Date: Fri, 2 Jun 2023 18:51:27 +0200
Subject: [PATCH 1/3] Move float breaking out of
 Parser::parse_expr_tuple_field_access_float

Purely a refactor in preparation of using it in offset_of!() parsing
---
 compiler/rustc_parse/src/parser/expr.rs | 75 +++++++++++++++++--------
 1 file changed, 53 insertions(+), 22 deletions(-)

diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 1b28f3c97e8..9e5f85dc7dc 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -91,6 +91,18 @@ impl From<P<Expr>> for LhsExpr {
     }
 }
 
+#[derive(Debug)]
+enum DestructuredFloat {
+    /// 1e2
+    Single(Symbol, Span),
+    /// 1.
+    TrailingDot(Symbol, Span, Span),
+    /// 1.2 | 1.2e3
+    MiddleDot(Symbol, Span, Span, Symbol, Span),
+    /// Invalid
+    Error,
+}
+
 impl<'a> Parser<'a> {
     /// Parses an expression.
     #[inline]
@@ -1013,13 +1025,8 @@ impl<'a> Parser<'a> {
     // support pushing "future tokens" (would be also helpful to `break_and_eat`), or
     // we should break everything including floats into more basic proc-macro style
     // tokens in the lexer (probably preferable).
-    fn parse_expr_tuple_field_access_float(
-        &mut self,
-        lo: Span,
-        base: P<Expr>,
-        float: Symbol,
-        suffix: Option<Symbol>,
-    ) -> P<Expr> {
+    // See also `TokenKind::break_two_token_op` which does similar splitting of `>>` into `>`.
+    fn break_up_float(&mut self, float: Symbol) -> DestructuredFloat {
         #[derive(Debug)]
         enum FloatComponent {
             IdentLike(String),
@@ -1056,7 +1063,7 @@ impl<'a> Parser<'a> {
         match &*components {
             // 1e2
             [IdentLike(i)] => {
-                self.parse_expr_tuple_field_access(lo, base, Symbol::intern(&i), suffix, None)
+                DestructuredFloat::Single(Symbol::intern(&i), span)
             }
             // 1.
             [IdentLike(i), Punct('.')] => {
@@ -1068,11 +1075,8 @@ impl<'a> Parser<'a> {
                 } else {
                     (span, span)
                 };
-                assert!(suffix.is_none());
                 let symbol = Symbol::intern(&i);
-                self.token = Token::new(token::Ident(symbol, false), ident_span);
-                let next_token = (Token::new(token::Dot, dot_span), self.token_spacing);
-                self.parse_expr_tuple_field_access(lo, base, symbol, None, Some(next_token))
+                DestructuredFloat::TrailingDot(symbol, ident_span, dot_span)
             }
             // 1.2 | 1.2e3
             [IdentLike(i1), Punct('.'), IdentLike(i2)] => {
@@ -1088,16 +1092,8 @@ impl<'a> Parser<'a> {
                     (span, span, span)
                 };
                 let symbol1 = Symbol::intern(&i1);
-                self.token = Token::new(token::Ident(symbol1, false), ident1_span);
-                // This needs to be `Spacing::Alone` to prevent regressions.
-                // See issue #76399 and PR #76285 for more details
-                let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone);
-                let base1 =
-                    self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1));
                 let symbol2 = Symbol::intern(&i2);
-                let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
-                self.bump_with((next_token2, self.token_spacing)); // `.`
-                self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None)
+                DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span)
             }
             // 1e+ | 1e- (recovered)
             [IdentLike(_), Punct('+' | '-')] |
@@ -1109,12 +1105,47 @@ impl<'a> Parser<'a> {
             [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
                 // See the FIXME about `TokenCursor` above.
                 self.error_unexpected_after_dot();
-                base
+                DestructuredFloat::Error
             }
             _ => panic!("unexpected components in a float token: {:?}", components),
         }
     }
 
+    fn parse_expr_tuple_field_access_float(
+        &mut self,
+        lo: Span,
+        base: P<Expr>,
+        float: Symbol,
+        suffix: Option<Symbol>,
+    ) -> P<Expr> {
+        match self.break_up_float(float) {
+            // 1e2
+            DestructuredFloat::Single(sym, _sp) => {
+                self.parse_expr_tuple_field_access(lo, base, sym, suffix, None)
+            }
+            // 1.
+            DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {
+                assert!(suffix.is_none());
+                self.token = Token::new(token::Ident(sym, false), ident_span);
+                let next_token = (Token::new(token::Dot, dot_span), self.token_spacing);
+                self.parse_expr_tuple_field_access(lo, base, sym, None, Some(next_token))
+            }
+            // 1.2 | 1.2e3
+            DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span) => {
+                self.token = Token::new(token::Ident(symbol1, false), ident1_span);
+                // This needs to be `Spacing::Alone` to prevent regressions.
+                // See issue #76399 and PR #76285 for more details
+                let next_token1 = (Token::new(token::Dot, dot_span), Spacing::Alone);
+                let base1 =
+                    self.parse_expr_tuple_field_access(lo, base, symbol1, None, Some(next_token1));
+                let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
+                self.bump_with((next_token2, self.token_spacing)); // `.`
+                self.parse_expr_tuple_field_access(lo, base1, symbol2, suffix, None)
+            }
+            DestructuredFloat::Error => base,
+        }
+    }
+
     fn parse_expr_tuple_field_access(
         &mut self,
         lo: Span,

From 1b90f5efaf46073a7da509a895a0688e1c6300c3 Mon Sep 17 00:00:00 2001
From: est31 <MTest31@outlook.com>
Date: Fri, 2 Jun 2023 18:53:04 +0200
Subject: [PATCH 2/3] Support float-like tuple indices in offset_of!()

The tokenizer gives us whole float literal tokens, we have to split them up
in order to be able to create field access from them.
---
 compiler/rustc_parse/src/parser/expr.rs      |  47 +++-
 tests/ui/offset-of/offset-of-tuple-nested.rs |  32 +++
 tests/ui/offset-of/offset-of-tuple.rs        |  52 ++++-
 tests/ui/offset-of/offset-of-tuple.stderr    | 234 +++++++++++++++++--
 4 files changed, 344 insertions(+), 21 deletions(-)
 create mode 100644 tests/ui/offset-of/offset-of-tuple-nested.rs

diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 9e5f85dc7dc..df06115ef3b 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1852,10 +1852,53 @@ impl<'a> Parser<'a> {
         let (fields, _trailing, _recovered) = self.parse_seq_to_before_end(
             &TokenKind::CloseDelim(Delimiter::Parenthesis),
             seq_sep,
-            Parser::parse_field_name,
+            |this| {
+                let token::Literal(token::Lit { kind: token::Float, symbol, suffix }) = this.token.kind
+                else {
+                    return Ok(thin_vec![this.parse_field_name()?]);
+                };
+                let res = match this.break_up_float(symbol) {
+                    // 1e2
+                    DestructuredFloat::Single(sym, sp) => {
+                        this.bump();
+                        thin_vec![Ident::new(sym, sp)]
+                    }
+                    // 1.
+                    DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
+                        assert!(suffix.is_none());
+                        // Analogous to Self::break_and_eat
+                        this.token_cursor.break_last_token = true;
+                        // This might work, in cases like `1. 2.3`, and might not,
+                        // in cases like `offset_of!(Ty, 1.)`.
+                        this.token = Token::new(token::Ident(sym, false), sym_span);
+                        this.bump_with((Token::new(token::Dot, dot_span), this.token_spacing));
+                        thin_vec![Ident::new(sym, sym_span)]
+                    }
+                    // 1.2 | 1.2e3
+                    DestructuredFloat::MiddleDot(
+                        symbol1,
+                        ident1_span,
+                        _dot_span,
+                        symbol2,
+                        ident2_span,
+                    ) => {
+                        this.bump();
+                        thin_vec![
+                            Ident::new(symbol1, ident1_span),
+                            Ident::new(symbol2, ident2_span)
+                        ]
+                    }
+                    DestructuredFloat::Error => {
+                        this.bump();
+                        thin_vec![Ident::new(symbol, this.prev_token.span)]
+                    }
+                };
+                Ok(res)
+            },
         )?;
+        let fields = fields.into_iter().flatten().collect::<Vec<_>>();
         let span = lo.to(self.token.span);
-        Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec().into())))
+        Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.into())))
     }
 
     /// Returns a string literal if the next token is a string literal.
diff --git a/tests/ui/offset-of/offset-of-tuple-nested.rs b/tests/ui/offset-of/offset-of-tuple-nested.rs
new file mode 100644
index 00000000000..00fbb6bf8f4
--- /dev/null
+++ b/tests/ui/offset-of/offset-of-tuple-nested.rs
@@ -0,0 +1,32 @@
+// run-pass
+// Test for issue #112204 -- make sure this goes through the entire compilation pipeline,
+// similar to why `offset-of-unsized.rs` is also build-pass
+
+#![feature(offset_of)]
+#![feature(builtin_syntax)]
+
+use std::mem::offset_of;
+
+type ComplexTup = ((u8, (u8, (u8, u16), u8)), (u8, u32, u16));
+
+fn main() {
+    println!("{}", offset_of!(((u8, u8), u8), 0));
+    println!("{}", offset_of!(((u8, u8), u8), 1));
+    println!("{}", offset_of!(((u8, (u8, u8)), (u8, u8, u8)), 0.1.0));
+
+    // Complex case: do all combinations of spacings because the spacing determines what gets
+    // sent to the lexer.
+    println!("{}", offset_of!(ComplexTup, 0.1.1.1));
+    println!("{}", builtin # offset_of(ComplexTup, 0. 1.1.1));
+    println!("{}", offset_of!(ComplexTup, 0 . 1.1.1));
+    println!("{}", offset_of!(ComplexTup, 0 .1.1.1));
+    println!("{}", offset_of!(ComplexTup, 0.1 .1.1));
+    println!("{}", offset_of!(ComplexTup, 0.1 . 1.1));
+    println!("{}", offset_of!(ComplexTup, 0.1. 1.1));
+    println!("{}", builtin # offset_of(ComplexTup, 0.1.1. 1));
+    println!("{}", offset_of!(ComplexTup, 0.1.1 . 1));
+    println!("{}", offset_of!(ComplexTup, 0.1.1 .1));
+
+    println!("{}", offset_of!(((u8, u16), (u32, u16, u8)), 0.0));
+    println!("{}", offset_of!(((u8, u16), (u32, u16, u8)), 1.2));
+}
diff --git a/tests/ui/offset-of/offset-of-tuple.rs b/tests/ui/offset-of/offset-of-tuple.rs
index 4077538b77f..e31b037ee3e 100644
--- a/tests/ui/offset-of/offset-of-tuple.rs
+++ b/tests/ui/offset-of/offset-of-tuple.rs
@@ -1,10 +1,54 @@
 #![feature(offset_of)]
 #![feature(builtin_syntax)]
 
+use std::mem::offset_of;
+
 fn main() {
-    core::mem::offset_of!((u8, u8), _0); //~ ERROR no field `_0`
-    core::mem::offset_of!((u8, u8), +1); //~ ERROR no rules expected
-    core::mem::offset_of!((u8, u8), -1); //~ ERROR no rules expected
+    offset_of!((u8, u8), _0); //~ ERROR no field `_0`
+    offset_of!((u8, u8), 01); //~ ERROR no field `01`
+    offset_of!((u8, u8), 1e2); //~ ERROR no field `1e2`
+    offset_of!((u8, u8), 1_u8); //~ ERROR no field `1_`
+    //~| ERROR suffixes on a tuple index
+    offset_of!((u8, u8), +1); //~ ERROR no rules expected
+    offset_of!((u8, u8), -1); //~ ERROR no rules expected
+    offset_of!((u8, u8), 1.); //~ ERROR expected identifier, found `)`
+    offset_of!((u8, u8), 1 .); //~ ERROR unexpected end of macro
+    builtin # offset_of((u8, u8), 1e2); //~ ERROR no field `1e2`
     builtin # offset_of((u8, u8), _0); //~ ERROR no field `_0`
-    builtin # offset_of((u8, u8), +1); //~ ERROR expected identifier
+    builtin # offset_of((u8, u8), 01); //~ ERROR no field `01`
+    builtin # offset_of((u8, u8), 1_u8); //~ ERROR no field `1_`
+    //~| ERROR suffixes on a tuple index
+    // We need to put these into curly braces, otherwise only one of the
+    // errors will be emitted and the others suppressed.
+    { builtin # offset_of((u8, u8), +1) }; //~ ERROR expected identifier, found `+`
+    { builtin # offset_of((u8, u8), 1.) }; //~ ERROR expected identifier, found `)`
+    { builtin # offset_of((u8, u8), 1 .) }; //~ ERROR expected identifier, found `)`
+}
+
+type ComplexTup = ((u8, (u8, u8)), u8);
+
+fn nested() {
+    offset_of!(((u8, u16), (u32, u16, u8)), 0.2); //~ ERROR no field `2`
+    offset_of!(((u8, u16), (u32, u16, u8)), 1.2);
+    offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); //~ ERROR no field `0`
+
+    // All combinations of spaces (this sends different tokens to the parser)
+    offset_of!(ComplexTup, 0.0.1.); //~ ERROR expected identifier
+    offset_of!(ComplexTup, 0 .0.1.); //~ ERROR unexpected end of macro
+    offset_of!(ComplexTup, 0 . 0.1.); //~ ERROR unexpected end of macro
+    offset_of!(ComplexTup, 0. 0.1.); //~ ERROR no rules expected
+    offset_of!(ComplexTup, 0.0 .1.); //~ ERROR expected identifier, found `)`
+    offset_of!(ComplexTup, 0.0 . 1.); //~ ERROR expected identifier, found `)`
+    offset_of!(ComplexTup, 0.0. 1.); //~ ERROR expected identifier, found `)`
+
+    // Test for builtin too to ensure that the builtin syntax can also handle these cases
+    // We need to put these into curly braces, otherwise only one of the
+    // errors will be emitted and the others suppressed.
+    { builtin # offset_of(ComplexTup, 0.0.1.) }; //~ ERROR expected identifier, found `)`
+    { builtin # offset_of(ComplexTup, 0 .0.1.) }; //~ ERROR expected identifier, found `)`
+    { builtin # offset_of(ComplexTup, 0 . 0.1.) }; //~ ERROR expected identifier, found `)`
+    { builtin # offset_of(ComplexTup, 0. 0.1.) }; //~ ERROR expected identifier, found `)`
+    { builtin # offset_of(ComplexTup, 0.0 .1.) }; //~ ERROR expected identifier, found `)`
+    { builtin # offset_of(ComplexTup, 0.0 . 1.) }; //~ ERROR expected identifier, found `)`
+    { builtin # offset_of(ComplexTup, 0.0. 1.) }; //~ ERROR expected identifier, found `)`
 }
diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr
index cc9ce0f3455..954515f80a6 100644
--- a/tests/ui/offset-of/offset-of-tuple.stderr
+++ b/tests/ui/offset-of/offset-of-tuple.stderr
@@ -1,37 +1,241 @@
+error: suffixes on a tuple index are invalid
+  --> $DIR/offset-of-tuple.rs:19:35
+   |
+LL |     builtin # offset_of((u8, u8), 1_u8);
+   |                                   ^^^^ invalid suffix `u8`
+
 error: expected identifier, found `+`
-  --> $DIR/offset-of-tuple.rs:9:35
+  --> $DIR/offset-of-tuple.rs:23:37
    |
-LL |     builtin # offset_of((u8, u8), +1);
-   |                                   ^ expected identifier
+LL |     { builtin # offset_of((u8, u8), +1) };
+   |                                     ^ expected identifier
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:24:39
+   |
+LL |     { builtin # offset_of((u8, u8), 1.) };
+   |                                       ^ expected identifier
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:25:40
+   |
+LL |     { builtin # offset_of((u8, u8), 1 .) };
+   |                                        ^ expected identifier
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:47:45
+   |
+LL |     { builtin # offset_of(ComplexTup, 0.0.1.) };
+   |                                             ^ expected identifier
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:48:46
+   |
+LL |     { builtin # offset_of(ComplexTup, 0 .0.1.) };
+   |                                              ^ expected identifier
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:49:47
+   |
+LL |     { builtin # offset_of(ComplexTup, 0 . 0.1.) };
+   |                                               ^ expected identifier
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:50:46
+   |
+LL |     { builtin # offset_of(ComplexTup, 0. 0.1.) };
+   |                                              ^ expected identifier
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:51:46
+   |
+LL |     { builtin # offset_of(ComplexTup, 0.0 .1.) };
+   |                                              ^ expected identifier
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:52:47
+   |
+LL |     { builtin # offset_of(ComplexTup, 0.0 . 1.) };
+   |                                               ^ expected identifier
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:53:46
+   |
+LL |     { builtin # offset_of(ComplexTup, 0.0. 1.) };
+   |                                              ^ expected identifier
+
+error: suffixes on a tuple index are invalid
+  --> $DIR/offset-of-tuple.rs:10:26
+   |
+LL |     offset_of!((u8, u8), 1_u8);
+   |                          ^^^^ invalid suffix `u8`
 
 error: no rules expected the token `1`
-  --> $DIR/offset-of-tuple.rs:6:38
+  --> $DIR/offset-of-tuple.rs:12:27
    |
-LL |     core::mem::offset_of!((u8, u8), +1);
-   |                                      ^ no rules expected this token in macro call
+LL |     offset_of!((u8, u8), +1);
+   |                           ^ no rules expected this token in macro call
    |
    = note: while trying to match sequence start
 
 error: no rules expected the token `1`
-  --> $DIR/offset-of-tuple.rs:7:38
+  --> $DIR/offset-of-tuple.rs:13:27
    |
-LL |     core::mem::offset_of!((u8, u8), -1);
-   |                                      ^ no rules expected this token in macro call
+LL |     offset_of!((u8, u8), -1);
+   |                           ^ no rules expected this token in macro call
    |
    = note: while trying to match sequence start
 
-error[E0609]: no field `_0` on type `(u8, u8)`
-  --> $DIR/offset-of-tuple.rs:5:37
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:14:5
    |
-LL |     core::mem::offset_of!((u8, u8), _0);
-   |                                     ^^
+LL |     offset_of!((u8, u8), 1.);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     expected identifier
+   |     in this macro invocation
+   |
+   = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unexpected end of macro invocation
+  --> $DIR/offset-of-tuple.rs:15:29
+   |
+LL |     offset_of!((u8, u8), 1 .);
+   |                             ^ missing tokens in macro arguments
+   |
+note: while trying to match meta-variable `$fields:tt`
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:36:5
+   |
+LL |     offset_of!(ComplexTup, 0.0.1.);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     expected identifier
+   |     in this macro invocation
+   |
+   = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unexpected end of macro invocation
+  --> $DIR/offset-of-tuple.rs:37:35
+   |
+LL |     offset_of!(ComplexTup, 0 .0.1.);
+   |                                   ^ missing tokens in macro arguments
+   |
+note: while trying to match meta-variable `$fields:tt`
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+
+error: unexpected end of macro invocation
+  --> $DIR/offset-of-tuple.rs:38:36
+   |
+LL |     offset_of!(ComplexTup, 0 . 0.1.);
+   |                                    ^ missing tokens in macro arguments
+   |
+note: while trying to match meta-variable `$fields:tt`
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+
+error: no rules expected the token `0.1`
+  --> $DIR/offset-of-tuple.rs:39:31
+   |
+LL |     offset_of!(ComplexTup, 0. 0.1.);
+   |                               ^^^ no rules expected this token in macro call
+   |
+   = note: while trying to match sequence start
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:40:5
+   |
+LL |     offset_of!(ComplexTup, 0.0 .1.);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     expected identifier
+   |     in this macro invocation
+   |
+   = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:41:5
+   |
+LL |     offset_of!(ComplexTup, 0.0 . 1.);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     expected identifier
+   |     in this macro invocation
+   |
+   = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:42:5
+   |
+LL |     offset_of!(ComplexTup, 0.0. 1.);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     expected identifier
+   |     in this macro invocation
+   |
+   = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0609]: no field `_0` on type `(u8, u8)`
-  --> $DIR/offset-of-tuple.rs:8:35
+  --> $DIR/offset-of-tuple.rs:7:26
+   |
+LL |     offset_of!((u8, u8), _0);
+   |                          ^^
+
+error[E0609]: no field `01` on type `(u8, u8)`
+  --> $DIR/offset-of-tuple.rs:8:26
+   |
+LL |     offset_of!((u8, u8), 01);
+   |                          ^^
+
+error[E0609]: no field `1e2` on type `(u8, u8)`
+  --> $DIR/offset-of-tuple.rs:9:26
+   |
+LL |     offset_of!((u8, u8), 1e2);
+   |                          ^^^
+
+error[E0609]: no field `1_` on type `(u8, u8)`
+  --> $DIR/offset-of-tuple.rs:10:26
+   |
+LL |     offset_of!((u8, u8), 1_u8);
+   |                          ^^^^
+
+error[E0609]: no field `1e2` on type `(u8, u8)`
+  --> $DIR/offset-of-tuple.rs:16:35
+   |
+LL |     builtin # offset_of((u8, u8), 1e2);
+   |                                   ^^^
+
+error[E0609]: no field `_0` on type `(u8, u8)`
+  --> $DIR/offset-of-tuple.rs:17:35
    |
 LL |     builtin # offset_of((u8, u8), _0);
    |                                   ^^
 
-error: aborting due to 5 previous errors
+error[E0609]: no field `01` on type `(u8, u8)`
+  --> $DIR/offset-of-tuple.rs:18:35
+   |
+LL |     builtin # offset_of((u8, u8), 01);
+   |                                   ^^
+
+error[E0609]: no field `1_` on type `(u8, u8)`
+  --> $DIR/offset-of-tuple.rs:19:35
+   |
+LL |     builtin # offset_of((u8, u8), 1_u8);
+   |                                   ^^^^
+
+error[E0609]: no field `2` on type `(u8, u16)`
+  --> $DIR/offset-of-tuple.rs:31:47
+   |
+LL |     offset_of!(((u8, u16), (u32, u16, u8)), 0.2);
+   |                                               ^
+
+error[E0609]: no field `0` on type `u8`
+  --> $DIR/offset-of-tuple.rs:33:49
+   |
+LL |     offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0);
+   |                                                 ^
+
+error: aborting due to 33 previous errors
 
 For more information about this error, try `rustc --explain E0609`.

From 9fb266b525938f71089f23b49d756d77f550521b Mon Sep 17 00:00:00 2001
From: est31 <MTest31@outlook.com>
Date: Fri, 9 Jun 2023 00:07:39 +0200
Subject: [PATCH 3/3] Move parse_seq_to_before_end closure to own function

---
 compiler/rustc_parse/src/parser/expr.rs | 80 ++++++++++++-------------
 1 file changed, 37 insertions(+), 43 deletions(-)

diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index df06115ef3b..cea2a71c988 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1146,6 +1146,42 @@ impl<'a> Parser<'a> {
         }
     }
 
+    fn parse_field_name_maybe_tuple(&mut self) -> PResult<'a, ThinVec<Ident>> {
+        let token::Literal(token::Lit { kind: token::Float, symbol, suffix }) = self.token.kind
+        else {
+            return Ok(thin_vec![self.parse_field_name()?]);
+        };
+        Ok(match self.break_up_float(symbol) {
+            // 1e2
+            DestructuredFloat::Single(sym, sp) => {
+                self.bump();
+                thin_vec![Ident::new(sym, sp)]
+            }
+            // 1.
+            DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
+                assert!(suffix.is_none());
+                // Analogous to `Self::break_and_eat`
+                self.token_cursor.break_last_token = true;
+                // This might work, in cases like `1. 2`, and might not,
+                // in cases like `offset_of!(Ty, 1.)`. It depends on what comes
+                // after the float-like token, and therefore we have to make
+                // the other parts of the parser think that there is a dot literal.
+                self.token = Token::new(token::Ident(sym, false), sym_span);
+                self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));
+                thin_vec![Ident::new(sym, sym_span)]
+            }
+            // 1.2 | 1.2e3
+            DestructuredFloat::MiddleDot(symbol1, ident1_span, _dot_span, symbol2, ident2_span) => {
+                self.bump();
+                thin_vec![Ident::new(symbol1, ident1_span), Ident::new(symbol2, ident2_span)]
+            }
+            DestructuredFloat::Error => {
+                self.bump();
+                thin_vec![Ident::new(symbol, self.prev_token.span)]
+            }
+        })
+    }
+
     fn parse_expr_tuple_field_access(
         &mut self,
         lo: Span,
@@ -1852,49 +1888,7 @@ impl<'a> Parser<'a> {
         let (fields, _trailing, _recovered) = self.parse_seq_to_before_end(
             &TokenKind::CloseDelim(Delimiter::Parenthesis),
             seq_sep,
-            |this| {
-                let token::Literal(token::Lit { kind: token::Float, symbol, suffix }) = this.token.kind
-                else {
-                    return Ok(thin_vec![this.parse_field_name()?]);
-                };
-                let res = match this.break_up_float(symbol) {
-                    // 1e2
-                    DestructuredFloat::Single(sym, sp) => {
-                        this.bump();
-                        thin_vec![Ident::new(sym, sp)]
-                    }
-                    // 1.
-                    DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
-                        assert!(suffix.is_none());
-                        // Analogous to Self::break_and_eat
-                        this.token_cursor.break_last_token = true;
-                        // This might work, in cases like `1. 2.3`, and might not,
-                        // in cases like `offset_of!(Ty, 1.)`.
-                        this.token = Token::new(token::Ident(sym, false), sym_span);
-                        this.bump_with((Token::new(token::Dot, dot_span), this.token_spacing));
-                        thin_vec![Ident::new(sym, sym_span)]
-                    }
-                    // 1.2 | 1.2e3
-                    DestructuredFloat::MiddleDot(
-                        symbol1,
-                        ident1_span,
-                        _dot_span,
-                        symbol2,
-                        ident2_span,
-                    ) => {
-                        this.bump();
-                        thin_vec![
-                            Ident::new(symbol1, ident1_span),
-                            Ident::new(symbol2, ident2_span)
-                        ]
-                    }
-                    DestructuredFloat::Error => {
-                        this.bump();
-                        thin_vec![Ident::new(symbol, this.prev_token.span)]
-                    }
-                };
-                Ok(res)
-            },
+            Parser::parse_field_name_maybe_tuple,
         )?;
         let fields = fields.into_iter().flatten().collect::<Vec<_>>();
         let span = lo.to(self.token.span);