about summary refs log tree commit diff
diff options
context:
space:
mode:
authorest31 <MTest31@outlook.com>2023-06-02 18:53:04 +0200
committerest31 <MTest31@outlook.com>2023-06-08 23:42:58 +0200
commit1b90f5efaf46073a7da509a895a0688e1c6300c3 (patch)
tree1dfa03e86f163a72e16a6d62df81f0aead4684c6
parentd74ec96e8d334c765e35707f7b7f3c6499a1b43c (diff)
downloadrust-1b90f5efaf46073a7da509a895a0688e1c6300c3.tar.gz
rust-1b90f5efaf46073a7da509a895a0688e1c6300c3.zip
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.
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs47
-rw-r--r--tests/ui/offset-of/offset-of-tuple-nested.rs32
-rw-r--r--tests/ui/offset-of/offset-of-tuple.rs52
-rw-r--r--tests/ui/offset-of/offset-of-tuple.stderr232
4 files changed, 343 insertions, 20 deletions
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
+
+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 |     builtin # offset_of((u8, u8), +1);
-   |                                   ^ expected identifier
+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: expected identifier, found `)`
+  --> $DIR/offset-of-tuple.rs:14:5
+   |
+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:5:37
+  --> $DIR/offset-of-tuple.rs:7:26
    |
-LL |     core::mem::offset_of!((u8, u8), _0);
-   |                                     ^^
+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:8:35
+  --> $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`.