summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-06-21 05:03:08 -0700
committerGitHub <noreply@github.com>2017-06-21 05:03:08 -0700
commit480c2d197199e7b1f824a01cc63acd33d81f6622 (patch)
treea244ca35506dc52f8a965a797dedeaa5715a5e82
parent232a21ebc4a4ddc2468aed8e54d165c613037038 (diff)
parent814d28e0f256a24865f633b5992ced6f035d6f4c (diff)
Auto merge of #741 - tmfink:feature-699-constified-enum-module, r=emilio
Feature 699 constified enum module This is a work in progress for issue #699 that adds the `--constified-enum-module` option to bindgen. @emilio, could you give me some guidance on fixing the uses of the enum variant types? In the example below, `foo` should be replaced with `foo::Type`. I'm not sure of the proper way to rename `Item`s after the structures have been defined. My initial thought was to redefine the `CodeGenerator` trait to take a mutable reference to `item`, but that will not work because of the borrow checker. Thoughts? Todo: - [x] put constified enum variants in a `mod` - [x] ensure references to constified enum `foo` are changed to `foo::Type` - [x] handle `typedef` enums ----- Given the input header `tests/headers/constify-module-enums.h`: ~~~c // bindgen-flags: --constified-enum-module foo enum foo { THIS, SHOULD_BE, A_CONSTANT, }; struct bar { enum foo this_should_work; }; ~~~ `$ cargo run -- tests/headers/constify-module-enums.h --constified-enum-module foo --no-layout-tests` will output: ~~~rust /* automatically generated by rust-bindgen */ pub mod foo { pub type Type = ::std::os::raw::c_uint; pub const THIS: Type = 0; pub const SHOULD_BE: Type = 1; pub const A_CONSTANT: Type = 2; } #[repr(C)] #[derive(Debug, Copy)] pub struct bar { pub this_should_work: foo, } impl Clone for bar { fn clone(&self) -> Self { *self } } ~~~
-rw-r--r--src/codegen/mod.rs74
-rw-r--r--src/ir/enum_ty.rs15
-rw-r--r--src/ir/item.rs54
-rw-r--r--src/lib.rs29
-rw-r--r--src/options.rs18
-rw-r--r--tests/expectations/tests/constify-module-enums-basic.rs45
-rw-r--r--tests/expectations/tests/constify-module-enums-namespace.rs52
-rw-r--r--tests/expectations/tests/constify-module-enums-shadow-name.rs36
-rw-r--r--tests/expectations/tests/constify-module-enums-simple-alias.rs80
-rw-r--r--tests/expectations/tests/constify-module-enums-simple-nonamespace.rs40
-rw-r--r--tests/expectations/tests/constify-module-enums-types.rs193
-rw-r--r--tests/headers/constify-module-enums-basic.h17
-rw-r--r--tests/headers/constify-module-enums-namespace.hpp17
-rw-r--r--tests/headers/constify-module-enums-shadow-name.h12
-rw-r--r--tests/headers/constify-module-enums-simple-alias.hpp21
-rw-r--r--tests/headers/constify-module-enums-simple-nonamespace.hpp12
-rw-r--r--tests/headers/constify-module-enums-types.hpp78
17 files changed, 776 insertions, 17 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 3aff1b68..d926f02b 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -36,9 +36,12 @@ use std::mem;
use std::ops;
use syntax::abi;
use syntax::ast;
-use syntax::codemap::{Span, respan};
+use syntax::codemap::{DUMMY_SP, Span, respan};
use syntax::ptr::P;
+// Name of type defined in constified enum module
+pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &'static str = "Type";
+
fn root_import_depth(ctx: &BindgenContext, item: &Item) -> usize {
if !ctx.options().enable_cxx_namespaces {
return 0;
@@ -244,7 +247,6 @@ impl ForeignModBuilder {
}
fn build(self, ctx: &BindgenContext) -> P<ast::Item> {
- use syntax::codemap::DUMMY_SP;
P(ast::Item {
ident: ctx.rust_ident(""),
id: ast::DUMMY_NODE_ID,
@@ -2049,6 +2051,10 @@ enum EnumBuilder<'a> {
aster: P<ast::Item>,
},
Consts { aster: P<ast::Item> },
+ ModuleConsts {
+ module_name: &'a str,
+ module_items: Vec<P<ast::Item>>,
+ },
}
impl<'a> EnumBuilder<'a> {
@@ -2058,7 +2064,8 @@ impl<'a> EnumBuilder<'a> {
name: &'a str,
repr: P<ast::Ty>,
bitfield_like: bool,
- constify: bool)
+ constify: bool,
+ constify_module: bool)
-> Self {
if bitfield_like {
EnumBuilder::Bitfield {
@@ -2070,8 +2077,20 @@ impl<'a> EnumBuilder<'a> {
.build(),
}
} else if constify {
- EnumBuilder::Consts {
- aster: aster.type_(name).build_ty(repr),
+ if constify_module {
+ let type_definition = aster::item::ItemBuilder::new()
+ .pub_()
+ .type_(CONSTIFIED_ENUM_MODULE_REPR_NAME)
+ .build_ty(repr);
+
+ EnumBuilder::ModuleConsts {
+ module_name: name,
+ module_items: vec![type_definition],
+ }
+ } else {
+ EnumBuilder::Consts {
+ aster: aster.type_(name).build_ty(repr),
+ }
}
} else {
EnumBuilder::Rust(aster.enum_(name))
@@ -2143,6 +2162,27 @@ impl<'a> EnumBuilder<'a> {
result.push(constant);
self
}
+ EnumBuilder::ModuleConsts { module_name, module_items, .. } => {
+ // Variant type
+ let inside_module_type =
+ aster::AstBuilder::new().ty().id(CONSTIFIED_ENUM_MODULE_REPR_NAME);
+
+ let constant = aster::AstBuilder::new()
+ .item()
+ .pub_()
+ .const_(&*variant_name)
+ .expr()
+ .build(expr)
+ .build(inside_module_type.clone());
+
+ let mut module_items = module_items.clone();
+ module_items.push(constant);
+
+ EnumBuilder::ModuleConsts {
+ module_name,
+ module_items,
+ }
+ }
}
}
@@ -2208,6 +2248,22 @@ impl<'a> EnumBuilder<'a> {
aster
}
EnumBuilder::Consts { aster, .. } => aster,
+ EnumBuilder::ModuleConsts { module_items, module_name, .. } => {
+ // Create module item with type and variant definitions
+ let module_item = P(ast::Item {
+ ident: ast::Ident::from_str(module_name),
+ attrs: vec![],
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Mod(ast::Mod {
+ inner: DUMMY_SP,
+ items: module_items,
+ }),
+ vis: ast::Visibility::Public,
+ span: DUMMY_SP,
+ });
+
+ module_item
+ }
}
}
}
@@ -2273,7 +2329,10 @@ impl CodeGenerator for Enum {
.any(|v| ctx.options().bitfield_enums.matches(&v.name())))
};
- let is_constified_enum = {
+ let is_constified_enum_module = self.is_constified_enum_module(ctx, item);
+
+ let is_constified_enum = {
+ is_constified_enum_module ||
ctx.options().constified_enums.matches(&name) ||
(enum_ty.name().is_none() &&
self.variants()
@@ -2353,7 +2412,8 @@ impl CodeGenerator for Enum {
&name,
repr,
is_bitfield,
- is_constified_enum);
+ is_constified_enum,
+ is_constified_enum_module);
// A map where we keep a value -> variant relation.
let mut seen_values = HashMap::<_, String>::new();
diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs
index e64354fb..38de01d9 100644
--- a/src/ir/enum_ty.rs
+++ b/src/ir/enum_ty.rs
@@ -5,11 +5,14 @@ use super::item::Item;
use super::ty::TypeKind;
use clang;
use ir::annotations::Annotations;
+use ir::item::ItemCanonicalName;
use parse::{ClangItemParser, ParseError};
/// An enum representing custom handling that can be given to a variant.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum EnumVariantCustomBehavior {
+ /// This variant will be a module containing constants.
+ ModuleConstify,
/// This variant will be constified, that is, forced to generate a constant.
Constify,
/// This variant will be hidden entirely from the resulting enum.
@@ -121,6 +124,18 @@ impl Enum {
});
Ok(Enum::new(repr, variants))
}
+
+ /// Whether the enum should be an constified enum module
+ pub fn is_constified_enum_module(&self, ctx: &BindgenContext, item: &Item) -> bool {
+ let name = item.canonical_name(ctx);
+ let enum_ty = item.expect_type();
+
+ ctx.options().constified_enum_modules.matches(&name) ||
+ (enum_ty.name().is_none() &&
+ self.variants()
+ .iter()
+ .any(|v| ctx.options().constified_enum_modules.matches(&v.name())))
+ }
}
/// A single enum variant, to be contained only in an enum.
diff --git a/src/ir/item.rs b/src/ir/item.rs
index d41fe54a..b80ddbd9 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -1,5 +1,6 @@
//! Bindgen's core intermediate representation type.
+use super::super::codegen::CONSTIFIED_ENUM_MODULE_REPR_NAME;
use super::annotations::Annotations;
use super::context::{BindgenContext, ItemId, PartialType};
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
@@ -825,6 +826,36 @@ impl Item {
_ => None,
}
}
+
+ /// Returns whether the item is a constified module enum
+ fn is_constified_enum_module(&self, ctx: &BindgenContext) -> bool {
+ // Do not jump through aliases, except for aliases that point to a type
+ // with the same name, since we dont generate coe for them.
+ let item = self.id.into_resolver().through_type_refs().resolve(ctx);
+ let type_ = match *item.kind() {
+ ItemKind::Type(ref type_) => type_,
+ _ => return false,
+ };
+
+ match *type_.kind() {
+ TypeKind::Enum(ref enum_) => {
+ enum_.is_constified_enum_module(ctx, self)
+ }
+ TypeKind::Alias(inner_id) => {
+ // TODO(emilio): Make this "hop through type aliases that aren't
+ // really generated" an option in `ItemResolver`?
+ let inner_item = ctx.resolve_item(inner_id);
+ let name = item.canonical_name(ctx);
+
+ if inner_item.canonical_name(ctx) == name {
+ inner_item.is_constified_enum_module(ctx)
+ } else {
+ false
+ }
+ }
+ _ => false,
+ }
+ }
}
/// A set of items.
@@ -1443,14 +1474,25 @@ impl ItemCanonicalPath for Item {
fn namespace_aware_canonical_path(&self,
ctx: &BindgenContext)
-> Vec<String> {
- let path = self.canonical_path(ctx);
- if ctx.options().enable_cxx_namespaces {
- return path;
- }
+ let mut path = self.canonical_path(ctx);
+
+ // ASSUMPTION: (disable_name_namespacing && cxx_namespaces)
+ // is equivalent to
+ // disable_name_namespacing
if ctx.options().disable_name_namespacing {
- return vec![path.last().unwrap().clone()];
+ // Only keep the last item in path
+ let split_idx = path.len() - 1;
+ path = path.split_off(split_idx);
+ } else if !ctx.options().enable_cxx_namespaces {
+ // Ignore first item "root"
+ path = vec![path[1..].join("_")];
}
- return vec![path[1..].join("_")];
+
+ if self.is_constified_enum_module(ctx) {
+ path.push(CONSTIFIED_ENUM_MODULE_REPR_NAME.into());
+ }
+
+ return path;
}
fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
diff --git a/src/lib.rs b/src/lib.rs
index a1446754..bfa71d38 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -206,6 +206,16 @@ impl Builder {
.count();
self.options
+ .constified_enum_modules
+ .get_items()
+ .iter()
+ .map(|item| {
+ output_vector.push("--constified-enum-module".into());
+ output_vector.push(item.trim_left_matches("^").trim_right_matches("$").into());
+ })
+ .count();
+
+ self.options
.hidden_types
.get_items()
.iter()
@@ -562,8 +572,8 @@ impl Builder {
self
}
- /// Mark the given enum (or set of enums, if using a pattern) as being
- /// constant.
+ /// Mark the given enum (or set of enums, if using a pattern) as a set of
+ /// constants.
///
/// This makes bindgen generate constants instead of enums. Regular
/// expressions are supported.
@@ -572,6 +582,16 @@ impl Builder {
self
}
+ /// Mark the given enum (or set of enums, if using a pattern) as a set of
+ /// constants that should be put into a module.
+ ///
+ /// This makes bindgen generate a modules containing constants instead of
+ /// enums. Regular expressions are supported.
+ pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.constified_enum_modules.insert(arg);
+ self
+ }
+
/// Add a string to prepend to the generated bindings. The string is passed
/// through without any modification.
pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder {
@@ -813,6 +833,9 @@ pub struct BindgenOptions {
/// The enum patterns to mark an enum as constant.
pub constified_enums: RegexSet,
+ /// The enum patterns to mark an enum as a module of constants.
+ pub constified_enum_modules: RegexSet,
+
/// Whether we should generate builtins or not.
pub builtins: bool,
@@ -935,6 +958,7 @@ impl BindgenOptions {
self.hidden_types.build();
self.opaque_types.build();
self.bitfield_enums.build();
+ self.constified_enum_modules.build();
self.constified_enums.build();
}
}
@@ -949,6 +973,7 @@ impl Default for BindgenOptions {
whitelisted_vars: Default::default(),
bitfield_enums: Default::default(),
constified_enums: Default::default(),
+ constified_enum_modules: Default::default(),
builtins: false,
links: vec![],
emit_ast: false,
diff --git a/src/options.rs b/src/options.rs
index fc0dd247..6a6fde81 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -33,6 +33,15 @@ pub fn builder_from_flags<I>
.takes_value(true)
.multiple(true)
.number_of_values(1),
+ Arg::with_name("constified-enum-module")
+ .long("constified-enum-module")
+ .help("Mark any enum whose name matches <regex> as a module of \
+ constants instead of an enumeration. This option \
+ implies \"--constified-enum.\"")
+ .value_name("regex")
+ .takes_value(true)
+ .multiple(true)
+ .number_of_values(1),
Arg::with_name("blacklist-type")
.long("blacklist-type")
.help("Mark <type> as hidden.")
@@ -222,12 +231,17 @@ pub fn builder_from_flags<I>
}
}
- if let Some(bitfields) = matches.values_of("constified-enum") {
- for regex in bitfields {
+ if let Some(constifieds) = matches.values_of("constified-enum") {
+ for regex in constifieds {
builder = builder.constified_enum(regex);
}
}
+ if let Some(constified_mods) = matches.values_of("constified-enum-module") {
+ for regex in constified_mods {
+ builder = builder.constified_enum_module(regex);
+ }
+ }
if let Some(hidden_types) = matches.values_of("blacklist-type") {
for ty in hidden_types {
builder = builder.hide_type(ty);
diff --git a/tests/expectations/tests/constify-module-enums-basic.rs b/tests/expectations/tests/constify-module-enums-basic.rs
new file mode 100644
index 00000000..803c804b
--- /dev/null
+++ b/tests/expectations/tests/constify-module-enums-basic.rs
@@ -0,0 +1,45 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+
+
+pub mod foo {
+ pub type Type = ::std::os::raw::c_uint;
+ pub const THIS: Type = 0;
+ pub const SHOULD_BE: Type = 1;
+ pub const A_CONSTANT: Type = 2;
+}
+pub use self::foo::Type as foo_alias1;
+pub use self::foo_alias1 as foo_alias2;
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct bar {
+ pub this_should_work: foo::Type,
+}
+#[test]
+fn bindgen_test_layout_bar() {
+ assert_eq!(::std::mem::size_of::<bar>() , 4usize , concat ! (
+ "Size of: " , stringify ! ( bar ) ));
+ assert_eq! (::std::mem::align_of::<bar>() , 4usize , concat ! (
+ "Alignment of " , stringify ! ( bar ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . this_should_work as * const _
+ as usize } , 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( this_should_work ) ));
+}
+impl Clone for bar {
+ fn clone(&self) -> Self { *self }
+}
+impl Default for bar {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+extern "C" {
+ pub fn func1(arg1: foo::Type, arg2: *mut foo::Type,
+ arg3: *mut *mut foo::Type) -> *mut foo::Type;
+}
+extern "C" {
+ pub fn func2(arg1: foo_alias1, arg2: *mut foo_alias1,
+ arg3: *mut *mut foo_alias1) -> *mut foo_alias1;
+}
diff --git a/tests/expectations/tests/constify-module-enums-namespace.rs b/tests/expectations/tests/constify-module-enums-namespace.rs
new file mode 100644
index 00000000..4db009be
--- /dev/null
+++ b/tests/expectations/tests/constify-module-enums-namespace.rs
@@ -0,0 +1,52 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+
+
+#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
+pub mod root {
+ #[allow(unused_imports)]
+ use self::super::root;
+ pub mod ns1 {
+ #[allow(unused_imports)]
+ use self::super::super::root;
+ pub mod ns2 {
+ #[allow(unused_imports)]
+ use self::super::super::super::root;
+ pub mod foo {
+ pub type Type = ::std::os::raw::c_uint;
+ pub const THIS: Type = 0;
+ pub const SHOULD_BE: Type = 1;
+ pub const A_CONSTANT: Type = 2;
+ }
+ }
+ pub mod ns3 {
+ #[allow(unused_imports)]
+ use self::super::super::super::root;
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct bar {
+ pub this_should_work: root::ns1::ns2::foo::Type,
+ }
+ #[test]
+ fn bindgen_test_layout_bar() {
+ assert_eq!(::std::mem::size_of::<bar>() , 4usize , concat ! (
+ "Size of: " , stringify ! ( bar ) ));
+ assert_eq! (::std::mem::align_of::<bar>() , 4usize , concat !
+ ( "Alignment of " , stringify ! ( bar ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . this_should_work as
+ * const _ as usize } , 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) ,
+ "::" , stringify ! ( this_should_work ) ));
+ }
+ impl Clone for bar {
+ fn clone(&self) -> Self { *self }
+ }
+ impl Default for bar {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+ }
+ }
+ }
+}
diff --git a/tests/expectations/tests/constify-module-enums-shadow-name.rs b/tests/expectations/tests/constify-module-enums-shadow-name.rs
new file mode 100644
index 00000000..9b5fd7b8
--- /dev/null
+++ b/tests/expectations/tests/constify-module-enums-shadow-name.rs
@@ -0,0 +1,36 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+
+
+pub mod foo {
+ pub type Type = ::std::os::raw::c_uint;
+ pub const Type: Type = 0;
+ pub const Type_: Type = 1;
+ pub const Type1: Type = 2;
+ pub const Type__: Type = 3;
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct bar {
+ pub member: foo::Type,
+}
+#[test]
+fn bindgen_test_layout_bar() {
+ assert_eq!(::std::mem::size_of::<bar>() , 4usize , concat ! (
+ "Size of: " , stringify ! ( bar ) ));
+ assert_eq! (::std::mem::align_of::<bar>() , 4usize , concat ! (
+ "Alignment of " , stringify ! ( bar ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . member as * const _ as usize }
+ , 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( member ) ));
+}
+impl Clone for bar {
+ fn clone(&self) -> Self { *self }
+}
+impl Default for bar {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/constify-module-enums-simple-alias.rs b/tests/expectations/tests/constify-module-enums-simple-alias.rs
new file mode 100644
index 00000000..709a6947
--- /dev/null
+++ b/tests/expectations/tests/constify-module-enums-simple-alias.rs
@@ -0,0 +1,80 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+
+
+pub mod Foo {
+ pub type Type = ::std::os::raw::c_int;
+ pub const Variant1: Type = 0;
+ pub const Variant2: Type = 1;
+ pub const Variant3: Type = 2;
+}
+pub use self::Foo::Type as Foo_alias1;
+pub use self::Foo_alias1 as Foo_alias2;
+pub use self::Foo_alias2 as Foo_alias3;
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Bar {
+ pub baz1: Foo::Type,
+ pub baz2: Foo_alias1,
+ pub baz3: Foo_alias2,
+ pub baz4: Foo_alias3,
+ pub baz_ptr1: *mut Foo::Type,
+ pub baz_ptr2: *mut Foo_alias1,
+ pub baz_ptr3: *mut Foo_alias2,
+ pub baz_ptr4: *mut Foo_alias3,
+}
+#[test]
+fn bindgen_test_layout_Bar() {
+ assert_eq!(::std::mem::size_of::<Bar>() , 48usize , concat ! (
+ "Size of: " , stringify ! ( Bar ) ));
+ assert_eq! (::std::mem::align_of::<Bar>() , 8usize , concat ! (
+ "Alignment of " , stringify ! ( Bar ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . baz1 as * const _ as usize } ,
+ 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( baz1 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . baz2 as * const _ as usize } ,
+ 4usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( baz2 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . baz3 as * const _ as usize } ,
+ 8usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( baz3 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . baz4 as * const _ as usize } ,
+ 12usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( baz4 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . baz_ptr1 as * const _ as usize
+ } , 16usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( baz_ptr1 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . baz_ptr2 as * const _ as usize
+ } , 24usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( baz_ptr2 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . baz_ptr3 as * const _ as usize
+ } , 32usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( baz_ptr3 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . baz_ptr4 as * const _ as usize
+ } , 40usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( baz_ptr4 ) ));
+}
+impl Clone for Bar {
+ fn clone(&self) -> Self { *self }
+}
+impl Default for Bar {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/constify-module-enums-simple-nonamespace.rs b/tests/expectations/tests/constify-module-enums-simple-nonamespace.rs
new file mode 100644
index 00000000..4f8d46c5
--- /dev/null
+++ b/tests/expectations/tests/constify-module-enums-simple-nonamespace.rs
@@ -0,0 +1,40 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+
+
+pub mod one_Foo {
+ pub type Type = ::std::os::raw::c_int;
+ pub const Variant1: Type = 0;
+ pub const Variant2: Type = 1;
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Bar {
+ pub baz1: one_Foo::Type,
+ pub baz2: *mut one_Foo::Type,
+}
+#[test]
+fn bindgen_test_layout_Bar() {
+ assert_eq!(::std::mem::size_of::<Bar>() , 16usize , concat ! (
+ "Size of: " , stringify ! ( Bar ) ));
+ assert_eq! (::std::mem::align_of::<Bar>() , 8usize , concat ! (
+ "Alignment of " , stringify ! ( Bar ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . baz1 as * const _ as usize } ,
+ 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( baz1 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . baz2 as * const _ as usize } ,
+ 8usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( baz2 ) ));
+}
+impl Clone for Bar {
+ fn clone(&self) -> Self { *self }
+}
+impl Default for Bar {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/constify-module-enums-types.rs b/tests/expectations/tests/constify-module-enums-types.rs
new file mode 100644
index 00000000..4eb100c4
--- /dev/null
+++ b/tests/expectations/tests/constify-module-enums-types.rs
@@ -0,0 +1,193 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+
+
+pub mod foo {
+ pub type Type = ::std::os::raw::c_uint;
+ pub const THIS: Type = 0;
+ pub const SHOULD_BE: Type = 1;
+ pub const A_CONSTANT: Type = 2;
+ pub const ALSO_THIS: Type = 42;
+ pub const AND_ALSO_THIS: Type = 42;
+}
+pub mod anon_enum {
+ pub type Type = ::std::os::raw::c_uint;
+ pub const Variant1: Type = 0;
+ pub const Variant2: Type = 1;
+ pub const Variant3: Type = 2;
+}
+pub mod ns1_foo {
+ pub type Type = ::std::os::raw::c_uint;
+ pub const THIS: Type = 0;
+ pub const SHOULD_BE: Type = 1;
+ pub const A_CONSTANT: Type = 2;
+ pub const ALSO_THIS: Type = 42;
+}
+pub mod ns2_Foo {
+ pub type Type = ::std::os::raw::c_int;
+ pub const Variant1: Type = 0;
+ pub const Variant2: Type = 1;
+}
+pub use self::foo::Type as foo_alias1;
+pub use self::foo_alias1 as foo_alias2;
+pub use self::foo_alias2 as foo_alias3;
+pub use self::anon_enum::Type as anon_enum_alias1;
+pub use self::anon_enum_alias1 as anon_enum_alias2;
+pub use self::anon_enum_alias2 as anon_enum_alias3;
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct bar {
+ pub member1: foo::Type,
+ pub member2: foo_alias1,
+ pub member3: foo_alias2,
+ pub member4: foo_alias3,
+ pub member5: ns1_foo::Type,
+ pub member6: *mut ns2_Foo::Type,
+ pub member7: anon_enum::Type,
+ pub member8: anon_enum_alias1,
+ pub member9: anon_enum_alias2,
+ pub member10: anon_enum_alias3,
+}
+#[test]
+fn bindgen_test_layout_bar() {
+ assert_eq!(::std::mem::size_of::<bar>() , 48usize , concat ! (
+ "Size of: " , stringify ! ( bar ) ));
+ assert_eq! (::std::mem::align_of::<bar>() , 8usize , concat ! (
+ "Alignment of " , stringify ! ( bar ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . member1 as * const _ as usize }
+ , 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( member1 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . member2 as * const _ as usize }
+ , 4usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( member2 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . member3 as * const _ as usize }
+ , 8usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( member3 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . member4 as * const _ as usize }
+ , 12usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( member4 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . member5 as * const _ as usize }
+ , 16usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( member5 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . member6 as * const _ as usize }
+ , 24usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( member6 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . member7 as * const _ as usize }
+ , 32usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( member7 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . member8 as * const _ as usize }
+ , 36usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( member8 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . member9 as * const _ as usize }
+ , 40usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( member9 ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const bar ) ) . member10 as * const _ as usize
+ } , 44usize , concat ! (
+ "Alignment of field: " , stringify ! ( bar ) , "::" ,
+ stringify ! ( member10 ) ));
+}
+impl Clone for bar {
+ fn clone(&self) -> Self { *self }
+}
+impl Default for bar {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Baz {
+ pub member1: ns2_Foo::Type,
+}
+#[test]
+fn bindgen_test_layout_Baz() {
+ assert_eq!(::std::mem::size_of::<Baz>() , 4usize , concat ! (
+ "Size of: " , stringify ! ( Baz ) ));
+ assert_eq! (::std::mem::align_of::<Baz>() , 4usize , concat ! (
+ "Alignment of " , stringify ! ( Baz ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Baz ) ) . member1 as * const _ as usize }
+ , 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( Baz ) , "::" ,
+ stringify ! ( member1 ) ));
+}
+impl Clone for Baz {
+ fn clone(&self) -> Self { *self }
+}
+impl Default for Baz {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+pub mod one_Foo {
+ pub type Type = ::std::os::raw::c_int;
+ pub const Variant1: Type = 0;
+ pub const Variant2: Type = 1;
+}
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Bar {
+ pub baz: *mut one_Foo::Type,
+}
+#[test]
+fn bindgen_test_layout_Bar() {
+ assert_eq!(::std::mem::size_of::<Bar>() , 8usize , concat ! (
+ "Size of: " , stringify ! ( Bar ) ));
+ assert_eq! (::std::mem::align_of::<Bar>() , 8usize , concat ! (
+ "Alignment of " , stringify ! ( Bar ) ));
+ assert_eq! (unsafe {
+ & ( * ( 0 as * const Bar ) ) . baz as * const _ as usize } ,
+ 0usize , concat ! (
+ "Alignment of field: " , stringify ! ( Bar ) , "::" ,
+ stringify ! ( baz ) ));
+}
+impl Clone for Bar {
+ fn clone(&self) -> Self { *self }
+}
+impl Default for Bar {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+extern "C" {
+ #[link_name = "_Z5func13fooPS_PS0_"]
+ pub fn func1(arg1: foo::Type, arg2: *mut foo::Type,
+ arg3: *mut *mut foo::Type) -> *mut foo::Type;
+}
+extern "C" {
+ #[link_name = "_Z5func23fooPS_PS0_"]
+ pub fn func2(arg1: foo_alias1, arg2: *mut foo_alias1,
+ arg3: *mut *mut foo_alias1) -> *mut foo_alias1;
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Thing<T> {
+ pub thing: T,
+ pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
+}
+impl <T> Default for Thing<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+extern "C" {
+ #[link_name = "_Z5func35ThingI3fooE"]
+ pub fn func3(arg1: Thing<foo::Type>) -> foo::Type;
+}
+extern "C" {
+ #[link_name = "_Z5func45ThingIS_I3fooEE"]
+ pub fn func4(arg1: Thing<Thing<foo::Type>>) -> foo::Type;
+}
diff --git a/tests/headers/constify-module-enums-basic.h b/tests/headers/constify-module-enums-basic.h
new file mode 100644
index 00000000..631e8847
--- /dev/null
+++ b/tests/headers/constify-module-enums-basic.h
@@ -0,0 +1,17 @@
+// bindgen-flags: --constified-enum-module foo
+
+enum foo {
+ THIS,
+ SHOULD_BE,
+ A_CONSTANT,
+};
+
+typedef enum foo foo_alias1;
+typedef foo_alias1 foo_alias2;
+
+struct bar {
+ enum foo this_should_work;
+};
+
+enum foo *func1(enum foo arg1, enum foo *arg2, enum foo **arg3);
+foo_alias1 *func2(foo_alias1 arg1, foo_alias1 *arg2, foo_alias1 **arg3); \ No newline at end of file
diff --git a/tests/headers/constify-module-enums-namespace.hpp b/tests/headers/constify-module-enums-namespace.hpp
new file mode 100644
index 00000000..397f700f
--- /dev/null
+++ b/tests/headers/constify-module-enums-namespace.hpp
@@ -0,0 +1,17 @@
+// bindgen-flags: --enable-cxx-namespaces --constified-enum-module foo
+
+namespace ns1 {
+ namespace ns2 {
+ enum foo {
+ THIS,
+ SHOULD_BE,
+ A_CONSTANT,
+ };
+ }
+
+ namespace ns3 {
+ struct bar {
+ enum ns2::foo this_should_work;
+ };
+ }
+} \ No newline at end of file
diff --git a/tests/headers/constify-module-enums-shadow-name.h b/tests/headers/constify-module-enums-shadow-name.h
new file mode 100644
index 00000000..38b26106
--- /dev/null
+++ b/tests/headers/constify-module-enums-shadow-name.h
@@ -0,0 +1,12 @@
+// bindgen-flags: --constified-enum-module foo
+
+enum foo {
+ Type,
+ Type_,
+ Type1,
+ Type__,
+};
+
+struct bar {
+ enum foo member;
+};
diff --git a/tests/headers/constify-module-enums-simple-alias.hpp b/tests/headers/constify-module-enums-simple-alias.hpp
new file mode 100644
index 00000000..35ac4be3
--- /dev/null
+++ b/tests/headers/constify-module-enums-simple-alias.hpp
@@ -0,0 +1,21 @@
+// bindgen-flags: --constified-enum-module Foo
+
+enum class Foo {
+ Variant1, Variant2, Variant3,
+};
+
+typedef Foo Foo_alias1;
+typedef Foo_alias1 Foo_alias2;
+typedef Foo_alias2 Foo_alias3;
+
+class Bar {
+ Foo baz1;
+ Foo_alias1 baz2;
+ Foo_alias2 baz3;
+ Foo_alias3 baz4;
+
+ Foo *baz_ptr1;
+ Foo_alias1 *baz_ptr2;
+ Foo_alias2 *baz_ptr3;
+ Foo_alias3 *baz_ptr4;
+};
diff --git a/tests/headers/constify-module-enums-simple-nonamespace.hpp b/tests/headers/constify-module-enums-simple-nonamespace.hpp
new file mode 100644
index 00000000..54631451
--- /dev/null
+++ b/tests/headers/constify-module-enums-simple-nonamespace.hpp
@@ -0,0 +1,12 @@
+// bindgen-flags: --constified-enum-module one_Foo
+
+namespace one {
+ enum class Foo {
+ Variant1, Variant2,
+ };
+}
+
+class Bar {
+ one::Foo baz1;
+ one::Foo* baz2;
+};
diff --git a/tests/headers/constify-module-enums-types.hpp b/tests/headers/constify-module-enums-types.hpp
new file mode 100644
index 00000000..2c652499
--- /dev/null
+++ b/tests/headers/constify-module-enums-types.hpp
@@ -0,0 +1,78 @@
+// bindgen-flags: --constified-enum-module .*
+
+typedef enum foo {
+ THIS,
+ SHOULD_BE,
+ A_CONSTANT,
+ ALSO_THIS = 42,
+ AND_ALSO_THIS = 42,
+} foo;
+
+
+typedef enum {
+ Variant1, Variant2, Variant3,
+} anon_enum;
+
+
+namespace ns1 {
+ typedef enum {
+ THIS,
+ SHOULD_BE,
+ A_CONSTANT,
+ ALSO_THIS = 42,
+ } foo;
+}
+
+namespace ns2 {
+ enum class Foo {
+ Variant1,
+ Variant2,
+ };
+}
+
+typedef foo foo_alias1;
+typedef foo_alias1 foo_alias2;
+typedef foo_alias2 foo_alias3;
+
+typedef anon_enum anon_enum_alias1;
+typedef anon_enum_alias1 anon_enum_alias2;
+typedef anon_enum_alias2 anon_enum_alias3;
+
+typedef struct bar {
+ foo member1;
+ foo_alias1 member2;
+ foo_alias2 member3;
+ foo_alias3 member4;
+ ns1::foo member5;
+ ns2::Foo *member6;
+ anon_enum member7;
+ anon_enum_alias1 member8;
+ anon_enum_alias2 member9;
+ anon_enum_alias3 member10;
+} bar;
+
+class Baz {
+ ns2::Foo member1;
+};
+
+namespace one {
+ enum class Foo {
+ Variant1, Variant2,
+ };
+}
+
+class Bar {
+ one::Foo* baz;
+};
+
+foo *func1(foo arg1, foo *arg2, foo **arg3);
+foo_alias1 *func2(foo_alias1 arg1, foo_alias1 *arg2, foo_alias1 **arg3);
+
+template <class T>
+class Thing {
+ T thing;
+ T& get_thing();
+};
+
+foo func3(Thing<foo> arg1);
+foo func4(Thing< Thing<foo> > arg1); \ No newline at end of file