@@ -2,7 +2,8 @@ mod helpers;
2
2
mod struct_layout;
3
3
4
4
use self :: helpers:: { BlobTyBuilder , attributes} ;
5
- use self :: struct_layout:: StructLayoutTracker ;
5
+ use self :: struct_layout:: { align_to, bytes_from_bits} ;
6
+ use self :: struct_layout:: { bytes_from_bits_pow2, StructLayoutTracker } ;
6
7
use aster;
7
8
8
9
use ir:: annotations:: FieldAccessorKind ;
@@ -363,8 +364,7 @@ impl CodeGenerator for Module {
363
364
}
364
365
365
366
if item. id ( ) == ctx. root_module ( ) {
366
- let saw_union = result. saw_union ;
367
- if saw_union && !ctx. options ( ) . unstable_rust {
367
+ if result. saw_union && !ctx. options ( ) . unstable_rust {
368
368
utils:: prepend_union_types ( ctx, & mut * result) ;
369
369
}
370
370
if result. saw_incomplete_array {
@@ -717,12 +717,12 @@ impl<'a> ItemToRustTy for Vtable<'a> {
717
717
}
718
718
719
719
struct Bitfield < ' a > {
720
- index : usize ,
720
+ index : & ' a mut usize ,
721
721
fields : Vec < & ' a Field > ,
722
722
}
723
723
724
724
impl < ' a > Bitfield < ' a > {
725
- fn new ( index : usize , fields : Vec < & ' a Field > ) -> Self {
725
+ fn new ( index : & ' a mut usize , fields : Vec < & ' a Field > ) -> Self {
726
726
Bitfield {
727
727
index : index,
728
728
fields : fields,
@@ -732,89 +732,96 @@ impl<'a> Bitfield<'a> {
732
732
fn codegen_fields ( self ,
733
733
ctx : & BindgenContext ,
734
734
fields : & mut Vec < ast:: StructField > ,
735
- methods : & mut Vec < ast:: ImplItem > )
735
+ _methods : & mut Vec < ast:: ImplItem > )
736
736
-> Layout {
737
737
use aster:: struct_field:: StructFieldBuilder ;
738
- let mut total_width = self . fields
739
- . iter ( )
740
- . fold ( 0u32 , |acc, f| acc + f. bitfield ( ) . unwrap ( ) ) ;
741
-
742
- if !total_width. is_power_of_two ( ) || total_width < 8 {
743
- total_width = cmp:: max ( 8 , total_width. next_power_of_two ( ) ) ;
744
- }
745
- debug_assert_eq ! ( total_width % 8 , 0 ) ;
746
- let total_width_in_bytes = total_width as usize / 8 ;
747
-
748
- let bitfield_layout = Layout :: new ( total_width_in_bytes,
749
- total_width_in_bytes) ;
750
- let bitfield_type = BlobTyBuilder :: new ( bitfield_layout) . build ( ) ;
751
- let field_name = format ! ( "_bitfield_{}" , self . index) ;
752
- let field_ident = ctx. ext_cx ( ) . ident_of ( & field_name) ;
753
- let field = StructFieldBuilder :: named ( & field_name)
754
- . pub_ ( )
755
- . build_ty ( bitfield_type. clone ( ) ) ;
756
- fields. push ( field) ;
757
738
739
+ // NOTE: What follows is reverse-engineered from LLVM's
740
+ // lib/AST/RecordLayoutBuilder.cpp
741
+ //
742
+ // FIXME(emilio): There are some differences between Microsoft and the
743
+ // Itanium ABI, but we'll ignore those and stick to Itanium for now.
744
+ //
745
+ // Also, we need to handle packed bitfields and stuff.
746
+ // TODO(emilio): Take into account C++'s wide bitfields, and
747
+ // packing, sigh.
748
+ let mut total_size_in_bits = 0 ;
749
+ let mut max_align = 0 ;
750
+ let mut unfilled_bits_in_last_unit = 0 ;
751
+ let mut field_size_in_bits = 0 ;
752
+ * self . index += 1 ;
753
+ let mut last_field_name = format ! ( "_bitfield_{}" , self . index) ;
754
+ let mut last_field_align = 0 ;
758
755
759
- let mut offset = 0 ;
760
756
for field in self . fields {
761
757
let width = field. bitfield ( ) . unwrap ( ) ;
762
- let field_name = field. name ( )
763
- . map ( ToOwned :: to_owned)
764
- . unwrap_or_else ( || format ! ( "at_offset_{}" , offset) ) ;
765
-
766
758
let field_item = ctx. resolve_item ( field. ty ( ) ) ;
767
759
let field_ty_layout = field_item. kind ( )
768
760
. expect_type ( )
769
761
. layout ( ctx)
770
762
. expect ( "Bitfield without layout? Gah!" ) ;
771
763
772
- let field_type = field_item. to_rust_ty ( ctx) ;
773
- let int_type = BlobTyBuilder :: new ( field_ty_layout) . build ( ) ;
764
+ let field_align = field_ty_layout. align ;
774
765
775
- let getter_name = ctx. rust_ident ( & field_name) ;
776
- let setter_name = ctx. ext_cx ( )
777
- . ident_of ( & format ! ( "set_{}" , & field_name) ) ;
778
- let mask = ( ( 1usize << width) - 1 ) << offset;
779
- let prefix = ctx. trait_prefix ( ) ;
780
- // The transmute is unfortunate, but it's needed for enums in
781
- // bitfields.
782
- let item = quote_item ! ( ctx. ext_cx( ) ,
783
- impl X {
784
- #[ inline]
785
- pub fn $getter_name( & self ) -> $field_type {
786
- unsafe {
787
- :: $prefix:: mem:: transmute(
788
- (
789
- ( self . $field_ident &
790
- ( $mask as $bitfield_type) )
791
- >> $offset
792
- ) as $int_type
793
- )
794
- }
795
- }
766
+ if field_size_in_bits != 0 &&
767
+ ( width == 0 || width as usize > unfilled_bits_in_last_unit) {
768
+ field_size_in_bits = align_to ( field_size_in_bits, field_align) ;
769
+ // Push the new field.
770
+ let ty =
771
+ BlobTyBuilder :: new ( Layout :: new ( bytes_from_bits_pow2 ( field_size_in_bits) ,
772
+ bytes_from_bits_pow2 ( last_field_align) ) )
773
+ . build ( ) ;
796
774
797
- #[ inline]
798
- pub fn $setter_name( & mut self , val: $field_type) {
799
- self . $field_ident &= !( $mask as $bitfield_type) ;
800
- self . $field_ident |=
801
- ( val as $int_type as $bitfield_type << $offset) &
802
- ( $mask as $bitfield_type) ;
803
- }
804
- }
805
- )
806
- . unwrap ( ) ;
775
+ let field = StructFieldBuilder :: named ( & last_field_name)
776
+ . pub_ ( )
777
+ . build_ty ( ty) ;
778
+ fields. push ( field) ;
807
779
808
- let items = match item. unwrap ( ) . node {
809
- ast:: ItemKind :: Impl ( _, _, _, _, _, items) => items,
810
- _ => unreachable ! ( ) ,
811
- } ;
780
+ // TODO(emilio): dedup this.
781
+ * self . index += 1 ;
782
+ last_field_name = format ! ( "_bitfield_{}" , self . index) ;
783
+
784
+ // Now reset the size and the rest of stuff.
785
+ // unfilled_bits_in_last_unit = 0;
786
+ field_size_in_bits = 0 ;
787
+ last_field_align = 0 ;
788
+ }
789
+
790
+ // TODO(emilio): Create the accessors. Problem here is that we still
791
+ // don't know which one is going to be the final alignment of the
792
+ // bitfield, and whether we have to index in it. Thus, we don't know
793
+ // which integer type do we need.
794
+ //
795
+ // We could push them to a Vec or something, but given how buggy
796
+ // they where maybe it's not a great idea?
797
+ field_size_in_bits += width as usize ;
798
+ total_size_in_bits += width as usize ;
799
+
800
+
801
+ let data_size = align_to ( field_size_in_bits, field_align * 8 ) ;
802
+
803
+ max_align = cmp:: max ( max_align, field_align) ;
804
+
805
+ // NB: The width here is completely, absolutely intentional.
806
+ last_field_align = cmp:: max ( last_field_align, width as usize ) ;
807
+
808
+ unfilled_bits_in_last_unit = data_size - field_size_in_bits;
809
+ }
810
+
811
+ if field_size_in_bits != 0 {
812
+ // Push the last field.
813
+ let ty =
814
+ BlobTyBuilder :: new ( Layout :: new ( bytes_from_bits_pow2 ( field_size_in_bits) ,
815
+ bytes_from_bits_pow2 ( last_field_align) ) )
816
+ . build ( ) ;
812
817
813
- methods. extend ( items. into_iter ( ) ) ;
814
- offset += width;
818
+ let field = StructFieldBuilder :: named ( & last_field_name)
819
+ . pub_ ( )
820
+ . build_ty ( ty) ;
821
+ fields. push ( field) ;
815
822
}
816
823
817
- bitfield_layout
824
+ Layout :: new ( bytes_from_bits ( total_size_in_bits ) , max_align )
818
825
}
819
826
}
820
827
@@ -1062,12 +1069,10 @@ impl CodeGenerator for CompInfo {
1062
1069
debug_assert ! ( !current_bitfield_fields. is_empty( ) ) ;
1063
1070
let bitfield_fields =
1064
1071
mem:: replace ( & mut current_bitfield_fields, vec ! [ ] ) ;
1065
- bitfield_count += 1 ;
1066
- let bitfield_layout = Bitfield :: new ( bitfield_count,
1072
+ let bitfield_layout = Bitfield :: new ( & mut bitfield_count,
1067
1073
bitfield_fields)
1068
1074
. codegen_fields ( ctx, & mut fields, & mut methods) ;
1069
-
1070
- struct_layout. saw_bitfield ( bitfield_layout) ;
1075
+ struct_layout. saw_bitfield_batch ( bitfield_layout) ;
1071
1076
1072
1077
current_bitfield_width = None ;
1073
1078
current_bitfield_layout = None ;
@@ -1099,8 +1104,7 @@ impl CodeGenerator for CompInfo {
1099
1104
} else {
1100
1105
quote_ty ! ( ctx. ext_cx( ) , __BindgenUnionField<$ty>)
1101
1106
}
1102
- } else if let Some ( item) =
1103
- field_ty. is_incomplete_array ( ctx) {
1107
+ } else if let Some ( item) = field_ty. is_incomplete_array ( ctx) {
1104
1108
result. saw_incomplete_array ( ) ;
1105
1109
1106
1110
let inner = item. to_rust_ty ( ctx) ;
@@ -1224,12 +1228,10 @@ impl CodeGenerator for CompInfo {
1224
1228
debug_assert ! ( !current_bitfield_fields. is_empty( ) ) ;
1225
1229
let bitfield_fields = mem:: replace ( & mut current_bitfield_fields,
1226
1230
vec ! [ ] ) ;
1227
- bitfield_count += 1 ;
1228
- let bitfield_layout = Bitfield :: new ( bitfield_count,
1231
+ let bitfield_layout = Bitfield :: new ( & mut bitfield_count,
1229
1232
bitfield_fields)
1230
1233
. codegen_fields ( ctx, & mut fields, & mut methods) ;
1231
-
1232
- struct_layout. saw_bitfield ( bitfield_layout) ;
1234
+ struct_layout. saw_bitfield_batch ( bitfield_layout) ;
1233
1235
}
1234
1236
debug_assert ! ( current_bitfield_fields. is_empty( ) ) ;
1235
1237
@@ -1268,7 +1270,7 @@ impl CodeGenerator for CompInfo {
1268
1270
}
1269
1271
} else if !is_union && !self . is_unsized ( ctx) {
1270
1272
if let Some ( padding_field) =
1271
- layout. and_then ( |layout| struct_layout. pad_struct ( layout) ) {
1273
+ layout. and_then ( |layout| struct_layout. pad_struct ( & canonical_name , layout) ) {
1272
1274
fields. push ( padding_field) ;
1273
1275
}
1274
1276
@@ -2174,8 +2176,8 @@ impl ToRustTy for Type {
2174
2176
quote_ty ! ( ctx. ext_cx( ) , :: $prefix:: option:: Option <$ty>)
2175
2177
}
2176
2178
TypeKind :: Array ( item, len) => {
2177
- let inner = item. to_rust_ty ( ctx) ;
2178
- aster:: ty:: TyBuilder :: new ( ) . array ( len) . build ( inner )
2179
+ let ty = item. to_rust_ty ( ctx) ;
2180
+ aster:: ty:: TyBuilder :: new ( ) . array ( len) . build ( ty )
2179
2181
}
2180
2182
TypeKind :: Enum ( ..) => {
2181
2183
let path = item. namespace_aware_canonical_path ( ctx) ;
@@ -2190,7 +2192,7 @@ impl ToRustTy for Type {
2190
2192
. map ( |arg| arg. to_rust_ty ( ctx) )
2191
2193
. collect :: < Vec < _ > > ( ) ;
2192
2194
2193
- path. segments . last_mut ( ) . unwrap ( ) . parameters = if
2195
+ path. segments . last_mut ( ) . unwrap ( ) . parameters = if
2194
2196
template_args. is_empty ( ) {
2195
2197
None
2196
2198
} else {
0 commit comments