@@ -37,6 +37,12 @@ pub(super) enum AllowPlus {
3737 No ,
3838}
3939
40+ #[ derive( Copy , Clone , PartialEq ) ]
41+ pub ( super ) enum AllowAnonymousType {
42+ Yes ,
43+ No ,
44+ }
45+
4046#[ derive( PartialEq ) ]
4147pub ( super ) enum RecoverQPath {
4248 Yes ,
@@ -98,9 +104,19 @@ impl<'a> Parser<'a> {
98104 AllowCVariadic :: No ,
99105 RecoverQPath :: Yes ,
100106 RecoverReturnSign :: Yes ,
107+ AllowAnonymousType :: No ,
101108 )
102109 }
103110
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+ }
104120 /// Parse a type suitable for a function or function pointer parameter.
105121 /// The difference from `parse_ty` is that this version allows `...`
106122 /// (`CVarArgs`) at the top level of the type.
@@ -110,6 +126,7 @@ impl<'a> Parser<'a> {
110126 AllowCVariadic :: Yes ,
111127 RecoverQPath :: Yes ,
112128 RecoverReturnSign :: Yes ,
129+ AllowAnonymousType :: No ,
113130 )
114131 }
115132
@@ -125,6 +142,7 @@ impl<'a> Parser<'a> {
125142 AllowCVariadic :: No ,
126143 RecoverQPath :: Yes ,
127144 RecoverReturnSign :: Yes ,
145+ AllowAnonymousType :: No ,
128146 )
129147 }
130148
@@ -135,6 +153,7 @@ impl<'a> Parser<'a> {
135153 AllowCVariadic :: Yes ,
136154 RecoverQPath :: Yes ,
137155 RecoverReturnSign :: OnlyFatArrow ,
156+ AllowAnonymousType :: No ,
138157 )
139158 }
140159
@@ -152,6 +171,7 @@ impl<'a> Parser<'a> {
152171 AllowCVariadic :: No ,
153172 recover_qpath,
154173 recover_return_sign,
174+ AllowAnonymousType :: No ,
155175 ) ?;
156176 FnRetTy :: Ty ( ty)
157177 } else if recover_return_sign. can_recover ( & self . token . kind ) {
@@ -171,6 +191,7 @@ impl<'a> Parser<'a> {
171191 AllowCVariadic :: No ,
172192 recover_qpath,
173193 recover_return_sign,
194+ AllowAnonymousType :: No ,
174195 ) ?;
175196 FnRetTy :: Ty ( ty)
176197 } else {
@@ -184,6 +205,7 @@ impl<'a> Parser<'a> {
184205 allow_c_variadic : AllowCVariadic ,
185206 recover_qpath : RecoverQPath ,
186207 recover_return_sign : RecoverReturnSign ,
208+ allow_anonymous : AllowAnonymousType ,
187209 ) -> PResult < ' a , P < Ty > > {
188210 let allow_qpath_recovery = recover_qpath == RecoverQPath :: Yes ;
189211 maybe_recover_from_interpolated_ty_qpath ! ( self , allow_qpath_recovery) ;
@@ -226,19 +248,11 @@ impl<'a> Parser<'a> {
226248 }
227249 } else if self . eat_keyword ( kw:: Impl ) {
228250 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 ) )
230253 && self . look_ahead ( 1 , |t| t == & token:: OpenDelim ( token:: Brace ) )
231254 {
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) ?
242256 } else if self . is_explicit_dyn_type ( ) {
243257 self . parse_dyn_ty ( & mut impl_dyn_multi) ?
244258 } else if self . eat_lt ( ) {
@@ -263,7 +277,27 @@ impl<'a> Parser<'a> {
263277 let mut err = self . struct_span_err ( self . token . span , & msg) ;
264278 err. span_label ( self . token . span , "expected type" ) ;
265279 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+ }
267301 } ;
268302
269303 let span = lo. to ( self . prev_token . span ) ;
@@ -275,6 +309,22 @@ impl<'a> Parser<'a> {
275309 self . maybe_recover_from_bad_qpath ( ty, allow_qpath_recovery)
276310 }
277311
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+ }
278328 /// Parses either:
279329 /// - `(TYPE)`, a parenthesized type.
280330 /// - `(TYPE,)`, a tuple with a single field of type TYPE.
0 commit comments