@@ -1023,7 +1023,7 @@ impl<'a> Parser<'a> {
1023
1023
// we should break everything including floats into more basic proc-macro style
1024
1024
// tokens in the lexer (probably preferable).
1025
1025
// See also `TokenKind::break_two_token_op` which does similar splitting of `>>` into `>`.
1026
- fn break_up_float ( & mut self , float : Symbol ) -> DestructuredFloat {
1026
+ fn break_up_float ( & self , float : Symbol , span : Span ) -> DestructuredFloat {
1027
1027
#[ derive( Debug ) ]
1028
1028
enum FloatComponent {
1029
1029
IdentLike ( String ) ,
@@ -1053,7 +1053,6 @@ impl<'a> Parser<'a> {
1053
1053
// With proc macros the span can refer to anything, the source may be too short,
1054
1054
// or too long, or non-ASCII. It only makes sense to break our span into components
1055
1055
// if its underlying text is identical to our float literal.
1056
- let span = self . token . span ;
1057
1056
let can_take_span_apart =
1058
1057
|| self . span_to_snippet ( span) . as_deref ( ) == Ok ( float_str) . as_deref ( ) ;
1059
1058
@@ -1115,7 +1114,7 @@ impl<'a> Parser<'a> {
1115
1114
float : Symbol ,
1116
1115
suffix : Option < Symbol > ,
1117
1116
) -> P < Expr > {
1118
- match self . break_up_float ( float) {
1117
+ match self . break_up_float ( float, self . token . span ) {
1119
1118
// 1e2
1120
1119
DestructuredFloat :: Single ( sym, _sp) => {
1121
1120
self . parse_expr_tuple_field_access ( lo, base, sym, suffix, None )
@@ -1143,40 +1142,105 @@ impl<'a> Parser<'a> {
1143
1142
}
1144
1143
}
1145
1144
1146
- fn parse_field_name_maybe_tuple ( & mut self ) -> PResult < ' a , ThinVec < Ident > > {
1147
- let token:: Literal ( token:: Lit { kind : token:: Float , symbol, suffix } ) = self . token . kind
1148
- else {
1149
- return Ok ( thin_vec ! [ self . parse_field_name( ) ?] ) ;
1150
- } ;
1151
- Ok ( match self . break_up_float ( symbol) {
1152
- // 1e2
1153
- DestructuredFloat :: Single ( sym, sp) => {
1154
- self . bump ( ) ;
1155
- thin_vec ! [ Ident :: new( sym, sp) ]
1156
- }
1157
- // 1.
1158
- DestructuredFloat :: TrailingDot ( sym, sym_span, dot_span) => {
1159
- assert ! ( suffix. is_none( ) ) ;
1160
- // Analogous to `Self::break_and_eat`
1161
- self . break_last_token = true ;
1162
- // This might work, in cases like `1. 2`, and might not,
1163
- // in cases like `offset_of!(Ty, 1.)`. It depends on what comes
1164
- // after the float-like token, and therefore we have to make
1165
- // the other parts of the parser think that there is a dot literal.
1166
- self . token = Token :: new ( token:: Ident ( sym, false ) , sym_span) ;
1167
- self . bump_with ( ( Token :: new ( token:: Dot , dot_span) , self . token_spacing ) ) ;
1168
- thin_vec ! [ Ident :: new( sym, sym_span) ]
1169
- }
1170
- // 1.2 | 1.2e3
1171
- DestructuredFloat :: MiddleDot ( symbol1, ident1_span, _dot_span, symbol2, ident2_span) => {
1172
- self . bump ( ) ;
1173
- thin_vec ! [ Ident :: new( symbol1, ident1_span) , Ident :: new( symbol2, ident2_span) ]
1145
+ /// Parse the field access used in offset_of, matched by `$(e:expr)+`.
1146
+ /// Currently returns a list of idents. However, it should be possible in
1147
+ /// future to also do array indices, which might be arbitrary expressions.
1148
+ fn parse_floating_field_access ( & mut self ) -> PResult < ' a , P < [ Ident ] > > {
1149
+ let mut fields = Vec :: new ( ) ;
1150
+ let mut trailing_dot = None ;
1151
+
1152
+ loop {
1153
+ // This is expected to use a metavariable $(args:expr)+, but the builtin syntax
1154
+ // could be called directly. Calling `parse_expr` allows this function to only
1155
+ // consider `Expr`s.
1156
+ let expr = self . parse_expr ( ) ?;
1157
+ let mut current = & expr;
1158
+ let start_idx = fields. len ( ) ;
1159
+ loop {
1160
+ match current. kind {
1161
+ ExprKind :: Field ( ref left, right) => {
1162
+ // Field access is read right-to-left.
1163
+ fields. insert ( start_idx, right) ;
1164
+ trailing_dot = None ;
1165
+ current = left;
1166
+ }
1167
+ // Parse this both to give helpful error messages and to
1168
+ // verify it can be done with this parser setup.
1169
+ ExprKind :: Index ( ref left, ref _right, span) => {
1170
+ self . dcx ( ) . emit_err ( errors:: ArrayIndexInOffsetOf ( span) ) ;
1171
+ current = left;
1172
+ }
1173
+ ExprKind :: Lit ( token:: Lit {
1174
+ kind : token:: Float | token:: Integer ,
1175
+ symbol,
1176
+ suffix,
1177
+ } ) => {
1178
+ if let Some ( suffix) = suffix {
1179
+ self . expect_no_tuple_index_suffix ( current. span , suffix) ;
1180
+ }
1181
+ match self . break_up_float ( symbol, current. span ) {
1182
+ // 1e2
1183
+ DestructuredFloat :: Single ( sym, sp) => {
1184
+ trailing_dot = None ;
1185
+ fields. insert ( start_idx, Ident :: new ( sym, sp) ) ;
1186
+ }
1187
+ // 1.
1188
+ DestructuredFloat :: TrailingDot ( sym, sym_span, dot_span) => {
1189
+ assert ! ( suffix. is_none( ) ) ;
1190
+ trailing_dot = Some ( dot_span) ;
1191
+ fields. insert ( start_idx, Ident :: new ( sym, sym_span) ) ;
1192
+ }
1193
+ // 1.2 | 1.2e3
1194
+ DestructuredFloat :: MiddleDot (
1195
+ symbol1,
1196
+ span1,
1197
+ _dot_span,
1198
+ symbol2,
1199
+ span2,
1200
+ ) => {
1201
+ trailing_dot = None ;
1202
+ fields. insert ( start_idx, Ident :: new ( symbol2, span2) ) ;
1203
+ fields. insert ( start_idx, Ident :: new ( symbol1, span1) ) ;
1204
+ }
1205
+ DestructuredFloat :: Error => {
1206
+ trailing_dot = None ;
1207
+ fields. insert ( start_idx, Ident :: new ( symbol, self . prev_token . span ) ) ;
1208
+ }
1209
+ }
1210
+ break ;
1211
+ }
1212
+ ExprKind :: Path ( None , Path { ref segments, .. } ) => {
1213
+ match & segments[ ..] {
1214
+ [ PathSegment { ident, args : None , .. } ] => {
1215
+ trailing_dot = None ;
1216
+ fields. insert ( start_idx, * ident)
1217
+ }
1218
+ _ => {
1219
+ self . dcx ( ) . emit_err ( errors:: InvalidOffsetOf ( current. span ) ) ;
1220
+ break ;
1221
+ }
1222
+ }
1223
+ break ;
1224
+ }
1225
+ _ => {
1226
+ self . dcx ( ) . emit_err ( errors:: InvalidOffsetOf ( current. span ) ) ;
1227
+ break ;
1228
+ }
1229
+ }
1174
1230
}
1175
- DestructuredFloat :: Error => {
1176
- self . bump ( ) ;
1177
- thin_vec ! [ Ident :: new( symbol, self . prev_token. span) ]
1231
+
1232
+ if matches ! ( self . token. kind, token:: CloseDelim ( ..) | token:: Comma ) {
1233
+ break ;
1234
+ } else if trailing_dot. is_none ( ) {
1235
+ // This loop should only repeat if there is a trailing dot.
1236
+ self . dcx ( ) . emit_err ( errors:: InvalidOffsetOf ( self . token . span ) ) ;
1237
+ break ;
1178
1238
}
1179
- } )
1239
+ }
1240
+ if let Some ( dot) = trailing_dot {
1241
+ self . dcx ( ) . emit_err ( errors:: InvalidOffsetOf ( dot) ) ;
1242
+ }
1243
+ Ok ( fields. into_iter ( ) . collect ( ) )
1180
1244
}
1181
1245
1182
1246
fn parse_expr_tuple_field_access (
@@ -1907,15 +1971,29 @@ impl<'a> Parser<'a> {
1907
1971
let container = self . parse_ty ( ) ?;
1908
1972
self . expect ( & TokenKind :: Comma ) ?;
1909
1973
1910
- let seq_sep = SeqSep { sep : Some ( token:: Dot ) , trailing_sep_allowed : false } ;
1911
- let ( fields, _trailing, _recovered) = self . parse_seq_to_before_end (
1912
- & TokenKind :: CloseDelim ( Delimiter :: Parenthesis ) ,
1913
- seq_sep,
1914
- Parser :: parse_field_name_maybe_tuple,
1915
- ) ?;
1916
- let fields = fields. into_iter ( ) . flatten ( ) . collect :: < Vec < _ > > ( ) ;
1974
+ let fields = self . parse_floating_field_access ( ) ?;
1975
+ let trailing_comma = self . eat_noexpect ( & TokenKind :: Comma ) ;
1976
+
1977
+ if let Err ( mut e) =
1978
+ self . expect_one_of ( & [ ] , & [ TokenKind :: CloseDelim ( Delimiter :: Parenthesis ) ] )
1979
+ {
1980
+ if trailing_comma {
1981
+ e. note ( "unexpected third argument to offset_of" ) ;
1982
+ } else {
1983
+ e. note ( "offset_of expects dot-separated field and variant names" ) ;
1984
+ }
1985
+ e. emit ( ) ;
1986
+ }
1987
+
1988
+ // Eat tokens until the macro call ends.
1989
+ if self . may_recover ( ) {
1990
+ while !matches ! ( self . token. kind, token:: CloseDelim ( ..) | token:: Eof ) {
1991
+ self . bump ( ) ;
1992
+ }
1993
+ }
1994
+
1917
1995
let span = lo. to ( self . token . span ) ;
1918
- Ok ( self . mk_expr ( span, ExprKind :: OffsetOf ( container, fields. into ( ) ) ) )
1996
+ Ok ( self . mk_expr ( span, ExprKind :: OffsetOf ( container, fields) ) )
1919
1997
}
1920
1998
1921
1999
/// Returns a string literal if the next token is a string literal.
0 commit comments