@@ -175,10 +175,30 @@ impl<'a> AstValidator<'a> {
175
175
}
176
176
}
177
177
}
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
+ }
178
183
_ => visit:: walk_ty ( self , t) ,
179
184
}
180
185
}
181
186
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
+
182
202
fn err_handler ( & self ) -> & rustc_errors:: Handler {
183
203
& self . session . diagnostic ( )
184
204
}
@@ -213,6 +233,66 @@ impl<'a> AstValidator<'a> {
213
233
err. emit ( ) ;
214
234
}
215
235
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
+
216
296
fn check_decl_no_pat ( decl : & FnDecl , mut report_err : impl FnMut ( Span , Option < Ident > , bool ) ) {
217
297
for Param { pat, .. } in & decl. inputs {
218
298
match pat. kind {
@@ -732,6 +812,71 @@ impl<'a> AstValidator<'a> {
732
812
)
733
813
. emit ( ) ;
734
814
}
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
+ }
735
880
}
736
881
737
882
/// Checks that generic parameters are in the correct order,
@@ -850,72 +995,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
850
995
}
851
996
852
997
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) ;
919
1000
self . walk_ty ( ty)
920
1001
}
921
1002
@@ -929,6 +1010,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
929
1010
visit:: walk_lifetime ( self , lifetime) ;
930
1011
}
931
1012
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
+
932
1018
fn visit_item ( & mut self , item : & ' a Item ) {
933
1019
if item. attrs . iter ( ) . any ( |attr| self . session . is_proc_macro_attr ( attr) ) {
934
1020
self . has_proc_macro_decls = true ;
@@ -1084,14 +1170,42 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1084
1170
self . check_mod_file_item_asciionly ( item. ident ) ;
1085
1171
}
1086
1172
}
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 ;
1091
1189
}
1190
+ _ => { }
1191
+ } ,
1192
+ ItemKind :: Union ( ref vdata, ref generics) => {
1092
1193
if vdata. fields ( ) . is_empty ( ) {
1093
1194
self . err_handler ( ) . span_err ( item. span , "unions cannot have zero fields" ) ;
1094
1195
}
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
+ }
1095
1209
}
1096
1210
ItemKind :: Const ( def, .., None ) => {
1097
1211
self . check_defaultness ( item. span , def) ;
0 commit comments