summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <ecoal95@gmail.com>2016-11-08 20:45:04 +0100
committerEmilio Cobos Álvarez <ecoal95@gmail.com>2016-11-08 20:46:43 +0100
commit4062713e0fc3dbfc7c6329252a814579a4702677 (patch)
treeb1e2f29b291452eaa95e83f70b382c51f5eaad8a
parent19db528515e5e099cecb3fe7bf89209482046bd6 (diff)
codegen: Simplify bitfield logic a bit, make it work for unnamed enums, generate
default BitOr implementation.
-rwxr-xr-xsrc/bin/bindgen.rs6
-rwxr-xr-xsrc/codegen/mod.rs131
-rwxr-xr-xsrc/lib.rs2
-rw-r--r--tests/expectations/tests/bitfield-enum-basic.rs73
-rw-r--r--tests/headers/bitfield-enum-basic.h14
5 files changed, 164 insertions, 62 deletions
diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs
index b9e56b08..bdb3b292 100755
--- a/src/bin/bindgen.rs
+++ b/src/bin/bindgen.rs
@@ -92,9 +92,9 @@ Options:
matching <regex>. Same behavior on emptyness
than the type whitelisting.
- --bitfield-enum=<regex> Mark a bitfield as being used as an enum.
- This makes bindgen don't generate a rust enum
- for it, but a bitfield-like wrapper.
+ --bitfield-enum=<regex> Mark any enum whose name matches <regex> as a
+ set of bitfield flags instead of an
+ enumeration.
--dummy-uses=<path> For testing purposes, generate a C/C++ file
containing dummy uses of all types defined in
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 02051f27..20f377e1 100755
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -6,7 +6,7 @@ use aster;
use ir::annotations::FieldAccessorKind;
use ir::comp::{CompInfo, CompKind, Field, Method};
use ir::context::BindgenContext;
-use ir::enum_ty::Enum;
+use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
use ir::function::{Function, FunctionSig};
use ir::int::IntKind;
use ir::item::{Item, ItemCanonicalName, ItemCanonicalPath, ItemId};
@@ -1224,6 +1224,7 @@ impl MethodCodegen for Method {
}
}
+/// A helper type to construct enums, either bitfield ones or rust-style ones.
enum EnumBuilder<'a> {
Rust(aster::item::ItemEnumBuilder<aster::invoke::Identity>),
Bitfield {
@@ -1233,6 +1234,8 @@ enum EnumBuilder<'a> {
}
impl<'a> EnumBuilder<'a> {
+ /// Create a new enum given an item builder, a canonical name, a name for
+ /// the representation, and whether it should be represented as a rust enum.
fn new(aster: aster::item::ItemBuilder<aster::invoke::Identity>,
name: &'a str,
repr_name: &str,
@@ -1253,29 +1256,42 @@ impl<'a> EnumBuilder<'a> {
}
}
- fn with_variant_(self,
- ctx: &BindgenContext,
- name: &str,
- expr: P<ast::Expr>,
- rust_ty: P<ast::Ty>,
- result: &mut CodegenResult)
- -> Self {
+ /// Add a variant to this enum.
+ fn with_variant(self,
+ ctx: &BindgenContext,
+ variant: &EnumVariant,
+ mangling_prefix: Option<&String>,
+ rust_ty: P<ast::Ty>,
+ result: &mut CodegenResult)
+ -> Self {
+ let variant_name = ctx.rust_mangle(variant.name());
+ let expr = aster::AstBuilder::new().expr();
+ let expr = match variant.val() {
+ EnumVariantValue::Signed(v) => expr.int(v),
+ EnumVariantValue::Unsigned(v) => expr.uint(v),
+ };
+
match self {
EnumBuilder::Rust(b) => {
EnumBuilder::Rust(b.with_variant_(ast::Variant_ {
- name: ctx.rust_ident(name),
+ name: ctx.rust_ident(&*variant_name),
attrs: vec![],
data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
disr_expr: Some(expr),
}))
}
EnumBuilder::Bitfield { canonical_name, .. } => {
- // FIXME: Probably if unnamed we should be smarter! Easy to
- // improve.
- let constant_name = format!("{}_{}", canonical_name, name);
+ let constant_name = match mangling_prefix {
+ Some(prefix) => {
+ Cow::Owned(format!("{}_{}", prefix, variant_name))
+ }
+ None => variant_name,
+ };
+
let constant = aster::AstBuilder::new()
.item()
- .const_(constant_name)
+ .pub_()
+ .const_(&*constant_name)
.expr()
.call()
.id(canonical_name)
@@ -1289,10 +1305,32 @@ impl<'a> EnumBuilder<'a> {
}
}
- fn build(self) -> P<ast::Item> {
+ fn build(self,
+ ctx: &BindgenContext,
+ rust_ty: P<ast::Ty>,
+ result: &mut CodegenResult)
+ -> P<ast::Item> {
match self {
EnumBuilder::Rust(b) => b.build(),
- EnumBuilder::Bitfield { aster, .. } => aster,
+ EnumBuilder::Bitfield { canonical_name, aster } => {
+ let rust_ty_name = ctx.rust_ident_raw(canonical_name);
+ let prefix = ctx.trait_prefix();
+
+ let impl_ = quote_item!(ctx.ext_cx(),
+ impl ::$prefix::ops::BitOr<$rust_ty> for $rust_ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitor(self, other: Self) -> Self {
+ $rust_ty_name(self.0 | other.0)
+ }
+ }
+ )
+ .unwrap();
+
+ result.push(impl_);
+ aster
+ }
}
}
}
@@ -1304,8 +1342,6 @@ impl CodeGenerator for Enum {
ctx: &BindgenContext,
result: &mut CodegenResult,
item: &Item) {
- use ir::enum_ty::EnumVariantValue;
-
let name = item.canonical_name(ctx);
let enum_ty = item.expect_type();
let layout = enum_ty.layout(ctx);
@@ -1404,15 +1440,27 @@ impl CodeGenerator for Enum {
result.push(constant);
}
- // Used to mangle the constants we generate in the unnamed-enum case.
- let mut parent_canonical_name = None;
-
let mut builder =
EnumBuilder::new(builder, &name, repr_name, is_rust_enum);
// A map where we keep a value -> variant relation.
let mut seen_values = HashMap::<_, String>::new();
let enum_rust_ty = item.to_rust_ty(ctx);
+ let is_toplevel = item.is_toplevel(ctx);
+
+ // Used to mangle the constants we generate in the unnamed-enum case.
+ let parent_canonical_name = if is_toplevel {
+ None
+ } else {
+ Some(item.parent_id().canonical_name(ctx))
+ };
+
+ let constant_mangling_prefix = if enum_ty.name().is_none() {
+ parent_canonical_name.as_ref().map(|n| &*n)
+ } else {
+ Some(&name)
+ };
+
for variant in self.variants().iter() {
match seen_values.entry(variant.val()) {
Entry::Occupied(ref entry) => {
@@ -1426,46 +1474,30 @@ impl CodeGenerator for Enum {
enum_rust_ty.clone(),
result);
} else {
- // FIXME: Don't repeat this block below.
- let expr = aster::AstBuilder::new().expr();
- let expr = match variant.val() {
- EnumVariantValue::Signed(val) => expr.int(val),
- EnumVariantValue::Unsigned(val) => expr.uint(val),
- };
- let variant_name = ctx.rust_mangle(variant.name());
- builder = builder.with_variant_(ctx,
- &*variant_name,
- expr,
- enum_rust_ty.clone(),
- result);
+ builder = builder.with_variant(ctx,
+ variant,
+ constant_mangling_prefix,
+ enum_rust_ty.clone(),
+ result);
}
}
Entry::Vacant(entry) => {
- let expr = aster::AstBuilder::new().expr();
- let expr = match variant.val() {
- EnumVariantValue::Signed(val) => expr.int(val),
- EnumVariantValue::Unsigned(val) => expr.uint(val),
- };
+ builder = builder.with_variant(ctx,
+ variant,
+ constant_mangling_prefix,
+ enum_rust_ty.clone(),
+ result);
+
let variant_name = ctx.rust_mangle(variant.name());
- builder = builder.with_variant_(ctx,
- &*variant_name,
- expr,
- enum_rust_ty.clone(),
- result);
// If it's an unnamed enum, we also generate a constant so
// it can be properly accessed.
if is_rust_enum && enum_ty.name().is_none() {
// NB: if we want to do this for other kind of nested
// enums we can probably mangle the name.
- let mangled_name = if item.is_toplevel(ctx) {
+ let mangled_name = if is_toplevel {
variant_name.clone()
} else {
- if parent_canonical_name.is_none() {
- parent_canonical_name = Some(item.parent_id()
- .canonical_name(ctx));
- }
-
let parent_name = parent_canonical_name.as_ref()
.unwrap();
@@ -1486,7 +1518,8 @@ impl CodeGenerator for Enum {
}
}
- result.push(builder.build());
+ let enum_ = builder.build(ctx, enum_rust_ty, result);
+ result.push(enum_);
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 2e61840e..316212dc 100755
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -169,7 +169,7 @@ impl Builder {
/// Mark the given enum (or set of enums, if using a pattern) as being
/// bitfield-like.
///
- /// This makes bindgen to generate a type for it that isn't a rust `enum`.
+ /// This makes bindgen generate a type that isn't a rust `enum`.
pub fn bitfield_enum<T: Borrow<str>>(mut self, arg: T) -> Builder {
self.options.bitfield_enums.insert(&arg);
self
diff --git a/tests/expectations/tests/bitfield-enum-basic.rs b/tests/expectations/tests/bitfield-enum-basic.rs
index c287d9eb..03e07de6 100644
--- a/tests/expectations/tests/bitfield-enum-basic.rs
+++ b/tests/expectations/tests/bitfield-enum-basic.rs
@@ -4,17 +4,74 @@
#![allow(non_snake_case)]
-const Foo_Bar: Foo = Foo(2);
-const Foo_Baz: Foo = Foo(4);
-const Foo_Duplicated: Foo = Foo(4);
-const Foo_Negative: Foo = Foo(-3);
+pub const Foo_Bar: Foo = Foo(2);
+pub const Foo_Baz: Foo = Foo(4);
+pub const Foo_Duplicated: Foo = Foo(4);
+pub const Foo_Negative: Foo = Foo(-3);
+impl ::std::ops::BitOr<Foo> for Foo {
+ type
+ Output
+ =
+ Self;
+ #[inline]
+ fn bitor(self, other: Self) -> Self { Foo(self.0 | other.0) }
+}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Foo(pub i32);
-const Buz_Bar: Buz = Buz(2);
-const Buz_Baz: Buz = Buz(4);
-const Buz_Duplicated: Buz = Buz(4);
-const Buz_Negative: Buz = Buz(-3);
+pub const Buz_Bar: Buz = Buz(2);
+pub const Buz_Baz: Buz = Buz(4);
+pub const Buz_Duplicated: Buz = Buz(4);
+pub const Buz_Negative: Buz = Buz(-3);
+impl ::std::ops::BitOr<Buz> for Buz {
+ type
+ Output
+ =
+ Self;
+ #[inline]
+ fn bitor(self, other: Self) -> Self { Buz(self.0 | other.0) }
+}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Buz(pub i8);
+pub const NS_FOO: _bindgen_ty_1 = _bindgen_ty_1(1);
+pub const NS_BAR: _bindgen_ty_1 = _bindgen_ty_1(2);
+impl ::std::ops::BitOr<_bindgen_ty_1> for _bindgen_ty_1 {
+ type
+ Output
+ =
+ Self;
+ #[inline]
+ fn bitor(self, other: Self) -> Self { _bindgen_ty_1(self.0 | other.0) }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct _bindgen_ty_1(pub u32);
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Dummy {
+ pub _address: u8,
+}
+pub const Dummy_DUMMY_FOO: Dummy__bindgen_ty_1 = Dummy__bindgen_ty_1(1);
+pub const Dummy_DUMMY_BAR: Dummy__bindgen_ty_1 = Dummy__bindgen_ty_1(2);
+impl ::std::ops::BitOr<Dummy__bindgen_ty_1> for Dummy__bindgen_ty_1 {
+ type
+ Output
+ =
+ Self;
+ #[inline]
+ fn bitor(self, other: Self) -> Self {
+ Dummy__bindgen_ty_1(self.0 | other.0)
+ }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Dummy__bindgen_ty_1(pub u32);
+#[test]
+fn bindgen_test_layout_Dummy() {
+ assert_eq!(::std::mem::size_of::<Dummy>() , 1usize);
+ assert_eq!(::std::mem::align_of::<Dummy>() , 1usize);
+}
+impl Clone for Dummy {
+ fn clone(&self) -> Self { *self }
+}
diff --git a/tests/headers/bitfield-enum-basic.h b/tests/headers/bitfield-enum-basic.h
index 890735e9..364bebf2 100644
--- a/tests/headers/bitfield-enum-basic.h
+++ b/tests/headers/bitfield-enum-basic.h
@@ -1,4 +1,4 @@
-// bindgen-flags: --bitfield-enum ".*" -- -std=c++11
+// bindgen-flags: --bitfield-enum "Foo|Buz|NS_.*|DUMMY_.*" -- -std=c++11
enum Foo {
Bar = 1 << 1,
@@ -13,3 +13,15 @@ enum class Buz : signed char {
Duplicated = 1 << 2,
Negative = -3,
};
+
+enum {
+ NS_FOO = 1 << 0,
+ NS_BAR = 1 << 1,
+};
+
+class Dummy {
+ enum {
+ DUMMY_FOO = 1 << 0,
+ DUMMY_BAR = 1 << 1,
+ };
+};