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; +};