@@ -175,10 +175,30 @@ impl<'a> AstValidator<'a> {
175175 }
176176 }
177177 }
178+ TyKind :: AnonymousStruct ( ref fields, ..) | TyKind :: AnonymousUnion ( ref fields, ..) => {
179+ self . with_banned_assoc_ty_bound ( |this| {
180+ walk_list ! ( this, visit_struct_field_def, fields)
181+ } ) ;
182+ }
178183 _ => visit:: walk_ty ( self , t) ,
179184 }
180185 }
181186
187+ fn visit_struct_field_def ( & mut self , field : & ' a FieldDef ) {
188+ if let Some ( ident) = field. ident {
189+ if ident. name == kw:: Underscore {
190+ self . check_anonymous_field ( field) ;
191+ self . visit_vis ( & field. vis ) ;
192+ self . visit_ident ( ident) ;
193+ self . visit_ty_common ( & field. ty ) ;
194+ self . walk_ty ( & field. ty ) ;
195+ walk_list ! ( self , visit_attribute, & field. attrs) ;
196+ return ;
197+ }
198+ }
199+ self . visit_field_def ( field) ;
200+ }
201+
182202 fn err_handler ( & self ) -> & rustc_errors:: Handler {
183203 & self . session . diagnostic ( )
184204 }
@@ -213,6 +233,66 @@ impl<'a> AstValidator<'a> {
213233 err. emit ( ) ;
214234 }
215235
236+ fn check_anonymous_field ( & self , field : & FieldDef ) {
237+ let FieldDef { ty, .. } = field;
238+ match & ty. kind {
239+ TyKind :: AnonymousStruct ( ..) | TyKind :: AnonymousUnion ( ..) => {
240+ // We already checked for `kw::Underscore` before calling this function,
241+ // so skip the check
242+ }
243+ TyKind :: Path ( ..) => {
244+ // If the anonymous field contains a Path as type, we can't determine
245+ // if the path is a valid struct or union, so skip the check
246+ }
247+ _ => {
248+ let msg = "unnamed fields can only have struct or union types" ;
249+ let label = "not a struct or union" ;
250+ self . err_handler ( )
251+ . struct_span_err ( field. span , msg)
252+ . span_label ( ty. span , label)
253+ . emit ( ) ;
254+ }
255+ }
256+ }
257+
258+ fn deny_anonymous_struct ( & self , ty : & Ty ) {
259+ match & ty. kind {
260+ TyKind :: AnonymousStruct ( ..) => {
261+ self . err_handler ( )
262+ . struct_span_err (
263+ ty. span ,
264+ "anonymous structs are not allowed outside of unnamed struct or union fields" ,
265+ )
266+ . span_label ( ty. span , "anonymous struct declared here" )
267+ . emit ( ) ;
268+ }
269+ TyKind :: AnonymousUnion ( ..) => {
270+ self . err_handler ( )
271+ . struct_span_err (
272+ ty. span ,
273+ "anonymous unions are not allowed outside of unnamed struct or union fields" ,
274+ )
275+ . span_label ( ty. span , "anonymous union declared here" )
276+ . emit ( ) ;
277+ }
278+ _ => { }
279+ }
280+ }
281+
282+ fn deny_anonymous_field ( & self , field : & FieldDef ) {
283+ if let Some ( ident) = field. ident {
284+ if ident. name == kw:: Underscore {
285+ self . err_handler ( )
286+ . struct_span_err (
287+ field. span ,
288+ "anonymous fields are not allowed outside of structs or unions" ,
289+ )
290+ . span_label ( ident. span , "anonymous field declared here" )
291+ . emit ( )
292+ }
293+ }
294+ }
295+
216296 fn check_decl_no_pat ( decl : & FnDecl , mut report_err : impl FnMut ( Span , Option < Ident > , bool ) ) {
217297 for Param { pat, .. } in & decl. inputs {
218298 match pat. kind {
@@ -732,6 +812,71 @@ impl<'a> AstValidator<'a> {
732812 )
733813 . emit ( ) ;
734814 }
815+
816+ fn visit_ty_common ( & mut self , ty : & ' a Ty ) {
817+ match ty. kind {
818+ TyKind :: BareFn ( ref bfty) => {
819+ self . check_fn_decl ( & bfty. decl , SelfSemantic :: No ) ;
820+ Self :: check_decl_no_pat ( & bfty. decl , |span, _, _| {
821+ struct_span_err ! (
822+ self . session,
823+ span,
824+ E0561 ,
825+ "patterns aren't allowed in function pointer types"
826+ )
827+ . emit ( ) ;
828+ } ) ;
829+ self . check_late_bound_lifetime_defs ( & bfty. generic_params ) ;
830+ }
831+ TyKind :: TraitObject ( ref bounds, ..) => {
832+ let mut any_lifetime_bounds = false ;
833+ for bound in bounds {
834+ if let GenericBound :: Outlives ( ref lifetime) = * bound {
835+ if any_lifetime_bounds {
836+ struct_span_err ! (
837+ self . session,
838+ lifetime. ident. span,
839+ E0226 ,
840+ "only a single explicit lifetime bound is permitted"
841+ )
842+ . emit ( ) ;
843+ break ;
844+ }
845+ any_lifetime_bounds = true ;
846+ }
847+ }
848+ self . no_questions_in_bounds ( bounds, "trait object types" , false ) ;
849+ }
850+ TyKind :: ImplTrait ( _, ref bounds) => {
851+ if self . is_impl_trait_banned {
852+ struct_span_err ! (
853+ self . session,
854+ ty. span,
855+ E0667 ,
856+ "`impl Trait` is not allowed in path parameters"
857+ )
858+ . emit ( ) ;
859+ }
860+
861+ if let Some ( outer_impl_trait_sp) = self . outer_impl_trait {
862+ struct_span_err ! (
863+ self . session,
864+ ty. span,
865+ E0666 ,
866+ "nested `impl Trait` is not allowed"
867+ )
868+ . span_label ( outer_impl_trait_sp, "outer `impl Trait`" )
869+ . span_label ( ty. span , "nested `impl Trait` here" )
870+ . emit ( ) ;
871+ }
872+
873+ if !bounds. iter ( ) . any ( |b| matches ! ( b, GenericBound :: Trait ( ..) ) ) {
874+ self . err_handler ( ) . span_err ( ty. span , "at least one trait must be specified" ) ;
875+ }
876+ }
877+ _ => { }
878+ }
879+ }
735880}
736881
737882/// Checks that generic parameters are in the correct order,
@@ -850,72 +995,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
850995 }
851996
852997 fn visit_ty ( & mut self , ty : & ' a Ty ) {
853- match ty. kind {
854- TyKind :: BareFn ( ref bfty) => {
855- self . check_fn_decl ( & bfty. decl , SelfSemantic :: No ) ;
856- Self :: check_decl_no_pat ( & bfty. decl , |span, _, _| {
857- struct_span_err ! (
858- self . session,
859- span,
860- E0561 ,
861- "patterns aren't allowed in function pointer types"
862- )
863- . emit ( ) ;
864- } ) ;
865- self . check_late_bound_lifetime_defs ( & bfty. generic_params ) ;
866- }
867- TyKind :: TraitObject ( ref bounds, ..) => {
868- let mut any_lifetime_bounds = false ;
869- for bound in bounds {
870- if let GenericBound :: Outlives ( ref lifetime) = * bound {
871- if any_lifetime_bounds {
872- struct_span_err ! (
873- self . session,
874- lifetime. ident. span,
875- E0226 ,
876- "only a single explicit lifetime bound is permitted"
877- )
878- . emit ( ) ;
879- break ;
880- }
881- any_lifetime_bounds = true ;
882- }
883- }
884- self . no_questions_in_bounds ( bounds, "trait object types" , false ) ;
885- }
886- TyKind :: ImplTrait ( _, ref bounds) => {
887- if self . is_impl_trait_banned {
888- struct_span_err ! (
889- self . session,
890- ty. span,
891- E0667 ,
892- "`impl Trait` is not allowed in path parameters"
893- )
894- . emit ( ) ;
895- }
896-
897- if let Some ( outer_impl_trait_sp) = self . outer_impl_trait {
898- struct_span_err ! (
899- self . session,
900- ty. span,
901- E0666 ,
902- "nested `impl Trait` is not allowed"
903- )
904- . span_label ( outer_impl_trait_sp, "outer `impl Trait`" )
905- . span_label ( ty. span , "nested `impl Trait` here" )
906- . emit ( ) ;
907- }
908-
909- if !bounds. iter ( ) . any ( |b| matches ! ( b, GenericBound :: Trait ( ..) ) ) {
910- self . err_handler ( ) . span_err ( ty. span , "at least one trait must be specified" ) ;
911- }
912-
913- self . walk_ty ( ty) ;
914- return ;
915- }
916- _ => { }
917- }
918-
998+ self . visit_ty_common ( ty) ;
999+ self . deny_anonymous_struct ( ty) ;
9191000 self . walk_ty ( ty)
9201001 }
9211002
@@ -929,6 +1010,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
9291010 visit:: walk_lifetime ( self , lifetime) ;
9301011 }
9311012
1013+ fn visit_field_def ( & mut self , s : & ' a FieldDef ) {
1014+ self . deny_anonymous_field ( s) ;
1015+ visit:: walk_field_def ( self , s)
1016+ }
1017+
9321018 fn visit_item ( & mut self , item : & ' a Item ) {
9331019 if item. attrs . iter ( ) . any ( |attr| self . session . is_proc_macro_attr ( attr) ) {
9341020 self . has_proc_macro_decls = true ;
@@ -1084,14 +1170,42 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
10841170 self . check_mod_file_item_asciionly ( item. ident ) ;
10851171 }
10861172 }
1087- ItemKind :: Union ( ref vdata, _) => {
1088- if let VariantData :: Tuple ( ..) | VariantData :: Unit ( ..) = vdata {
1089- self . err_handler ( )
1090- . span_err ( item. span , "tuple and unit unions are not permitted" ) ;
1173+ ItemKind :: Struct ( ref vdata, ref generics) => match vdata {
1174+ // Duplicating the `Visitor` logic allows catching all cases
1175+ // of `Anonymous(Struct, Union)` outside of a field struct or union.
1176+ //
1177+ // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1178+ // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1179+ // it uses `visit_ty_common`, which doesn't contain that specific check.
1180+ VariantData :: Struct ( ref fields, ..) => {
1181+ self . visit_vis ( & item. vis ) ;
1182+ self . visit_ident ( item. ident ) ;
1183+ self . visit_generics ( generics) ;
1184+ self . with_banned_assoc_ty_bound ( |this| {
1185+ walk_list ! ( this, visit_struct_field_def, fields) ;
1186+ } ) ;
1187+ walk_list ! ( self , visit_attribute, & item. attrs) ;
1188+ return ;
10911189 }
1190+ _ => { }
1191+ } ,
1192+ ItemKind :: Union ( ref vdata, ref generics) => {
10921193 if vdata. fields ( ) . is_empty ( ) {
10931194 self . err_handler ( ) . span_err ( item. span , "unions cannot have zero fields" ) ;
10941195 }
1196+ match vdata {
1197+ VariantData :: Struct ( ref fields, ..) => {
1198+ self . visit_vis ( & item. vis ) ;
1199+ self . visit_ident ( item. ident ) ;
1200+ self . visit_generics ( generics) ;
1201+ self . with_banned_assoc_ty_bound ( |this| {
1202+ walk_list ! ( this, visit_struct_field_def, fields) ;
1203+ } ) ;
1204+ walk_list ! ( self , visit_attribute, & item. attrs) ;
1205+ return ;
1206+ }
1207+ _ => { }
1208+ }
10951209 }
10961210 ItemKind :: Const ( def, .., None ) => {
10971211 self . check_defaultness ( item. span , def) ;
0 commit comments