From cfdf15f5d04d4fbca3e7fcb46a1dd658ade973cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sat, 20 Aug 2016 22:32:16 -0700 Subject: [PATCH 1/2] Rewrite the core of the binding generator. TL;DR: The binding generator is a mess as of right now. At first it was funny (in a "this is challenging" sense) to improve on it, but this is not sustainable. The truth is that the current architecture of the binding generator is a huge pile of hacks, so these few days I've been working on rewriting it with a few goals. 1) Have the hacks as contained and identified as possible. They're sometimes needed because how clang exposes the AST, but ideally those hacks are well identified and don't interact randomly with each others. As an example, in the current bindgen when scanning the parameters of a function that references a struct clones all the struct information, then if the struct name changes (because we mangle it), everything breaks. 2) Support extending the bindgen output without having to deal with clang. The way I'm aiming to do this is separating completely the parsing stage from the code generation one, and providing a single id for each item the binding generator provides. 3) No more random mutation of the internal representation from anywhere. That means no more Rc>, no more random circular references, no more borrow_state... nothing. 4) No more deduplication of declarations before code generation. Current bindgen has a stage, called `tag_dup_decl`[1], that takes care of deduplicating declarations. That's completely buggy, and for C++ it's a complete mess, since we YOLO modify the world. I've managed to take rid of this using the clang canonical declaration, and the definition, to avoid scanning any type/item twice. 5) Code generation should not modify any internal data structure. It can lookup things, traverse whatever it needs, but not modifying randomly. 6) Each item should have a canonical name, and a single source of mangling logic, and that should be computed from the inmutable state, at code generation. I've put a few canonical_name stuff in the code generation phase, but it's still not complete, and should change if I implement namespaces. Improvements pending until this can land: 1) Add support for missing core stuff, mainly generating functions (note that we parse the signatures for types correctly though), bitfields, generating C++ methods. 2) Add support for the necessary features that were added to work around some C++ pitfalls, like opaque types, etc... 3) Add support for the sugar that Manish added recently. 4) Optionally (and I guess this can land without it, because basically nobody uses it since it's so buggy), bring back namespace support. These are not completely trivial, but I think I can do them quite easily with the current architecture. I'm putting the current state of affairs here as a request for comments... Any thoughts? Note that there are still a few smells I want to eventually re-redesign, like the ParseError::Recurse thing, but until that happens I'm way happier with this kind of architecture. I'm keeping the old `parser.rs` and `gen.rs` in tree just for reference while I code, but they will go away. [1]: https://github.com/Yamakaky/rust-bindgen/blob/master/src/gen.rs#L448 --- Cargo.toml | 24 +- build.rs | 7 +- src/bin/bindgen.rs | 83 +- src/clang.rs | 179 +- src/clangll.rs | 6 +- src/codegen/helpers.rs | 113 + src/codegen/mod.rs | 1904 +++++++++++++ src/gen.rs | 2364 ----------------- src/hacks/mod.rs | 1 - src/hacks/refcell.rs | 464 ---- src/ir/annotations.rs | 141 + src/ir/comp.rs | 718 +++++ src/ir/context.rs | 685 +++++ src/ir/enum_ty.rs | 110 + src/ir/function.rs | 220 ++ src/ir/int.rs | 30 + src/ir/item.rs | 681 +++++ src/ir/item_kind.rs | 89 + src/ir/layout.rs | 26 + src/ir/mod.rs | 12 + src/ir/module.rs | 52 + src/ir/ty.rs | 537 ++++ src/ir/var.rs | 160 ++ src/lib.rs | 224 +- src/parse.rs | 48 + src/parser.rs | 1516 ----------- src/regex_set.rs | 58 + src/types.rs | 882 ------ tests/expectations/accessors.rs | 136 +- tests/expectations/annotation_hide.rs | 22 +- tests/expectations/anon_enum.rs | 23 + tests/expectations/anon_enum_whitelist.rs | 13 + tests/expectations/anon_union.rs | 73 + tests/expectations/arg_keyword.rs | 10 + tests/expectations/class.rs | 63 +- tests/expectations/class_nested.rs | 49 +- tests/expectations/class_no_members.rs | 39 +- tests/expectations/class_static.rs | 24 +- tests/expectations/class_use_as.rs | 30 +- tests/expectations/class_with_dtor.rs | 12 +- tests/expectations/class_with_inner_struct.rs | 205 +- tests/expectations/class_with_typedef.rs | 56 +- tests/expectations/const_ptr.rs | 9 + tests/expectations/const_resolved_ty.rs | 9 + tests/expectations/const_tparam.rs | 11 + tests/expectations/crtp.rs | 24 +- tests/expectations/decl_ptr_to_array.rs | 3 +- .../duplicated_constants_in_ns.rs | 12 +- .../expectations/empty_template_param_name.rs | 12 + tests/expectations/enum.rs | 8 +- tests/expectations/enum_alias.rs | 9 + .../expectations/enum_and_vtable_mangling.rs | 29 +- tests/expectations/enum_dupe.rs | 6 +- tests/expectations/enum_explicit_type.rs | 20 +- tests/expectations/enum_negative.rs | 4 +- tests/expectations/enum_packed.rs | 12 +- tests/expectations/extern.rs | 3 +- tests/expectations/forward_declared_struct.rs | 28 +- tests/expectations/func_proto.rs | 3 +- tests/expectations/func_ptr.rs | 8 +- tests/expectations/func_ptr_in_struct.rs | 25 +- tests/expectations/func_with_func_ptr_arg.rs | 2 +- tests/expectations/in_class_typedef.rs | 21 + tests/expectations/inherit_named.rs | 17 + tests/expectations/inherit_typedef.rs | 33 + tests/expectations/inner_const.rs | 27 + tests/expectations/inner_template_self.rs | 22 +- tests/expectations/jsval_layout_opaque.rs | 163 +- tests/expectations/keywords.rs | 108 + tests/expectations/moar_bitfields.rs | 48 + tests/expectations/mutable.rs | 34 +- tests/expectations/namespace.rs | 71 +- tests/expectations/nested.rs | 51 +- tests/expectations/nested_vtable.rs | 48 + tests/expectations/no_copy.rs | 4 +- tests/expectations/nsStyleAutoArray.rs | 8 +- tests/expectations/only_bitfields.rs | 44 +- tests/expectations/opaque_in_struct.rs | 17 +- tests/expectations/opaque_pointer.rs | 29 +- tests/expectations/opaque_typedef.rs | 13 +- tests/expectations/overflowed_enum.rs | 8 +- tests/expectations/private.rs | 46 +- tests/expectations/redeclaration.rs | 9 + tests/expectations/ref_argument_array.rs | 24 +- tests/expectations/size_t_template.rs | 13 +- ...ruct_containing_forward_declared_struct.rs | 30 +- tests/expectations/struct_with_anon_struct.rs | 30 +- .../struct_with_anon_struct_array.rs | 52 +- .../struct_with_anon_struct_pointer.rs | 31 +- tests/expectations/struct_with_anon_union.rs | 43 +- .../struct_with_anon_unnamed_struct.rs | 31 +- .../struct_with_anon_unnamed_union.rs | 44 +- tests/expectations/struct_with_bitfields.rs | 150 +- .../expectations/struct_with_derive_debug.rs | 56 +- tests/expectations/struct_with_nesting.rs | 91 +- tests/expectations/struct_with_packing.rs | 14 +- tests/expectations/struct_with_struct.rs | 30 +- tests/expectations/template.rs | 144 +- tests/expectations/typeref.rs | 92 + tests/expectations/union_dtor.rs | 23 +- tests/expectations/union_fields.rs | 35 +- tests/expectations/union_template.rs | 58 +- tests/expectations/union_with_anon_struct.rs | 46 +- .../union_with_anon_struct_bitfield.rs | 89 +- tests/expectations/union_with_anon_union.rs | 56 +- .../union_with_anon_unnamed_struct.rs | 51 +- .../union_with_anon_unnamed_union.rs | 61 +- tests/expectations/union_with_big_member.rs | 53 +- tests/expectations/union_with_nesting.rs | 106 +- tests/expectations/unknown_attr.rs | 16 + tests/expectations/using.rs | 6 +- tests/expectations/variadic_template_args.rs | 21 + tests/expectations/virtual_dtor.rs | 19 + tests/expectations/virtual_overloaded.rs | 24 +- tests/expectations/vtable_recursive_sig.rs | 33 +- tests/expectations/weird_bitfields.rs | 130 +- tests/expectations/what_is_going_on.rs | 29 + tests/expectations/whitelist_basic.rs | 18 + tests/headers/anon_enum.hpp | 5 + tests/headers/anon_enum_whitelist.h | 6 + tests/headers/anon_union.hpp | 20 + tests/headers/arg_keyword.hpp | 1 + tests/headers/const_ptr.hpp | 3 + tests/headers/const_resolved_ty.h | 3 + tests/headers/const_tparam.hpp | 4 + tests/headers/duplicated_constants_in_ns.hpp | 2 +- tests/headers/empty_template_param_name.hpp | 4 + tests/headers/enum_alias.hpp | 7 + tests/headers/in_class_typedef.hpp | 10 + tests/headers/inherit_named.hpp | 5 + tests/headers/inherit_typedef.hpp | 5 + tests/headers/inner_const.hpp | 6 + tests/headers/jsval_layout_opaque.hpp | 15 +- tests/headers/nested_vtable.hpp | 8 + tests/headers/opaque_typedef.hpp | 2 +- tests/headers/private.hpp | 2 +- tests/headers/redeclaration.hpp | 7 + tests/headers/typeref.hpp | 28 + tests/headers/unknown_attr.h | 6 + tests/headers/virtual_dtor.hpp | 3 + tests/headers/what_is_going_on.hpp | 19 + tests/headers/whitelist_basic.hpp | 15 + 142 files changed, 8115 insertions(+), 6967 deletions(-) create mode 100644 src/codegen/helpers.rs create mode 100644 src/codegen/mod.rs delete mode 100644 src/gen.rs delete mode 100644 src/hacks/mod.rs delete mode 100644 src/hacks/refcell.rs create mode 100644 src/ir/annotations.rs create mode 100644 src/ir/comp.rs create mode 100644 src/ir/context.rs create mode 100644 src/ir/enum_ty.rs create mode 100644 src/ir/function.rs create mode 100644 src/ir/int.rs create mode 100644 src/ir/item.rs create mode 100644 src/ir/item_kind.rs create mode 100644 src/ir/layout.rs create mode 100644 src/ir/mod.rs create mode 100644 src/ir/module.rs create mode 100644 src/ir/ty.rs create mode 100644 src/ir/var.rs create mode 100644 src/parse.rs delete mode 100644 src/parser.rs create mode 100644 src/regex_set.rs delete mode 100644 src/types.rs create mode 100644 tests/expectations/anon_enum.rs create mode 100644 tests/expectations/anon_enum_whitelist.rs create mode 100644 tests/expectations/anon_union.rs create mode 100644 tests/expectations/arg_keyword.rs create mode 100644 tests/expectations/const_ptr.rs create mode 100644 tests/expectations/const_resolved_ty.rs create mode 100644 tests/expectations/const_tparam.rs create mode 100644 tests/expectations/empty_template_param_name.rs create mode 100644 tests/expectations/enum_alias.rs create mode 100644 tests/expectations/in_class_typedef.rs create mode 100644 tests/expectations/inherit_named.rs create mode 100644 tests/expectations/inherit_typedef.rs create mode 100644 tests/expectations/inner_const.rs create mode 100644 tests/expectations/moar_bitfields.rs create mode 100644 tests/expectations/nested_vtable.rs create mode 100644 tests/expectations/redeclaration.rs create mode 100644 tests/expectations/typeref.rs create mode 100644 tests/expectations/unknown_attr.rs create mode 100644 tests/expectations/variadic_template_args.rs create mode 100644 tests/expectations/virtual_dtor.rs create mode 100644 tests/expectations/what_is_going_on.rs create mode 100644 tests/expectations/whitelist_basic.rs create mode 100644 tests/headers/anon_enum.hpp create mode 100644 tests/headers/anon_enum_whitelist.h create mode 100644 tests/headers/anon_union.hpp create mode 100644 tests/headers/arg_keyword.hpp create mode 100644 tests/headers/const_ptr.hpp create mode 100644 tests/headers/const_resolved_ty.h create mode 100644 tests/headers/const_tparam.hpp create mode 100644 tests/headers/empty_template_param_name.hpp create mode 100644 tests/headers/enum_alias.hpp create mode 100644 tests/headers/in_class_typedef.hpp create mode 100644 tests/headers/inherit_named.hpp create mode 100644 tests/headers/inherit_typedef.hpp create mode 100644 tests/headers/inner_const.hpp create mode 100644 tests/headers/nested_vtable.hpp create mode 100644 tests/headers/redeclaration.hpp create mode 100644 tests/headers/typeref.hpp create mode 100644 tests/headers/unknown_attr.h create mode 100644 tests/headers/virtual_dtor.hpp create mode 100644 tests/headers/what_is_going_on.hpp create mode 100644 tests/headers/whitelist_basic.hpp diff --git a/Cargo.toml b/Cargo.toml index 04a13eb440..fdc102c895 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,18 @@ [package] -authors = ["Jyun-Yan You "] +authors = [ + "Jyun-Yan You ", + "Emilio Cobos Álvarez ", + "The Servo project developers", +] build = "build.rs" description = "A binding generator for Rust" -homepage = "https://github.com/crabtw/rust-bindgen" +homepage = "https://github.com/servo/rust-bindgen" keywords = ["bindings", "ffi", "code-generation"] license = "BSD-3-Clause" name = "bindgen" readme = "README.md" -repository = "https://github.com/crabtw/rust-bindgen" -version = "0.16.0" +repository = "https://github.com/servo/rust-bindgen" +version = "0.17.0" [[bin]] doc = false @@ -20,14 +24,16 @@ quasi_codegen = "0.15" [dependencies] clang-sys = "0.8.0" docopt = "0.6.82" -libc = "0.2.*" -log = "0.3.*" +libc = "0.2" +log = "0.3" +env_logger = "0.3" rustc-serialize = "0.3.19" -syntex_syntax = "0.38" +syntex_syntax = "0.43" +regex = "0.1" [dependencies.aster] features = ["with-syntex"] -version = "0.21.1" +version = "0.26" [dependencies.clippy] optional = true @@ -35,7 +41,7 @@ version = "*" [dependencies.quasi] features = ["with-syntex"] -version = "0.15" +version = "0.19" [features] llvm_stable = [] diff --git a/build.rs b/build.rs index 624be28276..b9cf3e6045 100644 --- a/build.rs +++ b/build.rs @@ -5,11 +5,12 @@ mod codegen { pub fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); - let src = Path::new("src/gen.rs"); - let dst = Path::new(&out_dir).join("gen.rs"); + let src = Path::new("src/codegen/mod.rs"); + let dst = Path::new(&out_dir).join("codegen.rs"); quasi_codegen::expand(&src, &dst).unwrap(); - println!("cargo:rerun-if-changed=src/gen.rs"); + println!("cargo:rerun-if-changed=src/codegen/mod.rs"); + println!("cargo:rerun-if-changed=src/codegen/helpers.rs"); } } diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs index 8c51513164..1e92ee6de7 100755 --- a/src/bin/bindgen.rs +++ b/src/bin/bindgen.rs @@ -2,6 +2,7 @@ #![crate_type = "bin"] extern crate bindgen; +extern crate env_logger; #[macro_use] extern crate docopt; #[macro_use] @@ -9,25 +10,12 @@ extern crate log; extern crate clang_sys; extern crate rustc_serialize; -use bindgen::{Bindings, BindgenOptions, LinkType, Logger}; +use bindgen::{Bindings, BindgenOptions, LinkType}; use std::io; use std::path; use std::env; use std::default::Default; use std::fs; -use std::process::exit; - -struct StdLogger; - -impl Logger for StdLogger { - fn error(&self, msg: &str) { - println!("{}", msg); - } - - fn warn(&self, msg: &str) { - println!("{}", msg); - } -} const USAGE: &'static str = " Usage: @@ -40,6 +28,9 @@ Usage: [--dtor-attr=...] \ [--opaque-type=...] \ [--blacklist-type=...] \ + [--whitelist-type=...] \ + [--whitelist-function=...] \ + [--whitelist-var=...] \ \ [-- ...] @@ -95,15 +86,25 @@ Options: ulonglong slonglong - --raw-line= TODO - --dtor-attr= TODO - --no-class-constants TODO - --no-unstable-rust TODO - --no-namespaced-constants TODO - --no-bitfield-methods TODO - --ignore-methods TODO - --opaque-type= TODO - --blacklist-type= TODO + --raw-line= Add a raw line at the beginning of the output. + --dtor-attr= Attributes to add to structures with destructor. + --no-class-constants Avoid generating class constants. + --no-unstable-rust Avoid generating unstable rust. + --no-namespaced-constants Avoid generating constants right under namespaces. + --no-bitfield-methods Avoid generating methods for bitfield access. + --ignore-methods Avoid generating all kind of methods. + --opaque-type= Mark a type as opaque. + --blacklist-type= Mark a type as hidden. + --whitelist-type= Whitelist the type. If this set or any other + of the whitelisting sets is not empty, then + all the non-whitelisted types (or dependant) + won't be generated. + --whitelist-function= Whitelist all the free-standing functions + matching . Same behavior on emptyness + than the type whitelisting. + --whitelist-var= Whitelist all the free-standing variables + matching . Same behavior on emptyness + than the type whitelisting. Options other than stated above are passed directly through to clang. @@ -134,6 +135,9 @@ struct Args { flag_ignore_methods: bool, flag_opaque_type: Vec, flag_blacklist_type: Vec, + flag_whitelist_type: Vec, + flag_whitelist_function: Vec, + flag_whitelist_var: Vec, arg_clang_args: Vec, } @@ -182,7 +186,10 @@ impl Into)>> for Args { options.gen_bitfield_methods = !self.flag_no_bitfield_methods; options.ignore_methods = self.flag_ignore_methods; options.opaque_types.extend(self.flag_opaque_type.drain(..)); - options.blacklist_type.extend(self.flag_blacklist_type.drain(..)); + options.hidden_types.extend(self.flag_blacklist_type.drain(..)); + options.whitelisted_types.extend(self.flag_whitelist_type.drain(..)); + options.whitelisted_functions.extend(self.flag_whitelist_function.drain(..)); + options.whitelisted_vars.extend(self.flag_whitelist_var.drain(..)); options.clang_args.extend(self.arg_clang_args.drain(..)); options.clang_args.push(self.arg_input_header); @@ -191,6 +198,13 @@ impl Into)>> for Args { } pub fn main() { + log::set_logger(|max_log_level| { + use env_logger::Logger; + let env_logger = Logger::new(); + max_log_level.set(env_logger.filter()); + Box::new(env_logger) + }).expect("Failed to set logger."); + let mut bind_args: Vec<_> = env::args().collect(); if let Some(clang) = clang_sys::support::Clang::find(None) { @@ -217,24 +231,13 @@ pub fn main() { .and_then(|d| d.argv(bind_args.iter()).decode()) .unwrap_or_else(|e| e.exit()); - let logger = StdLogger; let result: ParseResult<_> = args.into(); let (options, out) = result.unwrap_or_else(|msg| { - logger.error(&msg); - exit(-1); + panic!("Failed to generate_bindings: {:?}", msg); }); - match Bindings::generate(&options, Some(&logger as &Logger), None) { - Ok(bindings) => match bindings.write(out) { - Ok(()) => (), - Err(e) => { - logger.error(&format!("Unable to write bindings to file. {}", e)); - exit(-1); - } - }, - Err(()) => { - logger.error("Failed to generate bindings".into()); - exit(-1); - } - } + let bindings = Bindings::generate(options, None) + .expect("Unable to generate bindings"); + bindings.write(out) + .expect("Unable to write bindings to file."); } diff --git a/src/clang.rs b/src/clang.rs index f8a68e123c..5618007bd6 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -15,9 +15,24 @@ pub struct Cursor { x: CXCursor } +impl fmt::Debug for Cursor { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "Cursor({} kind: {}, loc: {})", + self.spelling(), kind_to_str(self.kind()), self.location()) + } +} + pub type CursorVisitor<'s> = for<'a, 'b> FnMut(&'a Cursor, &'b Cursor) -> Enum_CXChildVisitResult + 's; impl Cursor { + pub fn is_declaration(&self) -> bool { + unsafe { clang_isDeclaration(self.kind()) != 0 } + } + + pub fn null() -> Self { + Cursor { x: unsafe { clang_getNullCursor() } } + } + // common pub fn spelling(&self) -> String { unsafe { @@ -43,18 +58,71 @@ impl Cursor { } } + pub fn fallible_semantic_parent(&self) -> Option { + let sp = self.semantic_parent(); + if sp == *self || !sp.is_valid() { + return None; + } + Some(sp) + } + pub fn semantic_parent(&self) -> Cursor { unsafe { Cursor { x: clang_getCursorSemanticParent(self.x) } } } + pub fn num_template_args(&self) -> c_int { + unsafe { + clang_Cursor_getNumTemplateArguments(self.x) + } + } + + + /// This function gets the translation unit cursor. Note that we shouldn't + /// create a TranslationUnit struct here, because bindgen assumes there will + /// only be one of them alive at a time, and dispose it on drop. That can + /// change if this would be required, but I think we can survive fine + /// without it. + pub fn translation_unit(&self) -> Cursor { + assert!(self.is_valid()); + unsafe { + let tu = clang_Cursor_getTranslationUnit(self.x); + let cursor = Cursor { + x: clang_getTranslationUnitCursor(tu), + }; + assert!(cursor.is_valid()); + cursor + } + } + + pub fn is_toplevel(&self) -> bool { + let mut semantic_parent = self.semantic_parent(); + + while semantic_parent.kind() == CXCursor_Namespace || + semantic_parent.kind() == CXCursor_NamespaceAlias || + semantic_parent.kind() == CXCursor_NamespaceRef + { + semantic_parent = semantic_parent.semantic_parent(); + } + + let tu = self.translation_unit(); + // Yes, the second can happen with, e.g., macro definitions. + semantic_parent == tu || semantic_parent == tu.semantic_parent() + } + pub fn kind(&self) -> Enum_CXCursorKind { unsafe { clang_getCursorKind(self.x) } } + pub fn is_anonymous(&self) -> bool { + unsafe { + clang_Cursor_isAnonymous(self.x) != 0 + } + } + pub fn is_template(&self) -> bool { self.specialized().is_valid() } @@ -77,10 +145,11 @@ impl Cursor { } } - pub fn raw_comment(&self) -> String { - unsafe { + pub fn raw_comment(&self) -> Option { + let s = unsafe { String_ { x: clang_Cursor_getRawCommentText(self.x) }.to_string() - } + }; + if s.is_empty() { None } else { Some(s) } } pub fn comment(&self) -> Comment { @@ -165,12 +234,18 @@ impl Cursor { } } - pub fn enum_val(&self) -> i64 { + pub fn enum_val_signed(&self) -> i64 { unsafe { clang_getEnumConstantDeclValue(self.x) as i64 } } + pub fn enum_val_unsigned(&self) -> u64 { + unsafe { + clang_getEnumConstantDeclUnsignedValue(self.x) as u64 + } + } + // typedef pub fn typedef_type(&self) -> Type { unsafe { @@ -195,7 +270,7 @@ impl Cursor { pub fn args(&self) -> Vec { unsafe { let num = self.num_args() as usize; - let mut args = vec!(); + let mut args = vec![]; for i in 0..num { args.push(Cursor { x: clang_Cursor_getArgument(self.x, i as c_uint) }); } @@ -235,6 +310,12 @@ impl Cursor { } } + pub fn method_is_const(&self) -> bool { + unsafe { + clang_CXXMethod_isConst(self.x) != 0 + } + } + pub fn method_is_virtual(&self) -> bool { unsafe { clang_CXXMethod_isVirtual(self.x) != 0 @@ -274,29 +355,40 @@ impl PartialEq for Cursor { clang_equalCursors(self.x, other.x) == 1 } } - - fn ne(&self, other: &Cursor) -> bool { - !self.eq(other) - } } impl Eq for Cursor {} impl Hash for Cursor { fn hash(&self, state: &mut H) { - self.x.kind.hash(state); - self.x.xdata.hash(state); - self.x.data[0].hash(state); - self.x.data[1].hash(state); - self.x.data[2].hash(state); + unsafe { clang_hashCursor(self.x) }.hash(state) } } // type +#[derive(Clone, Hash)] pub struct Type { x: CXType } +impl PartialEq for Type { + fn eq(&self, other: &Self) -> bool { + unsafe { + clang_equalTypes(self.x, other.x) != 0 + } + } +} + +impl Eq for Type {} + +impl fmt::Debug for Type { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "Type({}, kind: {}, decl: {:?}, canon: {:?})", + self.spelling(), type_to_str(self.kind()), self.declaration(), + self.declaration().canonical()) + } +} + #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum LayoutError { Invalid, @@ -358,7 +450,7 @@ impl Type { pub fn is_const(&self) -> bool { unsafe { - clang_isConstQualifiedType(self.x) == 1 + clang_isConstQualifiedType(self.x) != 0 } } @@ -378,6 +470,24 @@ impl Type { } } + pub fn fallible_align(&self) -> Result { + unsafe { + let val = clang_Type_getAlignOf(self.x); + if val < 0 { + Err(LayoutError::from(val as i32)) + } else { + Ok(val as usize) + } + } + } + + pub fn fallible_layout(&self) -> Result<::ir::layout::Layout, LayoutError> { + use ir::layout::Layout; + let size = try!(self.fallible_size()); + let align = try!(self.fallible_align()); + Ok(Layout::new(size, align)) + } + pub fn align(&self) -> usize { unsafe { let val = clang_Type_getAlignOf(self.x); @@ -427,7 +537,7 @@ impl Type { // function pub fn is_variadic(&self) -> bool { unsafe { - clang_isFunctionTypeVariadic(self.x) == 1 + clang_isFunctionTypeVariadic(self.x) != 0 } } @@ -581,21 +691,25 @@ pub struct Index { } impl Index { - pub fn create(pch: bool, diag: bool) -> Index { + pub fn new(pch: bool, diag: bool) -> Index { unsafe { Index { x: clang_createIndex(pch as c_int, diag as c_int) } } } +} - pub fn dispose(&self) { +impl fmt::Debug for Index { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "Index {{ }}") + } +} + +impl Drop for Index { + fn drop(&mut self) { unsafe { clang_disposeIndex(self.x); } } - - pub fn is_null(&self) -> bool { - self.x.is_null() - } } // Token @@ -609,6 +723,12 @@ pub struct TranslationUnit { x: CXTranslationUnit } +impl fmt::Debug for TranslationUnit { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "TranslationUnit {{ }}") + } +} + impl TranslationUnit { pub fn parse(ix: &Index, file: &str, cmd_args: &[String], unsaved: &[UnsavedFile], opts: ::libc::c_uint) -> TranslationUnit { @@ -655,12 +775,6 @@ impl TranslationUnit { } } - pub fn dispose(&self) { - unsafe { - clang_disposeTranslationUnit(self.x); - } - } - pub fn is_null(&self) -> bool { self.x.is_null() } @@ -687,6 +801,15 @@ impl TranslationUnit { } } +impl Drop for TranslationUnit { + fn drop(&mut self) { + unsafe { + clang_disposeTranslationUnit(self.x); + } + } +} + + // Diagnostic pub struct Diagnostic { x: CXDiagnostic diff --git a/src/clangll.rs b/src/clangll.rs index b94356bcbc..47f41ff1ca 100644 --- a/src/clangll.rs +++ b/src/clangll.rs @@ -428,7 +428,7 @@ pub const CXCallingConv_X86_64SysV: c_uint = 11; pub const CXCallingConv_Invalid: c_uint = 100; pub const CXCallingConv_Unexposed: c_uint = 200; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Hash)] pub struct CXType { pub kind: Enum_CXTypeKind, pub data: [*mut c_void; 2], @@ -1076,6 +1076,7 @@ extern "C" { pub fn clang_Cursor_getNumArguments(C: CXCursor) -> c_int; pub fn clang_Cursor_getArgument(C: CXCursor, i: c_uint) -> CXCursor; + pub fn clang_Cursor_getNumTemplateArguments(T: CXCursor) -> c_int; pub fn clang_Cursor_getTemplateArgumentKind(C: CXCursor, i: c_uint) -> CXTemplateArgumentKind; pub fn clang_Cursor_getTemplateArgumentValue(C: CXCursor, i: c_uint) -> @@ -1148,6 +1149,7 @@ extern "C" { pieceIndex: c_uint, options: c_uint) -> CXSourceRange; + pub fn clang_Cursor_getOffsetOfField(C: CXCursor) -> c_longlong; pub fn clang_getCursorDisplayName(arg1: CXCursor) -> CXString; pub fn clang_getCursorReferenced(arg1: CXCursor) -> CXCursor; pub fn clang_getCursorDefinition(arg1: CXCursor) -> CXCursor; @@ -1168,6 +1170,7 @@ extern "C" { pub fn clang_Cursor_getMangling(C: CXCursor) -> CXString; pub fn clang_Cursor_getParsedComment(C: CXCursor) -> CXComment; pub fn clang_Cursor_getModule(C: CXCursor) -> CXModule; + pub fn clang_Cursor_isAnonymous(C: CXCursor) -> c_uint; pub fn clang_Module_getASTFile(Module: CXModule) -> CXFile; pub fn clang_Module_getParent(Module: CXModule) -> CXModule; pub fn clang_Module_getName(Module: CXModule) -> CXString; @@ -1241,6 +1244,7 @@ extern "C" { pub fn clang_FullComment_getAsHTML(Comment: CXComment) -> CXString; pub fn clang_FullComment_getAsXML(Comment: CXComment) -> CXString; pub fn clang_CXXMethod_isPureVirtual(C: CXCursor) -> c_uint; + pub fn clang_CXXMethod_isConst(C: CXCursor) -> c_uint; pub fn clang_CXXMethod_isStatic(C: CXCursor) -> c_uint; pub fn clang_CXXMethod_isVirtual(C: CXCursor) -> c_uint; pub fn clang_CXXField_isMutable(C: CXCursor) -> c_uint; diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs new file mode 100644 index 0000000000..e2fc11201a --- /dev/null +++ b/src/codegen/helpers.rs @@ -0,0 +1,113 @@ +/// Helpers for code generation that don't need macro expansion. + +use aster; +use ir::layout::Layout; +use syntax::ast; +use syntax::codemap::respan; +use syntax::ptr::P; + + +pub mod attributes { + use aster; + use syntax::ast; + + pub fn repr(which: &str) -> ast::Attribute { + aster::AstBuilder::new().attr().list("repr").words(&[which]).build() + } + + pub fn repr_list(which_ones: &[&str]) -> ast::Attribute { + aster::AstBuilder::new().attr().list("repr").words(which_ones).build() + } + + pub fn derives(which_ones: &[&str]) -> ast::Attribute { + aster::AstBuilder::new().attr().list("derive").words(which_ones).build() + } + + pub fn inline() -> ast::Attribute { + aster::AstBuilder::new().attr().word("inline") + } + + pub fn doc(comment: &str) -> ast::Attribute { + aster::AstBuilder::new().attr().doc(comment) + } + + pub fn link_name(name: &str) -> ast::Attribute { + aster::AstBuilder::new().attr().name_value("link_name").str(name) + } +} + +/// Generates a proper type for a field or type with a given `Layout`, that is, +/// a type with the correct size and alignment restrictions. +pub struct BlobTyBuilder { + layout: Layout, +} + +impl BlobTyBuilder { + pub fn new(layout: Layout) -> Self { + BlobTyBuilder { + layout: layout, + } + } + + pub fn build(self) -> P { + use std::cmp; + + let ty_name = match self.layout.align { + 8 => "u64", + 4 => "u32", + 2 => "u16", + 1 | _ => "u8", + }; + let data_len = if ty_name == "u8" { + self.layout.size + } else { + self.layout.size / cmp::max(self.layout.align, 1) + }; + + let inner_ty = aster::AstBuilder::new().ty().path().id(ty_name).build(); + if data_len == 1 { + inner_ty + } else { + ArrayTyBuilder::new().with_len(data_len).build(inner_ty) + } + } +} + +pub struct ArrayTyBuilder { + len: usize, +} + +impl ArrayTyBuilder { + pub fn new() -> Self { + ArrayTyBuilder { + len: 0, + } + } + + pub fn with_len(mut self, len: usize) -> Self { + self.len = len; + self + } + + pub fn build(self, ty: P) -> P { + use syntax::codemap::DUMMY_SP; + let size = + ast::LitKind::Int(self.len as u64, + ast::LitIntType::Unsigned(ast::UintTy::Us)); + let size = ast::ExprKind::Lit(P(respan(DUMMY_SP, size))); + let array_kind = ast::TyKind::FixedLengthVec(ty, + P(ast::Expr { + id: ast::DUMMY_NODE_ID, + node: size, + span: DUMMY_SP, + attrs: ast::ThinVec::new(), + }) + ); + + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: array_kind, + span: DUMMY_SP, + }) + } +} diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs new file mode 100644 index 0000000000..62cebf460a --- /dev/null +++ b/src/codegen/mod.rs @@ -0,0 +1,1904 @@ +mod helpers; + +use self::helpers::{attributes, ArrayTyBuilder, BlobTyBuilder}; + +use ir::context::BindgenContext; +use ir::item::{Item, ItemId, ItemCanonicalName, ItemCanonicalPath}; +use ir::ty::{Type, TypeKind}; +use ir::int::IntKind; +use ir::module::Module; +use ir::var::Var; +use ir::enum_ty::Enum; +use ir::function::{Function, FunctionSig}; +use ir::item_kind::ItemKind; +use ir::comp::{CompKind, CompInfo, Field, Method}; +use ir::layout::Layout; +use ir::annotations::FieldAccessorKind; + +use std::ops; +use std::mem; +use std::collections::BTreeSet; +use std::collections::HashSet; +use std::collections::hash_map::{HashMap, Entry}; + +use syntax::abi::Abi; +use syntax::ast; +use syntax::codemap::{Span, respan}; +use syntax::ptr::P; +use aster; + +fn root_import(ctx: &BindgenContext) -> P { + assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up"); + let root = ctx.root_module().canonical_name(ctx); + let root_ident = ctx.rust_ident(&root); + quote_item!(ctx.ext_cx(), use $root_ident;).unwrap() +} + +struct CodegenResult { + items: Vec>, + saw_union: bool, + items_seen: HashSet, + /// The set of generated function names, needed because in C/C++ is legal to + /// do something like: + /// + /// ``` + /// extern "C" { + /// void foo(); + /// } + /// + /// extern "C" { + /// void foo(); + /// } + /// ``` + /// + /// Being these two different declarations. + functions_seen: HashSet, +} + +impl CodegenResult { + fn new() -> Self { + CodegenResult { + items: vec![], + saw_union: false, + items_seen: Default::default(), + functions_seen: Default::default(), + } + } + + fn saw_union(&mut self) { + self.saw_union = true; + } + + fn seen(&self, item: ItemId) -> bool { + self.items_seen.contains(&item) + } + + fn set_seen(&mut self, item: ItemId) { + self.items_seen.insert(item); + } + + fn seen_function(&self, name: &str) -> bool { + self.functions_seen.contains(name) + } + + fn saw_function(&mut self, name: &str) { + self.functions_seen.insert(name.into()); + } + + fn inner(&mut self, cb: F) -> Vec> + where F: FnOnce(&mut Self) + { + let mut new = Self::new(); + + cb(&mut new); + + self.saw_union |= new.saw_union; + + new.items + } +} + +impl ops::Deref for CodegenResult { + type Target = Vec>; + + fn deref(&self) -> &Self::Target { + &self.items + } +} + +impl ops::DerefMut for CodegenResult { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.items + } +} + +struct ForeignModBuilder { + inner: ast::ForeignMod, +} + +impl ForeignModBuilder { + fn new(abi: Abi) -> Self { + ForeignModBuilder { + inner: ast::ForeignMod { + abi: abi, + items: vec![], + } + } + } + + fn with_foreign_item(mut self, item: ast::ForeignItem) -> Self { + self.inner.items.push(item); + self + } + + #[allow(dead_code)] + fn with_foreign_items(mut self, items: I) -> Self + where I: IntoIterator + { + self.inner.items.extend(items.into_iter()); + self + } + + fn build(self, ctx: &BindgenContext) -> P { + use syntax::codemap::DUMMY_SP; + P(ast::Item { + ident: ctx.rust_ident(""), + id: ast::DUMMY_NODE_ID, + node: ast::ItemKind::ForeignMod(self.inner), + vis: ast::Visibility::Public, + attrs: vec![], + span: DUMMY_SP, + }) + } +} + +/// A trait to convert a rust type into a pointer, optionally const, to the same +/// type. +/// +/// This is done due to aster's lack of pointer builder, I guess I should PR +/// there. +trait ToPtr { + fn to_ptr(self, is_const: bool, span: Span) -> P; +} + +impl ToPtr for P { + fn to_ptr(self, is_const: bool, span: Span) -> Self { + let ty = ast::TyKind::Ptr(ast::MutTy { + ty: self, + mutbl: if is_const { + ast::Mutability::Immutable + } else { + ast::Mutability::Mutable + } + }); + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ty, + span: span, + }) + } +} + +trait CodeGenerator { + /// Extra information from the caller. + type Extra; + + fn codegen(&self, + ctx: &BindgenContext, + result: &mut CodegenResult, + extra: &Self::Extra); +} + +impl CodeGenerator for Item { + type Extra = (); + + fn codegen(&self, + ctx: &BindgenContext, + result: &mut CodegenResult, + _extra: &()) { + if self.is_hidden(ctx) || result.seen(self.id()) { + return; + } + + result.set_seen(self.id()); + + match *self.kind() { + ItemKind::Module(ref module) => { + if !ctx.options().enable_cxx_namespaces && self.id() == ctx.root_module() { + return; + } + + module.codegen(ctx, result, self); + }, + ItemKind::Function(ref fun) => { + if !ctx.options().ignore_functions { + fun.codegen(ctx, result, self); + } + }, + ItemKind::Var(ref var) => { + var.codegen(ctx, result, self); + }, + ItemKind::Type(ref ty) => { + ty.codegen(ctx, result, self); + } + } + } +} + +impl CodeGenerator for Module { + type Extra = Item; + + fn codegen(&self, + ctx: &BindgenContext, + result: &mut CodegenResult, + item: &Item) { + if !ctx.options().enable_cxx_namespaces { + for child in self.children() { + ctx.resolve_item(*child).codegen(ctx, result, &()); + } + return; + } + + let inner_items = result.inner(|result| { + result.push(root_import(ctx)); + for child in self.children() { + ctx.resolve_item(*child).codegen(ctx, result, &()); + } + }); + + let module = ast::ItemKind::Mod(ast::Mod { + inner: ctx.span(), + items: inner_items, + }); + + let name = item.canonical_name(ctx); + let item = aster::AstBuilder::new().item().pub_() + .build_item_kind(name, module); + + result.push(item); + } +} + +impl CodeGenerator for Var { + type Extra = Item; + fn codegen(&self, + ctx: &BindgenContext, + result: &mut CodegenResult, + item: &Item) { + let name = item.canonical_name(ctx); + let ty = self.ty().to_rust_ty(ctx); + + if let Some(val) = self.val() { + let const_item = aster::AstBuilder::new().item().pub_().const_(name) + .expr().int(val).build(ty); + result.push(const_item) + } else { + let mut attrs = vec![]; + if let Some(mangled) = self.mangled_name() { + attrs.push(attributes::link_name(mangled)); + } else if name != self.name() { + attrs.push(attributes::link_name(self.name())); + } + + let item = ast::ForeignItem { + ident: ctx.rust_ident_raw(&name), + attrs: attrs, + node: ast::ForeignItemKind::Static(ty, !self.is_const()), + id: ast::DUMMY_NODE_ID, + span: ctx.span(), + vis: ast::Visibility::Public, + }; + + let item = ForeignModBuilder::new(Abi::C) + .with_foreign_item(item) + .build(ctx); + result.push(item); + } + } +} + +impl CodeGenerator for Type { + type Extra = Item; + + fn codegen(&self, + ctx: &BindgenContext, + result: &mut CodegenResult, + item: &Item) { + match *self.kind() { + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Array(..) | + TypeKind::Pointer(..) | + TypeKind::Reference(..) | + TypeKind::TemplateRef(..) | + TypeKind::Function(..) | + TypeKind::ResolvedTypeRef(..) | + TypeKind::Named(..) => { + // These items don't need code generation, they only need to be + // converted to rust types in fields, arguments, and such. + return; + } + TypeKind::Comp(ref ci) => ci.codegen(ctx, result, item), + TypeKind::Alias(ref spelling, inner) => { + let inner_item = ctx.resolve_item(inner); + let name = item.canonical_name(ctx); + + // Try to catch the common pattern: + // + // typedef struct foo { ... } foo; + // + // here. + // + if inner_item.canonical_name(ctx) == name { + return; + } + + // If this is a known named type, disallow generating anything + // for it too. + if utils::type_from_named(ctx, spelling, inner).is_some() { + return; + } + + let mut applicable_template_args = item.applicable_template_args(ctx); + let inner_rust_type = if item.is_opaque(ctx) { + applicable_template_args.clear(); + // Pray if there's no layout. + let layout = self.layout(ctx).unwrap_or_else(Layout::zero); + BlobTyBuilder::new(layout).build() + } else { + inner_item.to_rust_ty(ctx) + }; + + let rust_name = ctx.rust_ident(&name); + let mut typedef = aster::AstBuilder::new().item().pub_(); + + if let Some(comment) = item.comment() { + typedef = typedef.attr().doc(comment); + } + + let mut generics = typedef.type_(rust_name).generics(); + for template_arg in applicable_template_args.iter() { + let template_arg = ctx.resolve_type(*template_arg); + if template_arg.is_named() { + let name = template_arg.name().unwrap(); + if name.contains("typename ") { + error!("Item contained `typename`'d template param: {:?}", item); + return; + } + generics = generics.ty_param_id(template_arg.name().unwrap()); + } + } + + let typedef = generics.build().build_ty(inner_rust_type); + result.push(typedef) + } + TypeKind::Enum(ref ei) => ei.codegen(ctx, result, item), + ref u @ TypeKind::UnresolvedTypeRef(..) + => unreachable!("Should have been resolved after parsing {:?}!", u), + } + } +} + +struct Vtable<'a> { + item_id: ItemId, + #[allow(dead_code)] + methods: &'a [Method], + #[allow(dead_code)] + base_classes: &'a [ItemId], +} + +impl<'a> Vtable<'a> { + fn new(item_id: ItemId, methods: &'a [Method], base_classes: &'a [ItemId]) -> Self { + Vtable { + item_id: item_id, + methods: methods, + base_classes: base_classes, + } + } +} + +impl<'a> CodeGenerator for Vtable<'a> { + type Extra = Item; + + fn codegen(&self, + ctx: &BindgenContext, + result: &mut CodegenResult, + item: &Item) { + assert_eq!(item.id(), self.item_id); + // For now, generate an empty struct, later we should generate function + // pointers and whatnot. + let vtable = aster::AstBuilder::new().item().pub_() + .with_attr(attributes::repr("C")) + .struct_(self.canonical_name(ctx)) + .build(); + result.push(vtable); + } +} + +impl<'a> ItemCanonicalName for Vtable<'a> { + fn canonical_name(&self, _ctx: &BindgenContext) -> String { + format!("bindgen_vtable_{}", self.item_id) + } +} + +impl<'a> ItemToRustTy for Vtable<'a> { + fn to_rust_ty(&self, ctx: &BindgenContext) -> P { + aster::ty::TyBuilder::new().id(self.canonical_name(ctx)) + } +} + +struct Bitfield<'a> { + index: usize, + fields: Vec<&'a Field>, +} + +impl<'a> Bitfield<'a> { + fn new(index: usize, fields: Vec<&'a Field>) -> Self { + Bitfield { + index: index, + fields: fields, + } + } + + fn codegen_fields(self, + ctx: &BindgenContext, + fields: &mut Vec, + methods: &mut Vec) { + use aster::struct_field::StructFieldBuilder; + use std::cmp; + let mut total_width = self.fields.iter() + .fold(0u32, |acc, f| acc + f.bitfield().unwrap()); + + if !total_width.is_power_of_two() || total_width < 8 { + total_width = cmp::max(8, total_width.next_power_of_two()); + } + debug_assert_eq!(total_width % 8, 0); + let total_width_in_bytes = total_width as usize / 8; + + let bitfield_type = + BlobTyBuilder::new(Layout::new(total_width_in_bytes, total_width_in_bytes)).build(); + let field_name = format!("_bitfield_{}", self.index); + let field_ident = ctx.ext_cx().ident_of(&field_name); + let field = StructFieldBuilder::named(&field_name).pub_() + .build_ty(bitfield_type.clone()); + fields.push(field); + + + let mut offset = 0; + for field in self.fields { + let width = field.bitfield().unwrap(); + let field_name = field.name() + .map(ToOwned::to_owned) + .unwrap_or_else(|| format!("at_offset_{}", offset)); + + let field_item = ctx.resolve_item(field.ty()); + let field_ty_layout = field_item.kind().expect_type() + .layout(ctx) + .expect("Bitfield without layout? Gah!"); + + let field_type = field_item.to_rust_ty(ctx); + let int_type = BlobTyBuilder::new(field_ty_layout).build(); + + let getter_name = ctx.ext_cx().ident_of(&field_name); + let setter_name = ctx.ext_cx().ident_of(&format!("set_{}", &field_name)); + let mask = ((1usize << width) - 1) << offset; + // The transmute is unfortunate, but it's needed for enums in + // bitfields. + let item = quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub fn $getter_name(&self) -> $field_type { + unsafe { + ::std::mem::transmute( + ((self.$field_ident & ($mask as $bitfield_type)) >> $offset) + as $int_type) + } + } + + #[inline] + pub fn $setter_name(&mut self, val: $field_type) { + self.$field_ident &= !($mask as $bitfield_type); + self.$field_ident |= (val as $int_type as $bitfield_type << $offset) & ($mask as $bitfield_type); + } + } + ).unwrap(); + + let items = match item.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, items) => items, + _ => unreachable!(), + }; + + methods.extend(items.into_iter()); + offset += width; + } + } +} + +impl CodeGenerator for CompInfo { + type Extra = Item; + + fn codegen(&self, + ctx: &BindgenContext, + result: &mut CodegenResult, + item: &Item) { + use aster::struct_field::StructFieldBuilder; + // Don't output classes with template parameters that aren't types, and + // also don't output template specializations, neither total or partial. + // + // TODO: Generate layout tests for template specializations, yay! + if self.has_non_type_template_params() || self.is_template_specialization() { + return; + } + + let applicable_template_args = item.applicable_template_args(ctx); + + let mut attributes = vec![]; + let mut needs_clone_impl = false; + if let Some(comment) = item.comment() { + attributes.push(attributes::doc(comment)); + } + if self.packed() { + attributes.push(attributes::repr_list(&["C", "packed"])); + } else { + attributes.push(attributes::repr("C")); + } + + let mut derives = vec![]; + let ty = item.expect_type(); + if ty.can_derive_debug(ctx) { + derives.push("Debug"); + } + + if ty.can_derive_copy(ctx) && !item.annotations().disallow_copy() { + derives.push("Copy"); + if !applicable_template_args.is_empty() { + // FIXME: This requires extra logic if you have a big array in a + // templated struct. The reason for this is that the magic: + // fn clone(&self) -> Self { *self } + // doesn't work for templates. + // + // It's not hard to fix though. + derives.push("Clone"); + } else { + needs_clone_impl = true; + } + } + + if !derives.is_empty() { + attributes.push(attributes::derives(&derives)) + } + + let mut template_args_used = vec![false; applicable_template_args.len()]; + let canonical_name = item.canonical_name(ctx); + let builder = aster::AstBuilder::new().item().pub_() + .with_attrs(attributes) + .struct_(&canonical_name); + + // Generate the vtable from the method list if appropriate. + // TODO: I don't know how this could play with virtual methods that are + // not in the list of methods found by us, we'll see. Also, could the + // order of the vtable pointers vary? + // + // FIXME: Once we generate proper vtables, we need to codegen the + // vtable, but *not* generate a field for it in the case that + // needs_explicit_vtable is false but has_vtable is true. + // + // Also, we need to generate the vtable in such a way it "inherits" from + // the parent too. + let mut fields = vec![]; + if self.needs_explicit_vtable(ctx) { + let vtable = Vtable::new(item.id(), + self.methods(), + self.base_members()); + vtable.codegen(ctx, result, item); + + let vtable_type = vtable.to_rust_ty(ctx).to_ptr(true, ctx.span()); + + let vtable_field = StructFieldBuilder::named("vtable_").pub_() + .build_ty(vtable_type); + + fields.push(vtable_field); + } + + for (i, base) in self.base_members().iter().enumerate() { + let base_ty = ctx.resolve_type(*base); + // NB: We won't include unsized types in our base chain because they + // would contribute to our size given the dummy field we insert for + // unsized types. + // + // NB: Canonical type is here because it could be inheriting from a + // typedef, for example, and the lack of `unwrap()` is because we + // can inherit from a template parameter, yes. + if base_ty.is_unsized(ctx) { + continue; + } + + for (i, ty) in applicable_template_args.iter().enumerate() { + if base_ty.signature_contains_named_type(ctx, ctx.resolve_type(*ty)) { + template_args_used[i] = true; + } + } + + let inner = base.to_rust_ty(ctx); + let field_name = if i == 0 { + "_base".into() + } else { + format!("_base_{}", i) + }; + + let field = StructFieldBuilder::named(field_name) + .pub_().build_ty(inner); + fields.push(field); + } + + let is_union = self.kind() == CompKind::Union; + if is_union { + result.saw_union(); + } + + let layout = item.kind().expect_type().layout(ctx); + + let mut current_bitfield_width = None; + let mut current_bitfield_layout: Option = None; + let mut current_bitfield_fields = vec![]; + let mut bitfield_count = 0; + let struct_fields = self.fields(); + let fields_should_be_private = item.annotations() + .private_fields() + .unwrap_or(false); + let struct_accessor_kind = item.annotations() + .accessor_kind() + .unwrap_or(FieldAccessorKind::None); + + let mut methods = vec![]; + let mut anonymous_field_count = 0; + for field in struct_fields { + debug_assert_eq!(current_bitfield_width.is_some(), + current_bitfield_layout.is_some()); + debug_assert_eq!(current_bitfield_width.is_some(), + !current_bitfield_fields.is_empty()); + + let field_ty = ctx.resolve_type(field.ty()); + + // Try to catch a bitfield contination early. + if let (Some(ref mut bitfield_width), Some(width)) = (current_bitfield_width, field.bitfield()) { + let layout = current_bitfield_layout.unwrap(); + debug!("Testing bitfield continuation {} {} {:?}", + *bitfield_width, width, layout); + if *bitfield_width + width <= (layout.size * 8) as u32 { + *bitfield_width += width; + current_bitfield_fields.push(field); + continue; + } + } + + // Flush the current bitfield. + if current_bitfield_width.is_some() { + debug_assert!(!current_bitfield_fields.is_empty()); + let bitfield_fields = + mem::replace(&mut current_bitfield_fields, vec![]); + bitfield_count += 1; + Bitfield::new(bitfield_count, bitfield_fields) + .codegen_fields(ctx, &mut fields, &mut methods); + current_bitfield_width = None; + current_bitfield_layout = None; + } + debug_assert!(current_bitfield_fields.is_empty()); + + if let Some(width) = field.bitfield() { + let layout = field_ty.layout(ctx) + .expect("Bitfield type without layout?"); + current_bitfield_width = Some(width); + current_bitfield_layout = Some(layout); + current_bitfield_fields.push(field); + continue; + } + + for (i, ty) in applicable_template_args.iter().enumerate() { + if field_ty.signature_contains_named_type(ctx, ctx.resolve_type(*ty)) { + template_args_used[i] = true; + } + } + + let ty = field.ty().to_rust_ty(ctx); + + let ty = if is_union { + quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>) + } else { + ty + }; + + let mut attrs = vec![]; + if let Some(comment) = field.comment() { + attrs.push(attributes::doc(comment)); + } + let field_name = match field.name() { + Some(name) => ctx.rust_mangle(name).into_owned(), + None => { + anonymous_field_count += 1; + format!("__bindgen_anon_{}", anonymous_field_count) + } + }; + + let is_private = field.annotations() + .private_fields() + .unwrap_or(fields_should_be_private); + + let accessor_kind = field.annotations() + .accessor_kind() + .unwrap_or(struct_accessor_kind); + + let mut field = StructFieldBuilder::named(&field_name); + + if !is_private { + field = field.pub_(); + } + + let field = field.with_attrs(attrs) + .build_ty(ty.clone()); + + fields.push(field); + + // TODO: Factor the following code out, please! + if accessor_kind == FieldAccessorKind::None { + continue; + } + + let getter_name = + ctx.rust_ident_raw(&format!("get_{}", field_name)); + let mutable_getter_name = + ctx.rust_ident_raw(&format!("get_{}_mut", field_name)); + let field_name = ctx.rust_ident_raw(&field_name); + + let accessor_methods_impl = match accessor_kind { + FieldAccessorKind::None => unreachable!(), + FieldAccessorKind::Regular => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub fn $getter_name(&self) -> &$ty { + &self.$field_name + } + + #[inline] + pub fn $mutable_getter_name(&mut self) -> &mut $ty { + &mut self.$field_name + } + } + ) + } + FieldAccessorKind::Unsafe => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub unsafe fn $getter_name(&self) -> &$ty { + &self.$field_name + } + + #[inline] + pub unsafe fn $mutable_getter_name(&mut self) -> &mut $ty { + &mut self.$field_name + } + } + ) + } + FieldAccessorKind::Immutable => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub fn $getter_name(&self) -> &$ty { + &self.$field_name + } + } + ) + } + }; + + match accessor_methods_impl.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) + => methods.extend(items.clone()), + _ => unreachable!() + } + } + + // Flush the last bitfield if any. + // + // FIXME: Reduce duplication with the loop above. + // FIXME: May need to pass current_bitfield_layout too. + if current_bitfield_width.is_some() { + debug_assert!(!current_bitfield_fields.is_empty()); + let bitfield_fields = mem::replace(&mut current_bitfield_fields, vec![]); + bitfield_count += 1; + Bitfield::new(bitfield_count, bitfield_fields) + .codegen_fields(ctx, &mut fields, &mut methods); + } + debug_assert!(current_bitfield_fields.is_empty()); + + if is_union { + let layout = layout.expect("Unable to get layout information?"); + let ty = BlobTyBuilder::new(layout).build(); + let field = StructFieldBuilder::named("bindgen_union_field").pub_() + .build_ty(ty); + fields.push(field); + } + + // Yeah, sorry about that. + if item.is_opaque(ctx) { + fields.clear(); + methods.clear(); + for i in 0..template_args_used.len() { + template_args_used[i] = false; + } + + match layout { + Some(l) => { + let ty = BlobTyBuilder::new(l).build(); + let field = StructFieldBuilder::named("_bindgen_opaque_blob").pub_() + .build_ty(ty); + fields.push(field); + } + None => { + warn!("Opaque type without layout! Expect dragons!"); + } + } + } + + // C requires every struct to be addressable, so what C compilers do is + // making the struct 1-byte sized. + // + // NOTE: This check is conveniently here to avoid the dummy fields we + // may add for unused template parameters. + if self.is_unsized(ctx) { + let ty = BlobTyBuilder::new(Layout::new(1, 1)).build(); + let field = StructFieldBuilder::named("_address").pub_() + .build_ty(ty); + fields.push(field); + } + + // Append any extra template arguments that nobody has used so far. + for (i, ty) in applicable_template_args.iter().enumerate() { + if !template_args_used[i] { + let name = ctx.resolve_type(*ty).name().unwrap(); + let ident = ctx.rust_ident(name); + let field = + StructFieldBuilder::named(format!("_phantom_{}", i)).pub_() + .build_ty(quote_ty!(ctx.ext_cx(), ::std::marker::PhantomData<$ident>)); + fields.push(field) + } + } + + + let mut generics = aster::AstBuilder::new().generics(); + for template_arg in applicable_template_args.iter() { + // Take into account that here only arrive named types, not + // template specialisations that would need to be + // instantiated. + // + // TODO: Add template args from the parent, here and in + // `to_rust_ty`!! + let template_arg = ctx.resolve_type(*template_arg); + generics = generics.ty_param_id(template_arg.name().unwrap()); + } + + let generics = generics.build(); + + let rust_struct = builder.with_generics(generics.clone()) + .with_fields(fields).build(); + result.push(rust_struct); + + // Generate the inner types and all that stuff. + // + // TODO: In the future we might want to be smart, and use nested + // modules, and whatnot. + for ty in self.inner_types() { + let child_item = ctx.resolve_item(*ty); + // assert_eq!(child_item.parent_id(), item.id()); + child_item.codegen(ctx, result, &()); + } + + // NOTE: Some unexposed attributes (like alignment attributes) may + // affect layout, so we're bad and pray to the gods for avoid sending + // all the tests to shit when parsing things like max_align_t. + if self.found_unknown_attr() { + warn!("Type {} has an unkown attribute that may affect layout", canonical_name); + } + if applicable_template_args.is_empty() && !self.found_unknown_attr() { + for var in self.inner_vars() { + ctx.resolve_item(*var).codegen(ctx, result, &()); + } + + if let Some(layout) = layout { + let fn_name = + ctx.rust_ident_raw(&format!("bindgen_test_layout_{}", canonical_name)); + let ident = ctx.rust_ident_raw(&canonical_name); + let size_of_expr = + quote_expr!(ctx.ext_cx(), ::std::mem::size_of::<$ident>()); + let align_of_expr = + quote_expr!(ctx.ext_cx(), ::std::mem::align_of::<$ident>()); + let size = layout.size; + let align = layout.align; + let item = quote_item!(ctx.ext_cx(), + #[test] + fn $fn_name() { + assert_eq!($size_of_expr, $size); + assert_eq!($align_of_expr, $align); + }).unwrap(); + result.push(item); + } + + let mut method_names = Default::default(); + for method in self.methods() { + method.codegen_method(ctx, &mut methods, &mut method_names, result, item); + } + } + + // NB: We can't use to_rust_ty here since for opaque types this tries to + // use the specialization knowledge to generate a blob field. + let ty_for_impl = aster::AstBuilder::new().ty().path().id(&canonical_name).build(); + if needs_clone_impl { + let impl_ = quote_item!(ctx.ext_cx(), + impl X { + fn clone(&self) -> Self { *self } + } + ); + + let impl_ = match impl_.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), + _ => unreachable!(), + }; + + let clone_impl = + aster::AstBuilder::new().item().impl_() + .trait_().id("Clone").build() + .with_generics(generics.clone()) + .with_items(impl_) + .build_ty(ty_for_impl.clone()); + + result.push(clone_impl); + } + + if !methods.is_empty() { + let methods = + aster::AstBuilder::new().item().impl_() + .with_generics(generics) + .with_items(methods) + .build_ty(ty_for_impl); + result.push(methods); + } + } +} + +trait MethodCodegen { + fn codegen_method(&self, + ctx: &BindgenContext, + methods: &mut Vec, + method_names: &mut HashMap, + result: &mut CodegenResult, + parent: &Item); +} + +impl MethodCodegen for Method { + fn codegen_method(&self, + ctx: &BindgenContext, + methods: &mut Vec, + method_names: &mut HashMap, + result: &mut CodegenResult, + _parent: &Item) { + if ctx.options().ignore_methods { + return; + } + + if self.is_virtual() { + return; // FIXME + } + // First of all, output the actual function. + ctx.resolve_item(self.signature()).codegen(ctx, result, &()); + + let function_item = ctx.resolve_item(self.signature()); + let function = function_item.expect_function(); + let mut name = function.name().to_owned(); + let signature_item = ctx.resolve_item(function.signature()); + let signature = match *signature_item.expect_type().kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("How in the world?"), + }; + + let count = { + let mut count = method_names.entry(name.clone()) + .or_insert(0); + *count += 1; + *count - 1 + }; + + if count != 0 { + name.push_str(&count.to_string()); + } + + let function_name = function_item.canonical_name(ctx); + let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item).unwrap(); + if !self.is_static() { + let mutability = if self.is_const() { + ast::Mutability::Immutable + } else { + ast::Mutability::Mutable + }; + + assert!(!fndecl.inputs.is_empty()); + // FIXME: use aster here. + fndecl.inputs[0] = ast::Arg { + ty: P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::Rptr(None, ast::MutTy { + ty: P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::ImplicitSelf, + span: ctx.span() + }), + mutbl: mutability, + }), + span: ctx.span(), + }), + pat: P(ast::Pat { + id: ast::DUMMY_NODE_ID, + node: ast::PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Immutable), + respan(ctx.span(), ctx.ext_cx().ident_of("self")), + None), + span: ctx.span(), + }), + id: ast::DUMMY_NODE_ID, + }; + } + + let sig = ast::MethodSig { + unsafety: ast::Unsafety::Unsafe, + abi: Abi::Rust, + decl: P(fndecl.clone()), + generics: ast::Generics::default(), + constness: respan(ctx.span(), ast::Constness::NotConst), + }; + + // TODO: We need to keep in sync the argument names, so we should unify + // this with the other loop that decides them. + let mut unnamed_arguments = 0; + let mut exprs = signature.argument_types().iter().map(|&(ref name, _ty)| { + let arg_name = match *name { + Some(ref name) => ctx.rust_mangle(name).into_owned(), + None => { + unnamed_arguments += 1; + format!("arg{}", unnamed_arguments) + } + }; + aster::expr::ExprBuilder::new().id(arg_name) + }).collect::>(); + + if !self.is_static() { + assert!(!exprs.is_empty()); + exprs[0] = if self.is_const() { + quote_expr!(ctx.ext_cx(), &*self) + } else { + quote_expr!(ctx.ext_cx(), &mut *self) + }; + }; + + let call = aster::expr::ExprBuilder::new().call() + .id(function_name) + .with_args(exprs) + .build(); + + let block = ast::Block { + stmts: vec![ + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Expr(call), + span: ctx.span(), + } + ], + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + span: ctx.span(), + }; + + let mut attrs = vec![]; + attrs.push(attributes::inline()); + + let item = ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: ctx.ext_cx().ident_of(&name), + vis: ast::Visibility::Public, + attrs: attrs, + node: ast::ImplItemKind::Method(sig, P(block)), + defaultness: ast::Defaultness::Final, + span: ctx.span(), + }; + + methods.push(item); + } +} + +impl CodeGenerator for Enum { + type Extra = Item; + + fn codegen(&self, + ctx: &BindgenContext, + result: &mut CodegenResult, + item: &Item) { + use ir::enum_ty::EnumVariantValue; + + let name = item.canonical_name(ctx); + let layout = item.expect_type().layout(ctx); + + let repr = self.repr().map(|repr| ctx.resolve_type(repr)); + let repr = match repr { + Some(repr) => match *repr.canonical_type(ctx).kind() { + TypeKind::Int(int_kind) => int_kind, + _ => panic!("Unexpected type as enum repr"), + }, + None => { + warn!("Guessing type of enum! Forward declarations of enums shouldn't be legal!"); + IntKind::Int + } + }; + + let signed = repr.is_signed(); + let size = layout.map(|l| l.size).unwrap_or(0); + let repr_name = match (signed, size) { + (true, 1) => "i8", + (false, 1) => "u8", + (true, 2) => "i16", + (false, 2) => "u16", + (true, 4) => "i32", + (false, 4) => "u32", + (true, 8) => "i64", + (false, 8) => "u64", + _ => { + warn!("invalid enum decl: signed: {}, size: {}", signed, size); + "i32" + } + }; + + let mut builder = aster::AstBuilder::new().item().pub_(); + + // FIXME: Rust forbids repr with empty enums. Remove this condition when + // this is allowed. + if !self.variants().is_empty() { + builder = builder.with_attr(attributes::repr(repr_name)); + } + + if let Some(comment) = item.comment() { + builder = builder.with_attr(attributes::doc(comment)); + } + + let derives = + attributes::derives(&["Debug", "Copy", "Clone", "PartialEq", "Eq", "Hash"]); + + builder = builder.with_attr(derives); + + let mut builder = builder.enum_(&name); + + fn add_constant(enum_: &Type, + // Only to avoid recomputing every time. + enum_canonical_name: &str, + // May be the same as "variant" if it's because the enum + // is unnamed and we still haven't seen the value. + variant_name: &str, + referenced_name: &str, + enum_rust_ty: P, + result: &mut CodegenResult) { + let constant_name = if enum_.name().is_some() { + format!("{}_{}", enum_canonical_name, variant_name) + } else { + variant_name.into() + }; + + let constant = aster::AstBuilder::new().item().pub_() + .const_(constant_name) + .expr().path() + .ids(&[&*enum_canonical_name, referenced_name]) + .build().build(enum_rust_ty); + result.push(constant); + } + + // A map where we keep a value -> variant relation. + let mut seen_values = HashMap::<_, String>::new(); + let enum_ty = item.expect_type(); + let enum_rust_ty = item.to_rust_ty(ctx); + for variant in self.variants().iter() { + match seen_values.entry(variant.val()) { + Entry::Occupied(ref entry) => { + let existing_variant_name = entry.get(); + let variant_name = ctx.rust_mangle(variant.name()); + add_constant(enum_ty, &name, &*variant_name, + existing_variant_name, 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), + }; + let variant_name = ctx.rust_mangle(variant.name()); + builder = builder.with_variant_(ast::Variant_ { + name: ctx.rust_ident(&*variant_name), + attrs: vec![], + data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), + disr_expr: Some(expr), + }); + + // If it's an unnamed enum, we also generate a constant so + // it can be properly accessed. + if enum_ty.name().is_none() { + // NB: if we want to do this for other kind of nested + // enums we can probably mangle the name. + if item.is_toplevel(ctx) { + add_constant(enum_ty, &name, &variant_name, + &variant_name, enum_rust_ty.clone(), + result); + } + } + + entry.insert(variant_name.into_owned()); + } + } + } + + + result.push(builder.build()); + } +} + +trait ToRustTy { + type Extra; + + fn to_rust_ty(&self, ctx: &BindgenContext, extra: &Self::Extra) -> P; +} + +trait ItemToRustTy { + fn to_rust_ty(&self, ctx: &BindgenContext) -> P; +} + +// Convenience implementation. +impl ItemToRustTy for ItemId { + fn to_rust_ty(&self, ctx: &BindgenContext) -> P { + ctx.resolve_item(*self).to_rust_ty(ctx) + } +} + +impl ItemToRustTy for Item { + fn to_rust_ty(&self, ctx: &BindgenContext) -> P { + self.kind().expect_type().to_rust_ty(ctx, self) + } +} + +fn raw_type(ctx: &BindgenContext, name: &str) -> P { + let ident = ctx.rust_ident_raw(&name); + quote_ty!(ctx.ext_cx(), ::std::os::raw::$ident) +} + +impl ToRustTy for Type { + type Extra = Item; + + fn to_rust_ty(&self, ctx: &BindgenContext, item: &Item) -> P { + macro_rules! raw { + ($ty: ident) => { + raw_type(ctx, stringify!($ty)) + } + } + match *self.kind() { + TypeKind::Void => raw!(c_void), + // TODO: we should do something smart with nullptr, or maybe *const + // c_void is enough? + TypeKind::NullPtr => quote_ty!(ctx.ext_cx(), *const ::std::os::raw::c_void), + TypeKind::Int(ik) => { + match ik { + IntKind::Bool => aster::ty::TyBuilder::new().bool(), + IntKind::Char => raw!(c_char), + IntKind::UChar => raw!(c_uchar), + IntKind::Short => raw!(c_short), + IntKind::UShort => raw!(c_ushort), + IntKind::Int => raw!(c_int), + IntKind::UInt => raw!(c_uint), + IntKind::Long => raw!(c_long), + IntKind::ULong => raw!(c_ulong), + IntKind::LongLong => raw!(c_longlong), + IntKind::ULongLong => raw!(c_ulonglong), + IntKind::U16 => aster::ty::TyBuilder::new().u16(), + IntKind::U32 => aster::ty::TyBuilder::new().u32(), + } + } + TypeKind::Float(fk) => { + use ir::ty::FloatKind; + // TODO: we probably should just take the type layout into + // account? + match fk { + FloatKind::Float => aster::ty::TyBuilder::new().f32(), + FloatKind::Double | + FloatKind::LongDouble => aster::ty::TyBuilder::new().f64(), + } + } + TypeKind::Function(ref fs) => { + let ty = fs.to_rust_ty(ctx, item); + aster::AstBuilder::new().ty().option().build(ty) + } + TypeKind::Array(item, len) => { + let inner = item.to_rust_ty(ctx); + ArrayTyBuilder::new().with_len(len).build(inner) + } + TypeKind::Enum(..) => { + let path = item.canonical_path(ctx); + aster::AstBuilder::new().ty().path().ids(path).build() + } + TypeKind::TemplateRef(inner, ref template_args) => { + // PS: Sorry for the duplication here. + let mut inner_ty = inner.to_rust_ty(ctx).unwrap(); + + if let ast::TyKind::Path(_, ref mut path) = inner_ty.node { + path.segments.last_mut().unwrap().parameters = + ast::PathParameters::AngleBracketed( + ast::AngleBracketedParameterData { + lifetimes: vec![], + types: P::from_vec(template_args.iter().map(|arg| { + arg.to_rust_ty(ctx) + }).collect()), + bindings: P::from_vec(vec![]), + } + ); + } + + P(inner_ty) + } + TypeKind::ResolvedTypeRef(inner) => inner.to_rust_ty(ctx), + TypeKind::Alias(ref spelling, inner) => { + if item.is_opaque(ctx) { + // Pray if there's no available layout. + let layout = self.layout(ctx).unwrap_or_else(Layout::zero); + BlobTyBuilder::new(layout).build() + } else if let Some(ty) = utils::type_from_named(ctx, spelling, inner) { + ty + } else { + utils::build_templated_path(item, ctx, true) + } + } + TypeKind::Comp(ref info) => { + if item.is_opaque(ctx) || info.has_non_type_template_params() { + return match self.layout(ctx) { + Some(layout) => { + BlobTyBuilder::new(layout).build() + } + None => { + warn!("Couldn't compute layout for a type with non \ + template params or opaque, expect dragons!"); + aster::AstBuilder::new().ty().unit() + } + } + } + + utils::build_templated_path(item, ctx, false) + } + TypeKind::Pointer(inner) | + TypeKind::Reference(inner) => { + let inner = ctx.resolve_item(inner); + inner.to_rust_ty(ctx).to_ptr(inner.expect_type().is_const(), ctx.span()) + } + TypeKind::Named(..) => { + let name = item.canonical_name(ctx); + let ident = ctx.rust_ident(&name); + quote_ty!(ctx.ext_cx(), $ident) + } + ref u @ TypeKind::UnresolvedTypeRef(..) + => unreachable!("Should have been resolved after parsing {:?}!", u), + } + } +} + +impl ToRustTy for FunctionSig { + type Extra = Item; + + fn to_rust_ty(&self, ctx: &BindgenContext, _item: &Item) -> P { + // TODO: we might want to consider ignoring the reference return value. + let return_item = ctx.resolve_item(self.return_type()); + let ret = if let TypeKind::Void = *return_item.kind().expect_type().kind() { + ast::FunctionRetTy::Default(ctx.span()) + } else { + ast::FunctionRetTy::Ty(return_item.to_rust_ty(ctx)) + }; + + let mut unnamed_arguments = 0; + let arguments = self.argument_types().iter().map(|&(ref name, ty)| { + let arg_item = ctx.resolve_item(ty); + let arg_ty = arg_item.kind().expect_type(); + + // From the C90 standard (http://c0x.coding-guidelines.com/6.7.5.3.html) + // 1598 - A declaration of a parameter as “array of type” shall be + // adjusted to “qualified pointer to type”, where the type qualifiers + // (if any) are those specified within the [ and ] of the array type + // derivation. + let arg_ty = if let TypeKind::Array(t, _) = *arg_ty.kind() { + t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span()) + } else { + arg_item.to_rust_ty(ctx) + }; + + let arg_name = match *name { + Some(ref name) => ctx.rust_mangle(name).into_owned(), + None => { + unnamed_arguments += 1; + format!("arg{}", unnamed_arguments) + } + }; + + assert!(!arg_name.is_empty()); + + ast::Arg { + ty: arg_ty, + pat: aster::AstBuilder::new().pat().id(arg_name), + id: ast::DUMMY_NODE_ID, + } + }).collect::>(); + + let decl = P(ast::FnDecl { + inputs: arguments, + output: ret, + variadic: self.is_variadic(), + }); + + let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: self.abi(), + lifetimes: vec![], + decl: decl, + })); + + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: fnty, + span: ctx.span(), + }) + } +} + +impl CodeGenerator for Function { + type Extra = Item; + + fn codegen(&self, + ctx: &BindgenContext, + result: &mut CodegenResult, + item: &Item) { + let name = self.name(); + let canonical_name = item.canonical_name(ctx); + + // TODO: Maybe warn here if there's a type/argument mismatch, or + // something? + if result.seen_function(&canonical_name) { + return; + } + result.saw_function(&canonical_name); + + let signature_item = ctx.resolve_item(self.signature()); + let signature = signature_item.kind().expect_type(); + let signature = match *signature.kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("How?"), + }; + + let fndecl = utils::rust_fndecl_from_signature(ctx, signature_item); + + let mut attributes = vec![]; + + if let Some(comment) = item.comment() { + attributes.push(attributes::doc(comment)); + } + + if let Some(mangled) = self.mangled_name() { + attributes.push(attributes::link_name(mangled)); + } else if name != canonical_name { + attributes.push(attributes::link_name(name)); + } + + let foreign_item_kind = + ast::ForeignItemKind::Fn(fndecl, ast::Generics::default()); + + let foreign_item = + ast::ForeignItem { + ident: ctx.rust_ident_raw(&canonical_name), + attrs: attributes, + node: foreign_item_kind, + id: ast::DUMMY_NODE_ID, + span: ctx.span(), + vis: ast::Visibility::Public, + }; + + let item = ForeignModBuilder::new(signature.abi()) + .with_foreign_item(foreign_item) + .build(ctx); + + result.push(item); + } +} + +type ItemSet = BTreeSet; + +trait TypeCollector { + type Extra; + + fn collect_types(&self, + context: &BindgenContext, + types: &mut ItemSet, + extra: &Self::Extra); +} + +impl TypeCollector for ItemId { + type Extra = (); + + fn collect_types(&self, + context: &BindgenContext, + types: &mut ItemSet, + extra: &()) { + context.resolve_item(*self).collect_types(context, types, extra); + } +} + +impl TypeCollector for Item { + type Extra = (); + + fn collect_types(&self, + context: &BindgenContext, + types: &mut ItemSet, + _extra: &()) { + if self.is_hidden(context) || types.contains(&self.id()) { + return; + } + + match *self.kind() { + ItemKind::Type(ref ty) => { + types.insert(self.id()); + if !self.is_opaque(context) { + ty.collect_types(context, types, self); + } + } + _ => {}, // FIXME. + } + } +} + +impl TypeCollector for Type { + type Extra = Item; + + fn collect_types(&self, + context: &BindgenContext, + types: &mut ItemSet, + item: &Item) { + match *self.kind() { + TypeKind::Pointer(inner) | + TypeKind::Reference(inner) | + TypeKind::Array(inner, _) | + TypeKind::Alias(_, inner) | + TypeKind::Named(_, Some(inner)) | + TypeKind::ResolvedTypeRef(inner) + => inner.collect_types(context, types, &()), + + TypeKind::TemplateRef(inner, ref template_args) => { + inner.collect_types(context, types, &()); + for item in template_args { + item.collect_types(context, types, &()); + } + } + TypeKind::Comp(ref ci) => ci.collect_types(context, types, item), + TypeKind::Function(ref sig) => { + sig.collect_types(context, types, item) + } + // FIXME: Pending types! + ref other @ _ => { + debug!("Ignoring: {:?}", other); + }, + } + } +} + +impl TypeCollector for FunctionSig { + type Extra = Item; + + fn collect_types(&self, + context: &BindgenContext, + types: &mut ItemSet, + _item: &Item) { + self.return_type().collect_types(context, types, &()); + + for &(_, ty) in self.argument_types() { + ty.collect_types(context, types, &()); + } + } +} + +impl TypeCollector for CompInfo { + type Extra = Item; + + fn collect_types(&self, + context: &BindgenContext, + types: &mut ItemSet, + item: &Item) { + if let Some(template) = self.specialized_template() { + template.collect_types(context, types, &()); + } + + let applicable_template_args = item.applicable_template_args(context); + for arg in applicable_template_args { + arg.collect_types(context, types, &()); + } + + for base in self.base_members() { + base.collect_types(context, types, &()); + } + + for field in self.fields() { + field.ty().collect_types(context, types, &()); + } + + for ty in self.inner_types() { + ty.collect_types(context, types, &()); + } + + // FIXME(emilio): Methods, VTable? + } +} + +pub fn codegen(context: &mut BindgenContext) -> Vec> { + context.gen(|context| { + let mut result = CodegenResult::new(); + + debug!("codegen: {:?}", context.options()); + + // If the whitelisted types and functions sets are empty, just generate + // everything. + if context.options().whitelisted_types.is_empty() && + context.options().whitelisted_functions.is_empty() && + context.options().whitelisted_vars.is_empty() { + for (_item_id, item) in context.items() { + // Non-toplevel item parents are the responsible one for generating + // them. + if item.is_toplevel(context) { + item.codegen(context, &mut result, &()); + } + } + } else { + // Recursively collect all the types dependent on the whitelisted + // types, then generate them. + // + // FIXME(emilio): This pass is probably slow, but it can't be faster + // than docopt anyway :) + let mut items = ItemSet::new(); + for (_item_id, item) in context.items() { + // FIXME(emilio): This probably should look only at whether the + // parent is a module. + if !item.is_toplevel(context) { + continue; + } + + let name = item.canonical_name(context); + match *item.kind() { + ItemKind::Type(ref ty) => { + if context.options().whitelisted_types.matches(&name) { + item.collect_types(context, &mut items, &()); + } + // Unnamed top-level enums are special and we whitelist + // them via the whitelisted_vars filter, since they're + // effectively top-level constants, and there's no way + // for them to be referenced consistently. + if let TypeKind::Enum(ref enum_) = *ty.kind() { + if ty.name().is_none() { + if enum_.variants().iter().any(|variant| { + context.options().whitelisted_vars.matches(&variant.name()) + }) { + item.collect_types(context, &mut items, &()); + } + } + } + } + ItemKind::Function(ref fun) => { + if context.options().whitelisted_functions.matches(&name) { + items.insert(item.id()); + fun.signature().collect_types(context, &mut items, &()); + } + } + ItemKind::Var(ref var) => { + if context.options().whitelisted_vars.matches(&name) { + items.insert(item.id()); + var.ty().collect_types(context, &mut items, &()); + } + } + ItemKind::Module(..) => {} + } + } + + fn contains_parent(ctx: &BindgenContext, types: &ItemSet, id: ItemId) -> bool { + let item = ctx.resolve_item(id); + let mut last = id; + let mut current = item.parent_id(); + + while last != current { + if types.contains(¤t) { + return true; + } + last = current; + current = ctx.resolve_item(current).parent_id(); + } + + false + } + + for item_id in items.iter() { + let item = context.resolve_item(*item_id); + if item.is_toplevel(context) || !contains_parent(context, &items, *item_id) { + item.codegen(context, &mut result, &()); + } + } + } + let saw_union = result.saw_union; + let mut result = result.items; + if saw_union { + utils::prepend_union_types(context, &mut result); + } + result + }) +} + +mod utils { + use ir::context::BindgenContext; + use ir::item::{Item, ItemCanonicalPath, ItemId}; + use ir::ty::TypeKind; + use syntax::ast; + use syntax::ptr::P; + use std::mem; + use super::ItemToRustTy; + use aster; + + pub fn prepend_union_types(ctx: &BindgenContext, result: &mut Vec>) { + let union_field_decl = quote_item!(ctx.ext_cx(), + #[derive(Debug)] + #[repr(C)] + pub struct __BindgenUnionField(::std::marker::PhantomData); + ).unwrap(); + + let union_field_impl = quote_item!(&ctx.ext_cx(), + impl __BindgenUnionField { + #[inline] + pub fn new() -> Self { + __BindgenUnionField(::std::marker::PhantomData) + } + + #[inline] + pub unsafe fn as_ref(&self) -> &T { + ::std::mem::transmute(self) + } + + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { + ::std::mem::transmute(self) + } + } + ).unwrap(); + + let union_field_default_impl = quote_item!(&ctx.ext_cx(), + impl ::std::default::Default for __BindgenUnionField { + #[inline] + fn default() -> Self { + Self::new() + } + } + ).unwrap(); + + let union_field_clone_impl = quote_item!(&ctx.ext_cx(), + impl ::std::clone::Clone for __BindgenUnionField { + #[inline] + fn clone(&self) -> Self { + Self::new() + } + } + ).unwrap(); + + let union_field_copy_impl = quote_item!(&ctx.ext_cx(), + impl ::std::marker::Copy for __BindgenUnionField {} + ).unwrap(); + + let items = vec![ + union_field_decl, union_field_impl, + union_field_default_impl, + union_field_clone_impl, + union_field_copy_impl, + ]; + + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + + + pub fn build_templated_path(item: &Item, ctx: &BindgenContext, only_named: bool) -> P { + let path = item.canonical_path(ctx); + + let builder = aster::AstBuilder::new().ty().path(); + let template_args = if only_named { + item.applicable_template_args(ctx).iter().filter(|arg| { + ctx.resolve_type(**arg).is_named() + }).map(|arg| { + arg.to_rust_ty(ctx) + }).collect::>() + } else { + item.applicable_template_args(ctx).iter().map(|arg| { + arg.to_rust_ty(ctx) + }).collect::>() + }; + + // XXX: I suck at aster. + if path.len() == 1 { + return builder.segment(&path[0]) + .with_tys(template_args).build().build(); + } + + let mut builder = builder.id(&path[0]); + for (i, segment) in path.iter().skip(1).enumerate() { + // Take into account the skip(1) + builder = if i == path.len() - 2 { + // XXX Extra clone courtesy of the borrow checker. + builder.segment(&segment) + .with_tys(template_args.clone()).build() + } else { + builder.segment(&segment).build() + } + } + + builder.build() + } + + fn primitive_ty(ctx: &BindgenContext, name: &str) -> P { + let ident = ctx.rust_ident_raw(&name); + quote_ty!(ctx.ext_cx(), $ident) + } + + pub fn type_from_named(ctx: &BindgenContext, + name: &str, + _inner: ItemId) -> Option> { + // FIXME: We could use the inner item to check this is really a + // primitive type but, who the heck overrides these anyway? + macro_rules! ty { + ($which:ident) => {{ + primitive_ty(ctx, stringify!($which)) + }} + } + Some(match name { + "int8_t" => ty!(i8), + "uint8_t" => ty!(u8), + "int16_t" => ty!(i16), + "uint16_t" => ty!(u16), + "int32_t" => ty!(i32), + "uint32_t" => ty!(u32), + "int64_t" => ty!(i64), + "uint64_t" => ty!(u64), + + "uintptr_t" | + "size_t" => ty!(usize), + + "intptr_t" | + "ptrdiff_t" | + "ssize_t" => ty!(isize), + _ => return None, + }) + } + + pub fn rust_fndecl_from_signature(ctx: &BindgenContext, sig: &Item) -> P { + use codegen::ToRustTy; + + let signature = sig.kind().expect_type(); + let signature = match *signature.kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("How?"), + }; + + let decl_ty = signature.to_rust_ty(ctx, sig); + match decl_ty.unwrap().node { + ast::TyKind::BareFn(bare_fn) => bare_fn.unwrap().decl, + _ => panic!("How did this happen exactly?"), + } + } +} diff --git a/src/gen.rs b/src/gen.rs deleted file mode 100644 index eab4478afb..0000000000 --- a/src/gen.rs +++ /dev/null @@ -1,2364 +0,0 @@ -use std; -use hacks::refcell::RefCell; -use std::vec::Vec; -use std::rc::Rc; -use std::collections::HashMap; -use syntax::abi::Abi; -use syntax::ast; -use syntax::codemap::{Span, respan, ExpnInfo, NameAndSpan, MacroBang}; -use syntax::ext::base; -use syntax::ext::build::AstBuilder; -use syntax::ext::expand::ExpansionConfig; -use syntax::ext::quote::rt::ToTokens; -use syntax::feature_gate::Features; -use syntax::parse; -use syntax::parse::token::{InternedString, intern}; -use syntax::attr::mk_attr_id; -use syntax::ptr::P; -use syntax::print::pprust::tts_to_string; - -use super::BindgenOptions; -use super::LinkType; -use parser::Accessor; -use types::*; -use aster; - -struct GenCtx<'r> { - ext_cx: base::ExtCtxt<'r>, - options: BindgenOptions, - span: Span, - module_map: ModuleMap, - current_module_id: ModuleId, - saw_union: bool, -} - -impl<'r> GenCtx<'r> { - fn full_path_for_module(&self, id: ModuleId) -> Vec { - if !self.options.enable_cxx_namespaces { - return vec![]; - } - - let mut ret = vec![]; - - let mut current_id = Some(id); - while let Some(current) = current_id { - let module = &self.module_map.get(¤t).unwrap(); - ret.push(module.name.clone()); - current_id = module.parent_id; - } - - if self.current_module_id == ROOT_MODULE_ID { - ret.pop(); // The root module doens'n need a root:: in the pattern - } - - ret.reverse(); - ret - } - - fn current_module_mut(&mut self) -> &mut Module { - let id = self.current_module_id; - self.module_map.get_mut(&id).expect("Module not found!") - } -} - -fn first((val, _): (A, B)) -> A { - val -} - -fn ref_eq(thing: &T, other: &T) -> bool { - (thing as *const T) == (other as *const T) -} - -fn rust_id(ctx: &GenCtx, name: &str) -> (String, bool) { - let token = parse::token::Ident(ctx.ext_cx.ident_of(name)); - if token.is_any_keyword() || - name.contains("@") || - name.contains("?") || - name.contains("$") || - "bool" == name - { - let mut s = name.to_owned(); - s = s.replace("@", "_"); - s = s.replace("?", "_"); - s = s.replace("$", "_"); - s.push_str("_"); - (s, true) - } else { - (name.to_owned(), false) - } -} - -fn rust_type_id(ctx: &GenCtx, name: &str) -> String { - match name { - "bool" | "uint" | "u8" | "u16" | - "u32" | "f32" | "f64" | "i8" | - "i16" | "i32" | "i64" | "Self" | - "str" => { - let mut s = name.to_owned(); - s.push_str("_"); - s - } - "int8_t" => "i8".to_owned(), - "uint8_t" => "u8".to_owned(), - "int16_t" => "i16".to_owned(), - "uint16_t" => "u16".to_owned(), - "int32_t" => "i32".to_owned(), - "uint32_t" => "u32".to_owned(), - "int64_t" => "i64".to_owned(), - "uint64_t" => "u64".to_owned(), - "uintptr_t" - | "size_t" => "usize".to_owned(), - "intptr_t" - | "ptrdiff_t" - | "ssize_t" => "isize".to_owned(), - _ => first(rust_id(ctx, name)) - } -} - -fn comp_name(ctx: &GenCtx, kind: CompKind, name: &str) -> String { - match kind { - CompKind::Struct => struct_name(ctx, name), - CompKind::Union => union_name(ctx, name), - } -} - -fn struct_name(ctx: &GenCtx, name: &str) -> String { - if ctx.options.rename_types { - format!("Struct_{}", name) - } else { - name.to_owned() - } -} - -fn union_name(ctx: &GenCtx, name: &str) -> String { - if ctx.options.rename_types { - format!("Union_{}", name) - } else { - name.to_owned() - } -} - -fn enum_name(ctx: &GenCtx, name: &str) -> String { - if ctx.options.rename_types { - format!("Enum_{}", name) - } else { - name.to_owned() - } -} - -fn gen_unmangle_method(ctx: &mut GenCtx, - v: &VarInfo, - counts: &mut HashMap, - self_kind: Option) - -> ast::ImplItem { - let mut fndecl; - let mut args = vec![]; - - if let Some(mutability) = self_kind { - let selfexpr = match mutability { - ast::Mutability::Immutable => quote_expr!(&ctx.ext_cx, &*self), - ast::Mutability::Mutable => quote_expr!(&ctx.ext_cx, &mut *self), - }; - args.push(selfexpr); - } - - match v.ty { - TFuncPtr(ref sig) => { - fndecl = cfuncty_to_rs(ctx, - &*sig.ret_ty, sig.args.as_slice(), - false); - let mut unnamed: usize = 0; - let iter = if !args.is_empty() { - sig.args[1..].iter() - } else { - sig.args.iter() - }; - for &(ref n, _) in iter { - let argname = if n.is_empty() { - unnamed += 1; - format!("arg{}", unnamed) - } else { - first(rust_id(ctx, &n)) - }; - let expr = aster::AstBuilder::new().expr().path() - .segment(&argname).build().build(); - args.push(expr); - } - }, - _ => unreachable!() - }; - - - if let Some(mutability) = self_kind { - assert!(!fndecl.inputs.is_empty()); - fndecl.inputs[0] = ast::Arg { - ty: P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ast::TyKind::Rptr(None, ast::MutTy { - ty: P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ast::TyKind::ImplicitSelf, - span: ctx.span - }), - mutbl: mutability, - }), - span: ctx.span, - }), - pat: P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: ast::PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Immutable), - respan(ctx.span, ctx.ext_cx.ident_of("self")), - None), - span: ctx.span, - }), - id: ast::DUMMY_NODE_ID, - }; - } - - let sig = ast::MethodSig { - unsafety: ast::Unsafety::Unsafe, - abi: Abi::Rust, - decl: P(fndecl), - generics: ast::Generics::default(), - constness: ast::Constness::NotConst, - }; - - let mangled_rs = first(rust_id(ctx, &v.mangled)); - let call = P(ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::Call( - P(ast::Expr { - id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::Path(None, ast::Path { - span: ctx.span, - global: false, - segments: vec![ast::PathSegment { - identifier: ctx.ext_cx.ident_of(&mangled_rs), - parameters: ast::PathParameters::none() - }] - }), - span: ctx.span, - attrs: ast::ThinVec::new(), - }), - args - ), - span: ctx.span, - attrs: ast::ThinVec::new(), - }); - - let block = ast::Block { - stmts: vec![ - ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Expr(call), - span: ctx.span, - } - ], - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - span: ctx.span - }; - - let mut name = v.name.clone(); - let mut count = 0; - match counts.get(&v.name) { - Some(x) => { - count = *x; - name.push_str(&x.to_string()); - }, - None => () - } - count += 1; - counts.insert(v.name.clone(), count); - - let mut attrs = mk_doc_attr(ctx, &v.comment); - attrs.push(respan(ctx.span, ast::Attribute_ { - id: mk_attr_id(), - style: ast::AttrStyle::Outer, - value: P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("inline")))), - is_sugared_doc: false - })); - - let name = first(rust_id(ctx, &name)); - - ast::ImplItem { - id: ast::DUMMY_NODE_ID, - ident: ctx.ext_cx.ident_of(&name), - vis: ast::Visibility::Public, - attrs: attrs, - node: ast::ImplItemKind::Method(sig, P(block)), - defaultness: ast::Defaultness::Final, - span: ctx.span - } -} - -pub fn gen_mods(links: &[(String, LinkType)], - map: ModuleMap, - options: BindgenOptions, - span: Span) -> Vec> { - // Create a dummy ExtCtxt. We only need this for string interning and that uses TLS. - let mut features = Features::new(); - features.quote = true; - - let cfg = ExpansionConfig::default("xxx".to_owned()); - let sess = parse::ParseSess::new(); - let mut loader = base::DummyMacroLoader; - let mut ctx = GenCtx { - ext_cx: base::ExtCtxt::new(&sess, vec![], cfg, &mut loader), - options: options, - span: span, - module_map: map, - current_module_id: ROOT_MODULE_ID, - saw_union: false, - }; - - ctx.ext_cx.bt_push(ExpnInfo { - call_site: ctx.span, - callee: NameAndSpan { - format: MacroBang(intern("")), - allow_internal_unstable: false, - span: None - } - }); - - if let Some(root_mod) = gen_mod(&mut ctx, ROOT_MODULE_ID, links, span) { - // Move out of the pointer so we can mutate it - let mut root_mod_item = root_mod.and_then(|item| item); - - gen_union_field_definitions_if_necessary(&mut ctx, &mut root_mod_item); - - if !ctx.options.enable_cxx_namespaces { - match root_mod_item.node { - // XXX This clone might be really expensive, but doing: - ast::ItemKind::Mod(root) => { - return root.items; - } - _ => unreachable!(), - } - } - - let ident = root_mod_item.ident; - let root_export = quote_item!(&ctx.ext_cx, pub use $ident::*;).unwrap(); - - vec![root_export, P(root_mod_item)] - } else { - vec![] - } -} - -fn gen_mod(mut ctx: &mut GenCtx, - module_id: ModuleId, - links: &[(String, LinkType)], - span: Span) -> Option> { - - // XXX avoid this clone - let module = ctx.module_map.get(&module_id).unwrap().clone(); - - // Import just the root to minimise name conflicts - let mut globals = if module_id != ROOT_MODULE_ID { - // XXX Pass this previously instead of looking it up always? - let root_ident = ctx.ext_cx.ident_of(&ctx.module_map.get(&ROOT_MODULE_ID).unwrap().name); - let root_use = quote_item!(&ctx.ext_cx, use $root_ident;).unwrap(); - vec![root_use] - } else { - vec![] - }; - - ctx.current_module_id = module_id; - - globals.extend(gen_globals(&mut ctx, links, &module.globals).into_iter()); - - globals.extend(module.children_ids.iter().filter_map(|id| { - gen_mod(ctx, *id, links, span.clone()) - })); - - if !globals.is_empty() { - Some(P(ast::Item { - ident: ctx.ext_cx.ident_of(&module.name), - attrs: vec![], - id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::Mod(ast::Mod { - inner: span, - items: globals, - }), - vis: ast::Visibility::Public, - span: span.clone(), - })) - } else { - None - } -} - -fn gen_global(mut ctx: &mut GenCtx, - g: Global, - defs: &mut Vec>) { - match g { - GType(ti) => { - let t = ti.borrow().clone(); - defs.extend(ctypedef_to_rs(&mut ctx, t).into_iter()) - }, - GCompDecl(ci) => { - let mut c = ci.borrow().clone(); - let name = comp_name(&ctx, c.kind, &c.name); - // Use the reference template if any - while let Some(TComp(ref_template)) = c.ref_template.clone() { - if c.name != ref_template.borrow().name { - break; - } - c = ref_template.borrow().clone(); - } - if !c.args.is_empty() && - !c.args.iter().any(|a| a.name().map(|name| name.is_empty()).unwrap_or(true)) { - defs.extend(comp_to_rs(&mut ctx, &name, c).into_iter()); - } else { - defs.push(opaque_to_rs(&mut ctx, &name, c.layout())); - } - }, - GComp(ci) => { - let c = ci.borrow().clone(); - let name = comp_name(&ctx, c.kind, &c.name); - defs.extend(comp_to_rs(&mut ctx, &name, c).into_iter()) - }, - GEnumDecl(ei) => { - let e = ei.borrow().clone(); - let name = enum_name(&ctx, &e.name); - let dummy = EnumItem::new("_BindgenOpaqueEnum".to_owned(), "".to_owned(), 0); - - defs.extend(cenum_to_rs(&mut ctx, &name, e.kind, e.comment, &[dummy], e.layout).into_iter()) - }, - GEnum(ei) => { - let e = ei.borrow().clone(); - let name = enum_name(&ctx, &e.name); - defs.extend(cenum_to_rs(&mut ctx, &name, e.kind, e.comment, &e.items, e.layout).into_iter()) - }, - GVar(vi) => { - let v = vi.borrow(); - let ty = cty_to_rs(&mut ctx, &v.ty, v.is_const, true); - defs.push(const_to_rs(&mut ctx, &v.name, v.val.unwrap(), ty)); - }, - _ => { } - } -} - -fn gen_globals(mut ctx: &mut GenCtx, - links: &[(String, LinkType)], - globs: &[Global]) -> Vec> { - let uniq_globs = tag_dup_decl(globs); - - let mut fs = vec![]; - let mut vs = vec![]; - let mut gs = vec![]; - for g in uniq_globs.into_iter() { - match g { - GOther => {} - GFunc(_) => fs.push(g), - GVar(_) => { - let is_int_const = { - match g { - GVar(ref vi) => { - let v = vi.borrow(); - v.is_const && v.val.is_some() - } - _ => unreachable!() - } - }; - if is_int_const { - gs.push(g); - } else { - vs.push(g); - } - } - _ => gs.push(g) - } - } - - let mut defs = vec![]; - gs = remove_redundant_decl(gs); - - for mut g in gs.into_iter() { - if let Some(substituted) = ctx.current_module_mut().translations.remove(&g.name()) { - match (substituted.layout(), g.layout()) { - (Some(l), Some(lg)) if l.size == lg.size => {}, - (None, None) => {}, - _ => { - warn!("warning: substituted type for {} does not match its size", g.name()); - } - } - g = substituted; - } - - gen_global(ctx, g, &mut defs); - } - - let mut pending_translations = std::mem::replace(&mut ctx.current_module_mut().translations, HashMap::new()); - for (name, g) in pending_translations.drain() { - warn!("warning: generating definition for not found type: {}", name); - gen_global(ctx, g, &mut defs); - } - - let vars: Vec<_> = vs.into_iter().map(|v| { - match v { - GVar(vi) => { - let v = vi.borrow(); - cvar_to_rs(&mut ctx, v.name.clone(), v.mangled.clone(), &v.ty, v.is_const) - }, - _ => unreachable!() - } - }).collect(); - - let mut unmangle_count: HashMap = HashMap::new(); - let funcs = { - let func_list = fs.into_iter().map(|f| { - match f { - GFunc(vi) => { - let v = vi.borrow(); - match v.ty { - TFuncPtr(ref sig) => { - let mut name = v.name.clone(); - let mut count = 0; - match unmangle_count.get(&v.name) { - Some(x) => { - count = *x; - name.push_str(&x.to_string()); - }, - None => () - } - count += 1; - unmangle_count.insert(v.name.clone(), count); - - let decl = cfunc_to_rs(&mut ctx, name, v.mangled.clone(), v.comment.clone(), - &*sig.ret_ty, &sig.args[..], - sig.is_variadic, ast::Visibility::Public); - (sig.abi, decl) - } - _ => unreachable!() - } - }, - _ => unreachable!() - } - }); - - let mut map: HashMap> = HashMap::new(); - for (abi, func) in func_list { - map.entry(abi).or_insert(vec![]).push(func); - } - map - }; - - if !vars.is_empty() { - defs.push(mk_extern(&mut ctx, links, vars, Abi::C)); - } - - for (abi, funcs) in funcs.into_iter() { - defs.push(mk_extern(&mut ctx, &links, funcs, abi)); - } - - //let attrs = vec!(mk_attr_list(&mut ctx, "allow", ["dead_code", "non_camel_case_types", "uppercase_variables"])); - - defs -} - -fn mk_extern(ctx: &GenCtx, links: &[(String, LinkType)], - foreign_items: Vec, - abi: Abi) -> P { - let attrs: Vec<_> = links.iter().map(|&(ref l, ref k)| { - let k = match *k { - LinkType::Default => None, - LinkType::Static => Some("static"), - LinkType::Framework => Some("framework") - }; - let link_name = P(respan(ctx.span, ast::MetaItemKind::NameValue( - InternedString::new("name"), - respan(ctx.span, ast::LitKind::Str(intern(l).as_str(), ast::StrStyle::Cooked)) - ))); - let link_args = match k { - None => vec!(link_name), - Some(ref k) => vec!(link_name, P(respan(ctx.span, ast::MetaItemKind::NameValue( - InternedString::new("kind"), - respan(ctx.span, ast::LitKind::Str(intern(k).as_str(), ast::StrStyle::Cooked)) - )))) - }; - respan(ctx.span, ast::Attribute_ { - id: mk_attr_id(), - style: ast::AttrStyle::Outer, - value: P(respan(ctx.span, ast::MetaItemKind::List( - InternedString::new("link"), - link_args) - )), - is_sugared_doc: false - }) - }).collect(); - - let mut items = vec![]; - items.extend(foreign_items.into_iter()); - let ext = ast::ItemKind::ForeignMod(ast::ForeignMod { - abi: abi, - items: items - }); - - P(ast::Item { - ident: ctx.ext_cx.ident_of(""), - attrs: attrs, - id: ast::DUMMY_NODE_ID, - node: ext, - vis: ast::Visibility::Inherited, - span: ctx.span - }) -} - -fn mk_impl(_ctx: &GenCtx, ty: P, - items: Vec) - -> P { - aster::AstBuilder::new().item().impl_().with_items(items).build_ty(ty) -} - -fn remove_redundant_decl(gs: Vec) -> Vec { - fn check_decl(a: &Global, ty: &Type) -> bool { - match *a { - GComp(ref ci1) => match *ty { - TComp(ref ci2) => { - ref_eq(ci1, ci2) && ci1.borrow().name.is_empty() - }, - _ => false - }, - GEnum(ref ei1) => match *ty { - TEnum(ref ei2) => { - ref_eq(ei1, ei2) && ei1.borrow().name.is_empty() - }, - _ => false - }, - _ => false - } - } - - let typedefs: Vec = gs.iter().filter_map(|g| - match *g { - GType(ref ti) => Some(ti.borrow().ty.clone()), - _ => None - } - ).collect(); - - gs.into_iter().filter(|g| - !typedefs.iter().any(|t| check_decl(g, t)) - ).collect() -} - -fn tag_dup_decl(gs: &[Global]) -> Vec { - fn check(name1: &str, name2: &str) -> bool { - !name1.is_empty() && name1 == name2 - } - - fn check_dup(g1: &Global, g2: &Global) -> bool { - match (g1, g2) { - (>ype(ref ti1), >ype(ref ti2)) => { - let a = ti1.borrow(); - let b = ti2.borrow(); - check(&a.name, &b.name) - }, - (&GComp(ref ci1), &GComp(ref ci2)) => { - let a = ci1.borrow(); - let b = ci2.borrow(); - check(&a.name, &b.name) - }, - (&GCompDecl(ref ci1), &GCompDecl(ref ci2)) => { - let a = ci1.borrow(); - let b = ci2.borrow(); - check(&a.name, &b.name) - }, - (&GEnum(ref ei1), &GEnum(ref ei2)) => { - let a = ei1.borrow(); - let b = ei2.borrow(); - check(&a.name, &b.name) - }, - (&GEnumDecl(ref ei1), &GEnumDecl(ref ei2)) => { - let a = ei1.borrow(); - let b = ei2.borrow(); - check(&a.name, &b.name) - }, - (&GVar(ref vi1), &GVar(ref vi2)) => { - let a = vi1.borrow(); - let b = vi2.borrow(); - check(&a.name, &b.name) && - check(&a.mangled, &b.mangled) - }, - (&GFunc(ref vi1), &GFunc(ref vi2)) => { - let a = vi1.borrow(); - let b = vi2.borrow(); - check(&a.name, &b.name) && - check(&a.mangled, &b.mangled) - }, - _ => false - } - } - - fn check_opaque_dup(g1: &Global, g2: &Global) -> bool { - match (g1, g2) { - (&GCompDecl(ref ci1), &GComp(ref ci2)) => { - let a = ci1.borrow(); - let b = ci2.borrow(); - check(&a.name, &b.name) - }, - (&GEnumDecl(ref ei1), &GEnum(ref ei2)) => { - let a = ei1.borrow(); - let b = ei2.borrow(); - check(&a.name, &b.name) - }, - _ => false, - } - } - - if gs.is_empty() { - return vec![]; - } - - let mut step: Vec = vec![]; - step.push(gs[0].clone()); - - for (i, _gsi) in gs.iter().enumerate().skip(1) { - let mut dup = false; - for j in 0..i { - if i == j { - continue; - } - if check_dup(&gs[i], &gs[j]) { - dup = true; - break; - } - } - if !dup { - step.push(gs[i].clone()); - } - } - - let len = step.len(); - let mut res: Vec = vec![]; - for i in 0..len { - let mut dup = false; - match &step[i] { - &GCompDecl(_) | &GEnumDecl(_) => { - for j in 0..len { - if i == j { - continue; - } - if check_opaque_dup(&step[i], &step[j]) { - dup = true; - break; - } - } - }, - _ => (), - } - - if !dup { - res.push(step[i].clone()); - } - } - - res -} - -fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> Vec> { - fn mk_item(ctx: &GenCtx, name: &str, comment: &str, ty: &Type) -> P { - let rust_name = rust_type_id(ctx, name); - let rust_ty = if cty_is_translatable(ty) { - cty_to_rs(ctx, ty, true, true) - } else { - cty_to_rs(ctx, &TVoid, true, true) - }; - aster::AstBuilder::new().item().pub_() - .with_attrs(mk_doc_attr(ctx, comment)) - .type_(&rust_name).build_ty(P(rust_ty)) - } - - if ty.hide { - return vec![]; - } - - if ty.opaque { - return mk_opaque_struct(ctx, &ty.name, &ty.layout); - } - - let item = match ty.ty { - TComp(ref ci) => { - assert!(!ci.borrow().name.is_empty()); - mk_item(ctx, &ty.name, &ty.comment, &ty.ty) - }, - TEnum(ref ei) => { - assert!(!ei.borrow().name.is_empty()); - mk_item(ctx, &ty.name, &ty.comment, &ty.ty) - }, - _ => mk_item(ctx, &ty.name, &ty.comment, &ty.ty), - }; - - vec![item] -} - -fn comp_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) - -> Vec> { - if ci.hide { - return vec![]; - } - - if ci.opaque { - let name = first(rust_id(ctx, &ci.name)); - return mk_opaque_struct(ctx, &name, &ci.layout()); - } - - if ci.has_non_type_template_params || - ci.args.iter().any(|f| f == &TVoid) { - return vec![]; - } - - let mut template_args_used = vec![false; ci.args.len()]; - - match ci.kind { - CompKind::Struct => cstruct_to_rs(ctx, name, ci, &mut template_args_used), - CompKind::Union => cunion_to_rs(ctx, name, ci, &mut template_args_used), - } -} - -fn comp_attrs(ctx: &GenCtx, ci: &CompInfo, name: &str, extra: &mut Vec>) -> Vec { - let mut attrs = mk_doc_attr(ctx, &ci.comment); - attrs.push(mk_repr_attr(ctx, &ci.layout())); - let mut derives = vec![]; - - if ci.can_derive_debug() && ctx.options.derive_debug { - derives.push("Debug"); - } - - if ci.has_destructor() { - for attr in ctx.options.dtor_attrs.iter() { - let attr = ctx.ext_cx.ident_of(attr); - attrs.push(quote_attr!(&ctx.ext_cx, #[$attr])); - } - } - - if ci.can_derive_copy() { - derives.push("Copy"); - - // TODO: make mk_clone_impl work for template arguments, - // meanwhile just fallback to deriving. - if ci.args.is_empty() { - extra.push(mk_clone_impl(ctx, name)); - } else { - derives.push("Clone"); - } - } - - if !derives.is_empty() { - attrs.push(mk_deriving_attr(ctx, &derives)); - } - - attrs -} - -fn gen_accessors(ctx: &mut GenCtx, name: &str, ty: &ast::Ty, accessor: Accessor, - methods: &mut Vec) { - if accessor == Accessor::None { - return; - } - let ident = ctx.ext_cx.ident_of(&format!("{}", name)); - let mutable_getter_name = ctx.ext_cx.ident_of(&format!("get_{}_mut", name)); - let getter_name = ctx.ext_cx.ident_of(&format!("get_{}", name)); - let imp = match accessor { - Accessor::Regular => quote_item!(&ctx.ext_cx, - impl X { - #[inline] - pub fn $getter_name(&self) -> & $ty { - & self.$ident - } - pub fn $mutable_getter_name(&mut self) -> &mut $ty { - &mut self.$ident - } - } - ), - Accessor::Unsafe => quote_item!(&ctx.ext_cx, - impl X { - #[inline] - pub unsafe fn $getter_name(&self) -> & $ty { - & self.$ident - } - pub unsafe fn $mutable_getter_name(&mut self) -> &mut $ty { - &mut self.$ident - } - } - ), - Accessor::Immutable => quote_item!(&ctx.ext_cx, - impl X { - #[inline] - pub fn $getter_name(&self) -> & $ty { - & self.$ident - } - } - ), - _ => return - }; - match imp.unwrap().node { - ast::ItemKind::Impl(_, _, _, _, _, ref items) => methods.extend(items.clone()), - _ => unreachable!() - } -} - -fn add_extra_template_fields_if_needed(ctx: &GenCtx, - template_args: &[Type], - template_args_used: &[bool], - fields: &mut Vec) { - let mut phantom_count = 0; - for (i, arg) in template_args.iter().enumerate() { - if template_args_used[i] { - continue; - } - - let f_name = format!("_phantom{}", phantom_count); - phantom_count += 1; - let inner_type = P(cty_to_rs(ctx, &arg, true, false)); - - fields.push(ast::StructField { - span: ctx.span, - ident: Some(ctx.ext_cx.ident_of(&f_name)), - vis: ast::Visibility::Public, - id: ast::DUMMY_NODE_ID, - ty: quote_ty!(&ctx.ext_cx, ::std::marker::PhantomData<$inner_type>), - attrs: vec![], - }); - } -} - -fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo, - template_args_used: &mut [bool]) -> Vec> { - let layout = ci.layout(); - let members = &ci.members; - let template_args = &ci.args; - let methodlist = &ci.methods; - let mut fields = vec![]; - let mut methods = vec![]; - // Nested composites may need to emit declarations and implementations as - // they are encountered. The declarations end up in 'extra' and are emitted - // after the current struct. - let mut extra = vec![]; - let mut unnamed: u32 = 0; - let mut bitfields: u32 = 0; - - let id = rust_type_id(ctx, name); - let id_ty = P(mk_ty(ctx, false, &[id.clone()])); - - if ci.has_vtable { - let mut vffields = vec![]; - let base_vftable = match members.get(0) { - Some(&CompMember::Field(FieldInfo { ty: TComp(ref ci2), .. })) => { - let ci2 = ci2.borrow(); - if ci2.has_vtable { - Some(format!("_vftable_{}", ci2.name)) - } else { - None - } - }, - _ => None, - }; - - if let Some(ref base) = base_vftable { - let field = ast::StructField { - span: ctx.span, - vis: ast::Visibility::Public, - ident: Some(ctx.ext_cx.ident_of("_base")), - id: ast::DUMMY_NODE_ID, - ty: P(mk_ty(ctx, false, &[base.clone()])), - attrs: vec![], - }; - vffields.push(field); - } - - let mut counts: HashMap = HashMap::new(); - for vm in ci.vmethods.iter() { - let ty = match vm.ty { - TFuncPtr(ref sig) => { - let decl = cfuncty_to_rs(ctx, &*sig.ret_ty, sig.args.as_slice(), sig.is_variadic); - mk_fn_proto_ty(ctx, &decl, sig.abi) - }, - _ => unreachable!() - }; - - let mut name = vm.name.clone(); - let mut count = 0; - match counts.get(&vm.name) { - Some(x) => { - count = *x; - name.push_str(&x.to_string()); - }, - None => () - } - count += 1; - counts.insert(vm.name.clone(), count); - - let name = first(rust_id(ctx, &name)); - - vffields.push(ast::StructField { - span: ctx.span, - vis: ast::Visibility::Public, - ident: Some(ctx.ext_cx.ident_of(&name)), - id: ast::DUMMY_NODE_ID, - ty: P(ty), - attrs: vec![], - }); - } - - // FIXME: rustc actually generates tons of warnings - // due to an empty repr(C) type, so we just generate - // a dummy field with pointer-alignment to supress it. - if vffields.is_empty() { - vffields.push(mk_blob_field(ctx, "_bindgen_empty_ctype_warning_fix", - &Layout::new(::std::mem::size_of::<*mut ()>(), ::std::mem::align_of::<*mut ()>()))); - } - - let vf_name = format!("_vftable_{}", name); - let item = aster::AstBuilder::new().item() - .with_attr(mk_repr_attr(ctx, &layout)) - .pub_() - .struct_(&vf_name) - .with_fields(vffields).build(); - - extra.push(item); - - if base_vftable.is_none() { - let vf_type = mk_ty(ctx, false, &[vf_name]); - fields.push(ast::StructField { - span: ctx.span, - ident: Some(ctx.ext_cx.ident_of("_vftable")), - vis: ast::Visibility::Public, - id: ast::DUMMY_NODE_ID, - ty: P(mk_ptrty(ctx, &vf_type, true)), - attrs: vec![] - }); - } - } - - let mut anon_enum_count = 0; - let mut setters = vec![]; - - for m in members.iter() { - match *m { - CompMember::Enum(ref ei) => { - let empty_name = ei.borrow().name.is_empty(); - if empty_name { - ei.borrow_mut().name = format!("{}_enum{}", name, anon_enum_count); - anon_enum_count += 1; - } - - let e = ei.borrow().clone(); - extra.extend(cenum_to_rs(ctx, &e.name, e.kind, e.comment, &e.items, e.layout).into_iter()); - } - CompMember::Field(ref f) => { - let f_name = match f.bitfields { - Some(_) => { - bitfields += 1; - format!("_bitfield_{}", bitfields) - } - None => rust_type_id(ctx, &f.name) - }; - - let is_translatable = cty_is_translatable(&f.ty); - if !is_translatable || f.ty.is_opaque() { - if !is_translatable { - warn!("{}::{} not translatable, void: {}", ci.name, f.name, f.ty == TVoid); - } - if let Some(layout) = f.ty.layout() { - fields.push(mk_blob_field(ctx, &f_name, &layout)); - } - continue; - } - - if ctx.options.gen_bitfield_methods { - let mut offset: u32 = 0; - if let Some(ref bitfields) = f.bitfields { - for &(ref bf_name, bf_size) in bitfields.iter() { - setters.extend(gen_bitfield_methods(ctx, &f_name, bf_name, &f.ty, offset as usize, bf_size).into_iter()); - offset += bf_size; - } - setters.push(gen_fullbitfield_method(ctx, &f_name, &f.ty, bitfields)) - } - } - - // If the member is not a template argument, it needs the full path. - let mut needs_full_path = true; - for (index, arg) in template_args.iter().enumerate() { - let used = f.ty.signature_contains_type(arg); - - if used { - template_args_used[index] = true; - needs_full_path = *arg == f.ty || match f.ty { - TPtr(ref t, _, _, _) => **t != *arg, - TArray(ref t, _, _) => **t != *arg, - _ => true, - }; - break; - } - } - - let rust_ty = P(cty_to_rs(ctx, &f.ty, f.bitfields.is_none(), needs_full_path)); - - // Wrap mutable fields in a Cell/UnsafeCell - let rust_ty = if f.mutable { - if !f.ty.can_derive_copy() { - quote_ty!(&ctx.ext_cx, ::std::cell::UnsafeCell<$rust_ty>) - // We can only wrap in a cell for non-copiable types, since - // Cell: Clone, but not Copy. - // - // It's fine though, since mutating copiable types is trivial - // and doesn't make a lot of sense marking fields as `mutable`. - } else if !ci.can_derive_copy() { - quote_ty!(&ctx.ext_cx, ::std::cell::Cell<$rust_ty>) - } else { - rust_ty - } - } else { - rust_ty - }; - let vis = if f.private { - ast::Visibility::Inherited - } else { - ast::Visibility::Public - }; - gen_accessors(ctx, &f_name, &rust_ty, f.accessor, &mut methods); - let field = ast::StructField { - span: ctx.span, - ident: Some(ctx.ext_cx.ident_of(&f_name)), - vis: vis, - id: ast::DUMMY_NODE_ID, - ty: rust_ty, - attrs: mk_doc_attr(ctx, &f.comment) - }; - fields.push(field); - } - CompMember::Comp(ref rc_c) => { - let name_is_empty = rc_c.borrow().name.is_empty(); - - if name_is_empty { - let c = rc_c.borrow(); - unnamed += 1; - let field_name = format!("_bindgen_data_{}_", unnamed); - fields.push(mk_blob_field(ctx, &field_name, &c.layout())); - methods.extend(gen_comp_methods(ctx, &field_name, 0, c.kind, &c.members, &mut extra).into_iter()); - } else { - let name = comp_name(&ctx, rc_c.borrow().kind, &rc_c.borrow().name); - extra.extend(comp_to_rs(ctx, &name, rc_c.borrow().clone()).into_iter()); - } - } - } - } - - add_extra_template_fields_if_needed(ctx, template_args, - template_args_used, - &mut fields); - - if !setters.is_empty() { - extra.push(mk_impl(ctx, id_ty.clone(), setters)); - } - - let field_count = fields.len(); - let variant_data = if fields.is_empty() { - ast::VariantData::Unit(ast::DUMMY_NODE_ID) - } else { - ast::VariantData::Struct(fields, ast::DUMMY_NODE_ID) - }; - - let ty_params = mk_ty_params(ctx, &template_args); - - let def = ast::ItemKind::Struct( - variant_data, - ast::Generics { - lifetimes: vec![], - ty_params: P::from_vec(ty_params), - where_clause: ast::WhereClause { - id: ast::DUMMY_NODE_ID, - predicates: vec![] - } - } - ); - - let attrs = comp_attrs(&ctx, &ci, name, &mut extra); - - let struct_def = ast::Item { - ident: ctx.ext_cx.ident_of(&id), - attrs: attrs, - id: ast::DUMMY_NODE_ID, - node: def, - vis: ast::Visibility::Public, - span: ctx.span - }; - - let mut items = vec![P(struct_def)]; - if !methods.is_empty() { - items.push(mk_impl(ctx, id_ty.clone(), methods)); - } - - // Template args have incomplete type in general - // - // XXX if x is a class without members, C++ still will report - // sizeof(x) == 1, since it requires to be adressable. - // - // We maybe should add a dummy byte if it's the case, but... - // That could play wrong with inheritance. - // - // So for now don't generate a test if the struct/class is empty - // or has only empty bases. - if ci.args.is_empty() && field_count > 0 && - (ci.has_nonempty_base || ci.base_members < field_count) { - extra.push(mk_test_fn(ctx, name, &layout)); - } - - items.extend(extra.into_iter()); - - let mut mangledlist = vec![]; - let mut unmangledlist = vec![]; - let mut unmangle_count: HashMap = HashMap::new(); - for v in methodlist { - let v = v.clone(); - match v.ty { - TFuncPtr(ref sig) => { - let name = v.mangled.clone(); - let explicit_self = if v.is_static { - None - } else if v.is_const { - Some(ast::Mutability::Immutable) - } else { - Some(ast::Mutability::Mutable) - }; - unmangledlist.push(gen_unmangle_method(ctx, &v, &mut unmangle_count, explicit_self)); - mangledlist.push(cfunc_to_rs(ctx, name, String::new(), String::new(), - &*sig.ret_ty, sig.args.as_slice(), - sig.is_variadic, ast::Visibility::Inherited)); - } - _ => unreachable!() - } - } - if !mangledlist.is_empty() { - items.push(mk_extern(ctx, &[], mangledlist, Abi::C)); - items.push(mk_impl(ctx, id_ty, unmangledlist)); - } - - if !ci.vars.is_empty() && template_args.is_empty() { - let vars = ci.vars.into_iter().map(|v| { - let vi = v.varinfo(); - let v = vi.borrow_mut(); - let mut var_name = v.name.clone(); - if !v.mangled.is_empty() { - var_name = format!("{}_consts_{}", name, v.name); - } - cvar_to_rs(ctx, var_name, v.mangled.clone(), &v.ty, v.is_const) - }).collect(); - - items.push(mk_extern(ctx, &[], vars, Abi::C)); - } - items -} - -fn opaque_to_rs(ctx: &mut GenCtx, name: &str, _layout: Layout) -> P { - // XXX can't repr(C) an empty enum - let id = rust_type_id(ctx, name); - let ident = ctx.ext_cx.ident_of(&id); - quote_item!(&ctx.ext_cx, pub enum $ident {}).unwrap() -} - -fn cunion_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo, - template_args_used: &mut [bool]) -> Vec> { - const UNION_DATA_FIELD_NAME: &'static str = "_bindgen_data_"; - - ctx.saw_union = true; - - let members = &ci.members; - let layout = ci.layout(); - - fn mk_item(ctx: &GenCtx, name: &str, item: ast::ItemKind, vis: - ast::Visibility, attrs: Vec) -> P { - P(ast::Item { - ident: ctx.ext_cx.ident_of(name), - attrs: attrs, - id: ast::DUMMY_NODE_ID, - node: item, - vis: vis, - span: ctx.span - }) - } - - let tmp_ci = Rc::new(RefCell::new(ci.clone())); - let union = TComp(tmp_ci); - - - // Nested composites may need to emit declarations and implementations as - // they are encountered. The declarations end up in 'extra' and are emitted - // after the current union. - let mut extra = vec![]; - - fn mk_union_field(ctx: &GenCtx, name: &str, ty: ast::Ty) -> ast::StructField { - let field_ty = if !ctx.options.enable_cxx_namespaces || - ctx.current_module_id == ROOT_MODULE_ID { - quote_ty!(&ctx.ext_cx, __BindgenUnionField<$ty>) - } else { - quote_ty!(&ctx.ext_cx, root::__BindgenUnionField<$ty>) - }; - - ast::StructField { - span: ctx.span, - ident: Some(ctx.ext_cx.ident_of(name)), - vis: ast::Visibility::Public, - id: ast::DUMMY_NODE_ID, - ty: field_ty, - attrs: vec![], - } - } - - let mut fields = - members.iter().flat_map(|member| { - if let CompMember::Field(ref f) = *member { - let mut needs_full_path = true; - for (index, arg) in ci.args.iter().enumerate() { - let used = f.ty.signature_contains_type(arg); - - if used { - template_args_used[index] = true; - needs_full_path = *arg == f.ty || match f.ty { - TPtr(ref t, _, _, _) => **t != *arg, - TArray(ref t, _, _) => **t != *arg, - _ => true, - }; - break; - } - } - - let cty = cty_to_rs(ctx, &f.ty, false, needs_full_path); - Some(mk_union_field(ctx, &f.name, cty)) - } else { - None - } - }).collect::>(); - - fields.push(mk_blob_field(ctx, UNION_DATA_FIELD_NAME, &layout)); - - add_extra_template_fields_if_needed(ctx, &ci.args, - template_args_used, - &mut fields); - - let ty_params = mk_ty_params(ctx, &ci.args); - - let generics = ast::Generics { - lifetimes: vec![], - ty_params: P::from_vec(ty_params), - where_clause: ast::WhereClause { - id: ast::DUMMY_NODE_ID, - predicates: vec![] - } - }; - - // TODO: use aster here. - let def = ast::ItemKind::Struct( - ast::VariantData::Struct(fields, ast::DUMMY_NODE_ID), - generics.clone() - ); - - let union_id = rust_type_id(ctx, name); - - let union_attrs = comp_attrs(&ctx, &ci, name, &mut extra); - - if ci.args.is_empty() { - extra.push(mk_test_fn(ctx, &name, &layout)); - } - - let union_def = mk_item(ctx, &union_id, def, ast::Visibility::Public, union_attrs); - let union_impl = ast::ItemKind::Impl( - ast::Unsafety::Normal, - ast::ImplPolarity::Positive, - generics, - None, - P(cty_to_rs(ctx, &union, true, true)), - gen_comp_methods(ctx, UNION_DATA_FIELD_NAME, 0, CompKind::Union, &members, &mut extra), - ); - let mut items = vec!( - union_def, - mk_item(ctx, "", union_impl, ast::Visibility::Inherited, vec![]) - ); - - items.extend(extra.into_iter()); - items -} - -fn const_to_rs(ctx: &mut GenCtx, name: &str, val: i64, val_ty: ast::Ty) -> P { - let id = first(rust_id(ctx, name)); - aster::AstBuilder::new().item().pub_().const_(&id) - .expr().int(val) - .ty().build(P(val_ty)) -} - -fn enum_size_to_unsigned_max_value(size: usize) -> u64 { - match size { - 1 => std::u8::MAX as u64, - 2 => std::u16::MAX as u64, - 4 => std::u32::MAX as u64, - 8 => std::u64::MAX, - _ => unreachable!("invalid enum size: {}", size) - } -} - -fn enum_size_to_rust_type_name(signed: bool, size: usize) -> &'static str { - match (signed, size) { - (true, 1) => "i8", - (false, 1) => "u8", - (true, 2) => "i16", - (false, 2) => "u16", - (true, 4) => "i32", - (false, 4) => "u32", - (true, 8) => "i64", - (false, 8) => "u64", - _ => { - warn!("invalid enum decl: signed: {}, size: {}", signed, size); - "i32" - } - } -} - -fn cenum_value_to_int_lit(ctx: &mut GenCtx, - enum_is_signed: bool, - size: usize, - value: i64) -> P { - if enum_is_signed { - if value == std::i64::MIN { - let lit = ast::LitKind::Int(std::u64::MAX, ast::LitIntType::Unsuffixed); - ctx.ext_cx.expr_lit(ctx.span, lit) - } else { - let lit = ast::LitKind::Int(value.abs() as u64, ast::LitIntType::Unsuffixed); - let expr = ctx.ext_cx.expr_lit(ctx.span, lit); - if value < 0 { - ctx.ext_cx.expr(ctx.span, ast::ExprKind::Unary(ast::UnOp::Neg, expr)) - } else { - expr - } - } - } else { - let u64_value = value as u64 & enum_size_to_unsigned_max_value(size); - let int_lit = ast::LitKind::Int(u64_value, ast::LitIntType::Unsuffixed); - ctx.ext_cx.expr_lit(ctx.span, int_lit) - } -} - -fn cenum_to_rs(ctx: &mut GenCtx, - name: &str, - kind: IKind, - comment: String, - enum_items: &[EnumItem], - layout: Layout) -> Vec> { - let enum_name = ctx.ext_cx.ident_of(name); - let enum_ty = ctx.ext_cx.ty_ident(ctx.span, enum_name); - let enum_is_signed = kind.is_signed(); - let enum_repr = enum_size_to_rust_type_name(enum_is_signed, layout.size); - - let mut items = vec![]; - - if !ctx.options.rust_enums { - items.push(ctx.ext_cx.item_ty(ctx.span, - enum_name, - ctx.ext_cx.ty_ident(ctx.span, - ctx.ext_cx.ident_of(enum_repr)))); - for item in enum_items { - let value = cenum_value_to_int_lit(ctx, enum_is_signed, layout.size, item.val); - let name = first(rust_id(ctx, &item.name)); - items.push(ctx.ext_cx.item_const(ctx.span, ctx.ext_cx.ident_of(&name), enum_ty.clone(), value)); - } - return items; - } - - let mut variants = vec![]; - let mut found_values = HashMap::new(); - for item in enum_items { - let name = first(rust_id(ctx, &item.name)); - let name = ctx.ext_cx.ident_of(&name); - if let Some(orig) = found_values.get(&item.val) { - let value = ctx.ext_cx.expr_path( - ctx.ext_cx.path(ctx.span, vec![enum_name, *orig])); - items.push(P(ast::Item { - ident: name, - attrs: vec![], - id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::Const(enum_ty.clone(), value), - vis: ast::Visibility::Public, - span: ctx.span, - })); - continue; - } - - found_values.insert(item.val, name); - let value = cenum_value_to_int_lit( - ctx, enum_is_signed, layout.size, item.val); - - variants.push(respan(ctx.span, ast::Variant_ { - name: name, - attrs: vec![], - data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), - disr_expr: Some(value), - })); - } - - let enum_repr = InternedString::new(enum_repr); - - let repr_arg = ctx.ext_cx.meta_word(ctx.span, enum_repr); - let repr_list = ctx.ext_cx.meta_list(ctx.span, InternedString::new("repr"), vec![repr_arg]); - - let mut attrs = mk_doc_attr(ctx, &comment); - attrs.push(respan(ctx.span, ast::Attribute_ { - id: mk_attr_id(), - style: ast::AttrStyle::Outer, - value: repr_list, - is_sugared_doc: false, - })); - - attrs.push(if ctx.options.derive_debug { - mk_deriving_attr(ctx, &["Debug", "Copy", "Clone", "Eq", "PartialEq", "Hash"]) - } else { - mk_deriving_attr(ctx, &["Copy", "Clone", "Eq", "PartialEq", "Hash"]) - }); - - items.push(P(ast::Item { - ident: enum_name, - attrs: attrs, - id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::Enum(ast::EnumDef { variants: variants }, ast::Generics::default()), - vis: ast::Visibility::Public, - span: ctx.span, - })); - - items -} - -/// Generates accessors for fields in nested structs and unions which must be -/// represented in Rust as an untyped array. This process may generate -/// declarations and implementations that must be placed at the root level. -/// These are emitted into `extra`. -fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize, - kind: CompKind, members: &[CompMember], - extra: &mut Vec>) -> Vec { - let mk_field_method = |ctx: &mut GenCtx, f: &FieldInfo, offset: usize| { - // TODO: Implement bitfield accessors - if f.bitfields.is_some() { return None; } - - let f_name = first(rust_id(ctx, &f.name)); - let ret_ty = P(cty_to_rs(ctx, &TPtr(Box::new(f.ty.clone()), false, false, Layout::zero()), true, true)); - - // When the offset is zero, generate slightly prettier code. - let method = { - let impl_str = format!(r" - impl X {{ - pub unsafe fn {}(&mut self) -> {} {{ - let raw: *mut u8 = ::std::mem::transmute(&self.{}); - ::std::mem::transmute(raw.offset({})) - }} - }} - ", f_name, tts_to_string(&ret_ty.to_tokens(&ctx.ext_cx)[..]), data_field, offset); - - parse::new_parser_from_source_str(ctx.ext_cx.parse_sess(), - ctx.ext_cx.cfg(), "".to_string(), impl_str).parse_item().unwrap().unwrap() - }; - - method.and_then(|i| { - match i.node { - ast::ItemKind::Impl(_, _, _, _, _, mut items) => { - items.pop() - } - _ => unreachable!("impl parsed to something other than impl") - } - }) - }; - - let mut offset = data_offset; - let mut methods = vec![]; - for m in members.into_iter() { - let advance_by = match *m { - CompMember::Field(ref f) => { - if ctx.options.gen_bitfield_methods { - methods.extend(mk_field_method(ctx, f, offset).into_iter()); - } - f.ty.size() - } - CompMember::Comp(ref rc_c) => { - let c = rc_c.borrow(); - let name = comp_name(&ctx, c.kind, &c.name); - extra.extend(comp_to_rs(ctx, &name, c.clone()).into_iter()); - c.layout().size - } - CompMember::Enum(_) => 0 - }; - match kind { - CompKind::Struct => { offset += advance_by; } - CompKind::Union => { } - } - } - methods -} - -fn type_for_bitfield_width(ctx: &mut GenCtx, width: u32, is_arg: bool) -> ast::Ty { - let input_type = if width > 16 { - "u32" - } else if width > 8 { - "u16" - } else if width > 1 { - "u8" - } else { - if is_arg { - "bool" - } else { - "u8" - } - }; - mk_ty(ctx, false, &[input_type.to_owned()]) -} - -fn gen_bitfield_methods(ctx: &mut GenCtx, bindgen_name: &str, - field_name: &str, field_type: &Type, - offset: usize, width: u32) -> Vec { - let input_type = type_for_bitfield_width(ctx, width, true); - let width = width as usize; - - let field_type = cty_to_rs(ctx, field_type, false, true); - - let real_field_name = if field_name.is_empty() { - format!("at_offset_{}", offset) - } else { - field_name.into() - }; - - - let bindgen_ident = ctx.ext_cx.ident_of(bindgen_name); - let setter_name = ctx.ext_cx.ident_of(&format!("set_{}", real_field_name)); - let getter_name = ctx.ext_cx.ident_of(&real_field_name); - - let mask = ((1usize << width) - 1) << offset; - let item = quote_item!(&ctx.ext_cx, - impl X { - #[inline] - pub fn $getter_name(&self) -> $field_type { - (self.$bindgen_ident & ($mask as $field_type)) >> $offset - } - - #[inline] - pub fn $setter_name(&mut self, val: $input_type) { - self.$bindgen_ident &= !($mask as $field_type); - self.$bindgen_ident |= (val as $field_type << $offset) & ($mask as $field_type); - } - } - ).unwrap(); - - match item.node { - ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), - _ => unreachable!() - } -} - -fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String, - bitfield_type: &Type, bitfields: &[(String, u32)]) -> ast::ImplItem { - let field_type = cty_to_rs(ctx, bitfield_type, false, true); - let mut args = vec![]; - let mut unnamed: usize = 0; - for &(ref name, width) in bitfields.iter() { - let ident = if name.is_empty() { - unnamed += 1; - let dummy = format!("unnamed_bitfield{}", unnamed); - ctx.ext_cx.ident_of(&dummy) - } else { - ctx.ext_cx.ident_of(name) - }; - args.push(ast::Arg { - ty: P(type_for_bitfield_width(ctx, width, true)), - pat: P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: ast::PatKind::Ident( - ast::BindingMode::ByValue(ast::Mutability::Immutable), - respan(ctx.span, ident), - None - ), - span: ctx.span - }), - id: ast::DUMMY_NODE_ID, - }); - } - - let fndecl = ast::FnDecl { - inputs: args, - output: ast::FunctionRetTy::Ty(P(field_type.clone())), - variadic: false - }; - - let mut offset = 0; - - let mut exprs = quote_expr!(&ctx.ext_cx, 0); - - let mut unnamed: usize = 0; - for &(ref name, width) in bitfields.iter() { - let name_ident = if name.is_empty() { - unnamed += 1; - let dummy = format!("unnamed_bitfield{}", unnamed); - ctx.ext_cx.ident_of(&dummy) - } else { - ctx.ext_cx.ident_of(name) - }; - exprs = quote_expr!(&ctx.ext_cx, - $exprs | (($name_ident as $field_type) << $offset) - ); - - offset += width; - } - - let block = ast::Block { - stmts: vec![ - ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Expr(exprs), - span: ctx.span, - } - ], - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - span: ctx.span - }; - - let mut attrs = vec![]; - - let node = ast::ImplItemKind::Method( - ast::MethodSig { - unsafety: ast::Unsafety::Normal, - abi: Abi::Rust, - decl: P(fndecl), - generics: ast::Generics::default(), - constness: if ctx.options.unstable_rust { - ast::Constness::Const - } else { - attrs.push(quote_attr!(&ctx.ext_cx, #[inline])); - ast::Constness::NotConst - }, - }, P(block) - ); - - ast::ImplItem { - id: ast::DUMMY_NODE_ID, - ident: ctx.ext_cx.ident_of(&format!("new{}", bindgen_name)), - vis: ast::Visibility::Public, - attrs: attrs, - node: node, - span: ctx.span, - defaultness: ast::Defaultness::Final, - } -} - -fn mk_blob_field(ctx: &GenCtx, name: &str, layout: &Layout) -> ast::StructField { - let ty_name = match layout.align { - 8 => "u64", - 4 => "u32", - 2 => "u16", - 1 | _ => "u8", - }; - let data_len = if ty_name == "u8" { layout.size } else { layout.size / layout.align }; - - let base_ty = mk_ty(ctx, false, &[ty_name.to_owned()]); - let data_ty = if data_len == 1 { - P(base_ty) - } else { - P(mk_arrty(ctx, &base_ty, data_len)) - }; - ast::StructField { - span: ctx.span, - vis: ast::Visibility::Public, - ident: Some(ctx.ext_cx.ident_of(name)), - id: ast::DUMMY_NODE_ID, - ty: data_ty, - attrs: vec![] - } -} - -fn mk_link_name_attr(ctx: &GenCtx, name: String) -> ast::Attribute { - let lit = respan(ctx.span, ast::LitKind::Str(intern(&name).as_str(), ast::StrStyle::Cooked)); - let attr_val = P(respan(ctx.span, ast::MetaItemKind::NameValue( - InternedString::new("link_name"), lit - ))); - let attr = ast::Attribute_ { - id: mk_attr_id(), - style: ast::AttrStyle::Outer, - value: attr_val, - is_sugared_doc: false - }; - respan(ctx.span, attr) -} - -fn mk_repr_attr(ctx: &GenCtx, layout: &Layout) -> ast::Attribute { - let mut values = vec!(P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("C"))))); - if layout.packed { - values.push(P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("packed"))))); - } - let attr_val = P(respan(ctx.span, ast::MetaItemKind::List( - InternedString::new("repr"), - values - ))); - - respan(ctx.span, ast::Attribute_ { - id: mk_attr_id(), - style: ast::AttrStyle::Outer, - value: attr_val, - is_sugared_doc: false - }) -} - -// NB: This requires that the type you implement it for also -// implements Copy. -// -// Implements std::clone::Clone using dereferencing. -// -// This is to bypass big arrays not implementing clone, -// but implementing copy due to hacks inside rustc's internals. -fn mk_clone_impl(ctx: &GenCtx, ty_name: &str) -> P { - let impl_str = format!(r" - impl ::std::clone::Clone for {} {{ - fn clone(&self) -> Self {{ *self }} - }} - ", ty_name); - - parse::new_parser_from_source_str(ctx.ext_cx.parse_sess(), - ctx.ext_cx.cfg(), "".to_owned(), impl_str).parse_item().unwrap().unwrap() -} - -fn mk_deriving_attr(ctx: &GenCtx, attrs: &[&'static str]) -> ast::Attribute { - let attr_val = P(respan(ctx.span, ast::MetaItemKind::List( - InternedString::new("derive"), - attrs.iter().map(|attr| { - P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new(attr)))) - }).collect() - ))); - - respan(ctx.span, ast::Attribute_ { - id: mk_attr_id(), - style: ast::AttrStyle::Outer, - value: attr_val, - is_sugared_doc: false - }) -} - -fn mk_doc_attr(ctx: &GenCtx, doc: &str) -> Vec { - if doc.is_empty() { - return vec![]; - } - - let attr_val = P(respan(ctx.span, ast::MetaItemKind::NameValue( - InternedString::new("doc"), - respan(ctx.span, ast::LitKind::Str(intern(doc).as_str(), ast::StrStyle::Cooked)) - ))); - - vec!(respan(ctx.span, ast::Attribute_ { - id: mk_attr_id(), - style: ast::AttrStyle::Outer, - value: attr_val, - is_sugared_doc: true - })) -} - -fn cvar_to_rs(ctx: &mut GenCtx, name: String, - mangled: String, ty: &Type, - is_const: bool) -> ast::ForeignItem { - let (rust_name, was_mangled) = rust_id(ctx, &name); - - let mut attrs = vec![]; - if !mangled.is_empty() { - attrs.push(mk_link_name_attr(ctx, mangled)); - } else if was_mangled { - attrs.push(mk_link_name_attr(ctx, name)); - } - - let val_ty = P(cty_to_rs(ctx, ty, true, true)); - - ast::ForeignItem { - ident: ctx.ext_cx.ident_of(&rust_name), - attrs: attrs, - node: ast::ForeignItemKind::Static(val_ty, !is_const), - id: ast::DUMMY_NODE_ID, - span: ctx.span, - vis: ast::Visibility::Public, - } -} - -fn cfuncty_to_rs(ctx: &GenCtx, - rty: &Type, - aty: &[(String, Type)], - var: bool) -> ast::FnDecl { - - let ret = match *rty { - TVoid => ast::FunctionRetTy::Default(ctx.span), - // Disable references in returns for now - TPtr(ref t, is_const, _, ref layout) => - ast::FunctionRetTy::Ty(P(cty_to_rs(ctx, &TPtr(t.clone(), is_const, false, layout.clone()), true, true))), - _ => ast::FunctionRetTy::Ty(P(cty_to_rs(ctx, rty, true, true))) - }; - - let mut unnamed: usize = 0; - let args: Vec = aty.iter().map(|arg| { - let (ref n, ref t) = *arg; - - let arg_name = if n.is_empty() { - unnamed += 1; - format!("arg{}", unnamed) - } else { - first(rust_id(ctx, &n)) - }; - - // From the C90 standard (http://c0x.coding-guidelines.com/6.7.5.3.html) - // 1598 - A declaration of a parameter as “array of type” shall be - // adjusted to “qualified pointer to type”, where the type qualifiers - // (if any) are those specified within the [ and ] of the array type - // derivation. - let arg_ty = P(match *t { - TArray(ref typ, _, l) => cty_to_rs(ctx, &TPtr(typ.clone(), false, false, l), true, true), - _ => cty_to_rs(ctx, t, true, true), - }); - - ast::Arg { - ty: arg_ty, - pat: P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: ast::PatKind::Ident( - ast::BindingMode::ByValue(ast::Mutability::Immutable), - respan(ctx.span, ctx.ext_cx.ident_of(&arg_name)), - None - ), - span: ctx.span - }), - id: ast::DUMMY_NODE_ID, - } - }).collect(); - - let var = !args.is_empty() && var; - ast::FnDecl { - inputs: args, - output: ret, - variadic: var - } -} - -fn cfunc_to_rs(ctx: &mut GenCtx, - name: String, - mangled: String, - comment: String, - rty: &Type, - aty: &[(String, Type)], - var: bool, - vis: ast::Visibility) -> ast::ForeignItem { - let var = !aty.is_empty() && var; - let decl = ast::ForeignItemKind::Fn( - P(cfuncty_to_rs(ctx, rty, aty, var)), - ast::Generics::default() - ); - - let (rust_name, was_mangled) = rust_id(ctx, &name); - - let mut attrs = mk_doc_attr(ctx, &comment); - if !mangled.is_empty() { - attrs.push(mk_link_name_attr(ctx, mangled)); - } else if was_mangled { - attrs.push(mk_link_name_attr(ctx, name)); - } - - ast::ForeignItem { - ident: ctx.ext_cx.ident_of(&rust_name), - attrs: attrs, - node: decl, - id: ast::DUMMY_NODE_ID, - span: ctx.span, - vis: vis, - } -} - -fn cty_to_rs(ctx: &GenCtx, ty: &Type, allow_bool: bool, use_full_path: bool) -> ast::Ty { - let prefix = vec!["std".to_owned(), "os".to_owned(), "raw".to_owned()]; - let raw = |fragment: &str| { - let mut path = prefix.clone(); - path.push(fragment.to_owned()); - path - }; - - match *ty { - TVoid => mk_ty(ctx, true, &raw("c_void")), - TInt(i, ref layout) => match i { - IBool => { - let ty_name = match layout.size { - 1 if allow_bool => "bool", - 2 => "u16", - 4 => "u32", - 8 => "u64", - _ => "u8", - }; - mk_ty(ctx, false, &[ty_name.to_owned()]) - }, - ISChar => mk_ty(ctx, true, &raw("c_char")), - IUChar => mk_ty(ctx, true, &raw("c_uchar")), - IInt => mk_ty(ctx, true, &raw("c_int")), - IUInt => mk_ty(ctx, true, &raw("c_uint")), - IShort => mk_ty(ctx, true, &raw("c_short")), - IUShort => mk_ty(ctx, true, &raw("c_ushort")), - ILong => mk_ty(ctx, true, &raw("c_long")), - IULong => mk_ty(ctx, true, &raw("c_ulong")), - ILongLong => mk_ty(ctx, true, &raw("c_longlong")), - IULongLong => mk_ty(ctx, true, &raw("c_ulonglong")) - }, - TFloat(f, _) => match f { - FFloat => mk_ty(ctx, false, &["f32".to_owned()]), - FDouble => mk_ty(ctx, false, &["f64".to_owned()]) - }, - TPtr(ref t, is_const, _is_ref, _) => { - let id = cty_to_rs(ctx, &**t, allow_bool, use_full_path); - mk_ptrty(ctx, &id, is_const) - }, - TArray(ref t, s, _) => { - let ty = cty_to_rs(ctx, &**t, allow_bool, use_full_path); - mk_arrty(ctx, &ty, s) - }, - TFuncPtr(ref sig) => { - let decl = cfuncty_to_rs(ctx, &*sig.ret_ty, &sig.args[..], sig.is_variadic); - mk_fnty(ctx, &decl, sig.abi) - }, - TFuncProto(ref sig) => { - let decl = cfuncty_to_rs(ctx, &*sig.ret_ty, &sig.args[..], sig.is_variadic); - mk_fn_proto_ty(ctx, &decl, sig.abi) - }, - TNamed(ref ti) => { - let id = rust_type_id(ctx, &ti.borrow().name); - - if use_full_path { - let mut path = ctx.full_path_for_module(ti.borrow().module_id); - path.push(id); - mk_ty(ctx, false, &path) - } else { - mk_ty(ctx, false, &[id]) - } - }, - TComp(ref ci) => { - let c = ci.borrow(); - let id = comp_name(&ctx, c.kind, &c.name); - - let args = c.args.iter().map(|gt| { - P(cty_to_rs(ctx, gt, allow_bool, false)) - }).collect(); - - if use_full_path { - let mut path = ctx.full_path_for_module(c.module_id()); - path.push(id); - mk_ty_args(ctx, false, &path, args) - } else { - mk_ty_args(ctx, false, &[id], args) - } - }, - TEnum(ref ei) => { - let e = ei.borrow(); - let id = enum_name(&ctx, &e.name); - - if use_full_path { - let mut path = ctx.full_path_for_module(e.module_id); - path.push(id); - mk_ty(ctx, false, &path) - } else { - mk_ty(ctx, false, &[id]) - } - } - } -} - -fn cty_is_translatable(ty: &Type) -> bool { - match *ty { - TVoid => false, - TArray(ref t, _, _) => { - cty_is_translatable(&**t) - }, - TComp(ref ci) => { - let c = ci.borrow(); - !c.args.iter().any(|gt| gt == &TVoid) && !c.has_non_type_template_params - }, - _ => true, - } -} - -fn mk_ty(ctx: &GenCtx, global: bool, segments: &[String]) -> ast::Ty { - mk_ty_args(ctx, global, segments, vec![]) -} - -fn mk_ty_args(ctx: &GenCtx, global: bool, segments: &[String], args: Vec>) -> ast::Ty { - let segment_count = segments.len(); - let ty = ast::TyKind::Path( - None, - ast::Path { - span: ctx.span, - global: global, - segments: segments.iter().enumerate().map(|(i, s)| { - ast::PathSegment { - identifier: ctx.ext_cx.ident_of(s), - parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { - lifetimes: vec![], - types: if i == segment_count - 1 { P::from_vec(args.clone()) } else { P::new() }, - bindings: P::new(), - }), - } - }).collect() - }, - ); - - ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ty, - span: ctx.span - } -} - -fn mk_ptrty(ctx: &GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty { - let ty = ast::TyKind::Ptr(ast::MutTy { - ty: P(base.clone()), - mutbl: if is_const { ast::Mutability::Immutable } else { ast::Mutability::Mutable } - }); - - ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ty, - span: ctx.span - } -} - -#[allow(dead_code)] -fn mk_refty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty { - let ty = ast::TyKind::Rptr( - None, - ast::MutTy { - ty: P(base.clone()), - mutbl: if is_const { ast::Mutability::Immutable } else { ast::Mutability::Mutable } - } - ); - - ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ty, - span: ctx.span - } -} - -fn mk_arrty(ctx: &GenCtx, base: &ast::Ty, n: usize) -> ast::Ty { - let int_lit = ast::LitKind::Int(n as u64, ast::LitIntType::Unsigned(ast::UintTy::Us)); - let sz = ast::ExprKind::Lit(P(respan(ctx.span, int_lit))); - let ty = ast::TyKind::FixedLengthVec( - P(base.clone()), - P(ast::Expr { - id: ast::DUMMY_NODE_ID, - node: sz, - span: ctx.span, - attrs: ast::ThinVec::new(), - }) - ); - - ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ty, - span: ctx.span - } -} - -fn mk_fn_proto_ty(ctx: &GenCtx, - decl: &ast::FnDecl, - abi: Abi) -> ast::Ty { - let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { - unsafety: ast::Unsafety::Unsafe, - abi: abi, - lifetimes: vec![], - decl: P(decl.clone()) - })); - - ast::Ty { - id: ast::DUMMY_NODE_ID, - node: fnty, - span: ctx.span, - } -} - -fn mk_fnty(ctx: &GenCtx, decl: &ast::FnDecl, abi: Abi) -> ast::Ty { - let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { - unsafety: ast::Unsafety::Unsafe, - abi: abi, - lifetimes: vec![], - decl: P(decl.clone()) - })); - - let segs = vec![ - ast::PathSegment { - identifier: ctx.ext_cx.ident_of("std"), - parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { - lifetimes: vec![], - types: P::new(), - bindings: P::new(), - }), - }, - ast::PathSegment { - identifier: ctx.ext_cx.ident_of("option"), - parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { - lifetimes: vec![], - types: P::new(), - bindings: P::new(), - }), - }, - ast::PathSegment { - identifier: ctx.ext_cx.ident_of("Option"), - parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { - lifetimes: vec![], - types: P::from_vec(vec![ - P(ast::Ty { - id: ast::DUMMY_NODE_ID, - node: fnty, - span: ctx.span - }) - ]), - bindings: P::new(), - }), - } - ]; - - ast::Ty { - id: ast::DUMMY_NODE_ID, - node: ast::TyKind::Path( - None, - ast::Path { - span: ctx.span, - global: true, - segments: segs - }, - ), - span: ctx.span - } -} - -fn mk_test_fn(ctx: &GenCtx, name: &str, layout: &Layout) -> P { - let size = layout.size; - let align = layout.align; - let struct_name = ctx.ext_cx.ident_of(name); - - let fn_name = ctx.ext_cx.ident_of(&format!("bindgen_test_layout_{}", name)); - - let size_of_expr = quote_expr!(&ctx.ext_cx, ::std::mem::size_of::<$struct_name>()); - let align_of_expr = quote_expr!(&ctx.ext_cx, ::std::mem::align_of::<$struct_name>()); - let item = quote_item!(&ctx.ext_cx, - #[test] - fn $fn_name() { - assert_eq!($size_of_expr, $size); - assert_eq!($align_of_expr, $align); - }).unwrap(); - item -} - -fn mk_opaque_struct(ctx: &GenCtx, name: &str, layout: &Layout) -> Vec> { - let blob_field = mk_blob_field(ctx, "_bindgen_opaque_blob", layout); - let variant_data = if layout.size == 0 { - ast::VariantData::Unit(ast::DUMMY_NODE_ID) - } else { - ast::VariantData::Struct(vec![blob_field], ast::DUMMY_NODE_ID) - }; - - let def = ast::ItemKind::Struct( - variant_data, - ast::Generics { - lifetimes: vec![], - ty_params: P::new(), - where_clause: ast::WhereClause { - id: ast::DUMMY_NODE_ID, - predicates: vec![] - } - } - ); - - let struct_decl = P(ast::Item { - ident: ctx.ext_cx.ident_of(&name), - attrs: vec![mk_repr_attr(ctx, layout)], - id: ast::DUMMY_NODE_ID, - node: def, - vis: ast::Visibility::Public, - span: ctx.span - }); - - let mut ret = vec![struct_decl]; - - // The test should always be correct but... - if *layout != Layout::zero() { - ret.push(mk_test_fn(ctx, &name, layout)); - } - - ret -} - -/// Generates a vector of rust's ty params from a list of types -fn mk_ty_params(ctx: &GenCtx, template_args: &[Type]) -> Vec { - template_args.iter().map(|gt| { - let name = match *gt { - TNamed(ref ti) => { - ctx.ext_cx.ident_of(&ti.borrow().name) - }, - _ => ctx.ext_cx.ident_of("") - }; - ast::TyParam { - ident: name, - id: ast::DUMMY_NODE_ID, - bounds: P::new(), - default: None, - span: ctx.span - } - }).collect() -} - -fn gen_union_field_definitions_if_necessary(ctx: &mut GenCtx, mut root_mod: &mut ast::Item) { - if !ctx.saw_union { - return; - } - - let union_field_decl = quote_item!(&ctx.ext_cx, - #[derive(Copy, Debug)] - #[repr(C)] - pub struct __BindgenUnionField(::std::marker::PhantomData); - ).unwrap(); - - let union_field_impl = quote_item!(&ctx.ext_cx, - impl __BindgenUnionField { - #[inline] - pub fn new() -> Self { - __BindgenUnionField(::std::marker::PhantomData) - } - - #[inline] - pub unsafe fn as_ref(&self) -> &T { - ::std::mem::transmute(self) - } - - #[inline] - pub unsafe fn as_mut(&mut self) -> &mut T { - ::std::mem::transmute(self) - } - } - ).unwrap(); - - let union_field_default_impl = quote_item!(&ctx.ext_cx, - impl ::std::default::Default for __BindgenUnionField { - #[inline] - fn default() -> Self { - Self::new() - } - } - ).unwrap(); - - let union_field_clone_impl = quote_item!(&ctx.ext_cx, - impl ::std::clone::Clone for __BindgenUnionField { - #[inline] - fn clone(&self) -> Self { - Self::new() - } - } - ).unwrap(); - - let items = vec![union_field_decl, union_field_impl, union_field_default_impl, union_field_clone_impl]; - match root_mod.node { - ast::ItemKind::Mod(ref mut root) => { - let old_items = std::mem::replace(&mut root.items, items); - root.items.extend(old_items.into_iter()); - } - _ => unreachable!(), - } -} diff --git a/src/hacks/mod.rs b/src/hacks/mod.rs deleted file mode 100644 index 793390025f..0000000000 --- a/src/hacks/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod refcell; diff --git a/src/hacks/refcell.rs b/src/hacks/refcell.rs deleted file mode 100644 index 408e95d4d5..0000000000 --- a/src/hacks/refcell.rs +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. -// See http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A fork of std::cell::RefCell that makes `as_unsafe_cell` usable on stable Rust. -//! -//! FIXME(https://github.com/rust-lang/rust/issues/27708): Remove this -//! (revert commit f7f81e0ed0b62402db291e28a9bb16f7194ebf78 / PR #11835) -//! when `std::cell::RefCell::as_unsafe_cell` is in Rust’s stable channel. - -#![allow(unsafe_code, dead_code)] - -use std::cell::{UnsafeCell, Cell}; -use std::cmp::Ordering; -use std::ops::{Deref, DerefMut}; - -/// A fork of std::cell::RefCell that makes `as_unsafe_cell` usable on stable Rust. -/// -/// FIXME(https://github.com/rust-lang/rust/issues/27708): Remove this -/// (revert commit f7f81e0ed0b62402db291e28a9bb16f7194ebf78 / PR #11835) -/// when `std::cell::RefCell::as_unsafe_cell` is in Rust’s stable channel. -#[derive(Debug)] -pub struct RefCell { - borrow: Cell, - value: UnsafeCell, -} -type BorrowFlag = usize; - -/// An enumeration of values returned from the `state` method on a `RefCell`. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum BorrowState { - /// The cell is currently being read, there is at least one active `borrow`. - Reading, - /// The cell is currently being written to, there is an active `borrow_mut`. - Writing, - /// There are no outstanding borrows on this cell. - Unused, -} - -// Values [1, MAX-1] represent the number of `Ref` active -// (will not outgrow its range since `usize` is the size of the address space) -const UNUSED: BorrowFlag = 0; -const WRITING: BorrowFlag = !0; - -impl RefCell { - /// Creates a new `RefCell` containing `value`. - /// - /// # Examples - /// - /// ``` - /// use std::cell::RefCell; - /// - /// let c = RefCell::new(5); - /// ``` - #[inline] - pub fn new(value: T) -> RefCell { - RefCell { - value: UnsafeCell::new(value), - borrow: Cell::new(UNUSED), - } - } - - /// Consumes the `RefCell`, returning the wrapped value. - /// - /// # Examples - /// - /// ``` - /// use std::cell::RefCell; - /// - /// let c = RefCell::new(5); - /// - /// let five = c.into_inner(); - /// ``` - #[inline] - pub fn into_inner(self) -> T { - // Since this function takes `self` (the `RefCell`) by value, the - // compiler statically verifies that it is not currently borrowed. - // Therefore the following assertion is just a `debug_assert!`. - debug_assert!(self.borrow.get() == UNUSED); - unsafe { self.value.into_inner() } - } -} - -impl RefCell { - /// Query the current state of this `RefCell` - /// - /// The returned value can be dispatched on to determine if a call to - /// `borrow` or `borrow_mut` would succeed. - #[inline] - pub fn borrow_state(&self) -> BorrowState { - match self.borrow.get() { - WRITING => BorrowState::Writing, - UNUSED => BorrowState::Unused, - _ => BorrowState::Reading, - } - } - - /// Immutably borrows the wrapped value. - /// - /// The borrow lasts until the returned `Ref` exits scope. Multiple - /// immutable borrows can be taken out at the same time. - /// - /// # Panics - /// - /// Panics if the value is currently mutably borrowed. - /// - /// # Examples - /// - /// ``` - /// use std::cell::RefCell; - /// - /// let c = RefCell::new(5); - /// - /// let borrowed_five = c.borrow(); - /// let borrowed_five2 = c.borrow(); - /// ``` - /// - /// An example of panic: - /// - /// ``` - /// use std::cell::RefCell; - /// use std::thread; - /// - /// let result = thread::spawn(move || { - /// let c = RefCell::new(5); - /// let m = c.borrow_mut(); - /// - /// let b = c.borrow(); // this causes a panic - /// }).join(); - /// - /// assert!(result.is_err()); - /// ``` - #[inline] - pub fn borrow(&self) -> Ref { - match BorrowRef::new(&self.borrow) { - Some(b) => Ref { - value: unsafe { &*self.value.get() }, - borrow: b, - }, - None => panic!("RefCell already mutably borrowed"), - } - } - - /// Mutably borrows the wrapped value. - /// - /// The borrow lasts until the returned `RefMut` exits scope. The value - /// cannot be borrowed while this borrow is active. - /// - /// # Panics - /// - /// Panics if the value is currently borrowed. - /// - /// # Examples - /// - /// ``` - /// use std::cell::RefCell; - /// - /// let c = RefCell::new(5); - /// - /// *c.borrow_mut() = 7; - /// - /// assert_eq!(*c.borrow(), 7); - /// ``` - /// - /// An example of panic: - /// - /// ``` - /// use std::cell::RefCell; - /// use std::thread; - /// - /// let result = thread::spawn(move || { - /// let c = RefCell::new(5); - /// let m = c.borrow(); - /// - /// let b = c.borrow_mut(); // this causes a panic - /// }).join(); - /// - /// assert!(result.is_err()); - /// ``` - #[inline] - pub fn borrow_mut(&self) -> RefMut { - match BorrowRefMut::new(&self.borrow) { - Some(b) => RefMut { - value: unsafe { &mut *self.value.get() }, - borrow: b, - }, - None => panic!("RefCell already borrowed"), - } - } - - /// Returns a reference to the underlying `UnsafeCell`. - /// - /// This can be used to circumvent `RefCell`'s safety checks. - /// - /// This function is `unsafe` because `UnsafeCell`'s field is public. - #[inline] - pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell { - &self.value - } - - /// Returns a mutable reference to the underlying data. - /// - /// This call borrows `RefCell` mutably (at compile-time) so there is no - /// need for dynamic checks. - #[inline] - pub fn get_mut(&mut self) -> &mut T { - unsafe { - &mut *self.value.get() - } - } -} - -unsafe impl Send for RefCell where T: Send {} - -impl Clone for RefCell { - #[inline] - fn clone(&self) -> RefCell { - RefCell::new(self.borrow().clone()) - } -} - -impl Default for RefCell { - #[inline] - fn default() -> RefCell { - RefCell::new(Default::default()) - } -} - -impl PartialEq for RefCell { - #[inline] - fn eq(&self, other: &RefCell) -> bool { - *self.borrow() == *other.borrow() - } -} - -impl Eq for RefCell {} - -impl PartialOrd for RefCell { - #[inline] - fn partial_cmp(&self, other: &RefCell) -> Option { - self.borrow().partial_cmp(&*other.borrow()) - } - - #[inline] - fn lt(&self, other: &RefCell) -> bool { - *self.borrow() < *other.borrow() - } - - #[inline] - fn le(&self, other: &RefCell) -> bool { - *self.borrow() <= *other.borrow() - } - - #[inline] - fn gt(&self, other: &RefCell) -> bool { - *self.borrow() > *other.borrow() - } - - #[inline] - fn ge(&self, other: &RefCell) -> bool { - *self.borrow() >= *other.borrow() - } -} - -impl Ord for RefCell { - #[inline] - fn cmp(&self, other: &RefCell) -> Ordering { - self.borrow().cmp(&*other.borrow()) - } -} - -struct BorrowRef<'b> { - borrow: &'b Cell, -} - -impl<'b> BorrowRef<'b> { - #[inline] - fn new(borrow: &'b Cell) -> Option> { - match borrow.get() { - WRITING => None, - b => { - borrow.set(b + 1); - Some(BorrowRef { borrow: borrow }) - }, - } - } -} - -impl<'b> Drop for BorrowRef<'b> { - #[inline] - fn drop(&mut self) { - let borrow = self.borrow.get(); - debug_assert!(borrow != WRITING && borrow != UNUSED); - self.borrow.set(borrow - 1); - } -} - -impl<'b> Clone for BorrowRef<'b> { - #[inline] - fn clone(&self) -> BorrowRef<'b> { - // Since this Ref exists, we know the borrow flag - // is not set to WRITING. - let borrow = self.borrow.get(); - debug_assert!(borrow != UNUSED); - // Prevent the borrow counter from overflowing. - assert!(borrow != WRITING); - self.borrow.set(borrow + 1); - BorrowRef { borrow: self.borrow } - } -} - -/// Wraps a borrowed reference to a value in a `RefCell` box. -/// A wrapper type for an immutably borrowed value from a `RefCell`. -/// -/// See the [module-level documentation](index.html) for more. -pub struct Ref<'b, T: ?Sized + 'b> { - value: &'b T, - borrow: BorrowRef<'b>, -} - -impl<'b, T: ?Sized> Deref for Ref<'b, T> { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - self.value - } -} - -impl<'b, T: ?Sized> Ref<'b, T> { - /// Copies a `Ref`. - /// - /// The `RefCell` is already immutably borrowed, so this cannot fail. - /// - /// This is an associated function that needs to be used as - /// `Ref::clone(...)`. A `Clone` implementation or a method would interfere - /// with the widespread use of `r.borrow().clone()` to clone the contents of - /// a `RefCell`. - #[inline] - pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> { - Ref { - value: orig.value, - borrow: orig.borrow.clone(), - } - } - - /// Make a new `Ref` for a component of the borrowed data. - /// - /// The `RefCell` is already immutably borrowed, so this cannot fail. - /// - /// This is an associated function that needs to be used as `Ref::map(...)`. - /// A method would interfere with methods of the same name on the contents - /// of a `RefCell` used through `Deref`. - /// - /// # Example - /// - /// ``` - /// use std::cell::{RefCell, Ref}; - /// - /// let c = RefCell::new((5, 'b')); - /// let b1: Ref<(u32, char)> = c.borrow(); - /// let b2: Ref = Ref::map(b1, |t| &t.0); - /// assert_eq!(*b2, 5) - /// ``` - #[inline] - pub fn map(orig: Ref<'b, T>, f: F) -> Ref<'b, U> - where F: FnOnce(&T) -> &U - { - Ref { - value: f(orig.value), - borrow: orig.borrow, - } - } -} - -impl<'b, T: ?Sized> RefMut<'b, T> { - /// Make a new `RefMut` for a component of the borrowed data, e.g. an enum - /// variant. - /// - /// The `RefCell` is already mutably borrowed, so this cannot fail. - /// - /// This is an associated function that needs to be used as - /// `RefMut::map(...)`. A method would interfere with methods of the same - /// name on the contents of a `RefCell` used through `Deref`. - /// - /// # Example - /// - /// ``` - /// use std::cell::{RefCell, RefMut}; - /// - /// let c = RefCell::new((5, 'b')); - /// { - /// let b1: RefMut<(u32, char)> = c.borrow_mut(); - /// let mut b2: RefMut = RefMut::map(b1, |t| &mut t.0); - /// assert_eq!(*b2, 5); - /// *b2 = 42; - /// } - /// assert_eq!(*c.borrow(), (42, 'b')); - /// ``` - #[inline] - pub fn map(orig: RefMut<'b, T>, f: F) -> RefMut<'b, U> - where F: FnOnce(&mut T) -> &mut U - { - RefMut { - value: f(orig.value), - borrow: orig.borrow, - } - } -} - -struct BorrowRefMut<'b> { - borrow: &'b Cell, -} - -impl<'b> Drop for BorrowRefMut<'b> { - #[inline] - fn drop(&mut self) { - let borrow = self.borrow.get(); - debug_assert!(borrow == WRITING); - self.borrow.set(UNUSED); - } -} - -impl<'b> BorrowRefMut<'b> { - #[inline] - fn new(borrow: &'b Cell) -> Option> { - match borrow.get() { - UNUSED => { - borrow.set(WRITING); - Some(BorrowRefMut { borrow: borrow }) - }, - _ => None, - } - } -} - -/// A wrapper type for a mutably borrowed value from a `RefCell`. -/// -/// See the [module-level documentation](index.html) for more. -pub struct RefMut<'b, T: ?Sized + 'b> { - value: &'b mut T, - borrow: BorrowRefMut<'b>, -} - -impl<'b, T: ?Sized> Deref for RefMut<'b, T> { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - self.value - } -} - -impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> { - #[inline] - fn deref_mut(&mut self) -> &mut T { - self.value - } -} diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs new file mode 100644 index 0000000000..cc61dbfd7d --- /dev/null +++ b/src/ir/annotations.rs @@ -0,0 +1,141 @@ +use clang; + +#[derive(Copy, PartialEq, Clone, Debug)] +pub enum FieldAccessorKind { + None, + Regular, + Unsafe, + Immutable, +} + +/// Annotations for a given item, or a field. +#[derive(Clone, PartialEq, Debug)] +pub struct Annotations { + /// Whether this item is marked as opaque. Only applies to types. + opaque: bool, + /// Whether this item should be hidden from the output. Only applies to + /// types. + hide: bool, + /// Whether this type should be replaced by another. The name must be the + /// canonical name that that type would get. + use_instead_of: Option, + /// Manually disable deriving copy/clone on this type. Only applies to + /// struct or union types. + disallow_copy: bool, + /// Whether fields should be marked as private or not. You can set this on + /// structs (it will apply to all the fields), or individual fields. + private_fields: Option, + /// The kind of accessor this field will have. Also can be applied to + /// structs so all the fields inside share it by default. + accessor_kind: Option, +} + +fn parse_accessor(s: &str) -> FieldAccessorKind { + match s { + "false" => FieldAccessorKind::None, + "unsafe" => FieldAccessorKind::Unsafe, + "immutable" => FieldAccessorKind::Immutable, + _ => FieldAccessorKind::Regular, + } +} + +impl Default for Annotations { + fn default() -> Self { + Annotations { + opaque: false, + hide: false, + use_instead_of: None, + disallow_copy: false, + private_fields: None, + accessor_kind: None + } + } +} + +impl Annotations { + pub fn new(cursor: &clang::Cursor) -> Option { + let mut anno = Annotations::default(); + let mut matched_one = false; + anno.parse(&cursor.comment(), &mut matched_one); + + if matched_one { + Some(anno) + } else { + None + } + } + + pub fn hide(&self) -> bool { + self.hide + } + + pub fn opaque(&self) -> bool { + self.opaque + } + + /// For a given type, indicates the type it should replace. + /// + /// For example, in the following code: + /// + /// ```cpp + /// + /// /**
*/ + /// struct Foo { int x; }; + /// + /// struct Bar { char foo; }; + /// ``` + /// + /// the generated code would look something like: + /// + /// ```rust + /// /**
*/ + /// struct Bar { + /// int x; + /// }; + /// ``` + /// + /// That is, code for `Foo` is used to generate `Bar`. + pub fn use_instead_of(&self) -> Option<&str> { + self.use_instead_of.as_ref().map(|s| &**s) + } + + pub fn disallow_copy(&self) -> bool { + self.disallow_copy + } + + pub fn private_fields(&self) -> Option { + self.private_fields + } + + pub fn accessor_kind(&self) -> Option { + self.accessor_kind + } + + fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) { + use clangll::CXComment_HTMLStartTag; + if comment.kind() == CXComment_HTMLStartTag && + comment.get_tag_name() == "div" && + comment.get_num_tag_attrs() > 1 && + comment.get_tag_attr_name(0) == "rustbindgen" { + *matched = true; + for i in 0..comment.get_num_tag_attrs() { + let value = comment.get_tag_attr_value(i); + let name = comment.get_tag_attr_name(i); + match name.as_str() { + "opaque" => self.opaque = true, + "hide" => self.hide = true, + "nocopy" => self.disallow_copy = true, + "replaces" => self.use_instead_of = Some(value), + "private" => self.private_fields = Some(value != "false"), + "accessor" + => self.accessor_kind = Some(parse_accessor(&value)), + _ => {}, + } + } + } + + for i in 0..comment.num_children() { + self.parse(&comment.get_child(i), matched); + } + } +} diff --git a/src/ir/comp.rs b/src/ir/comp.rs new file mode 100644 index 0000000000..1e6bf555f7 --- /dev/null +++ b/src/ir/comp.rs @@ -0,0 +1,718 @@ +use super::annotations::Annotations; +use super::context::BindgenContext; +use super::context::TypeResolver; +use super::layout::Layout; +use super::item::{Item, ItemId}; +use super::ty::{Type, RUST_DERIVE_IN_ARRAY_LIMIT}; +use std::cell::Cell; +use std::cmp; +use parse::{ClangItemParser, ParseError}; +use clang; + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum CompKind { + Struct, + Union, +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum MethodKind { + Static, + Normal, + Virtual, +} + +/// A struct representing a C++ method, either static, normal, or virtual. +#[derive(Debug)] +pub struct Method { + kind: MethodKind, + /// The signature of the method. Take into account this is not a `Type` + /// item, but a `Function` one. + /// + /// This is tricky and probably this field should be renamed. + signature: ItemId, + is_const: bool, +} + +impl Method { + fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self { + Method { + kind: kind, + signature: signature, + is_const: is_const, + } + } + + pub fn kind(&self) -> MethodKind { + self.kind + } + + pub fn is_virtual(&self) -> bool { + self.kind == MethodKind::Virtual + } + + pub fn is_static(&self) -> bool { + self.kind == MethodKind::Static + } + + pub fn signature(&self) -> ItemId { + self.signature + } + + pub fn is_const(&self) -> bool { + self.is_const + } +} + +/// A struct representing a C++ field. +#[derive(Clone, Debug)] +pub struct Field { + /// The name of the field, empty if it's an unnamed bitfield width. + name: Option, + /// The inner type. + ty: ItemId, + /// The doc comment on the field if any. + comment: Option, + /// Annotations for this field, or the default. + annotations: Annotations, + /// If this field is a bitfield, and how many bits does it contain if it is. + bitfield: Option, + /// If the C++ field is marked as `mutable` + mutable: bool, +} + +impl Field { + pub fn new(name: Option, + ty: ItemId, + comment: Option, + annotations: Option, + bitfield: Option, + mutable: bool) -> Field { + Field { + name: name, + ty: ty, + comment: comment, + annotations: annotations.unwrap_or_default(), + bitfield: bitfield, + mutable: mutable, + } + } + + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(|n| &**n) + } + + pub fn ty(&self) -> ItemId { + self.ty + } + + pub fn comment(&self) -> Option<&str> { + self.comment.as_ref().map(|c| &**c) + } + + pub fn bitfield(&self) -> Option { + self.bitfield + } + + pub fn is_mutable(&self) -> bool { + self.mutable + } + + pub fn annotations(&self) -> &Annotations { + &self.annotations + } +} + + +#[derive(Debug)] +pub struct CompInfo { + /// Whether this is a struct or a union. + kind: CompKind, + /// The members of this struct or union. + fields: Vec, + /// The template parameters of this class. These are non-concrete, and + /// should always be a Type(TypeKind::Named(name)), but still they need to + /// be registered with an unique type id in the context. + template_args: Vec, + /// The method declarations inside this class, if in C++ mode. + methods: Vec, + /// Vector of classes this one inherits from. + base_members: Vec, + /// The parent reference template if any. + ref_template: Option, + /// The inner types that were declared inside this class, in something like: + /// + /// class Foo { + /// typedef int FooTy; + /// struct Bar { + /// int baz; + /// }; + /// } + /// + /// static Foo::Bar const = {3}; + inner_types: Vec, + /// Set of static constants declared inside this class. + inner_vars: Vec, + /// Whether this type should generate an vtable (TODO: Should be able to + /// look at the virtual methods and ditch this field). + has_vtable: bool, + /// Whether this type has destructor. + has_destructor: bool, + /// Whether this type has a base type with more than one member. + /// + /// TODO: We should be able to compute this. + has_nonempty_base: bool, + /// If this type has a template parameter which is not a type (e.g.: a size_t) + has_non_type_template_params: bool, + /// Whether this struct layout is packed. + packed: bool, + /// Whether this struct is anonymous. + is_anonymous: bool, + /// Used to know if we've found an opaque attribute that could cause us to + /// generate a type with invalid layout. This is explicitly used to avoid us + /// generating bad alignments when parsing types like max_align_t. + /// + /// It's not clear what the behavior should be here, if generating the item + /// and pray, or behave as an opaque type. + found_unknown_attr: bool, + /// Used to detect if we've run in a can_derive_debug cycle while cycling + /// around the template arguments. + detect_derive_debug_cycle: Cell, + /// Used to detect if we've run in a has_destructor cycle while cycling + /// around the template arguments. + detect_has_destructor_cycle: Cell, +} + +impl CompInfo { + pub fn new(kind: CompKind) -> Self { + CompInfo { + kind: kind, + fields: vec![], + template_args: vec![], + methods: vec![], + base_members: vec![], + ref_template: None, + inner_types: vec![], + inner_vars: vec![], + has_vtable: false, + has_destructor: false, + has_nonempty_base: false, + has_non_type_template_params: false, + packed: false, + is_anonymous: false, + found_unknown_attr: false, + detect_derive_debug_cycle: Cell::new(false), + detect_has_destructor_cycle: Cell::new(false), + } + } + + pub fn can_derive_debug(&self, type_resolver: &TypeResolver, layout: Option) -> bool { + // We can reach here recursively via template parameters of a member, + // for example. + if self.detect_derive_debug_cycle.get() { + warn!("Derive debug cycle detected!"); + return true; + } + + if self.kind == CompKind::Union { + let layout = layout.unwrap_or_else(Layout::zero); + let size_divisor = cmp::max(1, layout.align); + return layout.size / size_divisor <= RUST_DERIVE_IN_ARRAY_LIMIT; + } + + self.detect_derive_debug_cycle.set(true); + + let can_derive_debug = + self.template_args.iter().all(|ty| { + type_resolver.resolve_type(*ty) + .can_derive_debug(type_resolver) + }) && + self.fields.iter().all(|field| { + type_resolver.resolve_type(field.ty) + .can_derive_debug(type_resolver) + }); + + self.detect_derive_debug_cycle.set(false); + + can_derive_debug + } + + pub fn is_unsized(&self, type_resolver: &TypeResolver) -> bool { + !self.has_vtable(type_resolver) && self.fields.is_empty() && + self.base_members.iter().all(|base| { + type_resolver + .resolve_type(*base) + .canonical_type(type_resolver) + .is_unsized(type_resolver) + }) && + self.ref_template.map_or(true, |template| { + type_resolver.resolve_type(template).is_unsized(type_resolver) + }) + } + + pub fn has_destructor(&self, type_resolver: &TypeResolver) -> bool { + if self.detect_has_destructor_cycle.get() { + warn!("Cycle detected looking for destructors"); + // Assume no destructor, since we don't have an explicit one. + return false; + } + + self.detect_has_destructor_cycle.set(true); + + let has_destructor = self.has_destructor || match self.kind { + CompKind::Union => false, + CompKind::Struct => { + // NB: We can't rely on a type with type parameters + // not having destructor. + // + // This is unfortunate, but... + self.ref_template.as_ref().map_or(false, |t| { + type_resolver.resolve_type(*t).has_destructor(type_resolver) + }) || + self.template_args.iter().any(|t| { + type_resolver.resolve_type(*t).has_destructor(type_resolver) + }) || + self.base_members.iter().any(|t| { + type_resolver.resolve_type(*t).has_destructor(type_resolver) + }) || + self.fields.iter().any(|field| { + type_resolver.resolve_type(field.ty) + .has_destructor(type_resolver) + }) + } + }; + + self.detect_has_destructor_cycle.set(false); + + has_destructor + } + + pub fn can_derive_copy(&self, type_resolver: &TypeResolver) -> bool { + // NOTE: Take into account that while unions in C and C++ are copied by + // default, the may have an explicit destructor in C++, so we can't + // defer this check just for the union case. + if self.has_destructor(type_resolver) { + return false; + } + + match self.kind { + CompKind::Union => true, + CompKind::Struct => { + // With template args, use a safe subset of the types, + // since copyability depends on the types itself. + self.ref_template.as_ref().map_or(true, |t| { + type_resolver.resolve_type(*t).can_derive_copy(type_resolver) + }) && + self.base_members.iter().all(|t| { + type_resolver.resolve_type(*t).can_derive_copy(type_resolver) + }) && + self.fields.iter().all(|field| { + type_resolver.resolve_type(field.ty) + .can_derive_copy(type_resolver) + }) + } + } + } + + pub fn is_template_specialization(&self) -> bool { + self.ref_template.is_some() + } + + pub fn specialized_template(&self) -> Option { + self.ref_template + } + + // Computes the layout of this type. + // + // This is called as a fallback under some circumstances where LLVM doesn't + // give us the correct layout. + // If we're a union without known layout, we try to compute it from our + // members. This is not ideal, but clang fails to report the size for + // these kind of unions, see test/headers/template_union.hpp + pub fn layout(&self, type_resolver: &TypeResolver) -> Option { + use std::cmp; + + // We can't do better than clang here, sorry. + if self.kind == CompKind::Struct { + return None; + } + + let mut max_size = 0; + let mut max_align = 0; + for field in &self.fields { + let field_layout = type_resolver.resolve_type(field.ty) + .layout(type_resolver); + + if let Some(layout) = field_layout { + max_size = cmp::max(max_size, layout.size); + max_align = cmp::max(max_align, layout.align); + } + } + + Some(Layout::new(max_size, max_align)) + } + + pub fn fields(&self) -> &[Field] { + &self.fields + } + + pub fn template_args(&self) -> &[ItemId] { + &self.template_args + } + + pub fn has_non_type_template_params(&self) -> bool { + self.has_non_type_template_params + } + + pub fn has_vtable(&self, type_resolver: &TypeResolver) -> bool { + self.has_vtable || self.base_members().iter().any(|base| { + type_resolver + .resolve_type(*base) + .has_vtable(type_resolver) + }) || self.ref_template.map_or(false, |template| { + type_resolver.resolve_type(template).has_vtable(type_resolver) + }) + } + + pub fn methods(&self) -> &[Method] { + &self.methods + } + + pub fn kind(&self) -> CompKind { + self.kind + } + + pub fn base_members(&self) -> &[ItemId] { + &self.base_members + } + + pub fn from_ty(potential_id: ItemId, + ty: &clang::Type, + location: Option, + ctx: &mut BindgenContext) -> Result { + use clangll::*; + // Sigh... For class templates we want the location, for + // specialisations, we want the declaration... So just try both. + // + // TODO: Yeah, this code reads really bad. + let mut cursor = ty.declaration(); + let mut kind = Self::kind_from_cursor(&cursor); + if kind.is_err() { + if let Some(location) = location { + kind = Self::kind_from_cursor(&location); + cursor = location; + } + } + + let kind = try!(kind); + + debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor); + + + let mut ci = CompInfo::new(kind); + ci.is_anonymous = cursor.is_anonymous(); + ci.template_args = match ty.num_template_args() { + // In forward declarations and not specializations, etc, they are in + // the ast, we'll meet them in CXCursor_TemplateTypeParameter + -1 => vec![], + len => { + let mut list = Vec::with_capacity(len as usize); + for i in 0..len { + let arg_type = ty.template_arg_type(i); + if arg_type.kind() != CXType_Invalid { + let type_id = + Item::from_ty_or_ref(arg_type, None, None, ctx); + + list.push(type_id); + } else { + ci.has_non_type_template_params = true; + warn!("warning: Template parameter is not a type"); + } + } + + list + } + }; + + ci.ref_template = Item::parse(cursor.specialized(), None, ctx).ok(); + + let mut maybe_anonymous_struct_field = None; + cursor.visit(|cur, _other| { + if cur.kind() != CXCursor_FieldDecl { + if let Some((ty, ref _clang_ty)) = maybe_anonymous_struct_field { + let field = Field::new(None, ty, None, None, None, false); + ci.fields.push(field); + } + maybe_anonymous_struct_field = None; + } + + match cur.kind() { + CXCursor_FieldDecl => { + match maybe_anonymous_struct_field.take() { + Some((ty, clang_ty)) => { + let mut used = false; + cur.visit(|child, _| { + if child.cur_type() == clang_ty { + used = true; + } + CXChildVisit_Continue + }); + if !used { + let field = Field::new(None, ty, None, None, None, false); + ci.fields.push(field); + } + }, + None => {} + } + + let bit_width = cur.bit_width(); + let field_type = + Item::from_ty_or_ref(cur.cur_type(), Some(*cur), Some(potential_id), ctx); + let comment = cur.raw_comment(); + let annotations = Annotations::new(cur); + let name = cur.spelling(); + let is_mutable = cursor.is_mutable_field(); + + // Name can be empty if there are bitfields, for example, + // see tests/headers/struct_with_bitfields.h + assert!(!name.is_empty() || bit_width.is_some(), + "Empty field name?"); + + let name = if name.is_empty() { None } else { Some(name) }; + + let field = Field::new(name, field_type, comment, + annotations, bit_width, is_mutable); + ci.fields.push(field); + + // No we look for things like attributes and stuff. + cur.visit(|cur, _| { + if cur.kind() == CXCursor_UnexposedAttr { + ci.found_unknown_attr = true; + } + CXChildVisit_Continue + }); + + } + CXCursor_UnexposedAttr => { + ci.found_unknown_attr = true; + } + CXCursor_EnumDecl | + CXCursor_TypeAliasDecl | + CXCursor_TypedefDecl | + CXCursor_StructDecl | + CXCursor_UnionDecl | + CXCursor_ClassTemplate | + CXCursor_ClassDecl => { + let inner = Item::parse(*cur, Some(potential_id), ctx) + .expect("Inner ClassDecl"); + if !ci.inner_types.contains(&inner) { + ci.inner_types.push(inner); + } + // A declaration of an union or a struct without name could + // also be an unnamed field, unfortunately. + if cur.spelling().is_empty() && cur.kind() != CXCursor_EnumDecl { + maybe_anonymous_struct_field = Some((inner, cur.cur_type())); + } + } + CXCursor_PackedAttr => { + ci.packed = true; + } + CXCursor_TemplateTypeParameter => { + // Yes! You can arrive here with an empty template parameter + // name! Awesome, isn't it? + // + // see tests/headers/empty_template_param_name.hpp + if cur.spelling().is_empty() { + return CXChildVisit_Continue; + } + + let default_type = + Item::from_ty(&cur.cur_type(), Some(*cur), Some(potential_id), ctx).ok(); + + let param = Item::named_type(cur.spelling(), default_type, potential_id, ctx); + ci.template_args.push(param); + } + CXCursor_CXXBaseSpecifier => { + if !ci.has_vtable { + ci.has_vtable = cur.is_virtual_base(); + } + let type_id = Item::from_ty(&cur.cur_type(), None, None, ctx) + .expect("BaseSpecifier"); + ci.base_members.push(type_id); + } + CXCursor_CXXMethod => { + let is_virtual = cur.method_is_virtual(); + let is_static = cur.method_is_static(); + debug_assert!(!(is_static && is_virtual), "How?"); + + if !ci.has_vtable { + ci.has_vtable = is_virtual; + } + + let linkage = cur.linkage(); + if linkage != CXLinkage_External { + return CXChildVisit_Continue; + } + + if cur.access_specifier() == CX_CXXPrivate { + return CXChildVisit_Continue; + } + + let visibility = cur.visibility(); + if visibility != CXVisibility_Default { + return CXChildVisit_Continue; + } + + if cur.is_inlined_function() { + return CXChildVisit_Continue; + } + + let spelling = cur.spelling(); + if spelling.starts_with("operator") { + return CXChildVisit_Continue; + } + + // This used to not be here, but then I tried generating + // stylo bindings with this (without path filters), and + // cried a lot with a method in gfx/Point.h + // (ToUnknownPoint), that somehow was causing the same type + // to be inserted in the map two times. + // + // I couldn't make a reduced test case, but anyway... + // Methods of template functions not only use to be inlined, + // but also instantiated, and we wouldn't be able to call + // them, so just bail out. + if !ci.template_args.is_empty() { + return CXChildVisit_Continue; + } + + // NB: This gets us an owned `Function`, not a `FunctionSig`. + let method_signature = Item::parse(*cur, Some(potential_id), ctx) + .expect("CXXMethod"); + let is_const = cur.method_is_const(); + let method_kind = if is_static { + MethodKind::Static + } else if is_virtual { + MethodKind::Virtual + } else { + MethodKind::Normal + }; + ci.methods.push(Method::new(method_kind, method_signature, is_const)); + } + CXCursor_Destructor => { + if cur.method_is_virtual() { + // FIXME: Push to the method list? + ci.has_vtable = true; + } + ci.has_destructor = true; + } + CXCursor_NonTypeTemplateParameter => { + ci.has_non_type_template_params = true; + } + CXCursor_VarDecl => { + let linkage = cur.linkage(); + if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal { + return CXChildVisit_Continue; + } + + let visibility = cur.visibility(); + if visibility != CXVisibility_Default { + return CXChildVisit_Continue; + } + + let item = Item::parse(*cur, Some(potential_id), ctx) + .expect("VarDecl"); + ci.inner_vars.push(item); + } + // Intentionally not handled + CXCursor_CXXAccessSpecifier | + CXCursor_CXXFinalAttr | + CXCursor_Constructor | + CXCursor_FunctionTemplate | + CXCursor_ConversionFunction => {} + _ => { + warn!("unhandled composite member `{}` (kind {}) in `{}` ({})", + cur.spelling(), cur.kind(), cursor.spelling(), + cur.location()); + } + } + CXChildVisit_Continue + }); + + if let Some((ty, _)) = maybe_anonymous_struct_field { + let field = Field::new(None, ty, None, None, None, false); + ci.fields.push(field); + } + + Ok(ci) + } + + fn kind_from_cursor(cursor: &clang::Cursor) -> Result { + use clangll::*; + Ok(match cursor.kind() { + CXCursor_UnionDecl => CompKind::Union, + CXCursor_ClassDecl | + CXCursor_StructDecl => CompKind::Struct, + CXCursor_ClassTemplatePartialSpecialization | + CXCursor_ClassTemplate => { + match cursor.template_kind() { + CXCursor_UnionDecl => CompKind::Union, + _ => CompKind::Struct, + } + } + _ => { + warn!("Unknown kind for comp type: {:?}", cursor); + return Err(ParseError::Continue); + } + }) + } + + pub fn signature_contains_named_type(&self, + type_resolver: &TypeResolver, + ty: &Type) -> bool { + // We don't generate these, so rather don't make the codegen step to + // think we got it covered. + if self.has_non_type_template_params() { + return false; + } + self.template_args.iter().any(|arg| { + type_resolver.resolve_type(*arg) + .signature_contains_named_type(type_resolver, ty) + }) + } + + pub fn inner_types(&self) -> &[ItemId] { + &self.inner_types + } + + pub fn inner_vars(&self) -> &[ItemId] { + &self.inner_vars + } + + pub fn found_unknown_attr(&self) -> bool { + self.found_unknown_attr + } + + pub fn packed(&self) -> bool { + self.packed + } + + /// Returns whether this type needs an explicit vtable because it has + /// virtual methods and none of its base classes has already a vtable. + pub fn needs_explicit_vtable(&self, type_resolver: &TypeResolver) -> bool { + self.has_vtable(type_resolver) && !self.base_members.iter().any(|base| { + // NB: Ideally, we could rely in all these types being `comp`, and + // life would be beautiful. + // + // Unfortunately, given the way we implement --match-pat, and also + // that you can inherit from templated types, we need to handle + // other cases here too. + type_resolver + .resolve_type(*base) + .canonical_type(type_resolver) + .as_comp().map_or(false, |ci| { + ci.has_vtable(type_resolver) + }) + }) + } +} diff --git a/src/ir/context.rs b/src/ir/context.rs new file mode 100644 index 0000000000..5ddedda067 --- /dev/null +++ b/src/ir/context.rs @@ -0,0 +1,685 @@ +use super::ty::{Type, TypeKind, FloatKind}; +use super::item::{Item, ItemCanonicalName, ItemId}; +use super::item_kind::ItemKind; +use super::int::IntKind; +use super::module::Module; +use clang::{self, Cursor}; +use std::borrow::{Cow, Borrow}; +use std::collections::btree_map::{self, BTreeMap}; +use std::collections::{HashSet, HashMap}; +use std::fmt; +use syntax::ast::Ident; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::ext::base::ExtCtxt; +use parse::ClangItemParser; +use BindgenOptions; + +// This is just convenience to avoid creating a manual debug impl for the +// context. +struct GenContext<'ctx>(ExtCtxt<'ctx>); + +impl<'ctx> fmt::Debug for GenContext <'ctx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "GenContext {{ ... }}") + } +} + +/// A context used during parsing and generation of structs. +#[derive(Debug)] +pub struct BindgenContext<'ctx> { + /// The map of all the items parsed so far. + /// + /// It's a BTreeMap because we want the keys to be sorted to have consistent + /// output. + items: BTreeMap, + + /// Clang cursor to type map. This is needed to be able to associate types + /// with item ids during parsing. + /// + /// The cursor used for storage is the definition cursor. + types: HashMap, + + /// A cursor to module map. Similar reason than above. + modules: HashMap, + + /// The root module, this is guaranteed to be an item of kind Module. + root_module: ItemId, + + /// Current module being traversed. + current_module: ItemId, + + /// A stack with the current type declarations and types we're parsing. This + /// is needed to avoid infinite recursion when parsing a type like: + /// + /// struct c { struct c* next; }; + /// + /// This means effectively, that a type has a potential ID before knowing if + /// it's a correct type. But that's not important in practice. + /// + /// We could also use the `types` HashMap, but my intention with it is that + /// only valid types and declarations end up there, and this could + /// potentially break that assumption. + /// + /// FIXME: Should not be public, though... meh. + pub currently_parsed_types: Vec<(Cursor, ItemId)>, + + /// A HashSet with all the already parsed macro names. This is done to avoid + /// hard errors while parsing duplicated macros. + parsed_macros: HashSet, + + /// The active replacements collected from replaces="xxx" annotations. + replacements: HashMap, + + collected_typerefs: bool, + + /// Dummy structures for code generation. + gen_ctx: Option<&'ctx GenContext<'ctx>>, + span: Span, + + /// The clang index for parsing. + index: clang::Index, + + /// The translation unit for parsing. + translation_unit: clang::TranslationUnit, + + /// The options given by the user via cli or other medium. + options: BindgenOptions, +} + +impl<'ctx> BindgenContext<'ctx> { + pub fn new(options: BindgenOptions) -> Self { + use clangll; + + let index = clang::Index::new(false, true); + + let translation_unit = + clang::TranslationUnit::parse(&index, "", &options.clang_args, &[], + clangll::CXTranslationUnit_DetailedPreprocessingRecord); + + let root_module = Self::build_root_module(); + let mut me = BindgenContext { + items: Default::default(), + types: Default::default(), + modules: Default::default(), + root_module: root_module.id(), + current_module: root_module.id(), + currently_parsed_types: vec![], + parsed_macros: Default::default(), + replacements: Default::default(), + collected_typerefs: false, + gen_ctx: None, + span: DUMMY_SP, + index: index, + translation_unit: translation_unit, + options: options, + }; + + me.add_item(root_module, None, None); + + me + } + + pub fn add_item(&mut self, + item: Item, + declaration: Option, + location: Option) { + use clangll::{CXCursor_ClassTemplate, CXCursor_ClassTemplatePartialSpecialization}; + debug!("BindgenContext::add_item({:?}, declaration: {:?}, loc: {:?}", item, declaration, location); + debug_assert!(declaration.is_some() || !item.kind().is_type() || + item.kind().expect_type().is_builtin_or_named(), + "Adding a type without declaration?"); + + let id = item.id(); + let is_type = item.kind().is_type(); + let old_item = self.items.insert(id, item); + assert!(old_item.is_none(), "Inserted type twice?"); + + if is_type && declaration.is_some() { + let declaration = declaration.unwrap(); + debug_assert_eq!(declaration, declaration.canonical()); + if declaration.is_valid() { + let old = self.types.insert(declaration, id); + debug_assert_eq!(old, None); + } else if location.is_some() && + (location.unwrap().kind() == CXCursor_ClassTemplate || + location.unwrap().kind() == CXCursor_ClassTemplatePartialSpecialization) { + let old = self.types.insert(location.unwrap().canonical(), id); + debug_assert_eq!(old, None); + } else { + // This could happen, for example, with types like `int*` or + // similar. + // + // Fortunately, we don't care about those types being + // duplicated, so we can just ignore them. + debug!("Invalid declaration {:?} found for type {:?}", + declaration, self.items.get(&id).unwrap().kind().expect_type()); + } + } + } + + // TODO: Move all this syntax crap to other part of the code. + pub fn ext_cx(&self) -> &ExtCtxt<'ctx> { + &self.gen_ctx.expect("Not in gen phase").0 + } + + pub fn span(&self) -> Span { + self.span + } + + /// Mangles a name so it doesn't conflict with any keyword. + pub fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> { + use syntax::parse::token; + let ident = self.rust_ident_raw(&name); + let token = token::Ident(ident); + if token.is_any_keyword() || + name.contains("@") || + name.contains("?") || + name.contains("$") || + "bool" == name + { + let mut s = name.to_owned(); + s = s.replace("@", "_"); + s = s.replace("?", "_"); + s = s.replace("$", "_"); + s.push_str("_"); + return Cow::Owned(s) + } + Cow::Borrowed(name) + } + + /// Returns a mangled name as a rust identifier. + pub fn rust_ident(&self, name: &str) -> Ident { + self.rust_ident_raw(&self.rust_mangle(name)) + } + + pub fn rust_ident_raw(&self, name: &S) -> Ident + where S: Borrow, + { + self.ext_cx().ident_of(name.borrow()) + } + + pub fn items<'a>(&'a self) -> btree_map::Iter<'a, ItemId, Item> { + self.items.iter() + } + + pub fn collected_typerefs(&self) -> bool { + self.collected_typerefs + } + + fn collect_typerefs(&mut self) -> Vec<(ItemId, clang::Type, Option)> { + debug_assert!(!self.collected_typerefs); + self.collected_typerefs = true; + let mut typerefs = vec![]; + for (id, ref mut item) in &mut self.items { + let kind = item.kind(); + let ty = match kind.as_type() { + Some(ty) => ty, + None => continue, + }; + + match *ty.kind() { + TypeKind::UnresolvedTypeRef(ref ty, loc) => { + typerefs.push((*id, ty.clone(), loc)); + } + _ => {}, + }; + } + typerefs + } + + fn resolve_typerefs(&mut self) { + let typerefs = self.collect_typerefs(); + + for (id, ty, loc) in typerefs { + let _resolved = { + let resolved = Item::from_ty(&ty, loc, None, self) + .expect("What happened?"); + let mut item = self.items.get_mut(&id).unwrap(); + + *item.kind_mut().as_type_mut().unwrap().kind_mut() = + TypeKind::ResolvedTypeRef(resolved); + resolved + }; + + // Something in the STL is trolling me. I don't need this assertion + // right now, but worth investigating properly once this lands. + // + // debug_assert!(self.items.get(&resolved).is_some(), "How?"); + } + } + + fn process_replacements(&mut self) { + if self.replacements.is_empty() { + return; + } + + // FIXME: This is linear, but the replaces="xxx" annotation was already + // there, and for better or worse it's useful, sigh... + // + // We leverage the ResolvedTypeRef thing, though, which is cool :P. + + let mut replacements = vec![]; + + for (id, item) in self.items.iter() { + let ty = match item.kind().as_type() { + Some(ty) => ty, + None => continue, + }; + + // canonical_name calls are expensive. + let ci = match ty.as_comp() { + Some(ci) => ci, + None => continue, + }; + + if ci.is_template_specialization() { + continue; + } + + if let Some(replacement) = self.replacements.get(&item.canonical_name(self)) { + if replacement != id { + // We set this just after parsing the annotation. It's + // very unlikely, but this can happen. + if self.items.get(replacement).is_some() { + replacements.push((*id, *replacement)); + } + } + } + } + + for (id, replacement) in replacements { + let mut item = self.items.get_mut(&id).unwrap(); + *item.kind_mut().as_type_mut().unwrap().kind_mut() = + TypeKind::ResolvedTypeRef(replacement); + } + } + + // Enters in the generation phase. + pub fn gen(&mut self, cb: F) -> Out + where F: FnOnce(&Self) -> Out + { + use syntax::ext::expand::ExpansionConfig; + use syntax::codemap::{ExpnInfo, MacroBang, NameAndSpan}; + use syntax::ext::base; + use syntax::parse; + use std::mem; + + let cfg = ExpansionConfig::default("xxx".to_owned()); + let sess = parse::ParseSess::new(); + let mut loader = base::DummyMacroLoader; + let mut ctx = + GenContext(base::ExtCtxt::new(&sess, vec![], cfg, &mut loader)); + + ctx.0.bt_push(ExpnInfo { + call_site: self.span, + callee: NameAndSpan { + format: MacroBang(parse::token::intern("")), + allow_internal_unstable: false, + span: None + } + }); + + // FIXME: This is evil, we should move code generation to use a wrapper + // of BindgenContext instead, I guess. Even though we know it's fine + // because we remove it before the end of this function. + self.gen_ctx = Some(unsafe { mem::transmute(&ctx) }); + + self.resolve_typerefs(); + self.process_replacements(); + + let ret = cb(self); + self.gen_ctx = None; + ret + } + + // This deserves a comment. Builtin types don't get a valid declaration, so + // we can't add it to the cursor->type map. + // + // That being said, they're not generated anyway, and are few, so the + // duplication and special-casing is fine. + // + // If at some point we care about the memory here, probably a map TypeKind + // -> builtin type ItemId would be the best to improve that. + fn add_builtin_item(&mut self, item: Item) { + debug_assert!(item.kind().is_type()); + let id = item.id(); + let old_item = self.items.insert(id, item); + assert!(old_item.is_none(), "Inserted type twice?"); + } + + fn build_root_module() -> Item { + let module = Module::new(Some("root".into())); + let id = ItemId::next(); + Item::new(id, None, None, id, ItemKind::Module(module)) + } + + pub fn root_module(&self) -> ItemId { + self.root_module + } + + pub fn resolve_type(&self, type_id: ItemId) -> &Type { + self.items.get(&type_id).unwrap().kind().expect_type() + } + + pub fn safe_resolve_type(&self, type_id: ItemId) -> Option<&Type> { + self.items.get(&type_id).map(|t| t.kind().expect_type()) + } + + pub fn resolve_item_fallible(&self, item_id: ItemId) -> Option<&Item> { + self.items.get(&item_id) + } + + pub fn resolve_item(&self, item_id: ItemId) -> &Item { + match self.items.get(&item_id) { + Some(item) => item, + None => panic!("Not an item: {:?}", item_id), + } + } + + pub fn current_module(&self) -> ItemId { + self.current_module + } + + /// This is one of the hackiest methods in all the parsing code. This method + /// is used to allow having templates with another argument names instead of + /// the canonical ones. + /// + /// This is surprisingly difficult to do with libclang, due to the fact that + /// partial template specializations don't provide explicit template + /// argument information. + /// + /// The only way to do this as far as I know, is inspecting manually the + /// AST, looking for TypeRefs inside. This, unfortunately, doesn't work for + /// more complex cases, see the comment on the assertion below. + /// + /// To see an example of what this handles: + /// + /// ``` + /// template + /// class Incomplete { + /// T p; + /// }; + /// + /// template + /// class Foo { + /// Incomplete bar; + /// }; + /// ``` + fn build_template_wrapper(&mut self, + wrapping: ItemId, + parent_id: ItemId, + ty: &clang::Type, + location: clang::Cursor) -> ItemId { + use clangll::*; + let mut args = vec![]; + let mut found_invalid_template_ref = false; + let self_id = ItemId::next(); + location.visit(|c, _| { + if c.kind() == CXCursor_TemplateRef && + c.cur_type().kind() == CXType_Invalid { + found_invalid_template_ref = true; + } + if c.kind() == CXCursor_TypeRef { + let new_ty = + Item::from_ty_or_ref(c.cur_type(), Some(*c), Some(self_id), self); + args.push(new_ty); + } + CXChildVisit_Continue + }); + + let item = { + let wrapping_type = self.resolve_type(wrapping); + let old_args = match *wrapping_type.kind() { + TypeKind::Comp(ref ci) => ci.template_args(), + _ => panic!("how?"), + }; + // The following assertion actually fails with partial template + // specialization. But as far as I know there's no way at all to + // grab the specialized types from neither the AST or libclang. + // + // This flaw was already on the old parser, but I now think it has + // no clear solution. + // + // For an easy example in which there's no way at all of getting the + // `int` type, except manually parsing the spelling: + // + // template + // class Incomplete { + // T d; + // U p; + // }; + // + // template + // class Foo { + // Incomplete bar; + // }; + // + // debug_assert_eq!(old_args.len(), args.len()); + // + // That being said, this is not so common, so just error! and hope + // for the best, returning the previous type, who knows. + if old_args.len() != args.len() { + error!("Found partial template specialization, expect dragons!"); + return wrapping; + } + + let type_kind = TypeKind::TemplateRef(wrapping, args); + let name = ty.spelling(); + let name = if name.is_empty() { None } else { Some(name) }; + let ty = Type::new(name, ty.fallible_layout().ok(), type_kind, ty.is_const()); + Item::new(self_id, None, None, parent_id, ItemKind::Type(ty)) + }; + + // Bypass all the validations in add_item explicitly. + self.items.insert(self_id, item); + self_id + } + + /// Looks up for an already resolved type, either because it's builtin, or + /// because we already have it in the map. + pub fn builtin_or_resolved_ty(&mut self, + parent_id: Option, + ty: &clang::Type, + location: Option) -> Option { + use clangll::{CXCursor_ClassTemplate, CXCursor_ClassTemplatePartialSpecialization}; + debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}", ty, location, parent_id); + let mut declaration = ty.declaration(); + if !declaration.is_valid() { + if let Some(location) = location { + if location.kind() == CXCursor_ClassTemplate || + location.kind() == CXCursor_ClassTemplatePartialSpecialization { + declaration = location; + } + } + } + let canonical_declaration = declaration.canonical(); + if canonical_declaration.is_valid() { + // First lookup to see if we already have it resolved. + let id = self.types.get(&canonical_declaration).map(|id| *id); + if let Some(id) = id { + debug!("Already resolved ty {:?}, {:?}, {:?} {:?}", + id, declaration, ty, location); + // If the declaration existed, we *might* be done, but it's not + // the case for class templates, where the template arguments + // may vary. + // + // In this case, we create a TemplateRef with the new template + // arguments, pointing to the canonical template. + // + // Note that we only do it if parent_id is some, and we have a + // location for building the new arguments, the template + // argument names don't matter in the global context. + if (declaration.kind() == CXCursor_ClassTemplate || + declaration.kind() == CXCursor_ClassTemplatePartialSpecialization) && + *ty != canonical_declaration.cur_type() && + location.is_some() && parent_id.is_some() { + return Some( + self.build_template_wrapper(id, parent_id.unwrap(), ty, + location.unwrap())); + } + + return Some(self.build_ty_wrapper(id, parent_id, ty)); + } + } + + debug!("Not resolved, maybe builtin?"); + + // Else, build it. + self.build_builtin_ty(ty, declaration) + } + + // This is unfortunately a lot of bloat, but is needed to properly track + // constness et. al. + // + // We should probably make the constness tracking separate, so it doesn't + // bloat that much, but hey, we already bloat the heck out of builtin types. + fn build_ty_wrapper(&mut self, + wrapped_id: ItemId, + parent_id: Option, + ty: &clang::Type) -> ItemId { + let id = ItemId::next(); + let spelling = ty.spelling(); + let is_const = ty.is_const(); + let layout = ty.fallible_layout().ok(); + let type_kind = TypeKind::ResolvedTypeRef(wrapped_id); + let ty = Type::new(Some(spelling), layout, type_kind, is_const); + let item = Item::new(id, None, None, + parent_id.unwrap_or(self.current_module), ItemKind::Type(ty)); + self.add_builtin_item(item); + id + } + + fn build_builtin_ty(&mut self, + ty: &clang::Type, + _declaration: Cursor) -> Option { + use clangll::*; + let type_kind = match ty.kind() { + CXType_NullPtr => TypeKind::NullPtr, + CXType_Void => TypeKind::Void, + CXType_Bool => TypeKind::Int(IntKind::Bool), + CXType_Int => TypeKind::Int(IntKind::Int), + CXType_UInt => TypeKind::Int(IntKind::UInt), + CXType_SChar | + CXType_Char_S => TypeKind::Int(IntKind::Char), + CXType_UChar | + CXType_Char_U => TypeKind::Int(IntKind::UChar), + CXType_Short => TypeKind::Int(IntKind::Short), + CXType_UShort => TypeKind::Int(IntKind::UShort), + CXType_WChar | + CXType_Char16 => TypeKind::Int(IntKind::U16), + CXType_Char32 => TypeKind::Int(IntKind::U32), + CXType_Long => TypeKind::Int(IntKind::Long), + CXType_ULong => TypeKind::Int(IntKind::ULong), + CXType_LongLong => TypeKind::Int(IntKind::LongLong), + CXType_ULongLong => TypeKind::Int(IntKind::ULongLong), + CXType_Float => TypeKind::Float(FloatKind::Float), + CXType_Double => TypeKind::Float(FloatKind::Double), + CXType_LongDouble => TypeKind::Float(FloatKind::LongDouble), + _ => return None, + }; + + let spelling = ty.spelling(); + let is_const = ty.is_const(); + let layout = ty.fallible_layout().ok(); + let ty = Type::new(Some(spelling), layout, type_kind, is_const); + let id = ItemId::next(); + let item = Item::new(id, None, None, self.root_module, ItemKind::Type(ty)); + self.add_builtin_item(item); + Some(id) + } + + pub fn translation_unit(&self) -> &clang::TranslationUnit { + &self.translation_unit + } + + pub fn parsed_macro(&self, macro_name: &str) -> bool { + self.parsed_macros.contains(macro_name) + } + + pub fn note_parsed_macro(&mut self, macro_name: String) { + debug_assert!(!self.parsed_macros.contains(¯o_name)); + self.parsed_macros.insert(macro_name); + } + + pub fn in_codegen_phase(&self) -> bool { + self.gen_ctx.is_some() + } + + /// This is a bit of a hack, but it's done so using the replaces="xxx" + /// annotation implies hide in the other type. + pub fn replace(&mut self, name: &str, potential_ty: ItemId) { + self.replacements.insert(name.into(), potential_ty); + } + + pub fn hidden_by_name(&self, name: &str) -> bool { + debug_assert!(self.in_codegen_phase(), + "You're not supposed to call this yet"); + self.options.hidden_types.contains(name) + } + + pub fn opaque_by_name(&self, name: &str) -> bool { + debug_assert!(self.in_codegen_phase(), + "You're not supposed to call this yet"); + self.options.opaque_types.contains(name) + } + + pub fn options(&self) -> &BindgenOptions { + &self.options + } + + /// Given a CXCursor_Namespace cursor, return the item id of the + /// corresponding module, or create one on the fly. + pub fn module(&mut self, cursor: clang::Cursor) -> ItemId { + use clangll::*; + assert!(cursor.kind() == CXCursor_Namespace, "Be a nice person"); + let cursor = cursor.canonical(); + let module_id = match self.modules.get(&cursor) { + Some(id) => return *id, + None => ItemId::next(), + }; + + let module_name = self.translation_unit + .tokens(&cursor).and_then(|tokens| { + if tokens.len() <= 1 { + None + } else { + match &*tokens[1].spelling { + "{" => None, + s => Some(s.to_owned()), + } + } + }); + + let module = Module::new(module_name); + let module = Item::new(module_id, None, None, self.current_module, + ItemKind::Module(module)); + + self.add_item(module, None, None); + + module_id + } + + pub fn with_module(&mut self, module_id: ItemId, cb: F) + where F: FnOnce(&mut Self, &mut Vec) + { + debug_assert!(self.resolve_item(module_id).kind().is_module(), "Wat"); + + let previous_id = self.current_module; + self.current_module = module_id; + + let mut children = vec![]; + cb(self, &mut children); + + self.items.get_mut(&module_id).unwrap() + .as_module_mut().expect("Not a module?") + .children_mut().extend(children.into_iter()); + + self.current_module = previous_id; + } +} + +/// This was originally a type that only exposes the resolve_type operation to +/// its consumers. +/// +/// Later a made resolve_type public, so... meh. It should go away soon. +pub type TypeResolver<'ctx> = BindgenContext<'ctx>; diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs new file mode 100644 index 0000000000..c85ee07a2d --- /dev/null +++ b/src/ir/enum_ty.rs @@ -0,0 +1,110 @@ +use super::item::{Item, ItemId}; +use super::ty::TypeKind; +use super::context::BindgenContext; +use parse::{ClangItemParser, ParseError}; +use clang; + +#[derive(Debug)] +pub struct Enum { + /// The representation used for this enum. + /// Should be an IntKind type. + /// + /// It's None if the enum is a forward declaration and isn't defined + /// anywhere else, see tests/headers/func_ptr_in_struct.h + repr: Option, + /// The different variants, with explicit values. + variants: Vec, +} + +impl Enum { + pub fn new(repr: Option, variants: Vec) -> Self { + Enum { + repr: repr, + variants: variants, + } + } + + pub fn repr(&self) -> Option { + self.repr + } + + pub fn variants(&self) -> &[EnumVariant] { + &self.variants + } + + pub fn from_ty(ty: &clang::Type, + ctx: &mut BindgenContext) -> Result { + use clangll::*; + if ty.kind() != CXType_Enum { + return Err(ParseError::Continue); + } + + let declaration = ty.declaration().canonical(); + let repr = Item::from_ty(&declaration.enum_type(), None, None, ctx).ok(); + let mut variants = vec![]; + + let is_signed = match repr { + Some(repr) => { + let repr_type = ctx.resolve_type(repr); + match *repr_type.canonical_type(ctx).kind() { + TypeKind::Int(ref int_kind) => int_kind.is_signed(), + ref other => panic!("Since when enums can be non-integers? {:?}", other), + } + } + // Assume signedness since the default type by the C standard is an + // int. + None => true, + }; + + declaration.visit(|cursor, _| { + if cursor.kind() == CXCursor_EnumConstantDecl { + let name = cursor.spelling(); + let comment = cursor.raw_comment(); + let val = if is_signed { + EnumVariantValue::Signed(cursor.enum_val_signed()) + } else { + EnumVariantValue::Unsigned(cursor.enum_val_unsigned()) + }; + variants.push(EnumVariant::new(name, comment, val)); + } + CXChildVisit_Continue + }); + + Ok(Enum::new(repr, variants)) + } +} + +/// A single enum variant, to be contained only in an enum. +#[derive(Debug)] +pub struct EnumVariant { + /// The name of the variant. + name: String, + /// An optional doc comment. + comment: Option, + /// The integer value of the variant. + val: EnumVariantValue, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum EnumVariantValue { + Signed(i64), + Unsigned(u64), +} + +impl EnumVariant { + pub fn new(name: String, comment: Option, val: EnumVariantValue) -> Self { + EnumVariant { + name: name, + comment: comment, + val: val, + } + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn val(&self) -> EnumVariantValue { + self.val + } +} diff --git a/src/ir/function.rs b/src/ir/function.rs new file mode 100644 index 0000000000..b95ac57bb4 --- /dev/null +++ b/src/ir/function.rs @@ -0,0 +1,220 @@ +use super::item::{Item, ItemId}; +use super::ty::TypeKind; +use super::context::BindgenContext; +use syntax::abi; +use clang; +use clangll::Enum_CXCallingConv; +use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; + +/// A function declaration , with a signature, arguments, and argument names. +/// +/// The argument names vector must be the same length as the ones in the +/// signature. +#[derive(Debug)] +pub struct Function { + name: String, + /// The mangled name, that is, the symbol. + mangled_name: Option, + /// The id pointing to the current function signature. + signature: ItemId, + /// The doc comment on the function, if any. + comment: Option, +} + +impl Function { + pub fn new(name: String, + mangled_name: Option, + sig: ItemId, + comment: Option) -> Self { + Function { + name: name, + mangled_name: mangled_name, + signature: sig, + comment: comment, + } + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn mangled_name(&self) -> Option<&str> { + self.mangled_name.as_ref().map(|n| &**n) + } + + pub fn signature(&self) -> ItemId { + self.signature + } +} + +/// A function signature. +#[derive(Debug)] +pub struct FunctionSig { + /// The return type of the function. + return_type: ItemId, + /// The type of the arguments, optionally with the name of the argument when + /// declared. + argument_types: Vec<(Option, ItemId)>, + /// Whether this function is variadic. + is_variadic: bool, + /// The abi of this function. + abi: abi::Abi, +} + +fn get_abi(cc: Enum_CXCallingConv) -> abi::Abi { + use clangll::*; + match cc { + CXCallingConv_Default => abi::Abi::C, + CXCallingConv_C => abi::Abi::C, + CXCallingConv_X86StdCall => abi::Abi::Stdcall, + CXCallingConv_X86FastCall => abi::Abi::Fastcall, + CXCallingConv_AAPCS => abi::Abi::Aapcs, + CXCallingConv_X86_64Win64 => abi::Abi::Win64, + other => panic!("unsupported calling convention: {}", other), + } +} + +pub fn cursor_mangling(cursor: &clang::Cursor) -> Option { + let mut mangling = cursor.mangling(); + + // Try to undo backend linkage munging (prepended _, generally) + if cfg!(target_os = "macos") { + mangling.remove(0); + } + + if mangling.is_empty() { None } else { Some(mangling) } +} + +impl FunctionSig { + pub fn new(return_type: ItemId, + arguments: Vec<(Option, ItemId)>, + is_variadic: bool, + abi: abi::Abi) -> Self { + FunctionSig { + return_type: return_type, + argument_types: arguments, + is_variadic: is_variadic, + abi: abi, + } + } + + pub fn from_ty(ty: &clang::Type, + cursor: &clang::Cursor, + ctx: &mut BindgenContext) -> Result { + use clangll::*; + debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor); + + // Don't parse operatorxx functions in C++ + let spelling = cursor.spelling(); + if spelling.starts_with("operator") { + return Err(ParseError::Continue); + } + + let cursor = if cursor.is_valid() { + *cursor + } else { + ty.declaration() + }; + let mut args: Vec<_> = match cursor.kind() { + CXCursor_FunctionDecl | + CXCursor_CXXMethod => { + // For CXCursor_FunctionDecl, cursor.args() is the reliable way + // to get parameter names and types. + cursor.args().iter().map(|arg| { + let arg_ty = arg.cur_type(); + let name = arg.spelling(); + let name = if name.is_empty() { None } else { Some(name) }; + let ty = Item::from_ty(&arg_ty, Some(*arg), None, ctx) + .expect("Argument?"); + (name, ty) + }).collect() + } + _ => { + // For non-CXCursor_FunctionDecl, visiting the cursor's children + // is the only reliable way to get parameter names. + let mut args = vec![]; + cursor.visit(|c, _| { + if c.kind() == CXCursor_ParmDecl { + let ty = Item::from_ty(&c.cur_type(), Some(*c), None, ctx) + .expect("ParmDecl?"); + let name = c.spelling(); + let name = if name.is_empty() { None } else { Some(name) }; + args.push((name, ty)); + } + CXChildVisit_Continue + }); + args + } + }; + + if cursor.kind() == CXCursor_CXXMethod { + let is_const = cursor.method_is_const(); + let is_virtual = cursor.method_is_virtual(); + let is_static = cursor.method_is_static(); + if !is_static && !is_virtual { + let class = Item::parse(cursor.semantic_parent(), None, ctx) + .expect("Expected to parse the class"); + let ptr = Item::builtin_type(TypeKind::Pointer(class), is_const, ctx); + args.insert(0, (Some("this".into()), ptr)); + } else if is_virtual { + let void = Item::builtin_type(TypeKind::Void, false, ctx); + let ptr = Item::builtin_type(TypeKind::Pointer(void), false, ctx); + args.insert(0, (Some("this".into()), ptr)); + } + } + + let ret = try!(Item::from_ty(&ty.ret_type(), None, None, ctx)); + let abi = get_abi(ty.call_conv()); + + Ok(Self::new(ret, args, ty.is_variadic(), abi)) + } + + pub fn return_type(&self) -> ItemId { + self.return_type + } + + pub fn argument_types(&self) -> &[(Option, ItemId)] { + &self.argument_types + } + + pub fn abi(&self) -> abi::Abi { + self.abi + } + + pub fn is_variadic(&self) -> bool { + // Clang reports some functions as variadic when they *might* be + // variadic. We do the argument check because rust doesn't codegen well + // variadic functions without an initial argument. + self.is_variadic && !self.argument_types.is_empty() + } +} + +impl ClangSubItemParser for Function { + fn parse(cursor: clang::Cursor, + context: &mut BindgenContext) -> Result, ParseError> { + use clangll::*; + match cursor.kind() { + CXCursor_FunctionDecl | + CXCursor_CXXMethod => {}, + _ => return Err(ParseError::Continue), + }; + + debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type()); + + // Grab the signature using Item::from_ty. + let sig = try!(Item::from_ty(&cursor.cur_type(), Some(cursor), None, context)); + + let name = cursor.spelling(); + assert!(!name.is_empty(), "Empty function name?"); + + let mut mangled_name = cursor_mangling(&cursor); + if mangled_name.as_ref() == Some(&name) { + mangled_name = None; + } + + let comment = cursor.raw_comment(); + + let function = Self::new(name, mangled_name, sig, comment); + Ok(ParseResult::New(function, Some(cursor))) + } +} diff --git a/src/ir/int.rs b/src/ir/int.rs new file mode 100644 index 0000000000..d2769b772a --- /dev/null +++ b/src/ir/int.rs @@ -0,0 +1,30 @@ +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum IntKind { + Bool, + Char, + UChar, + Short, + UShort, + Int, + UInt, + Long, + ULong, + LongLong, + ULongLong, + U16, // For Char16 and Wchar + U32, // For Char32 + // Though now we're at it we could add equivalents for the rust types... +} + +impl IntKind { + pub fn is_signed(&self) -> bool { + use self::IntKind::*; + match *self { + Bool | UChar | UShort | + UInt | ULong | ULongLong | U16 | U32 => false, + + Char | Short | Int | + Long | LongLong => true, + } + } +} diff --git a/src/ir/item.rs b/src/ir/item.rs new file mode 100644 index 0000000000..c9ac71a4d9 --- /dev/null +++ b/src/ir/item.rs @@ -0,0 +1,681 @@ +use super::context::BindgenContext; +use super::item_kind::ItemKind; +use super::ty::{Type, TypeKind}; +use super::function::Function; +use super::module::Module; +use super::annotations::Annotations; +use std::fmt; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; +use clang; +use clangll; + +/// A trait to get the canonical name from an item. +/// +/// This is the trait that will eventually isolate all the logic related to name +/// mangling and that kind of stuff. +/// +/// This assumes no nested paths, at some point I'll have to make it a more +/// complex thing. +/// +/// This name is required to be safe for Rust, that is, is not expected to +/// return any rust keyword from here. +pub trait ItemCanonicalName { + fn canonical_name(&self, ctx: &BindgenContext) -> String; +} + +/// The same, but specifies the path that needs to be followed to reach an item. +/// +/// To contrast with canonical_name, here's an example: +/// +/// ``` +/// namespace foo { +/// const BAR = 3; +/// } +/// ``` +/// +/// For bar, the canonical path is foo::BAR, while the canonical name is just +/// BAR. +pub trait ItemCanonicalPath { + fn canonical_path(&self, ctx: &BindgenContext) -> Vec; +} + +/// A single identifier for an item. +/// +/// TODO: Build stronger abstractions on top of this, like TypeId(ItemId), ... +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ItemId(usize); + +impl fmt::Display for ItemId { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + try!(write!(fmt, "_bindgen_id_")); + self.0.fmt(fmt) + } +} + +pub static NEXT_ITEM_ID: AtomicUsize = ATOMIC_USIZE_INIT; + +impl ItemId { + pub fn next() -> Self { + ItemId(NEXT_ITEM_ID.fetch_add(1, Ordering::Relaxed)) + } +} + +// Pure convenience +impl ItemCanonicalName for ItemId { + fn canonical_name(&self, ctx: &BindgenContext) -> String { + debug_assert!(ctx.in_codegen_phase(), + "You're not supposed to call this yet"); + ctx.resolve_item(*self).canonical_name(ctx) + } +} + +impl ItemCanonicalPath for ItemId { + fn canonical_path(&self, ctx: &BindgenContext) -> Vec { + debug_assert!(ctx.in_codegen_phase(), + "You're not supposed to call this yet"); + ctx.resolve_item(*self).canonical_path(ctx) + } +} + +#[derive(Debug)] +pub struct Item { + /// This item's id. + id: ItemId, + /// A doc comment over the item, if any. + comment: Option, + /// Annotations extracted from the doc comment, or the default ones + /// otherwise. + annotations: Annotations, + /// An item's parent id. This will most likely be a class where this item + /// was declared, or a module, etc. + /// + /// All the items have a parent, except the root module, in which case the + /// parent id is its own id. + parent_id: ItemId, + /// The item kind. + kind: ItemKind, +} + +impl Item { + pub fn new(id: ItemId, + comment: Option, + annotations: Option, + parent_id: ItemId, + kind: ItemKind) -> Self { + debug_assert!(id != parent_id || kind.is_module()); + Item { + id: id, + parent_id: parent_id, + comment: comment, + annotations: annotations.unwrap_or_default(), + kind: kind, + } + } + + pub fn id(&self) -> ItemId { + self.id + } + + pub fn parent_id(&self) -> ItemId { + self.parent_id + } + + pub fn comment(&self) -> Option<&str> { + self.comment.as_ref().map(|c| &**c) + } + + pub fn kind(&self) -> &ItemKind { + &self.kind + } + + pub fn kind_mut(&mut self) -> &mut ItemKind { + &mut self.kind + } + + pub fn is_toplevel(&self, ctx: &BindgenContext) -> bool { + // FIXME: Workaround for some types falling behind when parsing weird + // stl classes, for example. + if ctx.options().enable_cxx_namespaces && + self.kind().is_module() && + self.id() != ctx.root_module() { + return false; + } + + let mut parent = self.parent_id; + loop { + let parent_item = match ctx.resolve_item_fallible(parent) { + Some(item) => item, + None => return false, + }; + + if parent_item.id() == ctx.root_module() { + return true; + } else if ctx.options().enable_cxx_namespaces || !parent_item.kind().is_module() { + return false; + } + + parent = parent_item.parent_id(); + } + } + + pub fn expect_type(&self) -> &Type { + self.kind().expect_type() + } + + pub fn expect_function(&self) -> &Function { + self.kind().expect_function() + } + + pub fn applicable_template_args(&self, ctx: &BindgenContext) -> Vec { + let ty = match *self.kind() { + ItemKind::Type(ref ty) => ty, + _ => return vec![], + }; + + fn parent_contains(ctx: &BindgenContext, + parent_template_args: &[ItemId], + item: ItemId) -> bool { + let item_ty = ctx.resolve_type(item); + parent_template_args.iter().any(|parent_item| { + let parent_ty = ctx.resolve_type(*parent_item); + match (parent_ty.kind(), item_ty.kind()) { + (&TypeKind::Named(ref n, _), &TypeKind::Named(ref i, _)) => n == i, + _ => false, + } + }) + } + + match *ty.kind() { + TypeKind::Named(..) => vec![self.id()], + TypeKind::Array(inner, _) | + TypeKind::Pointer(inner) | + TypeKind::Reference(inner) | + TypeKind::Alias(_, inner) | + TypeKind::ResolvedTypeRef(inner) => { + ctx.resolve_item(inner).applicable_template_args(ctx) + } + // XXX Is this completely correct? Partial template specialization + // is hard anyways, sigh... + TypeKind::TemplateRef(_, ref args) => { + args.clone() + } + // In a template specialization we've got all we want. + TypeKind::Comp(ref ci) if ci.is_template_specialization() => { + ci.template_args().iter().cloned().collect() + } + TypeKind::Comp(ref ci) => { + let mut parent_template_args = + ctx.resolve_item(self.parent_id()) + .applicable_template_args(ctx); + + for ty in ci.template_args() { + if !parent_contains(ctx, &parent_template_args, *ty) { + parent_template_args.push(*ty); + } + } + + parent_template_args + } + _ => vec![], + } + } + + fn is_module(&self) -> bool { + match self.kind { + ItemKind::Module(..) => true, + _ => false, + } + } + + pub fn annotations(&self) -> &Annotations { + &self.annotations + } + + /// Whether this item should be hidden, either due to annotations, or due to + /// other kind of configuration. + pub fn is_hidden(&self, ctx: &BindgenContext) -> bool { + debug_assert!(ctx.in_codegen_phase(), + "You're not supposed to call this yet"); + self.annotations.hide() || + ctx.hidden_by_name(&self.real_canonical_name(ctx, false)) + } + + pub fn is_opaque(&self, ctx: &BindgenContext) -> bool { + debug_assert!(ctx.in_codegen_phase(), + "You're not supposed to call this yet"); + self.annotations.opaque() || + ctx.opaque_by_name(&self.real_canonical_name(ctx, false)) + } + + /// Get the canonical name without taking into account the replaces + /// annotation. + fn real_canonical_name(&self, ctx: &BindgenContext, count_namespaces: bool) -> String { + let base_name = match *self.kind() { + ItemKind::Type(ref ty) => { + match *ty.kind() { + // If we're a template specialization, our name is our parent's + TypeKind::Comp(ref ci) if ci.is_template_specialization() => { + return ci.specialized_template().unwrap().canonical_name(ctx); + }, + // Same as above + TypeKind::ResolvedTypeRef(inner) | + TypeKind::TemplateRef(inner, _) => { + return inner.canonical_name(ctx); + } + // If we're a named type, we don't need to mangle it, and we + // should be able to assert we're not top level. + TypeKind::Named(ref name, _) => { + return name.to_owned(); + } + _ => {} + } + + ty.name().map(ToOwned::to_owned) + .unwrap_or_else(|| format!("_bindgen_ty{}", self.id())) + } + ItemKind::Function(ref fun) => { + let mut base = fun.name().to_owned(); + + // We might need to deduplicate if we're a method. + let parent = ctx.resolve_item(self.parent_id()); + if let ItemKind::Type(ref ty) = *parent.kind() { + if let TypeKind::Comp(ref ci) = *ty.kind() { + let mut count = 0; + let mut found = false; + for method in ci.methods() { + if method.signature() == self.id() { + found = true; + break; + } + let fun = ctx.resolve_item(method.signature()) + .expect_function(); + if fun.name() == base { + count += 1; + } + } + + assert!(found, "Method not found?"); + if count != 0 { + base.push_str(&count.to_string()); + } + } + } + base + } + ItemKind::Var(ref var) => { + var.name().to_owned() + } + ItemKind::Module(ref module) => { + module.name().map(ToOwned::to_owned) + .unwrap_or_else(|| format!("_bindgen_mod{}", self.id())) + } + }; + + let parent = ctx.resolve_item(self.parent_id()); + let parent_is_namespace = parent.is_module(); + if self.is_toplevel(ctx) || (parent_is_namespace && count_namespaces) { + return ctx.rust_mangle(&base_name).into_owned(); + } + + // TODO: allow modification of the mangling functions, maybe even per + // item type? + format!("{}_{}", parent.canonical_name(ctx), base_name) + } + + pub fn as_module_mut(&mut self) -> Option<&mut Module> { + match self.kind { + ItemKind::Module(ref mut module) => Some(module), + _ => None, + } + } +} + +impl ClangItemParser for Item { + fn builtin_type(kind: TypeKind, is_const: bool, ctx: &mut BindgenContext) -> ItemId { + // Feel free to add more here, I'm just lazy. + match kind { + TypeKind::Void | + TypeKind::Int(..) | + TypeKind::Pointer(..) | + TypeKind::Float(..) => {}, + _ => panic!("Unsupported builtin type"), + } + + let ty = Type::new(None, None, kind, is_const); + let id = ItemId::next(); + let module = ctx.root_module(); + ctx.add_item(Item::new(id, None, None, module, ItemKind::Type(ty)), + None, None); + id + } + + + fn parse(cursor: clang::Cursor, + parent_id: Option, + context: &mut BindgenContext) -> Result { + use ir::function::Function; + use ir::module::Module; + use ir::var::Var; + + if !cursor.is_valid() { + return Err(ParseError::Continue); + } + + let comment = cursor.raw_comment(); + let annotations = Annotations::new(&cursor); + + // FIXME: The current_module logic is not really accurate. We should be + // able to index modules by their Cursor, and locate the proper module + // for a given item. + // + // We don't support modules properly though, so there's no rush for + // this. + let current_module = context.current_module(); + macro_rules! try_parse { + ($what:ident) => { + match $what::parse(cursor, context) { + Ok(ParseResult::New(item, declaration)) => { + let id = ItemId::next(); + context.add_item(Item::new(id, comment, annotations, + parent_id.unwrap_or(current_module), + ItemKind::$what(item)), + declaration, + Some(cursor)); + return Ok(id); + } + Ok(ParseResult::AlreadyResolved(id)) => { + return Ok(id); + } + Err(ParseError::Recurse) => return Err(ParseError::Recurse), + Err(ParseError::Continue) => {}, + } + } + } + + try_parse!(Module); + + // NOTE: Is extremely important to parse functions and vars **before** + // types. Otherwise we can parse a function declaration as a type + // (which is legal), and lose functions to generate. + // + // In general, I'm not totally confident this split between + // ItemKind::Function and TypeKind::FunctionSig is totally worth it, but + // I guess we can try. + try_parse!(Function); + try_parse!(Var); + + // Types are sort of special, so to avoid parsing template classes + // twice, handle them separately. + { + let definition = cursor.definition(); + let applicable_cursor = if definition.is_valid() { + definition + } else { + cursor + }; + match Self::from_ty(&applicable_cursor.cur_type(), + Some(applicable_cursor), parent_id, context) + { + Ok(ty) => return Ok(ty), + Err(ParseError::Recurse) => return Err(ParseError::Recurse), + Err(ParseError::Continue) => {}, + } + } + + // Guess how does clang treat extern "C" blocks? + if cursor.kind() == clangll::CXCursor_UnexposedDecl { + Err(ParseError::Recurse) + } else { + error!("Unhandled cursor kind: {}", ::clang::kind_to_str(cursor.kind())); + Err(ParseError::Continue) + } + } + + fn from_ty_or_ref(ty: clang::Type, + location: Option, + parent_id: Option, + context: &mut BindgenContext) -> ItemId { + debug!("from_ty_or_ref: {:?}, {:?}, {:?}", ty, location, parent_id); + + if context.collected_typerefs() { + debug!("refs already collected, resolving directly"); + return Self::from_ty(&ty, location, parent_id, context) + .expect("Unable to resolve type"); + } + + if let Some(ty) = context.builtin_or_resolved_ty(parent_id, &ty, location) { + debug!("{:?} already resolved: {:?}", ty, location); + return ty; + } + + debug!("New unresolved type reference: {:?}, {:?}", ty, location); + + let is_const = ty.is_const(); + let kind = TypeKind::UnresolvedTypeRef(ty, location); + let id = ItemId::next(); + let current_module = context.current_module(); + context.add_item(Item::new(id, None, None, + parent_id.unwrap_or(current_module), + ItemKind::Type(Type::new(None, None, kind, is_const))), + Some(clang::Cursor::null()), + None); + id + } + + + fn from_ty(ty: &clang::Type, + location: Option, + parent_id: Option, + context: &mut BindgenContext) -> Result { + Self::from_ty_with_id(ItemId::next(), ty, location, parent_id, context) + } + + fn from_ty_with_id(id: ItemId, + ty: &clang::Type, + location: Option, + parent_id: Option, + context: &mut BindgenContext) -> Result { + use clangll::*; + + let decl = { + let decl = ty.declaration(); + let definition = decl.definition(); + if definition.is_valid() { + definition + } else { + decl + } + }; + + let comment = + decl.raw_comment() + .or_else(|| location.as_ref().and_then(|l| l.raw_comment())); + let annotations = + Annotations::new(&decl) + .or_else(|| location.as_ref().and_then(|l| Annotations::new(l))); + + if let Some(ref replaced) = annotations.as_ref().and_then(|a| a.use_instead_of()) { + context.replace(replaced, id); + } + + if let Some(ty) = context.builtin_or_resolved_ty(parent_id, ty, location) { + return Ok(ty); + } + + // First, check we're not recursing. + let mut valid_decl = decl.kind() != CXCursor_NoDeclFound; + let declaration_to_look_for = if valid_decl { + decl.canonical() + } else if location.is_some() && location.unwrap().kind() == CXCursor_ClassTemplate { + valid_decl = true; + location.unwrap() + } else { + decl + }; + + if valid_decl { + if let Some(&(_, item_id)) = context.currently_parsed_types.iter().find(|&&(d, _)| d == declaration_to_look_for) { + debug!("Avoiding recursion parsing type: {:?}", ty); + return Ok(item_id); + } + } + + let current_module = context.current_module(); + if valid_decl { + context.currently_parsed_types.push((declaration_to_look_for, id)); + } + + let result = Type::from_clang_ty(id, ty, location, parent_id, context); + let ret = match result { + Ok(ParseResult::AlreadyResolved(ty)) => Ok(ty), + Ok(ParseResult::New(item, declaration)) => { + context.add_item(Item::new(id, comment, annotations, + parent_id.unwrap_or(current_module), + ItemKind::Type(item)), + declaration, + location); + Ok(id) + } + Err(ParseError::Continue) => Err(ParseError::Continue), + Err(ParseError::Recurse) => { + debug!("Item::from_ty recursing in the ast"); + let mut result = Err(ParseError::Recurse); + if let Some(ref location) = location { + // Need to pop here, otherwise we'll get stuck. + // + // TODO: Find a nicer interface, really. Also, the + // declaration_to_look_for suspiciously shares a lot of + // logic with ir::context, so we should refactor that. + if valid_decl { + let (popped_decl, _) = context.currently_parsed_types.pop().unwrap(); + assert_eq!(popped_decl, declaration_to_look_for); + } + + location.visit(|cur, _other| { + use clangll::*; + result = Item::from_ty_with_id(id, ty, Some(*cur), parent_id, context); + match result { + Ok(..) => CXChildVisit_Break, + Err(ParseError::Recurse) => CXChildVisit_Recurse, + Err(ParseError::Continue) => CXChildVisit_Continue, + } + }); + + if valid_decl { + context.currently_parsed_types.push((declaration_to_look_for, id)); + } + } + // If we have recursed into the AST all we know, and we still + // haven't found what we've got, let's + // just make a named type. + // + // This is what happens with some template members, for example. + // + // FIXME: Maybe we should restrict this to things with parent? + // It's harmless, but if we restrict that, then + // tests/headers/nsStyleAutoArray.hpp crashes. + if let Err(ParseError::Recurse) = result { + Ok(Self::named_type_with_id(id, ty.spelling(), + None, + parent_id.unwrap_or(context.current_module()), + context)) + } else { + result + } + } + }; + + if valid_decl { + let (popped_decl, _) = context.currently_parsed_types.pop().unwrap(); + assert_eq!(popped_decl, declaration_to_look_for); + } + + ret + } + + /// A named type is a template parameter, e.g., the "T" in Foo. They're + /// always local so it's the only exception when there's no declaration for + /// a type. + /// + /// It must have an id, and must not be the current module id. Ideally we + /// could assert the parent id is a Comp(..) type, but that info isn't + /// available yet. + fn named_type_with_id(id: ItemId, + name: S, + default: Option, + parent_id: ItemId, + context: &mut BindgenContext) -> ItemId + where S: Into + { + // see tests/headers/const_tparam.hpp + // and tests/headers/variadic_tname.hpp + let name = name.into().replace("const ", "").replace(".", ""); + + context.add_item(Item::new(id, None, None, parent_id, + ItemKind::Type(Type::named(name, default))), + None, + None); + + id + } + + fn named_type(name: S, + default: Option, + parent_id: ItemId, + context: &mut BindgenContext) -> ItemId + where S: Into + { + Self::named_type_with_id(ItemId::next(), name, default, parent_id, context) + } +} + +impl ItemCanonicalName for Item { + fn canonical_name(&self, ctx: &BindgenContext) -> String { + debug_assert!(ctx.in_codegen_phase(), + "You're not supposed to call this yet"); + if let Some(other_canon_type) = self.annotations.use_instead_of() { + return other_canon_type.to_owned(); + } + self.real_canonical_name(ctx, ctx.options().enable_cxx_namespaces) + } +} + +impl ItemCanonicalPath for Item { + fn canonical_path(&self, ctx: &BindgenContext) -> Vec { + if !ctx.options().enable_cxx_namespaces { + return vec![self.canonical_name(ctx)]; + } + + if self.id() == ctx.root_module() { + match self.kind { + ItemKind::Module(ref module) => { + return vec![module.name().unwrap().into()] + } + _ => panic!("Something has wrong horribly wrong"), + } + } + + // TODO: This duplicates too much logic with real_canonical_name. + if let ItemKind::Type(ref ty) = *self.kind() { + match *ty.kind() { + TypeKind::Comp(ref ci) if ci.is_template_specialization() => { + return ci.specialized_template().unwrap().canonical_path(ctx); + }, + TypeKind::ResolvedTypeRef(inner) | + TypeKind::TemplateRef(inner, _) => { + return inner.canonical_path(ctx); + } + TypeKind::Named(ref name, _) => { + return vec![name.clone()]; + } + _ => {} + } + } + + let mut parent_path = self.parent_id().canonical_path(&ctx); + parent_path.push(self.real_canonical_name(ctx, true)); + + parent_path + } +} diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs new file mode 100644 index 0000000000..b6f317a7db --- /dev/null +++ b/src/ir/item_kind.rs @@ -0,0 +1,89 @@ +use super::function::Function; +use super::module::Module; +use super::ty::Type; +use super::var::Var; + +/// A item we parse and translate. +#[derive(Debug)] +pub enum ItemKind { + /// A module, created implicitly once (the root module), or via C++ + /// namespaces. + Module(Module), + + /// A type declared in any of the multiple ways it can be declared. + Type(Type), + + /// A function or method declaration. + Function(Function), + /// A variable declaration, most likely a static. + Var(Var), +} + +impl ItemKind { + pub fn as_module(&self) -> Option<&Module> { + match *self { + ItemKind::Module(ref module) => Some(module), + _ => None, + } + } + + pub fn is_module(&self) -> bool { + self.as_module().is_some() + } + + pub fn expect_module(&self) -> &Module { + self.as_module().expect("Not a module") + } + + pub fn as_function(&self) -> Option<&Function> { + match *self { + ItemKind::Function(ref func) => Some(func), + _ => None, + } + } + + pub fn is_function(&self) -> bool { + self.as_function().is_some() + } + + pub fn expect_function(&self) -> &Function { + self.as_function().expect("Not a function") + } + + pub fn as_type(&self) -> Option<&Type> { + match *self { + ItemKind::Type(ref ty) => Some(ty), + _ => None, + } + } + + pub fn as_type_mut(&mut self) -> Option<&mut Type> { + match *self { + ItemKind::Type(ref mut ty) => Some(ty), + _ => None, + } + } + + pub fn is_type(&self) -> bool { + self.as_type().is_some() + } + + pub fn expect_type(&self) -> &Type { + self.as_type().expect("Not a type") + } + + pub fn as_var(&self) -> Option<&Var> { + match *self { + ItemKind::Var(ref v) => Some(v), + _ => None, + } + } + + pub fn is_var(&self) -> bool { + self.as_var().is_some() + } + + pub fn expect_var(&self) -> &Var { + self.as_var().expect("Not a var") + } +} diff --git a/src/ir/layout.rs b/src/ir/layout.rs new file mode 100644 index 0000000000..d672ebea27 --- /dev/null +++ b/src/ir/layout.rs @@ -0,0 +1,26 @@ + +/// A type that represents the struct layout of a type. +#[derive(Debug, Clone, Copy)] +pub struct Layout { + pub size: usize, + pub align: usize, + pub packed: bool, +} + +impl Layout { + pub fn new(size: usize, align: usize) -> Self { + Layout { + size: size, + align: align, + packed: false, + } + } + + pub fn is_zero(&self) -> bool { + self.size == 0 && self.align == 0 + } + + pub fn zero() -> Self { + Self::new(0, 0) + } +} diff --git a/src/ir/mod.rs b/src/ir/mod.rs new file mode 100644 index 0000000000..07ac3059f6 --- /dev/null +++ b/src/ir/mod.rs @@ -0,0 +1,12 @@ +pub mod annotations; +pub mod comp; +pub mod context; +pub mod enum_ty; +pub mod function; +pub mod int; +pub mod item; +pub mod item_kind; +pub mod layout; +pub mod module; +pub mod ty; +pub mod var; diff --git a/src/ir/module.rs b/src/ir/module.rs new file mode 100644 index 0000000000..77fee5ef4f --- /dev/null +++ b/src/ir/module.rs @@ -0,0 +1,52 @@ +use super::context::BindgenContext; +use super::item::ItemId; +use clang; +use parse::{ClangSubItemParser, ParseError, ParseResult}; +use parse_one; + +/// A module, as in, a C++ namespace. +#[derive(Clone, Debug)] +pub struct Module { + /// The name of the module, or none if it's anonymous. + name: Option, + /// The children of this module, just here for convenience. + children_ids: Vec, +} + +impl Module { + pub fn new(name: Option) -> Self { + Module { + name: name, + children_ids: vec![], + } + } + + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(|n| &**n) + } + + pub fn children_mut(&mut self) -> &mut Vec { + &mut self.children_ids + } + + pub fn children(&self) -> &[ItemId] { + &self.children_ids + } +} + +impl ClangSubItemParser for Module { + fn parse(cursor: clang::Cursor, ctx: &mut BindgenContext) -> Result, ParseError> { + use clangll::*; + match cursor.kind() { + CXCursor_Namespace => { + let module_id = ctx.module(cursor); + ctx.with_module(module_id, |ctx, children| { + cursor.visit(|cursor, _| parse_one(ctx, *cursor, Some(module_id), children)) + }); + + Ok(ParseResult::AlreadyResolved(module_id)) + } + _ => Err(ParseError::Continue) + } + } +} diff --git a/src/ir/ty.rs b/src/ir/ty.rs new file mode 100644 index 0000000000..b044843703 --- /dev/null +++ b/src/ir/ty.rs @@ -0,0 +1,537 @@ +use super::comp::CompInfo; +use super::enum_ty::Enum; +use super::function::FunctionSig; +use super::item::{Item, ItemId}; +use super::int::IntKind; +use super::layout::Layout; +use super::context::BindgenContext; +use super::context::TypeResolver; +use parse::{ClangItemParser, ParseResult, ParseError}; +use clang::{self, Cursor}; + +#[derive(Debug)] +pub struct Type { + /// The name of the type, or None if it was an unnamed struct or union. + name: Option, + /// The layout of the type, if known. + layout: Option, + /// Whether this type is marked as opaque. + opaque: bool, + /// Whether this type is marked as hidden. + hide: bool, + /// The inner kind of the type + kind: TypeKind, + /// Whether this type is const-qualified. + is_const: bool, +} + +pub const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32usize; + +impl Type { + pub fn as_comp(&self) -> Option<&CompInfo> { + match self.kind { + TypeKind::Comp(ref ci) => Some(ci), + _ => None, + } + } + + pub fn new(name: Option, + layout: Option, + kind: TypeKind, + is_const: bool) -> Self { + Type { + name: name, + layout: layout, + opaque: false, + hide: false, + kind: kind, + is_const: is_const, + } + } + + pub fn kind(&self) -> &TypeKind { + &self.kind + } + + pub fn kind_mut(&mut self) -> &mut TypeKind { + &mut self.kind + } + + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(|name| &**name) + } + + pub fn is_comp(&self) -> bool { + match self.kind { + TypeKind::Comp(..) => true, + _ => false, + } + } + + pub fn is_named(&self) -> bool { + match self.kind { + TypeKind::Named(..) => true, + _ => false, + } + } + + pub fn is_builtin_or_named(&self) -> bool { + match self.kind { + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::Function(..) | + TypeKind::Array(..) | + TypeKind::Reference(..) | + TypeKind::Pointer(..) | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Named(..) => true, + _ => false, + } + } + + /// Creates a new named type, with name `name`. + pub fn named(name: String, default: Option) -> Self { + assert!(!name.is_empty()); + // TODO: stop duplicating the name, it's stupid. + let kind = TypeKind::Named(name.clone(), default); + Self::new(Some(name), None, kind, false) + } + + pub fn is_integer_literal(&self) -> bool { + match *self.kind() { + TypeKind::Int(..) => true, + _ => false, + } + } + + pub fn is_const(&self) -> bool { + self.is_const + } + + pub fn layout(&self, type_resolver: &TypeResolver) -> Option { + use std::mem; + + self.layout.or_else(|| { + match self.kind { + TypeKind::Comp(ref ci) + => ci.layout(type_resolver), + // FIXME(emilio): This is a hack for anonymous union templates. + // Use the actual pointer size! + TypeKind::Pointer(..) + => Some(Layout::new(mem::size_of::<*mut ()>(), mem::align_of::<*mut ()>())), + TypeKind::ResolvedTypeRef(inner) + => type_resolver.resolve_type(inner).layout(type_resolver), + _ => None, + } + }) + } + + pub fn is_opaque(&self, _type_resolver: &TypeResolver) -> bool { + self.opaque + } + + pub fn can_derive_debug(&self, type_resolver: &TypeResolver) -> bool { + !self.is_opaque(type_resolver) && match self.kind { + TypeKind::Array(t, len) => { + len <= RUST_DERIVE_IN_ARRAY_LIMIT && + type_resolver.resolve_type(t).can_derive_debug(type_resolver) + } + TypeKind::ResolvedTypeRef(t) | + TypeKind::Alias(_, t) => { + type_resolver.resolve_type(t).can_derive_debug(type_resolver) + } + TypeKind::Comp(ref info) => { + info.can_derive_debug(type_resolver, self.layout(type_resolver)) + } + _ => true, + } + } + + // For some reason, deriving copies of an array of a type that is not known + // to be copy is a compile error. e.g.: + // + // #[derive(Copy)] + // struct A { + // member: T, + // } + // + // is fine, while: + // + // #[derive(Copy)] + // struct A { + // member: [T; 1], + // } + // + // is an error. + // + // That's the point of the existence of can_derive_copy_in_array(). + pub fn can_derive_copy_in_array(&self, type_resolver: &TypeResolver) -> bool { + match self.kind { + TypeKind::ResolvedTypeRef(t) | + TypeKind::Alias(_, t) | + TypeKind::Array(t, _) => { + type_resolver.resolve_type(t) + .can_derive_copy_in_array(type_resolver) + } + TypeKind::Named(..) => false, + _ => self.can_derive_copy(type_resolver), + } + } + + pub fn can_derive_copy(&self, type_resolver: &TypeResolver) -> bool { + !self.is_opaque(type_resolver) && match self.kind { + TypeKind::Array(t, len) => { + len <= RUST_DERIVE_IN_ARRAY_LIMIT && + type_resolver.resolve_type(t).can_derive_copy_in_array(type_resolver) + } + TypeKind::ResolvedTypeRef(t) | + TypeKind::TemplateRef(t, _) | + TypeKind::Alias(_, t) => { + type_resolver.resolve_type(t).can_derive_copy(type_resolver) + } + TypeKind::Comp(ref info) => { + info.can_derive_copy(type_resolver) + } + _ => true, + } + } + + pub fn has_vtable(&self, type_resolver: &TypeResolver) -> bool { + // FIXME: Can we do something about template parameters? Huh... + match self.kind { + TypeKind::TemplateRef(t, _) | + TypeKind::Alias(_, t) | + TypeKind::ResolvedTypeRef(t) | + TypeKind::Array(t, _) => { + type_resolver.resolve_type(t).has_vtable(type_resolver) + } + TypeKind::Comp(ref info) => { + info.has_vtable(type_resolver) + } + _ => false, + } + + } + + pub fn has_destructor(&self, type_resolver: &TypeResolver) -> bool { + self.is_opaque(type_resolver) || match self.kind { + TypeKind::TemplateRef(t, _) | + TypeKind::Alias(_, t) | + TypeKind::ResolvedTypeRef(t) | + TypeKind::Array(t, _) => { + type_resolver.resolve_type(t).has_destructor(type_resolver) + } + TypeKind::Comp(ref info) => { + info.has_destructor(type_resolver) + } + _ => false, + } + } + + pub fn signature_contains_named_type(&self, + type_resolver: &TypeResolver, + ty: &Type) -> bool { + debug_assert!(ty.is_named()); + let name = match *ty.kind() { + TypeKind::Named(ref name, _) => name, + _ => unreachable!(), + }; + + match self.kind { + TypeKind::Named(ref this_name, _) + => this_name == name, + TypeKind::ResolvedTypeRef(t) | + TypeKind::Array(t, _) | + TypeKind::Pointer(t) + => type_resolver.resolve_type(t) + .signature_contains_named_type(type_resolver, ty), + TypeKind::TemplateRef(_inner, ref template_args) => { + template_args.iter().any(|arg| { + type_resolver.resolve_type(*arg) + .signature_contains_named_type(type_resolver, ty) + }) + } + TypeKind::Comp(ref ci) + => ci.signature_contains_named_type(type_resolver, ty), + _ => false, + } + } + + pub fn canonical_type<'tr>(&'tr self, type_resolver: &'tr TypeResolver) -> &'tr Type { + match self.kind { + TypeKind::Named(..) | + TypeKind::Array(..) | + TypeKind::Comp(..) | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Function(..) | + TypeKind::Enum(..) | + TypeKind::Reference(..) | + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::Pointer(..) => self, + + TypeKind::ResolvedTypeRef(inner) | + TypeKind::Alias(_, inner) | + TypeKind::TemplateRef(inner, _) + => type_resolver.resolve_type(inner).canonical_type(type_resolver), + + TypeKind::UnresolvedTypeRef(..) + => unreachable!("Should have been resolved after parsing!"), + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum FloatKind { + Float, + Double, + LongDouble, +} + +/// The different kinds of types that we can parse. +/// +/// TODO: The name in the Alias and Named kinds is a bit unsound, should be in +/// type.name? +#[derive(Debug)] +pub enum TypeKind { + /// The void type. + Void, + /// The nullptr_t type. + NullPtr, + /// A compound type, that is, a class, struct, or union. + Comp(CompInfo), + /// An integer type, of a given kind. `bool` and `char` are also considered + /// integers. + Int(IntKind), + /// A floating point type. + Float(FloatKind), + /// A type alias, with a name, that points to another type. + Alias(String, ItemId), + /// An array of a type and a lenght. + Array(ItemId, usize), + /// A function type, with a given signature. + Function(FunctionSig), + /// An enum type. + Enum(Enum), + /// A pointer to a type. The bool field represents whether it's const or + /// not. + Pointer(ItemId), + /// A reference to a type, as in: int& foo(). + Reference(ItemId), + /// A reference to a template, with different template parameter names. To + /// see why this is needed, check out the creation of this variant in + /// `Type::from_clang_ty`. + TemplateRef(ItemId, Vec), + + /// A reference to a yet-to-resolve type. This stores the clang cursor + /// itself, and postpones its resolution. + /// + /// These are gone in a phase after parsing where these are mapped to + /// already known types, and are converted to ResolvedTypeRef. + /// + /// see tests/headers/typeref.hpp to see somewhere where this is a problem. + UnresolvedTypeRef(clang::Type, Option), + ResolvedTypeRef(ItemId), + + /// A named type, that is, a template parameter, with an optional default + /// type. + Named(String, Option), +} + +impl Type { + pub fn is_unsized(&self, type_resolver: &TypeResolver) -> bool { + match self.kind { + TypeKind::Void => true, + TypeKind::Comp(ref ci) => ci.is_unsized(type_resolver), + TypeKind::Array(inner, size) => { + size == 0 || + type_resolver.resolve_type(inner).is_unsized(type_resolver) + } + TypeKind::ResolvedTypeRef(inner) | + TypeKind::Alias(_, inner) | + TypeKind::TemplateRef(inner, _) + => type_resolver.resolve_type(inner).is_unsized(type_resolver), + TypeKind::Named(..) | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Function(..) | + TypeKind::Enum(..) | + TypeKind::Reference(..) | + TypeKind::NullPtr | + TypeKind::Pointer(..) => false, + + TypeKind::UnresolvedTypeRef(..) + => unreachable!("Should have been resolved after parsing!"), + } + } + + pub fn from_clang_ty(potential_id: ItemId, + ty: &clang::Type, + location: Option, + parent_id: Option, + ctx: &mut BindgenContext) -> Result, ParseError> { + use clangll::*; + if let Some(ty) = ctx.builtin_or_resolved_ty(parent_id, ty, location) { + debug!("{:?} already resolved: {:?}", ty, location); + return Ok(ParseResult::AlreadyResolved(ty)); + } + + let layout = ty.fallible_layout().ok(); + let cursor = ty.declaration(); + let mut name = cursor.spelling(); + + debug!("from_clang_ty: {:?}, ty: {:?}, loc: {:?}", potential_id, ty, location); + debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types); + + let canonical_ty = ty.canonical_type(); + let kind = match ty.kind() { + CXType_Unexposed if *ty != canonical_ty && + canonical_ty.kind() != CXType_Invalid => { + debug!("Looking for canonical type: {:?}", canonical_ty); + return Self::from_clang_ty(potential_id, &canonical_ty, + location, parent_id, ctx); + } + CXType_Unexposed | + CXType_Invalid => { + // For some reason Clang doesn't give us any hint + // in some situations where we should generate a + // function pointer (see + // tests/headers/func_ptr_in_struct.h), so we do a + // guess here trying to see if it has a valid return + // type. + if ty.ret_type().kind() != CXType_Invalid { + let signature = + try!(FunctionSig::from_ty(ty, &location.unwrap_or(cursor), ctx)); + TypeKind::Function(signature) + // Same here, with template specialisations we can safely assume + // this is a Comp(..) + } else if ty.num_template_args() > 0 { + debug!("Template specialization: {:?}", ty); + let complex = + CompInfo::from_ty(potential_id, ty, location, ctx) + .expect("C'mon"); + TypeKind::Comp(complex) + } else if let Some(location) = location { + match location.kind() { + CXCursor_ClassTemplatePartialSpecialization | + CXCursor_ClassTemplate => { + name = location.spelling(); + let complex = + CompInfo::from_ty(potential_id, ty, Some(location), ctx) + .expect("C'mon"); + TypeKind::Comp(complex) + } + CXCursor_TemplateRef => { + let referenced = location.referenced(); + return Self::from_clang_ty(potential_id, + &referenced.cur_type(), + Some(referenced), + parent_id, + ctx); + } + CXCursor_TypeRef => { + let referenced = location.referenced(); + // FIXME: use potential id? + return Ok(ParseResult::AlreadyResolved( + Item::from_ty_or_ref(referenced.cur_type(), + Some(referenced), + parent_id, + ctx))); + } + _ => { + if ty.kind() == CXType_Unexposed { + warn!("Unexposed type {:?}, recursing inside, loc: {:?}", ty, location); + return Err(ParseError::Recurse); + } + + error!("invalid type {:?}", ty); + return Err(ParseError::Continue); + } + } + } else { + // TODO: Don't duplicate this! + if ty.kind() == CXType_Unexposed { + warn!("Unexposed type {:?}, recursing inside", ty); + return Err(ParseError::Recurse); + } + + error!("invalid type `{}`", ty.spelling()); + return Err(ParseError::Continue); + } + } + // NOTE: We don't resolve pointers eagerly because the pointee type + // might not have been parsed, and if it contains templates or + // something else we might get confused, see the comment inside + // TypeRef. + // + // We might need to, though, if the context is already in the + // process of resolving them. + CXType_MemberPointer | + CXType_Pointer => { + let inner = + Item::from_ty_or_ref(ty.pointee_type(), Some(ty.pointee_type().declaration()), parent_id, ctx); + TypeKind::Pointer(inner) + } + // XXX: RValueReference is most likely wrong, but I don't think we + // can even add bindings for that, so huh. + CXType_RValueReference | + CXType_LValueReference => { + let inner = + Item::from_ty_or_ref(ty.pointee_type(), Some(ty.pointee_type().declaration()), parent_id, ctx); + TypeKind::Reference(inner) + } + // XXX DependentSizedArray is wrong + CXType_VariableArray | + CXType_DependentSizedArray | + CXType_IncompleteArray => { + let inner = Item::from_ty(&ty.elem_type(), location, parent_id, ctx) + .expect("Not able to resolve array element?"); + TypeKind::Pointer(inner) + } + CXType_FunctionNoProto | + CXType_FunctionProto => { + let signature = try!(FunctionSig::from_ty(ty, &location.unwrap_or(cursor), ctx)); + TypeKind::Function(signature) + } + CXType_Typedef => { + let inner = cursor.typedef_type(); + let inner = + Item::from_ty_or_ref(inner, location, parent_id, ctx); + TypeKind::Alias(ty.spelling(), inner) + } + CXType_Enum => { + let enum_ = Enum::from_ty(ty, ctx) + .expect("Not an enum?"); + TypeKind::Enum(enum_) + } + CXType_Record => { + let complex = CompInfo::from_ty(potential_id, ty, location, ctx) + .expect("Not a complex type?"); + TypeKind::Comp(complex) + } + CXType_ConstantArray => { + let inner = Item::from_ty(&ty.elem_type(), location, parent_id, ctx) + .expect("Not able to resolve array element?"); + TypeKind::Array(inner, ty.array_size()) + } + #[cfg(not(feature="llvm_stable"))] + CXType_Elaborated => { + return Self::from_clang_ty(potential_id, &ty.named(), + location, parent_id, ctx); + } + _ => { + error!("unsupported type {:?} at {:?}", ty, location); + return Err(ParseError::Continue); + } + }; + + let name = if name.is_empty() { None } else { Some(name) }; + let is_const = ty.is_const(); + + let ty = Type::new(name, layout, kind, is_const); + // TODO: maybe declaration.canonical()? + Ok(ParseResult::New(ty, Some(cursor.canonical()))) + } +} diff --git a/src/ir/var.rs b/src/ir/var.rs new file mode 100644 index 0000000000..ac59973bcb --- /dev/null +++ b/src/ir/var.rs @@ -0,0 +1,160 @@ +use super::item::{Item, ItemId}; +use super::context::BindgenContext; +use super::ty::TypeKind; +use super::int::IntKind; +use super::function::cursor_mangling; +use parse::{ClangItemParser, ClangSubItemParser, ParseResult, ParseError}; +use clang; + +#[derive(Debug)] +pub struct Var { + /// The name of the variable. + name: String, + /// The mangled name of the variable. + mangled_name: Option, + /// The type of the variable. + ty: ItemId, + /// TODO: support non-integer constants? + /// The integer value of the variable. + val: Option, + /// Whether this variable is const. + is_const: bool, +} + +impl Var { + pub fn new(name: String, + mangled: Option, + ty: ItemId, + val: Option, + is_const: bool) -> Var { + assert!(!name.is_empty()); + Var { + name: name, + mangled_name: mangled, + ty: ty, + val: val, + is_const: is_const, + } + } + + pub fn is_const(&self) -> bool { + self.is_const + } + + pub fn val(&self) -> Option { + self.val + } + + pub fn ty(&self) -> ItemId { + self.ty + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn mangled_name(&self) -> Option<&str> { + self.mangled_name.as_ref().map(|n| &**n) + } +} + +impl ClangSubItemParser for Var { + fn parse(cursor: clang::Cursor, + context: &mut BindgenContext) -> Result, ParseError> { + use clangll::*; + match cursor.kind() { + CXCursor_MacroDefinition => { + let value = match parse_int_literal_tokens(&cursor, context.translation_unit(), 1) { + None => return Err(ParseError::Continue), + Some(v) => v, + }; + + let name = cursor.spelling(); + if name.is_empty() { + warn!("Empty macro name?"); + return Err(ParseError::Continue); + } + + if context.parsed_macro(&name) { + warn!("Duplicated macro definition: {}", name); + return Err(ParseError::Continue); + } + context.note_parsed_macro(name.clone()); + + let ty = if value.abs() > u32::max_value() as i64 { + Item::builtin_type(TypeKind::Int(IntKind::ULongLong), true, context) + } else { + Item::builtin_type(TypeKind::Int(IntKind::UInt), true, context) + }; + + Ok(ParseResult::New(Var::new(name, None, ty, Some(value), true), Some(cursor))) + } + CXCursor_VarDecl => { + let name = cursor.spelling(); + if name.is_empty() { + warn!("Empty constant name?"); + return Err(ParseError::Continue); + } + + let ty = cursor.cur_type(); + + // XXX this is redundant, remove! + let is_const = ty.is_const(); + + let ty = Item::from_ty(&ty, Some(cursor), None, context) + .expect("Unable to resolve constant type?"); + + let mut value = None; + + // Note: Ty might not be totally resolved yet, see + // tests/headers/inner_const.hpp + // + // That's fine because in that case we know it's not a literal. + if context.safe_resolve_type(ty).map_or(false, |t| t.is_integer_literal()) { + // Try to parse a literal token value + cursor.visit(|c, _| { + if c.kind() == CXCursor_IntegerLiteral { + value = + parse_int_literal_tokens(&c, + context.translation_unit(), + 0); + } + CXChildVisit_Continue + }); + } + + let mangling = cursor_mangling(&cursor); + + let var = Var::new(name, mangling, ty, value, is_const); + Ok(ParseResult::New(var, Some(cursor))) + + } + _ => { + /* TODO */ + Err(ParseError::Continue) + } + } + } +} + +fn parse_int_literal_tokens(cursor: &clang::Cursor, + unit: &clang::TranslationUnit, + which: usize) -> Option { + use clangll::CXToken_Literal; + let tokens = match unit.tokens(cursor) { + None => return None, + Some(tokens) => tokens, + }; + + if tokens.len() <= which || tokens[which].kind != CXToken_Literal { + return None; + } + + let s = &tokens[which].spelling; + // TODO: try to preserve hex literals? + if s.starts_with("0x") { + i64::from_str_radix(&s[2..], 16).ok() + } else { + s.parse().ok() + } +} diff --git a/src/lib.rs b/src/lib.rs index a6b33c8e32..33bd66e706 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,19 +4,34 @@ #![cfg_attr(feature = "clippy", feature(plugin))] #![cfg_attr(feature = "clippy", plugin(clippy))] +// To avoid rather annoying warnings when matching with CXCursor_xxx as a +// constant. +#![allow(non_upper_case_globals)] + extern crate syntex_syntax as syntax; extern crate aster; extern crate quasi; extern crate clang_sys; extern crate libc; +extern crate regex; #[macro_use] extern crate log; -use std::collections::HashSet; -use std::default::Default; -use std::io::{Write, self}; +mod clangll; +mod clang; +mod ir; +mod parse; +mod regex_set; +mod codegen { + include!(concat!(env!("OUT_DIR"), "/codegen.rs")); +} + +use std::borrow::Borrow; +use std::io::{self, Write}; use std::fs::OpenOptions; use std::path::Path; +use std::marker; +use std::collections::HashSet; use syntax::ast; use syntax::codemap::{DUMMY_SP, Span}; @@ -24,21 +39,16 @@ use syntax::print::pprust; use syntax::print::pp::eof; use syntax::ptr::P; -use types::ModuleMap; +use ir::context::BindgenContext; +use ir::item::{Item, ItemId}; +use parse::{ClangItemParser, ParseError}; +use regex_set::RegexSet; -mod types; -mod clangll; -mod clang; -mod parser; -mod hacks; -mod gen { - include!(concat!(env!("OUT_DIR"), "/gen.rs")); -} - -#[derive(Clone)] +#[derive(Debug)] pub struct Builder<'a> { options: BindgenOptions, - logger: Option<&'a Logger> + // TODO: Before the logger was here, do we still want the lifetime? + phantom: marker::PhantomData<&'a ()>, } pub fn builder<'a>() -> Builder<'a> { @@ -51,17 +61,22 @@ impl<'a> Builder<'a> { } pub fn match_pat>(&mut self, arg: T) -> &mut Self { - self.options.match_pat.push(arg.into()); + self.options.match_pat.insert(arg.into()); self } - pub fn blacklist_type>(&mut self, arg: T) -> &mut Self { - self.options.blacklist_type.push(arg.into()); + pub fn hide_type>(&mut self, arg: T) -> &mut Self { + self.options.hidden_types.insert(arg.into()); self } pub fn opaque_type>(&mut self, arg: T) -> &mut Self { - self.options.opaque_types.push(arg.into()); + self.options.opaque_types.insert(arg.into()); + self + } + + pub fn whitelisted_type>(&mut self, arg: &T) -> &mut Self { + self.options.whitelisted_types.insert(arg); self } @@ -124,36 +139,34 @@ impl<'a> Builder<'a> { self } - pub fn log(&mut self, logger: &'a Logger) -> &mut Self { - self.logger = Some(logger); - self - } - pub fn disable_class_constants(&mut self) -> &mut Self { self.options.class_constants = false; self } - pub fn generate(&self) -> Result { - Bindings::generate(&self.options, self.logger, None) + pub fn generate(self) -> Result { + Bindings::generate(self.options, None) } } impl<'a> Default for Builder<'a> { fn default() -> Builder<'a> { Builder { - logger: None, - options: Default::default() + options: Default::default(), + phantom: marker::PhantomData, } } } -#[derive(Clone)] /// Deprecated - use a `Builder` instead +#[derive(Debug)] pub struct BindgenOptions { - pub match_pat: Vec, - pub blacklist_type: Vec, - pub opaque_types: Vec, + pub match_pat: HashSet, + pub hidden_types: HashSet, + pub opaque_types: HashSet, + pub whitelisted_types: RegexSet, + pub whitelisted_functions: RegexSet, + pub whitelisted_vars: RegexSet, pub builtins: bool, pub rust_enums: bool, pub links: Vec<(String, LinkType)>, @@ -171,7 +184,7 @@ pub struct BindgenOptions { pub class_constants: bool, /// Wether to generate names that are **directly** under namespaces. pub namespaced_constants: bool, - // whether to use msvc mangling rules + /// Whether to use msvc mangling rules pub msvc_mangling: bool, pub override_enum_ty: String, pub raw_lines: Vec, @@ -183,9 +196,12 @@ pub struct BindgenOptions { impl Default for BindgenOptions { fn default() -> BindgenOptions { BindgenOptions { - match_pat: vec![], - blacklist_type: vec![], - opaque_types: vec![], + match_pat: Default::default(), + hidden_types: Default::default(), + opaque_types: Default::default(), + whitelisted_types: Default::default(), + whitelisted_functions: Default::default(), + whitelisted_vars: Default::default(), builtins: false, rust_enums: true, links: vec![], @@ -216,11 +232,6 @@ pub enum LinkType { Framework } -pub trait Logger { - fn error(&self, msg: &str); - fn warn(&self, msg: &str); -} - #[derive(Debug, Clone)] pub struct Bindings { module: ast::Mod, @@ -229,25 +240,20 @@ pub struct Bindings { impl Bindings { /// Deprecated - use a `Builder` instead - pub fn generate(options: &BindgenOptions, logger: Option<&Logger>, span: Option) -> Result { - let l = DummyLogger; - let logger = logger.unwrap_or(&l as &Logger); - + pub fn generate(options: BindgenOptions, span: Option) -> Result { let span = span.unwrap_or(DUMMY_SP); - let module_map = try!(parse_headers(options, logger)); + let mut context = BindgenContext::new(options); + parse(&mut context); let module = ast::Mod { inner: span, - items: gen::gen_mods(&options.links[..], - module_map, - options.clone(), - span) + items: codegen::codegen(&mut context), }; Ok(Bindings { module: module, - raw_lines: options.raw_lines.clone(), + raw_lines: context.options().raw_lines.clone(), }) } @@ -290,68 +296,6 @@ impl Bindings { } } - -struct DummyLogger; - -impl Logger for DummyLogger { - fn error(&self, _msg: &str) { } - fn warn(&self, _msg: &str) { } -} - -fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result { - fn str_to_ikind(s: &str) -> Option { - match s { - "uchar" => Some(types::IUChar), - "schar" => Some(types::ISChar), - "ushort" => Some(types::IUShort), - "sshort" => Some(types::IShort), - "uint" => Some(types::IUInt), - "sint" => Some(types::IInt), - "ulong" => Some(types::IULong), - "slong" => Some(types::ILong), - "ulonglong" => Some(types::IULongLong), - "slonglong" => Some(types::ILongLong), - _ => None, - } - } - - // TODO: Unify most of these with BindgenOptions? - let clang_opts = parser::ClangParserOptions { - builtin_names: builtin_names(), - builtins: options.builtins, - match_pat: options.match_pat.clone(), - emit_ast: options.emit_ast, - class_constants: options.class_constants, - namespaced_constants: options.namespaced_constants, - ignore_functions: options.ignore_functions, - ignore_methods: options.ignore_methods, - fail_on_unknown_type: options.fail_on_unknown_type, - enable_cxx_namespaces: options.enable_cxx_namespaces, - override_enum_ty: str_to_ikind(&options.override_enum_ty), - clang_args: options.clang_args.clone(), - opaque_types: options.opaque_types.clone(), - blacklist_type: options.blacklist_type.clone(), - msvc_mangling: options.msvc_mangling, - }; - - parser::parse(clang_opts, logger) -} - -fn builtin_names() -> HashSet { - let mut names = HashSet::new(); - let keys = [ - "__va_list_tag", - "__va_list", - "__builtin_va_list", - ]; - - for s in &keys { - names.insert((*s).to_owned()); - } - - names -} - #[test] fn builder_state() { let logger = DummyLogger; @@ -365,3 +309,57 @@ fn builder_state() { assert!(build.options.clang_args.binary_search(&"example.h".to_owned()).is_ok()); assert!(build.options.links.binary_search(&("m".to_owned(), LinkType::Static)).is_ok()); } + +/// Determines whether the given cursor is in any of the files matched by the +/// options. +fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool { + let (file, _, _, _) = cursor.location().location(); + + match file.name() { + None => ctx.options().builtins, + Some(..) => true, + } +} + +pub fn parse_one(ctx: &mut BindgenContext, + cursor: clang::Cursor, + parent: Option, + children: &mut Vec) -> clangll::Enum_CXVisitorResult { + if !filter_builtins(ctx, &cursor) { + return CXChildVisit_Continue + } + + use clangll::CXChildVisit_Continue; + match Item::parse(cursor, parent, ctx) { + Ok(id) => children.push(id), + Err(ParseError::Continue) => {}, + Err(ParseError::Recurse) => { + cursor.visit(|child, _| parse_one(ctx, *child, parent, children)); + } + } + CXChildVisit_Continue +} + +fn parse(context: &mut BindgenContext) { + use clang::Diagnostic; + use clangll::*; + + for d in context.translation_unit().diags().iter() { + let msg = d.format(Diagnostic::default_opts()); + let is_err = d.severity() >= CXDiagnostic_Error; + println!("{}, err: {}", msg, is_err); + } + + let cursor = context.translation_unit().cursor(); + if context.options().emit_ast { + cursor.visit(|cur, _| clang::ast_dump(cur, 0)); + } + + let root = context.root_module(); + context.with_module(root, |context, children| { + cursor.visit(|cursor, _| parse_one(context, *cursor, None, children)) + }); + + assert!(context.current_module() == context.root_module(), + "How did this happen?"); +} diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000000..39d2644a85 --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,48 @@ +use clang; +use ir::ty::TypeKind; +use ir::item::ItemId; +use ir::context::BindgenContext; + +#[derive(Debug)] +pub enum ParseError { + Recurse, + Continue, +} + +#[derive(Debug)] +pub enum ParseResult { + AlreadyResolved(ItemId), + New(T, Option), +} + +pub trait ClangSubItemParser : Sized { + /// The fact that is a reference guarantees it's holded by the context, and + /// allow returning already existing types. + fn parse(cursor: clang::Cursor, context: &mut BindgenContext) -> Result, ParseError>; +} + +pub trait ClangItemParser: Sized { + fn parse(cursor: clang::Cursor, + parent: Option, + context: &mut BindgenContext) -> Result; + fn from_ty_or_ref(ty: clang::Type, + location: Option, + parent_id: Option, + context: &mut BindgenContext) -> ItemId; + fn from_ty_with_id(id: ItemId, + ty: &clang::Type, + location: Option, + parent: Option, + ctx: &mut BindgenContext) -> Result; + fn from_ty(ty: &clang::Type, + location: Option, + parent: Option, + ctx: &mut BindgenContext) -> Result; + fn named_type(name: S, default: Option, parent: ItemId, + context: &mut BindgenContext) -> ItemId + where S: Into; + fn named_type_with_id(id: ItemId, name: S, default: Option, + parent: ItemId, context: &mut BindgenContext) -> ItemId + where S: Into; + fn builtin_type(kind: TypeKind, is_const: bool, context: &mut BindgenContext) -> ItemId; +} diff --git a/src/parser.rs b/src/parser.rs deleted file mode 100644 index 0e531420f1..0000000000 --- a/src/parser.rs +++ /dev/null @@ -1,1516 +0,0 @@ -#![allow(non_upper_case_globals)] - -use std::collections::{HashMap, HashSet}; -use hacks::refcell::RefCell; -use std::rc::Rc; -use std::path::Path; -use std::cmp; - -use syntax::abi; - -use types as il; -use types::*; -use clang as cx; -use clang::{ast_dump, Comment, Cursor, Diagnostic, TranslationUnit, type_to_str, kind_to_str}; -use clangll::*; - -use super::Logger; - -#[derive(Clone)] -pub struct ClangParserOptions { - pub builtin_names: HashSet, - pub builtins: bool, - pub match_pat: Vec, - pub emit_ast: bool, - pub fail_on_unknown_type: bool, - pub ignore_functions: bool, - pub ignore_methods: bool, - pub enable_cxx_namespaces: bool, - pub class_constants: bool, - pub namespaced_constants: bool, - pub override_enum_ty: Option, - pub clang_args: Vec, - pub opaque_types: Vec, - pub blacklist_type: Vec, - pub msvc_mangling: bool, -} - -struct ClangParserCtx<'a> { - options: ClangParserOptions, - name: HashMap, - builtin_defs: Vec, - module_map: ModuleMap, - current_module_id: ModuleId, - /// This member is used to track down if we're in a namespace if the - /// enable_cxx_namespaces option is disabled. - namespace_depth: usize, - current_translation_unit: TranslationUnit, - logger: &'a (Logger+'a), - err_count: i32, - anonymous_modules_found: usize, -} - -impl<'a> ClangParserCtx<'a> { - fn module(&self, id: &ModuleId) -> &Module { - self.module_map.get(id).expect("Module not found!") - } - - fn current_module(&self) -> &Module { - self.module(&self.current_module_id) - } - - fn in_root_namespace(&self) -> bool { - self.namespace_depth == 0 - } - - fn current_module_mut(&mut self) -> &mut Module { - self.module_map.get_mut(&self.current_module_id).expect("Module not found!") - } -} - -fn cursor_link_name(_: &mut ClangParserCtx, cursor: &Cursor) -> String { - // Try to undo backend linkage munging (prepended _, generally) - let mut mangling = cursor.mangling(); - if cfg!(target_os = "macos") { - mangling.remove(0); - } - mangling -} - -fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool { - let (file, _, _, _) = cursor.location().location(); - - let name = match file.name() { - None => return ctx.options.builtins, - Some(name) => name, - }; - - if ctx.options.match_pat.is_empty() { - return true; - } - - let name = name.replace("\\", "/"); - ctx.options.match_pat.iter().any(|pat| name.contains(pat)) -} - -fn conv_template_type_parameter(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Type { - assert_eq!(cursor.kind(), CXCursor_TemplateTypeParameter); - let ty = conv_ty(ctx, &cursor.cur_type(), cursor); - let layout = Layout::new(ty.size(), ty.align()); - TNamed(Rc::new(RefCell::new(TypeInfo::new(cursor.spelling(), ctx.current_module_id, TVoid, layout)))) -} - -fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { - let cursor = cursor.canonical(); - let override_enum_ty = ctx.options.override_enum_ty; - let new_decl = !ctx.name.contains_key(&cursor); - - let decl = if new_decl { - let spelling = cursor.spelling(); - let comment = cursor.raw_comment(); - let (file, _, _, _) = cursor.location().location(); - let ty = cursor.cur_type(); - let layout = Layout::from_ty(&ty); - let filename = match Path::new(&file.name().unwrap_or("".to_owned())).file_name() { - Some(name) => name.to_string_lossy().replace(".", "_"), - _ => "".to_string() - }; - let glob_decl = match cursor.kind() { - CXCursor_UnionDecl | - CXCursor_ClassTemplate | - CXCursor_ClassDecl | - CXCursor_StructDecl => { - let anno = Annotations::new(&cursor); - - let kind = match cursor.kind() { - CXCursor_UnionDecl => CompKind::Union, - CXCursor_ClassTemplate => { - match cursor.template_kind() { - CXCursor_UnionDecl => CompKind::Union, - _ => CompKind::Struct, - } - } - _ => CompKind::Struct, - }; - - let opaque = ctx.options.opaque_types.iter().any(|name| *name == spelling); - let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling); - - let mut has_non_type_template_params = false; - let args = match ty.num_template_args() { - // In forward declarations, etc, they are in the ast... sigh - -1 => { - let mut args = vec![]; - cursor.visit(|c, _| { - if c.kind() == CXCursor_TemplateTypeParameter { - args.push(conv_template_type_parameter(ctx, c)); - } - CXChildVisit_Continue - }); - args - } - len => { - let mut list = Vec::with_capacity(len as usize); - for i in 0..len { - let arg_type = ty.template_arg_type(i); - if arg_type.kind() != CXType_Invalid { - list.push(conv_ty(ctx, &arg_type, &cursor)); - } else { - has_non_type_template_params = true; - ctx.logger.warn("warning: Template parameter is not a type"); - } - } - list - } - }; - - let mut ci = CompInfo::new(spelling, ctx.current_module_id, - filename, comment, kind, vec![], - layout, anno); - ci.parser_cursor = Some(cursor); - - // If it's an instantiation of another template, - // find the canonical declaration to find the module - // it belongs to and if it's opaque. - let parent = cursor.specialized(); - if let Some(parent) = ctx.name.get(&parent) { - ci.ref_template = Some(parent.clone().to_type()) - } - - ci.opaque = opaque; - ci.hide = hide; - ci.args = args; - ci.has_non_type_template_params = has_non_type_template_params; - - let ci = Rc::new(RefCell::new(ci)); - GCompDecl(ci) - } - CXCursor_EnumDecl => { - let kind = match override_enum_ty { - Some(t) => t, - None => match cursor.enum_type().kind() { - CXType_SChar | CXType_Char_S => ISChar, - CXType_UChar | CXType_Char_U => IUChar, - CXType_UShort => IUShort, - CXType_UInt => IUInt, - CXType_ULong => IULong, - CXType_ULongLong => IULongLong, - CXType_Short => IShort, - CXType_Int => IInt, - CXType_Long => ILong, - CXType_LongLong => ILongLong, - _ => IInt, - } - }; - - let ei = Rc::new(RefCell::new(EnumInfo::new(spelling, ctx.current_module_id, filename, kind, vec!(), layout))); - GEnumDecl(ei) - } - CXCursor_TypeAliasDecl | CXCursor_TypedefDecl => { - let opaque = ctx.options.opaque_types.iter().any(|name| *name == spelling); - let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling); - let mut ti = TypeInfo::new(spelling, ctx.current_module_id, TVoid, layout); - ti.opaque = opaque; - ti.hide = hide; - - let ti = Rc::new(RefCell::new(ti)); - GType(ti) - } - CXCursor_VarDecl => { - let mangled = cursor_link_name(ctx, &cursor); - let is_const = ty.is_const(); - let ty = conv_ty_resolving_typedefs(ctx, &ty, &cursor, true); - let mut vi = VarInfo::new(spelling, mangled, comment, ty); - vi.is_const = is_const; - cursor.visit(|c, _: &Cursor| { - vi.val = visit_literal(c, &ctx.current_translation_unit); - CXChildVisit_Continue - }); - GVar(Rc::new(RefCell::new(vi))) - } - CXCursor_MacroDefinition => { - let vi = Rc::new(RefCell::new(VarInfo::new(spelling, String::new(), comment, TVoid))); - GVar(vi) - } - CXCursor_FunctionDecl => { - let mangled = cursor_link_name(ctx, &cursor); - let vi = Rc::new(RefCell::new(VarInfo::new(spelling, mangled, comment, TVoid))); - GFunc(vi) - } - _ => GOther, - }; - - ctx.name.insert(cursor, glob_decl.clone()); - glob_decl - } else { - ctx.name.get(&cursor).unwrap().clone() - }; - - if new_decl && ctx.options.builtin_names.contains(&cursor.spelling()) { - ctx.builtin_defs.push(cursor); - } - - decl -} - -fn opaque_decl(ctx: &mut ClangParserCtx, decl: &Cursor) { - let spelling = decl.spelling(); - let hide = ctx.options.blacklist_type.iter().any(|name| *name == spelling); - - if hide { - return; - } - - let name = decl_name(ctx, decl); - ctx.current_module_mut().globals.push(name); -} - -fn fwd_decl()>(ctx: &mut ClangParserCtx, cursor: &Cursor, f: F) { - let def = cursor.definition(); - if cursor == &def { - f(ctx); - } else if def.kind() == CXCursor_NoDeclFound || - def.kind() == CXCursor_InvalidFile { - opaque_decl(ctx, cursor); - } -} - -fn get_abi(cc: Enum_CXCallingConv) -> abi::Abi { - match cc { - CXCallingConv_Default => abi::Abi::C, - CXCallingConv_C => abi::Abi::C, - CXCallingConv_X86StdCall => abi::Abi::Stdcall, - CXCallingConv_X86FastCall => abi::Abi::Fastcall, - CXCallingConv_AAPCS => abi::Abi::Aapcs, - CXCallingConv_X86_64Win64 => abi::Abi::Win64, - other => panic!("unsupported calling convention: {}", other), - } -} - -fn conv_ptr_ty_resolving_typedefs(ctx: &mut ClangParserCtx, - ty: &cx::Type, - cursor: &Cursor, - is_ref: bool, - layout: Layout, - resolve_typedefs: bool) -> il::Type { - let is_const = ty.is_const(); - match ty.kind() { - CXType_Void => { - return TPtr(Box::new(TVoid), is_const, is_ref, layout) - } - CXType_Unexposed | - CXType_FunctionProto | - CXType_FunctionNoProto => { - let ret_ty = ty.ret_type(); - return if ret_ty.kind() != CXType_Invalid { - TFuncPtr(mk_fn_sig(ctx, ty, cursor)) - } else if cursor.kind() == CXCursor_VarDecl { - let can_ty = ty.canonical_type(); - conv_ty_resolving_typedefs(ctx, &can_ty, cursor, resolve_typedefs) - } else { - TPtr(Box::new(conv_decl_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs)), ty.is_const(), is_ref, layout) - }; - } - CXType_Typedef => { - let decl = ty.declaration(); - let def_ty = decl.typedef_type(); - if def_ty.kind() == CXType_FunctionProto || - def_ty.kind() == CXType_FunctionNoProto { - return TPtr(Box::new(conv_ptr_ty_resolving_typedefs(ctx, &def_ty, cursor, is_ref, layout, resolve_typedefs)), is_const, is_ref, layout); - } else { - return TPtr(Box::new(conv_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs)), is_const, is_ref, layout); - } - } - _ => return TPtr(Box::new(conv_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs)), is_const, is_ref, layout), - } -} - -fn mk_fn_sig(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::FuncSig { - mk_fn_sig_resolving_typedefs(ctx, ty, cursor, &[]) -} - -fn mk_fn_sig_resolving_typedefs(ctx: &mut ClangParserCtx, - ty: &cx::Type, - cursor: &Cursor, - typedefs: &[String]) -> il::FuncSig { - let args_lst: Vec<(String, il::Type)> = match cursor.kind() { - CXCursor_FunctionDecl | CXCursor_CXXMethod => { - // For CXCursor_FunctionDecl, cursor.args() is the reliable way to - // get parameter names and types. - cursor.args().iter().map(|arg| { - let arg_name = arg.spelling(); - let arg_ty = arg.cur_type(); - let is_class_typedef = arg_ty.sanitized_spelling_in(typedefs); - (arg_name, conv_ty_resolving_typedefs(ctx, &arg_ty, arg, is_class_typedef)) - }).collect() - } - _ => { - // For non-CXCursor_FunctionDecl, visiting the cursor's children is - // the only reliable way to get parameter names. - let mut args_lst = vec!(); - cursor.visit(|c: &Cursor, _: &Cursor| { - if c.kind() == CXCursor_ParmDecl { - let is_class_typedef = c.cur_type().sanitized_spelling_in(typedefs); - args_lst.push((c.spelling(), conv_ty_resolving_typedefs(ctx, &c.cur_type(), c, is_class_typedef))); - } - CXChildVisit_Continue - }); - args_lst - } - }; - - let ret_ty = Box::new(conv_ty(ctx, &ty.ret_type(), cursor)); - let abi = get_abi(ty.call_conv()); - - // Function is presumed unsafe if it takes a pointer argument. - let is_unsafe = args_lst.iter().any(|arg| match arg.1 { - TPtr(..) => true, - _ => false - }); - - il::FuncSig { - ret_ty: ret_ty, - args: args_lst, - is_variadic: ty.is_variadic(), - is_safe: !is_unsafe, - abi: abi, - } -} - -fn conv_decl_ty_resolving_typedefs(ctx: &mut ClangParserCtx, - ty: &cx::Type, - cursor: &Cursor, - resolve_typedefs: bool) -> il::Type { - let ty_decl = ty.declaration(); - // println!("conv_ty_decl: `{}`, ty kind {}: {}, decl `{}` kind {}: {}", cursor.spelling(), ty.kind(), type_to_str(ty.kind()), ty_decl.spelling(), ty_decl.kind(), kind_to_str(ty_decl.kind())); - return match ty_decl.kind() { - CXCursor_StructDecl | - CXCursor_UnionDecl | - CXCursor_ClassTemplate | - CXCursor_ClassDecl => { - let decl = decl_name(ctx, &ty_decl); - // NB: This will only return a number greater than 0 if this is a **full** class - // template specialization. - // - // If the cursor kind is CXCursor_ClassTemplate, this will still return -1 - // and we'll have to keep traversing the cursor. - let args = match ty.num_template_args() { - -1 => vec![], - len => { - let mut list = Vec::with_capacity(len as usize); - for i in 0..len { - let arg_type = ty.template_arg_type(i); - if arg_type.kind() != CXType_Invalid { - list.push(conv_ty(ctx, &arg_type, &cursor)); - } else { - ctx.logger.warn("warning: Template parameter is not a type"); - } - } - list - } - }; - - let ci = decl.compinfo(); - // NB: Args might be filled from decl_name, - // it's important not to override - // - // We might incur in double borrows here. If that's the case, we're - // already scanning the compinfo, and we'd get the args from the - // ast. - use hacks::refcell::BorrowState; - if !args.is_empty() && ci.borrow_state() == BorrowState::Unused { - ci.borrow_mut().args = args; - - // XXX: This is a super-dumb way to get the spesialisation, - // but it seems to be the only one that'd work here... - cursor.visit(|c, _: &Cursor| { - if c.kind() == CXCursor_TemplateRef { - let decl = decl_name(ctx, &c.referenced()); - ci.borrow_mut().ref_template = Some(decl.to_type()); - } - CXChildVisit_Continue - }); - } - - TComp(ci) - } - CXCursor_EnumDecl => { - let decl = decl_name(ctx, &ty_decl); - let ei = decl.enuminfo(); - TEnum(ei) - } - CXCursor_TypeAliasDecl | - CXCursor_TypedefDecl => { - if resolve_typedefs { - return conv_ty_resolving_typedefs(ctx, &ty_decl.typedef_type(), &ty_decl.typedef_type().declaration(), resolve_typedefs); - } - - let decl = decl_name(ctx, &ty_decl); - let ti = decl.typeinfo(); - TNamed(ti) - } - CXCursor_NoDeclFound => { - let canonical = ty.canonical_type(); - let kind = canonical.kind(); - if kind != CXType_Invalid && kind != CXType_Unexposed { - conv_ty_resolving_typedefs(ctx, &canonical, &ty_decl, resolve_typedefs) - } else { - let layout = Layout::from_ty(ty); - TNamed(Rc::new(RefCell::new(TypeInfo::new(ty.spelling().replace("const ", ""), ctx.current_module_id, TVoid, layout)))) - } - } - _ => { - let fail = ctx.options.fail_on_unknown_type; - log_err_warn(ctx, - &format!("unsupported decl `{}` ({})", - kind_to_str(ty_decl.kind()), ty_decl.location() - ), - fail - ); - TVoid - } - }; -} - -fn conv_ty(ctx: &mut ClangParserCtx, - ty: &cx::Type, - cursor: &Cursor) -> il::Type { - conv_ty_resolving_typedefs(ctx, ty, cursor, false) -} - -fn conv_ty_resolving_typedefs(ctx: &mut ClangParserCtx, - ty: &cx::Type, - cursor: &Cursor, - resolve_typedefs: bool) -> il::Type { - let layout = Layout::from_ty(&ty); - // println!("conv_ty: `{}` layout: {:?}, kind {}: {}", cursor.spelling(), layout, ty.kind(), type_to_str(ty.kind())); - - match ty.kind() { - CXType_Void => TVoid, - CXType_Invalid => { - log_err_warn(ctx, - &format!("invalid type `{}` ({})", - cursor.spelling(), cursor.location() - ), - false - ); - TVoid - } - CXType_Bool => TInt(IBool, layout), - CXType_SChar | - CXType_Char_S => TInt(ISChar, layout), - CXType_UChar | - CXType_Char_U => TInt(IUChar, layout), - CXType_WChar => TInt(IShort, layout), - CXType_Char16 | - CXType_UShort => TInt(IUShort, layout), - CXType_UInt => TInt(IUInt, layout), - CXType_ULong => TInt(IULong, layout), - CXType_ULongLong => TInt(IULongLong, layout), - CXType_Short => TInt(IShort, layout), - CXType_Int => TInt(IInt, layout), - CXType_Long => TInt(ILong, layout), - CXType_LongLong => TInt(ILongLong, layout), - CXType_Float => TFloat(FFloat, layout), - CXType_Double => TFloat(FDouble, layout), - CXType_LongDouble => TFloat(FDouble, layout), - CXType_Pointer => conv_ptr_ty_resolving_typedefs(ctx, &ty.pointee_type(), cursor, false, layout, resolve_typedefs), - CXType_LValueReference => conv_ptr_ty_resolving_typedefs(ctx, &ty.pointee_type(), cursor, true, layout, resolve_typedefs), - // XXX DependentSizedArray is wrong - CXType_VariableArray | - CXType_DependentSizedArray | - CXType_IncompleteArray => { - conv_ptr_ty_resolving_typedefs(ctx, &ty.elem_type(), cursor, false, layout, resolve_typedefs) - } - CXType_FunctionProto => TFuncProto(mk_fn_sig(ctx, ty, cursor)), - CXType_Record | - CXType_Typedef | - CXType_Unexposed | - CXType_Enum => conv_decl_ty_resolving_typedefs(ctx, ty, cursor, resolve_typedefs), - CXType_ConstantArray => TArray(Box::new(conv_ty_resolving_typedefs(ctx, &ty.elem_type(), cursor, resolve_typedefs)), ty.array_size(), layout), - #[cfg(not(feature="llvm_stable"))] - CXType_Elaborated => conv_ty_resolving_typedefs(ctx, &ty.named(), cursor, resolve_typedefs), - _ => { - let fail = ctx.options.fail_on_unknown_type; - log_err_warn(ctx, - &format!("unsupported type `{}` ({})", - type_to_str(ty.kind()), cursor.location() - ), - fail - ); - TVoid - }, - } -} - -fn opaque_ty(ctx: &mut ClangParserCtx, ty: &cx::Type) { - if ty.kind() == CXType_Record || ty.kind() == CXType_Enum { - let decl = ty.declaration(); - let def = decl.definition(); - if def.kind() == CXCursor_NoDeclFound || - def.kind() == CXCursor_InvalidFile { - opaque_decl(ctx, &decl); - } - } -} - -#[derive(Copy, PartialEq, Clone, Debug)] -pub enum Accessor { - None, - Regular, - Unsafe, - Immutable, -} - -#[derive(Clone, PartialEq, Debug)] -pub struct Annotations { - opaque: bool, - hide: bool, - use_as: Option, - /// Disable deriving copy/clone on this struct. - no_copy: bool, - // In the None case we fall back to the value specified - // in the enclosing decl - private: Option, - accessor: Option, -} - -fn parse_accessor(s: &str) -> Accessor { - match s { - "false" => Accessor::None, - "unsafe" => Accessor::Unsafe, - "immutable" => Accessor::Immutable, - _ => Accessor::Regular, - } -} - -impl Annotations { - fn new(cursor: &Cursor) -> Annotations { - let mut anno = Annotations { - opaque: false, - hide: false, - use_as: None, - no_copy: false, - private: None, - accessor: None - }; - - anno.parse(&cursor.comment()); - anno - } - - fn parse(&mut self, comment: &Comment) { - if comment.kind() == CXComment_HTMLStartTag && - comment.get_tag_name() == "div" && - comment.get_num_tag_attrs() > 1 && - comment.get_tag_attr_name(0) == "rustbindgen" { - for i in 0..comment.get_num_tag_attrs() { - let name = comment.get_tag_attr_name(i); - match name.as_str() { - "opaque" => self.opaque = true, - "hide" => self.hide = true, - "replaces" => self.use_as = Some(comment.get_tag_attr_value(i)), - "nocopy" => self.no_copy = true, - "private" => self.private = Some(comment.get_tag_attr_value(i) != "false"), - "accessor" => { - self.accessor = Some(parse_accessor(&comment.get_tag_attr_value(i))) - }, - _ => (), - } - } - } - - for i in 0..comment.num_children() { - self.parse(&comment.get_child(i)); - } - } -} - -/// Recursively visits a cursor that represents a composite (struct or union) -/// type and fills members with CompMember instances representing the fields and -/// nested composites that make up the visited composite. -fn visit_composite(cursor: &Cursor, parent: &Cursor, - ctx: &mut ClangParserCtx, - ci: &mut CompInfo) -> Enum_CXVisitorResult { - assert!(ci.parser_cursor.is_some()); - fn is_bitfield_continuation(field: &il::FieldInfo, _ty: &il::Type, width: u32) -> bool { - match (&field.bitfields, field.ty.layout()) { - (&Some(ref bitfields), Some(layout)) => { - let actual_width = bitfields.iter().map(|&(_, w)| w).fold(0u32, |acc, w| acc + w); - actual_width + width <= (layout.size * 8) as u32 - }, - _ => false - } - } - - match cursor.kind() { - CXCursor_TypeAliasDecl | CXCursor_TypedefDecl => { - ci.typedefs.push(cursor.spelling().to_owned()); - } - CXCursor_FieldDecl => { - let anno = Annotations::new(cursor); - if anno.hide { - return CXChildVisit_Continue; - } - - let is_class_typedef = cursor.cur_type().sanitized_spelling_in(&ci.typedefs); - let mutable = cursor.is_mutable_field(); - - let cursor_ty = cursor.cur_type(); - - // NB: Overwritten in the case of non-integer bitfield - let mut ty = conv_ty_resolving_typedefs(ctx, - &cursor_ty, - cursor, - is_class_typedef); - - - use hacks::refcell::BorrowState; - if let Some(child_ci) = ty.get_outermost_composite() { - if let BorrowState::Unused = child_ci.borrow_state() { - let mut child_ci = child_ci.borrow_mut(); - let child_cursor = child_ci.parser_cursor.unwrap(); - - // TODO: This is lame, ideally we should use cursors. - // The problem this loop is trying to solve is - // tests/headers/inner_template_self.hpp, and templates with - // incomplete types. - // - // The problem with this is that, in the first case (see the - // CXCursor_ClassDecl branch below) clang treats the *prev* - // field as a Class Declaration instead of a Class Template, - // so we have to check now for the name and the module id. - // - // Ideally, some method like `semantic_parent` or - // `lexical_parent` should return the reference to the - // class, but I've tried everything I could think about and - // failed miserably. - // - // Also, there could be more complex cases, like a templated - // type in an inner type declaration, that this is - // completely unable to catch. - // - // In the second case (the CXCursor_ClassTemplate branch), - // we're not able to retrieve the template parameters of an - // incomplete type via the declaration or anything like - // that. We can inspect the AST and deduct them though, - // since there's a leading CXCursor_TemplateRef. - if child_ci.args.is_empty() && child_cursor.kind() == CXCursor_ClassDecl { - // println!("child: {:?} {:?}, {:?}, {:?}", cursor.spelling(), - // type_to_str(cursor_ty.kind()), - // type_to_str(child_cursor.cur_type().kind()), - // kind_to_str(child_cursor.kind())); - if child_ci.name == ci.name && - child_ci.module_id == ci.module_id { - child_ci.args = ci.args.clone(); - } - } - - if child_cursor.kind() == CXCursor_ClassTemplate { - // We need to take into account the possibly different - // type template names, so we need to clear them and - // re-scan. - child_ci.args.clear(); - let mut found_invalid_template_ref = false; - cursor.visit(|c, _| { - // println!("ichild: {:?} {:?}, {:?}", c.spelling(), - // kind_to_str(c.kind()), - // type_to_str(c.cur_type().kind())); - if c.kind() == CXCursor_TemplateRef && - c.cur_type().kind() == CXType_Invalid { - found_invalid_template_ref = true; - } - if found_invalid_template_ref && - c.kind() == CXCursor_TypeRef { - child_ci.args.push(TNamed(Rc::new(RefCell::new( - TypeInfo::new(c.spelling(), - ctx.current_module_id, - TVoid, - Layout::zero()))))); - } - CXChildVisit_Continue - }) - } - } - } - - let comment = cursor.raw_comment(); - - let (name, bitfields) = match (cursor.bit_width(), ci.members.last_mut()) { - // The field is a continuation of an exising bitfield - (Some(width), Some(&mut il::CompMember::Field(ref mut field))) - if is_bitfield_continuation(field, &ty, width) => { - - // println!("found bitfield continuation {} (width: {})", cursor.spelling(), width); - - field.bitfields.as_mut().unwrap().push((cursor.spelling(), width)); - return CXChildVisit_Continue; - }, - // The field is the start of a new bitfield - (Some(width), _) => { - // Bitfields containing enums are not supported by the c standard - // https://stackoverflow.com/questions/11983231/is-it-safe-to-use-an-enum-in-a-bit-field - - match ty { - il::TInt(..) => {}, - _ => { - // NOTE: We rely on the name of the type converted - // to rust types, and on the alignment. - let bits = cmp::max(width, ty.size() as u32 * 8); - let layout_size = cmp::max(1, bits.next_power_of_two() / 8) as usize; - - let msg = format!("Enums in bitfields are not supported ({}::{}). Trying to recover with width: {}", - parent.spelling(), cursor.spelling(), layout_size * 8); - ctx.logger.warn(&msg); - - let name = match layout_size { - 1 => "uint8_t", - 2 => "uint16_t", - 4 => "uint32_t", - 8 => "uint64_t", - _ => panic!("bitfield width not supported: {}", layout_size), - }; - - // NB: We rely on the ULongLong not being translated - // (using the common uintxx_t name) - let ti = TypeInfo::new(name.into(), - ctx.current_module_id, - TInt(IKind::IULongLong, Layout::new(layout_size, layout_size)), - Layout::new(layout_size, layout_size)); - ty = TNamed(Rc::new(RefCell::new(ti))) - } - } - ("".to_owned(), Some(vec![(cursor.spelling(), width)])) - }, - // The field is not a bitfield - (None, _) => (cursor.spelling(), None) - }; - - // The Clang C api does not fully expose composite fields, but it - // does expose them in a way that can be detected. When the current - // field kind is TComp, TPtr or TArray and the previous member is a - // composite type - the same type as this field - then this is a - // composite field. e.g.: - // - // struct foo { - // union { - // int a; - // char b; - // } bar; - // }; - // - // struct foo { - // union { - // int a; - // char b; - // } **bar; - // }; - // - // struct foo { - // union { - // int a; - // char b; - // } bar[3][2]; - // }; - // - - //let is_composite = match (inner_composite(&ty), ci.members.last()) { - // (Some(ty_compinfo), Some(&CompMember::Comp(ref c))) => { - // c.borrow().deref() as *const _ == ty_compinfo.borrow().deref() as *const _ - // }, - // _ => false - //}; - - if let Some(&mut CompMember::Field(ref mut info)) = ci.members.last_mut() { - if bitfields.is_none() && info.bitfields.is_none() { - let should_replace = if let TComp(ref ci) = info.ty { - if ci.borrow().was_unnamed && ty.was_unnamed() && - Some(&ci.borrow().name) == ty.name().as_ref() { - true - } else { - false - } - } else { - false - }; - - if should_replace { - *info = FieldInfo::new(name, ty, comment, bitfields, mutable); - info.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false)); - info.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None)); - return CXChildVisit_Continue; - } - } - } - - let mut field = FieldInfo::new(name, ty, comment, bitfields, mutable); - field.private = anno.private.unwrap_or(ci.anno.private.unwrap_or(false)); - field.accessor = anno.accessor.unwrap_or(ci.anno.accessor.unwrap_or(Accessor::None)); - ci.members.push(CompMember::Field(field)); - } - CXCursor_StructDecl | - CXCursor_UnionDecl | - CXCursor_ClassTemplate | - CXCursor_ClassDecl => { - fwd_decl(ctx, cursor, |ctx_| { - // If the struct is anonymous (i.e. declared here) then it - // cannot be used elsewhere and so does not need to be added - // to globals otherwise it will be declared later and a global. - let decl = decl_name(ctx_, cursor); - let ci2 = decl.compinfo(); - - // Mangle the name to prevent multiple definitions - // of the same inner type to cause conflicts - let new_name = [&*ci.name, &*ci2.borrow().name].join("_").to_owned(); - ci2.borrow_mut().name = new_name; - - // This clear() is needed because of the speculation we do on - // incomplete types inside visit_composite() members. - // - // If this type ends up being complete, we're going to really - // parse them now, so we should reset them. - ci2.borrow_mut().args.clear(); - - // Propagate template arguments and typedefs to inner structs - ci2.borrow_mut().args.extend(ci.args.clone().into_iter()); - ci2.borrow_mut().typedefs.extend(ci.typedefs.clone().into_iter()); - - cursor.visit(|c, p| { - let mut ci_ = ci2.borrow_mut(); - visit_composite(c, p, ctx_, &mut ci_) - }); - - ci.members.push(CompMember::Comp(decl.compinfo())); - - // Anonymous structs are legal in both C++ and C11 - if ci2.borrow().was_unnamed { - let ci2b = ci2.borrow(); - let field = FieldInfo::new(ci2b.name.clone(), TComp(ci2.clone()), ci2b.comment.clone(), None, false); - ci.members.push(CompMember::Field(field)); - } - }); - } - CXCursor_PackedAttr => { - ci.set_packed(true); - } - CXCursor_TemplateTypeParameter => { - ci.args.push(conv_template_type_parameter(ctx, cursor)); - } - CXCursor_EnumDecl => { - let anno = Annotations::new(cursor); - - fwd_decl(ctx, cursor, |ctx_| { - let decl = decl_name(ctx_, cursor); - let ei = decl.enuminfo(); - // Mangle the name to avoid name conflicts with inner types - let new_name = [&*ci.name, &*ei.borrow().name].join("_").to_owned(); - ei.borrow_mut().name = new_name; - ei.borrow_mut().comment = cursor.raw_comment(); - cursor.visit(|c, _: &Cursor| { - let mut ei_ = ei.borrow_mut(); - visit_enum(c, &mut ei_.items) - }); - if anno.opaque { - ei.borrow_mut().items = vec!(); - } - ci.members.push(CompMember::Enum(ei)); - }); - } - CXCursor_CXXBaseSpecifier => { - let ty = conv_ty(ctx, &cursor.cur_type(), cursor); - let fieldname = if ci.members.is_empty() { - "_base".to_string() - } else { - format!("_base{}", ci.members.len()) - }; - let found_virtual_base = if ci.members.is_empty() { - false - } else if let CompMember::Field(ref fi) = ci.members[0] { - if let TComp(ref ci2) = fi.ty { - ci2.borrow().has_vtable - } else { - false - } - } else { - false - }; - - if let TComp(ref info) = ty { - ci.has_nonempty_base |= !info.borrow().members.is_empty(); - ci.has_destructor |= info.borrow().has_destructor; - ci.typedefs.extend(info.borrow().typedefs.clone().into_iter()); - } - - let field = FieldInfo::new(fieldname, ty, "".to_owned(), None, false); - if !found_virtual_base && cursor.is_virtual_base() { - ci.members.insert(0, CompMember::Field(field)); - ci.has_vtable = true; - } else { - ci.members.push(CompMember::Field(field)); - } - ci.base_members += 1; - } - CXCursor_CXXMethod => { - // Make sure to mark has_vtable properly, even if we - // would otherwise skip this method due to linkage/visibility. - if cursor.method_is_virtual() { - ci.has_vtable = true; - } - - let linkage = cursor.linkage(); - if linkage != CXLinkage_External { - return CXChildVisit_Continue; - } - - let visibility = cursor.visibility(); - if visibility != CXVisibility_Default { - return CXChildVisit_Continue; - } - - if cursor.is_inlined_function() { - return CXChildVisit_Continue; - } - - // XXX no methods yet for templates - if !ci.args.is_empty() { - return CXChildVisit_Continue; - } - - if cursor.access_specifier() == CX_CXXPrivate { - return CXChildVisit_Continue; - } - - let spelling = cursor.spelling(); - if spelling.len() > 8 && - &(spelling)[..8] == "operator" { - return CXChildVisit_Continue; - } - - fn is_override(ci: &CompInfo, sig: &Type, name: &str) -> bool { - for vm in ci.vmethods.iter() { - if vm.name == name && &vm.ty == sig { - return true; - } - } - for base in ci.members[..ci.base_members].iter() { - let base = match *base { - CompMember::Field(ref fi) => { - match fi.ty { - TComp(ref ci) => ci.clone(), - _ => continue, - } - }, - _ => unreachable!() - }; - if is_override(&*base.borrow(), sig, name) { - return true; - } - } - return false; - } - - let mut sig = mk_fn_sig_resolving_typedefs(ctx, &cursor.cur_type(), cursor, &ci.typedefs); - if !cursor.method_is_static() { - // XXX what have i done - if cursor.method_is_virtual() { - sig.args.insert(0, ("this".to_string(),TPtr(Box::new(TVoid), cursor.cur_type().is_const(), false, Layout::zero()))); - } else { - // XXX This is weak and doesn't work if names are mangled further, but... - // We can't have access to the current Rc from here, so we can't pass the type - // here. - // - // Also, it would form an rc cycle. - // - // Possibly marking the "this" attribute with TOther or a similar marked value - // would be a better choice. - sig.args.insert(0, ("this".to_string(), - TPtr(Box::new(TNamed(Rc::new(RefCell::new(TypeInfo::new(ci.name.clone(), ctx.current_module_id, TVoid, Layout::zero()))))), cursor.cur_type().is_const(), false, Layout::zero()))); - } - } - - // XXX with final classes we can optimize a bit - let sig = TFuncPtr(sig); - if is_override(ci, &sig, &spelling) { - return CXChildVisit_Continue; - } - - let mut vi = VarInfo::new(spelling, cursor_link_name(ctx, &cursor), cursor.raw_comment(), sig); - vi.is_static = cursor.method_is_static(); - vi.is_const = cursor.cur_type().is_const(); - - if ctx.options.ignore_methods { - return CXChildVisit_Continue; - } - - if cursor.method_is_virtual() { - ci.vmethods.push(vi); - } else { - ci.methods.push(vi); - } - } - CXCursor_Destructor => { - ci.has_destructor = true; - // Propagate the change to the parent - if let Some(ref t) = ci.ref_template { - match *t { - TComp(ref parent_ci) => parent_ci.borrow_mut().has_destructor = true, - _ => {} - } - } - } - CXCursor_NonTypeTemplateParameter => { - log_err_warn(ctx, &format!("warning: Non-type template parameter in composite member could affect layout: `{}` (kind {}) in `{}` ({})", - cursor.spelling(), cursor.kind(), parent.spelling(), - cursor.location()), false); - ci.has_non_type_template_params = true; - } - CXCursor_VarDecl => { - if !ctx.options.class_constants { - return CXChildVisit_Continue; - } - - let linkage = cursor.linkage(); - if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal { - return CXChildVisit_Continue; - } - - let visibility = cursor.visibility(); - if visibility != CXVisibility_Default { - return CXChildVisit_Continue; - } - - let var = decl_name(ctx, cursor); - ci.vars.push(var); - } - // Intentionally not handled - CXCursor_CXXAccessSpecifier | - CXCursor_CXXFinalAttr | - CXCursor_Constructor | - CXCursor_FunctionTemplate | - CXCursor_ConversionFunction => {} - _ => { - // XXX: Some kind of warning would be nice, but this produces far - // too many. - log_err_warn(ctx, &format!("unhandled composite member `{}` (kind {}) in `{}` ({})", - cursor.spelling(), cursor.kind(), parent.spelling(), - cursor.location()), false); - } - } - CXChildVisit_Continue -} - -fn visit_enum(cursor: &Cursor, - items: &mut Vec) -> Enum_CXVisitorResult { - if cursor.kind() == CXCursor_EnumConstantDecl { - let name = cursor.spelling(); - let comment = cursor.raw_comment(); - let val = cursor.enum_val(); - let item = EnumItem::new(name, comment, val); - items.push(item); - } - CXChildVisit_Continue -} - -fn parse_int_literal_tokens(cursor: &Cursor, unit: &TranslationUnit, which: usize) -> Option { - match unit.tokens(cursor) { - None => None, - Some(tokens) => { - if tokens.len() <= which || tokens[which].kind != CXToken_Literal { - None - } else { - let ref s = tokens[which].spelling; - let parsed = { - //TODO: try to preserve hex literals? - if s.starts_with("0x") { - i64::from_str_radix(&s[2..], 16) - } else { - s.parse() - } - }; - match parsed { - Ok(i) => Some(i), - Err(_) => None, - } - } - } - } -} - -fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option { - if cursor.kind() == CXCursor_IntegerLiteral { - return parse_int_literal_tokens(cursor, unit, 0); - } - return None; -} - -fn visit_top(cursor: &Cursor, - mut ctx: &mut ClangParserCtx) -> Enum_CXVisitorResult { - if !match_pattern(ctx, cursor) { - return CXChildVisit_Continue; - } - - match cursor.kind() { - CXCursor_UnexposedDecl => { - return CXChildVisit_Recurse; - } - CXCursor_StructDecl - | CXCursor_UnionDecl - | CXCursor_ClassDecl - | CXCursor_ClassTemplate => { - let anno = Annotations::new(cursor); - fwd_decl(ctx, cursor, move |ctx_| { - let decl = decl_name(ctx_, cursor); - let ci = decl.compinfo(); - // This clear() is needed because of the speculation we do - // on incomplete types inside visit_composite() members. - ci.borrow_mut().args.clear(); - cursor.visit(|c, p| { - let mut ci_ = ci.borrow_mut(); - visit_composite(c, p, ctx_, &mut ci_) - }); - - if anno.opaque { - ci.borrow_mut().opaque = true; - } - - if anno.hide { - ci.borrow_mut().hide = true; - } - - if anno.no_copy { - ci.borrow_mut().no_copy = true; - } - - // If we find a previous translation, we take it now and carry - // on. - // - // XXX: This clone is spurious and could be avoided with another - // scope I think. - let name = ci.borrow().name.clone(); - if let Some(translation) = ctx_.current_module_mut().translations.remove(&name) { - println!("*** {}: found previous translation", name); - if let GComp(ref translated) = translation { - *ci.borrow_mut() = translated.borrow().clone(); - } - } - - if let Some(other_type_name) = anno.use_as { - ci.borrow_mut().name = other_type_name.clone(); - // if the translated type already existed, and we can - // replace it, just do it (tm). - // - // We'll still need the translations map for not found - // translations and stuff like that. - // - // This is a linear search, which is crap, but fwiw it's not - // too common (just when a type marked as translation is - // found). - // - // NB: We have to also loop through the `name` map to take - // declarations in files that haven't been matched into - // account (since they won't appear in globals). - let mut found_in_globals = false; - for v in ctx_.current_module_mut().globals.iter_mut() { - match *v { - GComp(ref mut other_ci) => { - if other_ci.borrow().name == other_type_name { - *other_ci.borrow_mut() = ci.borrow().clone(); - found_in_globals = true; - } - }, - _ => {}, - } - } - - for (cursor, v) in ctx_.name.iter_mut() { - // We can find ourselves here, and that's no fun at - // all. - if *cursor == ci.borrow().parser_cursor.unwrap() { - continue; - } - match *v { - GComp(ref mut other_ci) | - GCompDecl(ref mut other_ci) => { - if other_ci.borrow().name == other_type_name { - // We have to preserve template parameter - // names here if we want to survive. - let args = other_ci.borrow().args.clone(); - *other_ci.borrow_mut() = ci.borrow().clone(); - other_ci.borrow_mut().args = args; - } - } - _ => {} - } - } - - if !found_in_globals { - ctx_.current_module_mut().translations - .insert(other_type_name, GComp(ci)); - } - } else { - ctx_.current_module_mut().globals.push(GComp(ci)); - } - }); - CXChildVisit_Continue - } - CXCursor_EnumDecl => { - fwd_decl(ctx, cursor, |ctx_| { - let decl = decl_name(ctx_, cursor); - let ei = decl.enuminfo(); - ei.borrow_mut().comment = cursor.raw_comment(); - cursor.visit(|c, _: &Cursor| { - let mut ei_ = ei.borrow_mut(); - visit_enum(c, &mut ei_.items) - }); - ctx_.current_module_mut().globals.push(GEnum(ei)); - }); - CXChildVisit_Continue - } - CXCursor_FunctionDecl => { - if ctx.options.ignore_functions { - return CXChildVisit_Continue; - } - - let linkage = cursor.linkage(); - if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal { - return CXChildVisit_Continue; - } - - let visibility = cursor.visibility(); - if visibility != CXVisibility_Default { - return CXChildVisit_Continue; - } - - if cursor.is_inlined_function() { - return CXChildVisit_Continue; - } - - let spelling = cursor.spelling(); - if spelling.len() > 8 && - &(spelling)[..8] == "operator" { - return CXChildVisit_Continue; - } - - let func = decl_name(ctx, cursor); - let vi = func.varinfo(); - let mut vi = vi.borrow_mut(); - - vi.ty = TFuncPtr(mk_fn_sig(ctx, &cursor.cur_type(), cursor)); - ctx.current_module_mut().globals.push(func); - - CXChildVisit_Continue - } - CXCursor_VarDecl => { - // TODO: At some point we might want to mangle them instead? - // We already have a bunch of that logic. - if !ctx.in_root_namespace() && !ctx.options.namespaced_constants { - return CXChildVisit_Continue; - } - - let linkage = cursor.linkage(); - if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal { - return CXChildVisit_Continue; - } - - let visibility = cursor.visibility(); - if visibility != CXVisibility_Default { - return CXChildVisit_Continue; - } - let val = decl_name(ctx, cursor); - ctx.current_module_mut().globals.push(val); - - CXChildVisit_Continue - } - CXCursor_TypeAliasDecl | CXCursor_TypedefDecl => { - let anno = Annotations::new(cursor); - if anno.hide { - return CXChildVisit_Continue; - } - - let mut under_ty = cursor.typedef_type(); - if under_ty.kind() == CXType_Unexposed { - under_ty = under_ty.canonical_type(); - } - - if cursor.spelling() == - cursor.typedef_type().declaration().spelling() { - // XXX: This is a real hack, but in the common idiom of: - // typedef struct xxx { ... } xxx; - // - // The annotation arrives here, so... - if anno.opaque { - ctx.options.opaque_types.push(cursor.spelling()); - } - return CXChildVisit_Continue; - } - let ty = conv_ty(ctx, &under_ty, cursor); - let typedef = decl_name(ctx, cursor); - let ti = typedef.typeinfo(); - let mut ti = ti.borrow_mut(); - ti.ty = ty.clone(); - - if anno.opaque { - ti.opaque = true; - } - - ti.comment = cursor.raw_comment(); - ctx.current_module_mut().globals.push(typedef); - - opaque_ty(ctx, &under_ty); - - CXChildVisit_Continue - } - CXCursor_FieldDecl => { - CXChildVisit_Continue - } - CXCursor_Namespace => { - if !ctx.options.enable_cxx_namespaces { - ctx.namespace_depth += 1; - cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx)); - ctx.namespace_depth -= 1; - return CXChildVisit_Continue; - } - - let namespace_name = match ctx.current_translation_unit.tokens(cursor) { - None => None, - Some(tokens) => { - if tokens.len() <= 1 { - None - } else { - match &*tokens[1].spelling { - "{" => None, - s => Some(s.to_owned()), - } - } - } - }.unwrap_or_else(|| { - ctx.anonymous_modules_found += 1; - format!("__anonymous{}", ctx.anonymous_modules_found) - }); - - // Find an existing namespace children of the current one - let mod_id = ctx.current_module() - .children_ids.iter() - .find(|id| ctx.module_map.get(id).unwrap().name == namespace_name) - .map(|id| *id); - - let mod_id = match mod_id { - Some(id) => id, - None => { - let parent_id = ctx.current_module_id; - let id = ModuleId::next(); - ctx.module_map.get_mut(&parent_id).unwrap().children_ids.push(id); - ctx.module_map.insert(id, Module::new(namespace_name, Some(parent_id))); - id - } - }; - - let previous_id = ctx.current_module_id; - - ctx.current_module_id = mod_id; - ctx.namespace_depth += 1; - cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx)); - ctx.namespace_depth -= 1; - ctx.current_module_id = previous_id; - - return CXChildVisit_Continue; - } - CXCursor_MacroDefinition => { - let val = parse_int_literal_tokens(cursor, &ctx.current_translation_unit, 1); - let val = match val { - None => return CXChildVisit_Continue, // Not an integer literal. - Some(v) => v, - }; - let var = decl_name(ctx, cursor); - let vi = var.varinfo(); - let mut vi = vi.borrow_mut(); - vi.ty = if val.abs() > u32::max_value() as i64 { - TInt(IULongLong, Layout::new(8, 8)) - } else { - TInt(IUInt, Layout::new(4, 4)) - }; - vi.is_const = true; - vi.val = Some(val); - ctx.current_module_mut().globals.push(var); - - return CXChildVisit_Continue; - } - _ => { - // println!("Not handled cursor: {}", cursor.kind()); - return CXChildVisit_Continue; - } - } -} - -fn log_err_warn(ctx: &mut ClangParserCtx, msg: &str, is_err: bool) { - if is_err { - ctx.err_count += 1; - ctx.logger.error(msg); - } else { - ctx.logger.warn(msg); - } -} - -pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result { - let ix = cx::Index::create(false, true); - if ix.is_null() { - logger.error("Clang failed to create index"); - return Err(()) - } - - let unit = TranslationUnit::parse(&ix, "", &options.clang_args, &[], CXTranslationUnit_DetailedPreprocessingRecord); - if unit.is_null() { - logger.error("No input files given"); - return Err(()) - } - - let mut ctx = ClangParserCtx { - options: options, - name: HashMap::new(), - builtin_defs: vec!(), - module_map: ModuleMap::new(), - namespace_depth: 0, - current_module_id: ROOT_MODULE_ID, - current_translation_unit: unit, - logger: logger, - err_count: 0, - anonymous_modules_found: 0, - }; - - ctx.module_map.insert(ROOT_MODULE_ID, Module::new("root".to_owned(), None)); - - let diags = ctx.current_translation_unit.diags(); - for d in &diags { - let msg = d.format(Diagnostic::default_opts()); - let is_err = d.severity() >= CXDiagnostic_Error; - log_err_warn(&mut ctx, &msg, is_err); - } - - if ctx.err_count > 0 { - logger.error(&format!("{} errors after diagnostics", ctx.err_count)); - return Err(()) - } - - let cursor = ctx.current_translation_unit.cursor(); - - if ctx.options.emit_ast { - cursor.visit(|cur, _: &Cursor| ast_dump(cur, 0)); - } - - cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx)); - - while !ctx.builtin_defs.is_empty() { - let c = ctx.builtin_defs.remove(0); - visit_top(&c.definition(), &mut ctx); - } - - ctx.current_translation_unit.dispose(); - ix.dispose(); - - if ctx.err_count > 0 { - logger.error(&format!("{} errors after translation", ctx.err_count)); - return Err(()) - } - - Ok(ctx.module_map) -} diff --git a/src/regex_set.rs b/src/regex_set.rs new file mode 100644 index 0000000000..20bc56bf96 --- /dev/null +++ b/src/regex_set.rs @@ -0,0 +1,58 @@ +use std::borrow::Borrow; +use regex::Regex; + +// Yeah, I'm aware this is sorta crappy, should be cheaper to compile a regex +// ORing all the patterns, I guess... +#[derive(Debug)] +pub struct RegexSet { + items: Vec +} + +impl RegexSet { + pub fn is_empty(&self) -> bool { + self.items.is_empty() + } + + pub fn extend(&mut self, iter: I) + where I: IntoIterator + { + for s in iter.into_iter() { + self.insert(&s) + } + } + + pub fn insert(&mut self, string: &S) + where S: Borrow + { + let s = string.borrow(); + match Regex::new(&format!("^{}$", s)) { + Ok(r) => { + self.items.push(r); + } + Err(err) => { + error!("Invalid pattern provided: {}, {:?}", s, err); + } + } + } + + pub fn matches(&self, string: &S) -> bool + where S: Borrow + { + let s = string.borrow(); + for r in &self.items { + if r.is_match(s) { + return true; + } + } + + false + } +} + +impl Default for RegexSet { + fn default() -> Self { + RegexSet { + items: vec![], + } + } +} diff --git a/src/types.rs b/src/types.rs deleted file mode 100644 index 60af3f5991..0000000000 --- a/src/types.rs +++ /dev/null @@ -1,882 +0,0 @@ -use std::cell::Cell; -use hacks::refcell::RefCell; -use std::fmt; -use std::rc::Rc; -use std::collections::HashMap; -use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - -use syntax::abi; - -pub use self::Global::*; -pub use self::Type::*; -pub use self::IKind::*; -pub use self::FKind::*; -use clang::{self, Cursor}; - -use parser::{Annotations, Accessor}; - -static NEXT_MODULE_ID: AtomicUsize = ATOMIC_USIZE_INIT; - -#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] -pub struct ModuleId(usize); -pub static ROOT_MODULE_ID: ModuleId = ModuleId(0); - -impl ModuleId { - pub fn next() -> ModuleId { - ModuleId(NEXT_MODULE_ID.fetch_add(1, Ordering::SeqCst) + 1) - } -} - -pub type ModuleMap = HashMap; - -#[derive(Clone)] -pub struct Module { - pub name: String, - pub globals: Vec, - pub parent_id: Option, - // Just for convenience - pub children_ids: Vec, - /// Types that must be substituted in this module, - /// in the form original_name -> substituted_type - pub translations: HashMap, -} - -impl Module { - pub fn new(name: String, parent_id: Option) -> Self { - Module { - name: name, - globals: vec![], - parent_id: parent_id, - children_ids: vec![], - translations: HashMap::new(), - } - } - - #[allow(dead_code)] - pub fn add_global(&mut self, g: Global) { - self.globals.push(g) - } -} - -#[derive(Clone, PartialEq)] -pub enum Global { - GType(Rc>), - GComp(Rc>), - GCompDecl(Rc>), - GEnum(Rc>), - GEnumDecl(Rc>), - GVar(Rc>), - GFunc(Rc>), - GOther -} - -impl Global { - // XXX prevent this dumb to_owned()... didn't want to deal with the borrowed lifetime - pub fn name(&self) -> String { - match *self { - GType(ref info) => info.borrow().name.to_owned(), - GComp(ref info) - | GCompDecl(ref info) => info.borrow().name.to_owned(), - GEnum(ref info) - | GEnumDecl(ref info) => info.borrow().name.to_owned(), - GVar(ref info) - | GFunc(ref info) => info.borrow().name.to_owned(), - GOther => "".to_owned(), - } - } - - pub fn layout(&self) -> Option { - Some(match *self { - GType(ref info) => info.borrow().layout, - GComp(ref info) - | GCompDecl(ref info) => info.borrow().layout, - GEnum(ref info) - | GEnumDecl(ref info) => info.borrow().layout, - GVar(_) - | GFunc(_) - | GOther => return None, - }) - } - - pub fn compinfo(&self) -> Rc> { - match *self { - GComp(ref i) - | GCompDecl(ref i) => i.clone(), - _ => panic!("global_compinfo") - } - } - - pub fn enuminfo(&self) -> Rc> { - match *self { - GEnum(ref i) - | GEnumDecl(ref i) => i.clone(), - _ => panic!("global_enuminfo") - } - } - - pub fn typeinfo(&self) -> Rc> { - match *self { - GType(ref i) => i.clone(), - _ => panic!("global_typeinfo") - } - } - - pub fn varinfo(&self) -> Rc> { - match *self { - GVar(ref i) - | GFunc(ref i) => i.clone(), - _ => panic!("global_varinfo") - } - } - - pub fn to_type(self) -> Type { - match self { - GType(ti) => TNamed(ti), - GComp(ci) - | GCompDecl(ci) => TComp(ci), - GEnum(ei) - | GEnumDecl(ei) => TEnum(ei), - GVar(_) - | GFunc(_) - | GOther => TVoid, - } - } -} - -impl fmt::Debug for Global { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - GType(ref ti) => ti.borrow().fmt(f), - GComp(ref ci) - | GCompDecl(ref ci) => ci.borrow().fmt(f), - GEnum(ref ei) - | GEnumDecl(ref ei) => ei.borrow().fmt(f), - GVar(ref vi) - | GFunc(ref vi) => vi.borrow().fmt(f), - GOther => "*".fmt(f), - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct FuncSig { - pub ret_ty: Box, - pub args: Vec<(String, Type)>, - pub is_variadic: bool, - pub is_safe: bool, - pub abi: abi::Abi, -} - -// NOTE: Remember to add your new variant to the PartialEq implementation below! -#[derive(Clone, Debug)] -pub enum Type { - TVoid, - TInt(IKind, Layout), - TFloat(FKind, Layout), - TPtr(Box, bool, bool, Layout), - TArray(Box, usize, Layout), - TFuncProto(FuncSig), - TFuncPtr(FuncSig), - TNamed(Rc>), - TComp(Rc>), - TEnum(Rc>) -} - -/// Compares to Rc types looking first at the value they point to. -/// -/// This is needed to avoid infinite recursion in things like virtual function -/// signatures. -fn ref_ptr_aware_eq(one: &Rc, other: &Rc) -> bool { - &**one as *const T == &**other as *const T || - **one == **other -} - -impl PartialEq for Type { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (&TVoid, &TVoid) - => true, - (&TInt(ref kind, ref l), &TInt(ref o_kind, ref o_l)) - => kind == o_kind && l == o_l, - (&TFloat(ref kind, ref l), &TFloat(ref o_kind, ref o_l)) - => kind == o_kind && l == o_l, - (&TPtr(ref ty, is_const, is_ref, ref l), &TPtr(ref o_ty, o_is_const, o_is_ref, ref o_l)) - => is_const == o_is_const && is_ref == o_is_ref && l == o_l && ty == o_ty, - (&TArray(ref ty, count, ref l), &TArray(ref o_ty, o_count, ref o_l)) - => count == o_count && l == o_l && ty == o_ty, - (&TFuncProto(ref sig), &TFuncProto(ref o_sig)) - => sig == o_sig, - (&TNamed(ref ti), &TNamed(ref o_ti)) - => ref_ptr_aware_eq(ti, o_ti), - (&TComp(ref ci), &TComp(ref o_ci)) - => ref_ptr_aware_eq(ci, o_ci), - (&TEnum(ref ei), &TEnum(ref o_ei)) - => ref_ptr_aware_eq(ei, o_ei), - _ => false, - } - } -} - -impl Type { - #[allow(dead_code)] - pub fn name(&self) -> Option { - match *self { - TNamed(ref info) => Some(info.borrow().name.clone()), - TComp(ref info) => Some(info.borrow().name.clone()), - TEnum(ref info) => Some(info.borrow().name.clone()), - TArray(ref t, _, _) => t.name(), - TPtr(ref t, _, _, _) => t.name(), - _ => None - } - } - - pub fn signature_contains_type(&self, other: &Type) -> bool { - self == other || match *self { - TPtr(ref t, _, _, _) => t.signature_contains_type(other), - TArray(ref t, _, _) => t.signature_contains_type(other), - TComp(ref info) => info.borrow().signature_contains_type(other), - _ => false, - } - } - - // XXX Add this info to enums? - pub fn was_unnamed(&self) -> bool { - match *self { - TComp(ref ci) => ci.borrow().was_unnamed, - TArray(ref t, _, _) => t.was_unnamed(), - TPtr(ref t, _, _, _) => t.was_unnamed(), - _ => false, - } - } - - pub fn get_outermost_composite(&self) -> Option>> { - match *self { - TComp(ref ci) => Some(ci.clone()), - TArray(ref t, _, _) => t.get_outermost_composite(), - TPtr(ref t, _, _, _) => t.get_outermost_composite(), - _ => None, - } - } - - pub fn size(&self) -> usize { - self.layout().map(|l| l.size).unwrap_or(0) - } - - pub fn align(&self) -> usize { - self.layout().map(|l| l.align).unwrap_or(0) - } - - pub fn layout(&self) -> Option { - Some(match *self { - TInt(_, l) => l.clone(), - TFloat(_, l) => l.clone(), - TPtr(_, _, _, l) => l.clone(), - TArray(_, _, l) => l.clone(), - TComp(ref ci) => ci.borrow().layout.clone(), - TEnum(ref ei) => ei.borrow().layout.clone(), - // Test first with the underlying type layout, else with the reported one - // This fixes a weird bug in SM when it can't find layout for uint32_t - TNamed(ref ti) => ti.borrow().ty.layout().unwrap_or(ti.borrow().layout.clone()), - TVoid | - TFuncProto(..) | - TFuncPtr(..) => return None, - }) - } - - pub fn can_derive_debug(&self) -> bool { - !self.is_opaque() && match *self { - TArray(ref t, size, _) => size <= 32 && t.can_derive_debug(), - TNamed(ref ti) => ti.borrow().ty.can_derive_debug(), - TComp(ref comp) => comp.borrow().can_derive_debug(), - _ => true, - } - } - - // For some reason, deriving copies of an array of a type that is not known to be copy - // is a compile error. e.g.: - // - // #[derive(Copy)] - // struct A { - // member: T, - // } - // - // is fine, while: - // - // #[derive(Copy)] - // struct A { - // member: [T; 1], - // } - // - // is an error. - // - // That's the point of the existance of can_derive_copy_in_array(). - pub fn can_derive_copy_in_array(&self) -> bool { - match *self { - TVoid => false, - TNamed(ref ti) => ti.borrow().ty.can_derive_copy_in_array(), - TArray(ref t, _, _) => t.can_derive_copy_in_array(), - ref t => t.can_derive_copy(), - } - } - - pub fn can_derive_copy(&self) -> bool { - !self.is_opaque() && match *self { - TArray(ref t, _, _) => t.can_derive_copy_in_array(), - TNamed(ref ti) => ti.borrow().ty.can_derive_copy(), - TComp(ref comp) => comp.borrow().can_derive_copy(), - _ => true, - } - } - - pub fn is_opaque(&self) -> bool { - match *self { - TArray(ref t, _, _) => t.is_opaque(), - TPtr(ref t, _, _, _) => t.is_opaque(), - TNamed(ref ti) => ti.borrow().opaque || ti.borrow().ty.is_opaque(), - TComp(ref ci) => ci.borrow().is_opaque(), - _ => false, - } - } - - #[allow(dead_code)] - pub fn is_union_like(&self) -> bool { - match *self { - TArray(ref t, _, _) => t.is_union_like(), - TPtr(ref t, _, _, _) => t.is_union_like(), - TNamed(ref ti) => ti.borrow().ty.is_union_like(), - TComp(ref ci) => ci.borrow().kind == CompKind::Union, - _ => false, - } - } - - // If a type is opaque we conservatively - // assume it has destructor - pub fn has_destructor(&self) -> bool { - self.is_opaque() || match *self { - TArray(ref t, _, _) => t.has_destructor(), - TNamed(ref ti) => ti.borrow().ty.has_destructor(), - TComp(ref ci) => ci.borrow().has_destructor(), - _ => false, - } - } - - pub fn is_translatable(&self) -> bool { - match *self { - TVoid => false, - TArray(ref t, _, _) => t.is_translatable(), - TComp(ref ci) => ci.borrow().is_translatable(), - // NB: TNamed explicitely ommited here - _ => true, - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Layout { - pub size: usize, - pub align: usize, - pub packed: bool, -} - -impl Layout { - pub fn new(size: usize, align: usize) -> Self { - Layout { size: size, align: align, packed: false } - } - - // TODO: make this fallible using fallible_size(). - pub fn from_ty(ty: &clang::Type) -> Self { - Self::new(ty.size(), ty.align()) - } - - pub fn zero() -> Layout { - Layout { size: 0, align: 0, packed: false } - } - - pub fn is_zero(&self) -> bool { - *self == Self::zero() - } -} - -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum IKind { - IBool, - ISChar, - IUChar, - IShort, - IUShort, - IInt, - IUInt, - ILong, - IULong, - ILongLong, - IULongLong -} - -impl IKind { - #[allow(dead_code)] - pub fn is_signed(self) -> bool { - match self { - IBool => false, - ISChar => true, - IUChar => false, - IShort => true, - IUShort => false, - IInt => true, - IUInt => false, - ILong => true, - IULong => false, - ILongLong => true, - IULongLong => false, - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum FKind { - FFloat, - FDouble -} - -#[derive(Clone, PartialEq, Debug)] -pub enum CompMember { - Field(FieldInfo), - Comp(Rc>), - Enum(Rc>), -} - -#[derive(Copy, Clone, PartialEq)] -pub enum CompKind { - Struct, - Union, -} - -#[derive(Clone, PartialEq)] -pub struct CompInfo { - pub kind: CompKind, - pub name: String, - pub module_id: ModuleId, - pub filename: String, - pub comment: String, - pub members: Vec, - pub args: Vec, - pub methods: Vec, - pub vmethods: Vec, - pub ref_template: Option, - pub has_vtable: bool, - pub has_destructor: bool, - pub has_nonempty_base: bool, - pub hide: bool, - pub parser_cursor: Option, - /// If this struct should be replaced by an opaque blob. - /// - /// This is useful if for some reason we can't generate - /// the correct layout. - pub opaque: bool, - pub base_members: usize, - layout: Layout, - /// If this struct is explicitely marked as non-copiable. - pub no_copy: bool, - /// Typedef'd types names, that we'll resolve early to avoid name conflicts - pub typedefs: Vec, - /// If this type has a template parameter which is not a type (e.g.: a size_t) - pub has_non_type_template_params: bool, - /// If this type was unnamed when parsed - pub was_unnamed: bool, - /// Set of static vars declared inside this class. - pub vars: Vec, - /// Used to detect if we've run in a can_derive_debug cycle while cycling - /// around the template arguments. - detect_derive_debug_cycle: Cell, - /// Used to detect if we've run in a has_destructor cycle while cycling - /// around the template arguments. - detect_has_destructor_cycle: Cell, - - /// Annotations on the decl - pub anno: Annotations, -} - -static mut UNNAMED_COUNTER: u32 = 0; - -fn unnamed_name(name: String, filename: &String) -> String { - if name.is_empty() { - let n = unsafe { UNNAMED_COUNTER += 1; UNNAMED_COUNTER }; - format!("{}_unnamed_{}", filename, n) - } else { - name - } -} - -impl CompInfo { - pub fn new(name: String, - module_id: ModuleId, - filename: String, - comment: String, - kind: CompKind, - members: Vec, - layout: Layout, - anno: Annotations) -> CompInfo { - let was_unnamed = name.is_empty(); - CompInfo { - kind: kind, - module_id: module_id, - name: unnamed_name(name, &filename), - filename: filename, - comment: comment, - members: members, - args: vec![], - methods: vec![], - vmethods: vec![], - ref_template: None, - has_vtable: false, - has_destructor: false, - has_nonempty_base: false, - hide: false, - parser_cursor: None, - opaque: false, - no_copy: false, - base_members: 0, - layout: layout, - typedefs: vec![], - vars: vec![], - has_non_type_template_params: false, - was_unnamed: was_unnamed, - detect_derive_debug_cycle: Cell::new(false), - detect_has_destructor_cycle: Cell::new(false), - anno: anno, - } - } - - // Gets or computes the layout as appropriately. - pub fn layout(&self) -> Layout { - use std::cmp; - // The returned layout from clang is zero as of right now, but we should - // change it to be fallible to distinguish correctly between zero-sized - // types and unknown layout. - if !self.layout.is_zero() { - return self.layout.clone(); - } - - if self.args.is_empty() { - return self.layout.clone(); - } - - if self.kind == CompKind::Struct { - return self.layout.clone(); - } - - // If we're a union without known layout, we try to compute it from our - // members. This is not ideal, but clang fails to report the size for - // these kind of unions, see test/headers/template_union.hpp - let mut max_size = 0; - let mut max_align = 0; - for member in &self.members { - let layout = match *member { - CompMember::Field(ref f) => f.ty.layout().unwrap_or(Layout::zero()), - CompMember::Comp(ref ci) => ci.borrow().layout(), - CompMember::Enum(ref ei) => ei.borrow().layout.clone(), - }; - - max_size = cmp::max(max_size, layout.size); - max_align = cmp::max(max_align, layout.align); - } - - Layout::new(max_size, max_align) - } - - pub fn set_packed(&mut self, packed: bool) { - self.layout.packed = packed - } - - // Return the module id or the class declaration module id. - pub fn module_id(&self) -> ModuleId { - self.ref_template.as_ref().and_then(|t| if let TComp(ref ci) = *t { - Some(ci.borrow().module_id) - } else { - None - }).unwrap_or(self.module_id) - } - - pub fn can_derive_debug(&self) -> bool { - if self.hide || self.is_opaque() { - return false; - } - - if self.detect_derive_debug_cycle.get() { - println!("Derive debug cycle detected: {}!", self.name); - return true; - } - - match self.kind { - CompKind::Union => { - let size_divisor = if self.layout.align == 0 { 1 } else { self.layout.align }; - if self.layout.size / size_divisor > 32 { - return false; - } - - true - } - CompKind::Struct => { - self.detect_derive_debug_cycle.set(true); - - let can_derive_debug = self.args.iter().all(|ty| ty.can_derive_debug()) && - self.members.iter() - .all(|member| match *member { - CompMember::Field(ref f) => f.ty.can_derive_debug(), - _ => true, - }); - self.detect_derive_debug_cycle.set(false); - - can_derive_debug - } - } - } - - pub fn is_opaque(&self) -> bool { - if let Some(ref template) = self.ref_template { - if template.is_opaque() { - return true; - } - } - self.opaque - } - - pub fn has_destructor(&self) -> bool { - if self.detect_has_destructor_cycle.get() { - warn!("Cycle detected looking for destructors: {}!", self.name); - // Assume no destructor, since we don't have an explicit one. - return false; - } - - self.detect_has_destructor_cycle.set(true); - - let has_destructor = self.has_destructor || match self.kind { - CompKind::Union => false, - CompKind::Struct => { - // NB: We can't rely on a type with type parameters - // not having destructor. - // - // This is unfortunate, but... - self.ref_template.as_ref().map_or(false, |t| t.has_destructor()) || - self.args.iter().any(|t| t.has_destructor()) || - self.members.iter().enumerate().any(|(index, m)| match *m { - CompMember::Field(ref f) => { - // Base members may not be resolved yet - if index < self.base_members { - f.ty.has_destructor() - } else { - f.ty.has_destructor() || !f.ty.is_translatable() - } - }, - _ => false, - }) - } - }; - - self.detect_has_destructor_cycle.set(false); - - has_destructor - } - - pub fn can_derive_copy(&self) -> bool { - if self.no_copy { - return false; - } - - // NOTE: Take into account that while unions in C and C++ are copied by - // default, the may have an explicit destructor in C++, so we can't - // defer this check just for the union case. - if self.has_destructor() { - return false; - } - - match self.kind { - CompKind::Union => true, - CompKind::Struct => { - // With template args, use a safe subset of the types, - // since copyability depends on the types itself. - self.ref_template.as_ref().map_or(true, |t| t.can_derive_copy()) && - self.members.iter().all(|m| match *m { - CompMember::Field(ref f) => f.ty.can_derive_copy(), - _ => true, - }) - } - } - } - - pub fn is_translatable(&self) -> bool { - match self.kind { - CompKind::Union => true, - CompKind::Struct => { - self.args.iter().all(|t| t != &TVoid) && !self.has_non_type_template_params - } - } - } - - pub fn signature_contains_type(&self, other: &Type) -> bool { - self.args.iter().any(|t| t.signature_contains_type(other)) - } -} - -impl fmt::Debug for CompInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "CompInfo({}, ref: {:?}, args: {:?}, members: {:?}", self.name, self.ref_template, self.args, self.members) - } -} - -#[derive(Clone, PartialEq)] -pub struct FieldInfo { - pub name: String, - pub ty: Type, - pub comment: String, - pub bitfields: Option>, - /// If the C++ field is marked as `mutable` - pub mutable: bool, - /// True when field or enclosing struct - /// has a `
` annotation - pub private: bool, - /// Set by the `
` - /// annotation on a field or enclosing struct - pub accessor: Accessor, -} - -impl FieldInfo { - pub fn new(name: String, - ty: Type, - comment: String, - bitfields: Option>, - mutable: bool) -> FieldInfo { - FieldInfo { - name: name, - ty: ty, - comment: comment, - bitfields: bitfields, - mutable: mutable, - private: false, - accessor: Accessor::None, - } - } -} - -impl fmt::Debug for FieldInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.name.fmt(f) - } -} - -#[derive(Clone, PartialEq)] -pub struct EnumInfo { - pub name: String, - pub module_id: ModuleId, - pub comment: String, - pub filename: String, - pub items: Vec, - pub kind: IKind, - pub layout: Layout, -} - -impl EnumInfo { - pub fn new(name: String, module_id: ModuleId, filename: String, kind: IKind, items: Vec, layout: Layout) -> EnumInfo { - EnumInfo { - name: unnamed_name(name, &filename), - module_id: module_id, - comment: String::new(), - filename: filename, - items: items, - kind: kind, - layout: layout, - } - } -} - -impl fmt::Debug for EnumInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.name.fmt(f) - } -} - -#[derive(Clone, PartialEq)] -pub struct EnumItem { - pub name: String, - pub comment: String, - pub val: i64 -} - -impl EnumItem { - pub fn new(name: String, comment: String, val: i64) -> EnumItem { - EnumItem { - name: name, - comment: comment, - val: val - } - } -} - -#[derive(Clone, PartialEq)] -pub struct TypeInfo { - pub name: String, - pub module_id: ModuleId, - pub comment: String, - pub ty: Type, - pub layout: Layout, - // TODO: Is this really useful? - // You can just make opaque the underlying type - pub opaque: bool, - pub hide: bool, -} - -impl TypeInfo { - pub fn new(name: String, module_id: ModuleId, ty: Type, layout: Layout) -> TypeInfo { - TypeInfo { - name: name, - module_id: module_id, - comment: String::new(), - ty: ty, - layout: layout, - opaque: false, - hide: false, - } - } -} - -impl fmt::Debug for TypeInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.name.fmt(f) - } -} - -#[derive(Clone, PartialEq)] -pub struct VarInfo { - pub name: String, - pub mangled: String, - pub comment: String, - pub ty: Type, - //TODO: support non-integer constants - pub val: Option, - pub is_const: bool, - pub is_static: bool, -} - -impl VarInfo { - pub fn new(name: String, mangled: String, comment: String, ty: Type) -> VarInfo { - let mangled = if name == mangled { - String::new() - } else { - mangled - }; - VarInfo { - name: name, - mangled: mangled, - comment: comment, - ty: ty, - val: None, - is_const: false, - is_static: false, - } - } -} - -impl fmt::Debug for VarInfo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.name.fmt(f) - } -} diff --git a/tests/expectations/accessors.rs b/tests/expectations/accessors.rs index 8d314878fc..b721980c4c 100644 --- a/tests/expectations/accessors.rs +++ b/tests/expectations/accessors.rs @@ -6,7 +6,7 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_SomeAccessors { +pub struct SomeAccessors { pub mNoAccessor: ::std::os::raw::c_int, /**
*/ pub mBothAccessors: ::std::os::raw::c_int, @@ -15,11 +15,20 @@ pub struct Struct_SomeAccessors { /**
*/ pub mImmutableAccessor: ::std::os::raw::c_int, } -impl Struct_SomeAccessors { +#[test] +fn bindgen_test_layout_SomeAccessors() { + assert_eq!(::std::mem::size_of::() , 16usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for SomeAccessors { + fn clone(&self) -> Self { *self } +} +impl SomeAccessors { #[inline] pub fn get_mBothAccessors(&self) -> &::std::os::raw::c_int { &self.mBothAccessors } + #[inline] pub fn get_mBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int { &mut self.mBothAccessors } @@ -27,6 +36,7 @@ impl Struct_SomeAccessors { pub unsafe fn get_mUnsafeAccessors(&self) -> &::std::os::raw::c_int { &self.mUnsafeAccessors } + #[inline] pub unsafe fn get_mUnsafeAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int { &mut self.mUnsafeAccessors @@ -36,26 +46,27 @@ impl Struct_SomeAccessors { &self.mImmutableAccessor } } -impl ::std::clone::Clone for Struct_SomeAccessors { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Struct_SomeAccessors() { - assert_eq!(::std::mem::size_of::() , 16usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} /**
*/ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_AllAccessors { +pub struct AllAccessors { pub mBothAccessors: ::std::os::raw::c_int, pub mAlsoBothAccessors: ::std::os::raw::c_int, } -impl Struct_AllAccessors { +#[test] +fn bindgen_test_layout_AllAccessors() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for AllAccessors { + fn clone(&self) -> Self { *self } +} +impl AllAccessors { #[inline] pub fn get_mBothAccessors(&self) -> &::std::os::raw::c_int { &self.mBothAccessors } + #[inline] pub fn get_mBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int { &mut self.mBothAccessors } @@ -63,31 +74,33 @@ impl Struct_AllAccessors { pub fn get_mAlsoBothAccessors(&self) -> &::std::os::raw::c_int { &self.mAlsoBothAccessors } + #[inline] pub fn get_mAlsoBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int { &mut self.mAlsoBothAccessors } } -impl ::std::clone::Clone for Struct_AllAccessors { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Struct_AllAccessors() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} /**
*/ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_AllUnsafeAccessors { +pub struct AllUnsafeAccessors { pub mBothAccessors: ::std::os::raw::c_int, pub mAlsoBothAccessors: ::std::os::raw::c_int, } -impl Struct_AllUnsafeAccessors { +#[test] +fn bindgen_test_layout_AllUnsafeAccessors() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for AllUnsafeAccessors { + fn clone(&self) -> Self { *self } +} +impl AllUnsafeAccessors { #[inline] pub unsafe fn get_mBothAccessors(&self) -> &::std::os::raw::c_int { &self.mBothAccessors } + #[inline] pub unsafe fn get_mBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int { &mut self.mBothAccessors @@ -96,23 +109,16 @@ impl Struct_AllUnsafeAccessors { pub unsafe fn get_mAlsoBothAccessors(&self) -> &::std::os::raw::c_int { &self.mAlsoBothAccessors } + #[inline] pub unsafe fn get_mAlsoBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int { &mut self.mAlsoBothAccessors } } -impl ::std::clone::Clone for Struct_AllUnsafeAccessors { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Struct_AllUnsafeAccessors() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} /**
*/ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_ContradictAccessors { +pub struct ContradictAccessors { pub mBothAccessors: ::std::os::raw::c_int, /**
*/ pub mNoAccessors: ::std::os::raw::c_int, @@ -121,11 +127,20 @@ pub struct Struct_ContradictAccessors { /**
*/ pub mImmutableAccessor: ::std::os::raw::c_int, } -impl Struct_ContradictAccessors { +#[test] +fn bindgen_test_layout_ContradictAccessors() { + assert_eq!(::std::mem::size_of::() , 16usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for ContradictAccessors { + fn clone(&self) -> Self { *self } +} +impl ContradictAccessors { #[inline] pub fn get_mBothAccessors(&self) -> &::std::os::raw::c_int { &self.mBothAccessors } + #[inline] pub fn get_mBothAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int { &mut self.mBothAccessors } @@ -133,6 +148,7 @@ impl Struct_ContradictAccessors { pub unsafe fn get_mUnsafeAccessors(&self) -> &::std::os::raw::c_int { &self.mUnsafeAccessors } + #[inline] pub unsafe fn get_mUnsafeAccessors_mut(&mut self) -> &mut ::std::os::raw::c_int { &mut self.mUnsafeAccessors @@ -142,53 +158,47 @@ impl Struct_ContradictAccessors { &self.mImmutableAccessor } } -impl ::std::clone::Clone for Struct_ContradictAccessors { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Struct_ContradictAccessors() { - assert_eq!(::std::mem::size_of::() , 16usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} /**
*/ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_Replaced { +pub struct Replaced { pub mAccessor: ::std::os::raw::c_int, } -impl Struct_Replaced { +#[test] +fn bindgen_test_layout_Replaced() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for Replaced { + fn clone(&self) -> Self { *self } +} +impl Replaced { #[inline] pub fn get_mAccessor(&self) -> &::std::os::raw::c_int { &self.mAccessor } + #[inline] pub fn get_mAccessor_mut(&mut self) -> &mut ::std::os::raw::c_int { &mut self.mAccessor } } -impl ::std::clone::Clone for Struct_Replaced { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Struct_Replaced() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} /**
*/ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_Wrapper { - pub mReplaced: Struct_Replaced, +pub struct Wrapper { + pub mReplaced: Replaced, } -impl Struct_Wrapper { - #[inline] - pub fn get_mReplaced(&self) -> &Struct_Replaced { &self.mReplaced } - pub fn get_mReplaced_mut(&mut self) -> &mut Struct_Replaced { - &mut self.mReplaced - } +#[test] +fn bindgen_test_layout_Wrapper() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Struct_Wrapper { +impl Clone for Wrapper { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Struct_Wrapper() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +impl Wrapper { + #[inline] + pub fn get_mReplaced(&self) -> &Replaced { &self.mReplaced } + #[inline] + pub fn get_mReplaced_mut(&mut self) -> &mut Replaced { + &mut self.mReplaced + } } diff --git a/tests/expectations/annotation_hide.rs b/tests/expectations/annotation_hide.rs index 14ba8310e5..dcaf7997b6 100644 --- a/tests/expectations/annotation_hide.rs +++ b/tests/expectations/annotation_hide.rs @@ -4,8 +4,11 @@ #![allow(non_snake_case)] -pub enum Struct_C { } +/** + *
+ */ #[repr(C)] +#[derive(Debug, Copy)] pub struct D { pub _bindgen_opaque_blob: u32, } @@ -14,16 +17,19 @@ fn bindgen_test_layout_D() { assert_eq!(::std::mem::size_of::() , 4usize); assert_eq!(::std::mem::align_of::() , 4usize); } +impl Clone for D { + fn clone(&self) -> Self { *self } +} #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_NotAnnotated { +pub struct NotAnnotated { pub f: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_NotAnnotated { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_NotAnnotated() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_NotAnnotated() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for NotAnnotated { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/anon_enum.rs b/tests/expectations/anon_enum.rs new file mode 100644 index 0000000000..6b8688e135 --- /dev/null +++ b/tests/expectations/anon_enum.rs @@ -0,0 +1,23 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Test { + pub foo: ::std::os::raw::c_int, + pub bar: f32, +} +#[repr(u32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Test__bindgen_ty_bindgen_id_4 { T_NONE = 0, } +#[test] +fn bindgen_test_layout_Test() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for Test { + fn clone(&self) -> Self { *self } +} diff --git a/tests/expectations/anon_enum_whitelist.rs b/tests/expectations/anon_enum_whitelist.rs new file mode 100644 index 0000000000..62c1f1a5e1 --- /dev/null +++ b/tests/expectations/anon_enum_whitelist.rs @@ -0,0 +1,13 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +pub const NODE_FLAG_FOO: _bindgen_ty_bindgen_id_1 = + _bindgen_ty_bindgen_id_1::NODE_FLAG_FOO; +pub const NODE_FLAG_BAR: _bindgen_ty_bindgen_id_1 = + _bindgen_ty_bindgen_id_1::NODE_FLAG_BAR; +#[repr(u32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum _bindgen_ty_bindgen_id_1 { NODE_FLAG_FOO = 0, NODE_FLAG_BAR = 1, } diff --git a/tests/expectations/anon_union.rs b/tests/expectations/anon_union.rs new file mode 100644 index 0000000000..66963f40f9 --- /dev/null +++ b/tests/expectations/anon_union.rs @@ -0,0 +1,73 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[derive(Debug)] +#[repr(C)] +pub struct __BindgenUnionField(::std::marker::PhantomData); +impl __BindgenUnionField { + #[inline] + pub fn new() -> Self { __BindgenUnionField(::std::marker::PhantomData) } + #[inline] + pub unsafe fn as_ref(&self) -> &T { ::std::mem::transmute(self) } + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { ::std::mem::transmute(self) } +} +impl ::std::default::Default for __BindgenUnionField { + #[inline] + fn default() -> Self { Self::new() } +} +impl ::std::clone::Clone for __BindgenUnionField { + #[inline] + fn clone(&self) -> Self { Self::new() } +} +impl ::std::marker::Copy for __BindgenUnionField { } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TErrorResult { + pub mResult: ::std::os::raw::c_int, + pub __bindgen_anon_1: TErrorResult__bindgen_ty_bindgen_id_9, + pub mMightHaveUnreported: bool, + pub mUnionState: TErrorResult_UnionState, + pub _phantom_0: ::std::marker::PhantomData, +} +pub const TErrorResult_UnionState_HasException: TErrorResult_UnionState = + TErrorResult_UnionState::HasMessage; +#[repr(i32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum TErrorResult_UnionState { HasMessage = 0, } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TErrorResult_Message { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TErrorResult_DOMExceptionInfo { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct TErrorResult__bindgen_ty_bindgen_id_9 { + pub mMessage: __BindgenUnionField<*mut TErrorResult_Message>, + pub mDOMExceptionInfo: __BindgenUnionField<*mut TErrorResult_DOMExceptionInfo>, + pub bindgen_union_field: u64, + pub _phantom_0: ::std::marker::PhantomData, +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct ErrorResult { + pub _base: TErrorResult<::std::os::raw::c_int>, +} +#[test] +fn bindgen_test_layout_ErrorResult() { + assert_eq!(::std::mem::size_of::() , 24usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for ErrorResult { + fn clone(&self) -> Self { *self } +} diff --git a/tests/expectations/arg_keyword.rs b/tests/expectations/arg_keyword.rs new file mode 100644 index 0000000000..cb1cc4327a --- /dev/null +++ b/tests/expectations/arg_keyword.rs @@ -0,0 +1,10 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +extern "C" { + #[link_name = "_Z3fooPKc"] + pub fn foo(type_: *const ::std::os::raw::c_char); +} diff --git a/tests/expectations/class.rs b/tests/expectations/class.rs index 450a57a6a5..5951e0e699 100644 --- a/tests/expectations/class.rs +++ b/tests/expectations/class.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,65 +23,52 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] -#[derive(Copy)] -pub struct Struct_C { +pub struct C { pub a: ::std::os::raw::c_int, pub big_array: [::std::os::raw::c_char; 33usize], } -impl ::std::clone::Clone for Struct_C { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_C() { - assert_eq!(::std::mem::size_of::() , 40usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_C() { + assert_eq!(::std::mem::size_of::() , 40usize); + assert_eq!(::std::mem::align_of::() , 4usize); } #[repr(C)] #[derive(Debug)] -pub struct Struct_WithDtor { +pub struct WithDtor { pub b: ::std::os::raw::c_int, } #[test] -fn bindgen_test_layout_Struct_WithDtor() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_WithDtor() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_Union { +pub struct Union { pub d: __BindgenUnionField, pub i: __BindgenUnionField<::std::os::raw::c_int>, - pub _bindgen_data_: u32, + pub bindgen_union_field: u32, } -impl Union_Union { - pub unsafe fn d(&mut self) -> *mut f32 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn i(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } +#[test] +fn bindgen_test_layout_Union() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Union_Union { +impl Clone for Union { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Union_Union() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_WithUnion { - pub data: Union_Union, -} -impl ::std::clone::Clone for Struct_WithUnion { - fn clone(&self) -> Self { *self } +pub struct WithUnion { + pub data: Union, } #[test] -fn bindgen_test_layout_Struct_WithUnion() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_WithUnion() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for WithUnion { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/class_nested.rs b/tests/expectations/class_nested.rs index 22e7220969..593e156d36 100644 --- a/tests/expectations/class_nested.rs +++ b/tests/expectations/class_nested.rs @@ -6,53 +6,54 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_A { +pub struct A { pub member_a: ::std::os::raw::c_int, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_A_B { +pub struct A_B { pub member_b: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_A_B { +#[test] +fn bindgen_test_layout_A_B() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for A_B { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_A_B() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Struct_A { +impl Clone for A { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Struct_A() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +extern "C" { + #[link_name = "var"] + pub static mut var: A_B; } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_D { - pub member: Struct_A_B, -} -impl ::std::clone::Clone for Struct_D { - fn clone(&self) -> Self { *self } +pub struct D { + pub member: A_B, } #[test] -fn bindgen_test_layout_Struct_D() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_D() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for D { + fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_Templated { +pub struct Templated { pub member: T, } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_Templated_Templated_inner { +pub struct Templated_Templated_inner { pub member_ptr: *mut T, } -extern "C" { - pub static mut var: Struct_A_B; -} diff --git a/tests/expectations/class_no_members.rs b/tests/expectations/class_no_members.rs index 8468c02b59..017f7c2266 100644 --- a/tests/expectations/class_no_members.rs +++ b/tests/expectations/class_no_members.rs @@ -6,31 +6,40 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_whatever; -impl ::std::clone::Clone for Struct_whatever { +pub struct whatever { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_whatever() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +impl Clone for whatever { fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_whatever_child { - pub _base: Struct_whatever, +pub struct whatever_child { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_whatever_child() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); } -impl ::std::clone::Clone for Struct_whatever_child { +impl Clone for whatever_child { fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_whatever_child_with_member { - pub _base: Struct_whatever, +pub struct whatever_child_with_member { pub m_member: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_whatever_child_with_member { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_whatever_child_with_member() { - assert_eq!(::std::mem::size_of::() , - 4usize); - assert_eq!(::std::mem::align_of::() , - 4usize); +fn bindgen_test_layout_whatever_child_with_member() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for whatever_child_with_member { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/class_static.rs b/tests/expectations/class_static.rs index 8aa156d89f..8108be2da3 100644 --- a/tests/expectations/class_static.rs +++ b/tests/expectations/class_static.rs @@ -6,15 +6,27 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_MyClass; -impl ::std::clone::Clone for Struct_MyClass { - fn clone(&self) -> Self { *self } +pub struct MyClass { + pub _address: u8, } extern "C" { #[link_name = "_ZN7MyClass7exampleE"] - pub static mut Struct_MyClass_consts_example: - *const ::std::os::raw::c_int; + pub static mut MyClass_example: *const ::std::os::raw::c_int; +} +extern "C" { #[link_name = "_ZN7MyClass26example_check_no_collisionE"] - pub static mut Struct_MyClass_consts_example_check_no_collision: + pub static mut MyClass_example_check_no_collision: *const ::std::os::raw::c_int; } +#[test] +fn bindgen_test_layout_MyClass() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +impl Clone for MyClass { + fn clone(&self) -> Self { *self } +} +extern "C" { + #[link_name = "_ZL26example_check_no_collision"] + pub static mut example_check_no_collision: *const ::std::os::raw::c_int; +} diff --git a/tests/expectations/class_use_as.rs b/tests/expectations/class_use_as.rs index 4d06fecac4..c3843b31ee 100644 --- a/tests/expectations/class_use_as.rs +++ b/tests/expectations/class_use_as.rs @@ -9,27 +9,27 @@ */ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_whatever { +pub struct whatever { pub replacement: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_whatever { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_whatever() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_whatever() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for whatever { + fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_container { - pub c: Struct_whatever, -} -impl ::std::clone::Clone for Struct_container { - fn clone(&self) -> Self { *self } +pub struct container { + pub c: whatever, } #[test] -fn bindgen_test_layout_Struct_container() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_container() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for container { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/class_with_dtor.rs b/tests/expectations/class_with_dtor.rs index 3cc48dfbb4..8ed1ddf9fe 100644 --- a/tests/expectations/class_with_dtor.rs +++ b/tests/expectations/class_with_dtor.rs @@ -6,17 +6,17 @@ #[repr(C)] #[derive(Debug)] -pub struct Struct_HandleWithDtor { +pub struct HandleWithDtor { pub ptr: *mut T, } -pub type HandleValue = Struct_HandleWithDtor<::std::os::raw::c_int>; +pub type HandleValue = HandleWithDtor<::std::os::raw::c_int>; #[repr(C)] #[derive(Debug)] -pub struct Struct_WithoutDtor { +pub struct WithoutDtor { pub shouldBeWithDtor: HandleValue, } #[test] -fn bindgen_test_layout_Struct_WithoutDtor() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 8usize); +fn bindgen_test_layout_WithoutDtor() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); } diff --git a/tests/expectations/class_with_inner_struct.rs b/tests/expectations/class_with_inner_struct.rs index b465a1832a..464c622df0 100644 --- a/tests/expectations/class_with_inner_struct.rs +++ b/tests/expectations/class_with_inner_struct.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,109 +23,94 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_A { +pub struct A { pub c: ::std::os::raw::c_uint, - pub named_union: Union_A_class_with_inner_struct_hpp_unnamed_1, - pub A_class_with_inner_struct_hpp_unnamed_2: Union_A_class_with_inner_struct_hpp_unnamed_2, + pub named_union: A__bindgen_ty_bindgen_id_6, + pub __bindgen_anon_1: A__bindgen_ty_bindgen_id_9, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_A_Segment { +pub struct A_Segment { pub begin: ::std::os::raw::c_int, pub end: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_A_Segment { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_A_Segment() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_A_Segment() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for A_Segment { + fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_A_class_with_inner_struct_hpp_unnamed_1 { +pub struct A__bindgen_ty_bindgen_id_6 { pub f: __BindgenUnionField<::std::os::raw::c_int>, - pub _bindgen_data_: u32, + pub bindgen_union_field: u32, } -impl Union_A_class_with_inner_struct_hpp_unnamed_1 { - pub unsafe fn f(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } +#[test] +fn bindgen_test_layout_A__bindgen_ty_bindgen_id_6() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Union_A_class_with_inner_struct_hpp_unnamed_1 { +impl Clone for A__bindgen_ty_bindgen_id_6 { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Union_A_class_with_inner_struct_hpp_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 4usize); - assert_eq!(::std::mem::align_of::() - , 4usize); -} #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_A_class_with_inner_struct_hpp_unnamed_2 { +pub struct A__bindgen_ty_bindgen_id_9 { pub d: __BindgenUnionField<::std::os::raw::c_int>, - pub _bindgen_data_: u32, + pub bindgen_union_field: u32, } -impl Union_A_class_with_inner_struct_hpp_unnamed_2 { - pub unsafe fn d(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } +#[test] +fn bindgen_test_layout_A__bindgen_ty_bindgen_id_9() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Union_A_class_with_inner_struct_hpp_unnamed_2 { +impl Clone for A__bindgen_ty_bindgen_id_9 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Union_A_class_with_inner_struct_hpp_unnamed_2() { - assert_eq!(::std::mem::size_of::() - , 4usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 12usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Struct_A { +impl Clone for A { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Struct_A() { - assert_eq!(::std::mem::size_of::() , 12usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_B { +pub struct B { pub d: ::std::os::raw::c_uint, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_B_Segment { +pub struct B_Segment { pub begin: ::std::os::raw::c_int, pub end: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_B_Segment { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_B_Segment() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_B_Segment() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Struct_B { +impl Clone for B_Segment { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_B() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_B() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for B { + fn clone(&self) -> Self { *self } } #[repr(i32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_StepSyntax { +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum StepSyntax { Keyword = 0, FunctionalWithoutKeyword = 1, FunctionalWithStartKeyword = 2, @@ -133,98 +118,80 @@ pub enum Enum_StepSyntax { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_C { +pub struct C { pub d: ::std::os::raw::c_uint, - pub C_class_with_inner_struct_hpp_unnamed_3: Union_C_class_with_inner_struct_hpp_unnamed_3, + pub __bindgen_anon_1: C__bindgen_ty_bindgen_id_21, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_C_class_with_inner_struct_hpp_unnamed_3 { - pub mFunc: __BindgenUnionField, - pub C_class_with_inner_struct_hpp_unnamed_3_class_with_inner_struct_hpp_unnamed_5: __BindgenUnionField, - pub _bindgen_data_: [u32; 4usize], -} -impl Union_C_class_with_inner_struct_hpp_unnamed_3 { - pub unsafe fn mFunc(&mut self) - -> - *mut Struct_C_class_with_inner_struct_hpp_unnamed_3_class_with_inner_struct_hpp_unnamed_4 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn C_class_with_inner_struct_hpp_unnamed_3_class_with_inner_struct_hpp_unnamed_5(&mut self) - -> - *mut Struct_C_class_with_inner_struct_hpp_unnamed_3_class_with_inner_struct_hpp_unnamed_5 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } -} -impl ::std::clone::Clone for Union_C_class_with_inner_struct_hpp_unnamed_3 { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Union_C_class_with_inner_struct_hpp_unnamed_3() { - assert_eq!(::std::mem::size_of::() - , 16usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +pub struct C__bindgen_ty_bindgen_id_21 { + pub mFunc: __BindgenUnionField, + pub __bindgen_anon_1: __BindgenUnionField, + pub bindgen_union_field: [u32; 4usize], } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_C_class_with_inner_struct_hpp_unnamed_3_class_with_inner_struct_hpp_unnamed_4 { +pub struct C__bindgen_ty_bindgen_id_21__bindgen_ty_bindgen_id_22 { pub mX1: f32, pub mY1: f32, pub mX2: f32, pub mY2: f32, } -impl ::std::clone::Clone for - Struct_C_class_with_inner_struct_hpp_unnamed_3_class_with_inner_struct_hpp_unnamed_4 - { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_C_class_with_inner_struct_hpp_unnamed_3_class_with_inner_struct_hpp_unnamed_4() { - assert_eq!(::std::mem::size_of::() +fn bindgen_test_layout_C__bindgen_ty_bindgen_id_21__bindgen_ty_bindgen_id_22() { + assert_eq!(::std::mem::size_of::() , 16usize); - assert_eq!(::std::mem::align_of::() + assert_eq!(::std::mem::align_of::() , 4usize); } +impl Clone for C__bindgen_ty_bindgen_id_21__bindgen_ty_bindgen_id_22 { + fn clone(&self) -> Self { *self } +} #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_C_class_with_inner_struct_hpp_unnamed_3_class_with_inner_struct_hpp_unnamed_5 { - pub mStepSyntax: Enum_StepSyntax, +pub struct C__bindgen_ty_bindgen_id_21__bindgen_ty_bindgen_id_28 { + pub mStepSyntax: StepSyntax, pub mSteps: ::std::os::raw::c_uint, } -impl ::std::clone::Clone for - Struct_C_class_with_inner_struct_hpp_unnamed_3_class_with_inner_struct_hpp_unnamed_5 - { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_C_class_with_inner_struct_hpp_unnamed_3_class_with_inner_struct_hpp_unnamed_5() { - assert_eq!(::std::mem::size_of::() +fn bindgen_test_layout_C__bindgen_ty_bindgen_id_21__bindgen_ty_bindgen_id_28() { + assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() + assert_eq!(::std::mem::align_of::() , 4usize); } +impl Clone for C__bindgen_ty_bindgen_id_21__bindgen_ty_bindgen_id_28 { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_C__bindgen_ty_bindgen_id_21() { + assert_eq!(::std::mem::size_of::() , + 16usize); + assert_eq!(::std::mem::align_of::() , + 4usize); +} +impl Clone for C__bindgen_ty_bindgen_id_21 { + fn clone(&self) -> Self { *self } +} #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_C_Segment { +pub struct C_Segment { pub begin: ::std::os::raw::c_int, pub end: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_C_Segment { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_C_Segment() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_C_Segment() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Struct_C { +impl Clone for C_Segment { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_C() { - assert_eq!(::std::mem::size_of::() , 20usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_C() { + assert_eq!(::std::mem::size_of::() , 20usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for C { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/class_with_typedef.rs b/tests/expectations/class_with_typedef.rs index 44bce6d712..bc19f2bd0d 100644 --- a/tests/expectations/class_with_typedef.rs +++ b/tests/expectations/class_with_typedef.rs @@ -8,57 +8,65 @@ pub type AnotherInt = ::std::os::raw::c_int; #[repr(C)] #[derive(Debug, Copy)] pub struct C { - pub c: ::std::os::raw::c_int, - pub ptr: *mut ::std::os::raw::c_int, - pub arr: [::std::os::raw::c_int; 10usize], + pub c: C_MyInt, + pub ptr: *mut C_MyInt, + pub arr: [C_MyInt; 10usize], pub d: AnotherInt, pub other_ptr: *mut AnotherInt, } -impl ::std::clone::Clone for C { - fn clone(&self) -> Self { *self } -} +pub type C_MyInt = ::std::os::raw::c_int; +pub type C_Lookup = *const ::std::os::raw::c_char; #[test] fn bindgen_test_layout_C() { assert_eq!(::std::mem::size_of::() , 72usize); assert_eq!(::std::mem::align_of::() , 8usize); } extern "C" { - fn _ZN1C6methodEi(this: *mut C, c: ::std::os::raw::c_int); - fn _ZN1C9methodRefERi(this: *mut C, c: *mut ::std::os::raw::c_int); - fn _ZN1C16complexMethodRefERPKc(this: *mut C, - c: *mut *const ::std::os::raw::c_char); - fn _ZN1C13anotherMethodEi(this: *mut C, c: AnotherInt); + #[link_name = "_ZN1C6methodEi"] + pub fn C_method(this: *mut C, c: C_MyInt); +} +extern "C" { + #[link_name = "_ZN1C9methodRefERi"] + pub fn C_methodRef(this: *mut C, c: *mut C_MyInt); +} +extern "C" { + #[link_name = "_ZN1C16complexMethodRefERPKc"] + pub fn C_complexMethodRef(this: *mut C, c: *mut C_Lookup); +} +extern "C" { + #[link_name = "_ZN1C13anotherMethodEi"] + pub fn C_anotherMethod(this: *mut C, c: AnotherInt); +} +impl Clone for C { + fn clone(&self) -> Self { *self } } impl C { #[inline] - pub unsafe fn method(&mut self, c: ::std::os::raw::c_int) { - _ZN1C6methodEi(&mut *self, c) - } + pub unsafe fn method(&mut self, c: C_MyInt) { C_method(&mut *self, c) } #[inline] - pub unsafe fn methodRef(&mut self, c: *mut ::std::os::raw::c_int) { - _ZN1C9methodRefERi(&mut *self, c) + pub unsafe fn methodRef(&mut self, c: *mut C_MyInt) { + C_methodRef(&mut *self, c) } #[inline] - pub unsafe fn complexMethodRef(&mut self, - c: *mut *const ::std::os::raw::c_char) { - _ZN1C16complexMethodRefERPKc(&mut *self, c) + pub unsafe fn complexMethodRef(&mut self, c: *mut C_Lookup) { + C_complexMethodRef(&mut *self, c) } #[inline] pub unsafe fn anotherMethod(&mut self, c: AnotherInt) { - _ZN1C13anotherMethodEi(&mut *self, c) + C_anotherMethod(&mut *self, c) } } #[repr(C)] #[derive(Debug, Copy)] pub struct D { pub _base: C, - pub ptr: *mut ::std::os::raw::c_int, -} -impl ::std::clone::Clone for D { - fn clone(&self) -> Self { *self } + pub ptr: *mut C_MyInt, } #[test] fn bindgen_test_layout_D() { assert_eq!(::std::mem::size_of::() , 80usize); assert_eq!(::std::mem::align_of::() , 8usize); } +impl Clone for D { + fn clone(&self) -> Self { *self } +} diff --git a/tests/expectations/const_ptr.rs b/tests/expectations/const_ptr.rs new file mode 100644 index 0000000000..89400df17c --- /dev/null +++ b/tests/expectations/const_ptr.rs @@ -0,0 +1,9 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +extern "C" { + pub fn foo(bar: *const ::std::os::raw::c_void); +} diff --git a/tests/expectations/const_resolved_ty.rs b/tests/expectations/const_resolved_ty.rs new file mode 100644 index 0000000000..77d8f43823 --- /dev/null +++ b/tests/expectations/const_resolved_ty.rs @@ -0,0 +1,9 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +extern "C" { + pub fn foo(foo: *const u8); +} diff --git a/tests/expectations/const_tparam.rs b/tests/expectations/const_tparam.rs new file mode 100644 index 0000000000..59649626fc --- /dev/null +++ b/tests/expectations/const_tparam.rs @@ -0,0 +1,11 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct C { + pub foo: *mut T, +} diff --git a/tests/expectations/crtp.rs b/tests/expectations/crtp.rs index c6964524be..e4a86b2430 100644 --- a/tests/expectations/crtp.rs +++ b/tests/expectations/crtp.rs @@ -7,23 +7,37 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct Base { - pub _phantom0: ::std::marker::PhantomData, + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug, Copy)] pub struct Derived { - pub _base: Base, + pub _address: u8, } -impl ::std::clone::Clone for Derived { +#[test] +fn bindgen_test_layout_Derived() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +impl Clone for Derived { fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug)] pub struct BaseWithDestructor { - pub _phantom0: ::std::marker::PhantomData, + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug)] pub struct DerivedFromBaseWithDestructor { - pub _base: BaseWithDestructor, + pub _address: u8, +} +#[test] +fn bindgen_test_layout_DerivedFromBaseWithDestructor() { + assert_eq!(::std::mem::size_of::() , + 1usize); + assert_eq!(::std::mem::align_of::() , + 1usize); } diff --git a/tests/expectations/decl_ptr_to_array.rs b/tests/expectations/decl_ptr_to_array.rs index e7dabeee51..b8abedb5c3 100644 --- a/tests/expectations/decl_ptr_to_array.rs +++ b/tests/expectations/decl_ptr_to_array.rs @@ -5,5 +5,6 @@ extern "C" { - pub static mut foo: [::std::os::raw::c_int; 1usize]; + #[link_name = "foo"] + pub static mut foo: *mut [::std::os::raw::c_int; 1usize]; } diff --git a/tests/expectations/duplicated_constants_in_ns.rs b/tests/expectations/duplicated_constants_in_ns.rs index b4b7b2bcee..cb69890cc6 100644 --- a/tests/expectations/duplicated_constants_in_ns.rs +++ b/tests/expectations/duplicated_constants_in_ns.rs @@ -4,4 +4,14 @@ #![allow(non_snake_case)] - +pub mod root { + use root; + pub mod foo { + use root; + pub const FOO: ::std::os::raw::c_int = 4; + } + pub mod bar { + use root; + pub const FOO: ::std::os::raw::c_int = 5; + } +} diff --git a/tests/expectations/empty_template_param_name.rs b/tests/expectations/empty_template_param_name.rs new file mode 100644 index 0000000000..d165df80cc --- /dev/null +++ b/tests/expectations/empty_template_param_name.rs @@ -0,0 +1,12 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __iterator_traits<_Iterator> { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData<_Iterator>, +} diff --git a/tests/expectations/enum.rs b/tests/expectations/enum.rs index f6f510dd2f..8138d69781 100644 --- a/tests/expectations/enum.rs +++ b/tests/expectations/enum.rs @@ -5,8 +5,8 @@ #[repr(u32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Foo { Bar = 0, Qux = 1, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Foo { Bar = 0, Qux = 1, } #[repr(i32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Neg { MinusOne = -1, One = 1, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Neg { MinusOne = -1, One = 1, } diff --git a/tests/expectations/enum_alias.rs b/tests/expectations/enum_alias.rs new file mode 100644 index 0000000000..7ea8559863 --- /dev/null +++ b/tests/expectations/enum_alias.rs @@ -0,0 +1,9 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(u8)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Bar { VAL = 0, } diff --git a/tests/expectations/enum_and_vtable_mangling.rs b/tests/expectations/enum_and_vtable_mangling.rs index c68dc102c2..3c7d5370d4 100644 --- a/tests/expectations/enum_and_vtable_mangling.rs +++ b/tests/expectations/enum_and_vtable_mangling.rs @@ -4,27 +4,26 @@ #![allow(non_snake_case)] +pub const match_: _bindgen_ty_bindgen_id_1 = _bindgen_ty_bindgen_id_1::match_; +pub const whatever_else: _bindgen_ty_bindgen_id_1 = + _bindgen_ty_bindgen_id_1::whatever_else; #[repr(u32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_enum_and_vtable_mangling_hpp_unnamed_1 { - match_ = 0, - whatever_else = 1, +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum _bindgen_ty_bindgen_id_1 { match_ = 0, whatever_else = 1, } +#[repr(C)] +pub struct bindgen_vtable__bindgen_id_4 { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_C { - pub _vftable: *const _vftable_Struct_C, +pub struct C { + pub vtable_: *const bindgen_vtable__bindgen_id_4, pub i: ::std::os::raw::c_int, } -#[repr(C)] -pub struct _vftable_Struct_C { - pub match_: unsafe extern "C" fn(this: *mut ::std::os::raw::c_void), +#[test] +fn bindgen_test_layout_C() { + assert_eq!(::std::mem::size_of::() , 16usize); + assert_eq!(::std::mem::align_of::() , 8usize); } -impl ::std::clone::Clone for Struct_C { +impl Clone for C { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Struct_C() { - assert_eq!(::std::mem::size_of::() , 16usize); - assert_eq!(::std::mem::align_of::() , 8usize); -} diff --git a/tests/expectations/enum_dupe.rs b/tests/expectations/enum_dupe.rs index 10464881dc..322b89fc7c 100644 --- a/tests/expectations/enum_dupe.rs +++ b/tests/expectations/enum_dupe.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -pub const Dupe: Enum_Foo = Enum_Foo::Bar; +pub const Foo_Dupe: Foo = Foo::Bar; #[repr(u32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Foo { Bar = 1, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Foo { Bar = 1, } diff --git a/tests/expectations/enum_explicit_type.rs b/tests/expectations/enum_explicit_type.rs index 1b94c2848a..352f4ea90f 100644 --- a/tests/expectations/enum_explicit_type.rs +++ b/tests/expectations/enum_explicit_type.rs @@ -5,17 +5,17 @@ #[repr(u8)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Foo { Bar = 0, Qux = 1, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Foo { Bar = 0, Qux = 1, } #[repr(i8)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Neg { MinusOne = -1, One = 1, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Neg { MinusOne = -1, One = 1, } #[repr(u16)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Bigger { Much = 255, Larger = 256, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Bigger { Much = 255, Larger = 256, } #[repr(i64)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_MuchLong { MuchLow = -4294967296, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum MuchLong { MuchLow = -4294967296, } #[repr(u64)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_MuchLongLong { MuchHigh = 4294967296, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum MuchLongLong { MuchHigh = 4294967296, } diff --git a/tests/expectations/enum_negative.rs b/tests/expectations/enum_negative.rs index 03db5709ef..74cf4f1688 100644 --- a/tests/expectations/enum_negative.rs +++ b/tests/expectations/enum_negative.rs @@ -5,5 +5,5 @@ #[repr(i32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Foo { Bar = -2, Qux = 1, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Foo { Bar = -2, Qux = 1, } diff --git a/tests/expectations/enum_packed.rs b/tests/expectations/enum_packed.rs index 7684a26d21..963763e18b 100644 --- a/tests/expectations/enum_packed.rs +++ b/tests/expectations/enum_packed.rs @@ -5,11 +5,11 @@ #[repr(u8)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Foo { Bar = 0, Qux = 1, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Foo { Bar = 0, Qux = 1, } #[repr(i8)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Neg { MinusOne = -1, One = 1, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Neg { MinusOne = -1, One = 1, } #[repr(u16)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Bigger { Much = 255, Larger = 256, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Bigger { Much = 255, Larger = 256, } diff --git a/tests/expectations/extern.rs b/tests/expectations/extern.rs index 8f1223412e..e7ac750494 100644 --- a/tests/expectations/extern.rs +++ b/tests/expectations/extern.rs @@ -5,4 +5,5 @@ pub type foo = - unsafe extern "C" fn(bar: ::std::os::raw::c_int) -> ::std::os::raw::c_int; + ::std::option::Option ::std::os::raw::c_int>; diff --git a/tests/expectations/forward_declared_struct.rs b/tests/expectations/forward_declared_struct.rs index 3a812c0d16..5c2764e106 100644 --- a/tests/expectations/forward_declared_struct.rs +++ b/tests/expectations/forward_declared_struct.rs @@ -6,27 +6,27 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_a { +pub struct a { pub b: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_a { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_a() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_a() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for a { + fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_c { +pub struct c { pub d: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_c { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_c() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_c() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for c { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/func_proto.rs b/tests/expectations/func_proto.rs index 8f1223412e..e7ac750494 100644 --- a/tests/expectations/func_proto.rs +++ b/tests/expectations/func_proto.rs @@ -5,4 +5,5 @@ pub type foo = - unsafe extern "C" fn(bar: ::std::os::raw::c_int) -> ::std::os::raw::c_int; + ::std::option::Option ::std::os::raw::c_int>; diff --git a/tests/expectations/func_ptr.rs b/tests/expectations/func_ptr.rs index 01e413a6b4..c62e532d7e 100644 --- a/tests/expectations/func_ptr.rs +++ b/tests/expectations/func_ptr.rs @@ -5,10 +5,8 @@ extern "C" { + #[link_name = "foo"] pub static mut foo: - ::std::option::Option ::std::os::raw::c_int>; + *mut ::std::option::Option ::std::os::raw::c_int>; } diff --git a/tests/expectations/func_ptr_in_struct.rs b/tests/expectations/func_ptr_in_struct.rs index 3d7b5f68cf..0d4ccdbf73 100644 --- a/tests/expectations/func_ptr_in_struct.rs +++ b/tests/expectations/func_ptr_in_struct.rs @@ -4,23 +4,18 @@ #![allow(non_snake_case)] -#[repr(i32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_baz { _BindgenOpaqueEnum = 0, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum baz { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_Foo { - pub bar: ::std::option::Option Enum_baz>, -} -impl ::std::clone::Clone for Struct_Foo { - fn clone(&self) -> Self { *self } +pub struct Foo { + pub bar: *mut ::std::option::Option baz>, } #[test] -fn bindgen_test_layout_Struct_Foo() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 8usize); +fn bindgen_test_layout_Foo() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for Foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/func_with_func_ptr_arg.rs b/tests/expectations/func_with_func_ptr_arg.rs index 4ac2528674..b6e345f6d4 100644 --- a/tests/expectations/func_with_func_ptr_arg.rs +++ b/tests/expectations/func_with_func_ptr_arg.rs @@ -5,5 +5,5 @@ extern "C" { - pub fn foo(bar: ::std::option::Option); + pub fn foo(bar: *mut ::std::option::Option); } diff --git a/tests/expectations/in_class_typedef.rs b/tests/expectations/in_class_typedef.rs new file mode 100644 index 0000000000..4e95ca8c6a --- /dev/null +++ b/tests/expectations/in_class_typedef.rs @@ -0,0 +1,21 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData, +} +pub type Foo_elem_type = T; +pub type Foo_ptr_type = *mut T; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo_Bar { + pub x: ::std::os::raw::c_int, + pub y: ::std::os::raw::c_int, + pub _phantom_0: ::std::marker::PhantomData, +} diff --git a/tests/expectations/inherit_named.rs b/tests/expectations/inherit_named.rs new file mode 100644 index 0000000000..8081c649b7 --- /dev/null +++ b/tests/expectations/inherit_named.rs @@ -0,0 +1,17 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Wohoo { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Weeee { + pub _base: T, +} diff --git a/tests/expectations/inherit_typedef.rs b/tests/expectations/inherit_typedef.rs new file mode 100644 index 0000000000..ca9041e202 --- /dev/null +++ b/tests/expectations/inherit_typedef.rs @@ -0,0 +1,33 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Foo { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_Foo() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +impl Clone for Foo { + fn clone(&self) -> Self { *self } +} +pub type TypedefedFoo = Foo; +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Bar { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_Bar() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +impl Clone for Bar { + fn clone(&self) -> Self { *self } +} diff --git a/tests/expectations/inner_const.rs b/tests/expectations/inner_const.rs new file mode 100644 index 0000000000..666b8ce2ec --- /dev/null +++ b/tests/expectations/inner_const.rs @@ -0,0 +1,27 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Foo { + pub bar: ::std::os::raw::c_int, +} +extern "C" { + #[link_name = "_ZN3Foo3BOOE"] + pub static mut Foo_BOO: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "_ZN3Foo8whateverE"] + pub static mut Foo_whatever: Foo; +} +#[test] +fn bindgen_test_layout_Foo() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for Foo { + fn clone(&self) -> Self { *self } +} diff --git a/tests/expectations/inner_template_self.rs b/tests/expectations/inner_template_self.rs index 60af23eeab..b965b92d7c 100644 --- a/tests/expectations/inner_template_self.rs +++ b/tests/expectations/inner_template_self.rs @@ -6,20 +6,20 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_LinkedList { - pub next: *mut Struct_LinkedList, - pub prev: *mut Struct_LinkedList, +pub struct LinkedList { + pub next: *mut LinkedList, + pub prev: *mut LinkedList, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_InstantiateIt { - pub m_list: Struct_LinkedList<::std::os::raw::c_int>, -} -impl ::std::clone::Clone for Struct_InstantiateIt { - fn clone(&self) -> Self { *self } +pub struct InstantiateIt { + pub m_list: LinkedList<::std::os::raw::c_int>, } #[test] -fn bindgen_test_layout_Struct_InstantiateIt() { - assert_eq!(::std::mem::size_of::() , 16usize); - assert_eq!(::std::mem::align_of::() , 8usize); +fn bindgen_test_layout_InstantiateIt() { + assert_eq!(::std::mem::size_of::() , 16usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for InstantiateIt { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/jsval_layout_opaque.rs b/tests/expectations/jsval_layout_opaque.rs index fa9b89b91f..69fe54dc0e 100644 --- a/tests/expectations/jsval_layout_opaque.rs +++ b/tests/expectations/jsval_layout_opaque.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,9 +23,10 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } pub const JSVAL_TAG_SHIFT: ::std::os::raw::c_uint = 47; #[repr(u8)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum JSValueType { JSVAL_TYPE_DOUBLE = 0, JSVAL_TYPE_INT32 = 1, @@ -40,7 +41,7 @@ pub enum JSValueType { JSVAL_TYPE_MISSING = 33, } #[repr(u32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum JSValueTag { JSVAL_TAG_MAX_DOUBLE = 131056, JSVAL_TAG_INT32 = 131057, @@ -53,7 +54,7 @@ pub enum JSValueTag { JSVAL_TAG_OBJECT = 131064, } #[repr(u64)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum JSValueShiftedTag { JSVAL_SHIFTED_TAG_MAX_DOUBLE = 18444492278190833663, JSVAL_SHIFTED_TAG_INT32 = 18444633011384221696, @@ -66,7 +67,7 @@ pub enum JSValueShiftedTag { JSVAL_SHIFTED_TAG_OBJECT = 18445618173802708992, } #[repr(u32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum JSWhyMagic { JS_ELEMENTS_HOLE = 0, JS_NO_ITER_VALUE = 1, @@ -92,155 +93,107 @@ pub enum JSWhyMagic { #[derive(Debug, Copy)] pub struct jsval_layout { pub asBits: __BindgenUnionField, - pub debugView: __BindgenUnionField, - pub s: __BindgenUnionField, + pub debugView: __BindgenUnionField, + pub s: __BindgenUnionField, pub asDouble: __BindgenUnionField, pub asPtr: __BindgenUnionField<*mut ::std::os::raw::c_void>, pub asWord: __BindgenUnionField, pub asUIntPtr: __BindgenUnionField, - pub _bindgen_data_: u64, -} -impl jsval_layout { - pub unsafe fn asBits(&mut self) -> *mut u64 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn debugView(&mut self) - -> *mut jsval_layout_jsval_layout_opaque_hpp_unnamed_1 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn s(&mut self) - -> *mut jsval_layout_jsval_layout_opaque_hpp_unnamed_2 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn asDouble(&mut self) -> *mut f64 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn asPtr(&mut self) -> *mut *mut ::std::os::raw::c_void { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn asWord(&mut self) -> *mut usize { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn asUIntPtr(&mut self) -> *mut usize { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } -} -impl ::std::clone::Clone for jsval_layout { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_jsval_layout() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 8usize); + pub bindgen_union_field: u64, } #[repr(C)] #[derive(Debug, Copy)] -pub struct jsval_layout_jsval_layout_opaque_hpp_unnamed_1 { +pub struct jsval_layout__bindgen_ty_bindgen_id_81 { pub _bitfield_1: u64, } -impl jsval_layout_jsval_layout_opaque_hpp_unnamed_1 { +#[test] +fn bindgen_test_layout_jsval_layout__bindgen_ty_bindgen_id_81() { + assert_eq!(::std::mem::size_of::() + , 8usize); + assert_eq!(::std::mem::align_of::() + , 8usize); +} +impl Clone for jsval_layout__bindgen_ty_bindgen_id_81 { + fn clone(&self) -> Self { *self } +} +impl jsval_layout__bindgen_ty_bindgen_id_81 { #[inline] pub fn payload47(&self) -> u64 { - (self._bitfield_1 & (140737488355327usize as u64)) >> 0usize + unsafe { + ::std::mem::transmute(((self._bitfield_1 & + (140737488355327usize as u64)) >> + 0u32) as u64) + } } #[inline] - pub fn set_payload47(&mut self, val: u32) { + pub fn set_payload47(&mut self, val: u64) { self._bitfield_1 &= !(140737488355327usize as u64); self._bitfield_1 |= - ((val as u64) << 0usize) & (140737488355327usize as u64); + ((val as u64 as u64) << 0u32) & (140737488355327usize as u64); } #[inline] - pub fn tag(&self) -> u64 { - (self._bitfield_1 & (18446603336221196288usize as u64)) >> 47usize + pub fn tag(&self) -> JSValueTag { + unsafe { + ::std::mem::transmute(((self._bitfield_1 & + (18446603336221196288usize as u64)) >> + 47u32) as u32) + } } #[inline] - pub fn set_tag(&mut self, val: u32) { + pub fn set_tag(&mut self, val: JSValueTag) { self._bitfield_1 &= !(18446603336221196288usize as u64); self._bitfield_1 |= - ((val as u64) << 47usize) & (18446603336221196288usize as u64); - } - #[inline] - pub fn new_bitfield_1(payload47: u32, tag: u32) -> u64 { - 0 | ((payload47 as u64) << 0u32) | ((tag as u64) << 47u32) + ((val as u32 as u64) << 47u32) & + (18446603336221196288usize as u64); } } -impl ::std::clone::Clone for jsval_layout_jsval_layout_opaque_hpp_unnamed_1 { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_jsval_layout_jsval_layout_opaque_hpp_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 8usize); - assert_eq!(::std::mem::align_of::() - , 8usize); -} #[repr(C)] #[derive(Debug, Copy)] -pub struct jsval_layout_jsval_layout_opaque_hpp_unnamed_2 { - pub payload: jsval_layout_jsval_layout_opaque_hpp_unnamed_2_jsval_layout_opaque_hpp_unnamed_3, +pub struct jsval_layout__bindgen_ty_bindgen_id_85 { + pub payload: jsval_layout__bindgen_ty_bindgen_id_85__bindgen_ty_bindgen_id_86, } #[repr(C)] #[derive(Debug, Copy)] -pub struct jsval_layout_jsval_layout_opaque_hpp_unnamed_2_jsval_layout_opaque_hpp_unnamed_3 { +pub struct jsval_layout__bindgen_ty_bindgen_id_85__bindgen_ty_bindgen_id_86 { pub i32: __BindgenUnionField, pub u32: __BindgenUnionField, pub why: __BindgenUnionField, - pub _bindgen_data_: u32, -} -impl jsval_layout_jsval_layout_opaque_hpp_unnamed_2_jsval_layout_opaque_hpp_unnamed_3 - { - pub unsafe fn i32(&mut self) -> *mut i32 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn u32(&mut self) -> *mut u32 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn why(&mut self) -> *mut JSWhyMagic { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } -} -impl ::std::clone::Clone for - jsval_layout_jsval_layout_opaque_hpp_unnamed_2_jsval_layout_opaque_hpp_unnamed_3 - { - fn clone(&self) -> Self { *self } + pub bindgen_union_field: u32, } #[test] -fn bindgen_test_layout_jsval_layout_jsval_layout_opaque_hpp_unnamed_2_jsval_layout_opaque_hpp_unnamed_3() { - assert_eq!(::std::mem::size_of::() +fn bindgen_test_layout_jsval_layout__bindgen_ty_bindgen_id_85__bindgen_ty_bindgen_id_86() { + assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for jsval_layout_jsval_layout_opaque_hpp_unnamed_2 { +impl Clone for + jsval_layout__bindgen_ty_bindgen_id_85__bindgen_ty_bindgen_id_86 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_jsval_layout_jsval_layout_opaque_hpp_unnamed_2() { - assert_eq!(::std::mem::size_of::() +fn bindgen_test_layout_jsval_layout__bindgen_ty_bindgen_id_85() { + assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() + assert_eq!(::std::mem::align_of::() , 4usize); } +impl Clone for jsval_layout__bindgen_ty_bindgen_id_85 { + fn clone(&self) -> Self { *self } +} +impl Clone for jsval_layout { + fn clone(&self) -> Self { *self } +} #[repr(C)] #[derive(Debug, Copy)] pub struct Value { pub data: jsval_layout, } -impl ::std::clone::Clone for Value { - fn clone(&self) -> Self { *self } -} #[test] fn bindgen_test_layout_Value() { assert_eq!(::std::mem::size_of::() , 8usize); assert_eq!(::std::mem::align_of::() , 8usize); } +impl Clone for Value { + fn clone(&self) -> Self { *self } +} diff --git a/tests/expectations/keywords.rs b/tests/expectations/keywords.rs index 12e9b5c260..5b75389e00 100644 --- a/tests/expectations/keywords.rs +++ b/tests/expectations/keywords.rs @@ -5,90 +5,198 @@ extern "C" { + #[link_name = "u8"] pub static mut u8: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "u16"] pub static mut u16: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "u32"] pub static mut u32: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "u64"] pub static mut u64: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "i8"] pub static mut i8: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "i16"] pub static mut i16: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "i32"] pub static mut i32: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "i64"] pub static mut i64: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "f32"] pub static mut f32: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "f64"] pub static mut f64: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "usize"] pub static mut usize: ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "isize"] pub static mut isize: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "as"] pub static mut as_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "box"] pub static mut box_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "crate"] pub static mut crate_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "false"] pub static mut false_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "fn"] pub static mut fn_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "impl"] pub static mut impl_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "in"] pub static mut in_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "let"] pub static mut let_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "loop"] pub static mut loop_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "match"] pub static mut match_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "mod"] pub static mut mod_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "move"] pub static mut move_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "mut"] pub static mut mut_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "pub"] pub static mut pub_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "ref"] pub static mut ref_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "self"] pub static mut self_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "Self"] pub static mut Self_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "super"] pub static mut super_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "trait"] pub static mut trait_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "true"] pub static mut true_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "type"] pub static mut type_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "unsafe"] pub static mut unsafe_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "use"] pub static mut use_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "where"] pub static mut where_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "abstract"] pub static mut abstract_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "alignof"] pub static mut alignof_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "become"] pub static mut become_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "final"] pub static mut final_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "macro"] pub static mut macro_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "offsetof"] pub static mut offsetof_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "override"] pub static mut override_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "priv"] pub static mut priv_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "proc"] pub static mut proc_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "pure"] pub static mut pure_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "unsized"] pub static mut unsized_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "virtual"] pub static mut virtual_: ::std::os::raw::c_int; +} +extern "C" { #[link_name = "yield"] pub static mut yield_: ::std::os::raw::c_int; } diff --git a/tests/expectations/moar_bitfields.rs b/tests/expectations/moar_bitfields.rs new file mode 100644 index 0000000000..7c034120f0 --- /dev/null +++ b/tests/expectations/moar_bitfields.rs @@ -0,0 +1,48 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(u32)] +pub enum WhenToScroll { + SCROLL_ALWAYS = 0, + SCROLL_IF_NOT_VISIBLE = 1, + SCROLL_IF_NOT_FULLY_VISIBLE = 2, +} +#[repr(C)] +pub struct ScrollAxis { + pub mWhereToScroll: ::std::os::raw::c_short, + pub _bitfield_1: u16, +} +#[test] +fn bindgen_test_layout_ScrollAxis() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl ScrollAxis { + #[inline] + pub fn mWhenToScroll(&self) -> WhenToScroll { + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (255usize as u16)) >> + 0u32) as u32) + } + } + #[inline] + pub fn set_mWhenToScroll(&mut self, val: WhenToScroll) { + self._bitfield_1 &= !(255usize as u16); + self._bitfield_1 |= ((val as u32 as u16) << 0u32) & (255usize as u16); + } + #[inline] + pub fn mOnlyIfPerceivedScrollableDirection(&self) -> bool { + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (256usize as u16)) >> + 8u32) as u8) + } + } + #[inline] + pub fn set_mOnlyIfPerceivedScrollableDirection(&mut self, val: bool) { + self._bitfield_1 &= !(256usize as u16); + self._bitfield_1 |= ((val as u8 as u16) << 8u32) & (256usize as u16); + } +} diff --git a/tests/expectations/mutable.rs b/tests/expectations/mutable.rs index cf2c5937c7..0d0d6ea341 100644 --- a/tests/expectations/mutable.rs +++ b/tests/expectations/mutable.rs @@ -6,37 +6,37 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_C { +pub struct C { pub m_member: ::std::os::raw::c_int, pub m_other: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_C { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_C() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_C() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for C { + fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug)] -pub struct Struct_NonCopiable { - pub m_member: ::std::cell::Cell<::std::os::raw::c_int>, +pub struct NonCopiable { + pub m_member: ::std::os::raw::c_int, } #[test] -fn bindgen_test_layout_Struct_NonCopiable() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_NonCopiable() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } #[repr(C)] #[derive(Debug)] -pub struct Struct_NonCopiableWithNonCopiableMutableMember { - pub m_member: ::std::cell::UnsafeCell, +pub struct NonCopiableWithNonCopiableMutableMember { + pub m_member: NonCopiable, } #[test] -fn bindgen_test_layout_Struct_NonCopiableWithNonCopiableMutableMember() { - assert_eq!(::std::mem::size_of::() +fn bindgen_test_layout_NonCopiableWithNonCopiableMutableMember() { + assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() + assert_eq!(::std::mem::align_of::() , 4usize); } diff --git a/tests/expectations/namespace.rs b/tests/expectations/namespace.rs index 36113536f4..0bd6e8e07b 100644 --- a/tests/expectations/namespace.rs +++ b/tests/expectations/namespace.rs @@ -4,17 +4,8 @@ #![allow(non_snake_case)] -pub use root::*; pub mod root { - #[repr(C)] - #[derive(Debug)] - pub struct Struct_C { - pub _base: __anonymous1::Struct_A, - pub m_c: T, - pub m_c_ptr: *mut T, - pub m_c_arr: [T; 10usize], - pub _phantom0: ::std::marker::PhantomData, - } + use root; extern "C" { #[link_name = "_Z9top_levelv"] pub fn top_level(); @@ -27,44 +18,68 @@ pub mod root { pub fn in_whatever(); } } - pub mod __anonymous1 { + pub mod _bindgen_mod_bindgen_id_12 { use root; + pub mod empty { + use root; + } + extern "C" { + #[link_name = "_ZN12_GLOBAL__N_13fooEv"] + pub fn foo(); + } #[repr(C)] #[derive(Debug, Copy)] - pub struct Struct_A { + pub struct A { pub b: root::whatever::whatever_int_t, } - impl ::std::clone::Clone for Struct_A { - fn clone(&self) -> Self { *self } - } #[test] - fn bindgen_test_layout_Struct_A() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); - } - extern "C" { - #[link_name = "_ZN12_GLOBAL__N_13fooEv"] - pub fn foo(); + fn bindgen_test_layout_A() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } - pub mod empty { - use root; + impl Clone for A { + fn clone(&self) -> Self { *self } } } + #[repr(C)] + #[derive(Debug)] + pub struct C { + pub _base: root::_bindgen_mod_bindgen_id_12::A, + pub m_c: T, + pub m_c_ptr: *mut T, + pub m_c_arr: [T; 10usize], + } pub mod w { use root; pub type whatever_int_t = ::std::os::raw::c_uint; #[repr(C)] #[derive(Debug)] - pub struct Struct_D { - pub m_c: root::Struct_C, + pub struct D { + pub m_c: root::C, } extern "C" { #[link_name = "_ZN1w3hehEv"] pub fn heh() -> root::w::whatever_int_t; + } + extern "C" { #[link_name = "_ZN1w3fooEv"] - pub fn foo() -> root::Struct_C<::std::os::raw::c_int>; + pub fn foo() -> root::C<::std::os::raw::c_int>; + } + extern "C" { #[link_name = "_ZN1w4barrEv"] - pub fn barr() -> root::Struct_C; + pub fn barr() -> root::C; } } } +extern "C" { + #[link_name = "_Z9top_levelv"] + pub fn top_level(); +} +#[repr(C)] +#[derive(Debug)] +pub struct C { + pub _base: root::_bindgen_mod_bindgen_id_12::A, + pub m_c: T, + pub m_c_ptr: *mut T, + pub m_c_arr: [T; 10usize], +} diff --git a/tests/expectations/nested.rs b/tests/expectations/nested.rs index 2f7fae9aae..fdd435aaba 100644 --- a/tests/expectations/nested.rs +++ b/tests/expectations/nested.rs @@ -6,47 +6,54 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_Calc { +pub struct Calc { pub w: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_Calc { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_Calc() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_Calc() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for Calc { + fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_Test; +pub struct Test { + pub _address: u8, +} #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_Test_Size { - pub mWidth: Struct_Test_Size_Dimension, - pub mHeight: Struct_Test_Size_Dimension, +pub struct Test_Size { + pub mWidth: Test_Size_Dimension, + pub mHeight: Test_Size_Dimension, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_Test_Size_Dimension { - pub _base: Struct_Calc, +pub struct Test_Size_Dimension { + pub _base: Calc, +} +#[test] +fn bindgen_test_layout_Test_Size_Dimension() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Struct_Test_Size_Dimension { +impl Clone for Test_Size_Dimension { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_Test_Size_Dimension() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_Test_Size() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Struct_Test_Size { +impl Clone for Test_Size { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_Test_Size() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_Test() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); } -impl ::std::clone::Clone for Struct_Test { +impl Clone for Test { fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/nested_vtable.rs b/tests/expectations/nested_vtable.rs new file mode 100644 index 0000000000..0c4f7dbe7c --- /dev/null +++ b/tests/expectations/nested_vtable.rs @@ -0,0 +1,48 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +pub struct bindgen_vtable__bindgen_id_1 { +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct nsISupports { + pub vtable_: *const bindgen_vtable__bindgen_id_1, +} +#[test] +fn bindgen_test_layout_nsISupports() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for nsISupports { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct nsIRunnable { + pub _base: nsISupports, +} +#[test] +fn bindgen_test_layout_nsIRunnable() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for nsIRunnable { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Runnable { + pub _base: nsIRunnable, +} +#[test] +fn bindgen_test_layout_Runnable() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for Runnable { + fn clone(&self) -> Self { *self } +} diff --git a/tests/expectations/no_copy.rs b/tests/expectations/no_copy.rs index 601b65c8ad..53ab967700 100644 --- a/tests/expectations/no_copy.rs +++ b/tests/expectations/no_copy.rs @@ -7,7 +7,7 @@ /**
*/ #[repr(C)] #[derive(Debug)] -pub struct Struct_CopiableButWait { +pub struct CopiableButWait { pub whatever: ::std::os::raw::c_int, - pub _phantom0: ::std::marker::PhantomData, + pub _phantom_0: ::std::marker::PhantomData, } diff --git a/tests/expectations/nsStyleAutoArray.rs b/tests/expectations/nsStyleAutoArray.rs index 8acfa15094..c150ec4609 100644 --- a/tests/expectations/nsStyleAutoArray.rs +++ b/tests/expectations/nsStyleAutoArray.rs @@ -6,17 +6,17 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_nsTArray { +pub struct nsTArray { pub mBuff: *mut T, } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_nsStyleAutoArray { +pub struct nsStyleAutoArray { pub mFirstElement: T, - pub mOtherElements: Struct_nsTArray, + pub mOtherElements: nsTArray, } #[repr(i32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum nsStyleAutoArray_WithSingleInitialElement { WITH_SINGLE_INITIAL_ELEMENT = 0, } diff --git a/tests/expectations/only_bitfields.rs b/tests/expectations/only_bitfields.rs index d46a1f8311..68968826b1 100644 --- a/tests/expectations/only_bitfields.rs +++ b/tests/expectations/only_bitfields.rs @@ -6,34 +6,40 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_C { +pub struct C { pub _bitfield_1: u8, } -impl Struct_C { +#[test] +fn bindgen_test_layout_C() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +impl Clone for C { + fn clone(&self) -> Self { *self } +} +impl C { #[inline] - pub fn a(&self) -> u8 { (self._bitfield_1 & (1usize as u8)) >> 0usize } + pub fn a(&self) -> bool { + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (1usize as u8)) >> + 0u32) as u8) + } + } #[inline] pub fn set_a(&mut self, val: bool) { self._bitfield_1 &= !(1usize as u8); - self._bitfield_1 |= ((val as u8) << 0usize) & (1usize as u8); + self._bitfield_1 |= ((val as u8 as u8) << 0u32) & (1usize as u8); } #[inline] - pub fn b(&self) -> u8 { (self._bitfield_1 & (254usize as u8)) >> 1usize } - #[inline] - pub fn set_b(&mut self, val: u8) { - self._bitfield_1 &= !(254usize as u8); - self._bitfield_1 |= ((val as u8) << 1usize) & (254usize as u8); + pub fn b(&self) -> bool { + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (254usize as u8)) >> + 1u32) as u8) + } } #[inline] - pub fn new_bitfield_1(a: bool, b: u8) -> u8 { - 0 | ((a as u8) << 0u32) | ((b as u8) << 1u32) + pub fn set_b(&mut self, val: bool) { + self._bitfield_1 &= !(254usize as u8); + self._bitfield_1 |= ((val as u8 as u8) << 1u32) & (254usize as u8); } } -impl ::std::clone::Clone for Struct_C { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Struct_C() { - assert_eq!(::std::mem::size_of::() , 1usize); - assert_eq!(::std::mem::align_of::() , 1usize); -} diff --git a/tests/expectations/opaque_in_struct.rs b/tests/expectations/opaque_in_struct.rs index a5e3dff67b..d537f5c74b 100644 --- a/tests/expectations/opaque_in_struct.rs +++ b/tests/expectations/opaque_in_struct.rs @@ -4,7 +4,9 @@ #![allow(non_snake_case)] +/**
*/ #[repr(C)] +#[derive(Debug, Copy)] pub struct opaque { pub _bindgen_opaque_blob: u32, } @@ -13,12 +15,19 @@ fn bindgen_test_layout_opaque() { assert_eq!(::std::mem::size_of::() , 4usize); assert_eq!(::std::mem::align_of::() , 4usize); } +impl Clone for opaque { + fn clone(&self) -> Self { *self } +} #[repr(C)] -pub struct Struct_container { +#[derive(Debug, Copy)] +pub struct container { pub contained: u32, } #[test] -fn bindgen_test_layout_Struct_container() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_container() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for container { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/opaque_pointer.rs b/tests/expectations/opaque_pointer.rs index eb5f09cd26..067f55bda2 100644 --- a/tests/expectations/opaque_pointer.rs +++ b/tests/expectations/opaque_pointer.rs @@ -4,7 +4,11 @@ #![allow(non_snake_case)] +/** + *
+ */ #[repr(C)] +#[derive(Debug, Copy)] pub struct OtherOpaque { pub _bindgen_opaque_blob: u32, } @@ -13,16 +17,29 @@ fn bindgen_test_layout_OtherOpaque() { assert_eq!(::std::mem::size_of::() , 4usize); assert_eq!(::std::mem::align_of::() , 4usize); } +impl Clone for OtherOpaque { + fn clone(&self) -> Self { *self } +} +/** + *
+ */ #[repr(C)] -pub struct Opaque; +#[derive(Debug, Copy, Clone)] +pub struct Opaque { + pub _phantom_0: ::std::marker::PhantomData, +} #[repr(C)] -pub struct Struct_WithOpaquePtr { - pub whatever: u64, +#[derive(Debug, Copy)] +pub struct WithOpaquePtr { + pub whatever: *mut Opaque<::std::os::raw::c_int>, pub other: u32, pub t: u32, } #[test] -fn bindgen_test_layout_Struct_WithOpaquePtr() { - assert_eq!(::std::mem::size_of::() , 16usize); - assert_eq!(::std::mem::align_of::() , 8usize); +fn bindgen_test_layout_WithOpaquePtr() { + assert_eq!(::std::mem::size_of::() , 16usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for WithOpaquePtr { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/opaque_typedef.rs b/tests/expectations/opaque_typedef.rs index a54ac881e2..c45cbc6f5e 100644 --- a/tests/expectations/opaque_typedef.rs +++ b/tests/expectations/opaque_typedef.rs @@ -6,11 +6,10 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_RandomTemplate { - pub _phantom0: ::std::marker::PhantomData, +pub struct RandomTemplate { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData, } -pub enum Struct_Wat { } -pub enum Struct_Wat3 { } -#[repr(C)] -pub struct ShouldBeOpaque; -pub type ShouldNotBeOpaque = Struct_RandomTemplate<::std::os::raw::c_int>; +/**
*/ +pub type ShouldBeOpaque = [u8; 0usize]; +pub type ShouldNotBeOpaque = RandomTemplate; diff --git a/tests/expectations/overflowed_enum.rs b/tests/expectations/overflowed_enum.rs index 2228e44b32..9e1f8a7f62 100644 --- a/tests/expectations/overflowed_enum.rs +++ b/tests/expectations/overflowed_enum.rs @@ -5,12 +5,12 @@ #[repr(u32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Foo { +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Foo { BAP_ARM = 9698489, BAP_X86 = 11960045, BAP_X86_64 = 3128633167, } #[repr(u16)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_Bar { One = 1, Big = 2, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Bar { One = 1, Big = 2, } diff --git a/tests/expectations/private.rs b/tests/expectations/private.rs index 7263e3ee0d..c4ac37d171 100644 --- a/tests/expectations/private.rs +++ b/tests/expectations/private.rs @@ -6,47 +6,47 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_HasPrivate { +pub struct HasPrivate { pub mNotPrivate: ::std::os::raw::c_int, /**
*/ mIsPrivate: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_HasPrivate { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_HasPrivate() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_HasPrivate() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for HasPrivate { + fn clone(&self) -> Self { *self } } /**
*/ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_VeryPrivate { +pub struct VeryPrivate { mIsPrivate: ::std::os::raw::c_int, mIsAlsoPrivate: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_VeryPrivate { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_VeryPrivate() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_VeryPrivate() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for VeryPrivate { + fn clone(&self) -> Self { *self } } /**
*/ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_ContradictPrivate { - /**
*/ - mNotPrivate: ::std::os::raw::c_int, +pub struct ContradictPrivate { + /**
*/ + pub mNotPrivate: ::std::os::raw::c_int, mIsPrivate: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_ContradictPrivate { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_ContradictPrivate() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_ContradictPrivate() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for ContradictPrivate { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/redeclaration.rs b/tests/expectations/redeclaration.rs new file mode 100644 index 0000000000..0d7e585cad --- /dev/null +++ b/tests/expectations/redeclaration.rs @@ -0,0 +1,9 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +extern "C" { + pub fn foo(); +} diff --git a/tests/expectations/ref_argument_array.rs b/tests/expectations/ref_argument_array.rs index 9660fbf235..5cfac9d81e 100644 --- a/tests/expectations/ref_argument_array.rs +++ b/tests/expectations/ref_argument_array.rs @@ -6,22 +6,18 @@ pub const NSID_LENGTH: ::std::os::raw::c_uint = 10; #[repr(C)] -#[derive(Debug, Copy)] -pub struct Struct_nsID { - pub _vftable: *const _vftable_Struct_nsID, +pub struct bindgen_vtable__bindgen_id_4 { } #[repr(C)] -pub struct _vftable_Struct_nsID { - pub ToProvidedString: unsafe extern "C" fn(this: - *mut ::std::os::raw::c_void, - aDest: - *mut [::std::os::raw::c_char; 10usize]), -} -impl ::std::clone::Clone for Struct_nsID { - fn clone(&self) -> Self { *self } +#[derive(Debug, Copy)] +pub struct nsID { + pub vtable_: *const bindgen_vtable__bindgen_id_4, } #[test] -fn bindgen_test_layout_Struct_nsID() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 8usize); +fn bindgen_test_layout_nsID() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for nsID { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/size_t_template.rs b/tests/expectations/size_t_template.rs index 6f249ae507..78351ecc2e 100644 --- a/tests/expectations/size_t_template.rs +++ b/tests/expectations/size_t_template.rs @@ -5,12 +5,15 @@ #[repr(C)] -#[derive(Debug)] -pub struct Struct_C { +#[derive(Debug, Copy)] +pub struct C { pub arr: [u32; 3usize], } #[test] -fn bindgen_test_layout_Struct_C() { - assert_eq!(::std::mem::size_of::() , 12usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_C() { + assert_eq!(::std::mem::size_of::() , 12usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for C { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/struct_containing_forward_declared_struct.rs b/tests/expectations/struct_containing_forward_declared_struct.rs index 11ca55b8c7..388cc59592 100644 --- a/tests/expectations/struct_containing_forward_declared_struct.rs +++ b/tests/expectations/struct_containing_forward_declared_struct.rs @@ -6,27 +6,27 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_a { - pub val_a: *mut Struct_b, -} -impl ::std::clone::Clone for Struct_a { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Struct_a() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 8usize); +pub struct a { + pub val_a: *mut a_b, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_b { +pub struct a_b { pub val_b: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_b { +#[test] +fn bindgen_test_layout_a_b() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for a_b { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_b() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_a() { + assert_eq!(::std::mem::size_of::
() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for a { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/struct_with_anon_struct.rs b/tests/expectations/struct_with_anon_struct.rs index 52495279a2..e28c4fc097 100644 --- a/tests/expectations/struct_with_anon_struct.rs +++ b/tests/expectations/struct_with_anon_struct.rs @@ -6,30 +6,30 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo { - pub bar: Struct_foo_struct_with_anon_struct_h_unnamed_1, +pub struct foo { + pub bar: foo__bindgen_ty_bindgen_id_2, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo_struct_with_anon_struct_h_unnamed_1 { +pub struct foo__bindgen_ty_bindgen_id_2 { pub a: ::std::os::raw::c_int, pub b: ::std::os::raw::c_int, } -impl ::std::clone::Clone for Struct_foo_struct_with_anon_struct_h_unnamed_1 { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_foo_struct_with_anon_struct_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 8usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_2() { + assert_eq!(::std::mem::size_of::() , + 8usize); + assert_eq!(::std::mem::align_of::() , + 4usize); } -impl ::std::clone::Clone for Struct_foo { +impl Clone for foo__bindgen_ty_bindgen_id_2 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_foo() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/struct_with_anon_struct_array.rs b/tests/expectations/struct_with_anon_struct_array.rs index 19a16cd6cb..48cc71d25f 100644 --- a/tests/expectations/struct_with_anon_struct_array.rs +++ b/tests/expectations/struct_with_anon_struct_array.rs @@ -6,49 +6,47 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo { - pub bar: [Struct_foo_struct_with_anon_struct_array_h_unnamed_1; 2usize], - pub baz: [[[Struct_foo_struct_with_anon_struct_array_h_unnamed_2; 4usize]; 3usize]; 2usize], +pub struct foo { + pub bar: [foo__bindgen_ty_bindgen_id_2; 2usize], + pub baz: [[[foo__bindgen_ty_bindgen_id_6; 4usize]; 3usize]; 2usize], } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo_struct_with_anon_struct_array_h_unnamed_1 { +pub struct foo__bindgen_ty_bindgen_id_2 { pub a: ::std::os::raw::c_int, pub b: ::std::os::raw::c_int, } -impl ::std::clone::Clone for - Struct_foo_struct_with_anon_struct_array_h_unnamed_1 { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_foo_struct_with_anon_struct_array_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 8usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_2() { + assert_eq!(::std::mem::size_of::() , + 8usize); + assert_eq!(::std::mem::align_of::() , + 4usize); +} +impl Clone for foo__bindgen_ty_bindgen_id_2 { + fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo_struct_with_anon_struct_array_h_unnamed_2 { +pub struct foo__bindgen_ty_bindgen_id_6 { pub a: ::std::os::raw::c_int, pub b: ::std::os::raw::c_int, } -impl ::std::clone::Clone for - Struct_foo_struct_with_anon_struct_array_h_unnamed_2 { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_foo_struct_with_anon_struct_array_h_unnamed_2() { - assert_eq!(::std::mem::size_of::() - , 8usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_6() { + assert_eq!(::std::mem::size_of::() , + 8usize); + assert_eq!(::std::mem::align_of::() , + 4usize); } -impl ::std::clone::Clone for Struct_foo { +impl Clone for foo__bindgen_ty_bindgen_id_6 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_foo() { - assert_eq!(::std::mem::size_of::() , 208usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 208usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/struct_with_anon_struct_pointer.rs b/tests/expectations/struct_with_anon_struct_pointer.rs index 84aa0f153c..a4b693a730 100644 --- a/tests/expectations/struct_with_anon_struct_pointer.rs +++ b/tests/expectations/struct_with_anon_struct_pointer.rs @@ -6,31 +6,30 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo { - pub bar: *mut Struct_foo_struct_with_anon_struct_pointer_h_unnamed_1, +pub struct foo { + pub bar: *mut foo__bindgen_ty_bindgen_id_2, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo_struct_with_anon_struct_pointer_h_unnamed_1 { +pub struct foo__bindgen_ty_bindgen_id_2 { pub a: ::std::os::raw::c_int, pub b: ::std::os::raw::c_int, } -impl ::std::clone::Clone for - Struct_foo_struct_with_anon_struct_pointer_h_unnamed_1 { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_foo_struct_with_anon_struct_pointer_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 8usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_2() { + assert_eq!(::std::mem::size_of::() , + 8usize); + assert_eq!(::std::mem::align_of::() , + 4usize); } -impl ::std::clone::Clone for Struct_foo { +impl Clone for foo__bindgen_ty_bindgen_id_2 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_foo() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 8usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/struct_with_anon_union.rs b/tests/expectations/struct_with_anon_union.rs index 04883f789a..889bccf7af 100644 --- a/tests/expectations/struct_with_anon_union.rs +++ b/tests/expectations/struct_with_anon_union.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,43 +23,34 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo { - pub bar: Union_foo_struct_with_anon_union_h_unnamed_1, +pub struct foo { + pub bar: foo__bindgen_ty_bindgen_id_2, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo_struct_with_anon_union_h_unnamed_1 { +pub struct foo__bindgen_ty_bindgen_id_2 { pub a: __BindgenUnionField<::std::os::raw::c_uint>, pub b: __BindgenUnionField<::std::os::raw::c_ushort>, - pub _bindgen_data_: u32, + pub bindgen_union_field: u32, } -impl Union_foo_struct_with_anon_union_h_unnamed_1 { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } +#[test] +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_2() { + assert_eq!(::std::mem::size_of::() , + 4usize); + assert_eq!(::std::mem::align_of::() , + 4usize); } -impl ::std::clone::Clone for Union_foo_struct_with_anon_union_h_unnamed_1 { +impl Clone for foo__bindgen_ty_bindgen_id_2 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Union_foo_struct_with_anon_union_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 4usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Struct_foo { +impl Clone for foo { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Struct_foo() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} diff --git a/tests/expectations/struct_with_anon_unnamed_struct.rs b/tests/expectations/struct_with_anon_unnamed_struct.rs index 6f7afeae41..ca590b1bd6 100644 --- a/tests/expectations/struct_with_anon_unnamed_struct.rs +++ b/tests/expectations/struct_with_anon_unnamed_struct.rs @@ -6,31 +6,30 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo { - pub foo_struct_with_anon_unnamed_struct_h_unnamed_1: Struct_foo_struct_with_anon_unnamed_struct_h_unnamed_1, +pub struct foo { + pub __bindgen_anon_1: foo__bindgen_ty_bindgen_id_2, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo_struct_with_anon_unnamed_struct_h_unnamed_1 { +pub struct foo__bindgen_ty_bindgen_id_2 { pub a: ::std::os::raw::c_uint, pub b: ::std::os::raw::c_uint, } -impl ::std::clone::Clone for - Struct_foo_struct_with_anon_unnamed_struct_h_unnamed_1 { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_foo_struct_with_anon_unnamed_struct_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 8usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_2() { + assert_eq!(::std::mem::size_of::() , + 8usize); + assert_eq!(::std::mem::align_of::() , + 4usize); } -impl ::std::clone::Clone for Struct_foo { +impl Clone for foo__bindgen_ty_bindgen_id_2 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_foo() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/struct_with_anon_unnamed_union.rs b/tests/expectations/struct_with_anon_unnamed_union.rs index 73bd0111f6..013a9184f9 100644 --- a/tests/expectations/struct_with_anon_unnamed_union.rs +++ b/tests/expectations/struct_with_anon_unnamed_union.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,44 +23,34 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo { - pub foo_struct_with_anon_unnamed_union_h_unnamed_1: Union_foo_struct_with_anon_unnamed_union_h_unnamed_1, +pub struct foo { + pub __bindgen_anon_1: foo__bindgen_ty_bindgen_id_2, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo_struct_with_anon_unnamed_union_h_unnamed_1 { +pub struct foo__bindgen_ty_bindgen_id_2 { pub a: __BindgenUnionField<::std::os::raw::c_uint>, pub b: __BindgenUnionField<::std::os::raw::c_ushort>, - pub _bindgen_data_: u32, + pub bindgen_union_field: u32, } -impl Union_foo_struct_with_anon_unnamed_union_h_unnamed_1 { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } +#[test] +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_2() { + assert_eq!(::std::mem::size_of::() , + 4usize); + assert_eq!(::std::mem::align_of::() , + 4usize); } -impl ::std::clone::Clone for - Union_foo_struct_with_anon_unnamed_union_h_unnamed_1 { +impl Clone for foo__bindgen_ty_bindgen_id_2 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Union_foo_struct_with_anon_unnamed_union_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 4usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Struct_foo { +impl Clone for foo { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Struct_foo() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} diff --git a/tests/expectations/struct_with_bitfields.rs b/tests/expectations/struct_with_bitfields.rs index c2bfc54316..3fb83a47ed 100644 --- a/tests/expectations/struct_with_bitfields.rs +++ b/tests/expectations/struct_with_bitfields.rs @@ -6,127 +6,117 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_bitfield { - pub _bitfield_1: ::std::os::raw::c_ushort, +pub struct bitfield { + pub _bitfield_1: u8, pub e: ::std::os::raw::c_int, - pub _bitfield_2: ::std::os::raw::c_uint, - pub _bitfield_3: ::std::os::raw::c_uint, + pub _bitfield_2: u8, + pub _bitfield_3: u32, } -impl Struct_bitfield { +#[test] +fn bindgen_test_layout_bitfield() { + assert_eq!(::std::mem::size_of::() , 16usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for bitfield { + fn clone(&self) -> Self { *self } +} +impl bitfield { #[inline] pub fn a(&self) -> ::std::os::raw::c_ushort { - (self._bitfield_1 & (1usize as ::std::os::raw::c_ushort)) >> 0usize + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (1usize as u8)) >> + 0u32) as u16) + } } #[inline] - pub fn set_a(&mut self, val: bool) { - self._bitfield_1 &= !(1usize as ::std::os::raw::c_ushort); - self._bitfield_1 |= - ((val as ::std::os::raw::c_ushort) << 0usize) & - (1usize as ::std::os::raw::c_ushort); + pub fn set_a(&mut self, val: ::std::os::raw::c_ushort) { + self._bitfield_1 &= !(1usize as u8); + self._bitfield_1 |= ((val as u16 as u8) << 0u32) & (1usize as u8); } #[inline] pub fn b(&self) -> ::std::os::raw::c_ushort { - (self._bitfield_1 & (2usize as ::std::os::raw::c_ushort)) >> 1usize + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (2usize as u8)) >> + 1u32) as u16) + } } #[inline] - pub fn set_b(&mut self, val: bool) { - self._bitfield_1 &= !(2usize as ::std::os::raw::c_ushort); - self._bitfield_1 |= - ((val as ::std::os::raw::c_ushort) << 1usize) & - (2usize as ::std::os::raw::c_ushort); + pub fn set_b(&mut self, val: ::std::os::raw::c_ushort) { + self._bitfield_1 &= !(2usize as u8); + self._bitfield_1 |= ((val as u16 as u8) << 1u32) & (2usize as u8); } #[inline] pub fn c(&self) -> ::std::os::raw::c_ushort { - (self._bitfield_1 & (4usize as ::std::os::raw::c_ushort)) >> 2usize + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (4usize as u8)) >> + 2u32) as u16) + } } #[inline] - pub fn set_c(&mut self, val: bool) { - self._bitfield_1 &= !(4usize as ::std::os::raw::c_ushort); - self._bitfield_1 |= - ((val as ::std::os::raw::c_ushort) << 2usize) & - (4usize as ::std::os::raw::c_ushort); + pub fn set_c(&mut self, val: ::std::os::raw::c_ushort) { + self._bitfield_1 &= !(4usize as u8); + self._bitfield_1 |= ((val as u16 as u8) << 2u32) & (4usize as u8); } #[inline] pub fn at_offset_3(&self) -> ::std::os::raw::c_ushort { - (self._bitfield_1 & (8usize as ::std::os::raw::c_ushort)) >> 3usize + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (8usize as u8)) >> + 3u32) as u16) + } } #[inline] - pub fn set_at_offset_3(&mut self, val: bool) { - self._bitfield_1 &= !(8usize as ::std::os::raw::c_ushort); - self._bitfield_1 |= - ((val as ::std::os::raw::c_ushort) << 3usize) & - (8usize as ::std::os::raw::c_ushort); + pub fn set_at_offset_3(&mut self, val: ::std::os::raw::c_ushort) { + self._bitfield_1 &= !(8usize as u8); + self._bitfield_1 |= ((val as u16 as u8) << 3u32) & (8usize as u8); } #[inline] pub fn at_offset_4(&self) -> ::std::os::raw::c_ushort { - (self._bitfield_1 & (48usize as ::std::os::raw::c_ushort)) >> 4usize + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (48usize as u8)) >> + 4u32) as u16) + } } #[inline] - pub fn set_at_offset_4(&mut self, val: u8) { - self._bitfield_1 &= !(48usize as ::std::os::raw::c_ushort); - self._bitfield_1 |= - ((val as ::std::os::raw::c_ushort) << 4usize) & - (48usize as ::std::os::raw::c_ushort); + pub fn set_at_offset_4(&mut self, val: ::std::os::raw::c_ushort) { + self._bitfield_1 &= !(48usize as u8); + self._bitfield_1 |= ((val as u16 as u8) << 4u32) & (48usize as u8); } #[inline] pub fn d(&self) -> ::std::os::raw::c_ushort { - (self._bitfield_1 & (192usize as ::std::os::raw::c_ushort)) >> 6usize + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (192usize as u8)) >> + 6u32) as u16) + } } #[inline] - pub fn set_d(&mut self, val: u8) { - self._bitfield_1 &= !(192usize as ::std::os::raw::c_ushort); - self._bitfield_1 |= - ((val as ::std::os::raw::c_ushort) << 6usize) & - (192usize as ::std::os::raw::c_ushort); - } - #[inline] - pub fn new_bitfield_1(a: bool, b: bool, c: bool, unnamed_bitfield1: bool, - unnamed_bitfield2: u8, d: u8) - -> ::std::os::raw::c_ushort { - 0 | ((a as ::std::os::raw::c_ushort) << 0u32) | - ((b as ::std::os::raw::c_ushort) << 1u32) | - ((c as ::std::os::raw::c_ushort) << 2u32) | - ((unnamed_bitfield1 as ::std::os::raw::c_ushort) << 3u32) | - ((unnamed_bitfield2 as ::std::os::raw::c_ushort) << 4u32) | - ((d as ::std::os::raw::c_ushort) << 6u32) + pub fn set_d(&mut self, val: ::std::os::raw::c_ushort) { + self._bitfield_1 &= !(192usize as u8); + self._bitfield_1 |= ((val as u16 as u8) << 6u32) & (192usize as u8); } #[inline] pub fn f(&self) -> ::std::os::raw::c_uint { - (self._bitfield_2 & (3usize as ::std::os::raw::c_uint)) >> 0usize - } - #[inline] - pub fn set_f(&mut self, val: u8) { - self._bitfield_2 &= !(3usize as ::std::os::raw::c_uint); - self._bitfield_2 |= - ((val as ::std::os::raw::c_uint) << 0usize) & - (3usize as ::std::os::raw::c_uint); + unsafe { + ::std::mem::transmute(((self._bitfield_2 & (3usize as u8)) >> + 0u32) as u32) + } } #[inline] - pub fn new_bitfield_2(f: u8) -> ::std::os::raw::c_uint { - 0 | ((f as ::std::os::raw::c_uint) << 0u32) + pub fn set_f(&mut self, val: ::std::os::raw::c_uint) { + self._bitfield_2 &= !(3usize as u8); + self._bitfield_2 |= ((val as u32 as u8) << 0u32) & (3usize as u8); } #[inline] pub fn g(&self) -> ::std::os::raw::c_uint { - (self._bitfield_3 & (4294967295usize as ::std::os::raw::c_uint)) >> - 0usize + unsafe { + ::std::mem::transmute(((self._bitfield_3 & + (4294967295usize as u32)) >> 0u32) as + u32) + } } #[inline] - pub fn set_g(&mut self, val: u32) { - self._bitfield_3 &= !(4294967295usize as ::std::os::raw::c_uint); + pub fn set_g(&mut self, val: ::std::os::raw::c_uint) { + self._bitfield_3 &= !(4294967295usize as u32); self._bitfield_3 |= - ((val as ::std::os::raw::c_uint) << 0usize) & - (4294967295usize as ::std::os::raw::c_uint); - } - #[inline] - pub fn new_bitfield_3(g: u32) -> ::std::os::raw::c_uint { - 0 | ((g as ::std::os::raw::c_uint) << 0u32) + ((val as u32 as u32) << 0u32) & (4294967295usize as u32); } } -impl ::std::clone::Clone for Struct_bitfield { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Struct_bitfield() { - assert_eq!(::std::mem::size_of::() , 16usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} diff --git a/tests/expectations/struct_with_derive_debug.rs b/tests/expectations/struct_with_derive_debug.rs index f89d9d722f..52906a8106 100644 --- a/tests/expectations/struct_with_derive_debug.rs +++ b/tests/expectations/struct_with_derive_debug.rs @@ -6,53 +6,45 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_LittleArray { +pub struct LittleArray { pub a: [::std::os::raw::c_int; 32usize], } -impl ::std::clone::Clone for Struct_LittleArray { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_LittleArray() { - assert_eq!(::std::mem::size_of::() , 128usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_LittleArray() { + assert_eq!(::std::mem::size_of::() , 128usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for LittleArray { + fn clone(&self) -> Self { *self } } #[repr(C)] -#[derive(Copy)] -pub struct Struct_BigArray { +pub struct BigArray { pub a: [::std::os::raw::c_int; 33usize], } -impl ::std::clone::Clone for Struct_BigArray { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_BigArray() { - assert_eq!(::std::mem::size_of::() , 132usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_BigArray() { + assert_eq!(::std::mem::size_of::() , 132usize); + assert_eq!(::std::mem::align_of::() , 4usize); } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_WithLittleArray { - pub a: Struct_LittleArray, -} -impl ::std::clone::Clone for Struct_WithLittleArray { - fn clone(&self) -> Self { *self } +pub struct WithLittleArray { + pub a: LittleArray, } #[test] -fn bindgen_test_layout_Struct_WithLittleArray() { - assert_eq!(::std::mem::size_of::() , 128usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} -#[repr(C)] -#[derive(Copy)] -pub struct Struct_WithBigArray { - pub a: Struct_BigArray, +fn bindgen_test_layout_WithLittleArray() { + assert_eq!(::std::mem::size_of::() , 128usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Struct_WithBigArray { +impl Clone for WithLittleArray { fn clone(&self) -> Self { *self } } +#[repr(C)] +pub struct WithBigArray { + pub a: BigArray, +} #[test] -fn bindgen_test_layout_Struct_WithBigArray() { - assert_eq!(::std::mem::size_of::() , 132usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_WithBigArray() { + assert_eq!(::std::mem::size_of::() , 132usize); + assert_eq!(::std::mem::align_of::() , 4usize); } diff --git a/tests/expectations/struct_with_nesting.rs b/tests/expectations/struct_with_nesting.rs index 2de481eadf..ca5ec09e68 100644 --- a/tests/expectations/struct_with_nesting.rs +++ b/tests/expectations/struct_with_nesting.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,89 +23,70 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo { +pub struct foo { pub a: ::std::os::raw::c_uint, - pub foo_struct_with_nesting_h_unnamed_1: Union_foo_struct_with_nesting_h_unnamed_1, + pub __bindgen_anon_1: foo__bindgen_ty_bindgen_id_3, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo_struct_with_nesting_h_unnamed_1 { +pub struct foo__bindgen_ty_bindgen_id_3 { pub b: __BindgenUnionField<::std::os::raw::c_uint>, - pub foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_2: __BindgenUnionField, - pub foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_3: __BindgenUnionField, - pub _bindgen_data_: u32, -} -impl Union_foo_struct_with_nesting_h_unnamed_1 { - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_2(&mut self) - -> - *mut Struct_foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_2 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_3(&mut self) - -> - *mut Struct_foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_3 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } -} -impl ::std::clone::Clone for Union_foo_struct_with_nesting_h_unnamed_1 { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Union_foo_struct_with_nesting_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 4usize); - assert_eq!(::std::mem::align_of::() - , 4usize); + pub __bindgen_anon_1: __BindgenUnionField, + pub __bindgen_anon_2: __BindgenUnionField, + pub bindgen_union_field: u32, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_2 { +pub struct foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_5 { pub c1: ::std::os::raw::c_ushort, pub c2: ::std::os::raw::c_ushort, } -impl ::std::clone::Clone for - Struct_foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_2 { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_2() { - assert_eq!(::std::mem::size_of::() +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_5() { + assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() + assert_eq!(::std::mem::align_of::() , 2usize); } +impl Clone for foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_5 { + fn clone(&self) -> Self { *self } +} #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_3 { +pub struct foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_8 { pub d1: ::std::os::raw::c_uchar, pub d2: ::std::os::raw::c_uchar, pub d3: ::std::os::raw::c_uchar, pub d4: ::std::os::raw::c_uchar, } -impl ::std::clone::Clone for - Struct_foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_3 { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_foo_struct_with_nesting_h_unnamed_1_struct_with_nesting_h_unnamed_3() { - assert_eq!(::std::mem::size_of::() +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_8() { + assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() + assert_eq!(::std::mem::align_of::() , 1usize); } -impl ::std::clone::Clone for Struct_foo { +impl Clone for foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_8 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_foo() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_3() { + assert_eq!(::std::mem::size_of::() , + 4usize); + assert_eq!(::std::mem::align_of::() , + 4usize); +} +impl Clone for foo__bindgen_ty_bindgen_id_3 { + fn clone(&self) -> Self { *self } +} +#[test] +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/struct_with_packing.rs b/tests/expectations/struct_with_packing.rs index 9f99743596..93fc3f11b2 100644 --- a/tests/expectations/struct_with_packing.rs +++ b/tests/expectations/struct_with_packing.rs @@ -6,15 +6,15 @@ #[repr(C, packed)] #[derive(Debug, Copy)] -pub struct Struct_a { +pub struct a { pub b: ::std::os::raw::c_char, pub c: ::std::os::raw::c_short, } -impl ::std::clone::Clone for Struct_a { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_a() { - assert_eq!(::std::mem::size_of::() , 3usize); - assert_eq!(::std::mem::align_of::() , 1usize); +fn bindgen_test_layout_a() { + assert_eq!(::std::mem::size_of::() , 3usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +impl Clone for a { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/struct_with_struct.rs b/tests/expectations/struct_with_struct.rs index 0c6ab12238..27ff4795e3 100644 --- a/tests/expectations/struct_with_struct.rs +++ b/tests/expectations/struct_with_struct.rs @@ -6,30 +6,30 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo { - pub bar: Struct_foo_struct_with_struct_h_unnamed_1, +pub struct foo { + pub bar: foo__bindgen_ty_bindgen_id_2, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo_struct_with_struct_h_unnamed_1 { +pub struct foo__bindgen_ty_bindgen_id_2 { pub x: ::std::os::raw::c_uint, pub y: ::std::os::raw::c_uint, } -impl ::std::clone::Clone for Struct_foo_struct_with_struct_h_unnamed_1 { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_foo_struct_with_struct_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 8usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_2() { + assert_eq!(::std::mem::size_of::() , + 8usize); + assert_eq!(::std::mem::align_of::() , + 4usize); } -impl ::std::clone::Clone for Struct_foo { +impl Clone for foo__bindgen_ty_bindgen_id_2 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_foo() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/template.rs b/tests/expectations/template.rs index 2f3f9a219f..76afc87966 100644 --- a/tests/expectations/template.rs +++ b/tests/expectations/template.rs @@ -6,110 +6,129 @@ #[repr(C)] #[derive(Debug)] -pub struct Struct_Foo { +pub struct Foo { pub m_member: T, pub m_member_ptr: *mut T, pub m_member_arr: [T; 1usize], - pub _phantom0: ::std::marker::PhantomData, + pub _phantom_1: ::std::marker::PhantomData, +} +extern "C" { + #[link_name = "_Z3bar3FooIiiE"] + pub fn bar(foo: Foo<::std::os::raw::c_int, ::std::os::raw::c_int>); } #[repr(C)] #[derive(Debug)] -pub struct Struct_D { - pub m_foo: Struct_Foo<::std::os::raw::c_int, ::std::os::raw::c_int>, - pub _phantom0: ::std::marker::PhantomData, +pub struct D { + pub m_foo: D_MyFoo, + pub _phantom_0: ::std::marker::PhantomData, } +pub type D_MyFoo = Foo<::std::os::raw::c_int, ::std::os::raw::c_int>; #[repr(C)] #[derive(Debug)] -pub struct Struct_D_U { - pub m_nested_foo: Struct_Foo<::std::os::raw::c_int, - ::std::os::raw::c_int>, +pub struct D_U { + pub m_nested_foo: D_MyFoo, pub m_baz: Z, - pub _phantom0: ::std::marker::PhantomData, + pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_Rooted { +pub struct Rooted { pub prev: *mut T, - pub next: *mut Struct_Rooted<*mut ::std::os::raw::c_void>, + pub next: *mut Rooted<*mut ::std::os::raw::c_void>, pub ptr: T, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_RootedContainer { - pub root: Struct_Rooted<*mut ::std::os::raw::c_void>, -} -impl ::std::clone::Clone for Struct_RootedContainer { - fn clone(&self) -> Self { *self } +pub struct RootedContainer { + pub root: Rooted<*mut ::std::os::raw::c_void>, } #[test] -fn bindgen_test_layout_Struct_RootedContainer() { - assert_eq!(::std::mem::size_of::() , 24usize); - assert_eq!(::std::mem::align_of::() , 8usize); +fn bindgen_test_layout_RootedContainer() { + assert_eq!(::std::mem::size_of::() , 24usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for RootedContainer { + fn clone(&self) -> Self { *self } } -pub type WithDtorIntFwd = Struct_WithDtor<::std::os::raw::c_int>; #[repr(C)] #[derive(Debug)] -pub struct Struct_WithDtor { +pub struct WithDtor { pub member: T, } +pub type WithDtorIntFwd = WithDtor<::std::os::raw::c_int>; #[repr(C)] #[derive(Debug)] -pub struct Struct_PODButContainsDtor { +pub struct PODButContainsDtor { pub member: WithDtorIntFwd, } #[test] -fn bindgen_test_layout_Struct_PODButContainsDtor() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_PODButContainsDtor() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } +/**
*/ #[repr(C)] -pub struct Opaque; +#[derive(Debug, Copy, Clone)] +pub struct Opaque { + pub _phantom_0: ::std::marker::PhantomData, +} #[repr(C)] -pub struct Struct_POD { +#[derive(Debug, Copy)] +pub struct POD { pub opaque_member: u32, } #[test] -fn bindgen_test_layout_Struct_POD() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_POD() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Struct_NestedBase { - pub buff: *mut T, - pub _phantom0: ::std::marker::PhantomData, +impl Clone for POD { + fn clone(&self) -> Self { *self } } /** *
*/ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_NestedReplaced { +pub struct NestedReplaced { pub buff: *mut T, } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_NestedContainer { - pub c: T, - pub nested: Struct_NestedReplaced, - pub inc: Struct_Incomplete, +pub struct NestedBase { + pub buff: *mut T, + pub _phantom_1: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_Incomplete { +pub struct Incomplete { pub d: T, } #[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NestedContainer { + pub c: T, + pub nested: NestedReplaced, + pub inc: Incomplete, +} +#[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_Untemplated; -impl ::std::clone::Clone for Struct_Untemplated { +pub struct Untemplated { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_Untemplated() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +impl Clone for Untemplated { fn clone(&self) -> Self { *self } } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_Templated { - pub m_untemplated: Struct_Untemplated, - pub _phantom0: ::std::marker::PhantomData, +pub struct Templated { + pub m_untemplated: Untemplated, + pub _phantom_0: ::std::marker::PhantomData, } /** * If the replacement doesn't happen at the parse level the container would be @@ -119,9 +138,19 @@ pub struct Struct_Templated { */ #[repr(C)] #[derive(Debug)] -pub struct Struct_ReplacedWithoutDestructor { +pub struct ReplacedWithoutDestructor { pub buff: *mut T, } +#[repr(C)] +#[derive(Debug)] +pub struct ShouldNotBeCopiable { + pub m_member: ReplacedWithoutDestructor, +} +#[repr(C)] +#[derive(Debug)] +pub struct ShouldNotBeCopiableAsWell { + pub m_member: ReplacedWithoutDestructorFwd, +} /** * If the replacement doesn't happen at the parse level the container would be * copy and the replacement wouldn't, so this wouldn't compile. @@ -130,25 +159,12 @@ pub struct Struct_ReplacedWithoutDestructor { */ #[repr(C)] #[derive(Debug)] -pub struct Struct_ReplacedWithoutDestructorFwd { +pub struct ReplacedWithoutDestructorFwd { pub buff: *mut T, } #[repr(C)] -#[derive(Debug)] -pub struct Struct_ShouldNotBeCopiable { - pub m_member: Struct_ReplacedWithoutDestructor, -} -#[repr(C)] -#[derive(Debug)] -pub struct Struct_ShouldNotBeCopiableAsWell { - pub m_member: Struct_ReplacedWithoutDestructorFwd, -} -#[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_TemplateWithVar { - pub _phantom0: ::std::marker::PhantomData, -} -extern "C" { - #[link_name = "_Z3bar3FooIiiE"] - pub fn bar(foo: Struct_Foo<::std::os::raw::c_int, ::std::os::raw::c_int>); +pub struct TemplateWithVar { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData, } diff --git a/tests/expectations/typeref.rs b/tests/expectations/typeref.rs new file mode 100644 index 0000000000..35a873c9e3 --- /dev/null +++ b/tests/expectations/typeref.rs @@ -0,0 +1,92 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[derive(Debug)] +#[repr(C)] +pub struct __BindgenUnionField(::std::marker::PhantomData); +impl __BindgenUnionField { + #[inline] + pub fn new() -> Self { __BindgenUnionField(::std::marker::PhantomData) } + #[inline] + pub unsafe fn as_ref(&self) -> &T { ::std::mem::transmute(self) } + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { ::std::mem::transmute(self) } +} +impl ::std::default::Default for __BindgenUnionField { + #[inline] + fn default() -> Self { Self::new() } +} +impl ::std::clone::Clone for __BindgenUnionField { + #[inline] + fn clone(&self) -> Self { Self::new() } +} +impl ::std::marker::Copy for __BindgenUnionField { } +#[repr(C)] +#[derive(Debug, Copy)] +pub struct nsFoo { + pub mBar: StyleShapeSource<::std::os::raw::c_int>, +} +#[test] +fn bindgen_test_layout_nsFoo() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for nsFoo { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct FragmentOrURL { + pub mIsLocalRef: bool, +} +#[test] +fn bindgen_test_layout_FragmentOrURL() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +impl Clone for FragmentOrURL { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Position { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_Position() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +impl Clone for Position { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy)] +pub struct Bar { + pub mFoo: *mut nsFoo, +} +#[test] +fn bindgen_test_layout_Bar() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for Bar { + fn clone(&self) -> Self { *self } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct StyleShapeSource { + pub __bindgen_anon_1: StyleShapeSource__bindgen_ty_bindgen_id_13, + pub _phantom_0: ::std::marker::PhantomData, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct StyleShapeSource__bindgen_ty_bindgen_id_13 { + pub mPosition: __BindgenUnionField<*mut Position>, + pub mFragmentOrURL: __BindgenUnionField<*mut FragmentOrURL>, + pub bindgen_union_field: u64, + pub _phantom_0: ::std::marker::PhantomData, +} diff --git a/tests/expectations/union_dtor.rs b/tests/expectations/union_dtor.rs index c1e260da7d..4d1fa25a38 100644 --- a/tests/expectations/union_dtor.rs +++ b/tests/expectations/union_dtor.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,25 +23,16 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug)] -pub struct Union_UnionWithDtor { +pub struct UnionWithDtor { pub mFoo: __BindgenUnionField<::std::os::raw::c_int>, pub mBar: __BindgenUnionField<*mut ::std::os::raw::c_void>, - pub _bindgen_data_: u64, -} -impl Union_UnionWithDtor { - pub unsafe fn mFoo(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn mBar(&mut self) -> *mut *mut ::std::os::raw::c_void { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } + pub bindgen_union_field: u64, } #[test] -fn bindgen_test_layout_Union_UnionWithDtor() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 8usize); +fn bindgen_test_layout_UnionWithDtor() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); } diff --git a/tests/expectations/union_fields.rs b/tests/expectations/union_fields.rs index 1a957eaaec..684a9e047e 100644 --- a/tests/expectations/union_fields.rs +++ b/tests/expectations/union_fields.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,36 +23,21 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_union_fields_hpp_unnamed_1 { +pub struct _bindgen_ty_bindgen_id_1 { pub mInt: __BindgenUnionField<::std::os::raw::c_int>, pub mFloat: __BindgenUnionField, pub mPointer: __BindgenUnionField<*mut ::std::os::raw::c_void>, - pub _bindgen_data_: u64, + pub bindgen_union_field: u64, } -impl Union_union_fields_hpp_unnamed_1 { - pub unsafe fn mInt(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn mFloat(&mut self) -> *mut f32 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn mPointer(&mut self) -> *mut *mut ::std::os::raw::c_void { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } +#[test] +fn bindgen_test_layout__bindgen_ty_bindgen_id_1() { + assert_eq!(::std::mem::size_of::<_bindgen_ty_bindgen_id_1>() , 8usize); + assert_eq!(::std::mem::align_of::<_bindgen_ty_bindgen_id_1>() , 8usize); } -impl ::std::clone::Clone for Union_union_fields_hpp_unnamed_1 { +impl Clone for _bindgen_ty_bindgen_id_1 { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Union_union_fields_hpp_unnamed_1() { - assert_eq!(::std::mem::size_of::() , - 8usize); - assert_eq!(::std::mem::align_of::() , - 8usize); -} -pub type nsStyleUnion = Union_union_fields_hpp_unnamed_1; +pub type nsStyleUnion = _bindgen_ty_bindgen_id_1; diff --git a/tests/expectations/union_template.rs b/tests/expectations/union_template.rs index eb6705f094..f07087de6a 100644 --- a/tests/expectations/union_template.rs +++ b/tests/expectations/union_template.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,64 +23,36 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_NastyStruct { +pub struct NastyStruct { pub mIsSome: bool, - pub mStorage: Union_NastyStruct_union_template_hpp_unnamed_1, - pub NastyStruct_union_template_hpp_unnamed_2: Union_NastyStruct_union_template_hpp_unnamed_2, + pub mStorage: NastyStruct__bindgen_ty_bindgen_id_5, + pub __bindgen_anon_1: NastyStruct__bindgen_ty_bindgen_id_9, + pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Union_NastyStruct_union_template_hpp_unnamed_1 { +pub struct NastyStruct__bindgen_ty_bindgen_id_5 { pub mFoo: __BindgenUnionField<*mut ::std::os::raw::c_void>, pub mDummy: __BindgenUnionField<::std::os::raw::c_ulong>, - pub _bindgen_data_: u64, - pub _phantom0: ::std::marker::PhantomData, -} -impl Union_NastyStruct_union_template_hpp_unnamed_1 { - pub unsafe fn mFoo(&mut self) -> *mut *mut ::std::os::raw::c_void { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn mDummy(&mut self) -> *mut ::std::os::raw::c_ulong { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } + pub bindgen_union_field: u64, + pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Union_NastyStruct_union_template_hpp_unnamed_2 { +pub struct NastyStruct__bindgen_ty_bindgen_id_9 { pub wat: __BindgenUnionField<::std::os::raw::c_short>, pub wut: __BindgenUnionField<*mut ::std::os::raw::c_int>, - pub _bindgen_data_: u64, - pub _phantom0: ::std::marker::PhantomData, -} -impl Union_NastyStruct_union_template_hpp_unnamed_2 { - pub unsafe fn wat(&mut self) -> *mut ::std::os::raw::c_short { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn wut(&mut self) -> *mut *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } + pub bindgen_union_field: u64, + pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Union_Whatever { +pub struct Whatever { pub mTPtr: __BindgenUnionField<*mut ::std::os::raw::c_void>, pub mInt: __BindgenUnionField<::std::os::raw::c_int>, - pub _bindgen_data_: u64, - pub _phantom0: ::std::marker::PhantomData, -} -impl Union_Whatever { - pub unsafe fn mTPtr(&mut self) -> *mut *mut ::std::os::raw::c_void { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn mInt(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } + pub bindgen_union_field: u64, + pub _phantom_0: ::std::marker::PhantomData, } diff --git a/tests/expectations/union_with_anon_struct.rs b/tests/expectations/union_with_anon_struct.rs index 850f39bc26..f216b0bf72 100644 --- a/tests/expectations/union_with_anon_struct.rs +++ b/tests/expectations/union_with_anon_struct.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,40 +23,34 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo { - pub bar: __BindgenUnionField, - pub _bindgen_data_: [u32; 2usize], -} -impl Union_foo { - pub unsafe fn bar(&mut self) - -> *mut Struct_foo_union_with_anon_struct_h_unnamed_1 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } -} -impl ::std::clone::Clone for Union_foo { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Union_foo() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 4usize); +pub struct foo { + pub bar: __BindgenUnionField, + pub bindgen_union_field: [u32; 2usize], } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo_union_with_anon_struct_h_unnamed_1 { +pub struct foo__bindgen_ty_bindgen_id_2 { pub a: ::std::os::raw::c_uint, pub b: ::std::os::raw::c_uint, } -impl ::std::clone::Clone for Struct_foo_union_with_anon_struct_h_unnamed_1 { +#[test] +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_2() { + assert_eq!(::std::mem::size_of::() , + 8usize); + assert_eq!(::std::mem::align_of::() , + 4usize); +} +impl Clone for foo__bindgen_ty_bindgen_id_2 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_foo_union_with_anon_struct_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 8usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/union_with_anon_struct_bitfield.rs b/tests/expectations/union_with_anon_struct_bitfield.rs index ce59836e98..80be0e55e3 100644 --- a/tests/expectations/union_with_anon_struct_bitfield.rs +++ b/tests/expectations/union_with_anon_struct_bitfield.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,75 +23,62 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo { +pub struct foo { pub a: __BindgenUnionField<::std::os::raw::c_int>, - pub foo_union_with_anon_struct_bitfield_h_unnamed_1: __BindgenUnionField, - pub _bindgen_data_: u32, + pub __bindgen_anon_1: __BindgenUnionField, + pub bindgen_union_field: u32, } -impl Union_foo { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn foo_union_with_anon_struct_bitfield_h_unnamed_1(&mut self) - -> *mut Struct_foo_union_with_anon_struct_bitfield_h_unnamed_1 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } -} -impl ::std::clone::Clone for Union_foo { - fn clone(&self) -> Self { *self } +#[repr(C)] +#[derive(Debug, Copy)] +pub struct foo__bindgen_ty_bindgen_id_3 { + pub _bitfield_1: u32, } #[test] -fn bindgen_test_layout_Union_foo() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_3() { + assert_eq!(::std::mem::size_of::() , + 4usize); + assert_eq!(::std::mem::align_of::() , + 4usize); } -#[repr(C)] -#[derive(Debug, Copy)] -pub struct Struct_foo_union_with_anon_struct_bitfield_h_unnamed_1 { - pub _bitfield_1: ::std::os::raw::c_int, +impl Clone for foo__bindgen_ty_bindgen_id_3 { + fn clone(&self) -> Self { *self } } -impl Struct_foo_union_with_anon_struct_bitfield_h_unnamed_1 { +impl foo__bindgen_ty_bindgen_id_3 { #[inline] pub fn b(&self) -> ::std::os::raw::c_int { - (self._bitfield_1 & (127usize as ::std::os::raw::c_int)) >> 0usize + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (127usize as u32)) >> + 0u32) as u32) + } } #[inline] - pub fn set_b(&mut self, val: u8) { - self._bitfield_1 &= !(127usize as ::std::os::raw::c_int); - self._bitfield_1 |= - ((val as ::std::os::raw::c_int) << 0usize) & - (127usize as ::std::os::raw::c_int); + pub fn set_b(&mut self, val: ::std::os::raw::c_int) { + self._bitfield_1 &= !(127usize as u32); + self._bitfield_1 |= ((val as u32 as u32) << 0u32) & (127usize as u32); } #[inline] pub fn c(&self) -> ::std::os::raw::c_int { - (self._bitfield_1 & (4294967168usize as ::std::os::raw::c_int)) >> - 7usize + unsafe { + ::std::mem::transmute(((self._bitfield_1 & + (4294967168usize as u32)) >> 7u32) as + u32) + } } #[inline] - pub fn set_c(&mut self, val: u32) { - self._bitfield_1 &= !(4294967168usize as ::std::os::raw::c_int); + pub fn set_c(&mut self, val: ::std::os::raw::c_int) { + self._bitfield_1 &= !(4294967168usize as u32); self._bitfield_1 |= - ((val as ::std::os::raw::c_int) << 7usize) & - (4294967168usize as ::std::os::raw::c_int); - } - #[inline] - pub fn new_bitfield_1(b: u8, c: u32) -> ::std::os::raw::c_int { - 0 | ((b as ::std::os::raw::c_int) << 0u32) | - ((c as ::std::os::raw::c_int) << 7u32) + ((val as u32 as u32) << 7u32) & (4294967168usize as u32); } } -impl ::std::clone::Clone for - Struct_foo_union_with_anon_struct_bitfield_h_unnamed_1 { - fn clone(&self) -> Self { *self } -} #[test] -fn bindgen_test_layout_Struct_foo_union_with_anon_struct_bitfield_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 4usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/union_with_anon_union.rs b/tests/expectations/union_with_anon_union.rs index f610342dec..e7f43cbe48 100644 --- a/tests/expectations/union_with_anon_union.rs +++ b/tests/expectations/union_with_anon_union.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,51 +23,35 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo { - pub bar: __BindgenUnionField, - pub _bindgen_data_: u32, -} -impl Union_foo { - pub unsafe fn bar(&mut self) - -> *mut Union_foo_union_with_anon_union_h_unnamed_1 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } -} -impl ::std::clone::Clone for Union_foo { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Union_foo() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); +pub struct foo { + pub bar: __BindgenUnionField, + pub bindgen_union_field: u32, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo_union_with_anon_union_h_unnamed_1 { +pub struct foo__bindgen_ty_bindgen_id_2 { pub a: __BindgenUnionField<::std::os::raw::c_uint>, pub b: __BindgenUnionField<::std::os::raw::c_ushort>, - pub _bindgen_data_: u32, + pub bindgen_union_field: u32, } -impl Union_foo_union_with_anon_union_h_unnamed_1 { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } +#[test] +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_2() { + assert_eq!(::std::mem::size_of::() , + 4usize); + assert_eq!(::std::mem::align_of::() , + 4usize); } -impl ::std::clone::Clone for Union_foo_union_with_anon_union_h_unnamed_1 { +impl Clone for foo__bindgen_ty_bindgen_id_2 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Union_foo_union_with_anon_union_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 4usize); - assert_eq!(::std::mem::align_of::() - , 4usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/union_with_anon_unnamed_struct.rs b/tests/expectations/union_with_anon_unnamed_struct.rs index cdc760c407..80b3e97af3 100644 --- a/tests/expectations/union_with_anon_unnamed_struct.rs +++ b/tests/expectations/union_with_anon_unnamed_struct.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,48 +23,37 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_pixel { +pub struct pixel { pub rgba: __BindgenUnionField<::std::os::raw::c_uint>, - pub pixel_union_with_anon_unnamed_struct_h_unnamed_1: __BindgenUnionField, - pub _bindgen_data_: u32, -} -impl Union_pixel { - pub unsafe fn rgba(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn pixel_union_with_anon_unnamed_struct_h_unnamed_1(&mut self) - -> *mut Struct_pixel_union_with_anon_unnamed_struct_h_unnamed_1 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } -} -impl ::std::clone::Clone for Union_pixel { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Union_pixel() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); + pub __bindgen_anon_1: __BindgenUnionField, + pub bindgen_union_field: u32, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_pixel_union_with_anon_unnamed_struct_h_unnamed_1 { +pub struct pixel__bindgen_ty_bindgen_id_3 { pub r: ::std::os::raw::c_uchar, pub g: ::std::os::raw::c_uchar, pub b: ::std::os::raw::c_uchar, pub a: ::std::os::raw::c_uchar, } -impl ::std::clone::Clone for - Struct_pixel_union_with_anon_unnamed_struct_h_unnamed_1 { +#[test] +fn bindgen_test_layout_pixel__bindgen_ty_bindgen_id_3() { + assert_eq!(::std::mem::size_of::() , + 4usize); + assert_eq!(::std::mem::align_of::() , + 1usize); +} +impl Clone for pixel__bindgen_ty_bindgen_id_3 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_pixel_union_with_anon_unnamed_struct_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 4usize); - assert_eq!(::std::mem::align_of::() - , 1usize); +fn bindgen_test_layout_pixel() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for pixel { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/union_with_anon_unnamed_union.rs b/tests/expectations/union_with_anon_unnamed_union.rs index 50dfc8d093..3ddea69e38 100644 --- a/tests/expectations/union_with_anon_unnamed_union.rs +++ b/tests/expectations/union_with_anon_unnamed_union.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,57 +23,36 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo { +pub struct foo { pub a: __BindgenUnionField<::std::os::raw::c_uint>, - pub foo_union_with_anon_unnamed_union_h_unnamed_1: __BindgenUnionField, - pub _bindgen_data_: u32, -} -impl Union_foo { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn foo_union_with_anon_unnamed_union_h_unnamed_1(&mut self) - -> *mut Union_foo_union_with_anon_unnamed_union_h_unnamed_1 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } -} -impl ::std::clone::Clone for Union_foo { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Union_foo() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); + pub __bindgen_anon_1: __BindgenUnionField, + pub bindgen_union_field: u32, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo_union_with_anon_unnamed_union_h_unnamed_1 { +pub struct foo__bindgen_ty_bindgen_id_3 { pub b: __BindgenUnionField<::std::os::raw::c_ushort>, pub c: __BindgenUnionField<::std::os::raw::c_uchar>, - pub _bindgen_data_: u16, + pub bindgen_union_field: u16, } -impl Union_foo_union_with_anon_unnamed_union_h_unnamed_1 { - pub unsafe fn b(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn c(&mut self) -> *mut ::std::os::raw::c_uchar { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } +#[test] +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_3() { + assert_eq!(::std::mem::size_of::() , + 2usize); + assert_eq!(::std::mem::align_of::() , + 2usize); } -impl ::std::clone::Clone for - Union_foo_union_with_anon_unnamed_union_h_unnamed_1 { +impl Clone for foo__bindgen_ty_bindgen_id_3 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Union_foo_union_with_anon_unnamed_union_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 2usize); - assert_eq!(::std::mem::align_of::() - , 2usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/union_with_big_member.rs b/tests/expectations/union_with_big_member.rs index d1cd63d499..521a5ff4c7 100644 --- a/tests/expectations/union_with_big_member.rs +++ b/tests/expectations/union_with_big_member.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,53 +23,34 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Copy)] -pub struct Union_WithBigArray { +pub struct WithBigArray { pub a: __BindgenUnionField<::std::os::raw::c_int>, pub b: __BindgenUnionField<[::std::os::raw::c_int; 33usize]>, - pub _bindgen_data_: [u32; 33usize], + pub bindgen_union_field: [u32; 33usize], } -impl Union_WithBigArray { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut [::std::os::raw::c_int; 33usize] { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } +#[test] +fn bindgen_test_layout_WithBigArray() { + assert_eq!(::std::mem::size_of::() , 132usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Union_WithBigArray { +impl Clone for WithBigArray { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Union_WithBigArray() { - assert_eq!(::std::mem::size_of::() , 132usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} #[repr(C)] #[derive(Copy)] -pub struct Union_WithBigMember { +pub struct WithBigMember { pub a: __BindgenUnionField<::std::os::raw::c_int>, - pub b: __BindgenUnionField, - pub _bindgen_data_: [u32; 33usize], + pub b: __BindgenUnionField, + pub bindgen_union_field: [u32; 33usize], } -impl Union_WithBigMember { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_int { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b(&mut self) -> *mut Union_WithBigArray { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } +#[test] +fn bindgen_test_layout_WithBigMember() { + assert_eq!(::std::mem::size_of::() , 132usize); + assert_eq!(::std::mem::align_of::() , 4usize); } -impl ::std::clone::Clone for Union_WithBigMember { +impl Clone for WithBigMember { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Union_WithBigMember() { - assert_eq!(::std::mem::size_of::() , 132usize); - assert_eq!(::std::mem::align_of::() , 4usize); -} diff --git a/tests/expectations/union_with_nesting.rs b/tests/expectations/union_with_nesting.rs index 4117786dfe..6b8d318dd3 100644 --- a/tests/expectations/union_with_nesting.rs +++ b/tests/expectations/union_with_nesting.rs @@ -4,7 +4,7 @@ #![allow(non_snake_case)] -#[derive(Copy, Debug)] +#[derive(Debug)] #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); impl __BindgenUnionField { @@ -23,101 +23,69 @@ impl ::std::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { Self::new() } } +impl ::std::marker::Copy for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo { +pub struct foo { pub a: __BindgenUnionField<::std::os::raw::c_uint>, - pub foo_union_with_nesting_h_unnamed_1: __BindgenUnionField, - pub _bindgen_data_: u32, -} -impl Union_foo { - pub unsafe fn a(&mut self) -> *mut ::std::os::raw::c_uint { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn foo_union_with_nesting_h_unnamed_1(&mut self) - -> *mut Struct_foo_union_with_nesting_h_unnamed_1 { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } -} -impl ::std::clone::Clone for Union_foo { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Union_foo() { - assert_eq!(::std::mem::size_of::() , 4usize); - assert_eq!(::std::mem::align_of::() , 4usize); + pub __bindgen_anon_1: __BindgenUnionField, + pub bindgen_union_field: u32, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_foo_union_with_nesting_h_unnamed_1 { - pub foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_2: Union_foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_2, - pub foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_3: Union_foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_3, +pub struct foo__bindgen_ty_bindgen_id_3 { + pub __bindgen_anon_1: foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_4, + pub __bindgen_anon_2: foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_7, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_2 { +pub struct foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_4 { pub b1: __BindgenUnionField<::std::os::raw::c_ushort>, pub b2: __BindgenUnionField<::std::os::raw::c_ushort>, - pub _bindgen_data_: u16, -} -impl Union_foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_2 { - pub unsafe fn b1(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn b2(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } -} -impl ::std::clone::Clone for - Union_foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_2 { - fn clone(&self) -> Self { *self } + pub bindgen_union_field: u16, } #[test] -fn bindgen_test_layout_Union_foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_2() { - assert_eq!(::std::mem::size_of::() +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_4() { + assert_eq!(::std::mem::size_of::() , 2usize); - assert_eq!(::std::mem::align_of::() + assert_eq!(::std::mem::align_of::() , 2usize); } +impl Clone for foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_4 { + fn clone(&self) -> Self { *self } +} #[repr(C)] #[derive(Debug, Copy)] -pub struct Union_foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_3 { +pub struct foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_7 { pub c1: __BindgenUnionField<::std::os::raw::c_ushort>, pub c2: __BindgenUnionField<::std::os::raw::c_ushort>, - pub _bindgen_data_: u16, + pub bindgen_union_field: u16, } -impl Union_foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_3 { - pub unsafe fn c1(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } - pub unsafe fn c2(&mut self) -> *mut ::std::os::raw::c_ushort { - let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_); - ::std::mem::transmute(raw.offset(0)) - } +#[test] +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_7() { + assert_eq!(::std::mem::size_of::() + , 2usize); + assert_eq!(::std::mem::align_of::() + , 2usize); } -impl ::std::clone::Clone for - Union_foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_3 { +impl Clone for foo__bindgen_ty_bindgen_id_3__bindgen_ty_bindgen_id_7 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Union_foo_union_with_nesting_h_unnamed_1_union_with_nesting_h_unnamed_3() { - assert_eq!(::std::mem::size_of::() - , 2usize); - assert_eq!(::std::mem::align_of::() - , 2usize); +fn bindgen_test_layout_foo__bindgen_ty_bindgen_id_3() { + assert_eq!(::std::mem::size_of::() , + 4usize); + assert_eq!(::std::mem::align_of::() , + 2usize); } -impl ::std::clone::Clone for Struct_foo_union_with_nesting_h_unnamed_1 { +impl Clone for foo__bindgen_ty_bindgen_id_3 { fn clone(&self) -> Self { *self } } #[test] -fn bindgen_test_layout_Struct_foo_union_with_nesting_h_unnamed_1() { - assert_eq!(::std::mem::size_of::() - , 4usize); - assert_eq!(::std::mem::align_of::() - , 2usize); +fn bindgen_test_layout_foo() { + assert_eq!(::std::mem::size_of::() , 4usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for foo { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/unknown_attr.rs b/tests/expectations/unknown_attr.rs new file mode 100644 index 0000000000..06da6a3c4e --- /dev/null +++ b/tests/expectations/unknown_attr.rs @@ -0,0 +1,16 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct _bindgen_ty_bindgen_id_1 { + pub __clang_max_align_nonce1: ::std::os::raw::c_longlong, + pub __clang_max_align_nonce2: f64, +} +impl Clone for _bindgen_ty_bindgen_id_1 { + fn clone(&self) -> Self { *self } +} +pub type max_align_t = _bindgen_ty_bindgen_id_1; diff --git a/tests/expectations/using.rs b/tests/expectations/using.rs index adc1e61b8f..dbb6c84f23 100644 --- a/tests/expectations/using.rs +++ b/tests/expectations/using.rs @@ -6,9 +6,9 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Struct_Point { +pub struct Point { pub x: T, pub y: T, } -pub type IntPoint2D = Struct_Point<::std::os::raw::c_int>; -pub type IntVec2D = Struct_Point<::std::os::raw::c_int>; +pub type IntPoint2D = Point<::std::os::raw::c_int>; +pub type IntVec2D = Point<::std::os::raw::c_int>; diff --git a/tests/expectations/variadic_template_args.rs b/tests/expectations/variadic_template_args.rs new file mode 100644 index 0000000000..f0c6810651 --- /dev/null +++ b/tests/expectations/variadic_template_args.rs @@ -0,0 +1,21 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +pub struct RefPtr { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData, +} +#[repr(C)] +pub struct RefPtr_Proxy { + pub _address: u8, + pub _phantom_0: ::std::marker::PhantomData, + pub _phantom_1: ::std::marker::PhantomData, + pub _phantom_2: ::std::marker::PhantomData, +} +pub type RefPtr_Proxy_member_function = + *mut ::std::option::Option type-parameter-1-0>; diff --git a/tests/expectations/virtual_dtor.rs b/tests/expectations/virtual_dtor.rs new file mode 100644 index 0000000000..99e0a535ed --- /dev/null +++ b/tests/expectations/virtual_dtor.rs @@ -0,0 +1,19 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +pub struct bindgen_vtable__bindgen_id_1 { +} +#[repr(C)] +#[derive(Debug)] +pub struct nsSlots { + pub vtable_: *const bindgen_vtable__bindgen_id_1, +} +#[test] +fn bindgen_test_layout_nsSlots() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} diff --git a/tests/expectations/virtual_overloaded.rs b/tests/expectations/virtual_overloaded.rs index a59f9c2705..d395fed01c 100644 --- a/tests/expectations/virtual_overloaded.rs +++ b/tests/expectations/virtual_overloaded.rs @@ -5,22 +5,18 @@ #[repr(C)] -#[derive(Debug, Copy)] -pub struct Struct_C { - pub _vftable: *const _vftable_Struct_C, +pub struct bindgen_vtable__bindgen_id_1 { } #[repr(C)] -pub struct _vftable_Struct_C { - pub do_thing: unsafe extern "C" fn(this: *mut ::std::os::raw::c_void, - arg1: ::std::os::raw::c_char), - pub do_thing1: unsafe extern "C" fn(this: *mut ::std::os::raw::c_void, - arg1: ::std::os::raw::c_int), -} -impl ::std::clone::Clone for Struct_C { - fn clone(&self) -> Self { *self } +#[derive(Debug, Copy)] +pub struct C { + pub vtable_: *const bindgen_vtable__bindgen_id_1, } #[test] -fn bindgen_test_layout_Struct_C() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 8usize); +fn bindgen_test_layout_C() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); +} +impl Clone for C { + fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/vtable_recursive_sig.rs b/tests/expectations/vtable_recursive_sig.rs index 8f972e921f..1044c4e46a 100644 --- a/tests/expectations/vtable_recursive_sig.rs +++ b/tests/expectations/vtable_recursive_sig.rs @@ -6,31 +6,30 @@ #[repr(C)] #[derive(Debug, Copy)] -pub struct Base { - pub _vftable: *const _vftable_Base, +pub struct Derived { + pub _base: Base, } -#[repr(C)] -pub struct _vftable_Base { - pub AsDerived: unsafe extern "C" fn(this: *mut ::std::os::raw::c_void) - -> *mut Derived, +#[test] +fn bindgen_test_layout_Derived() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); } -impl ::std::clone::Clone for Base { +impl Clone for Derived { fn clone(&self) -> Self { *self } } -#[test] -fn bindgen_test_layout_Base() { - assert_eq!(::std::mem::size_of::() , 8usize); - assert_eq!(::std::mem::align_of::() , 8usize); +#[repr(C)] +pub struct bindgen_vtable__bindgen_id_2 { } #[repr(C)] #[derive(Debug, Copy)] -pub struct Derived { - pub _base: Base, +pub struct Base { + pub vtable_: *const bindgen_vtable__bindgen_id_2, } -#[repr(C)] -pub struct _vftable_Derived { - pub _base: _vftable_Base, +#[test] +fn bindgen_test_layout_Base() { + assert_eq!(::std::mem::size_of::() , 8usize); + assert_eq!(::std::mem::align_of::() , 8usize); } -impl ::std::clone::Clone for Derived { +impl Clone for Base { fn clone(&self) -> Self { *self } } diff --git a/tests/expectations/weird_bitfields.rs b/tests/expectations/weird_bitfields.rs index 6166a60fe4..56ee76a59e 100644 --- a/tests/expectations/weird_bitfields.rs +++ b/tests/expectations/weird_bitfields.rs @@ -5,17 +5,17 @@ #[repr(u32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Enum_nsStyleSVGOpacitySource { +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum nsStyleSVGOpacitySource { eStyleSVGOpacitySource_Normal = 0, eStyleSVGOpacitySource_ContextFillOpacity = 1, eStyleSVGOpacitySource_ContextStrokeOpacity = 2, } #[repr(C)] #[derive(Debug, Copy)] -pub struct Struct_Weird { +pub struct Weird { pub mStrokeDasharrayLength: ::std::os::raw::c_uint, - pub _bitfield_1: ::std::os::raw::c_uint, + pub _bitfield_1: u32, pub mClipRule: ::std::os::raw::c_uchar, pub mColorInterpolation: ::std::os::raw::c_uchar, pub mColorInterpolationFilters: ::std::os::raw::c_uchar, @@ -27,100 +27,102 @@ pub struct Struct_Weird { pub mStrokeLinejoin: ::std::os::raw::c_uchar, pub mTextAnchor: ::std::os::raw::c_uchar, pub mTextRendering: ::std::os::raw::c_uchar, - pub _bitfield_2: u32, + pub _bitfield_2: u16, } -impl Struct_Weird { +#[test] +fn bindgen_test_layout_Weird() { + assert_eq!(::std::mem::size_of::() , 24usize); + assert_eq!(::std::mem::align_of::() , 4usize); +} +impl Clone for Weird { + fn clone(&self) -> Self { *self } +} +impl Weird { #[inline] pub fn bitTest(&self) -> ::std::os::raw::c_uint { - (self._bitfield_1 & (65535usize as ::std::os::raw::c_uint)) >> 0usize + unsafe { + ::std::mem::transmute(((self._bitfield_1 & (65535usize as u32)) >> + 0u32) as u32) + } } #[inline] - pub fn set_bitTest(&mut self, val: u16) { - self._bitfield_1 &= !(65535usize as ::std::os::raw::c_uint); + pub fn set_bitTest(&mut self, val: ::std::os::raw::c_uint) { + self._bitfield_1 &= !(65535usize as u32); self._bitfield_1 |= - ((val as ::std::os::raw::c_uint) << 0usize) & - (65535usize as ::std::os::raw::c_uint); + ((val as u32 as u32) << 0u32) & (65535usize as u32); } #[inline] pub fn bitTest2(&self) -> ::std::os::raw::c_uint { - (self._bitfield_1 & (2147418112usize as ::std::os::raw::c_uint)) >> - 16usize + unsafe { + ::std::mem::transmute(((self._bitfield_1 & + (2147418112usize as u32)) >> 16u32) as + u32) + } } #[inline] - pub fn set_bitTest2(&mut self, val: u16) { - self._bitfield_1 &= !(2147418112usize as ::std::os::raw::c_uint); + pub fn set_bitTest2(&mut self, val: ::std::os::raw::c_uint) { + self._bitfield_1 &= !(2147418112usize as u32); self._bitfield_1 |= - ((val as ::std::os::raw::c_uint) << 16usize) & - (2147418112usize as ::std::os::raw::c_uint); - } - #[inline] - pub fn new_bitfield_1(bitTest: u16, bitTest2: u16) - -> ::std::os::raw::c_uint { - 0 | ((bitTest as ::std::os::raw::c_uint) << 0u32) | - ((bitTest2 as ::std::os::raw::c_uint) << 16u32) + ((val as u32 as u32) << 16u32) & (2147418112usize as u32); } #[inline] - pub fn mFillOpacitySource(&self) -> u32 { - (self._bitfield_2 & (7usize as u32)) >> 0usize + pub fn mFillOpacitySource(&self) -> nsStyleSVGOpacitySource { + unsafe { + ::std::mem::transmute(((self._bitfield_2 & (7usize as u16)) >> + 0u32) as u32) + } } #[inline] - pub fn set_mFillOpacitySource(&mut self, val: u8) { - self._bitfield_2 &= !(7usize as u32); - self._bitfield_2 |= ((val as u32) << 0usize) & (7usize as u32); + pub fn set_mFillOpacitySource(&mut self, val: nsStyleSVGOpacitySource) { + self._bitfield_2 &= !(7usize as u16); + self._bitfield_2 |= ((val as u32 as u16) << 0u32) & (7usize as u16); } #[inline] - pub fn mStrokeOpacitySource(&self) -> u32 { - (self._bitfield_2 & (56usize as u32)) >> 3usize + pub fn mStrokeOpacitySource(&self) -> nsStyleSVGOpacitySource { + unsafe { + ::std::mem::transmute(((self._bitfield_2 & (56usize as u16)) >> + 3u32) as u32) + } } #[inline] - pub fn set_mStrokeOpacitySource(&mut self, val: u8) { - self._bitfield_2 &= !(56usize as u32); - self._bitfield_2 |= ((val as u32) << 3usize) & (56usize as u32); + pub fn set_mStrokeOpacitySource(&mut self, val: nsStyleSVGOpacitySource) { + self._bitfield_2 &= !(56usize as u16); + self._bitfield_2 |= ((val as u32 as u16) << 3u32) & (56usize as u16); } #[inline] - pub fn mStrokeDasharrayFromObject(&self) -> u32 { - (self._bitfield_2 & (64usize as u32)) >> 6usize + pub fn mStrokeDasharrayFromObject(&self) -> bool { + unsafe { + ::std::mem::transmute(((self._bitfield_2 & (64usize as u16)) >> + 6u32) as u8) + } } #[inline] pub fn set_mStrokeDasharrayFromObject(&mut self, val: bool) { - self._bitfield_2 &= !(64usize as u32); - self._bitfield_2 |= ((val as u32) << 6usize) & (64usize as u32); + self._bitfield_2 &= !(64usize as u16); + self._bitfield_2 |= ((val as u8 as u16) << 6u32) & (64usize as u16); } #[inline] - pub fn mStrokeDashoffsetFromObject(&self) -> u32 { - (self._bitfield_2 & (128usize as u32)) >> 7usize + pub fn mStrokeDashoffsetFromObject(&self) -> bool { + unsafe { + ::std::mem::transmute(((self._bitfield_2 & (128usize as u16)) >> + 7u32) as u8) + } } #[inline] pub fn set_mStrokeDashoffsetFromObject(&mut self, val: bool) { - self._bitfield_2 &= !(128usize as u32); - self._bitfield_2 |= ((val as u32) << 7usize) & (128usize as u32); + self._bitfield_2 &= !(128usize as u16); + self._bitfield_2 |= ((val as u8 as u16) << 7u32) & (128usize as u16); } #[inline] - pub fn mStrokeWidthFromObject(&self) -> u32 { - (self._bitfield_2 & (256usize as u32)) >> 8usize + pub fn mStrokeWidthFromObject(&self) -> bool { + unsafe { + ::std::mem::transmute(((self._bitfield_2 & (256usize as u16)) >> + 8u32) as u8) + } } #[inline] pub fn set_mStrokeWidthFromObject(&mut self, val: bool) { - self._bitfield_2 &= !(256usize as u32); - self._bitfield_2 |= ((val as u32) << 8usize) & (256usize as u32); + self._bitfield_2 &= !(256usize as u16); + self._bitfield_2 |= ((val as u8 as u16) << 8u32) & (256usize as u16); } - #[inline] - pub fn new_bitfield_2(mFillOpacitySource: u8, mStrokeOpacitySource: u8, - mStrokeDasharrayFromObject: bool, - mStrokeDashoffsetFromObject: bool, - mStrokeWidthFromObject: bool) -> u32 { - 0 | ((mFillOpacitySource as u32) << 0u32) | - ((mStrokeOpacitySource as u32) << 3u32) | - ((mStrokeDasharrayFromObject as u32) << 6u32) | - ((mStrokeDashoffsetFromObject as u32) << 7u32) | - ((mStrokeWidthFromObject as u32) << 8u32) - } -} -impl ::std::clone::Clone for Struct_Weird { - fn clone(&self) -> Self { *self } -} -#[test] -fn bindgen_test_layout_Struct_Weird() { - assert_eq!(::std::mem::size_of::() , 24usize); - assert_eq!(::std::mem::align_of::() , 4usize); } diff --git a/tests/expectations/what_is_going_on.rs b/tests/expectations/what_is_going_on.rs new file mode 100644 index 0000000000..b6a5c86a00 --- /dev/null +++ b/tests/expectations/what_is_going_on.rs @@ -0,0 +1,29 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy)] +pub struct UnknownUnits { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_UnknownUnits() { + assert_eq!(::std::mem::size_of::() , 1usize); + assert_eq!(::std::mem::align_of::() , 1usize); +} +impl Clone for UnknownUnits { + fn clone(&self) -> Self { *self } +} +pub type Float = f32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PointTyped { + pub x: Float, + pub y: Float, + pub _phantom_0: ::std::marker::PhantomData, + pub _phantom_1: ::std::marker::PhantomData, +} +pub type IntPoint = PointTyped; diff --git a/tests/expectations/whitelist_basic.rs b/tests/expectations/whitelist_basic.rs new file mode 100644 index 0000000000..0104f04959 --- /dev/null +++ b/tests/expectations/whitelist_basic.rs @@ -0,0 +1,18 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct WhitelistMe { + pub foo: ::std::os::raw::c_int, + pub bar: WhitelistMe_Inner, + pub _phantom_0: ::std::marker::PhantomData, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct WhitelistMe_Inner { + pub bar: T, +} diff --git a/tests/headers/anon_enum.hpp b/tests/headers/anon_enum.hpp new file mode 100644 index 0000000000..c740520241 --- /dev/null +++ b/tests/headers/anon_enum.hpp @@ -0,0 +1,5 @@ +struct Test { + int foo; + float bar; + enum { T_NONE }; +}; diff --git a/tests/headers/anon_enum_whitelist.h b/tests/headers/anon_enum_whitelist.h new file mode 100644 index 0000000000..15cda6b1e7 --- /dev/null +++ b/tests/headers/anon_enum_whitelist.h @@ -0,0 +1,6 @@ +// bindgen-flags: --whitelist-var NODE_.* + +enum { + NODE_FLAG_FOO, + NODE_FLAG_BAR, +}; diff --git a/tests/headers/anon_union.hpp b/tests/headers/anon_union.hpp new file mode 100644 index 0000000000..126f6a6ee3 --- /dev/null +++ b/tests/headers/anon_union.hpp @@ -0,0 +1,20 @@ +template +struct TErrorResult { + enum UnionState { + HasMessage, + HasException, + }; + int mResult; + struct Message; + struct DOMExceptionInfo; + union { + Message* mMessage; + DOMExceptionInfo* mDOMExceptionInfo; + }; + + bool mMightHaveUnreported; + UnionState mUnionState; +}; + +struct ErrorResult : public TErrorResult { +}; diff --git a/tests/headers/arg_keyword.hpp b/tests/headers/arg_keyword.hpp new file mode 100644 index 0000000000..9f0af85030 --- /dev/null +++ b/tests/headers/arg_keyword.hpp @@ -0,0 +1 @@ +void foo(const char* type); diff --git a/tests/headers/const_ptr.hpp b/tests/headers/const_ptr.hpp new file mode 100644 index 0000000000..66744f8beb --- /dev/null +++ b/tests/headers/const_ptr.hpp @@ -0,0 +1,3 @@ +extern "C" { + void foo(const void* bar); +} diff --git a/tests/headers/const_resolved_ty.h b/tests/headers/const_resolved_ty.h new file mode 100644 index 0000000000..2521e61c04 --- /dev/null +++ b/tests/headers/const_resolved_ty.h @@ -0,0 +1,3 @@ +typedef unsigned char uint8_t; + +void foo(const uint8_t* foo); diff --git a/tests/headers/const_tparam.hpp b/tests/headers/const_tparam.hpp new file mode 100644 index 0000000000..a2db574cab --- /dev/null +++ b/tests/headers/const_tparam.hpp @@ -0,0 +1,4 @@ +template +class C { + const T* const foo; +}; diff --git a/tests/headers/duplicated_constants_in_ns.hpp b/tests/headers/duplicated_constants_in_ns.hpp index 42197a169d..bb34364107 100644 --- a/tests/headers/duplicated_constants_in_ns.hpp +++ b/tests/headers/duplicated_constants_in_ns.hpp @@ -1,4 +1,4 @@ -// bindgen-flags: --no-namespaced-constants +// bindgen-flags: --enable-cxx-namespaces namespace foo { const int FOO = 4; } diff --git a/tests/headers/empty_template_param_name.hpp b/tests/headers/empty_template_param_name.hpp new file mode 100644 index 0000000000..b3360bc95c --- /dev/null +++ b/tests/headers/empty_template_param_name.hpp @@ -0,0 +1,4 @@ +template using __void_t = void; + +template> + struct __iterator_traits { }; diff --git a/tests/headers/enum_alias.hpp b/tests/headers/enum_alias.hpp new file mode 100644 index 0000000000..658f8fde9a --- /dev/null +++ b/tests/headers/enum_alias.hpp @@ -0,0 +1,7 @@ +// bindgen-flags: -- -std=c++11 + +typedef unsigned char uint8_t; + +enum Bar : uint8_t { + VAL +}; diff --git a/tests/headers/in_class_typedef.hpp b/tests/headers/in_class_typedef.hpp new file mode 100644 index 0000000000..dda7472ddb --- /dev/null +++ b/tests/headers/in_class_typedef.hpp @@ -0,0 +1,10 @@ + +template +class Foo { + typedef T elem_type; + typedef T* ptr_type; + + typedef struct Bar { + int x, y; + } Bar; +}; diff --git a/tests/headers/inherit_named.hpp b/tests/headers/inherit_named.hpp new file mode 100644 index 0000000000..9881d1b6a5 --- /dev/null +++ b/tests/headers/inherit_named.hpp @@ -0,0 +1,5 @@ +template +class Wohoo {}; + +template +class Weeee : public T {}; diff --git a/tests/headers/inherit_typedef.hpp b/tests/headers/inherit_typedef.hpp new file mode 100644 index 0000000000..8d699e826c --- /dev/null +++ b/tests/headers/inherit_typedef.hpp @@ -0,0 +1,5 @@ +struct Foo {}; + +typedef Foo TypedefedFoo; + +struct Bar: public TypedefedFoo {}; diff --git a/tests/headers/inner_const.hpp b/tests/headers/inner_const.hpp new file mode 100644 index 0000000000..25c2e603a6 --- /dev/null +++ b/tests/headers/inner_const.hpp @@ -0,0 +1,6 @@ + +class Foo { + static int BOO; + static Foo whatever; + int bar; +}; diff --git a/tests/headers/jsval_layout_opaque.hpp b/tests/headers/jsval_layout_opaque.hpp index d432d8d3c4..85c5be63c4 100644 --- a/tests/headers/jsval_layout_opaque.hpp +++ b/tests/headers/jsval_layout_opaque.hpp @@ -1,7 +1,16 @@ -// bindgen-flags: --match jsval_layout_opaque.hpp --no-type-renaming --no-unstable-rust -- -std=c++11 +// bindgen-flags: --no-unstable-rust -- -std=c++11 + +/** + * These typedefs are hacky, but keep our tests consistent across 64-bit + * platforms, otherwise the id's change and our CI is unhappy. + */ +typedef unsigned char uint8_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef unsigned long long size_t; +typedef unsigned long long uintptr_t; -#include -#include #define JS_PUNBOX64 #define IS_LITTLE_ENDIAN diff --git a/tests/headers/nested_vtable.hpp b/tests/headers/nested_vtable.hpp new file mode 100644 index 0000000000..87d6ce1f22 --- /dev/null +++ b/tests/headers/nested_vtable.hpp @@ -0,0 +1,8 @@ +class nsISupports { +public: + virtual nsISupports* QueryInterface(); +}; + +class nsIRunnable : public nsISupports {}; + +class Runnable : public nsIRunnable {}; diff --git a/tests/headers/opaque_typedef.hpp b/tests/headers/opaque_typedef.hpp index 2d9a5781a9..2564073857 100644 --- a/tests/headers/opaque_typedef.hpp +++ b/tests/headers/opaque_typedef.hpp @@ -14,4 +14,4 @@ class Wat3<3>; /**
*/ typedef RandomTemplate ShouldBeOpaque; -typedef RandomTemplate ShouldNotBeOpaque; +typedef RandomTemplate ShouldNotBeOpaque; diff --git a/tests/headers/private.hpp b/tests/headers/private.hpp index 070bdddcdc..c0f3ce7f50 100644 --- a/tests/headers/private.hpp +++ b/tests/headers/private.hpp @@ -15,7 +15,7 @@ struct VeryPrivate { /**
*/ struct ContradictPrivate { - /**
*/ + /**
*/ int mNotPrivate; int mIsPrivate; }; diff --git a/tests/headers/redeclaration.hpp b/tests/headers/redeclaration.hpp new file mode 100644 index 0000000000..d536b158b4 --- /dev/null +++ b/tests/headers/redeclaration.hpp @@ -0,0 +1,7 @@ +extern "C" { + void foo(); +} + +extern "C" { + void foo(); +} diff --git a/tests/headers/typeref.hpp b/tests/headers/typeref.hpp new file mode 100644 index 0000000000..b94c98ef6b --- /dev/null +++ b/tests/headers/typeref.hpp @@ -0,0 +1,28 @@ +struct nsFoo; + +namespace mozilla { + +struct FragmentOrURL { bool mIsLocalRef; }; +struct Position { }; + +} // namespace mozilla + +class Bar { + nsFoo* mFoo; +}; + +namespace mozilla { + +template +struct StyleShapeSource { + union { + Position* mPosition; + FragmentOrURL* mFragmentOrURL; + }; +}; + +} // namespace mozilla + +struct nsFoo { + mozilla::StyleShapeSource mBar; +}; diff --git a/tests/headers/unknown_attr.h b/tests/headers/unknown_attr.h new file mode 100644 index 0000000000..f87e9f0b3a --- /dev/null +++ b/tests/headers/unknown_attr.h @@ -0,0 +1,6 @@ +typedef struct { + long long __clang_max_align_nonce1 + __attribute__((__aligned__(__alignof__(long long)))); + long double __clang_max_align_nonce2 + __attribute__((__aligned__(__alignof__(long double)))); +} max_align_t; diff --git a/tests/headers/virtual_dtor.hpp b/tests/headers/virtual_dtor.hpp new file mode 100644 index 0000000000..c35dcab12d --- /dev/null +++ b/tests/headers/virtual_dtor.hpp @@ -0,0 +1,3 @@ +struct nsSlots { + virtual ~nsSlots(); +}; diff --git a/tests/headers/what_is_going_on.hpp b/tests/headers/what_is_going_on.hpp new file mode 100644 index 0000000000..078c1ad5aa --- /dev/null +++ b/tests/headers/what_is_going_on.hpp @@ -0,0 +1,19 @@ + +struct UnknownUnits {}; +typedef float Float; + +template +struct PointTyped { + F x; + F y; + + static PointTyped FromUnknownPoint(const PointTyped& aPoint) { + return PointTyped(aPoint.x, aPoint.y); + } + + PointTyped ToUnknownPoint() const { + return PointTyped(this->x, this->y); + } +}; + +typedef PointTyped IntPoint; diff --git a/tests/headers/whitelist_basic.hpp b/tests/headers/whitelist_basic.hpp new file mode 100644 index 0000000000..661528babc --- /dev/null +++ b/tests/headers/whitelist_basic.hpp @@ -0,0 +1,15 @@ +// bindgen-flags: --whitelist-type WhitelistMe + +template +class WhitelistMe { + class Inner { + T bar; + }; + + int foo; + Inner bar; +}; + +struct DontWhitelistMe { + void* foo; +}; From da69afdaf90f091944719edd258ca1bb0c19a82b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Tue, 13 Sep 2016 14:11:49 -0700 Subject: [PATCH 2/2] Back out docopt. --- Cargo.toml | 1 - src/bin/bindgen.rs | 228 ++++++++++++++++++------------------- tests/tools/run-bindgen.py | 20 +--- 3 files changed, 117 insertions(+), 132 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fdc102c895..883e40df81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ quasi_codegen = "0.15" [dependencies] clang-sys = "0.8.0" -docopt = "0.6.82" libc = "0.2" log = "0.3" env_logger = "0.3" diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs index 1e92ee6de7..1b9d480689 100755 --- a/src/bin/bindgen.rs +++ b/src/bin/bindgen.rs @@ -4,17 +4,16 @@ extern crate bindgen; extern crate env_logger; #[macro_use] -extern crate docopt; -#[macro_use] extern crate log; extern crate clang_sys; extern crate rustc_serialize; use bindgen::{Bindings, BindgenOptions, LinkType}; +use std::default::Default; use std::io; use std::path; +use std::process; use std::env; -use std::default::Default; use std::fs; const USAGE: &'static str = " @@ -23,9 +22,7 @@ Usage: [--link=...] \ [--static-link=...] \ [--framework-link=...] \ - [--match=...] \ [--raw-line=...] \ - [--dtor-attr=...] \ [--opaque-type=...] \ [--blacklist-type=...] \ [--whitelist-type=...] \ @@ -50,11 +47,6 @@ Options: -o= Write bindings to (defaults to stdout) - --match= Only output bindings for definitions from - files whose name contains . If multiple - match options are provided, files matching any - rule are bound to. - --builtins Output bindings for builtin definitions (for example __builtin_va_list) @@ -62,6 +54,8 @@ Options: methods. This is useful when you only care about struct layouts. + --ignore-methods Avoid generating all kind of methods. + --enable-cxx-namespaces Enable support for C++ namespaces. --no-type-renaming Don't rename types. @@ -74,25 +68,9 @@ Options: --use-msvc-mangling Handle MSVC C++ ABI mangling; requires that target be set to (i686|x86_64)-pc-win32 - --override-enum-type= Override enum type, type name could be - uchar - schar - ushort - sshort - uint - sint - ulong - slong - ulonglong - slonglong - --raw-line= Add a raw line at the beginning of the output. - --dtor-attr= Attributes to add to structures with destructor. - --no-class-constants Avoid generating class constants. --no-unstable-rust Avoid generating unstable rust. - --no-namespaced-constants Avoid generating constants right under namespaces. --no-bitfield-methods Avoid generating methods for bitfield access. - --ignore-methods Avoid generating all kind of methods. --opaque-type= Mark a type as opaque. --blacklist-type= Mark a type as hidden. --whitelist-type= Whitelist the type. If this set or any other @@ -110,91 +88,119 @@ Options: directly through to clang. "; -#[derive(Debug, RustcDecodable)] -struct Args { - arg_input_header: String, - flag_link: Vec, - flag_static_link: Vec, - flag_framework_link: Vec, - flag_o: Option, - flag_match: Vec, - flag_builtins: bool, - flag_ignore_functions: bool, - flag_enable_cxx_namespaces: bool, - flag_no_type_renaming: bool, - flag_allow_unknown_types: bool, - flag_emit_clang_ast: bool, - flag_use_msvc_mangling: bool, - flag_override_enum_type: String, - flag_raw_line: Vec, - flag_dtor_attr: Vec, - flag_no_class_constants: bool, - flag_no_unstable_rust: bool, - flag_no_namespaced_constants: bool, - flag_no_bitfield_methods: bool, - flag_ignore_methods: bool, - flag_opaque_type: Vec, - flag_blacklist_type: Vec, - flag_whitelist_type: Vec, - flag_whitelist_function: Vec, - flag_whitelist_var: Vec, - arg_clang_args: Vec, -} - -type ParseResult = Result; - -impl Into)>> for Args { - fn into(mut self) -> Result<(BindgenOptions, Box), String> { - let mut options: BindgenOptions = Default::default(); - - for lib in self.flag_link.drain(..) { - options.links.push((lib, LinkType::Default)); - } +// FIXME(emilio): Replace this with docopt if/when they fix their exponential +// algorithm for argument parsing. +fn parse_args_or_exit(args: Vec) -> (BindgenOptions, Box) { + let mut options = BindgenOptions::default(); + let mut dest_file = None; + let mut source_file = None; + + let mut iter = args.into_iter().skip(1); + loop { + let next = match iter.next() { + Some(arg) => arg, + _ => break, + }; - for lib in self.flag_static_link.drain(..) { - options.links.push((lib, LinkType::Static)); + match &*next { + "-h" | "--help" => { + println!("{}", USAGE); + process::exit(0); + } + "-l" | "--link" => { + let lib = iter.next().expect("--link needs an argument"); + options.links.push((lib, LinkType::Default)); + } + "--static-link" => { + let lib = iter.next().expect("--static-link needs an argument"); + options.links.push((lib, LinkType::Static)); + } + "--framework-link" => { + let lib = iter.next().expect("--framework-link needs an argument"); + options.links.push((lib, LinkType::Framework)); + } + "--raw-line" => { + let line = iter.next().expect("--raw-line needs an argument"); + options.raw_lines.push(line); + } + "--opaque-type" => { + let ty_canonical_name = iter.next().expect("--opaque-type expects a type"); + options.opaque_types.insert(ty_canonical_name); + } + "--blacklist-type" => { + let ty_canonical_name = iter.next().expect("--blacklist-type expects a type"); + options.hidden_types.insert(ty_canonical_name); + } + "--whitelist-type" => { + let ty_pat = iter.next().expect("--whitelist-type expects a type pattern"); + options.whitelisted_types.insert(&ty_pat); + } + "--whitelist-function" => { + let function_pat = iter.next().expect("--whitelist-function expects a pattern"); + options.whitelisted_functions.insert(&function_pat); + } + "--whitelist-var" => { + let var_pat = iter.next().expect("--whitelist-var expects a pattern"); + options.whitelisted_vars.insert(&var_pat); + } + "--" => { + while let Some(clang_arg) = iter.next() { + options.clang_args.push(clang_arg); + } + } + "--output" | "-o" => { + let out_name = iter.next().expect("-o expects a file name"); + dest_file = Some(out_name); + } + "--builtins" => { + options.builtins = true; + } + "--ignore-functions" => { + options.ignore_functions = true; + } + "--no-bitfield-methods" => { + options.gen_bitfield_methods = false; + } + "--ignore-methods" => { + options.ignore_methods = true; + } + "--enable-cxx-namespaces" => { + options.enable_cxx_namespaces = true; + } + "--no-type-renaming" => { + options.rename_types = false; + } + "--no-unstable-rust" => { + options.unstable_rust = false; + } + "--emit-clang-ast" => { + options.emit_ast = true; + } + "--use-msvc-mangling" => { + options.msvc_mangling = true; + } + other if source_file.is_none() => { + source_file = Some(other.into()); + } + other => { + panic!("Unknown option: \"{}\"", other); + } } + } - for lib in self.flag_framework_link.drain(..) { - options.links.push((lib, LinkType::Framework)); - } + if let Some(source_file) = source_file.take() { + options.clang_args.push(source_file); + } - let out = if let Some(ref path_name) = self.flag_o { - let path = path::Path::new(path_name); - let file = try!(fs::File::create(path).map_err(|_| { - format!("Opening {} failed", path_name) - })); - Box::new(io::BufWriter::new(file)) as Box - } else { - Box::new(io::BufWriter::new(io::stdout())) as Box - }; + let out = if let Some(ref path_name) = dest_file { + let path = path::Path::new(path_name); + let file = fs::File::create(path).expect("Opening out file failed"); + Box::new(io::BufWriter::new(file)) as Box + } else { + Box::new(io::BufWriter::new(io::stdout())) as Box + }; - options.match_pat.extend(self.flag_match.drain(..)); - options.builtins = self.flag_builtins; - options.ignore_functions = self.flag_ignore_functions; - options.enable_cxx_namespaces = self.flag_enable_cxx_namespaces; - options.rename_types = !self.flag_no_type_renaming; - options.fail_on_unknown_type = !self.flag_allow_unknown_types; - options.emit_ast = self.flag_emit_clang_ast; - options.msvc_mangling = self.flag_use_msvc_mangling; - options.override_enum_ty = self.flag_override_enum_type; - options.raw_lines.extend(self.flag_raw_line.drain(..)); - options.dtor_attrs.extend(self.flag_dtor_attr.drain(..)); - options.class_constants = !self.flag_no_class_constants; - options.unstable_rust = !self.flag_no_unstable_rust; - options.namespaced_constants = !self.flag_no_namespaced_constants; - options.gen_bitfield_methods = !self.flag_no_bitfield_methods; - options.ignore_methods = self.flag_ignore_methods; - options.opaque_types.extend(self.flag_opaque_type.drain(..)); - options.hidden_types.extend(self.flag_blacklist_type.drain(..)); - options.whitelisted_types.extend(self.flag_whitelist_type.drain(..)); - options.whitelisted_functions.extend(self.flag_whitelist_function.drain(..)); - options.whitelisted_vars.extend(self.flag_whitelist_var.drain(..)); - options.clang_args.extend(self.arg_clang_args.drain(..)); - options.clang_args.push(self.arg_input_header); - - Ok((options, out)) - } + (options, out) } pub fn main() { @@ -227,17 +233,11 @@ pub fn main() { } } - let args: Args = docopt::Docopt::new(USAGE) - .and_then(|d| d.argv(bind_args.iter()).decode()) - .unwrap_or_else(|e| e.exit()); - - let result: ParseResult<_> = args.into(); - let (options, out) = result.unwrap_or_else(|msg| { - panic!("Failed to generate_bindings: {:?}", msg); - }); + let (options, out) = parse_args_or_exit(bind_args); let bindings = Bindings::generate(options, None) .expect("Unable to generate bindings"); + bindings.write(out) .expect("Unable to write bindings to file."); } diff --git a/tests/tools/run-bindgen.py b/tests/tools/run-bindgen.py index bb58bc3a01..d58a028a48 100755 --- a/tests/tools/run-bindgen.py +++ b/tests/tools/run-bindgen.py @@ -18,36 +18,22 @@ [_, bindgen_path, c_path, rust_path] = sys.argv flags = [] -clang_flags = [] with open(sys.argv[2]) as f: for line in f: if line.startswith(BINDGEN_FLAGS_PREFIX): - flags = line.strip().split(BINDGEN_FLAGS_PREFIX)[1] - - try: - idx = flags.index(CLANG_FLAGS_SEPARATOR) - clang_flags = flags[idx + len(CLANG_FLAGS_SEPARATOR):].split(" ") - flags = flags[:idx] - except ValueError: - pass - - flags = flags.split(" ") + flags = line.strip().split(BINDGEN_FLAGS_PREFIX)[1].split(" ") break base_command = [bindgen_path, "-o", rust_path] for line in COMMON_PRELUDE.split("\n"): - flags.append("--raw-line") - flags.append(line) + base_command.append("--raw-line") + base_command.append(line) base_command.extend(flags) base_command.append(c_path) -if len(clang_flags): - base_command.append("--") - base_command.extend(clang_flags) - env = os.environ.copy() # El Capitan likes to unset dyld variables