@@ -16,8 +16,8 @@ use syn::spanned::Spanned;
16
16
use syn:: token:: Comma ;
17
17
use syn:: {
18
18
parenthesized, Abi , Attribute , Field , Fields , FieldsNamed , FieldsUnnamed , File , Item ,
19
- ItemConst , ItemMacro , ItemStruct , ItemType , LitInt , ReturnType , Type , TypeArray , TypeBareFn ,
20
- TypePtr , Visibility ,
19
+ ItemConst , ItemMacro , ItemStruct , ItemType , ItemUnion , LitInt , ReturnType , Type , TypeArray ,
20
+ TypeBareFn , TypePtr , Visibility ,
21
21
} ;
22
22
use walkdir:: WalkDir ;
23
23
@@ -253,26 +253,46 @@ fn check_fields(fields: &Punctuated<Field, Comma>, src: &Path) -> Result<(), Err
253
253
Ok ( ( ) )
254
254
}
255
255
256
+ fn check_type_attrs ( attrs : & [ Attribute ] , spanned : & dyn Spanned , src : & Path ) -> Result < ( ) , Error > {
257
+ let attrs = parse_attrs ( attrs, src) ?;
258
+ let reprs = get_reprs ( & attrs) ;
259
+
260
+ let allowed_reprs: & [ & [ Repr ] ] = & [ & [ Repr :: C ] , & [ Repr :: C , Repr :: Packed ] , & [ Repr :: Transparent ] ] ;
261
+
262
+ if allowed_reprs. contains ( & reprs. as_slice ( ) ) {
263
+ Ok ( ( ) )
264
+ } else {
265
+ Err ( Error :: new ( ErrorKind :: ForbiddenRepr , src, spanned) )
266
+ }
267
+ }
268
+
256
269
/// Validate a struct.
257
270
fn check_struct ( item : & ItemStruct , src : & Path ) -> Result < ( ) , Error > {
258
271
if !is_pub ( & item. vis ) {
259
272
return Err ( Error :: new ( ErrorKind :: MissingPub , src, & item. struct_token ) ) ;
260
273
}
261
274
262
- let attrs = parse_attrs ( & item. attrs , src) ?;
263
-
264
275
match & item. fields {
265
276
Fields :: Named ( FieldsNamed { named, .. } ) => check_fields ( named, src) ?,
266
277
Fields :: Unnamed ( FieldsUnnamed { unnamed, .. } ) => check_fields ( unnamed, src) ?,
267
278
Fields :: Unit => { }
268
279
}
269
280
270
- let reprs = get_reprs ( & attrs) ;
271
- let allowed_reprs: & [ & [ Repr ] ] = & [ & [ Repr :: C ] , & [ Repr :: C , Repr :: Packed ] , & [ Repr :: Transparent ] ] ;
272
- if !allowed_reprs. contains ( & reprs. as_slice ( ) ) {
273
- return Err ( Error :: new ( ErrorKind :: ForbiddenRepr , src, item) ) ;
281
+ check_type_attrs ( & item. attrs , item, src) ?;
282
+
283
+ Ok ( ( ) )
284
+ }
285
+
286
+ /// Validate a union.
287
+ fn check_union ( item : & ItemUnion , src : & Path ) -> Result < ( ) , Error > {
288
+ if !is_pub ( & item. vis ) {
289
+ return Err ( Error :: new ( ErrorKind :: MissingPub , src, & item. union_token ) ) ;
274
290
}
275
291
292
+ check_fields ( & item. fields . named , src) ?;
293
+
294
+ check_type_attrs ( & item. attrs , item, src) ?;
295
+
276
296
Ok ( ( ) )
277
297
}
278
298
@@ -319,6 +339,9 @@ fn check_item(item: &Item, src: &Path) -> Result<(), Error> {
319
339
Item :: Struct ( item) => {
320
340
check_struct ( item, src) ?;
321
341
}
342
+ Item :: Union ( item) => {
343
+ check_union ( item, src) ?;
344
+ }
322
345
Item :: Macro ( item) => {
323
346
check_macro ( item, src) ?;
324
347
}
@@ -555,4 +578,52 @@ mod tests {
555
578
ErrorKind :: ForbiddenType ,
556
579
) ;
557
580
}
581
+
582
+ #[ test]
583
+ fn test_union ( ) {
584
+ // Valid union.
585
+ assert ! ( check_union(
586
+ & parse_quote! {
587
+ #[ repr( C ) ]
588
+ pub union U {
589
+ pub a: u32 ,
590
+ pub b: u64 ,
591
+ }
592
+ } ,
593
+ src( ) ,
594
+ )
595
+ . is_ok( ) ) ;
596
+
597
+ // Missing `pub` on union.
598
+ check_item_err (
599
+ parse_quote ! {
600
+ #[ repr( C ) ]
601
+ struct U {
602
+ pub f: u32 ,
603
+ }
604
+ } ,
605
+ ErrorKind :: MissingPub ,
606
+ ) ;
607
+
608
+ // Missing `pub` on field.
609
+ check_item_err (
610
+ parse_quote ! {
611
+ #[ repr( C ) ]
612
+ pub struct U {
613
+ f: u32 ,
614
+ }
615
+ } ,
616
+ ErrorKind :: MissingPub ,
617
+ ) ;
618
+
619
+ // Forbidden `repr`.
620
+ check_item_err (
621
+ parse_quote ! {
622
+ pub struct S {
623
+ pub f: u32 ,
624
+ }
625
+ } ,
626
+ ErrorKind :: ForbiddenRepr ,
627
+ ) ;
628
+ }
558
629
}
0 commit comments