@@ -223,10 +223,27 @@ impl<'a> AstValidator<'a> {
223223 }
224224 }
225225 }
226+ TyKind :: AnonStruct ( ref fields, ..) | TyKind :: AnonUnion ( ref fields, ..) => {
227+ walk_list ! ( self , visit_field_def, fields)
228+ }
226229 _ => visit:: walk_ty ( self , t) ,
227230 }
228231 }
229232
233+ fn visit_struct_field_def ( & mut self , field : & ' a FieldDef ) {
234+ if let Some ( ident) = field. ident &&
235+ ident. name == kw:: Underscore {
236+ self . check_unnamed_field_ty ( & field. ty , ident. span ) ;
237+ self . visit_vis ( & field. vis ) ;
238+ self . visit_ident ( ident) ;
239+ self . visit_ty_common ( & field. ty ) ;
240+ self . walk_ty ( & field. ty ) ;
241+ walk_list ! ( self , visit_attribute, & field. attrs) ;
242+ } else {
243+ self . visit_field_def ( field) ;
244+ }
245+ }
246+
230247 fn err_handler ( & self ) -> & rustc_errors:: Handler {
231248 & self . session . diagnostic ( )
232249 }
@@ -264,6 +281,42 @@ impl<'a> AstValidator<'a> {
264281 }
265282 }
266283
284+ fn check_unnamed_field_ty ( & self , ty : & Ty , span : Span ) {
285+ if matches ! (
286+ & ty. kind,
287+ // We already checked for `kw::Underscore` before calling this function,
288+ // so skip the check
289+ TyKind :: AnonStruct ( ..) | TyKind :: AnonUnion ( ..)
290+ // If the anonymous field contains a Path as type, we can't determine
291+ // if the path is a valid struct or union, so skip the check
292+ | TyKind :: Path ( ..)
293+ ) {
294+ return ;
295+ }
296+ self . err_handler ( ) . emit_err ( errors:: InvalidUnnamedFieldTy { span, ty_span : ty. span } ) ;
297+ }
298+
299+ fn deny_anon_struct_or_union ( & self , ty : & Ty ) {
300+ let struct_or_union = match & ty. kind {
301+ TyKind :: AnonStruct ( ..) => "struct" ,
302+ TyKind :: AnonUnion ( ..) => "union" ,
303+ _ => return ,
304+ } ;
305+ self . err_handler ( )
306+ . emit_err ( errors:: AnonStructOrUnionNotAllowed { struct_or_union, span : ty. span } ) ;
307+ }
308+
309+ fn deny_unnamed_field ( & self , field : & FieldDef ) {
310+ if let Some ( ident) = field. ident &&
311+ ident. name == kw:: Underscore {
312+ self . err_handler ( )
313+ . emit_err ( errors:: InvalidUnnamedField {
314+ span : field. span ,
315+ ident_span : ident. span
316+ } ) ;
317+ }
318+ }
319+
267320 fn check_trait_fn_not_const ( & self , constness : Const ) {
268321 if let Const :: Yes ( span) = constness {
269322 self . session . emit_err ( errors:: TraitFnConst { span } ) ;
@@ -789,6 +842,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
789842
790843 fn visit_ty ( & mut self , ty : & ' a Ty ) {
791844 self . visit_ty_common ( ty) ;
845+ self . deny_anon_struct_or_union ( ty) ;
792846 self . walk_ty ( ty)
793847 }
794848
@@ -803,6 +857,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
803857 }
804858
805859 fn visit_field_def ( & mut self , field : & ' a FieldDef ) {
860+ self . deny_unnamed_field ( field) ;
806861 visit:: walk_field_def ( self , field)
807862 }
808863
@@ -995,10 +1050,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
9951050 self . check_mod_file_item_asciionly ( item. ident ) ;
9961051 }
9971052 }
998- ItemKind :: Union ( vdata, ..) => {
1053+ ItemKind :: Struct ( vdata, generics) => match vdata {
1054+ // Duplicating the `Visitor` logic allows catching all cases
1055+ // of `Anonymous(Struct, Union)` outside of a field struct or union.
1056+ //
1057+ // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1058+ // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1059+ // it uses `visit_ty_common`, which doesn't contain that specific check.
1060+ VariantData :: Struct ( fields, ..) => {
1061+ self . visit_vis ( & item. vis ) ;
1062+ self . visit_ident ( item. ident ) ;
1063+ self . visit_generics ( generics) ;
1064+ walk_list ! ( self , visit_struct_field_def, fields) ;
1065+ walk_list ! ( self , visit_attribute, & item. attrs) ;
1066+ return ;
1067+ }
1068+ _ => { }
1069+ } ,
1070+ ItemKind :: Union ( vdata, generics) => {
9991071 if vdata. fields ( ) . is_empty ( ) {
10001072 self . err_handler ( ) . emit_err ( errors:: FieldlessUnion { span : item. span } ) ;
10011073 }
1074+ match vdata {
1075+ VariantData :: Struct ( fields, ..) => {
1076+ self . visit_vis ( & item. vis ) ;
1077+ self . visit_ident ( item. ident ) ;
1078+ self . visit_generics ( generics) ;
1079+ walk_list ! ( self , visit_struct_field_def, fields) ;
1080+ walk_list ! ( self , visit_attribute, & item. attrs) ;
1081+ return ;
1082+ }
1083+ _ => { }
1084+ }
10021085 }
10031086 ItemKind :: Const ( box ConstItem { defaultness, expr : None , .. } ) => {
10041087 self . check_defaultness ( item. span , * defaultness) ;
0 commit comments