Skip to content

Commit 1b90f5e

Browse files
committed
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.
1 parent d74ec96 commit 1b90f5e

File tree

4 files changed

+343
-20
lines changed

4 files changed

+343
-20
lines changed

compiler/rustc_parse/src/parser/expr.rs

+45-2
Original file line numberDiff line numberDiff line change
@@ -1852,10 +1852,53 @@ impl<'a> Parser<'a> {
18521852
let (fields, _trailing, _recovered) = self.parse_seq_to_before_end(
18531853
&TokenKind::CloseDelim(Delimiter::Parenthesis),
18541854
seq_sep,
1855-
Parser::parse_field_name,
1855+
|this| {
1856+
let token::Literal(token::Lit { kind: token::Float, symbol, suffix }) = this.token.kind
1857+
else {
1858+
return Ok(thin_vec![this.parse_field_name()?]);
1859+
};
1860+
let res = match this.break_up_float(symbol) {
1861+
// 1e2
1862+
DestructuredFloat::Single(sym, sp) => {
1863+
this.bump();
1864+
thin_vec![Ident::new(sym, sp)]
1865+
}
1866+
// 1.
1867+
DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
1868+
assert!(suffix.is_none());
1869+
// Analogous to Self::break_and_eat
1870+
this.token_cursor.break_last_token = true;
1871+
// This might work, in cases like `1. 2.3`, and might not,
1872+
// in cases like `offset_of!(Ty, 1.)`.
1873+
this.token = Token::new(token::Ident(sym, false), sym_span);
1874+
this.bump_with((Token::new(token::Dot, dot_span), this.token_spacing));
1875+
thin_vec![Ident::new(sym, sym_span)]
1876+
}
1877+
// 1.2 | 1.2e3
1878+
DestructuredFloat::MiddleDot(
1879+
symbol1,
1880+
ident1_span,
1881+
_dot_span,
1882+
symbol2,
1883+
ident2_span,
1884+
) => {
1885+
this.bump();
1886+
thin_vec![
1887+
Ident::new(symbol1, ident1_span),
1888+
Ident::new(symbol2, ident2_span)
1889+
]
1890+
}
1891+
DestructuredFloat::Error => {
1892+
this.bump();
1893+
thin_vec![Ident::new(symbol, this.prev_token.span)]
1894+
}
1895+
};
1896+
Ok(res)
1897+
},
18561898
)?;
1899+
let fields = fields.into_iter().flatten().collect::<Vec<_>>();
18571900
let span = lo.to(self.token.span);
1858-
Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec().into())))
1901+
Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.into())))
18591902
}
18601903

18611904
/// Returns a string literal if the next token is a string literal.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// run-pass
2+
// Test for issue #112204 -- make sure this goes through the entire compilation pipeline,
3+
// similar to why `offset-of-unsized.rs` is also build-pass
4+
5+
#![feature(offset_of)]
6+
#![feature(builtin_syntax)]
7+
8+
use std::mem::offset_of;
9+
10+
type ComplexTup = ((u8, (u8, (u8, u16), u8)), (u8, u32, u16));
11+
12+
fn main() {
13+
println!("{}", offset_of!(((u8, u8), u8), 0));
14+
println!("{}", offset_of!(((u8, u8), u8), 1));
15+
println!("{}", offset_of!(((u8, (u8, u8)), (u8, u8, u8)), 0.1.0));
16+
17+
// Complex case: do all combinations of spacings because the spacing determines what gets
18+
// sent to the lexer.
19+
println!("{}", offset_of!(ComplexTup, 0.1.1.1));
20+
println!("{}", builtin # offset_of(ComplexTup, 0. 1.1.1));
21+
println!("{}", offset_of!(ComplexTup, 0 . 1.1.1));
22+
println!("{}", offset_of!(ComplexTup, 0 .1.1.1));
23+
println!("{}", offset_of!(ComplexTup, 0.1 .1.1));
24+
println!("{}", offset_of!(ComplexTup, 0.1 . 1.1));
25+
println!("{}", offset_of!(ComplexTup, 0.1. 1.1));
26+
println!("{}", builtin # offset_of(ComplexTup, 0.1.1. 1));
27+
println!("{}", offset_of!(ComplexTup, 0.1.1 . 1));
28+
println!("{}", offset_of!(ComplexTup, 0.1.1 .1));
29+
30+
println!("{}", offset_of!(((u8, u16), (u32, u16, u8)), 0.0));
31+
println!("{}", offset_of!(((u8, u16), (u32, u16, u8)), 1.2));
32+
}

tests/ui/offset-of/offset-of-tuple.rs

+48-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,54 @@
11
#![feature(offset_of)]
22
#![feature(builtin_syntax)]
33

4+
use std::mem::offset_of;
5+
46
fn main() {
5-
core::mem::offset_of!((u8, u8), _0); //~ ERROR no field `_0`
6-
core::mem::offset_of!((u8, u8), +1); //~ ERROR no rules expected
7-
core::mem::offset_of!((u8, u8), -1); //~ ERROR no rules expected
7+
offset_of!((u8, u8), _0); //~ ERROR no field `_0`
8+
offset_of!((u8, u8), 01); //~ ERROR no field `01`
9+
offset_of!((u8, u8), 1e2); //~ ERROR no field `1e2`
10+
offset_of!((u8, u8), 1_u8); //~ ERROR no field `1_`
11+
//~| ERROR suffixes on a tuple index
12+
offset_of!((u8, u8), +1); //~ ERROR no rules expected
13+
offset_of!((u8, u8), -1); //~ ERROR no rules expected
14+
offset_of!((u8, u8), 1.); //~ ERROR expected identifier, found `)`
15+
offset_of!((u8, u8), 1 .); //~ ERROR unexpected end of macro
16+
builtin # offset_of((u8, u8), 1e2); //~ ERROR no field `1e2`
817
builtin # offset_of((u8, u8), _0); //~ ERROR no field `_0`
9-
builtin # offset_of((u8, u8), +1); //~ ERROR expected identifier
18+
builtin # offset_of((u8, u8), 01); //~ ERROR no field `01`
19+
builtin # offset_of((u8, u8), 1_u8); //~ ERROR no field `1_`
20+
//~| ERROR suffixes on a tuple index
21+
// We need to put these into curly braces, otherwise only one of the
22+
// errors will be emitted and the others suppressed.
23+
{ builtin # offset_of((u8, u8), +1) }; //~ ERROR expected identifier, found `+`
24+
{ builtin # offset_of((u8, u8), 1.) }; //~ ERROR expected identifier, found `)`
25+
{ builtin # offset_of((u8, u8), 1 .) }; //~ ERROR expected identifier, found `)`
26+
}
27+
28+
type ComplexTup = ((u8, (u8, u8)), u8);
29+
30+
fn nested() {
31+
offset_of!(((u8, u16), (u32, u16, u8)), 0.2); //~ ERROR no field `2`
32+
offset_of!(((u8, u16), (u32, u16, u8)), 1.2);
33+
offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); //~ ERROR no field `0`
34+
35+
// All combinations of spaces (this sends different tokens to the parser)
36+
offset_of!(ComplexTup, 0.0.1.); //~ ERROR expected identifier
37+
offset_of!(ComplexTup, 0 .0.1.); //~ ERROR unexpected end of macro
38+
offset_of!(ComplexTup, 0 . 0.1.); //~ ERROR unexpected end of macro
39+
offset_of!(ComplexTup, 0. 0.1.); //~ ERROR no rules expected
40+
offset_of!(ComplexTup, 0.0 .1.); //~ ERROR expected identifier, found `)`
41+
offset_of!(ComplexTup, 0.0 . 1.); //~ ERROR expected identifier, found `)`
42+
offset_of!(ComplexTup, 0.0. 1.); //~ ERROR expected identifier, found `)`
43+
44+
// Test for builtin too to ensure that the builtin syntax can also handle these cases
45+
// We need to put these into curly braces, otherwise only one of the
46+
// errors will be emitted and the others suppressed.
47+
{ builtin # offset_of(ComplexTup, 0.0.1.) }; //~ ERROR expected identifier, found `)`
48+
{ builtin # offset_of(ComplexTup, 0 .0.1.) }; //~ ERROR expected identifier, found `)`
49+
{ builtin # offset_of(ComplexTup, 0 . 0.1.) }; //~ ERROR expected identifier, found `)`
50+
{ builtin # offset_of(ComplexTup, 0. 0.1.) }; //~ ERROR expected identifier, found `)`
51+
{ builtin # offset_of(ComplexTup, 0.0 .1.) }; //~ ERROR expected identifier, found `)`
52+
{ builtin # offset_of(ComplexTup, 0.0 . 1.) }; //~ ERROR expected identifier, found `)`
53+
{ builtin # offset_of(ComplexTup, 0.0. 1.) }; //~ ERROR expected identifier, found `)`
1054
}

0 commit comments

Comments
 (0)