Skip to content

ir: codegen: Handle too large bitfield units. #1719

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1310,23 +1310,26 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
F: Extend<proc_macro2::TokenStream>,
M: Extend<proc_macro2::TokenStream>,
{
use ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;

result.saw_bitfield_unit();

let layout = self.layout();
let unit_field_ty = helpers::bitfield_unit(ctx, layout);
let field_ty = {
let ty = helpers::bitfield_unit(ctx, self.layout());
if parent.is_union() && !parent.can_be_rust_union(ctx) {
result.saw_bindgen_union();
if ctx.options().enable_cxx_namespaces {
quote! {
root::__BindgenUnionField<#ty>
root::__BindgenUnionField<#unit_field_ty>
}
} else {
quote! {
__BindgenUnionField<#ty>
__BindgenUnionField<#unit_field_ty>
}
}
} else {
ty
unit_field_ty.clone()
}
};

Expand All @@ -1338,19 +1341,24 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
};
fields.extend(Some(field));

let unit_field_ty = helpers::bitfield_unit(ctx, self.layout());

let ctor_name = self.ctor_name();
let mut ctor_params = vec![];
let mut ctor_impl = quote! {};
let mut generate_ctor = true;

// We cannot generate any constructor if the underlying storage can't
// implement AsRef<[u8]> / AsMut<[u8]> / etc.
let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT;

for bf in self.bitfields() {
// Codegen not allowed for anonymous bitfields
if bf.name().is_none() {
continue;
}

if layout.size > RUST_DERIVE_IN_ARRAY_LIMIT {
continue;
}

let mut bitfield_representable_as_int = true;

bf.codegen(
Expand Down Expand Up @@ -1395,7 +1403,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
}));
}

struct_layout.saw_bitfield_unit(self.layout());
struct_layout.saw_bitfield_unit(layout);
}
}

Expand Down
49 changes: 31 additions & 18 deletions src/ir/analysis/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,25 +240,24 @@ impl<'ctx> CannotDerive<'ctx> {
self.derive_trait
);
return CanDerive::No;
} else {
if self.derive_trait.can_derive_large_array() {
trace!(" array can derive {}", self.derive_trait);
return CanDerive::Yes;
} else {
if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
trace!(
" array is small enough to derive {}",
self.derive_trait
);
return CanDerive::Yes;
} else {
trace!(
" array is too large to derive {}, but it may be implemented", self.derive_trait
);
return CanDerive::Manually;
}
}
}

if self.derive_trait.can_derive_large_array() {
trace!(" array can derive {}", self.derive_trait);
return CanDerive::Yes;
}

if len > RUST_DERIVE_IN_ARRAY_LIMIT {
trace!(
" array is too large to derive {}, but it may be implemented", self.derive_trait
);
return CanDerive::Manually;
}
trace!(
" array is small enough to derive {}",
self.derive_trait
);
return CanDerive::Yes;
}
TypeKind::Vector(t, len) => {
let inner_type =
Expand Down Expand Up @@ -362,6 +361,20 @@ impl<'ctx> CannotDerive<'ctx> {
return CanDerive::No;
}

// Bitfield units are always represented as arrays of u8, but
// they're not traced as arrays, so we need to check here
// instead.
if !self.derive_trait.can_derive_large_array() &&
info.has_too_large_bitfield_unit() &&
!item.is_opaque(self.ctx, &())
{
trace!(
" cannot derive {} for comp with too large bitfield unit",
self.derive_trait
);
return CanDerive::No;
}

let pred = self.derive_trait.consider_edge_comp();
return self.constrain_join(item, pred);
}
Expand Down
64 changes: 50 additions & 14 deletions src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use super::context::{BindgenContext, FunctionId, ItemId, TypeId, VarId};
use super::dot::DotAttributes;
use super::item::{IsOpaque, Item};
use super::layout::Layout;
// use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
use super::template::TemplateParameters;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
use clang;
use codegen::struct_layout::{align_to, bytes_from_bits_pow2};
use ir::derive::CanDeriveCopy;
Expand Down Expand Up @@ -497,7 +497,7 @@ fn raw_fields_to_fields_and_bitfield_units<I>(
ctx: &BindgenContext,
raw_fields: I,
packed: bool,
) -> Result<Vec<Field>, ()>
) -> Result<(Vec<Field>, bool), ()>
where
I: IntoIterator<Item = RawField>,
{
Expand Down Expand Up @@ -543,7 +543,7 @@ where
"The above loop should consume all items in `raw_fields`"
);

Ok(fields)
Ok((fields, bitfield_unit_count != 0))
}

/// Given a set of contiguous raw bitfields, group and allocate them into
Expand Down Expand Up @@ -707,7 +707,10 @@ where
#[derive(Debug)]
enum CompFields {
BeforeComputingBitfieldUnits(Vec<RawField>),
AfterComputingBitfieldUnits(Vec<Field>),
AfterComputingBitfieldUnits {
fields: Vec<Field>,
has_bitfield_units: bool,
},
ErrorComputingBitfieldUnits,
}

Expand Down Expand Up @@ -744,10 +747,13 @@ impl CompFields {
let result = raw_fields_to_fields_and_bitfield_units(ctx, raws, packed);

match result {
Ok(fields_and_units) => {
Ok((fields, has_bitfield_units)) => {
mem::replace(
self,
CompFields::AfterComputingBitfieldUnits(fields_and_units),
CompFields::AfterComputingBitfieldUnits {
fields,
has_bitfield_units,
},
);
}
Err(()) => {
Expand All @@ -758,11 +764,11 @@ impl CompFields {

fn deanonymize_fields(&mut self, ctx: &BindgenContext, methods: &[Method]) {
let fields = match *self {
CompFields::AfterComputingBitfieldUnits(ref mut fields) => fields,
CompFields::ErrorComputingBitfieldUnits => {
// Nothing to do here.
return;
}
CompFields::AfterComputingBitfieldUnits {
ref mut fields, ..
} => fields,
// Nothing to do here.
CompFields::ErrorComputingBitfieldUnits => return,
CompFields::BeforeComputingBitfieldUnits(_) => {
panic!("Not yet computed bitfield units.");
}
Expand Down Expand Up @@ -859,7 +865,7 @@ impl Trace for CompFields {
tracer.visit_kind(f.ty().into(), EdgeKind::Field);
}
}
CompFields::AfterComputingBitfieldUnits(ref fields) => {
CompFields::AfterComputingBitfieldUnits { ref fields, .. } => {
for f in fields {
f.trace(context, tracer, &());
}
Expand Down Expand Up @@ -1061,7 +1067,7 @@ impl CompInfo {
/// Construct a new compound type.
pub fn new(kind: CompKind) -> Self {
CompInfo {
kind: kind,
kind,
fields: CompFields::default(),
template_params: vec![],
methods: vec![],
Expand Down Expand Up @@ -1124,13 +1130,43 @@ impl CompInfo {
pub fn fields(&self) -> &[Field] {
match self.fields {
CompFields::ErrorComputingBitfieldUnits => &[],
CompFields::AfterComputingBitfieldUnits(ref fields) => fields,
CompFields::AfterComputingBitfieldUnits { ref fields, .. } => {
fields
}
CompFields::BeforeComputingBitfieldUnits(_) => {
panic!("Should always have computed bitfield units first");
}
}
}

fn has_bitfields(&self) -> bool {
match self.fields {
CompFields::ErrorComputingBitfieldUnits => false,
CompFields::AfterComputingBitfieldUnits {
has_bitfield_units,
..
} => has_bitfield_units,
CompFields::BeforeComputingBitfieldUnits(_) => {
panic!("Should always have computed bitfield units first");
}
}
}

/// Returns whether we have a too large bitfield unit, in which case we may
/// not be able to derive some of the things we should be able to normally
/// derive.
pub fn has_too_large_bitfield_unit(&self) -> bool {
if !self.has_bitfields() {
return false;
}
self.fields().iter().any(|field| match *field {
Field::DataMember(..) => false,
Field::Bitfields(ref unit) => {
unit.layout.size > RUST_DERIVE_IN_ARRAY_LIMIT
}
})
}

/// Does this type have any template parameters that aren't types
/// (e.g. int)?
pub fn has_non_type_template_params(&self) -> bool {
Expand Down
Loading