@@ -219,10 +219,30 @@ impl<'a> AstValidator<'a> {
219219 }
220220 }
221221 }
222+ TyKind :: AnonymousStruct ( ref fields, ..) | TyKind :: AnonymousUnion ( ref fields, ..) => {
223+ // self.with_banned_assoc_ty_bound(|this| {
224+ walk_list ! ( self , visit_struct_field_def, fields)
225+ // });
226+ }
222227 _ => visit:: walk_ty ( self , t) ,
223228 }
224229 }
225230
231+ fn visit_struct_field_def ( & mut self , field : & ' a FieldDef ) {
232+ if let Some ( ident) = field. ident {
233+ if ident. name == kw:: Underscore {
234+ self . check_anonymous_field ( field) ;
235+ self . visit_vis ( & field. vis ) ;
236+ self . visit_ident ( ident) ;
237+ self . visit_ty_common ( & field. ty ) ;
238+ self . walk_ty ( & field. ty ) ;
239+ walk_list ! ( self , visit_attribute, & field. attrs) ;
240+ return ;
241+ }
242+ }
243+ self . visit_field_def ( field) ;
244+ }
245+
226246 fn err_handler ( & self ) -> & rustc_errors:: Handler {
227247 & self . session . diagnostic ( )
228248 }
@@ -260,6 +280,66 @@ impl<'a> AstValidator<'a> {
260280 }
261281 }
262282
283+ fn check_anonymous_field ( & self , field : & FieldDef ) {
284+ let FieldDef { ty, .. } = field;
285+ match & ty. kind {
286+ TyKind :: AnonymousStruct ( ..) | TyKind :: AnonymousUnion ( ..) => {
287+ // We already checked for `kw::Underscore` before calling this function,
288+ // so skip the check
289+ }
290+ TyKind :: Path ( ..) => {
291+ // If the anonymous field contains a Path as type, we can't determine
292+ // if the path is a valid struct or union, so skip the check
293+ }
294+ _ => {
295+ let msg = "unnamed fields can only have struct or union types" ;
296+ let label = "not a struct or union" ;
297+ self . err_handler ( )
298+ . struct_span_err ( field. span , msg)
299+ . span_label ( ty. span , label)
300+ . emit ( ) ;
301+ }
302+ }
303+ }
304+
305+ fn deny_anonymous_struct ( & self , ty : & Ty ) {
306+ match & ty. kind {
307+ TyKind :: AnonymousStruct ( ..) => {
308+ self . err_handler ( )
309+ . struct_span_err (
310+ ty. span ,
311+ "anonymous structs are not allowed outside of unnamed struct or union fields" ,
312+ )
313+ . span_label ( ty. span , "anonymous struct declared here" )
314+ . emit ( ) ;
315+ }
316+ TyKind :: AnonymousUnion ( ..) => {
317+ self . err_handler ( )
318+ . struct_span_err (
319+ ty. span ,
320+ "anonymous unions are not allowed outside of unnamed struct or union fields" ,
321+ )
322+ . span_label ( ty. span , "anonymous union declared here" )
323+ . emit ( ) ;
324+ }
325+ _ => { }
326+ }
327+ }
328+
329+ fn deny_anonymous_field ( & self , field : & FieldDef ) {
330+ if let Some ( ident) = field. ident {
331+ if ident. name == kw:: Underscore {
332+ self . err_handler ( )
333+ . struct_span_err (
334+ field. span ,
335+ "anonymous fields are not allowed outside of structs or unions" ,
336+ )
337+ . span_label ( ident. span , "anonymous field declared here" )
338+ . emit ( ) ;
339+ }
340+ }
341+ }
342+
263343 fn check_trait_fn_not_const ( & self , constness : Const ) {
264344 if let Const :: Yes ( span) = constness {
265345 self . session . emit_err ( errors:: TraitFnConst { span } ) ;
@@ -785,6 +865,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
785865
786866 fn visit_ty ( & mut self , ty : & ' a Ty ) {
787867 self . visit_ty_common ( ty) ;
868+ self . deny_anonymous_struct ( ty) ;
788869 self . walk_ty ( ty)
789870 }
790871
@@ -799,6 +880,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
799880 }
800881
801882 fn visit_field_def ( & mut self , field : & ' a FieldDef ) {
883+ self . deny_anonymous_field ( field) ;
802884 visit:: walk_field_def ( self , field)
803885 }
804886
@@ -991,10 +1073,42 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
9911073 self . check_mod_file_item_asciionly ( item. ident ) ;
9921074 }
9931075 }
994- ItemKind :: Union ( vdata, ..) => {
1076+ ItemKind :: Struct ( vdata, generics) => match vdata {
1077+ // Duplicating the `Visitor` logic allows catching all cases
1078+ // of `Anonymous(Struct, Union)` outside of a field struct or union.
1079+ //
1080+ // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1081+ // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1082+ // it uses `visit_ty_common`, which doesn't contain that specific check.
1083+ VariantData :: Struct ( fields, ..) => {
1084+ self . visit_vis ( & item. vis ) ;
1085+ self . visit_ident ( item. ident ) ;
1086+ self . visit_generics ( generics) ;
1087+ // self.with_banned_assoc_ty_bound(|this| {
1088+ walk_list ! ( self , visit_struct_field_def, fields) ;
1089+ // });
1090+ walk_list ! ( self , visit_attribute, & item. attrs) ;
1091+ return ;
1092+ }
1093+ _ => { }
1094+ } ,
1095+ ItemKind :: Union ( vdata, generics) => {
9951096 if vdata. fields ( ) . is_empty ( ) {
9961097 self . err_handler ( ) . emit_err ( errors:: FieldlessUnion { span : item. span } ) ;
9971098 }
1099+ match vdata {
1100+ VariantData :: Struct ( fields, ..) => {
1101+ self . visit_vis ( & item. vis ) ;
1102+ self . visit_ident ( item. ident ) ;
1103+ self . visit_generics ( generics) ;
1104+ // self.with_banned_assoc_ty_bound(|this| {
1105+ walk_list ! ( self , visit_struct_field_def, fields) ;
1106+ // });
1107+ walk_list ! ( self , visit_attribute, & item. attrs) ;
1108+ return ;
1109+ }
1110+ _ => { }
1111+ }
9981112 }
9991113 ItemKind :: Const ( box ConstItem { defaultness, expr : None , .. } ) => {
10001114 self . check_defaultness ( item. span , * defaultness) ;
0 commit comments