@@ -37,6 +37,12 @@ pub(super) enum AllowPlus {
37
37
No ,
38
38
}
39
39
40
+ #[ derive( Copy , Clone , PartialEq ) ]
41
+ pub ( super ) enum AllowAnonymousType {
42
+ Yes ,
43
+ No ,
44
+ }
45
+
40
46
#[ derive( PartialEq ) ]
41
47
pub ( super ) enum RecoverQPath {
42
48
Yes ,
@@ -98,9 +104,19 @@ impl<'a> Parser<'a> {
98
104
AllowCVariadic :: No ,
99
105
RecoverQPath :: Yes ,
100
106
RecoverReturnSign :: Yes ,
107
+ AllowAnonymousType :: No ,
101
108
)
102
109
}
103
110
111
+ pub fn parse_ty_allow_anon_adt ( & mut self ) -> PResult < ' a , P < Ty > > {
112
+ self . parse_ty_common (
113
+ AllowPlus :: Yes ,
114
+ AllowCVariadic :: No ,
115
+ RecoverQPath :: Yes ,
116
+ RecoverReturnSign :: Yes ,
117
+ AllowAnonymousType :: Yes ,
118
+ )
119
+ }
104
120
/// Parse a type suitable for a function or function pointer parameter.
105
121
/// The difference from `parse_ty` is that this version allows `...`
106
122
/// (`CVarArgs`) at the top level of the type.
@@ -110,6 +126,7 @@ impl<'a> Parser<'a> {
110
126
AllowCVariadic :: Yes ,
111
127
RecoverQPath :: Yes ,
112
128
RecoverReturnSign :: Yes ,
129
+ AllowAnonymousType :: No ,
113
130
)
114
131
}
115
132
@@ -125,6 +142,7 @@ impl<'a> Parser<'a> {
125
142
AllowCVariadic :: No ,
126
143
RecoverQPath :: Yes ,
127
144
RecoverReturnSign :: Yes ,
145
+ AllowAnonymousType :: No ,
128
146
)
129
147
}
130
148
@@ -135,6 +153,7 @@ impl<'a> Parser<'a> {
135
153
AllowCVariadic :: Yes ,
136
154
RecoverQPath :: Yes ,
137
155
RecoverReturnSign :: OnlyFatArrow ,
156
+ AllowAnonymousType :: No ,
138
157
)
139
158
}
140
159
@@ -152,6 +171,7 @@ impl<'a> Parser<'a> {
152
171
AllowCVariadic :: No ,
153
172
recover_qpath,
154
173
recover_return_sign,
174
+ AllowAnonymousType :: No ,
155
175
) ?;
156
176
FnRetTy :: Ty ( ty)
157
177
} else if recover_return_sign. can_recover ( & self . token . kind ) {
@@ -171,6 +191,7 @@ impl<'a> Parser<'a> {
171
191
AllowCVariadic :: No ,
172
192
recover_qpath,
173
193
recover_return_sign,
194
+ AllowAnonymousType :: No ,
174
195
) ?;
175
196
FnRetTy :: Ty ( ty)
176
197
} else {
@@ -184,6 +205,7 @@ impl<'a> Parser<'a> {
184
205
allow_c_variadic : AllowCVariadic ,
185
206
recover_qpath : RecoverQPath ,
186
207
recover_return_sign : RecoverReturnSign ,
208
+ allow_anonymous : AllowAnonymousType ,
187
209
) -> PResult < ' a , P < Ty > > {
188
210
let allow_qpath_recovery = recover_qpath == RecoverQPath :: Yes ;
189
211
maybe_recover_from_interpolated_ty_qpath ! ( self , allow_qpath_recovery) ;
@@ -226,19 +248,11 @@ impl<'a> Parser<'a> {
226
248
}
227
249
} else if self . eat_keyword ( kw:: Impl ) {
228
250
self . parse_impl_ty ( & mut impl_dyn_multi) ?
229
- } else if self . token . is_keyword ( kw:: Union )
251
+ } else if allow_anonymous == AllowAnonymousType :: Yes
252
+ && ( self . token . is_keyword ( kw:: Union ) | self . token . is_keyword ( kw:: Struct ) )
230
253
&& self . look_ahead ( 1 , |t| t == & token:: OpenDelim ( token:: Brace ) )
231
254
{
232
- self . bump ( ) ;
233
- let ( fields, recovered) = self . parse_record_struct_body ( "union" ) ?;
234
- let span = lo. to ( self . prev_token . span ) ;
235
- self . sess . gated_spans . gate ( sym:: unnamed_fields, span) ;
236
- TyKind :: AnonymousUnion ( fields, recovered)
237
- } else if self . eat_keyword ( kw:: Struct ) {
238
- let ( fields, recovered) = self . parse_record_struct_body ( "struct" ) ?;
239
- let span = lo. to ( self . prev_token . span ) ;
240
- self . sess . gated_spans . gate ( sym:: unnamed_fields, span) ;
241
- TyKind :: AnonymousStruct ( fields, recovered)
255
+ self . parse_anonymous_ty ( lo) ?
242
256
} else if self . is_explicit_dyn_type ( ) {
243
257
self . parse_dyn_ty ( & mut impl_dyn_multi) ?
244
258
} else if self . eat_lt ( ) {
@@ -263,7 +277,27 @@ impl<'a> Parser<'a> {
263
277
let mut err = self . struct_span_err ( self . token . span , & msg) ;
264
278
err. span_label ( self . token . span , "expected type" ) ;
265
279
self . maybe_annotate_with_ascription ( & mut err, true ) ;
266
- return Err ( err) ;
280
+
281
+ if allow_anonymous == AllowAnonymousType :: No
282
+ && ( self . token . is_keyword ( kw:: Union ) || self . token . is_keyword ( kw:: Struct ) )
283
+ && self . look_ahead ( 1 , |t| t == & token:: OpenDelim ( token:: Brace ) )
284
+ {
285
+ // Recover the parser from anonymous types anywhere other than field types.
286
+ let snapshot = self . clone ( ) ;
287
+ match self . parse_anonymous_ty ( lo) {
288
+ Ok ( ty) => {
289
+ err. delay_as_bug ( ) ;
290
+ ty
291
+ }
292
+ Err ( mut snapshot_err) => {
293
+ snapshot_err. cancel ( ) ;
294
+ * self = snapshot;
295
+ return Err ( err) ;
296
+ }
297
+ }
298
+ } else {
299
+ return Err ( err) ;
300
+ }
267
301
} ;
268
302
269
303
let span = lo. to ( self . prev_token . span ) ;
@@ -275,6 +309,22 @@ impl<'a> Parser<'a> {
275
309
self . maybe_recover_from_bad_qpath ( ty, allow_qpath_recovery)
276
310
}
277
311
312
+ fn parse_anonymous_ty ( & mut self , lo : Span ) -> PResult < ' a , TyKind > {
313
+ let is_union = self . token . is_keyword ( kw:: Union ) ;
314
+ self . bump ( ) ;
315
+ self . parse_record_struct_body ( if is_union { "union" } else { "struct" } ) . map (
316
+ |( fields, recovered) | {
317
+ let span = lo. to ( self . prev_token . span ) ;
318
+ self . sess . gated_spans . gate ( sym:: unnamed_fields, span) ;
319
+ // These will be rejected during AST validation in `deny_anonymous_struct`.
320
+ return if is_union {
321
+ TyKind :: AnonymousUnion ( fields, recovered)
322
+ } else {
323
+ TyKind :: AnonymousStruct ( fields, recovered)
324
+ } ;
325
+ } ,
326
+ )
327
+ }
278
328
/// Parses either:
279
329
/// - `(TYPE)`, a parenthesized type.
280
330
/// - `(TYPE,)`, a tuple with a single field of type TYPE.
0 commit comments