Skip to content

Union support #61

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 4 commits into from
Sep 23, 2016
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
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,28 @@ doc = false
name = "bindgen"

[build-dependencies]
quasi_codegen = "0.15"
quasi_codegen = "0.20"

[dependencies]
clang-sys = "0.8.0"
libc = "0.2"
log = "0.3"
env_logger = "0.3"
rustc-serialize = "0.3.19"
syntex_syntax = "0.43"
syntex_syntax = "0.44"
regex = "0.1"

[dependencies.aster]
features = ["with-syntex"]
version = "0.26"
version = "0.28"

[dependencies.clippy]
optional = true
version = "*"

[dependencies.quasi]
features = ["with-syntex"]
version = "0.19"
version = "0.20"

[features]
llvm_stable = []
Expand Down
42 changes: 1 addition & 41 deletions src/codegen/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use aster;
use ir::layout::Layout;
use syntax::ast;
use syntax::codemap::respan;
use syntax::ptr::P;


Expand Down Expand Up @@ -68,46 +67,7 @@ impl BlobTyBuilder {
if data_len == 1 {
inner_ty
} else {
ArrayTyBuilder::new().with_len(data_len).build(inner_ty)
aster::ty::TyBuilder::new().array(data_len).build(inner_ty)
}
}
}

pub struct ArrayTyBuilder {
len: usize,
}

impl ArrayTyBuilder {
pub fn new() -> Self {
ArrayTyBuilder {
len: 0,
}
}

pub fn with_len(mut self, len: usize) -> Self {
self.len = len;
self
}

pub fn build(self, ty: P<ast::Ty>) -> P<ast::Ty> {
use syntax::codemap::DUMMY_SP;
let size =
ast::LitKind::Int(self.len as u64,
ast::LitIntType::Unsigned(ast::UintTy::Us));
let size = ast::ExprKind::Lit(P(respan(DUMMY_SP, size)));
let array_kind = ast::TyKind::FixedLengthVec(ty,
P(ast::Expr {
id: ast::DUMMY_NODE_ID,
node: size,
span: DUMMY_SP,
attrs: ast::ThinVec::new(),
})
);

P(ast::Ty {
id: ast::DUMMY_NODE_ID,
node: array_kind,
span: DUMMY_SP,
})
}
}
32 changes: 19 additions & 13 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mod helpers;

use self::helpers::{attributes, ArrayTyBuilder, BlobTyBuilder};
use self::helpers::{attributes, BlobTyBuilder};

use ir::context::BindgenContext;
use ir::item::{Item, ItemId, ItemCanonicalName, ItemCanonicalPath};
Expand Down Expand Up @@ -546,13 +546,14 @@ impl CodeGenerator for CompInfo {
attributes.push(attributes::repr("C"));
}

let is_union = self.kind() == CompKind::Union;
let mut derives = vec![];
let ty = item.expect_type();
if ty.can_derive_debug(ctx) {
derives.push("Debug");
}

if ty.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
derives.push("Copy");
if !applicable_template_args.is_empty() {
// FIXME: This requires extra logic if you have a big array in a
Expand All @@ -573,9 +574,15 @@ impl CodeGenerator for CompInfo {

let mut template_args_used = vec![false; applicable_template_args.len()];
let canonical_name = item.canonical_name(ctx);
let builder = aster::AstBuilder::new().item().pub_()
.with_attrs(attributes)
.struct_(&canonical_name);
let builder = if is_union && ctx.options().unstable_rust {
aster::AstBuilder::new().item().pub_()
.with_attrs(attributes)
.union_(&canonical_name)
} else {
aster::AstBuilder::new().item().pub_()
.with_attrs(attributes)
.struct_(&canonical_name)
};

// Generate the vtable from the method list if appropriate.
// TODO: I don't know how this could play with virtual methods that are
Expand Down Expand Up @@ -633,8 +640,6 @@ impl CodeGenerator for CompInfo {
.pub_().build_ty(inner);
fields.push(field);
}

let is_union = self.kind() == CompKind::Union;
if is_union {
result.saw_union();
}
Expand Down Expand Up @@ -705,7 +710,8 @@ impl CodeGenerator for CompInfo {

let ty = field.ty().to_rust_ty(ctx);

let ty = if is_union {
// NB: In unstable rust we use proper `union` types.
let ty = if is_union && !ctx.options().unstable_rust {
quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>)
} else {
ty
Expand Down Expand Up @@ -817,7 +823,7 @@ impl CodeGenerator for CompInfo {
}
debug_assert!(current_bitfield_fields.is_empty());

if is_union {
if is_union && !ctx.options().unstable_rust {
let layout = layout.expect("Unable to get layout information?");
let ty = BlobTyBuilder::new(layout).build();
let field = StructFieldBuilder::named("bindgen_union_field").pub_()
Expand Down Expand Up @@ -1311,7 +1317,7 @@ impl ToRustTy for Type {
// can't do better right now. We should be able to use
// i128/u128 when they're available.
IntKind::U128 |
IntKind::I128 => ArrayTyBuilder::new().with_len(2).build(aster::ty::TyBuilder::new().u64()),
IntKind::I128 => aster::ty::TyBuilder::new().array(2).u64(),
}
}
TypeKind::Float(fk) => {
Expand All @@ -1330,7 +1336,7 @@ impl ToRustTy for Type {
}
TypeKind::Array(item, len) => {
let inner = item.to_rust_ty(ctx);
ArrayTyBuilder::new().with_len(len).build(inner)
aster::ty::TyBuilder::new().array(len).build(inner)
}
TypeKind::Enum(..) => {
let path = item.canonical_path(ctx);
Expand Down Expand Up @@ -1375,7 +1381,7 @@ impl ToRustTy for Type {
}
None => {
warn!("Couldn't compute layout for a type with non \
template params or opaque, expect dragons!");
type template params or opaque, expect dragons!");
aster::AstBuilder::new().ty().unit()
}
}
Expand Down Expand Up @@ -1756,7 +1762,7 @@ pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> {
}
let saw_union = result.saw_union;
let mut result = result.items;
if saw_union {
if saw_union && !context.options().unstable_rust {
utils::prepend_union_types(context, &mut result);
}
result
Expand Down
52 changes: 36 additions & 16 deletions src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ impl CompInfo {
}

if self.kind == CompKind::Union {
if type_resolver.options().unstable_rust {
return false;
}

let layout = layout.unwrap_or_else(Layout::zero);
let size_divisor = cmp::max(1, layout.align);
return layout.size / size_divisor <= RUST_DERIVE_IN_ARRAY_LIMIT;
Expand All @@ -223,13 +227,21 @@ impl CompInfo {
self.detect_derive_debug_cycle.set(true);

let can_derive_debug =
self.base_members.iter().all(|ty| {
type_resolver.resolve_type(*ty)
.can_derive_debug(type_resolver)
}) &&
self.template_args.iter().all(|ty| {
type_resolver.resolve_type(*ty)
.can_derive_debug(type_resolver)
}) &&
self.fields.iter().all(|field| {
type_resolver.resolve_type(field.ty)
.can_derive_debug(type_resolver)
}) &&
self.ref_template.map_or(true, |template| {
type_resolver.resolve_type(template)
.can_derive_debug(type_resolver)
});

self.detect_derive_debug_cycle.set(false);
Expand Down Expand Up @@ -287,31 +299,39 @@ impl CompInfo {
has_destructor
}

pub fn can_derive_copy(&self, type_resolver: &TypeResolver) -> bool {
pub fn can_derive_copy(&self, type_resolver: &TypeResolver, item: &Item) -> bool {
// NOTE: Take into account that while unions in C and C++ are copied by
// default, the may have an explicit destructor in C++, so we can't
// defer this check just for the union case.
if self.has_destructor(type_resolver) {
return false;
}

match self.kind {
CompKind::Union => true,
CompKind::Struct => {
// With template args, use a safe subset of the types,
// since copyability depends on the types itself.
self.ref_template.as_ref().map_or(true, |t| {
type_resolver.resolve_type(*t).can_derive_copy(type_resolver)
}) &&
self.base_members.iter().all(|t| {
type_resolver.resolve_type(*t).can_derive_copy(type_resolver)
}) &&
self.fields.iter().all(|field| {
type_resolver.resolve_type(field.ty)
.can_derive_copy(type_resolver)
})
if self.kind == CompKind::Union {
if !type_resolver.options().unstable_rust {
return true;
}

// https://github.com/rust-lang/rust/issues/36640
if !self.template_args.is_empty() ||
self.ref_template.is_some() ||
!item.applicable_template_args(type_resolver).is_empty() {
return false;
}
}

// With template args, use a safe subset of the types,
// since copyability depends on the types itself.
self.ref_template.as_ref().map_or(true, |t| {
type_resolver.resolve_item(*t).can_derive_copy(type_resolver)
}) &&
self.base_members.iter().all(|t| {
type_resolver.resolve_item(*t).can_derive_copy(type_resolver)
}) &&
self.fields.iter().all(|field| {
type_resolver.resolve_item(field.ty)
.can_derive_copy(type_resolver)
})
}

pub fn is_template_specialization(&self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion src/ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ impl<'ctx> BindgenContext<'ctx> {

let cfg = ExpansionConfig::default("xxx".to_owned());
let sess = parse::ParseSess::new();
let mut loader = base::DummyMacroLoader;
let mut loader = base::DummyResolver;
let mut ctx =
GenContext(base::ExtCtxt::new(&sess, vec![], cfg, &mut loader));

Expand Down
8 changes: 8 additions & 0 deletions src/ir/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,14 @@ impl Item {
_ => None,
}
}

pub fn can_derive_copy(&self, ctx: &BindgenContext) -> bool {
self.expect_type().can_derive_copy(ctx, self)
}

pub fn can_derive_copy_in_array(&self, ctx: &BindgenContext) -> bool {
self.expect_type().can_derive_copy_in_array(ctx, self)
}
}

impl ClangItemParser for Item {
Expand Down
14 changes: 7 additions & 7 deletions src/ir/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,32 +175,32 @@ impl Type {
// is an error.
//
// That's the point of the existence of can_derive_copy_in_array().
pub fn can_derive_copy_in_array(&self, type_resolver: &TypeResolver) -> bool {
pub fn can_derive_copy_in_array(&self, type_resolver: &TypeResolver, item: &Item) -> bool {
match self.kind {
TypeKind::ResolvedTypeRef(t) |
TypeKind::Alias(_, t) |
TypeKind::Array(t, _) => {
type_resolver.resolve_type(t)
type_resolver.resolve_item(t)
.can_derive_copy_in_array(type_resolver)
}
TypeKind::Named(..) => false,
_ => self.can_derive_copy(type_resolver),
_ => self.can_derive_copy(type_resolver, item),
}
}

pub fn can_derive_copy(&self, type_resolver: &TypeResolver) -> bool {
pub fn can_derive_copy(&self, type_resolver: &TypeResolver, item: &Item) -> bool {
!self.is_opaque(type_resolver) && match self.kind {
TypeKind::Array(t, len) => {
len <= RUST_DERIVE_IN_ARRAY_LIMIT &&
type_resolver.resolve_type(t).can_derive_copy_in_array(type_resolver)
type_resolver.resolve_item(t).can_derive_copy_in_array(type_resolver)
}
TypeKind::ResolvedTypeRef(t) |
TypeKind::TemplateRef(t, _) |
TypeKind::Alias(_, t) => {
type_resolver.resolve_type(t).can_derive_copy(type_resolver)
type_resolver.resolve_item(t).can_derive_copy(type_resolver)
}
TypeKind::Comp(ref info) => {
info.can_derive_copy(type_resolver)
info.can_derive_copy(type_resolver, item)
}
_ => true,
}
Expand Down
4 changes: 2 additions & 2 deletions tests/tools/run-bindgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@

[_, bindgen_path, c_path, rust_path] = sys.argv

flags = []
flags = ["--no-unstable-rust"]

with open(sys.argv[2]) as f:
for line in f:
if line.startswith(BINDGEN_FLAGS_PREFIX):
flags = line.strip().split(BINDGEN_FLAGS_PREFIX)[1].split(" ")
flags.extend(line.strip().split(BINDGEN_FLAGS_PREFIX)[1].split(" "))
break

base_command = [bindgen_path, "-o", rust_path]
Expand Down