@@ -219,10 +219,30 @@ impl<'a> AstValidator<'a> {
219
219
}
220
220
}
221
221
}
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
+ }
222
227
_ => visit:: walk_ty ( self , t) ,
223
228
}
224
229
}
225
230
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
+
226
246
fn err_handler ( & self ) -> & rustc_errors:: Handler {
227
247
& self . session . diagnostic ( )
228
248
}
@@ -260,6 +280,66 @@ impl<'a> AstValidator<'a> {
260
280
}
261
281
}
262
282
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
+
263
343
fn check_trait_fn_not_const ( & self , constness : Const ) {
264
344
if let Const :: Yes ( span) = constness {
265
345
self . session . emit_err ( errors:: TraitFnConst { span } ) ;
@@ -785,6 +865,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
785
865
786
866
fn visit_ty ( & mut self , ty : & ' a Ty ) {
787
867
self . visit_ty_common ( ty) ;
868
+ self . deny_anonymous_struct ( ty) ;
788
869
self . walk_ty ( ty)
789
870
}
790
871
@@ -799,6 +880,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
799
880
}
800
881
801
882
fn visit_field_def ( & mut self , field : & ' a FieldDef ) {
883
+ self . deny_anonymous_field ( field) ;
802
884
visit:: walk_field_def ( self , field)
803
885
}
804
886
@@ -991,10 +1073,42 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
991
1073
self . check_mod_file_item_asciionly ( item. ident ) ;
992
1074
}
993
1075
}
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) => {
995
1096
if vdata. fields ( ) . is_empty ( ) {
996
1097
self . err_handler ( ) . emit_err ( errors:: FieldlessUnion { span : item. span } ) ;
997
1098
}
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
+ }
998
1112
}
999
1113
ItemKind :: Const ( box ConstItem { defaultness, expr : None , .. } ) => {
1000
1114
self . check_defaultness ( item. span , * defaultness) ;
0 commit comments