Skip to content

Commit 586f6bd

Browse files
committed
codegen: Simplify bitfield logic a bit, make it work for unnamed enums, generate
default BitOr implementation.
1 parent 19db528 commit 586f6bd

File tree

4 files changed

+163
-61
lines changed

4 files changed

+163
-61
lines changed

src/bin/bindgen.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ Options:
9292
matching <regex>. Same behavior on emptyness
9393
than the type whitelisting.
9494
95-
--bitfield-enum=<regex> Mark a bitfield as being used as an enum.
96-
This makes bindgen don't generate a rust enum
97-
for it, but a bitfield-like wrapper.
95+
--bitfield-enum=<regex> Mark any enum whose name matches <regex> as a
96+
set of bitfield flags instead of an
97+
enumeration.
9898
9999
--dummy-uses=<path> For testing purposes, generate a C/C++ file
100100
containing dummy uses of all types defined in

src/codegen/mod.rs

Lines changed: 82 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use aster;
66
use ir::annotations::FieldAccessorKind;
77
use ir::comp::{CompInfo, CompKind, Field, Method};
88
use ir::context::BindgenContext;
9-
use ir::enum_ty::Enum;
9+
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
1010
use ir::function::{Function, FunctionSig};
1111
use ir::int::IntKind;
1212
use ir::item::{Item, ItemCanonicalName, ItemCanonicalPath, ItemId};
@@ -1224,6 +1224,7 @@ impl MethodCodegen for Method {
12241224
}
12251225
}
12261226

1227+
/// A helper type to construct enums, either bitfield ones or rust-style ones.
12271228
enum EnumBuilder<'a> {
12281229
Rust(aster::item::ItemEnumBuilder<aster::invoke::Identity>),
12291230
Bitfield {
@@ -1233,6 +1234,8 @@ enum EnumBuilder<'a> {
12331234
}
12341235

12351236
impl<'a> EnumBuilder<'a> {
1237+
/// Create a new enum given an item builder, a canonical name, a name for
1238+
/// the representation, and whether it should be represented as a rust enum.
12361239
fn new(aster: aster::item::ItemBuilder<aster::invoke::Identity>,
12371240
name: &'a str,
12381241
repr_name: &str,
@@ -1253,29 +1256,42 @@ impl<'a> EnumBuilder<'a> {
12531256
}
12541257
}
12551258

1256-
fn with_variant_(self,
1257-
ctx: &BindgenContext,
1258-
name: &str,
1259-
expr: P<ast::Expr>,
1260-
rust_ty: P<ast::Ty>,
1261-
result: &mut CodegenResult)
1262-
-> Self {
1259+
/// Add a variant to this enum.
1260+
fn with_variant(self,
1261+
ctx: &BindgenContext,
1262+
variant: &EnumVariant,
1263+
mangling_prefix: Option<&String>,
1264+
rust_ty: P<ast::Ty>,
1265+
result: &mut CodegenResult)
1266+
-> Self {
1267+
let variant_name = ctx.rust_mangle(variant.name());
1268+
let expr = aster::AstBuilder::new().expr();
1269+
let expr = match variant.val() {
1270+
EnumVariantValue::Signed(v) => expr.int(v),
1271+
EnumVariantValue::Unsigned(v) => expr.uint(v),
1272+
};
1273+
12631274
match self {
12641275
EnumBuilder::Rust(b) => {
12651276
EnumBuilder::Rust(b.with_variant_(ast::Variant_ {
1266-
name: ctx.rust_ident(name),
1277+
name: ctx.rust_ident(&*variant_name),
12671278
attrs: vec![],
12681279
data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
12691280
disr_expr: Some(expr),
12701281
}))
12711282
}
12721283
EnumBuilder::Bitfield { canonical_name, .. } => {
1273-
// FIXME: Probably if unnamed we should be smarter! Easy to
1274-
// improve.
1275-
let constant_name = format!("{}_{}", canonical_name, name);
1284+
let constant_name = match mangling_prefix {
1285+
Some(prefix) => {
1286+
Cow::Owned(format!("{}_{}", prefix, variant_name))
1287+
}
1288+
None => variant_name,
1289+
};
1290+
12761291
let constant = aster::AstBuilder::new()
12771292
.item()
1278-
.const_(constant_name)
1293+
.pub_()
1294+
.const_(&*constant_name)
12791295
.expr()
12801296
.call()
12811297
.id(canonical_name)
@@ -1289,10 +1305,32 @@ impl<'a> EnumBuilder<'a> {
12891305
}
12901306
}
12911307

1292-
fn build(self) -> P<ast::Item> {
1308+
fn build(self,
1309+
ctx: &BindgenContext,
1310+
rust_ty: P<ast::Ty>,
1311+
result: &mut CodegenResult)
1312+
-> P<ast::Item> {
12931313
match self {
12941314
EnumBuilder::Rust(b) => b.build(),
1295-
EnumBuilder::Bitfield { aster, .. } => aster,
1315+
EnumBuilder::Bitfield { canonical_name, aster } => {
1316+
let rust_ty_name = ctx.rust_ident_raw(canonical_name);
1317+
let prefix = ctx.trait_prefix();
1318+
1319+
let impl_ = quote_item!(ctx.ext_cx(),
1320+
impl ::$prefix::ops::BitOr<$rust_ty> for $rust_ty {
1321+
type Output = Self;
1322+
1323+
#[inline]
1324+
fn bitor(self, other: Self) -> Self {
1325+
$rust_ty_name(self.0 | other.0)
1326+
}
1327+
}
1328+
)
1329+
.unwrap();
1330+
1331+
result.push(impl_);
1332+
aster
1333+
}
12961334
}
12971335
}
12981336
}
@@ -1304,8 +1342,6 @@ impl CodeGenerator for Enum {
13041342
ctx: &BindgenContext,
13051343
result: &mut CodegenResult,
13061344
item: &Item) {
1307-
use ir::enum_ty::EnumVariantValue;
1308-
13091345
let name = item.canonical_name(ctx);
13101346
let enum_ty = item.expect_type();
13111347
let layout = enum_ty.layout(ctx);
@@ -1404,15 +1440,27 @@ impl CodeGenerator for Enum {
14041440
result.push(constant);
14051441
}
14061442

1407-
// Used to mangle the constants we generate in the unnamed-enum case.
1408-
let mut parent_canonical_name = None;
1409-
14101443
let mut builder =
14111444
EnumBuilder::new(builder, &name, repr_name, is_rust_enum);
14121445

14131446
// A map where we keep a value -> variant relation.
14141447
let mut seen_values = HashMap::<_, String>::new();
14151448
let enum_rust_ty = item.to_rust_ty(ctx);
1449+
let is_toplevel = item.is_toplevel(ctx);
1450+
1451+
// Used to mangle the constants we generate in the unnamed-enum case.
1452+
let parent_canonical_name = if is_toplevel {
1453+
None
1454+
} else {
1455+
Some(item.parent_id().canonical_name(ctx))
1456+
};
1457+
1458+
let constant_mangling_prefix = if enum_ty.name().is_none() {
1459+
parent_canonical_name.as_ref().map(|n| &*n)
1460+
} else {
1461+
Some(&name)
1462+
};
1463+
14161464
for variant in self.variants().iter() {
14171465
match seen_values.entry(variant.val()) {
14181466
Entry::Occupied(ref entry) => {
@@ -1426,46 +1474,30 @@ impl CodeGenerator for Enum {
14261474
enum_rust_ty.clone(),
14271475
result);
14281476
} else {
1429-
// FIXME: Don't repeat this block below.
1430-
let expr = aster::AstBuilder::new().expr();
1431-
let expr = match variant.val() {
1432-
EnumVariantValue::Signed(val) => expr.int(val),
1433-
EnumVariantValue::Unsigned(val) => expr.uint(val),
1434-
};
1435-
let variant_name = ctx.rust_mangle(variant.name());
1436-
builder = builder.with_variant_(ctx,
1437-
&*variant_name,
1438-
expr,
1439-
enum_rust_ty.clone(),
1440-
result);
1477+
builder = builder.with_variant(ctx,
1478+
variant,
1479+
constant_mangling_prefix,
1480+
enum_rust_ty.clone(),
1481+
result);
14411482
}
14421483
}
14431484
Entry::Vacant(entry) => {
1444-
let expr = aster::AstBuilder::new().expr();
1445-
let expr = match variant.val() {
1446-
EnumVariantValue::Signed(val) => expr.int(val),
1447-
EnumVariantValue::Unsigned(val) => expr.uint(val),
1448-
};
1485+
builder = builder.with_variant(ctx,
1486+
variant,
1487+
constant_mangling_prefix,
1488+
enum_rust_ty.clone(),
1489+
result);
1490+
14491491
let variant_name = ctx.rust_mangle(variant.name());
1450-
builder = builder.with_variant_(ctx,
1451-
&*variant_name,
1452-
expr,
1453-
enum_rust_ty.clone(),
1454-
result);
14551492

14561493
// If it's an unnamed enum, we also generate a constant so
14571494
// it can be properly accessed.
14581495
if is_rust_enum && enum_ty.name().is_none() {
14591496
// NB: if we want to do this for other kind of nested
14601497
// enums we can probably mangle the name.
1461-
let mangled_name = if item.is_toplevel(ctx) {
1498+
let mangled_name = if is_toplevel {
14621499
variant_name.clone()
14631500
} else {
1464-
if parent_canonical_name.is_none() {
1465-
parent_canonical_name = Some(item.parent_id()
1466-
.canonical_name(ctx));
1467-
}
1468-
14691501
let parent_name = parent_canonical_name.as_ref()
14701502
.unwrap();
14711503

@@ -1486,7 +1518,8 @@ impl CodeGenerator for Enum {
14861518
}
14871519
}
14881520

1489-
result.push(builder.build());
1521+
let enum_ = builder.build(ctx, enum_rust_ty, result);
1522+
result.push(enum_);
14901523
}
14911524
}
14921525

tests/expectations/tests/bitfield-enum-basic.rs

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,74 @@
44
#![allow(non_snake_case)]
55

66

7-
const Foo_Bar: Foo = Foo(2);
8-
const Foo_Baz: Foo = Foo(4);
9-
const Foo_Duplicated: Foo = Foo(4);
10-
const Foo_Negative: Foo = Foo(-3);
7+
pub const Foo_Bar: Foo = Foo(2);
8+
pub const Foo_Baz: Foo = Foo(4);
9+
pub const Foo_Duplicated: Foo = Foo(4);
10+
pub const Foo_Negative: Foo = Foo(-3);
11+
impl ::std::ops::BitOr<Foo> for Foo {
12+
type
13+
Output
14+
=
15+
Self;
16+
#[inline]
17+
fn bitor(self, other: Self) -> Self { Foo(self.0 | other.0) }
18+
}
1119
#[repr(C)]
1220
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1321
pub struct Foo(pub i32);
14-
const Buz_Bar: Buz = Buz(2);
15-
const Buz_Baz: Buz = Buz(4);
16-
const Buz_Duplicated: Buz = Buz(4);
17-
const Buz_Negative: Buz = Buz(-3);
22+
pub const Buz_Bar: Buz = Buz(2);
23+
pub const Buz_Baz: Buz = Buz(4);
24+
pub const Buz_Duplicated: Buz = Buz(4);
25+
pub const Buz_Negative: Buz = Buz(-3);
26+
impl ::std::ops::BitOr<Buz> for Buz {
27+
type
28+
Output
29+
=
30+
Self;
31+
#[inline]
32+
fn bitor(self, other: Self) -> Self { Buz(self.0 | other.0) }
33+
}
1834
#[repr(C)]
1935
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2036
pub struct Buz(pub i8);
37+
pub const NS_FOO: _bindgen_ty_1 = _bindgen_ty_1(1);
38+
pub const NS_BAR: _bindgen_ty_1 = _bindgen_ty_1(2);
39+
impl ::std::ops::BitOr<_bindgen_ty_1> for _bindgen_ty_1 {
40+
type
41+
Output
42+
=
43+
Self;
44+
#[inline]
45+
fn bitor(self, other: Self) -> Self { _bindgen_ty_1(self.0 | other.0) }
46+
}
47+
#[repr(C)]
48+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
49+
pub struct _bindgen_ty_1(pub u32);
50+
#[repr(C)]
51+
#[derive(Debug, Copy)]
52+
pub struct Dummy {
53+
pub _address: u8,
54+
}
55+
pub const Dummy_DUMMY_FOO: Dummy__bindgen_ty_1 = Dummy__bindgen_ty_1(1);
56+
pub const Dummy_DUMMY_BAR: Dummy__bindgen_ty_1 = Dummy__bindgen_ty_1(2);
57+
impl ::std::ops::BitOr<Dummy__bindgen_ty_1> for Dummy__bindgen_ty_1 {
58+
type
59+
Output
60+
=
61+
Self;
62+
#[inline]
63+
fn bitor(self, other: Self) -> Self {
64+
Dummy__bindgen_ty_1(self.0 | other.0)
65+
}
66+
}
67+
#[repr(C)]
68+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
69+
pub struct Dummy__bindgen_ty_1(pub u32);
70+
#[test]
71+
fn bindgen_test_layout_Dummy() {
72+
assert_eq!(::std::mem::size_of::<Dummy>() , 1usize);
73+
assert_eq!(::std::mem::align_of::<Dummy>() , 1usize);
74+
}
75+
impl Clone for Dummy {
76+
fn clone(&self) -> Self { *self }
77+
}

tests/headers/bitfield-enum-basic.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// bindgen-flags: --bitfield-enum ".*" -- -std=c++11
1+
// bindgen-flags: --bitfield-enum "Foo|Buz|NS_.*|DUMMY_.*" -- -std=c++11
22

33
enum Foo {
44
Bar = 1 << 1,
@@ -13,3 +13,15 @@ enum class Buz : signed char {
1313
Duplicated = 1 << 2,
1414
Negative = -3,
1515
};
16+
17+
enum {
18+
NS_FOO = 1 << 0,
19+
NS_BAR = 1 << 1,
20+
};
21+
22+
class Dummy {
23+
enum {
24+
DUMMY_FOO = 1 << 0,
25+
DUMMY_BAR = 1 << 1,
26+
};
27+
};

0 commit comments

Comments
 (0)