@@ -219,10 +219,27 @@ impl<'a> AstValidator<'a> {
219
219
}
220
220
}
221
221
}
222
+ TyKind :: AnonStruct ( ref fields, ..) | TyKind :: AnonUnion ( ref fields, ..) => {
223
+ walk_list ! ( self , visit_field_def, fields)
224
+ }
222
225
_ => visit:: walk_ty ( self , t) ,
223
226
}
224
227
}
225
228
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
+
226
243
fn err_handler ( & self ) -> & rustc_errors:: Handler {
227
244
& self . session . diagnostic ( )
228
245
}
@@ -260,6 +277,42 @@ impl<'a> AstValidator<'a> {
260
277
}
261
278
}
262
279
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
+
263
316
fn check_trait_fn_not_const ( & self , constness : Const ) {
264
317
if let Const :: Yes ( span) = constness {
265
318
self . session . emit_err ( errors:: TraitFnConst { span } ) ;
@@ -785,6 +838,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
785
838
786
839
fn visit_ty ( & mut self , ty : & ' a Ty ) {
787
840
self . visit_ty_common ( ty) ;
841
+ self . deny_anon_struct_or_union ( ty) ;
788
842
self . walk_ty ( ty)
789
843
}
790
844
@@ -799,6 +853,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
799
853
}
800
854
801
855
fn visit_field_def ( & mut self , field : & ' a FieldDef ) {
856
+ self . deny_unnamed_field ( field) ;
802
857
visit:: walk_field_def ( self , field)
803
858
}
804
859
@@ -991,10 +1046,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
991
1046
self . check_mod_file_item_asciionly ( item. ident ) ;
992
1047
}
993
1048
}
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) => {
995
1067
if vdata. fields ( ) . is_empty ( ) {
996
1068
self . err_handler ( ) . emit_err ( errors:: FieldlessUnion { span : item. span } ) ;
997
1069
}
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
+ }
998
1081
}
999
1082
ItemKind :: Const ( box ConstItem { defaultness, expr : None , .. } ) => {
1000
1083
self . check_defaultness ( item. span , * defaultness) ;
0 commit comments