Skip to content

Commit 3885130

Browse files
author
bors-servo
authored
Auto merge of #437 - emilio:constify-all-enums, r=fitzgen
codegen: Respect original repr for bitfield-like enums, add a constifying variant. r? @fitzgen Fixes #430
2 parents 0c07e9e + 0df8441 commit 3885130

File tree

6 files changed

+143
-27
lines changed

6 files changed

+143
-27
lines changed

src/codegen/mod.rs

+64-17
Original file line numberDiff line numberDiff line change
@@ -1479,28 +1479,33 @@ enum EnumBuilder<'a> {
14791479
canonical_name: &'a str,
14801480
aster: P<ast::Item>,
14811481
},
1482+
Consts { aster: P<ast::Item>, }
14821483
}
14831484

14841485
impl<'a> EnumBuilder<'a> {
14851486
/// Create a new enum given an item builder, a canonical name, a name for
14861487
/// the representation, and whether it should be represented as a rust enum.
14871488
fn new(aster: aster::item::ItemBuilder<aster::invoke::Identity>,
14881489
name: &'a str,
1489-
repr_name: &str,
1490-
is_rust: bool)
1490+
repr: P<ast::Ty>,
1491+
bitfield_like: bool,
1492+
constify: bool)
14911493
-> Self {
1492-
if is_rust {
1493-
EnumBuilder::Rust(aster.enum_(name))
1494-
} else {
1494+
if bitfield_like {
14951495
EnumBuilder::Bitfield {
14961496
canonical_name: name,
14971497
aster: aster.tuple_struct(name)
14981498
.field()
14991499
.pub_()
1500-
.ty()
1501-
.id(repr_name)
1500+
.build_ty(repr)
15021501
.build(),
15031502
}
1503+
} else if constify {
1504+
EnumBuilder::Consts {
1505+
aster: aster.type_(name).build_ty(repr),
1506+
}
1507+
} else {
1508+
EnumBuilder::Rust(aster.enum_(name))
15041509
}
15051510
}
15061511

@@ -1550,6 +1555,25 @@ impl<'a> EnumBuilder<'a> {
15501555
result.push(constant);
15511556
self
15521557
}
1558+
EnumBuilder::Consts { .. } => {
1559+
let constant_name = match mangling_prefix {
1560+
Some(prefix) => {
1561+
Cow::Owned(format!("{}_{}", prefix, variant_name))
1562+
}
1563+
None => variant_name,
1564+
};
1565+
1566+
let constant = aster::AstBuilder::new()
1567+
.item()
1568+
.pub_()
1569+
.const_(&*constant_name)
1570+
.expr()
1571+
.build(expr)
1572+
.build(rust_ty);
1573+
1574+
result.push(constant);
1575+
self
1576+
}
15531577
}
15541578
}
15551579

@@ -1579,6 +1603,7 @@ impl<'a> EnumBuilder<'a> {
15791603
result.push(impl_);
15801604
aster
15811605
}
1606+
EnumBuilder::Consts { aster, .. } => aster,
15821607
}
15831608
}
15841609
}
@@ -1634,6 +1659,8 @@ impl CodeGenerator for Enum {
16341659

16351660
let mut builder = aster::AstBuilder::new().item().pub_();
16361661

1662+
// FIXME(emilio): These should probably use the path so it can
1663+
// disambiguate between namespaces, just like is_opaque etc.
16371664
let is_bitfield = {
16381665
ctx.options().bitfield_enums.matches(&name) ||
16391666
(enum_ty.name().is_none() &&
@@ -1642,30 +1669,42 @@ impl CodeGenerator for Enum {
16421669
.any(|v| ctx.options().bitfield_enums.matches(&v.name())))
16431670
};
16441671

1645-
let is_rust_enum = !is_bitfield;
1672+
let is_constified_enum = {
1673+
ctx.options().constified_enums.matches(&name) ||
1674+
(enum_ty.name().is_none() &&
1675+
self.variants()
1676+
.iter()
1677+
.any(|v| ctx.options().constified_enums.matches(&v.name())))
1678+
};
1679+
1680+
let is_rust_enum = !is_bitfield && !is_constified_enum;
16461681

16471682
// FIXME: Rust forbids repr with empty enums. Remove this condition when
16481683
// this is allowed.
1684+
//
1685+
// TODO(emilio): Delegate this to the builders?
16491686
if is_rust_enum {
16501687
if !self.variants().is_empty() {
16511688
builder = builder.with_attr(attributes::repr(repr_name));
16521689
}
1653-
} else {
1690+
} else if is_bitfield {
16541691
builder = builder.with_attr(attributes::repr("C"));
16551692
}
16561693

16571694
if let Some(comment) = item.comment() {
16581695
builder = builder.with_attr(attributes::doc(comment));
16591696
}
16601697

1661-
let derives = attributes::derives(&["Debug",
1662-
"Copy",
1663-
"Clone",
1664-
"PartialEq",
1665-
"Eq",
1666-
"Hash"]);
1698+
if !is_constified_enum {
1699+
let derives = attributes::derives(&["Debug",
1700+
"Copy",
1701+
"Clone",
1702+
"PartialEq",
1703+
"Eq",
1704+
"Hash"]);
16671705

1668-
builder = builder.with_attr(derives);
1706+
builder = builder.with_attr(derives);
1707+
}
16691708

16701709
fn add_constant<'a>(enum_: &Type,
16711710
// Only to avoid recomputing every time.
@@ -1695,8 +1734,16 @@ impl CodeGenerator for Enum {
16951734
result.push(constant);
16961735
}
16971736

1737+
let repr = self.repr()
1738+
.map(|repr| repr.to_rust_ty(ctx))
1739+
.unwrap_or_else(|| helpers::ast_ty::raw_type(ctx, repr_name));
1740+
16981741
let mut builder =
1699-
EnumBuilder::new(builder, &name, repr_name, is_rust_enum);
1742+
EnumBuilder::new(builder,
1743+
&name,
1744+
repr,
1745+
is_bitfield,
1746+
is_constified_enum);
17001747

17011748
// A map where we keep a value -> variant relation.
17021749
let mut seen_values = HashMap::<_, String>::new();

src/lib.rs

+27-6
Original file line numberDiff line numberDiff line change
@@ -182,34 +182,39 @@ impl Builder {
182182
self
183183
}
184184

185-
/// Hide the given type from the generated bindings. Regular expressions are supported.
185+
/// Hide the given type from the generated bindings. Regular expressions are
186+
/// supported.
186187
pub fn hide_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
187188
self.options.hidden_types.insert(arg);
188189
self
189190
}
190191

191-
/// Treat the given type as opaque in the generated bindings. Regular expressions are supported.
192+
/// Treat the given type as opaque in the generated bindings. Regular
193+
/// expressions are supported.
192194
pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
193195
self.options.opaque_types.insert(arg);
194196
self
195197
}
196198

197199
/// Whitelist the given type so that it (and all types that it transitively
198-
/// refers to) appears in the generated bindings. Regular expressions are supported.
200+
/// refers to) appears in the generated bindings. Regular expressions are
201+
/// supported.
199202
pub fn whitelisted_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
200203
self.options.whitelisted_types.insert(arg);
201204
self
202205
}
203206

204207
/// Whitelist the given function so that it (and all types that it
205-
/// transitively refers to) appears in the generated bindings. Regular expressions are supported.
208+
/// transitively refers to) appears in the generated bindings. Regular
209+
/// expressions are supported.
206210
pub fn whitelisted_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
207211
self.options.whitelisted_functions.insert(arg);
208212
self
209213
}
210214

211215
/// Whitelist the given variable so that it (and all types that it
212-
/// transitively refers to) appears in the generated bindings. Regular expressions are supported.
216+
/// transitively refers to) appears in the generated bindings. Regular
217+
/// expressions are supported.
213218
pub fn whitelisted_var<T: AsRef<str>>(mut self, arg: T) -> Builder {
214219
self.options.whitelisted_vars.insert(arg);
215220
self
@@ -218,12 +223,23 @@ impl Builder {
218223
/// Mark the given enum (or set of enums, if using a pattern) as being
219224
/// bitfield-like. Regular expressions are supported.
220225
///
221-
/// This makes bindgen generate a type that isn't a rust `enum`.
226+
/// This makes bindgen generate a type that isn't a rust `enum`. Regular
227+
/// expressions are supported.
222228
pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
223229
self.options.bitfield_enums.insert(arg);
224230
self
225231
}
226232

233+
/// Mark the given enum (or set of enums, if using a pattern) as being
234+
/// constant.
235+
///
236+
/// This makes bindgen generate constants instead of enums. Regular
237+
/// expressions are supported.
238+
pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
239+
self.options.constified_enums.insert(arg);
240+
self
241+
}
242+
227243
/// Add a string to prepend to the generated bindings. The string is passed
228244
/// through without any modification.
229245
pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder {
@@ -424,6 +440,9 @@ pub struct BindgenOptions {
424440
/// The enum patterns to mark an enum as bitfield.
425441
pub bitfield_enums: RegexSet,
426442

443+
/// The enum patterns to mark an enum as constant.
444+
pub constified_enums: RegexSet,
445+
427446
/// Whether we should generate builtins or not.
428447
pub builtins: bool,
429448

@@ -502,6 +521,7 @@ impl BindgenOptions {
502521
self.hidden_types.build();
503522
self.opaque_types.build();
504523
self.bitfield_enums.build();
524+
self.constified_enums.build();
505525
}
506526
}
507527

@@ -514,6 +534,7 @@ impl Default for BindgenOptions {
514534
whitelisted_functions: Default::default(),
515535
whitelisted_vars: Default::default(),
516536
bitfield_enums: Default::default(),
537+
constified_enums: Default::default(),
517538
builtins: false,
518539
links: vec![],
519540
emit_ast: false,

src/options.rs

+14
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ pub fn builder_from_flags<I>(args: I)
2424
.takes_value(true)
2525
.multiple(true)
2626
.number_of_values(1),
27+
Arg::with_name("constified-enum")
28+
.long("constified-enum")
29+
.help("Mark any enum whose name matches <regex> as a set of \
30+
constants instead of an enumeration.")
31+
.value_name("regex")
32+
.takes_value(true)
33+
.multiple(true)
34+
.number_of_values(1),
2735
Arg::with_name("blacklist-type")
2836
.long("blacklist-type")
2937
.help("Mark a type as hidden.")
@@ -174,6 +182,12 @@ pub fn builder_from_flags<I>(args: I)
174182
}
175183
}
176184

185+
if let Some(bitfields) = matches.values_of("constified-enum") {
186+
for regex in bitfields {
187+
builder = builder.constified_enum(regex);
188+
}
189+
}
190+
177191
if let Some(hidden_types) = matches.values_of("blacklist-type") {
178192
for ty in hidden_types {
179193
builder = builder.hide_type(ty);

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl ::std::ops::BitOr<Foo> for Foo {
1818
}
1919
#[repr(C)]
2020
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
21-
pub struct Foo(pub i32);
21+
pub struct Foo(pub ::std::os::raw::c_int);
2222
pub const Buz_Bar: Buz = Buz(2);
2323
pub const Buz_Baz: Buz = Buz(4);
2424
pub const Buz_Duplicated: Buz = Buz(4);
@@ -33,7 +33,7 @@ impl ::std::ops::BitOr<Buz> for Buz {
3333
}
3434
#[repr(C)]
3535
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
36-
pub struct Buz(pub i8);
36+
pub struct Buz(pub ::std::os::raw::c_char);
3737
pub const NS_FOO: _bindgen_ty_1 = _bindgen_ty_1(1);
3838
pub const NS_BAR: _bindgen_ty_1 = _bindgen_ty_1(2);
3939
impl ::std::ops::BitOr<_bindgen_ty_1> for _bindgen_ty_1 {
@@ -46,7 +46,7 @@ impl ::std::ops::BitOr<_bindgen_ty_1> for _bindgen_ty_1 {
4646
}
4747
#[repr(C)]
4848
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
49-
pub struct _bindgen_ty_1(pub u32);
49+
pub struct _bindgen_ty_1(pub ::std::os::raw::c_uint);
5050
#[repr(C)]
5151
#[derive(Debug, Copy)]
5252
pub struct Dummy {
@@ -66,7 +66,7 @@ impl ::std::ops::BitOr<Dummy__bindgen_ty_1> for Dummy__bindgen_ty_1 {
6666
}
6767
#[repr(C)]
6868
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
69-
pub struct Dummy__bindgen_ty_1(pub u32);
69+
pub struct Dummy__bindgen_ty_1(pub ::std::os::raw::c_uint);
7070
#[test]
7171
fn bindgen_test_layout_Dummy() {
7272
assert_eq!(::std::mem::size_of::<Dummy>() , 1usize);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
pub const foo_THIS: foo = 0;
8+
pub const foo_SHOULD_BE: foo = 1;
9+
pub const foo_A_CONSTANT: foo = 2;
10+
pub type foo = ::std::os::raw::c_uint;
11+
#[repr(C)]
12+
#[derive(Debug, Copy)]
13+
pub struct bar {
14+
pub this_should_work: foo,
15+
}
16+
#[test]
17+
fn bindgen_test_layout_bar() {
18+
assert_eq!(::std::mem::size_of::<bar>() , 4usize);
19+
assert_eq!(::std::mem::align_of::<bar>() , 4usize);
20+
}
21+
impl Clone for bar {
22+
fn clone(&self) -> Self { *self }
23+
}

tests/headers/constify-all-enums.h

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// bindgen-flags: --constified-enum foo
2+
3+
enum foo {
4+
THIS,
5+
SHOULD_BE,
6+
A_CONSTANT,
7+
};
8+
9+
struct bar {
10+
enum foo this_should_work;
11+
};

0 commit comments

Comments
 (0)