Skip to content

Commit 532fd14

Browse files
committed
Wip
1 parent 06f1a08 commit 532fd14

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+2171
-548
lines changed

src/codegen/mod.rs

Lines changed: 102 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -448,20 +448,24 @@ impl<'a> ItemCanonicalName for Vtable<'a> {
448448
}
449449
}
450450

451+
impl<'a> ItemToRustTy for Vtable<'a> {
452+
fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> {
453+
aster::ty::TyBuilder::new().id(self.canonical_name(ctx))
454+
}
455+
}
456+
451457
struct Bitfield<'a> {
452458
item: &'a Item,
453459
index: usize,
454460
fields: Vec<&'a Field>,
455-
layout: Layout,
456461
}
457462

458463
impl<'a> Bitfield<'a> {
459-
fn new(item: &'a Item, index: usize, fields: Vec<&'a Field>, layout: Layout) -> Self {
464+
fn new(item: &'a Item, index: usize, fields: Vec<&'a Field>) -> Self {
460465
Bitfield {
461466
item: item,
462467
index: index,
463468
fields: fields,
464-
layout: layout,
465469
}
466470
}
467471

@@ -490,15 +494,24 @@ impl<'a> Bitfield<'a> {
490494
fields: &mut Vec<ast::StructField>,
491495
methods: &mut Vec<ast::ImplItem>) {
492496
use aster::struct_field::StructFieldBuilder;
493-
let bitfield_type = BlobTyBuilder::new(self.layout).build();
497+
use std::cmp;
498+
let mut total_width = self.fields.iter()
499+
.fold(0u32, |acc, f| acc + f.bitfield().unwrap());
500+
501+
if !total_width.is_power_of_two() || total_width < 8 {
502+
total_width = cmp::max(8, total_width.next_power_of_two());
503+
}
504+
debug_assert_eq!(total_width % 8, 0);
505+
let total_width_in_bytes = total_width as usize / 8;
506+
507+
let bitfield_type =
508+
BlobTyBuilder::new(Layout::new(total_width_in_bytes, total_width_in_bytes)).build();
494509
let field_name = format!("_bitfield_{}", self.index);
510+
let field_ident = ctx.ext_cx().ident_of(&field_name);
495511
let field = StructFieldBuilder::named(&field_name).pub_()
496512
.build_ty(bitfield_type.clone());
497513
fields.push(field);
498514

499-
let field_ident = ctx.ext_cx().ident_of(&field_name);
500-
let total_width = self.fields.iter()
501-
.fold(0u32, |acc, f| acc + f.bitfield().unwrap());
502515

503516
let mut offset = 0;
504517
for field in self.fields {
@@ -571,7 +584,15 @@ impl CodeGenerator for CompInfo {
571584
if let Some(comment) = item.comment() {
572585
attributes.push(doc!(comment));
573586
}
574-
attributes.push(repr!("C"));
587+
if self.packed() {
588+
// TODO: reuse the repr! macro?
589+
let c_packed =
590+
aster::AstBuilder::new().attr().list("repr")
591+
.words(&["C", "packed"]).build();
592+
attributes.push(c_packed);
593+
} else {
594+
attributes.push(repr!("C"));
595+
}
575596

576597
let applicable_template_args = item.applicable_template_args(ctx);
577598
let mut template_args_used = vec![false; applicable_template_args.len()];
@@ -584,21 +605,36 @@ impl CodeGenerator for CompInfo {
584605
// TODO: I don't know how this could play with virtual methods that are
585606
// not in the list of methods found by us, we'll see. Also, could the
586607
// order of the vtable pointers vary?
608+
//
609+
// FIXME: Once we generate proper vtables, we need to codegen the
610+
// vtable, but *not* generate a field for it in the case that
611+
// needs_explicit_vtable is false but has_vtable is true.
612+
//
613+
// Also, we need to generate the vtable in such a way it "inherits" from
614+
// the parent too.
587615
let mut fields = vec![];
588-
if self.has_vtable() {
616+
if self.needs_explicit_vtable(ctx) {
589617
let vtable = Vtable::new(item.id(),
590618
self.methods(),
591619
self.base_members());
592620
vtable.codegen(ctx, result, item);
593621

622+
let vtable_type = vtable.to_rust_ty(ctx).to_ptr(true, ctx.span());
623+
594624
let vtable_field = StructFieldBuilder::named("vtable_").pub_()
595-
.ty().id(vtable.canonical_name(ctx));
625+
.build_ty(vtable_type);
596626

597627
fields.push(vtable_field);
598628
}
599629

600630
for (i, base) in self.base_members().iter().enumerate() {
601631
let base_ty = ctx.resolve_type(*base);
632+
// NB: We won't include unsized types in our base chain because they
633+
// would contribute to our size given the dummy field we insert for
634+
// unsized types.
635+
if base_ty.expect_comp().is_unsized(ctx) {
636+
continue;
637+
}
602638
for (i, ty) in applicable_template_args.iter().enumerate() {
603639
if base_ty.signature_contains_named_type(ctx, ctx.resolve_type(*ty)) {
604640
template_args_used[i] = true;
@@ -619,12 +655,13 @@ impl CodeGenerator for CompInfo {
619655
let layout = item.kind().expect_type().layout(ctx);
620656

621657
let mut current_bitfield_width = None;
622-
let mut current_bitfield_layout = None;
658+
let mut current_bitfield_layout: Option<Layout> = None;
623659
let mut current_bitfield_fields = vec![];
624660
let mut bitfield_count = 0;
625661
let struct_fields = self.fields();
626662

627663
let mut methods = vec![];
664+
let mut anonymous_field_count = 0;
628665
for field in struct_fields {
629666
debug_assert_eq!(current_bitfield_width.is_some(),
630667
current_bitfield_layout.is_some());
@@ -635,8 +672,9 @@ impl CodeGenerator for CompInfo {
635672

636673
// Try to catch a bitfield contination early.
637674
if let (Some(ref mut bitfield_width), Some(width)) = (current_bitfield_width, field.bitfield()) {
638-
let layout = field_ty.layout(ctx)
639-
.expect("How can a type in a bitfield have no layout?");
675+
let layout = current_bitfield_layout.unwrap();
676+
debug!("Testing bitfield continuation {} {} {:?}",
677+
*bitfield_width, width, layout);
640678
if *bitfield_width + width <= (layout.size * 8) as u32 {
641679
*bitfield_width += width;
642680
current_bitfield_fields.push(field);
@@ -650,8 +688,7 @@ impl CodeGenerator for CompInfo {
650688
let bitfield_fields =
651689
mem::replace(&mut current_bitfield_fields, vec![]);
652690
bitfield_count += 1;
653-
Bitfield::new(item, bitfield_count, bitfield_fields,
654-
current_bitfield_layout.unwrap())
691+
Bitfield::new(item, bitfield_count, bitfield_fields)
655692
.codegen_fields(ctx, &mut fields, &mut methods);
656693
current_bitfield_width = None;
657694
current_bitfield_layout = None;
@@ -660,7 +697,7 @@ impl CodeGenerator for CompInfo {
660697

661698
if let Some(width) = field.bitfield() {
662699
let layout = field_ty.layout(ctx)
663-
.expect("How can a type in a bitfield have no layout?");
700+
.expect("Bitfield type without layout?");
664701
current_bitfield_width = Some(width);
665702
current_bitfield_layout = Some(layout);
666703
current_bitfield_fields.push(field);
@@ -685,8 +722,14 @@ impl CodeGenerator for CompInfo {
685722
if let Some(comment) = field.comment() {
686723
attrs.push(doc!(comment));
687724
}
688-
689-
let field = StructFieldBuilder::named(field.name().unwrap()).pub_()
725+
let field_name = match field.name() {
726+
Some(name) => name.to_owned(),
727+
None => {
728+
anonymous_field_count += 1;
729+
format!("__bindgen_anon_{}", anonymous_field_count)
730+
}
731+
};
732+
let field = StructFieldBuilder::named(field_name).pub_()
690733
.with_attrs(attrs)
691734
.build_ty(ty);
692735
fields.push(field);
@@ -695,12 +738,12 @@ impl CodeGenerator for CompInfo {
695738
// Flush the last bitfield if any.
696739
//
697740
// FIXME: Reduce duplication with the loop above.
741+
// FIXME: May need to pass current_bitfield_layout too.
698742
if current_bitfield_width.is_some() {
699743
debug_assert!(!current_bitfield_fields.is_empty());
700744
let bitfield_fields = mem::replace(&mut current_bitfield_fields, vec![]);
701745
bitfield_count += 1;
702-
Bitfield::new(item, bitfield_count, bitfield_fields,
703-
current_bitfield_layout.unwrap())
746+
Bitfield::new(item, bitfield_count, bitfield_fields)
704747
.codegen_fields(ctx, &mut fields, &mut methods);
705748
}
706749
debug_assert!(current_bitfield_fields.is_empty());
@@ -716,6 +759,7 @@ impl CodeGenerator for CompInfo {
716759
// Yeah, sorry about that.
717760
if item.opaque(ctx) {
718761
fields.clear();
762+
methods.clear();
719763
for i in 0..template_args_used.len() {
720764
template_args_used[i] = false;
721765
}
@@ -733,6 +777,18 @@ impl CodeGenerator for CompInfo {
733777
}
734778
}
735779

780+
// C requires every struct to be addressable, so what C compilers do is
781+
// making the struct 1-byte sized.
782+
//
783+
// NOTE: This check is conveniently here to avoid the dummy fields we
784+
// may add for unused template parameters.
785+
if self.is_unsized(ctx) {
786+
let ty = BlobTyBuilder::new(Layout::new(1, 1)).build();
787+
let field = StructFieldBuilder::named("_address").pub_()
788+
.build_ty(ty);
789+
fields.push(field);
790+
}
791+
736792
// Append any extra template arguments that nobody has used so far.
737793
for (i, ty) in applicable_template_args.iter().enumerate() {
738794
if !template_args_used[i] {
@@ -781,11 +837,36 @@ impl CodeGenerator for CompInfo {
781837
ctx.resolve_item(*ty).codegen(ctx, result, &());
782838
}
783839

784-
if applicable_template_args.is_empty() {
840+
// NOTE: Some unexposed attributes (like alignment attributes) may
841+
// affect layout, so we're bad and pray to the gods for avoid sending
842+
// all the tests to shit when parsing things like max_align_t.
843+
if self.found_unknown_attr() {
844+
warn!("Type {} has an unkown attribute that may affect layout", canonical_name);
845+
}
846+
if applicable_template_args.is_empty() && !self.found_unknown_attr() {
785847
for var in self.inner_vars() {
786848
ctx.resolve_item(*var).codegen(ctx, result, &());
787849
}
788850

851+
if let Some(layout) = layout {
852+
let fn_name =
853+
ctx.rust_ident_raw(format!("bindgen_test_layout_{}", canonical_name));
854+
let ident = ctx.rust_ident_raw(canonical_name);
855+
let size_of_expr =
856+
quote_expr!(ctx.ext_cx(), ::std::mem::size_of::<$ident>());
857+
let align_of_expr =
858+
quote_expr!(ctx.ext_cx(), ::std::mem::align_of::<$ident>());
859+
let size = layout.size;
860+
let align = layout.align;
861+
let item = quote_item!(ctx.ext_cx(),
862+
#[test]
863+
fn $fn_name() {
864+
assert_eq!($size_of_expr, $size);
865+
assert_eq!($align_of_expr, $align);
866+
}).unwrap();
867+
result.push(item);
868+
}
869+
789870
for method in self.methods() {
790871
if !method.is_virtual() {
791872
ctx.resolve_item(method.signature()).codegen(ctx, result, &());

src/hacks/mod.rs

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)