@@ -243,10 +243,30 @@ impl<'a> AstValidator<'a> {
243
243
}
244
244
}
245
245
}
246
+ TyKind :: AnonymousStruct ( ref fields, ..) | TyKind :: AnonymousUnion ( ref fields, ..) => {
247
+ self . with_banned_assoc_ty_bound ( |this| {
248
+ walk_list ! ( this, visit_struct_field_def, fields)
249
+ } ) ;
250
+ }
246
251
_ => visit:: walk_ty ( self , t) ,
247
252
}
248
253
}
249
254
255
+ fn visit_struct_field_def ( & mut self , field : & ' a FieldDef ) {
256
+ if let Some ( ident) = field. ident {
257
+ if ident. name == kw:: Underscore {
258
+ self . check_anonymous_field ( field) ;
259
+ self . visit_vis ( & field. vis ) ;
260
+ self . visit_ident ( ident) ;
261
+ self . visit_ty_common ( & field. ty ) ;
262
+ self . walk_ty ( & field. ty ) ;
263
+ walk_list ! ( self , visit_attribute, & field. attrs) ;
264
+ return ;
265
+ }
266
+ }
267
+ self . visit_field_def ( field) ;
268
+ }
269
+
250
270
fn err_handler ( & self ) -> & rustc_errors:: Handler {
251
271
& self . session . diagnostic ( )
252
272
}
@@ -288,6 +308,66 @@ impl<'a> AstValidator<'a> {
288
308
}
289
309
}
290
310
311
+ fn check_anonymous_field ( & self , field : & FieldDef ) {
312
+ let FieldDef { ty, .. } = field;
313
+ match & ty. kind {
314
+ TyKind :: AnonymousStruct ( ..) | TyKind :: AnonymousUnion ( ..) => {
315
+ // We already checked for `kw::Underscore` before calling this function,
316
+ // so skip the check
317
+ }
318
+ TyKind :: Path ( ..) => {
319
+ // If the anonymous field contains a Path as type, we can't determine
320
+ // if the path is a valid struct or union, so skip the check
321
+ }
322
+ _ => {
323
+ let msg = "unnamed fields can only have struct or union types" ;
324
+ let label = "not a struct or union" ;
325
+ self . err_handler ( )
326
+ . struct_span_err ( field. span , msg)
327
+ . span_label ( ty. span , label)
328
+ . emit ( ) ;
329
+ }
330
+ }
331
+ }
332
+
333
+ fn deny_anonymous_struct ( & self , ty : & Ty ) {
334
+ match & ty. kind {
335
+ TyKind :: AnonymousStruct ( ..) => {
336
+ self . err_handler ( )
337
+ . struct_span_err (
338
+ ty. span ,
339
+ "anonymous structs are not allowed outside of unnamed struct or union fields" ,
340
+ )
341
+ . span_label ( ty. span , "anonymous struct declared here" )
342
+ . emit ( ) ;
343
+ }
344
+ TyKind :: AnonymousUnion ( ..) => {
345
+ self . err_handler ( )
346
+ . struct_span_err (
347
+ ty. span ,
348
+ "anonymous unions are not allowed outside of unnamed struct or union fields" ,
349
+ )
350
+ . span_label ( ty. span , "anonymous union declared here" )
351
+ . emit ( ) ;
352
+ }
353
+ _ => { }
354
+ }
355
+ }
356
+
357
+ fn deny_anonymous_field ( & self , field : & FieldDef ) {
358
+ if let Some ( ident) = field. ident {
359
+ if ident. name == kw:: Underscore {
360
+ self . err_handler ( )
361
+ . struct_span_err (
362
+ field. span ,
363
+ "anonymous fields are not allowed outside of structs or unions" ,
364
+ )
365
+ . span_label ( ident. span , "anonymous field declared here" )
366
+ . emit ( ) ;
367
+ }
368
+ }
369
+ }
370
+
291
371
fn check_trait_fn_not_const ( & self , constness : Const ) {
292
372
if let Const :: Yes ( span) = constness {
293
373
self . session . emit_err ( TraitFnConst { span } ) ;
@@ -974,6 +1054,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
974
1054
975
1055
fn visit_ty ( & mut self , ty : & ' a Ty ) {
976
1056
self . visit_ty_common ( ty) ;
1057
+ self . deny_anonymous_struct ( ty) ;
977
1058
self . walk_ty ( ty)
978
1059
}
979
1060
@@ -988,6 +1069,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
988
1069
}
989
1070
990
1071
fn visit_field_def ( & mut self , field : & ' a FieldDef ) {
1072
+ self . deny_anonymous_field ( field) ;
991
1073
visit:: walk_field_def ( self , field)
992
1074
}
993
1075
@@ -1179,10 +1261,42 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1179
1261
self . check_mod_file_item_asciionly ( item. ident ) ;
1180
1262
}
1181
1263
}
1182
- ItemKind :: Union ( vdata, ..) => {
1264
+ ItemKind :: Struct ( vdata, generics) => match vdata {
1265
+ // Duplicating the `Visitor` logic allows catching all cases
1266
+ // of `Anonymous(Struct, Union)` outside of a field struct or union.
1267
+ //
1268
+ // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1269
+ // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1270
+ // it uses `visit_ty_common`, which doesn't contain that specific check.
1271
+ VariantData :: Struct ( fields, ..) => {
1272
+ self . visit_vis ( & item. vis ) ;
1273
+ self . visit_ident ( item. ident ) ;
1274
+ self . visit_generics ( generics) ;
1275
+ self . with_banned_assoc_ty_bound ( |this| {
1276
+ walk_list ! ( this, visit_struct_field_def, fields) ;
1277
+ } ) ;
1278
+ walk_list ! ( self , visit_attribute, & item. attrs) ;
1279
+ return ;
1280
+ }
1281
+ _ => { }
1282
+ } ,
1283
+ ItemKind :: Union ( vdata, generics) => {
1183
1284
if vdata. fields ( ) . is_empty ( ) {
1184
1285
self . err_handler ( ) . span_err ( item. span , "unions cannot have zero fields" ) ;
1185
1286
}
1287
+ match vdata {
1288
+ VariantData :: Struct ( fields, ..) => {
1289
+ self . visit_vis ( & item. vis ) ;
1290
+ self . visit_ident ( item. ident ) ;
1291
+ self . visit_generics ( generics) ;
1292
+ self . with_banned_assoc_ty_bound ( |this| {
1293
+ walk_list ! ( this, visit_struct_field_def, fields) ;
1294
+ } ) ;
1295
+ walk_list ! ( self , visit_attribute, & item. attrs) ;
1296
+ return ;
1297
+ }
1298
+ _ => { }
1299
+ }
1186
1300
}
1187
1301
ItemKind :: Const ( def, .., None ) => {
1188
1302
self . check_defaultness ( item. span , * def) ;
0 commit comments