@@ -219,10 +219,27 @@ impl<'a> AstValidator<'a> {
219219 }
220220 }
221221 }
222+ TyKind :: AnonStruct ( ref fields, ..) | TyKind :: AnonUnion ( ref fields, ..) => {
223+ walk_list ! ( self , visit_field_def, fields)
224+ }
222225 _ => visit:: walk_ty ( self , t) ,
223226 }
224227 }
225228
229+ fn visit_struct_field_def ( & mut self , field : & ' a FieldDef ) {
230+ if let Some ( ident) = field. ident &&
231+ ident. name == kw:: Underscore {
232+ self . check_unnamed_field_ty ( & field. ty , ident. span ) ;
233+ self . visit_vis ( & field. vis ) ;
234+ self . visit_ident ( ident) ;
235+ self . visit_ty_common ( & field. ty ) ;
236+ self . walk_ty ( & field. ty ) ;
237+ walk_list ! ( self , visit_attribute, & field. attrs) ;
238+ } else {
239+ self . visit_field_def ( field) ;
240+ }
241+ }
242+
226243 fn err_handler ( & self ) -> & rustc_errors:: Handler {
227244 & self . session . diagnostic ( )
228245 }
@@ -260,6 +277,42 @@ impl<'a> AstValidator<'a> {
260277 }
261278 }
262279
280+ fn check_unnamed_field_ty ( & self , ty : & Ty , span : Span ) {
281+ if matches ! (
282+ & ty. kind,
283+ // We already checked for `kw::Underscore` before calling this function,
284+ // so skip the check
285+ TyKind :: AnonStruct ( ..) | TyKind :: AnonUnion ( ..)
286+ // If the anonymous field contains a Path as type, we can't determine
287+ // if the path is a valid struct or union, so skip the check
288+ | TyKind :: Path ( ..)
289+ ) {
290+ return ;
291+ }
292+ self . err_handler ( ) . emit_err ( errors:: InvalidUnnamedFieldTy { span, ty_span : ty. span } ) ;
293+ }
294+
295+ fn deny_anon_struct_or_union ( & self , ty : & Ty ) {
296+ let struct_or_union = match & ty. kind {
297+ TyKind :: AnonStruct ( ..) => "struct" ,
298+ TyKind :: AnonUnion ( ..) => "union" ,
299+ _ => return ,
300+ } ;
301+ self . err_handler ( )
302+ . emit_err ( errors:: AnonStructOrUnionNotAllowed { struct_or_union, span : ty. span } ) ;
303+ }
304+
305+ fn deny_unnamed_field ( & self , field : & FieldDef ) {
306+ if let Some ( ident) = field. ident &&
307+ ident. name == kw:: Underscore {
308+ self . err_handler ( )
309+ . emit_err ( errors:: InvalidUnnamedField {
310+ span : field. span ,
311+ ident_span : ident. span
312+ } ) ;
313+ }
314+ }
315+
263316 fn check_trait_fn_not_const ( & self , constness : Const ) {
264317 if let Const :: Yes ( span) = constness {
265318 self . session . emit_err ( errors:: TraitFnConst { span } ) ;
@@ -785,6 +838,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
785838
786839 fn visit_ty ( & mut self , ty : & ' a Ty ) {
787840 self . visit_ty_common ( ty) ;
841+ self . deny_anon_struct_or_union ( ty) ;
788842 self . walk_ty ( ty)
789843 }
790844
@@ -799,6 +853,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
799853 }
800854
801855 fn visit_field_def ( & mut self , field : & ' a FieldDef ) {
856+ self . deny_unnamed_field ( field) ;
802857 visit:: walk_field_def ( self , field)
803858 }
804859
@@ -991,10 +1046,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
9911046 self . check_mod_file_item_asciionly ( item. ident ) ;
9921047 }
9931048 }
994- ItemKind :: Union ( vdata, ..) => {
1049+ ItemKind :: Struct ( vdata, generics) => match vdata {
1050+ // Duplicating the `Visitor` logic allows catching all cases
1051+ // of `Anonymous(Struct, Union)` outside of a field struct or union.
1052+ //
1053+ // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1054+ // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1055+ // it uses `visit_ty_common`, which doesn't contain that specific check.
1056+ VariantData :: Struct ( fields, ..) => {
1057+ self . visit_vis ( & item. vis ) ;
1058+ self . visit_ident ( item. ident ) ;
1059+ self . visit_generics ( generics) ;
1060+ walk_list ! ( self , visit_struct_field_def, fields) ;
1061+ walk_list ! ( self , visit_attribute, & item. attrs) ;
1062+ return ;
1063+ }
1064+ _ => { }
1065+ } ,
1066+ ItemKind :: Union ( vdata, generics) => {
9951067 if vdata. fields ( ) . is_empty ( ) {
9961068 self . err_handler ( ) . emit_err ( errors:: FieldlessUnion { span : item. span } ) ;
9971069 }
1070+ match vdata {
1071+ VariantData :: Struct ( fields, ..) => {
1072+ self . visit_vis ( & item. vis ) ;
1073+ self . visit_ident ( item. ident ) ;
1074+ self . visit_generics ( generics) ;
1075+ walk_list ! ( self , visit_struct_field_def, fields) ;
1076+ walk_list ! ( self , visit_attribute, & item. attrs) ;
1077+ return ;
1078+ }
1079+ _ => { }
1080+ }
9981081 }
9991082 ItemKind :: Const ( box ConstItem { defaultness, expr : None , .. } ) => {
10001083 self . check_defaultness ( item. span , * defaultness) ;
0 commit comments