@@ -223,10 +223,27 @@ impl<'a> AstValidator<'a> {
223
223
}
224
224
}
225
225
}
226
+ TyKind :: AnonStruct ( ref fields, ..) | TyKind :: AnonUnion ( ref fields, ..) => {
227
+ walk_list ! ( self , visit_field_def, fields)
228
+ }
226
229
_ => visit:: walk_ty ( self , t) ,
227
230
}
228
231
}
229
232
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
+
230
247
fn err_handler ( & self ) -> & rustc_errors:: Handler {
231
248
& self . session . diagnostic ( )
232
249
}
@@ -264,6 +281,42 @@ impl<'a> AstValidator<'a> {
264
281
}
265
282
}
266
283
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
+
267
320
fn check_trait_fn_not_const ( & self , constness : Const ) {
268
321
if let Const :: Yes ( span) = constness {
269
322
self . session . emit_err ( errors:: TraitFnConst { span } ) ;
@@ -789,6 +842,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
789
842
790
843
fn visit_ty ( & mut self , ty : & ' a Ty ) {
791
844
self . visit_ty_common ( ty) ;
845
+ self . deny_anon_struct_or_union ( ty) ;
792
846
self . walk_ty ( ty)
793
847
}
794
848
@@ -803,6 +857,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
803
857
}
804
858
805
859
fn visit_field_def ( & mut self , field : & ' a FieldDef ) {
860
+ self . deny_unnamed_field ( field) ;
806
861
visit:: walk_field_def ( self , field)
807
862
}
808
863
@@ -995,10 +1050,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
995
1050
self . check_mod_file_item_asciionly ( item. ident ) ;
996
1051
}
997
1052
}
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) => {
999
1071
if vdata. fields ( ) . is_empty ( ) {
1000
1072
self . err_handler ( ) . emit_err ( errors:: FieldlessUnion { span : item. span } ) ;
1001
1073
}
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
+ }
1002
1085
}
1003
1086
ItemKind :: Const ( box ConstItem { defaultness, expr : None , .. } ) => {
1004
1087
self . check_defaultness ( item. span , * defaultness) ;
0 commit comments