Skip to content

Commit 89915f9

Browse files
committed
Make bindgen generate enums as constants by default
Also simplifies the logic that determines which enum variation gets chosen.
1 parent 4dd4ac7 commit 89915f9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+182
-110
lines changed

bindgen-integration/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ fn main() {
2929

3030
let bindings = Builder::default()
3131
.enable_cxx_namespaces()
32+
.rustified_enum(".*")
3233
.raw_line("pub use self::root::*;")
3334
.header("cpp/Test.h")
3435
.clang_args(&["-x", "c++", "-std=c++11"])

src/codegen/mod.rs

Lines changed: 80 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,7 +2072,41 @@ impl MethodCodegen for Method {
20722072
}
20732073
}
20742074

2075-
/// A helper type to construct enums, either bitfield ones or rust-style ones.
2075+
/// A helper type that represents different enum variations.
2076+
#[derive(Copy, Clone)]
2077+
enum EnumVariation {
2078+
Rust,
2079+
Bitfield,
2080+
Consts,
2081+
ModuleConsts
2082+
}
2083+
2084+
impl EnumVariation {
2085+
fn is_rust(&self) -> bool {
2086+
match *self {
2087+
EnumVariation::Rust => true,
2088+
_ => false
2089+
}
2090+
}
2091+
2092+
fn is_bitfield(&self) -> bool {
2093+
match *self {
2094+
EnumVariation::Bitfield => true,
2095+
_ => false
2096+
}
2097+
}
2098+
2099+
/// Both the `Const` and `ModuleConsts` variants will cause this to return
2100+
/// true.
2101+
fn is_const(&self) -> bool {
2102+
match *self {
2103+
EnumVariation::Consts | EnumVariation::ModuleConsts => true,
2104+
_ => false
2105+
}
2106+
}
2107+
}
2108+
2109+
/// A helper type to construct different enum variations.
20762110
enum EnumBuilder<'a> {
20772111
Rust(quote::Tokens),
20782112
Bitfield {
@@ -2088,26 +2122,44 @@ enum EnumBuilder<'a> {
20882122

20892123
impl<'a> EnumBuilder<'a> {
20902124
/// Create a new enum given an item builder, a canonical name, a name for
2091-
/// the representation, and whether it should be represented as a rust enum.
2125+
/// the representation, and which variation it should be generated as.
20922126
fn new(
20932127
name: &'a str,
20942128
attrs: Vec<quote::Tokens>,
20952129
repr: quote::Tokens,
2096-
bitfield_like: bool,
2097-
constify: bool,
2098-
constify_module: bool,
2130+
enum_variation: EnumVariation
20992131
) -> Self {
21002132
let ident = quote::Ident::new(name);
2101-
if bitfield_like {
2102-
EnumBuilder::Bitfield {
2103-
canonical_name: name,
2104-
tokens: quote! {
2133+
2134+
match enum_variation {
2135+
EnumVariation::Bitfield => {
2136+
EnumBuilder::Bitfield {
2137+
canonical_name: name,
2138+
tokens: quote! {
2139+
#( #attrs )*
2140+
pub struct #ident (pub #repr);
2141+
},
2142+
}
2143+
}
2144+
2145+
EnumVariation::Rust => {
2146+
let mut tokens = quote! {
21052147
#( #attrs )*
2106-
pub struct #ident (pub #repr);
2107-
},
2148+
pub enum #ident
2149+
};
2150+
tokens.append("{");
2151+
EnumBuilder::Rust(tokens)
21082152
}
2109-
} else if constify {
2110-
if constify_module {
2153+
2154+
EnumVariation::Consts => {
2155+
EnumBuilder::Consts(vec![
2156+
quote! {
2157+
pub type #ident = #repr;
2158+
}
2159+
])
2160+
}
2161+
2162+
EnumVariation::ModuleConsts => {
21112163
let ident = quote::Ident::new(CONSTIFIED_ENUM_MODULE_REPR_NAME);
21122164
let type_definition = quote! {
21132165
pub type #ident = #repr;
@@ -2117,20 +2169,7 @@ impl<'a> EnumBuilder<'a> {
21172169
module_name: name,
21182170
module_items: vec![type_definition],
21192171
}
2120-
} else {
2121-
EnumBuilder::Consts(vec![
2122-
quote! {
2123-
pub type #ident = #repr;
2124-
}
2125-
])
21262172
}
2127-
} else {
2128-
let mut tokens = quote! {
2129-
#( #attrs )*
2130-
pub enum #ident
2131-
};
2132-
tokens.append("{");
2133-
EnumBuilder::Rust(tokens)
21342173
}
21352174
}
21362175

@@ -2342,47 +2381,36 @@ impl CodeGenerator for Enum {
23422381

23432382
// FIXME(emilio): These should probably use the path so it can
23442383
// disambiguate between namespaces, just like is_opaque etc.
2345-
let is_bitfield = {
2346-
ctx.options().bitfield_enums.matches(&name) ||
2347-
(enum_ty.name().is_none() &&
2348-
self.variants().iter().any(|v| {
2349-
ctx.options().bitfield_enums.matches(&v.name())
2350-
}))
2351-
};
2352-
2353-
let is_constified_enum_module =
2354-
self.is_constified_enum_module(ctx, item);
2355-
2356-
let is_constified_enum = {
2357-
is_constified_enum_module ||
2358-
ctx.options().constified_enums.matches(&name) ||
2359-
(enum_ty.name().is_none() &&
2360-
self.variants().iter().any(|v| {
2361-
ctx.options().constified_enums.matches(&v.name())
2362-
}))
2384+
let variation = if self.is_bitfield(ctx, item) {
2385+
EnumVariation::Bitfield
2386+
} else if self.is_rustified_enum(ctx, item) {
2387+
EnumVariation::Rust
2388+
} else if self.is_constified_enum_module(ctx, item) {
2389+
EnumVariation::ModuleConsts
2390+
} else {
2391+
// We generate consts by default
2392+
EnumVariation::Consts
23632393
};
23642394

2365-
let is_rust_enum = !is_bitfield && !is_constified_enum;
2366-
23672395
let mut attrs = vec![];
23682396

23692397
// FIXME: Rust forbids repr with empty enums. Remove this condition when
23702398
// this is allowed.
23712399
//
23722400
// TODO(emilio): Delegate this to the builders?
2373-
if is_rust_enum {
2401+
if variation.is_rust() {
23742402
if !self.variants().is_empty() {
23752403
attrs.push(attributes::repr(repr_name));
23762404
}
2377-
} else if is_bitfield {
2405+
} else if variation.is_bitfield() {
23782406
attrs.push(attributes::repr("C"));
23792407
}
23802408

23812409
if let Some(comment) = item.comment(ctx) {
23822410
attrs.push(attributes::doc(comment));
23832411
}
23842412

2385-
if !is_constified_enum {
2413+
if !variation.is_const() {
23862414
attrs.push(attributes::derives(
23872415
&["Debug", "Copy", "Clone", "PartialEq", "Eq", "Hash"],
23882416
));
@@ -2427,9 +2455,7 @@ impl CodeGenerator for Enum {
24272455
&name,
24282456
attrs,
24292457
repr,
2430-
is_bitfield,
2431-
is_constified_enum,
2432-
is_constified_enum_module,
2458+
variation
24332459
);
24342460

24352461
// A map where we keep a value -> variant relation.
@@ -2475,7 +2501,7 @@ impl CodeGenerator for Enum {
24752501

24762502
match seen_values.entry(variant.val()) {
24772503
Entry::Occupied(ref entry) => {
2478-
if is_rust_enum {
2504+
if variation.is_rust() {
24792505
let variant_name = ctx.rust_mangle(variant.name());
24802506
let mangled_name =
24812507
if is_toplevel || enum_ty.name().is_some() {
@@ -2523,7 +2549,7 @@ impl CodeGenerator for Enum {
25232549
// If it's an unnamed enum, or constification is enforced,
25242550
// we also generate a constant so it can be properly
25252551
// accessed.
2526-
if (is_rust_enum && enum_ty.name().is_none()) ||
2552+
if (variation.is_rust() && enum_ty.name().is_none()) ||
25272553
variant.force_constification()
25282554
{
25292555
let mangled_name = if is_toplevel {

src/ir/enum_ty.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,18 @@ impl Enum {
128128
Ok(Enum::new(repr, variants))
129129
}
130130

131+
/// Whether the enum should be a bitfield
132+
pub fn is_bitfield(&self, ctx: &BindgenContext, item: &Item) -> bool {
133+
let name = item.canonical_name(ctx);
134+
let enum_ty = item.expect_type();
135+
136+
ctx.options().bitfield_enums.matches(&name) ||
137+
(enum_ty.name().is_none() &&
138+
self.variants().iter().any(|v| {
139+
ctx.options().bitfield_enums.matches(&v.name())
140+
}))
141+
}
142+
131143
/// Whether the enum should be an constified enum module
132144
pub fn is_constified_enum_module(
133145
&self,
@@ -143,6 +155,18 @@ impl Enum {
143155
ctx.options().constified_enum_modules.matches(&v.name())
144156
}))
145157
}
158+
159+
/// Whether the enum should be a Rust enum
160+
pub fn is_rustified_enum(&self, ctx: &BindgenContext, item: &Item) -> bool {
161+
let name = item.canonical_name(ctx);
162+
let enum_ty = item.expect_type();
163+
164+
ctx.options().rustified_enums.matches(&name) ||
165+
(enum_ty.name().is_none() &&
166+
self.variants().iter().any(|v| {
167+
ctx.options().rustified_enums.matches(&v.name())
168+
}))
169+
}
146170
}
147171

148172
/// A single enum variant, to be contained only in an enum.

src/lib.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,11 @@ impl Builder {
197197
.count();
198198

199199
self.options
200-
.constified_enums
200+
.rustified_enums
201201
.get_items()
202202
.iter()
203203
.map(|item| {
204-
output_vector.push("--constified-enum".into());
204+
output_vector.push("--rustified-enum".into());
205205
output_vector.push(
206206
item.trim_left_matches("^")
207207
.trim_right_matches("$")
@@ -666,21 +666,26 @@ impl Builder {
666666
self
667667
}
668668

669-
/// Mark the given enum (or set of enums, if using a pattern) as a set of
670-
/// constants.
669+
/// Mark the given enum (or set of enums, if using a pattern) as a Rust
670+
/// enum.
671671
///
672-
/// This makes bindgen generate constants instead of enums. Regular
672+
/// This makes bindgen generate enums instead of constants. Regular
673673
/// expressions are supported.
674-
pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
675-
self.options.constified_enums.insert(arg);
674+
///
675+
/// **Use this with caution.** You should not be using Rust enums unless
676+
/// you have complete control of the C/C++ code that you're binding to.
677+
/// Take a look at https://github.com/rust-lang/rust/issues/36927 for
678+
/// more information.
679+
pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
680+
self.options.rustified_enums.insert(arg);
676681
self
677682
}
678683

679684
/// Mark the given enum (or set of enums, if using a pattern) as a set of
680685
/// constants that should be put into a module.
681686
///
682-
/// This makes bindgen generate a modules containing constants instead of
683-
/// enums. Regular expressions are supported.
687+
/// This makes bindgen generate modules containing constants instead of
688+
/// just constants. Regular expressions are supported.
684689
pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder {
685690
self.options.constified_enum_modules.insert(arg);
686691
self
@@ -1094,8 +1099,8 @@ pub struct BindgenOptions {
10941099
/// The enum patterns to mark an enum as bitfield.
10951100
pub bitfield_enums: RegexSet,
10961101

1097-
/// The enum patterns to mark an enum as constant.
1098-
pub constified_enums: RegexSet,
1102+
/// The enum patterns to mark an enum as a Rust enum.
1103+
pub rustified_enums: RegexSet,
10991104

11001105
/// The enum patterns to mark an enum as a module of constants.
11011106
pub constified_enum_modules: RegexSet,
@@ -1251,7 +1256,7 @@ impl BindgenOptions {
12511256
self.opaque_types.build();
12521257
self.bitfield_enums.build();
12531258
self.constified_enum_modules.build();
1254-
self.constified_enums.build();
1259+
self.rustified_enums.build();
12551260
}
12561261

12571262
/// Update rust target version
@@ -1286,7 +1291,7 @@ impl Default for BindgenOptions {
12861291
whitelisted_functions: Default::default(),
12871292
whitelisted_vars: Default::default(),
12881293
bitfield_enums: Default::default(),
1289-
constified_enums: Default::default(),
1294+
rustified_enums: Default::default(),
12901295
constified_enum_modules: Default::default(),
12911296
builtins: false,
12921297
links: vec![],

src/options.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,18 @@ where
3434
.takes_value(true)
3535
.multiple(true)
3636
.number_of_values(1),
37-
Arg::with_name("constified-enum")
38-
.long("constified-enum")
39-
.help("Mark any enum whose name matches <regex> as a set of \
40-
constants instead of an enumeration.")
37+
Arg::with_name("rustified-enum")
38+
.long("rustified-enum")
39+
.help("Mark any enum whose name matches <regex> as a Rust enum \
40+
instead of a set of constants.")
4141
.value_name("regex")
4242
.takes_value(true)
4343
.multiple(true)
4444
.number_of_values(1),
4545
Arg::with_name("constified-enum-module")
4646
.long("constified-enum-module")
4747
.help("Mark any enum whose name matches <regex> as a module of \
48-
constants instead of an enumeration. This option \
49-
implies \"--constified-enum.\"")
48+
constants instead of just constants.")
5049
.value_name("regex")
5150
.takes_value(true)
5251
.multiple(true)
@@ -292,9 +291,9 @@ where
292291
}
293292
}
294293

295-
if let Some(constifieds) = matches.values_of("constified-enum") {
296-
for regex in constifieds {
297-
builder = builder.constified_enum(regex);
294+
if let Some(rustifieds) = matches.values_of("rustified-enum") {
295+
for regex in rustifieds {
296+
builder = builder.rustified_enum(regex);
298297
}
299298
}
300299

tests/headers/anon_enum.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq
1+
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --rustified-enum .*
22
struct Test {
33
int foo;
44
float bar;

tests/headers/anon_enum_trait.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq
1+
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --rustified-enum .*
22

33
template<typename _Tp>
44
class DataType {

tests/headers/anon_enum_whitelist.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// bindgen-flags: --whitelist-var NODE_.*
1+
// bindgen-flags: --whitelist-var NODE_.* --rustified-enum .*
22

33
enum {
44
NODE_FLAG_FOO,

tests/headers/anon_union.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq
1+
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --rustified-enum .*
22
template<typename T>
33
struct TErrorResult {
44
enum UnionState {

0 commit comments

Comments
 (0)