@@ -974,8 +974,8 @@ pub struct CompInfo {
974
974
/// size_t)
975
975
has_non_type_template_params : bool ,
976
976
977
- /// Whether this struct layout is packed .
978
- packed : bool ,
977
+ /// Whether we saw `__attribute__((packed))` on or within this type .
978
+ packed_attr : bool ,
979
979
980
980
/// Used to know if we've found an opaque attribute that could cause us to
981
981
/// generate a type with invalid layout. This is explicitly used to avoid us
@@ -1007,7 +1007,7 @@ impl CompInfo {
1007
1007
has_destructor : false ,
1008
1008
has_nonempty_base : false ,
1009
1009
has_non_type_template_params : false ,
1010
- packed : false ,
1010
+ packed_attr : false ,
1011
1011
found_unknown_attr : false ,
1012
1012
is_forward_declaration : false ,
1013
1013
}
@@ -1261,7 +1261,7 @@ impl CompInfo {
1261
1261
}
1262
1262
}
1263
1263
CXCursor_PackedAttr => {
1264
- ci. packed = true ;
1264
+ ci. packed_attr = true ;
1265
1265
}
1266
1266
CXCursor_TemplateTypeParameter => {
1267
1267
let param = Item :: type_param ( None , cur, ctx)
@@ -1439,8 +1439,31 @@ impl CompInfo {
1439
1439
}
1440
1440
1441
1441
/// Is this compound type packed?
1442
- pub fn packed ( & self ) -> bool {
1443
- self . packed
1442
+ pub fn is_packed ( & self , ctx : & BindgenContext , layout : & Option < Layout > ) -> bool {
1443
+ if self . packed_attr {
1444
+ return true
1445
+ }
1446
+
1447
+ // Even though `libclang` doesn't expose `#pragma packed(...)`, we can
1448
+ // detect it through its effects.
1449
+ if let Some ( ref parent_layout) = * layout {
1450
+ if self . fields ( ) . iter ( ) . any ( |f| match * f {
1451
+ Field :: Bitfields ( ref unit) => {
1452
+ unit. layout ( ) . align > parent_layout. align
1453
+ }
1454
+ Field :: DataMember ( ref data) => {
1455
+ let field_ty = ctx. resolve_type ( data. ty ( ) ) ;
1456
+ field_ty. layout ( ctx) . map_or ( false , |field_ty_layout| {
1457
+ field_ty_layout. align > parent_layout. align
1458
+ } )
1459
+ }
1460
+ } ) {
1461
+ info ! ( "Found a struct that was defined within `#pragma packed(...)`" ) ;
1462
+ return true ;
1463
+ }
1464
+ }
1465
+
1466
+ false
1444
1467
}
1445
1468
1446
1469
/// Returns true if compound type has been forward declared
@@ -1504,8 +1527,8 @@ impl DotAttributes for CompInfo {
1504
1527
) ?;
1505
1528
}
1506
1529
1507
- if self . packed {
1508
- writeln ! ( out, "<tr><td>packed </td><td>true</td></tr>" ) ?;
1530
+ if self . packed_attr {
1531
+ writeln ! ( out, "<tr><td>packed_attr </td><td>true</td></tr>" ) ?;
1509
1532
}
1510
1533
1511
1534
if self . is_forward_declaration {
@@ -1528,15 +1551,17 @@ impl DotAttributes for CompInfo {
1528
1551
}
1529
1552
1530
1553
impl IsOpaque for CompInfo {
1531
- type Extra = ( ) ;
1554
+ type Extra = Option < Layout > ;
1532
1555
1533
- fn is_opaque ( & self , ctx : & BindgenContext , _: & ( ) ) -> bool {
1534
- // Early return to avoid extra computation
1556
+ fn is_opaque ( & self , ctx : & BindgenContext , layout : & Option < Layout > ) -> bool {
1535
1557
if self . has_non_type_template_params {
1536
1558
return true
1537
1559
}
1538
1560
1539
- self . fields ( ) . iter ( ) . any ( |f| match * f {
1561
+ // Bitfields with a width that is larger than their unit's width have
1562
+ // some strange things going on, and the best we can do is make the
1563
+ // whole struct opaque.
1564
+ if self . fields ( ) . iter ( ) . any ( |f| match * f {
1540
1565
Field :: DataMember ( _) => {
1541
1566
false
1542
1567
} ,
@@ -1548,7 +1573,23 @@ impl IsOpaque for CompInfo {
1548
1573
bf. width ( ) / 8 > bitfield_layout. size as u32
1549
1574
} )
1550
1575
}
1551
- } )
1576
+ } ) {
1577
+ return true ;
1578
+ }
1579
+
1580
+ // We don't have `#[repr(packed = "N")]` in Rust yet, so the best we can
1581
+ // do is make this struct opaque.
1582
+ //
1583
+ // See https://github.com/rust-lang-nursery/rust-bindgen/issues/537 and
1584
+ // https://github.com/rust-lang/rust/issues/33158
1585
+ if self . is_packed ( ctx, layout) && layout. map_or ( false , |l| l. align > 1 ) {
1586
+ warn ! ( "Found a type that is both packed and aligned to greater than \
1587
+ 1; Rust doesn't have `#[repr(packed = \" N\" )]` yet, so we \
1588
+ are treating it as opaque") ;
1589
+ return true ;
1590
+ }
1591
+
1592
+ false
1552
1593
}
1553
1594
}
1554
1595
0 commit comments