summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md63
-rw-r--r--bindgen_plugin/src/bgmacro.rs10
-rw-r--r--build.rs19
-rw-r--r--src/bin/bindgen.rs48
-rw-r--r--src/clang.rs170
-rw-r--r--src/clangll.rs26
-rw-r--r--src/gen.rs1573
-rw-r--r--src/lib.rs57
-rw-r--r--src/parser.rs694
-rw-r--r--src/types.rs154
-rw-r--r--tests/headers/class.hpp3
-rw-r--r--tests/headers/namespace.h45
-rw-r--r--tests/headers/template.hpp5
-rw-r--r--tests/support.rs2
-rw-r--r--tests/test_builtins.rs1
-rw-r--r--tests/test_cxx.rs34
-rw-r--r--tests/test_decl.rs2
-rw-r--r--tests/test_enum.rs43
-rw-r--r--tests/test_extern.rs2
-rw-r--r--tests/test_func.rs13
-rw-r--r--tests/test_struct.rs222
-rw-r--r--tests/tests.rs1
22 files changed, 2249 insertions, 938 deletions
diff --git a/README.md b/README.md
index eb4f696c..47eda302 100644
--- a/README.md
+++ b/README.md
@@ -6,16 +6,37 @@ rust-bindgen
[![][travis-status-shield]](https://travis-ci.org/crabtw/rust-bindgen/)
A binding generator for the rust language.
+This is a fork designed to work on Spidermonkey headers.
It is ported from [clay's bindgen][].
Requirements
------------
-* clang 3.4 and up
+* clang 3.7 with patches https://github.com/michaelwu/clang/tree/release_37_smhacks or clang 3.8+
-Note: The libclang.so has to be statically linked with LLVM or you will
-encounter [issue 89][]. You can also use LD_PRELOAD=/path/to/libclang.so to
-workaround the problem.
+This bindgen fork requires a patched clang or clang 3.8+ to work properly. This is one way to build a patched clang:
+```
+git clone https://github.com/llvm-mirror/llvm
+cd llvm
+git checkout release_37
+cd tools
+git clone https://github.com/llvm-mirror/clang
+cd clang
+git remote add mwu https://github.com/michaelwu/clang
+git fetch mwu
+git checkout release_37_smhacks
+cd ../.. # llvm root dir
+mkdir build
+cd build
+../configure --enable-optimized
+make
+```
+
+Then before building, make sure to export the path to this copy of clang:
+
+ export LIBCLANG_PATH=~/llvm/build/Release+Asserts/lib
+
+This path also needs to be set in LD_LIBRARY_PATH (Linux) or DYLD_LIBRARY_PATH (OSX) when running bindgen.
Building
--------
@@ -71,6 +92,28 @@ Options:
Options other than stated above are passed to clang
```
+C++ Usage
+---------
+This fork of rust-bindgen can handle a number of C++ features. Because it currently uses a fork of clang though, it may require adding extra arguments to find certain headers. On OpenSUSE 13.2, these additional include pathes can be used:
+
+ -isystem /usr/lib64/gcc/x86_64-suse-linux/4.8/include -isystem /usr/lib64/gcc/x86_64-suse-linux/4.8/include-fixed
+
+On OSX, this include path seems to work:
+
+ -isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1
+
+When passing in header files, the file will automatically be treated as C++ if it ends in ``.hpp``. If it doesn't, ``-x c++`` can be used to force C++ mode.
+
+Annotations
+-----------
+The translation of classes, structs, enums, and typedefs can be adjusted using annotations. Annotations are specifically formatted html tags inside doxygen style comments. The opaque annotation instructs bindgen to ignore all fields defined in a struct/class.
+
+ /// <div rust-bindgen opaque></div>
+
+The hide annotation instructs bindgen to ignore the struct/class/field/enum completely.
+
+ /// <div rust-bindgen hide></div>
+
Macro Usage
-----------
@@ -118,15 +161,3 @@ main.rs
mod mysql_bindings {
bindgen!("/usr/include/mysql/mysql.h", match="mysql.h", link="mysql")
}
-
-TODO
-----
-
-* bitfield accessors
-
-[clay's bindgen]: https://github.com/jckarter/clay/blob/master/tools/bindgen.clay
-[crates-version-shield]: https://img.shields.io/crates/v/bindgen.svg?style=flat-square
-[crates-downloads-shield]: https://img.shields.io/crates/d/bindgen.svg?style=flat-square
-[crates-license-shield]: https://img.shields.io/crates/l/bindgen.svg?style=flat-square
-[travis-status-shield]: https://img.shields.io/travis/crabtw/rust-bindgen.svg?label=travis&style=flat-square
-[issue 89]: https://github.com/crabtw/rust-bindgen/issues/89
diff --git a/bindgen_plugin/src/bgmacro.rs b/bindgen_plugin/src/bgmacro.rs
index 707577c0..eebc56e6 100644
--- a/bindgen_plugin/src/bgmacro.rs
+++ b/bindgen_plugin/src/bgmacro.rs
@@ -25,8 +25,8 @@ pub fn bindgen_macro(cx: &mut base::ExtCtxt, sp: codemap::Span, tts: &[ast::Toke
}
// Reparse clang_args as it is passed in string form
- let clang_args = visit.options.clang_args.join(" ");
- visit.options.clang_args = parse_process_args(&clang_args[..]);
+ let clang_args = visit.options.clang_args.connect(" ");
+ visit.options.clang_args = parse_process_args(&clang_args);
if let Some(path) = bindgen::get_include_dir() {
visit.options.clang_args.push("-I".to_owned());
@@ -66,7 +66,7 @@ pub fn bindgen_macro(cx: &mut base::ExtCtxt, sp: codemap::Span, tts: &[ast::Toke
}
Box::new(BindgenResult { items: Some(SmallVector::many(items)) }) as Box<base::MacResult>
-
+
}
Err(_) => base::DummyResult::any(sp)
};
@@ -223,7 +223,7 @@ fn parse_macro_opts(cx: &mut base::ExtCtxt, tts: &[ast::TokenTree], visit: &mut
// I'm sure there's a nicer way of doing it
fn as_str<'a>(owned: &'a Option<String>) -> Option<&'a str> {
match owned {
- &Some(ref s) => Some(&s[..]),
+ &Some(ref s) => Some(s),
&None => None
}
}
@@ -289,7 +289,7 @@ fn parse_process_args(s: &str) -> Vec<String> {
if part.len() > 0 {
// Remove any extra whitespace outside the quotes
- let part = &part[..].trim();
+ let part = part.trim();
// Replace quoted characters
let part = part.replace("\\\"", "\"");
let part = part.replace("\\\'", "\'");
diff --git a/build.rs b/build.rs
index fd0617cb..73baa3fa 100644
--- a/build.rs
+++ b/build.rs
@@ -6,6 +6,7 @@ use std::process::Command;
const LINUX_CLANG_DIRS: &'static [&'static str] = &[
"/usr/lib",
"/usr/lib/llvm",
+ "/usr/lib/llvm-3.8/lib",
"/usr/lib/llvm-3.7/lib",
"/usr/lib/llvm-3.6/lib",
"/usr/lib/llvm-3.5/lib",
@@ -21,10 +22,7 @@ const MAC_CLANG_DIR: &'static [&'static str] = &[
const WIN_CLANG_DIRS: &'static [&'static str] = &["C:\\Program Files\\LLVM\\bin", "C:\\Program Files\\LLVM\\lib"];
fn path_exists(path: &Path) -> bool {
- match fs::metadata(path) {
- Ok(_) => true,
- Err(_) => false
- }
+ fs::metadata(path).is_ok()
}
fn main() {
@@ -37,16 +35,16 @@ fn main() {
} else if cfg!(target_os = "macos") {
MAC_CLANG_DIR.iter().map(ToString::to_string).collect()
} else if cfg!(target_os = "windows") {
- WIN_CLANG_DIRS.iter().map(ToString::to_string).collect()
+ WIN_CLANG_DIRS.iter().map(ToString::to_string).collect()
} else {
panic!("Platform not supported");
};
let clang_lib = if cfg!(target_os = "windows") {
- format!("libclang{}", env::consts::DLL_SUFFIX)
- } else {
- format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX)
- };
+ format!("libclang{}", env::consts::DLL_SUFFIX)
+ } else {
+ format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX)
+ };
//may contain path to libclang detected via ldconfig
let mut libclang_path_string = String::new();
@@ -60,7 +58,8 @@ fn main() {
None
}
}).next();
- if maybe_clang_dir == None && cfg!(target_os = "linux") {
+
+ if maybe_clang_dir.is_none() && cfg!(target_os = "linux") {
//try to find via lddconfig
//may return line, like
//libclang.so.3.7 (libc6,x86-64) => /usr/lib64/libclang.so.3.7
diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs
index c049f9a1..b0a3c8e8 100644
--- a/src/bin/bindgen.rs
+++ b/src/bin/bindgen.rs
@@ -2,7 +2,8 @@
#![crate_type = "bin"]
extern crate bindgen;
-#[macro_use] extern crate log;
+#[macro_use]
+extern crate log;
use bindgen::{Bindings, BindgenOptions, LinkType, Logger};
use std::io;
@@ -16,17 +17,17 @@ struct StdLogger;
impl Logger for StdLogger {
fn error(&self, msg: &str) {
- error!("{}", msg);
+ println!("{}", msg);
}
fn warn(&self, msg: &str) {
- warn!("{}", msg);
+ println!("{}", msg);
}
}
enum ParseResult {
CmdUsage,
- ParseOk(BindgenOptions, Box<io::Write+'static>),
+ ParseOk(BindgenOptions, Box<io::Write>),
ParseErr(String)
}
@@ -34,7 +35,6 @@ fn parse_args(args: &[String]) -> ParseResult {
let args_len = args.len();
let mut options: BindgenOptions = Default::default();
- options.derive_debug = false;
let mut out = Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>;
if args_len == 0 {
@@ -47,7 +47,7 @@ fn parse_args(args: &[String]) -> ParseResult {
options.links.push((args[ix][2..].to_string(), LinkType::Default));
ix += 1;
} else {
- match &args[ix][..] {
+ match &*args[ix] {
"--help" | "-h" => {
return ParseResult::CmdUsage;
}
@@ -98,12 +98,8 @@ fn parse_args(args: &[String]) -> ParseResult {
options.builtins = true;
ix += 1;
}
- "-no-rust-enums" => {
- options.rust_enums = false;
- ix += 1;
- }
- "-derive-debug" => {
- options.derive_debug = true;
+ "-ignore-functions" => {
+ options.ignore_functions = true;
ix += 1;
}
"-allow-unknown-types" => {
@@ -117,6 +113,14 @@ fn parse_args(args: &[String]) -> ParseResult {
options.override_enum_ty = args[ix + 1].clone();
ix += 2;
}
+ "-enable-cxx-namespaces" => {
+ options.enable_cxx_namespaces = true;
+ ix += 1;
+ }
+ "-no-type-renaming" => {
+ options.rename_types = false;
+ ix += 1;
+ }
_ => {
options.clang_args.push(args[ix].clone());
ix += 1;
@@ -129,7 +133,7 @@ fn parse_args(args: &[String]) -> ParseResult {
}
fn print_usage(bin: String) {
- let mut s = format!("Usage: {} [options] input.h", &bin[..]);
+ let mut s = format!("Usage: {} [options] input.h", &bin);
s.push_str(
"
Options:
@@ -145,6 +149,10 @@ Options:
matching any rule are bound to.
-builtins Output bindings for builtin definitions
(for example __builtin_va_list)
+ -ignore-functions Don't generate bindings for functions and methods.
+ This is useful when you only care about struct layouts.
+ -enable-cxx-namespaces Enable support for C++ namespaces.
+ -no-type-renaming Don't rename types.
-allow-unknown-types Don't fail if we encounter types we do not support,
instead treat them as void
-emit-clang-ast Output the ast (for debugging purposes)
@@ -163,14 +171,22 @@ Options:
Options other than stated above are passed to clang.
"
);
- print!("{}", &s[..]);
+ println!("{}", &s);
}
pub fn main() {
let mut bind_args: Vec<_> = env::args().collect();
let bin = bind_args.remove(0);
- match parse_args(&bind_args[..]) {
+ match bindgen::get_include_dir() {
+ Some(path) => {
+ bind_args.push("-I".to_owned());
+ bind_args.push(path);
+ }
+ None => (),
+ }
+
+ match parse_args(&bind_args) {
ParseResult::ParseErr(e) => panic!(e),
ParseResult::CmdUsage => print_usage(bin),
ParseResult::ParseOk(options, out) => {
@@ -179,7 +195,7 @@ pub fn main() {
Ok(bindings) => match bindings.write(out) {
Ok(()) => (),
Err(e) => {
- logger.error(&format!("Unable to write bindings to file. {}", e)[..]);
+ logger.error(&format!("Unable to write bindings to file. {}", e));
exit(-1);
}
},
diff --git a/src/clang.rs b/src/clang.rs
index a8c4aace..be07a0e3 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -3,11 +3,9 @@
use std::os::raw::{c_uint, c_char, c_int, c_ulong};
use std::{mem, ptr};
use std::fmt;
-use std::str;
-use std::ffi::CStr;
use std::hash::Hash;
use std::hash::Hasher;
-use std::ffi::CString;
+use std::ffi::{CString, CStr};
use clangll::*;
@@ -27,12 +25,40 @@ impl Cursor {
}
}
+ pub fn mangling(&self) -> String {
+ let mut mangling = unsafe {
+ String_ { x: clang_Cursor_getMangling(self.x) }.to_string()
+ };
+
+ // Try to undo backend mangling
+ if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
+ mangling.remove(0);
+ }
+ mangling
+ }
+
+ pub fn semantic_parent(&self) -> Cursor {
+ unsafe {
+ Cursor { x: clang_getCursorSemanticParent(self.x) }
+ }
+ }
+
pub fn kind(&self) -> Enum_CXCursorKind {
unsafe {
clang_getCursorKind(self.x)
}
}
+ pub fn is_template(&self) -> bool {
+ self.specialized().is_valid()
+ }
+
+ pub fn is_valid(&self) -> bool {
+ unsafe {
+ clang_isInvalid(self.kind()) == 0
+ }
+ }
+
pub fn location(&self) -> SourceLocation {
unsafe {
SourceLocation { x: clang_getCursorLocation(self.x) }
@@ -45,6 +71,18 @@ impl Cursor {
}
}
+ pub fn raw_comment(&self) -> String {
+ unsafe {
+ String_ { x: clang_Cursor_getRawCommentText(self.x) }.to_string()
+ }
+ }
+
+ pub fn comment(&self) -> Comment {
+ unsafe {
+ Comment { x: clang_Cursor_getParsedComment(self.x) }
+ }
+ }
+
pub fn cur_type(&self) -> Type {
unsafe {
Type { x: clang_getCursorType(self.x) }
@@ -63,6 +101,12 @@ impl Cursor {
}
}
+ pub fn specialized(&self) -> Cursor {
+ unsafe {
+ Cursor { x: clang_getSpecializedCursorTemplate(self.x) }
+ }
+ }
+
pub fn visit<F>(&self, func:F)
where F: for<'a, 'b> FnMut(&'a Cursor, &'b Cursor) -> Enum_CXChildVisitResult
{
@@ -112,6 +156,12 @@ impl Cursor {
}
}
+ pub fn visibility(&self) -> Enum_CXVisibilityKind {
+ unsafe {
+ clang_getCursorVisibility(self.x)
+ }
+ }
+
// function
pub fn args(&self) -> Vec<Cursor> {
unsafe {
@@ -135,6 +185,33 @@ impl Cursor {
clang_Cursor_getNumArguments(self.x)
}
}
+
+ // CXX member
+ pub fn access_specifier(&self) -> Enum_CX_CXXAccessSpecifier {
+ unsafe {
+ clang_getCXXAccessSpecifier(self.x)
+ }
+ }
+
+ // CXX method
+ pub fn method_is_static(&self) -> bool {
+ unsafe {
+ clang_CXXMethod_isStatic(self.x) != 0
+ }
+ }
+
+ pub fn method_is_virtual(&self) -> bool {
+ unsafe {
+ clang_CXXMethod_isVirtual(self.x) != 0
+ }
+ }
+
+ // CXX base
+ pub fn is_virtual_base(&self) -> bool {
+ unsafe {
+ clang_isVirtualBase(self.x) != 0
+ }
+ }
}
extern fn visit_children(cur: CXCursor, parent: CXCursor,
@@ -184,6 +261,12 @@ impl Type {
}
}
+ pub fn spelling(&self) -> String {
+ unsafe {
+ String_ { x: clang_getTypeSpelling(self.x) }.to_string()
+ }
+ }
+
pub fn is_const(&self) -> bool {
unsafe {
clang_isConstQualifiedType(self.x) == 1
@@ -204,6 +287,18 @@ impl Type {
}
}
+ pub fn num_template_args(&self) -> c_int {
+ unsafe {
+ clang_Type_getNumTemplateArguments(self.x)
+ }
+ }
+
+ pub fn template_arg_type(&self, i: c_int) -> Type {
+ unsafe {
+ Type { x: clang_Type_getTemplateArgumentAsType(self.x, i) }
+ }
+ }
+
// pointer
pub fn pointee_type(&self) -> Type {
unsafe {
@@ -291,6 +386,56 @@ impl fmt::Display for SourceLocation {
}
}
+// Comment
+pub struct Comment {
+ x: CXComment
+}
+
+impl Comment {
+ pub fn kind(&self) -> Enum_CXCommentKind {
+ unsafe {
+ clang_Comment_getKind(self.x)
+ }
+ }
+
+ pub fn num_children(&self) -> c_uint {
+ unsafe {
+ clang_Comment_getNumChildren(self.x)
+ }
+ }
+
+ pub fn get_child(&self, idx: c_uint) -> Comment {
+ unsafe {
+ Comment { x: clang_Comment_getChild(self.x, idx) }
+ }
+ }
+
+ // HTML
+ pub fn get_tag_name(&self) -> String {
+ unsafe {
+ String_ { x: clang_HTMLTagComment_getTagName(self.x) }.to_string()
+ }
+ }
+
+ pub fn get_num_tag_attrs(&self) -> c_uint {
+ unsafe {
+ clang_HTMLStartTag_getNumAttrs(self.x)
+ }
+ }
+
+ pub fn get_tag_attr_name(&self, idx: c_uint) -> String {
+ unsafe {
+ String_ { x: clang_HTMLStartTag_getAttrName(self.x, idx) }.to_string()
+ }
+ }
+
+ pub fn get_tag_attr_value(&self, idx: c_uint) -> String {
+ unsafe {
+ String_ { x: clang_HTMLStartTag_getAttrValue(self.x, idx) }.to_string()
+ }
+ }
+}
+
// File
pub struct File {
x: CXFile
@@ -320,7 +465,7 @@ impl fmt::Display for String_ {
unsafe {
let c_str = clang_getCString(self.x) as *const c_char;
let p = c_str as *const _;
- str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned().fmt(f)
+ f.write_str(&String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()))
}
}
}
@@ -361,14 +506,13 @@ pub struct TranslationUnit {
impl TranslationUnit {
pub fn parse(ix: &Index, file: &str, cmd_args: &[String],
- unsaved: &[UnsavedFile], opts: c_uint) -> TranslationUnit {
- let fname = CString::new(file.as_bytes()).unwrap();
- let fname = fname.as_ptr();
- let c_args: Vec<CString> = cmd_args.iter().map(|s| CString::new(s.as_bytes()).unwrap()).collect();
- let c_args: Vec<*const c_char> = c_args.iter().map(|s| s.as_ptr()).collect();
+ unsaved: &[UnsavedFile], opts: ::libc::c_uint) -> TranslationUnit {
+ let fname = CString::new(file).unwrap();
+ let _c_args: Vec<CString> = cmd_args.iter().map(|s| CString::new(s.clone()).unwrap()).collect();
+ let c_args: Vec<*const c_char> = _c_args.iter().map(|s| s.as_ptr()).collect();
let mut c_unsaved: Vec<Struct_CXUnsavedFile> = unsaved.iter().map(|f| f.x).collect();
let tu = unsafe {
- clang_parseTranslationUnit(ix.x, fname,
+ clang_parseTranslationUnit(ix.x, fname.as_ptr(),
c_args.as_ptr(),
c_args.len() as c_int,
c_unsaved.as_mut_ptr(),
@@ -478,8 +622,8 @@ pub struct UnsavedFile {
impl UnsavedFile {
pub fn new(name: &str, contents: &str) -> UnsavedFile {
- let name = CString::new(name.as_bytes()).unwrap();
- let contents = CString::new(contents.as_bytes()).unwrap();
+ let name = CString::new(name).unwrap();
+ let contents = CString::new(contents).unwrap();
let x = Struct_CXUnsavedFile {
Filename: name.as_ptr(),
Contents: contents.as_ptr(),
@@ -729,7 +873,7 @@ pub fn ast_dump(c: &Cursor, depth: isize)-> Enum_CXVisitorResult {
print_indent(depth, &format!("({} {} {}",
kind_to_str(c.kind()),
c.spelling(),
- type_to_str(ct))[..]
+ type_to_str(ct))
);
c.visit(| s, _: &Cursor| {
ast_dump(s, depth + 1)
diff --git a/src/clangll.rs b/src/clangll.rs
index 208df235..bd1652f0 100644
--- a/src/clangll.rs
+++ b/src/clangll.rs
@@ -328,12 +328,17 @@ pub struct CXComment {
pub ASTNode: *const c_void,
pub TranslationUnit: CXTranslationUnit,
}
-pub type Enum_CXLinkageKind = c_uint;
-pub const CXLinkage_Invalid: c_uint = 0;
-pub const CXLinkage_NoLinkage: c_uint = 1;
-pub const CXLinkage_Internal: c_uint = 2;
-pub const CXLinkage_UniqueExternal: c_uint = 3;
-pub const CXLinkage_External: c_uint = 4;
+pub type Enum_CXLinkageKind = ::libc::c_uint;
+pub const CXLinkage_Invalid: ::libc::c_uint = 0;
+pub const CXLinkage_NoLinkage: ::libc::c_uint = 1;
+pub const CXLinkage_Internal: ::libc::c_uint = 2;
+pub const CXLinkage_UniqueExternal: ::libc::c_uint = 3;
+pub const CXLinkage_External: ::libc::c_uint = 4;
+pub type Enum_CXVisibilityKind = ::libc::c_uint;
+pub const CXVisibility_Invalid: ::libc::c_uint = 0;
+pub const CXVisibility_Hidden: ::libc::c_uint = 1;
+pub const CXVisibility_Protected: ::libc::c_uint = 2;
+pub const CXVisibility_Default: ::libc::c_uint = 3;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Struct_CXPlatformAvailability {
@@ -1005,6 +1010,7 @@ extern "C" {
pub fn clang_isPreprocessing(arg1: Enum_CXCursorKind) -> c_uint;
pub fn clang_isUnexposed(arg1: Enum_CXCursorKind) -> c_uint;
pub fn clang_getCursorLinkage(cursor: CXCursor) -> Enum_CXLinkageKind;
+ pub fn clang_getCursorVisibility(cursor: CXCursor) -> Enum_CXVisibilityKind;
pub fn clang_getCursorAvailability(cursor: CXCursor) ->
Enum_CXAvailabilityKind;
pub fn clang_getCursorPlatformAvailability(cursor: CXCursor,
@@ -1081,8 +1087,11 @@ extern "C" {
c_longlong;
pub fn clang_Type_getCXXRefQualifier(T: CXType) ->
Enum_CXRefQualifierKind;
- pub fn clang_Cursor_isBitField(C: CXCursor) -> c_uint;
- pub fn clang_isVirtualBase(arg1: CXCursor) -> c_uint;
+ pub fn clang_Type_getNumTemplateArguments(T: CXType) -> ::libc::c_int;
+ pub fn clang_Type_getTemplateArgumentAsType(T: CXType, i: ::libc::c_int) ->
+ CXType;
+ pub fn clang_Cursor_isBitField(C: CXCursor) -> ::libc::c_uint;
+ pub fn clang_isVirtualBase(arg1: CXCursor) -> ::libc::c_uint;
pub fn clang_getCXXAccessSpecifier(arg1: CXCursor) ->
Enum_CX_CXXAccessSpecifier;
pub fn clang_getNumOverloadedDecls(cursor: CXCursor) -> c_uint;
@@ -1130,6 +1139,7 @@ extern "C" {
pub fn clang_Cursor_getCommentRange(C: CXCursor) -> CXSourceRange;
pub fn clang_Cursor_getRawCommentText(C: CXCursor) -> CXString;
pub fn clang_Cursor_getBriefCommentText(C: CXCursor) -> CXString;
+ 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_Module_getASTFile(Module: CXModule) -> CXFile;
diff --git a/src/gen.rs b/src/gen.rs
index da55ca72..93d2c989 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -3,9 +3,7 @@ use std::cell::RefCell;
use std::vec::Vec;
use std::rc::Rc;
use std::collections::HashMap;
-use std::collections::hash_map::Entry;
-
-use syntax::abi;
+use syntax::abi::Abi;
use syntax::ast;
use syntax::codemap::{Span, Spanned, respan, ExpnInfo, NameAndSpan, MacroBang};
use syntax::ext::base;
@@ -15,18 +13,45 @@ use syntax::ext::quote::rt::ToTokens;
use syntax::feature_gate::Features;
use syntax::owned_slice::OwnedSlice;
use syntax::parse;
-use syntax::parse::token::InternedString;
+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, LinkType};
+use super::BindgenOptions;
+use super::LinkType;
use types::*;
struct GenCtx<'r> {
ext_cx: base::ExtCtxt<'r>,
- unnamed_ty: usize,
- span: Span
+ options: BindgenOptions,
+ span: Span,
+ module_map: ModuleMap,
+ current_module_id: ModuleId,
+}
+
+impl<'r> GenCtx<'r> {
+ fn full_path_for_module(&self, id: ModuleId) -> Vec<String> {
+ 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(&current).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 first<A, B>((val, _): (A, B)) -> A {
@@ -37,11 +62,6 @@ fn ref_eq<T>(thing: &T, other: &T) -> bool {
(thing as *const T) == (other as *const T)
}
-fn to_intern_str(ctx: &mut GenCtx, s: String) -> parse::token::InternedString {
- let id = ctx.ext_cx.ident_of(&s[..]);
- id.name.as_str()
-}
-
fn empty_generics() -> ast::Generics {
ast::Generics {
lifetimes: Vec::new(),
@@ -53,73 +73,191 @@ fn empty_generics() -> ast::Generics {
}
}
-fn rust_id(ctx: &mut GenCtx, name: String) -> (String, bool) {
- let token = parse::token::Ident(ctx.ext_cx.ident_of(&name[..]), parse::token::Plain);
- if token.is_any_keyword() || "bool" == &name[..] {
- let mut s = "_".to_owned();
- s.push_str(&name[..]);
+fn rust_id(ctx: &mut GenCtx, name: &str) -> (String, bool) {
+ let token = parse::token::Ident(ctx.ext_cx.ident_of(name), parse::token::Plain);
+ if token.is_any_keyword() || "bool" == name {
+ let mut s = "_".to_string();
+ s.push_str(name);
(s, true)
} else {
- (name, false)
+ (name.to_owned(), false)
}
}
-fn rust_type_id(ctx: &mut GenCtx, name: String) -> String {
- if "bool" == &name[..] ||
- "uint" == &name[..] ||
- "u8" == &name[..] ||
- "u16" == &name[..] ||
- "u32" == &name[..] ||
- "f32" == &name[..] ||
- "f64" == &name[..] ||
- "i8" == &name[..] ||
- "i16" == &name[..] ||
- "i32" == &name[..] ||
- "i64" == &name[..] ||
- "Self" == &name[..] ||
- "str" == &name[..] {
- let mut s = "_".to_owned();
- s.push_str(&name[..]);
- s
- } else {
- let (n, _) = rust_id(ctx, name);
- n
+fn rust_type_id(ctx: &mut GenCtx, name: &str) -> String {
+ match name {
+ "bool" | "uint" | "u8" | "u16" |
+ "u32" | "f32" | "f64" | "i8" |
+ "i16" | "i32" | "i64" | "Self" |
+ "str" => {
+ let mut s = "_".to_string();
+ s.push_str(name);
+ s
+ }
+ _ => first(rust_id(ctx, name))
}
}
-fn unnamed_name(ctx: &mut GenCtx, name: String) -> String {
- if name.is_empty() {
- ctx.unnamed_ty += 1;
- format!("Unnamed{}", ctx.unnamed_ty)
- } else {
- 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 comp_name(kind: CompKind, name: &str) -> String {
- match kind {
- CompKind::Struct => struct_name(name),
- CompKind::Union => union_name(name),
+fn struct_name(ctx: &GenCtx, name: &str) -> String {
+ if ctx.options.rename_types {
+ format!("Struct_{}", name)
+ } else {
+ name.to_owned()
}
}
-fn struct_name(name: &str) -> String {
- format!("Struct_{}", name)
+fn union_name(ctx: &GenCtx, name: &str) -> String {
+ if ctx.options.rename_types {
+ format!("Union_{}", name)
+ } else {
+ name.to_owned()
+ }
}
-fn union_name(name: &str) -> String {
- format!("Union_{}", name)
+fn enum_name(ctx: &GenCtx, name: &str) -> String {
+ if ctx.options.rename_types {
+ format!("Enum_{}", name)
+ } else {
+ name.to_owned()
+ }
}
-fn enum_name(name: &str) -> String {
- format!("Enum_{}", name)
+fn gen_unmangle_method(ctx: &mut GenCtx,
+ v: &VarInfo,
+ counts: &mut HashMap<String, isize>,
+ self_kind: ast::SelfKind)
+ -> ast::ImplItem {
+ let fndecl;
+ let mut args = vec!();
+
+ match self_kind {
+ ast::SelfKind::Static => (),
+ ast::SelfKind::Region(_, mutable, _) => {
+ let selfexpr = match mutable {
+ ast::Mutability::Immutable => quote_expr!(&ctx.ext_cx, &*self),
+ ast::Mutability::Mutable => quote_expr!(&ctx.ext_cx, &mut *self),
+ };
+ args.push(selfexpr);
+ },
+ _ => unreachable!()
+ }
+
+ 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.len() > 0 {
+ sig.args[1..].iter()
+ } else {
+ sig.args.iter()
+ };
+ for arg in iter {
+ let (ref n, _) = *arg;
+ let argname = if n.is_empty() {
+ unnamed += 1;
+ format!("arg{}", unnamed)
+ } else {
+ first(rust_id(ctx, &n))
+ };
+ let expr = 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(&argname),
+ parameters: ast::PathParameters::none()
+ })
+ }),
+ span: ctx.span,
+ attrs: None,
+ };
+ args.push(P(expr));
+ }
+ },
+ _ => unreachable!()
+ };
+
+ let sig = ast::MethodSig {
+ unsafety: ast::Unsafety::Unsafe,
+ abi: Abi::Rust,
+ decl: P(fndecl),
+ generics: empty_generics(),
+ explicit_self: respan(ctx.span, self_kind),
+ constness: ast::Constness::NotConst,
+ };
+
+ let block = ast::Block {
+ stmts: vec!(),
+ expr: Some(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(&v.mangled),
+ parameters: ast::PathParameters::none()
+ })
+ }),
+ span: ctx.span,
+ attrs: None,
+ }),
+ args
+ ),
+ span: ctx.span,
+ attrs: None,
+ })),
+ 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
+ }));
+
+ 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)),
+ span: ctx.span
+ }
}
-pub fn gen_mod(
- options: &BindgenOptions,
- globs: Vec<Global>,
- span: Span)
- -> Vec<P<ast::Item>> {
+pub fn gen_mods(links: &[(String, LinkType)],
+ map: ModuleMap,
+ options: BindgenOptions,
+ span: Span) -> Vec<P<ast::Item>> {
// Create a dummy ExtCtxt. We only need this for string interning and that uses TLS.
let mut features = Features::new();
features.allow_quote = true;
@@ -130,25 +268,132 @@ pub fn gen_mod(
trace_mac: false,
};
let sess = &parse::ParseSess::new();
- let mut feature_gated_cfgs = Vec::new();
+ let mut feature_gated_cfgs = vec![];
let mut ctx = GenCtx {
- ext_cx: base::ExtCtxt::new(
- sess,
- Vec::new(),
- cfg,
- &mut feature_gated_cfgs,
- ),
- unnamed_ty: 0,
- span: span
+ ext_cx: base::ExtCtxt::new(sess, Vec::new(), cfg, &mut feature_gated_cfgs),
+ options: options,
+ span: span,
+ module_map: map,
+ current_module_id: ROOT_MODULE_ID,
};
+
ctx.ext_cx.bt_push(ExpnInfo {
call_site: ctx.span,
callee: NameAndSpan {
- format: MacroBang(parse::token::intern("")),
+ format: MacroBang(intern("")),
allow_internal_unstable: false,
span: None
}
});
+
+ if let Some(root_mod) = gen_mod(&mut ctx, ROOT_MODULE_ID, links, span) {
+ if !ctx.options.enable_cxx_namespaces {
+ match root_mod.node {
+ // XXX This clone might be really expensive, but doing:
+ // ast::ItemMod(ref mut root) => {
+ // return ::std::mem::replace(&mut root.items, vec![]);
+ // }
+ // fails with "error: cannot borrow immutable anonymous field as mutable".
+ // So...
+ ast::ItemKind::Mod(ref root) => {
+ return root.items.clone()
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ let root_export = P(ast::Item {
+ ident: ctx.ext_cx.ident_of(""),
+ attrs: vec![],
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Use(P(
+ Spanned {
+ node: ast::ViewPathGlob(ast::Path {
+ span: span.clone(),
+ global: false,
+ segments: vec![ast::PathSegment {
+ identifier: root_mod.ident,
+ parameters: ast::PathParameters::none(),
+ }]
+ }),
+ span: span.clone(),
+ })),
+ vis: ast::Visibility::Public,
+ span: span.clone(),
+ });
+
+ vec![root_export, root_mod]
+ } else {
+ vec![]
+ }
+}
+
+fn gen_mod(mut ctx: &mut GenCtx,
+ module_id: ModuleId,
+ links: &[(String, LinkType)],
+ span: Span) -> Option<P<ast::Item>> {
+
+ // 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 = ctx.ext_cx.ident_of(&ctx.module_map.get(&ROOT_MODULE_ID).unwrap().name);
+ vec![P(ast::Item {
+ ident: ctx.ext_cx.ident_of(""),
+ attrs: vec![],
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Use(P(
+ Spanned {
+ node: ast::ViewPathSimple(root.clone(),
+ ast::Path {
+ span: span.clone(),
+ global: false,
+ segments: vec![ast::PathSegment {
+ identifier: root,
+ parameters: ast::PathParameters::none(),
+ }]
+ }),
+ span: span.clone(),
+ })),
+ vis: ast::Visibility::Public,
+ span: span.clone(),
+ })]
+ } 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_globals(mut ctx: &mut GenCtx,
+ links: &[(String, LinkType)],
+ globs: &[Global]) -> Vec<P<ast::Item>> {
let uniq_globs = tag_dup_decl(globs);
let mut fs = vec!();
@@ -184,70 +429,51 @@ pub fn gen_mod(
for g in gs.into_iter() {
match g {
GType(ti) => {
- let t = ti.borrow();
- defs.extend(ctypedef_to_rs(
- &mut ctx,
- options.rust_enums,
- options.derive_debug,
- t.name.clone(), &t.ty))
+ let t = ti.borrow().clone();
+ defs.push(ctypedef_to_rs(&mut ctx, t))
},
GCompDecl(ci) => {
- {
- let mut c = ci.borrow_mut();
- c.name = unnamed_name(&mut ctx, c.name.clone());
- }
let c = ci.borrow().clone();
- defs.push(opaque_to_rs(&mut ctx, comp_name(c.kind, &c.name)));
+ let name = comp_name(&ctx, c.kind, &c.name);
+
+ defs.push(opaque_to_rs(&mut ctx, &name));
},
GComp(ci) => {
- {
- let mut c = ci.borrow_mut();
- c.name = unnamed_name(&mut ctx, c.name.clone());
- }
let c = ci.borrow().clone();
- defs.extend(comp_to_rs(&mut ctx, c.kind, comp_name(c.kind, &c.name),
- options.derive_debug,
- c.layout, c.members).into_iter())
+ let name = comp_name(&ctx, c.kind, &c.name);
+ defs.extend(comp_to_rs(&mut ctx, &name, c).into_iter())
},
GEnumDecl(ei) => {
- {
- let mut e = ei.borrow_mut();
- e.name = unnamed_name(&mut ctx, e.name.clone());
- }
let e = ei.borrow().clone();
- defs.push(opaque_to_rs(&mut ctx, enum_name(&e.name)));
+ let name = enum_name(&ctx, &e.name);
+
+ defs.push(opaque_to_rs(&mut ctx, &name));
},
GEnum(ei) => {
- {
- let mut e = ei.borrow_mut();
- e.name = unnamed_name(&mut ctx, e.name.clone());
- }
- let e = ei.borrow();
- defs.extend(cenum_to_rs(
- &mut ctx,
- options.rust_enums,
- options.derive_debug,
- enum_name(&e.name), e.kind, e.layout, &e.items));
+ 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);
+ let ty = cty_to_rs(&mut ctx, &v.ty, v.is_const, true);
defs.push(const_to_rs(&mut ctx, v.name.clone(), v.val.unwrap(), ty));
},
_ => { }
}
}
- let vars = vs.into_iter().map(|v| {
+ 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.ty, v.is_const)
+ cvar_to_rs(&mut ctx, v.name.clone(), v.mangled.clone(), &v.ty, v.is_const)
},
_ => unreachable!()
}
}).collect();
+ let mut unmangle_count: HashMap<String, isize> = HashMap::new();
let funcs = {
let func_list = fs.into_iter().map(|f| {
match f {
@@ -255,9 +481,21 @@ pub fn gen_mod(
let v = vi.borrow();
match v.ty {
TFuncPtr(ref sig) => {
- let decl = cfunc_to_rs(&mut ctx, v.name.clone(),
+ 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);
+ sig.is_variadic, ast::Visibility::Public);
(sig.abi, decl)
}
_ => unreachable!()
@@ -267,26 +505,19 @@ pub fn gen_mod(
}
});
- let mut map: HashMap<abi::Abi, Vec<_>> = HashMap::new();
+ let mut map: HashMap<Abi, Vec<_>> = HashMap::new();
for (abi, func) in func_list {
- match map.entry(abi) {
- Entry::Occupied(mut occ) => {
- occ.get_mut().push(func);
- }
- Entry::Vacant(vac) => {
- vac.insert(vec!(func));
- }
- }
+ map.entry(abi).or_insert(vec![]).push(func);
}
map
};
- if !Vec::is_empty(&vars) {
- defs.push(mk_extern(&mut ctx, &options.links, vars, abi::Abi::C));
+ 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, &options.links, funcs, abi));
+ 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"]));
@@ -296,44 +527,34 @@ pub fn gen_mod(
fn mk_extern(ctx: &mut GenCtx, links: &[(String, LinkType)],
foreign_items: Vec<ast::ForeignItem>,
- abi: abi::Abi) -> P<ast::Item> {
- let attrs = if links.is_empty() {
- Vec::new()
- } else {
- 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(
- to_intern_str(ctx, "name".to_owned()),
- respan(ctx.span, ast::LitKind::Str(
- to_intern_str(ctx, l.to_owned()),
- 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(
- to_intern_str(ctx, "kind".to_owned()),
- respan(ctx.span, ast::LitKind::Str(
- to_intern_str(ctx, (*k).to_owned()),
- ast::StrStyle::Cooked
- ))
- ))))
- };
- respan(ctx.span, ast::Attribute_ {
- id: mk_attr_id(),
- style: ast::AttrStyle::Outer,
- value: P(respan(ctx.span, ast::MetaItemKind::List(
- to_intern_str(ctx, "link".to_owned()),
- link_args)
- )),
- is_sugared_doc: false
- })
- }).collect()
- };
+ abi: Abi) -> P<ast::Item> {
+ 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::new();
items.extend(foreign_items.into_iter());
@@ -352,6 +573,28 @@ fn mk_extern(ctx: &mut GenCtx, links: &[(String, LinkType)],
})
}
+fn mk_impl(ctx: &mut GenCtx, ty: P<ast::Ty>,
+ items: Vec<ast::ImplItem>)
+ -> P<ast::Item> {
+ let ext = ast::ItemKind::Impl(
+ ast::Unsafety::Normal,
+ ast::ImplPolarity::Positive,
+ empty_generics(),
+ None,
+ ty,
+ items
+ );
+
+ P(ast::Item {
+ ident: ctx.ext_cx.ident_of(""),
+ attrs: vec!(),
+ id: ast::DUMMY_NODE_ID,
+ node: ext,
+ vis: ast::Visibility::Inherited,
+ span: ctx.span
+ })
+}
+
fn remove_redundant_decl(gs: Vec<Global>) -> Vec<Global> {
fn check_decl(a: &Global, ty: &Type) -> bool {
match *a {
@@ -383,7 +626,7 @@ fn remove_redundant_decl(gs: Vec<Global>) -> Vec<Global> {
).collect()
}
-fn tag_dup_decl(gs: Vec<Global>) -> Vec<Global> {
+fn tag_dup_decl(gs: &[Global]) -> Vec<Global> {
fn check(name1: &str, name2: &str) -> bool {
!name1.is_empty() && name1 == name2
}
@@ -393,75 +636,118 @@ fn tag_dup_decl(gs: Vec<Global>) -> Vec<Global> {
(&GType(ref ti1), &GType(ref ti2)) => {
let a = ti1.borrow();
let b = ti2.borrow();
- check(&a.name[..], &b.name[..])
+ check(&a.name, &b.name)
},
(&GComp(ref ci1), &GComp(ref ci2)) => {
let a = ci1.borrow();
let b = ci2.borrow();
- check(&a.name[..], &b.name[..])
+ check(&a.name, &b.name)
},
(&GCompDecl(ref ci1), &GCompDecl(ref ci2)) => {
let a = ci1.borrow();
let b = ci2.borrow();
- check(&a.name[..], &b.name[..])
+ check(&a.name, &b.name)
},
(&GEnum(ref ei1), &GEnum(ref ei2)) => {
let a = ei1.borrow();
let b = ei2.borrow();
- check(&a.name[..], &b.name[..])
+ check(&a.name, &b.name)
},
(&GEnumDecl(ref ei1), &GEnumDecl(ref ei2)) => {
let a = ei1.borrow();
let b = ei2.borrow();
- check(&a.name[..], &b.name[..])
+ 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.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.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 gs;
+ return vec![];
}
- let mut res: Vec<Global> = vec!();
- res.push(gs[0].clone());
+ let mut step: Vec<Global> = vec!();
+ step.push(gs[0].clone());
- for (i, gsi) in gs.iter().enumerate().skip(1) {
+ for (i, _gsi) in gs.iter().enumerate().skip(1) {
let mut dup = false;
- for gsj in gs.iter().take(i) {
- if check_dup(&gsi, &gsj) {
+ for j in 0..i {
+ if i == j {
+ continue;
+ }
+ if check_dup(&gs[i], &gs[j]) {
dup = true;
break;
}
}
if !dup {
- res.push(gsi.clone());
+ step.push(gs[i].clone());
+ }
+ }
+
+ let len = step.len();
+ let mut res: Vec<Global> = 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,
- rust_enums: bool,
- derive_debug: bool,
- name: String,
- ty: &Type)
- -> Vec<P<ast::Item>> {
- fn mk_item(ctx: &mut GenCtx, name: String, ty: &Type) -> P<ast::Item> {
+fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> P<ast::Item> {
+ fn mk_item(ctx: &mut GenCtx, name: &str, comment: &str, ty: &Type) -> P<ast::Item> {
let rust_name = rust_type_id(ctx, name);
- let rust_ty = cty_to_rs(ctx, ty);
+ let rust_ty = if cty_is_translatable(ty) {
+ cty_to_rs(ctx, ty, true, true)
+ } else {
+ cty_to_rs(ctx, &TVoid, true, true)
+ };
let base = ast::ItemKind::Ty(
P(ast::Ty {
id: ast::DUMMY_NODE_ID,
@@ -472,8 +758,8 @@ fn ctypedef_to_rs(
);
P(ast::Item {
- ident: ctx.ext_cx.ident_of(&rust_name[..]),
- attrs: Vec::new(),
+ ident: ctx.ext_cx.ident_of(&rust_name),
+ attrs: mk_doc_attr(ctx, comment),
id: ast::DUMMY_NODE_ID,
node: base,
vis: ast::Visibility::Public,
@@ -481,43 +767,32 @@ fn ctypedef_to_rs(
})
}
- match *ty {
+ match ty.ty {
TComp(ref ci) => {
- let is_empty = ci.borrow().name.is_empty();
- if is_empty {
- ci.borrow_mut().name = name.clone();
- let c = ci.borrow().clone();
- comp_to_rs(ctx, c.kind, name, derive_debug, c.layout, c.members)
- } else {
- vec!(mk_item(ctx, name, ty))
- }
+ assert!(!ci.borrow().name.is_empty());
+ mk_item(ctx, &ty.name, &ty.comment, &ty.ty)
},
TEnum(ref ei) => {
- let is_empty = ei.borrow().name.is_empty();
- if is_empty {
- ei.borrow_mut().name = name.clone();
- let e = ei.borrow();
- cenum_to_rs(ctx, rust_enums, derive_debug, name, e.kind, e.layout, &e.items)
- } else {
- vec!(mk_item(ctx, name, ty))
- }
+ assert!(!ei.borrow().name.is_empty());
+ mk_item(ctx, &ty.name, &ty.comment, &ty.ty)
},
- _ => vec!(mk_item(ctx, name, ty))
+ _ => mk_item(ctx, &ty.name, &ty.comment, &ty.ty),
}
}
-fn comp_to_rs(ctx: &mut GenCtx, kind: CompKind, name: String,
- derive_debug: bool,
- layout: Layout, members: Vec<CompMember>) -> Vec<P<ast::Item>> {
- match kind {
- CompKind::Struct => cstruct_to_rs(ctx, name, derive_debug, layout, members),
- CompKind::Union => cunion_to_rs(ctx, name, derive_debug, layout, members),
+fn comp_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo)
+ -> Vec<P<ast::Item>> {
+ match ci.kind {
+ CompKind::Struct => cstruct_to_rs(ctx, name, ci),
+ CompKind::Union => cunion_to_rs(ctx, name, ci.layout, ci.members),
}
}
-fn cstruct_to_rs(ctx: &mut GenCtx, name: String,
- derive_debug: bool,
- layout: Layout, members: Vec<CompMember>) -> Vec<P<ast::Item>> {
+fn cstruct_to_rs(ctx: &mut GenCtx, name: &str, ci: CompInfo) -> Vec<P<ast::Item>> {
+ 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
@@ -527,40 +802,198 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String,
let mut unnamed: u32 = 0;
let mut bitfields: u32 = 0;
- // Debug is only defined on little arrays
- let mut can_derive_debug = derive_debug;
+ if ci.hide ||
+ template_args.iter().any(|f| f == &TVoid) {
+ return vec!();
+ }
- for m in &members {
- let (opt_rc_c, opt_f) = match *m {
- CompMember::Field(ref f) => { (None, Some(f)) }
- CompMember::Comp(ref rc_c) => { (Some(rc_c), None) }
- CompMember::CompField(ref rc_c, ref f) => { (Some(rc_c), Some(f)) }
+ 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 = if !members.is_empty() {
+ if let CompMember::Field(ref fi) = members[0] {
+ match fi.ty {
+ TComp(ref ci2) => {
+ let ci2 = ci2.borrow();
+ if ci2.has_vtable {
+ Some(format!("_vftable_{}", ci2.name))
+ } else {
+ None
+ }
+ },
+ _ => None
+ }
+ } else {
+ None
+ }
+ } else {
+ None
};
+ if let Some(ref base) = base_vftable {
+ let field = ast::StructField_ {
+ kind: ast::NamedField(ctx.ext_cx.ident_of("_base"), ast::Visibility::Public),
+ id: ast::DUMMY_NODE_ID,
+ ty: P(mk_ty(ctx, false, &[base.clone()])),
+ attrs: vec!(),
+ };
+ vffields.push(respan(ctx.span, field));
+ }
+
+ 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 field = ast::StructField_ {
+ kind: ast::NamedField(ctx.ext_cx.ident_of(&vm.name), ast::Visibility::Public),
+ id: ast::DUMMY_NODE_ID,
+ ty: P(ty),
+ attrs: vec!(),
+ };
+ vffields.push(respan(ctx.span, field));
+ }
+
+ let vf_name = format!("_vftable_{}", name);
+ let item = P(ast::Item {
+ ident: ctx.ext_cx.ident_of(&vf_name),
+ attrs: vec!(mk_repr_attr(ctx, layout)),
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Struct(
+ ast::VariantData::Struct(vffields, ast::DUMMY_NODE_ID),
+ empty_generics()
+ ),
+ vis: ast::Visibility::Public,
+ span: ctx.span,
+ });
+ extra.push(item);
+
+ if base_vftable.is_none() {
+ let vf_type = mk_ty(ctx, false, &[vf_name]);
+ fields.push(respan(ctx.span, ast::StructField_ {
+ kind: ast::NamedField(ctx.ext_cx.ident_of("_vftable"), ast::Visibility::Public),
+ id: ast::DUMMY_NODE_ID,
+ ty: P(mk_ptrty(ctx, &vf_type, true)),
+ attrs: Vec::new()
+ }));
+ }
+ }
+
+ if members.is_empty() {
+ let mut phantom_count = 0;
+ for arg in template_args {
+ let f_name = format!("_phantom{}", phantom_count);
+ phantom_count += 1;
+ let inner_type = P(cty_to_rs(ctx, &arg, true, false));
+ fields.push(respan(ctx.span, ast::StructField_ {
+ kind: ast::NamedField(
+ ctx.ext_cx.ident_of(&f_name),
+ ast::Visibility::Public,
+ ),
+ id: ast::DUMMY_NODE_ID,
+ ty: quote_ty!(&ctx.ext_cx, ::std::marker::PhantomData<$inner_type>),
+ attrs: vec!(),
+ }));
+ }
+ }
+
+ let mut anon_enum_count = 0;
+ let mut setters = vec!();
+ let mut has_destructor = ci.has_destructor;
+ for m in members.iter() {
+ if let &CompMember::Enum(ref ei) = m {
+ let e = ei.borrow().clone();
+ let ename = if e.name.is_empty() {
+ let ename = format!("{}_enum{}", name, anon_enum_count);
+ anon_enum_count += 1;
+ ename
+ } else {
+ e.name.clone()
+ };
+ extra.extend(cenum_to_rs(ctx, ename, e.kind, e.comment, &e.items, e.layout).into_iter());
+ continue;
+ }
+
+ fn comp_fields(m: &CompMember)
+ -> (Option<Rc<RefCell<CompInfo>>>, Option<FieldInfo>) {
+ match m {
+ &CompMember::Field(ref f) => { (None, Some(f.clone())) }
+ &CompMember::Comp(ref rc_c) => {
+ let c = rc_c.borrow();
+ if c.members.len() == 1 {
+ comp_fields(&c.members[0])
+ } else {
+ (Some(rc_c.clone()), None)
+ }
+ }
+ &CompMember::CompField(ref rc_c, ref f) => { (Some(rc_c.clone()), Some(f.clone())) }
+ _ => unreachable!()
+ }
+ }
+
+ let (opt_rc_c, opt_f) = comp_fields(m);
+
if let Some(f) = opt_f {
+ if cty_has_destructor(&f.ty) {
+ has_destructor = true;
+ }
+ if !cty_is_translatable(&f.ty) {
+ continue;
+ }
let f_name = match f.bitfields {
Some(_) => {
bitfields += 1;
- format!("_bindgen_bitfield_{}_", bitfields)
+ format!("_bitfield_{}", bitfields)
}
- None => rust_type_id(ctx, f.name.clone())
+ None => rust_type_id(ctx, &f.name)
};
- if !f.ty.can_derive_debug() {
- can_derive_debug = false;
+ let mut offset: u32 = 0;
+ if let Some(ref bitfields) = f.bitfields {
+ for &(ref bf_name, bf_size) in bitfields.iter() {
+ setters.push(gen_bitfield_method(ctx, &f_name, bf_name, &f.ty, offset as usize, bf_size));
+ offset += bf_size;
+ }
+ setters.push(gen_fullbitfield_method(ctx, &f_name, &f.ty, bitfields))
}
- let f_ty = P(cty_to_rs(ctx, &f.ty));
+ let mut bypass = false;
+ let f_ty = if let Some(ref rc_c) = opt_rc_c {
+ if rc_c.borrow().members.len() == 1 {
+ if let CompMember::Field(ref inner_f) = rc_c.borrow().members[0] {
+ bypass = true;
+ inner_f.ty.clone()
+ } else {
+ f.ty.clone()
+ }
+ } else {
+ f.ty.clone()
+ }
+ } else {
+ f.ty.clone()
+ };
+
+ // If the member is not a template argument, it needs the full path.
+ let needs_full_path = !template_args.iter().any(|arg| *arg == f_ty);
+ let f_ty = P(cty_to_rs(ctx, &f_ty, f.bitfields.is_none(), needs_full_path));
fields.push(respan(ctx.span, ast::StructField_ {
kind: ast::NamedField(
- ctx.ext_cx.ident_of(&f_name[..]),
+ ctx.ext_cx.ident_of(&f_name),
ast::Visibility::Public,
),
id: ast::DUMMY_NODE_ID,
ty: f_ty,
- attrs: Vec::new()
+ attrs: mk_doc_attr(ctx, &f.comment)
}));
+ if bypass {
+ continue;
+ }
}
if let Some(rc_c) = opt_rc_c {
@@ -568,47 +1001,92 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String,
if c.name.is_empty() {
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, derive_debug).into_iter());
+ 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 {
- extra.extend(comp_to_rs(ctx, c.kind, comp_name(c.kind, &c.name),
- derive_debug,
- c.layout, c.members.clone()).into_iter());
+ let name = comp_name(&ctx, c.kind, &c.name);
+ extra.extend(comp_to_rs(ctx, &name, c.clone()).into_iter());
}
}
}
+ if !setters.is_empty() {
+ extra.push(P(ast::Item {
+ ident: ctx.ext_cx.ident_of(""),
+ attrs: vec!(),
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Impl(
+ ast::Unsafety::Normal,
+ ast::ImplPolarity::Positive,
+ empty_generics(),
+ None,
+ id_ty.clone(),
+ setters
+ ),
+ vis: ast::Visibility::Inherited,
+ span: ctx.span
+ }));
+ }
+
+ 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 = 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: OwnedSlice::empty(),
+ default: None,
+ span: ctx.span
+ }
+ }).collect();
let def = ast::ItemKind::Struct(
- ast::VariantData::Struct(fields, ast::DUMMY_NODE_ID),
- empty_generics()
+ variant_data,
+ ast::Generics {
+ lifetimes: vec!(),
+ ty_params: OwnedSlice::from_vec(ty_params),
+ where_clause: ast::WhereClause {
+ id: ast::DUMMY_NODE_ID,
+ predicates: vec!()
+ }
+ }
);
- let id = rust_type_id(ctx, name.clone());
- let mut attrs = vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx, false));
- if can_derive_debug {
- attrs.push(mk_deriving_debug_attr(ctx));
+ let mut attrs = mk_doc_attr(ctx, &ci.comment);
+ attrs.push(mk_repr_attr(ctx, layout));
+ if !has_destructor {
+ attrs.push(mk_deriving_copy_attr(ctx));
}
- let struct_def = P(ast::Item { ident: ctx.ext_cx.ident_of(&id[..]),
+ 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!(struct_def);
+ let mut items = vec!(P(struct_def));
if !methods.is_empty() {
let impl_ = ast::ItemKind::Impl(
ast::Unsafety::Normal,
ast::ImplPolarity::Positive,
empty_generics(),
None,
- P(mk_ty(ctx, false, vec!(id))),
+ id_ty.clone(),
methods
);
items.push(
P(ast::Item {
- ident: ctx.ext_cx.ident_of(&name[..]),
+ ident: ctx.ext_cx.ident_of(&name),
attrs: vec!(),
id: ast::DUMMY_NODE_ID,
node: impl_,
@@ -616,13 +1094,39 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String,
span: ctx.span}));
}
- items.push(mk_clone_impl(ctx, &name[..]));
- items.push(mk_default_impl(ctx, &name[..]));
items.extend(extra.into_iter());
+
+ let mut mangledlist = vec!();
+ let mut unmangledlist = vec!();
+ let mut unmangle_count: HashMap<String, isize> = 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 {
+ ast::SelfKind::Static
+ } else if v.is_const {
+ ast::SelfKind::Region(None, ast::Mutability::Immutable, ctx.ext_cx.ident_of("self"))
+ } else {
+ ast::SelfKind::Region(None, ast::Mutability::Mutable, ctx.ext_cx.ident_of("self"))
+ };
+ 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.len() > 0 {
+ items.push(mk_extern(ctx, &vec!(), mangledlist, Abi::C));
+ items.push(mk_impl(ctx, id_ty, unmangledlist));
+ }
items
}
-fn opaque_to_rs(ctx: &mut GenCtx, name: String) -> P<ast::Item> {
+fn opaque_to_rs(ctx: &mut GenCtx, name: &str) -> P<ast::Item> {
let def = ast::ItemKind::Enum(
ast::EnumDef {
variants: vec!()
@@ -632,7 +1136,7 @@ fn opaque_to_rs(ctx: &mut GenCtx, name: String) -> P<ast::Item> {
let id = rust_type_id(ctx, name);
P(ast::Item {
- ident: ctx.ext_cx.ident_of(&id[..]),
+ ident: ctx.ext_cx.ident_of(&id),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
node: def,
@@ -641,11 +1145,11 @@ fn opaque_to_rs(ctx: &mut GenCtx, name: String) -> P<ast::Item> {
})
}
-fn cunion_to_rs(ctx: &mut GenCtx, name: String, derive_debug: bool, layout: Layout, members: Vec<CompMember>) -> Vec<P<ast::Item>> {
+fn cunion_to_rs(ctx: &mut GenCtx, name: &str, layout: Layout, members: Vec<CompMember>) -> Vec<P<ast::Item>> {
fn mk_item(ctx: &mut GenCtx, name: String, item: ast::ItemKind, vis:
ast::Visibility, attrs: Vec<ast::Attribute>) -> P<ast::Item> {
P(ast::Item {
- ident: ctx.ext_cx.ident_of(&name[..]),
+ ident: ctx.ext_cx.ident_of(&name),
attrs: attrs,
id: ast::DUMMY_NODE_ID,
node: item,
@@ -654,8 +1158,9 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, derive_debug: bool, layout: Layo
})
}
- let ci = Rc::new(RefCell::new(CompInfo::new(name.clone(), CompKind::Union, members.clone(), layout)));
- let union = TNamed(Rc::new(RefCell::new(TypeInfo::new(name.clone(), TComp(ci)))));
+ // XXX what module id is correct?
+ let ci = Rc::new(RefCell::new(CompInfo::new(name.to_owned(), ROOT_MODULE_ID, name.to_owned(), "".to_owned(), CompKind::Union, members.clone(), layout)));
+ let union = TNamed(Rc::new(RefCell::new(TypeInfo::new(name.to_owned(), ROOT_MODULE_ID, TComp(ci), layout))));
// Nested composites may need to emit declarations and implementations as
// they are encountered. The declarations end up in 'extra' and are emitted
@@ -666,27 +1171,22 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, derive_debug: bool, layout: Layo
let data_field = mk_blob_field(ctx, data_field_name, layout);
let def = ast::ItemKind::Struct(
- ast::VariantData::Struct(
- vec!(data_field),
- ast::DUMMY_NODE_ID),
+ ast::VariantData::Struct(vec![data_field], ast::DUMMY_NODE_ID),
empty_generics()
);
- let union_id = rust_type_id(ctx, name.clone());
- let union_attrs = {
- let mut attrs = vec!(mk_repr_attr(ctx, layout), mk_deriving_copy_attr(ctx, false));
- if derive_debug {
- let can_derive_debug = members.iter()
- .all(|member| match *member {
- CompMember::Field(ref f) |
- CompMember::CompField(_, ref f) => f.ty.can_derive_debug(),
- _ => true
- });
- if can_derive_debug {
- attrs.push(mk_deriving_debug_attr(ctx))
- }
- }
- attrs
- };
+ let union_id = rust_type_id(ctx, name);
+ let mut union_attrs = vec!(mk_repr_attr(ctx, layout));
+ let can_derive_debug = members.iter()
+ .all(|member| match *member {
+ CompMember::Field(ref f) |
+ CompMember::CompField(_, ref f) => f.ty.can_derive_debug(),
+ _ => true
+ });
+ union_attrs.push(if can_derive_debug {
+ mk_deriving_copy_and_maybe_debug_attr(ctx)
+ } else {
+ mk_deriving_copy_attr(ctx)
+ });
let union_def = mk_item(ctx, union_id, def, ast::Visibility::Public, union_attrs);
@@ -695,8 +1195,8 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, derive_debug: bool, layout: Layo
ast::ImplPolarity::Positive,
empty_generics(),
None,
- P(cty_to_rs(ctx, &union)),
- gen_comp_methods(ctx, data_field_name, 0, CompKind::Union, &members, &mut extra, derive_debug),
+ P(cty_to_rs(ctx, &union, true, true)),
+ gen_comp_methods(ctx, data_field_name, 0, CompKind::Union, &members, &mut extra),
);
let mut items = vec!(
@@ -704,8 +1204,6 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, derive_debug: bool, layout: Layo
mk_item(ctx, "".to_owned(), union_impl, ast::Visibility::Inherited, Vec::new())
);
- items.push(mk_clone_impl(ctx, &name[..]));
- items.push(mk_default_impl(ctx, &name[..]));
items.extend(extra.into_iter());
items
}
@@ -726,7 +1224,7 @@ fn const_to_rs(ctx: &mut GenCtx, name: String, val: i64, val_ty: ast::Ty) -> P<a
value
);
- let id = first(rust_id(ctx, name.clone()));
+ let id = first(rust_id(ctx, &name));
P(ast::Item {
ident: ctx.ext_cx.ident_of(&id[..]),
attrs: Vec::new(),
@@ -737,6 +1235,16 @@ fn const_to_rs(ctx: &mut GenCtx, name: String, val: i64, val_ty: ast::Ty) -> P<a
})
}
+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",
@@ -751,81 +1259,60 @@ fn enum_size_to_rust_type_name(signed: bool, size: usize) -> &'static str {
}
}
-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 cenum_value_to_int_lit(
- ctx: &mut GenCtx,
- enum_is_signed: bool,
- size: usize,
- value: i64)
- -> P<ast::Expr> {
+fn cenum_value_to_int_lit(ctx: &mut GenCtx,
+ enum_is_signed: bool,
+ size: usize,
+ value: i64) -> P<ast::Expr> {
if enum_is_signed {
- let int_lit =
- ast::LitKind::Int(value.abs() as u64, ast::LitIntType::Unsuffixed);
+ let int_lit = ast::LitKind::Int(value.abs() as u64, ast::LitIntType::Unsuffixed);
let expr = ctx.ext_cx.expr_lit(ctx.span, int_lit);
+
if value < 0 {
- ctx.ext_cx.expr(
- ctx.span, ast::ExprKind::Unary(ast::UnOp::Neg, expr))
+ 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);
+ 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,
- rust_enums: bool,
- derive_debug: bool,
- name: String,
- kind: IKind,
- layout: Layout,
- enum_items: &[EnumItem])
- -> Vec<P<ast::Item>> {
+fn cenum_to_rs(ctx: &mut GenCtx,
+ name: String,
+ kind: IKind,
+ comment: String,
+ enum_items: &[EnumItem],
+ layout: Layout) -> Vec<P<ast::Item>> {
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);
+
+ // Rust is not happy with univariant enums
+ // if items.len() < 2 {
+ // return vec!();
+ // }
+ //
let mut items = vec![];
- if !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))));
+ 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);
- items.push(ctx.ext_cx.item_const(
- ctx.span,
- ctx.ext_cx.ident_of(&item.name),
- enum_ty.clone(),
- value));
+ let value = cenum_value_to_int_lit(ctx, enum_is_signed, layout.size, item.val);
+ items.push(ctx.ext_cx.item_const(ctx.span, ctx.ext_cx.ident_of(&item.name), enum_ty.clone(), value));
}
return items;
}
let mut variants = vec![];
let mut found_values = HashMap::new();
-
for item in enum_items {
let name = ctx.ext_cx.ident_of(&item.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]));
@@ -841,7 +1328,6 @@ fn cenum_to_rs(
}
found_values.insert(item.val, name);
-
let value = cenum_value_to_int_lit(
ctx, enum_is_signed, layout.size, item.val);
@@ -857,20 +1343,16 @@ fn cenum_to_rs(
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 repr_attr = respan(ctx.span, ast::Attribute_ {
+
+ 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,
- });
+ }));
- let attrs = {
- let mut v = vec![mk_deriving_copy_attr(ctx, true), repr_attr];
- if derive_debug {
- v.push(mk_deriving_debug_attr(ctx));
- }
- v
- };
+ attrs.push(mk_deriving_copy_and_maybe_debug_attr(ctx));
items.push(P(ast::Item {
ident: enum_name,
@@ -890,15 +1372,14 @@ fn cenum_to_rs(
/// 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<P<ast::Item>>,
- derive_debug: bool) -> Vec<ast::ImplItem> {
+ extra: &mut Vec<P<ast::Item>>) -> Vec<ast::ImplItem> {
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, _) = rust_id(ctx, f.name.clone());
- let ret_ty = P(cty_to_rs(ctx, &TPtr(Box::new(f.ty.clone()), false, Layout::zero())));
+ 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 = {
@@ -912,7 +1393,7 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize,
", 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_owned(), impl_str).parse_item().unwrap().unwrap()
+ ctx.ext_cx.cfg(), "".to_string(), impl_str).parse_item().unwrap().unwrap()
};
method.and_then(|i| {
@@ -936,18 +1417,18 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize,
CompMember::Comp(ref rc_c) => {
let c = &rc_c.borrow();
methods.extend(gen_comp_methods(ctx, data_field, offset, c.kind,
- &c.members, extra, derive_debug).into_iter());
+ &c.members, extra).into_iter());
c.layout.size
}
CompMember::CompField(ref rc_c, ref f) => {
methods.extend(mk_field_method(ctx, f, offset).into_iter());
let c = rc_c.borrow();
- extra.extend(comp_to_rs(ctx, c.kind, comp_name(c.kind, &c.name),
- derive_debug,
- c.layout, c.members.clone()).into_iter());
+ let name = comp_name(&ctx, c.kind, &c.name);
+ extra.extend(comp_to_rs(ctx, &name, c.clone()).into_iter());
f.ty.size()
}
+ CompMember::Enum(_) => 0
};
match kind {
CompKind::Struct => { offset += advance_by; }
@@ -957,28 +1438,121 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize,
methods
}
-// Implements std::default::Default using std::mem::zeroed.
-fn mk_default_impl(ctx: &GenCtx, ty_name: &str) -> P<ast::Item> {
- let impl_str = format!(r"
- impl ::std::default::Default for {} {{
- fn default() -> Self {{ unsafe {{ ::std::mem::zeroed() }} }}
- }}
- ", ty_name);
+fn type_for_bitfield_width(ctx: &mut GenCtx, width: u32) -> ast::Ty {
+ let input_type = if width > 16 {
+ "u32"
+ } else if width > 8 {
+ "u16"
+ } else if width > 1 {
+ "u8"
+ } else {
+ "bool"
+ };
+ mk_ty(ctx, false, &[input_type.to_owned()])
+}
- parse::new_parser_from_source_str(ctx.ext_cx.parse_sess(),
- ctx.ext_cx.cfg(), "".to_owned(), impl_str).parse_item().unwrap().unwrap()
+fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
+ field_name: &String, field_type: &Type,
+ offset: usize, width: u32) -> ast::ImplItem {
+ let input_type = type_for_bitfield_width(ctx, width);
+ let field_type = cty_to_rs(ctx, &field_type, false, true);
+ let setter_name = ctx.ext_cx.ident_of(&format!("set_{}", field_name));
+ let bindgen_ident = ctx.ext_cx.ident_of(&*bindgen_name);
+
+ let node = &quote_item!(&ctx.ext_cx,
+ impl X {
+ pub fn $setter_name(&mut self, val: $input_type) {
+ self.$bindgen_ident &= !(((1 << $width) - 1) << $offset);
+ self.$bindgen_ident |= (val as $field_type) << $offset;
+ }
+ }
+ ).unwrap().node;
+ match node {
+ &ast::ItemKind::Impl(_, _, _, _, _, ref items) => items[0].clone(),
+ _ => unreachable!()
+ }
}
-// Implements std::clone::Clone using dereferencing
-fn mk_clone_impl(ctx: &GenCtx, ty_name: &str) -> P<ast::Item> {
- let impl_str = format!(r"
- impl ::std::clone::Clone for {} {{
- fn clone(&self) -> Self {{ *self }}
- }}
- ", ty_name);
+fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String,
+ field_type: &Type, bitfields: &[(String, u32)]) -> ast::ImplItem {
+ let field_type = cty_to_rs(ctx, field_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)),
+ 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 stmts = Vec::with_capacity(bitfields.len() + 1);
- parse::new_parser_from_source_str(ctx.ext_cx.parse_sess(),
- ctx.ext_cx.cfg(), "".to_owned(), impl_str).parse_item().unwrap().unwrap()
+ 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: stmts,
+ expr: Some(exprs),
+ id: ast::DUMMY_NODE_ID,
+ rules: ast::BlockCheckMode::Default,
+ span: ctx.span
+ };
+
+ let node = ast::ImplItemKind::Method(
+ ast::MethodSig {
+ unsafety: ast::Unsafety::Normal,
+ abi: Abi::Rust,
+ decl: P(fndecl),
+ generics: empty_generics(),
+ explicit_self: respan(ctx.span, ast::SelfKind::Static),
+ constness: ast::Constness::Const,
+ }, P(block)
+ );
+
+ ast::ImplItem {
+ id: ast::DUMMY_NODE_ID,
+ ident: ctx.ext_cx.ident_of(&format!("new{}", bindgen_name)),
+ vis: ast::Visibility::Public,
+ attrs: vec!(),
+ node: node,
+ span: ctx.span,
+ }
}
fn mk_blob_field(ctx: &GenCtx, name: &str, layout: Layout) -> Spanned<ast::StructField_> {
@@ -989,8 +1563,13 @@ fn mk_blob_field(ctx: &GenCtx, name: &str, layout: Layout) -> Spanned<ast::Struc
1 | _ => "u8",
};
let data_len = if ty_name == "u8" { layout.size } else { layout.size / layout.align };
- let base_ty = mk_ty(ctx, false, vec!(ty_name.to_owned()));
- let data_ty = P(mk_arrty(ctx, &base_ty, data_len));
+
+ 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))
+ };
respan(ctx.span, ast::StructField_ {
kind: ast::NamedField(
ctx.ext_cx.ident_of(name),
@@ -1003,12 +1582,9 @@ fn mk_blob_field(ctx: &GenCtx, name: &str, layout: Layout) -> Spanned<ast::Struc
}
fn mk_link_name_attr(ctx: &mut GenCtx, name: String) -> ast::Attribute {
- let lit = respan(ctx.span, ast::LitKind::Str(
- to_intern_str(ctx, name),
- ast::StrStyle::Cooked
- ));
+ 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(
- to_intern_str(ctx, "link_name".to_owned()), lit
+ InternedString::new("link_name"), lit
)));
let attr = ast::Attribute_ {
id: mk_attr_id(),
@@ -1020,12 +1596,12 @@ fn mk_link_name_attr(ctx: &mut GenCtx, name: String) -> ast::Attribute {
}
fn mk_repr_attr(ctx: &mut GenCtx, layout: Layout) -> ast::Attribute {
- let mut values = vec!(P(respan(ctx.span, ast::MetaItemKind::Word(to_intern_str(ctx, "C".to_owned())))));
+ 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(to_intern_str(ctx, "packed".to_owned())))));
+ values.push(P(respan(ctx.span, ast::MetaItemKind::Word(InternedString::new("packed")))));
}
let attr_val = P(respan(ctx.span, ast::MetaItemKind::List(
- to_intern_str(ctx, "repr".to_owned()),
+ InternedString::new("repr"),
values
)));
@@ -1037,14 +1613,25 @@ fn mk_repr_attr(ctx: &mut GenCtx, layout: Layout) -> ast::Attribute {
})
}
-fn mk_deriving_copy_attr(ctx: &mut GenCtx, clone: bool) -> ast::Attribute {
- let mut words = vec!();
- if clone {
- words.push(ctx.ext_cx.meta_word(ctx.span, InternedString::new("Clone")));
+fn mk_deriving_copy_attr(ctx: &mut GenCtx) -> ast::Attribute {
+ mk_deriving_attr(ctx, &["Copy", "Clone"])
+}
+
+fn mk_deriving_copy_and_maybe_debug_attr(ctx: &mut GenCtx) -> ast::Attribute {
+ if ctx.options.derive_debug {
+ mk_deriving_attr(ctx, &["Copy", "Clone", "Debug"])
+ } else {
+ mk_deriving_copy_attr(ctx)
}
- words.push(ctx.ext_cx.meta_word(ctx.span, InternedString::new("Copy")));
+}
- let attr_val = ctx.ext_cx.meta_list(ctx.span, InternedString::new("derive"), words);
+fn mk_deriving_attr(ctx: &mut 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(),
@@ -1054,33 +1641,40 @@ fn mk_deriving_copy_attr(ctx: &mut GenCtx, clone: bool) -> ast::Attribute {
})
}
-fn mk_deriving_debug_attr(ctx: &mut GenCtx) -> ast::Attribute {
- let words = vec!(ctx.ext_cx.meta_word(ctx.span, InternedString::new("Debug")));
+fn mk_doc_attr(ctx: &mut GenCtx, doc: &str) -> Vec<ast::Attribute> {
+ if doc.is_empty() {
+ return vec!();
+ }
- let attr_val = ctx.ext_cx.meta_list(ctx.span, InternedString::new("derive"), words);
+ 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))
+ )));
- respan(ctx.span, ast::Attribute_ {
+ vec!(respan(ctx.span, ast::Attribute_ {
id: mk_attr_id(),
style: ast::AttrStyle::Outer,
value: attr_val,
- is_sugared_doc: false
- })
+ is_sugared_doc: true
+ }))
}
fn cvar_to_rs(ctx: &mut GenCtx, name: String,
- ty: &Type,
- is_const: bool) -> ast::ForeignItem {
- let (rust_name, was_mangled) = rust_id(ctx, name.clone());
+ mangled: String, ty: &Type,
+ is_const: bool) -> ast::ForeignItem {
+ let (rust_name, was_mangled) = rust_id(ctx, &name);
let mut attrs = Vec::new();
- if was_mangled {
+ 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));
+ let val_ty = P(cty_to_rs(ctx, ty, true, true));
ast::ForeignItem {
- ident: ctx.ext_cx.ident_of(&rust_name[..]),
+ ident: ctx.ext_cx.ident_of(&rust_name),
attrs: attrs,
node: ast::ForeignItemKind::Static(val_ty, !is_const),
id: ast::DUMMY_NODE_ID,
@@ -1096,7 +1690,10 @@ fn cfuncty_to_rs(ctx: &mut GenCtx,
let ret = match *rty {
TVoid => ast::FunctionRetTy::Default(ctx.span),
- _ => ast::FunctionRetTy::Ty(P(cty_to_rs(ctx, rty)))
+ // 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;
@@ -1107,7 +1704,7 @@ fn cfuncty_to_rs(ctx: &mut GenCtx,
unnamed += 1;
format!("arg{}", unnamed)
} else {
- first(rust_id(ctx, n.clone()))
+ first(rust_id(ctx, &n))
};
// From the C90 standard (http://c0x.coding-guidelines.com/6.7.5.3.html)
@@ -1116,8 +1713,8 @@ fn cfuncty_to_rs(ctx: &mut GenCtx,
// (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, l)),
- _ => cty_to_rs(ctx, 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 {
@@ -1126,7 +1723,7 @@ fn cfuncty_to_rs(ctx: &mut GenCtx,
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[..])),
+ respan(ctx.span, ctx.ext_cx.ident_of(&arg_name)),
None
),
span: ctx.span
@@ -1143,33 +1740,40 @@ fn cfuncty_to_rs(ctx: &mut GenCtx,
}
}
-fn cfunc_to_rs(ctx: &mut GenCtx, name: String, rty: &Type,
+fn cfunc_to_rs(ctx: &mut GenCtx,
+ name: String,
+ mangled: String,
+ comment: String,
+ rty: &Type,
aty: &[(String, Type)],
- var: bool) -> ast::ForeignItem {
+ 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)),
empty_generics()
);
- let (rust_name, was_mangled) = rust_id(ctx, name.clone());
+ let (rust_name, was_mangled) = rust_id(ctx, &name);
- let mut attrs = Vec::new();
- if was_mangled {
+ 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[..]),
+ ident: ctx.ext_cx.ident_of(&rust_name),
attrs: attrs,
node: decl,
id: ast::DUMMY_NODE_ID,
span: ctx.span,
- vis: ast::Visibility::Public,
+ vis: vis,
}
}
-fn cty_to_rs(ctx: &mut GenCtx, ty: &Type) -> ast::Ty {
+fn cty_to_rs(ctx: &mut 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();
@@ -1178,79 +1782,147 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type) -> ast::Ty {
};
match *ty {
- TVoid => mk_ty(ctx, true, raw("c_void")),
+ TVoid => mk_ty(ctx, true, &raw("c_void")),
TInt(i, ref layout) => match i {
IBool => {
let ty_name = match layout.size {
- 8 => "u64",
- 4 => "u32",
+ 1 if allow_bool => "bool",
2 => "u16",
- 1 | _ => "u8",
+ 4 => "u32",
+ 8 => "u64",
+ _ => "u8",
};
- mk_ty(ctx, false, vec!(ty_name.to_owned()))
+ 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"))
+ 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, true, raw("c_float")),
- FDouble => mk_ty(ctx, true, raw("c_double"))
+ FFloat => mk_ty(ctx, false, &["f32".to_owned()]),
+ FDouble => mk_ty(ctx, false, &["f64".to_owned()])
},
- TPtr(ref t, is_const, _) => {
- let id = cty_to_rs(ctx, &**t);
+ 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);
+ 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);
- let unsafety = if sig.is_safe { ast::Unsafety::Normal } else { ast::Unsafety::Unsafe };
- mk_fnty(ctx, &decl, unsafety, sig.abi)
+ mk_fnty(ctx, &decl, sig.abi)
},
TFuncProto(ref sig) => {
let decl = cfuncty_to_rs(ctx, &*sig.ret_ty, &sig.args[..], sig.is_variadic);
- let unsafety = if sig.is_safe { ast::Unsafety::Normal } else { ast::Unsafety::Unsafe };
- mk_fn_proto_ty(ctx, &decl, unsafety, sig.abi)
+ mk_fn_proto_ty(ctx, &decl, sig.abi)
},
TNamed(ref ti) => {
- let id = rust_type_id(ctx, ti.borrow().name.clone());
- mk_ty(ctx, false, vec!(id))
+ 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 mut c = ci.borrow_mut();
- c.name = unnamed_name(ctx, c.name.clone());
- mk_ty(ctx, false, vec!(comp_name(c.kind, &c.name)))
+ 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 mut e = ei.borrow_mut();
- e.name = unnamed_name(ctx, e.name.clone());
- mk_ty(ctx, false, vec!(enum_name(&e.name)))
+ 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)
+ },
+ _ => true,
+ }
+}
+
+fn cty_has_destructor(ty: &Type) -> bool {
+ match ty {
+ &TArray(ref t, _, _) => {
+ cty_has_destructor(&**t)
}
+ &TComp(ref ci) => {
+ let c = ci.borrow();
+ if c.has_destructor || c.members.iter().any(|f| match f {
+ &CompMember::Field(ref f) |
+ &CompMember::CompField(_, ref f) =>
+ cty_has_destructor(&f.ty),
+ _ => false,
+ }) {
+ return true;
+ }
+ c.ref_template.is_some()
+ },
+ &TNamed(ref ti) => {
+ cty_has_destructor(&ti.borrow().ty)
+ },
+ _ => false,
}
}
-fn mk_ty(ctx: &GenCtx, global: bool, segments: Vec<String>) -> ast::Ty {
+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<P<ast::Ty>>) -> ast::Ty {
+ let segment_count = segments.len();
let ty = ast::TyKind::Path(
None,
ast::Path {
span: ctx.span,
global: global,
- segments: segments.iter().map(|s| {
+ segments: segments.iter().enumerate().map(|(i, s)| {
ast::PathSegment {
- identifier: ctx.ext_cx.ident_of(&s[..]),
+ identifier: ctx.ext_cx.ident_of(s),
parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData {
- lifetimes: Vec::new(),
- types: OwnedSlice::empty(),
+ lifetimes: vec!(),
+ types: OwnedSlice::from_vec(if i == segment_count - 1 { args.clone() } else { vec![] }),
bindings: OwnedSlice::empty(),
}),
}
@@ -1278,6 +1950,23 @@ fn mk_ptrty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty {
}
}
+#[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)));
@@ -1300,10 +1989,9 @@ fn mk_arrty(ctx: &GenCtx, base: &ast::Ty, n: usize) -> ast::Ty {
fn mk_fn_proto_ty(ctx: &mut GenCtx,
decl: &ast::FnDecl,
- unsafety: ast::Unsafety,
- abi: abi::Abi) -> ast::Ty {
+ abi: Abi) -> ast::Ty {
let fnty = ast::TyKind::BareFn(P(ast::BareFnTy {
- unsafety: unsafety,
+ unsafety: ast::Unsafety::Unsafe,
abi: abi,
lifetimes: Vec::new(),
decl: P(decl.clone())
@@ -1316,12 +2004,9 @@ fn mk_fn_proto_ty(ctx: &mut GenCtx,
}
}
-fn mk_fnty(ctx: &mut GenCtx,
- decl: &ast::FnDecl,
- unsafety: ast::Unsafety,
- abi: abi::Abi) -> ast::Ty {
+fn mk_fnty(ctx: &mut GenCtx, decl: &ast::FnDecl, abi: Abi) -> ast::Ty {
let fnty = ast::TyKind::BareFn(P(ast::BareFnTy {
- unsafety: unsafety,
+ unsafety: ast::Unsafety::Unsafe,
abi: abi,
lifetimes: Vec::new(),
decl: P(decl.clone())
diff --git a/src/lib.rs b/src/lib.rs
index b10546da..fadf41d8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,12 +1,14 @@
#![crate_name = "bindgen"]
#![crate_type = "dylib"]
+#![feature(quote)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
extern crate syntex_syntax as syntax;
extern crate libc;
-#[macro_use] extern crate log;
+#[macro_use]
+extern crate log;
use std::collections::HashSet;
use std::default::Default;
@@ -21,7 +23,7 @@ use syntax::print::pprust;
use syntax::print::pp::eof;
use syntax::ptr::P;
-use types::Global;
+use types::ModuleMap;
mod types;
mod clangll;
@@ -84,6 +86,11 @@ impl<'a> Builder<'a> {
self
}
+ pub fn rename_types(&mut self, value: bool) -> &mut Self {
+ self.options.rename_types = value;
+ self
+ }
+
pub fn log(&mut self, logger: &'a Logger) -> &mut Self {
self.logger = Some(logger);
self
@@ -111,10 +118,13 @@ pub struct BindgenOptions {
pub rust_enums: bool,
pub links: Vec<(String, LinkType)>,
pub emit_ast: bool,
+ pub ignore_functions: bool,
pub fail_on_unknown_type: bool,
+ pub enable_cxx_namespaces: bool,
+ pub rename_types: bool,
+ pub derive_debug: bool,
pub override_enum_ty: String,
pub clang_args: Vec<String>,
- pub derive_debug: bool,
}
impl Default for BindgenOptions {
@@ -125,18 +135,18 @@ impl Default for BindgenOptions {
rust_enums: true,
links: Vec::new(),
emit_ast: false,
- fail_on_unknown_type: false,
- override_enum_ty: "".to_owned(),
- clang_args: match get_include_dir() {
- Some(path) => vec!("-idirafter".to_owned(), path),
- None => Vec::new()
- },
- derive_debug: true
+ ignore_functions: false,
+ fail_on_unknown_type: true,
+ rename_types: true,
+ derive_debug: true,
+ enable_cxx_namespaces: false,
+ override_enum_ty: "".to_string(),
+ clang_args: Vec::new()
}
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum LinkType {
Default,
Static,
@@ -148,7 +158,7 @@ pub trait Logger {
fn warn(&self, msg: &str);
}
-#[derive(Clone)]
+#[derive(Debug, Clone)]
pub struct Bindings {
module: ast::Mod
}
@@ -157,21 +167,18 @@ impl Bindings {
/// Deprecated - use a `Builder` instead
pub fn generate(options: &BindgenOptions, logger: Option<&Logger>, span: Option<Span>) -> Result<Bindings, ()> {
let l = DummyLogger;
- let logger = match logger {
- Some(l) => l,
- None => &l as &Logger
- };
+ let logger = logger.unwrap_or(&l as &Logger);
- let span = match span {
- Some(s) => s,
- None => DUMMY_SP
- };
+ let span = span.unwrap_or(DUMMY_SP);
- let globals = try!(parse_headers(options, logger));
+ let module_map = try!(parse_headers(options, logger));
let module = ast::Mod {
inner: span,
- items: gen::gen_mod(options, globals, span)
+ items: gen::gen_mods(&options.links[..],
+ module_map,
+ options.clone(),
+ span)
};
Ok(Bindings {
@@ -217,7 +224,7 @@ impl Logger for DummyLogger {
fn warn(&self, _msg: &str) { }
}
-fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global>, ()> {
+fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<ModuleMap, ()> {
fn str_to_ikind(s: &str) -> Option<types::IKind> {
match s {
"uchar" => Some(types::IUChar),
@@ -239,8 +246,10 @@ fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result<Vec<Global
builtins: options.builtins,
match_pat: options.match_pat.clone(),
emit_ast: options.emit_ast,
+ ignore_functions: options.ignore_functions,
fail_on_unknown_type: options.fail_on_unknown_type,
- override_enum_ty: str_to_ikind(&options.override_enum_ty[..]),
+ enable_cxx_namespaces: options.enable_cxx_namespaces,
+ override_enum_ty: str_to_ikind(&options.override_enum_ty),
clang_args: options.clang_args.clone(),
};
diff --git a/src/parser.rs b/src/parser.rs
index 7895aa68..c6fc174f 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -1,27 +1,30 @@
#![allow(non_upper_case_globals)]
use std::collections::{HashMap, HashSet};
-use std::collections::hash_map;
use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
+use std::path::Path;
use syntax::abi;
use types as il;
use types::*;
use clang as cx;
-use clang::{ast_dump, Cursor, Diagnostic, TranslationUnit, type_to_str};
+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<String>,
pub builtins: bool,
pub match_pat: Vec<String>,
pub emit_ast: bool,
pub fail_on_unknown_type: bool,
+ pub ignore_functions: bool,
+ pub enable_cxx_namespaces: bool,
pub override_enum_ty: Option<il::IKind>,
pub clang_args: Vec<String>,
}
@@ -29,10 +32,26 @@ pub struct ClangParserOptions {
struct ClangParserCtx<'a> {
options: ClangParserOptions,
name: HashMap<Cursor, Global>,
- globals: Vec<Global>,
builtin_defs: Vec<Cursor>,
+ module_map: ModuleMap,
+ current_module_id: ModuleId,
logger: &'a (Logger+'a),
- err_count: i32
+ 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 current_module_mut(&mut self) -> &mut Module {
+ self.module_map.get_mut(&self.current_module_id).expect("Module not found!")
+ }
}
fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool {
@@ -47,76 +66,119 @@ fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool {
return true;
}
- let mut found = false;
- ctx.options.match_pat.iter().all(|pat| {
- if (&name[..]).contains(pat) {
- found = true;
- }
- true
- });
-
- found
+ let name = file.name();
+ ctx.options.match_pat.iter().any(|pat| name.contains(pat))
}
fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
let cursor = cursor.canonical();
- let mut new_decl = false;
let override_enum_ty = ctx.options.override_enum_ty;
- let decl = match ctx.name.entry(cursor) {
- hash_map::Entry::Occupied(ref e) => e.get().clone(),
- hash_map::Entry::Vacant(e) => {
- new_decl = true;
- let spelling = cursor.spelling();
- let ty = cursor.cur_type();
- let layout = Layout::new(ty.size(), ty.align());
+ let new_decl = !ctx.name.contains_key(&cursor);
- let glob_decl = match cursor.kind() {
- CXCursor_StructDecl => {
- let ci = Rc::new(RefCell::new(CompInfo::new(spelling, CompKind::Struct, vec!(), layout)));
- GCompDecl(ci)
- }
- CXCursor_UnionDecl => {
- let ci = Rc::new(RefCell::new(CompInfo::new(spelling, CompKind::Union, vec!(), layout)));
- 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 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::new(ty.size(), ty.align());
+ let filename = match Path::new(&file.name()).file_name() {
+ Some(name) => name.to_string_lossy().replace(".", "_"),
+ _ => "".to_string()
+ };
+ let glob_decl = match cursor.kind() {
+ CXCursor_StructDecl => {
+ let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Struct, vec!(), layout)));
+ GCompDecl(ci)
+ }
+ CXCursor_UnionDecl => {
+ let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Union, vec!(), layout)));
+ 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_ClassTemplate => {
+ let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Struct, vec!(), layout)));
+ GCompDecl(ci)
+ }
+ CXCursor_ClassDecl => {
+ 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);
+ list.push(conv_ty(ctx, &arg_type, &cursor));
}
- };
- let ei = Rc::new(RefCell::new(EnumInfo::new(spelling, kind, vec!(), layout)));
- GEnumDecl(ei)
- }
- CXCursor_TypedefDecl => {
- let ti = Rc::new(RefCell::new(TypeInfo::new(spelling, TVoid)));
- GType(ti)
- }
- CXCursor_VarDecl => {
- let vi = Rc::new(RefCell::new(VarInfo::new(spelling, TVoid)));
- GVar(vi)
- }
- CXCursor_FunctionDecl => {
- let vi = Rc::new(RefCell::new(VarInfo::new(spelling, TVoid)));
- GFunc(vi)
- }
- _ => GOther,
- };
+ list
+ }
+ };
- e.insert(glob_decl.clone());
- glob_decl
- },
+ let module_id = if args.is_empty() {
+ ctx.current_module_id
+ } else {
+ // it's an instantiation of another template,
+ // find the canonical declaration to find the module it belongs to.
+ let parent = cursor.specialized();
+ ctx.name.get(&parent).and_then(|global| {
+ if let GCompDecl(ref ci) = *global {
+ Some(ci.borrow().module_id)
+ } else {
+ None
+ }
+ }).unwrap_or_else(|| {
+ ctx.logger.warn("Template class wasn't declared when parsing specialisation!");
+ ctx.current_module_id
+ })
+ };
+
+ let ci = Rc::new(RefCell::new(CompInfo::new(spelling, module_id, filename, comment, CompKind::Struct, vec!(), layout)));
+ ci.borrow_mut().args = args;
+ GCompDecl(ci)
+ }
+ CXCursor_TypedefDecl => {
+ let ti = Rc::new(RefCell::new(TypeInfo::new(spelling, ctx.current_module_id, TVoid, layout)));
+ GType(ti)
+ }
+ CXCursor_VarDecl => {
+ let mangled = cursor.mangling();
+ let vi = Rc::new(RefCell::new(VarInfo::new(spelling, mangled, comment, TVoid)));
+ GVar(vi)
+ }
+ CXCursor_MacroDefinition => {
+ let vi = Rc::new(RefCell::new(VarInfo::new(spelling, String::new(), comment, TVoid)));
+ GVar(vi)
+ }
+ CXCursor_FunctionDecl => {
+ let mangled = cursor.mangling();
+ 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()) {
@@ -128,7 +190,7 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global {
fn opaque_decl(ctx: &mut ClangParserCtx, decl: &Cursor) {
let name = decl_name(ctx, decl);
- ctx.globals.push(name);
+ ctx.current_module_mut().globals.push(name);
}
fn fwd_decl<F:FnOnce(&mut ClangParserCtx)->()>(ctx: &mut ClangParserCtx, cursor: &Cursor, f: F) {
@@ -153,45 +215,42 @@ fn get_abi(cc: Enum_CXCallingConv) -> abi::Abi {
}
}
-fn conv_ptr_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor, layout: Layout) -> il::Type {
+fn conv_ptr_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor, is_ref: bool, layout: Layout) -> il::Type {
let is_const = ty.is_const();
match ty.kind() {
CXType_Void => {
- TPtr(Box::new(TVoid), is_const, layout)
+ return TPtr(Box::new(TVoid), is_const, is_ref, layout)
}
CXType_Unexposed |
CXType_FunctionProto |
CXType_FunctionNoProto => {
let ret_ty = ty.ret_type();
- let decl = ty.declaration();
- if ret_ty.kind() != CXType_Invalid {
+ return if ret_ty.kind() != CXType_Invalid {
TFuncPtr(mk_fn_sig(ctx, ty, cursor))
- } else if decl.kind() != CXCursor_NoDeclFound {
- TPtr(Box::new(conv_decl_ty(ctx, &decl)), ty.is_const(), layout)
} else if cursor.kind() == CXCursor_VarDecl {
let can_ty = ty.canonical_type();
conv_ty(ctx, &can_ty, cursor)
} else {
- TPtr(Box::new(TVoid), ty.is_const(), layout)
- }
+ TPtr(Box::new(conv_decl_ty(ctx, ty, cursor)), 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 {
- TPtr(Box::new(conv_ptr_ty(ctx, &def_ty, cursor, layout)), is_const, layout)
+ return TPtr(Box::new(conv_ptr_ty(ctx, &def_ty, cursor, is_ref, layout)), is_const, is_ref, layout);
} else {
- TPtr(Box::new(conv_ty(ctx, ty, cursor)), is_const, layout)
+ return TPtr(Box::new(conv_ty(ctx, ty, cursor)), is_const, is_ref, layout);
}
}
- _ => TPtr(Box::new(conv_ty(ctx, ty, cursor)), is_const, layout),
+ _ => return TPtr(Box::new(conv_ty(ctx, ty, cursor)), is_const, is_ref, layout),
}
}
fn mk_fn_sig(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::FuncSig {
let args_lst: Vec<(String, il::Type)> = match cursor.kind() {
- CXCursor_FunctionDecl => {
+ CXCursor_FunctionDecl | CXCursor_CXXMethod => {
// For CXCursor_FunctionDecl, cursor.args() is the reliable way to
// get parameter names and types.
cursor.args().iter().map(|arg| {
@@ -218,7 +277,7 @@ fn mk_fn_sig(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Fu
// Function is presumed unsafe if it takes a pointer argument.
let is_unsafe = args_lst.iter().any(|arg| match arg.1 {
- TPtr(_, _, _) => true,
+ TPtr(..) => true,
_ => false
});
@@ -231,34 +290,67 @@ fn mk_fn_sig(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Fu
}
}
-fn conv_decl_ty(ctx: &mut ClangParserCtx, cursor: &Cursor) -> il::Type {
- match cursor.kind() {
- CXCursor_StructDecl => {
- let decl = decl_name(ctx, cursor);
- let ci = decl.compinfo();
- TComp(ci)
- }
- CXCursor_UnionDecl => {
- let decl = decl_name(ctx, cursor);
+fn conv_decl_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Type {
+ let ty_decl = &ty.declaration();
+ return match ty_decl.kind() {
+ CXCursor_StructDecl |
+ CXCursor_UnionDecl |
+ CXCursor_ClassTemplate |
+ CXCursor_ClassDecl => {
+ let decl = decl_name(ctx, ty_decl);
+ 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);
+ list.push(conv_ty(ctx, &arg_type, &cursor));
+ }
+ list
+ }
+ };
let ci = decl.compinfo();
+ if !args.is_empty() {
+ ci.borrow_mut().args = args;
+ cursor.visit(|c, _: &Cursor| {
+ if c.kind() != CXCursor_TemplateRef {
+ return CXChildVisit_Continue;
+ }
+ let cref = c.definition();
+ ci.borrow_mut().ref_template = Some(conv_decl_ty(ctx, &cref.cur_type(), &cref));
+ CXChildVisit_Continue
+ });
+ }
TComp(ci)
}
CXCursor_EnumDecl => {
- let decl = decl_name(ctx, cursor);
+ let decl = decl_name(ctx, ty_decl);
let ei = decl.enuminfo();
TEnum(ei)
}
CXCursor_TypedefDecl => {
- let decl = decl_name(ctx, cursor);
+ let decl = decl_name(ctx, ty_decl);
let ti = decl.typeinfo();
TNamed(ti)
}
- _ => TVoid
- }
+ CXCursor_NoDeclFound | CXCursor_TypeAliasDecl => {
+ let layout = Layout::new(ty.size(), ty.align());
+ 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 {
- debug!("conv_ty: ty=`{}` sp=`{}` loc=`{}`", type_to_str(ty.kind()), cursor.spelling(), cursor.location());
let layout = Layout::new(ty.size(), ty.align());
match ty.kind() {
CXType_Void | CXType_Invalid => TVoid,
@@ -267,6 +359,8 @@ fn conv_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Type
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),
@@ -278,22 +372,23 @@ fn conv_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Type
CXType_Float => TFloat(FFloat, layout),
CXType_Double => TFloat(FDouble, layout),
CXType_LongDouble => TFloat(FDouble, layout),
- CXType_Pointer => conv_ptr_ty(ctx, &ty.pointee_type(), cursor, layout),
+ CXType_Pointer => conv_ptr_ty(ctx, &ty.pointee_type(), cursor, false, layout),
+ CXType_LValueReference => conv_ptr_ty(ctx, &ty.pointee_type(), cursor, true, layout),
CXType_VariableArray | CXType_DependentSizedArray | CXType_IncompleteArray => {
- conv_ptr_ty(ctx, &ty.elem_type(), cursor, layout)
+ conv_ptr_ty(ctx, &ty.elem_type(), cursor, false, layout)
}
CXType_FunctionProto => TFuncProto(mk_fn_sig(ctx, ty, cursor)),
CXType_Record |
CXType_Typedef |
CXType_Unexposed |
- CXType_Enum => conv_decl_ty(ctx, &ty.declaration()),
+ CXType_Enum => conv_decl_ty(ctx, ty, cursor),
CXType_ConstantArray => TArray(Box::new(conv_ty(ctx, &ty.elem_type(), cursor)), ty.array_size(), layout),
_ => {
let fail = ctx.options.fail_on_unknown_type;
log_err_warn(ctx,
&format!("unsupported type `{}` ({})",
type_to_str(ty.kind()), cursor.location()
- )[..],
+ ),
fail
);
TVoid
@@ -312,17 +407,64 @@ fn opaque_ty(ctx: &mut ClangParserCtx, ty: &cx::Type) {
}
}
+struct Annotations {
+ opaque: bool,
+ hide: bool,
+}
+
+impl Annotations {
+ fn new(cursor: &Cursor) -> Annotations {
+ let mut anno = Annotations {
+ opaque: false,
+ hide: false,
+ };
+
+ 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,
+ _ => (),
+ }
+ }
+ }
+
+ 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,
+<<<<<<< 6f1904e52612db3a2517727c053e7cbc84601b2a
compinfo: &mut CompInfo) -> Enum_CXVisitorResult {
+=======
+ ci: &mut CompInfo) -> Enum_CXVisitorResult {
+
+>>>>>>> SM hacks squash
fn is_bitfield_continuation(field: &il::FieldInfo, ty: &il::Type, width: u32) -> bool {
match (&field.bitfields, ty) {
(&Some(ref bitfields), &il::TInt(_, layout)) if *ty == field.ty => {
bitfields.iter().map(|&(_, w)| w).fold(0u32, |acc, w| acc + w) + width <= (layout.size * 8) as u32
},
+ (&Some(ref bitfields), &il::TNamed(ref info)) if *ty == field.ty => {
+ let info = info.borrow();
+ bitfields.iter().map(|&(_, w)| w).fold(0u32, |acc, w| acc + w) + width <= (info.layout.size * 8) as u32
+ },
_ => false
}
}
@@ -342,9 +484,14 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
match cursor.kind() {
CXCursor_FieldDecl => {
+ let anno = Annotations::new(cursor);
+ if anno.hide {
+ return CXChildVisit_Continue;
+ }
let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
+ let comment = cursor.raw_comment();
- let (name, bitfields) = match (cursor.bit_width(), members.last_mut()) {
+ 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) => {
@@ -363,7 +510,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
_ => {
let msg = format!("Enums in bitfields are not supported ({}.{}).",
cursor.spelling(), parent.spelling());
- ctx.logger.warn(&msg[..]);
+ ctx.logger.warn(&msg);
}
}
("".to_owned(), Some(vec!((cursor.spelling(), width))))
@@ -400,22 +547,37 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
// };
//
+<<<<<<< 6f1904e52612db3a2517727c053e7cbc84601b2a
let is_composite = match (inner_composite(&ty), members.last()) {
+=======
+ fn inner_composite(mut ty: &il::Type) -> Option<&Rc<RefCell<CompInfo>>> {
+ loop {
+ match ty {
+ &TComp(ref comp_ty) => return Some(comp_ty),
+ &TPtr(ref ptr_ty, _, _, _) => ty = &**ptr_ty,
+ &TArray(ref array_ty, _, _) => ty = &**array_ty,
+ _ => return None
+ }
+ }
+ }
+
+ let is_composite = match (inner_composite(&ty), ci.members.last()) {
+>>>>>>> SM hacks squash
(Some(ty_compinfo), Some(&CompMember::Comp(ref c))) => {
c.borrow().deref() as *const _ == ty_compinfo.borrow().deref() as *const _
},
_ => false
};
- let field = FieldInfo::new(name, ty.clone(), bitfields);
+ let field = FieldInfo::new(name, ty.clone(), comment, bitfields);
if is_composite {
- if let Some(CompMember::Comp(c)) = members.pop() {
- members.push(CompMember::CompField(c, field));
+ if let Some(CompMember::Comp(c)) = ci.members.pop() {
+ ci.members.push(CompMember::CompField(c, field));
} else {
unreachable!(); // Checks in is_composite make this unreachable.
}
} else {
- members.push(CompMember::Field(field));
+ ci.members.push(CompMember::Field(field));
}
}
CXCursor_StructDecl | CXCursor_UnionDecl => {
@@ -424,16 +586,150 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor,
// 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 ci = decl.compinfo();
+ let ci2 = decl.compinfo();
cursor.visit(|c, p| {
- let mut ci_ = ci.borrow_mut();
+ let mut ci_ = ci2.borrow_mut();
visit_composite(c, p, ctx_, &mut ci_)
});
- members.push(CompMember::Comp(decl.compinfo()));
+ ci.members.push(CompMember::Comp(decl.compinfo()));
});
}
CXCursor_PackedAttr => {
- compinfo.layout.packed = true;
+ ci.layout.packed = true;
+ }
+ CXCursor_TemplateTypeParameter => {
+ let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
+ let layout = Layout::new(ty.size(), ty.align());
+ ci.args.push(TNamed(Rc::new(RefCell::new(TypeInfo::new(cursor.spelling(), ctx.current_module_id, TVoid, layout)))));
+ }
+ CXCursor_EnumDecl => {
+ let anno = Annotations::new(cursor);
+ 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)
+ });
+ 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.len() > 0 {
+ format!("_base{}", ci.members.len())
+ } else {
+ "_base".to_string()
+ };
+ 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
+ };
+ let field = FieldInfo::new(fieldname, ty.clone(), "".to_owned(), None);
+ 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 => {
+ if ctx.options.ignore_functions {
+ return CXChildVisit_Continue;
+ }
+
+ let linkage = cursor.linkage();
+ if linkage != CXLinkage_External {
+ return CXChildVisit_Continue;
+ }
+
+ let visibility = cursor.visibility();
+ if visibility != CXVisibility_Default {
+ return CXChildVisit_Continue;
+ }
+
+ if ci.args.len() > 0 {
+ 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;
+ }
+
+ if cursor.method_is_virtual() {
+ ci.has_vtable = true;
+ }
+
+ let mut sig = mk_fn_sig(ctx, &cursor.cur_type(), cursor);
+ 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 {
+ 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.mangling(), cursor.raw_comment(), sig);
+ vi.is_static = cursor.method_is_static();
+ vi.is_const = cursor.cur_type().is_const();
+
+ if cursor.method_is_virtual() {
+ ci.vmethods.push(vi);
+ } else {
+ ci.methods.push(vi);
+ }
+ }
+ CXCursor_Destructor => {
+ ci.has_destructor = true;
}
_ => {
// XXX: Some kind of warning would be nice, but this produces far
@@ -453,45 +749,48 @@ fn visit_enum(cursor: &Cursor,
items: &mut Vec<EnumItem>) -> 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, val);
+ let item = EnumItem::new(name, comment, val);
items.push(item);
}
CXChildVisit_Continue
}
-fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option<i64> {
- if cursor.kind() == CXCursor_IntegerLiteral {
- match unit.tokens(cursor) {
- None => None,
- Some(tokens) => {
- if tokens.is_empty() || tokens[0].kind != CXToken_Literal {
- None
- } else {
- let s = &tokens[0].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 parse_int_literal_tokens(cursor: &Cursor, unit: &TranslationUnit, which: usize) -> Option<i64> {
+ 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,
}
}
}
}
- else {
- None
+}
+
+fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option<i64> {
+ if cursor.kind() == CXCursor_IntegerLiteral {
+ return parse_int_literal_tokens(cursor, unit, 0);
}
+ return None;
}
fn visit_top(cursor: &Cursor,
- ctx: &mut ClangParserCtx,
+ mut ctx: &mut ClangParserCtx,
unit: &TranslationUnit) -> Enum_CXVisitorResult {
if !match_pattern(ctx, cursor) {
return CXChildVisit_Continue;
@@ -499,9 +798,10 @@ fn visit_top(cursor: &Cursor,
match cursor.kind() {
CXCursor_UnexposedDecl => {
- CXChildVisit_Recurse
+ return CXChildVisit_Recurse;
}
- CXCursor_StructDecl | CXCursor_UnionDecl => {
+ CXCursor_StructDecl | CXCursor_UnionDecl | CXCursor_ClassDecl | CXCursor_ClassTemplate => {
+ let anno = Annotations::new(cursor);
fwd_decl(ctx, cursor, |ctx_| {
let decl = decl_name(ctx_, cursor);
let ci = decl.compinfo();
@@ -509,7 +809,13 @@ fn visit_top(cursor: &Cursor,
let mut ci_ = ci.borrow_mut();
visit_composite(c, p, ctx_, &mut ci_)
});
- ctx_.globals.push(GComp(ci));
+ if anno.opaque {
+ ci.borrow_mut().members = vec!();
+ }
+ if anno.hide {
+ ci.borrow_mut().hide = true;
+ }
+ ctx_.current_module_mut().globals.push(GComp(ci));
});
CXChildVisit_Continue
}
@@ -517,11 +823,12 @@ fn visit_top(cursor: &Cursor,
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_.globals.push(GEnum(ei));
+ ctx_.current_module_mut().globals.push(GEnum(ei));
});
CXChildVisit_Continue
}
@@ -531,12 +838,23 @@ fn visit_top(cursor: &Cursor,
return CXChildVisit_Continue;
}
+ let visibility = cursor.visibility();
+ if visibility != CXVisibility_Default {
+ 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.globals.push(func);
+ ctx.current_module_mut().globals.push(func);
CXChildVisit_Continue
}
@@ -546,6 +864,10 @@ fn visit_top(cursor: &Cursor,
return CXChildVisit_Continue;
}
+ let visibility = cursor.visibility();
+ if visibility != CXVisibility_Default {
+ return CXChildVisit_Continue;
+ }
let ty = conv_ty(ctx, &cursor.cur_type(), cursor);
let var = decl_name(ctx, cursor);
let vi = var.varinfo();
@@ -556,7 +878,7 @@ fn visit_top(cursor: &Cursor,
vi.val = visit_literal(c, unit);
CXChildVisit_Continue
});
- ctx.globals.push(var);
+ ctx.current_module_mut().globals.push(var);
CXChildVisit_Continue
}
@@ -566,12 +888,17 @@ fn visit_top(cursor: &Cursor,
under_ty = under_ty.canonical_type();
}
+ if cursor.spelling() ==
+ cursor.typedef_type().declaration().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();
- ctx.globals.push(typedef);
+ ti.comment = cursor.raw_comment();
+ ctx.current_module_mut().globals.push(typedef);
opaque_ty(ctx, &under_ty);
@@ -580,36 +907,107 @@ fn visit_top(cursor: &Cursor,
CXCursor_FieldDecl => {
CXChildVisit_Continue
}
- _ => CXChildVisit_Continue,
+ CXCursor_Namespace => {
+ if !ctx.options.enable_cxx_namespaces {
+ return CXChildVisit_Recurse;
+ }
+
+ let namespace_name = match 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;
+ cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx, &unit));
+ ctx.current_module_id = previous_id;
+
+ return CXChildVisit_Continue;
+ }
+ CXCursor_MacroDefinition => {
+ let val = parse_int_literal_tokens(cursor, unit, 1);
+ if val.is_none() {
+ // Not an integer literal.
+ return CXChildVisit_Continue;
+ }
+ let var = decl_name(ctx, cursor);
+ let vi = var.varinfo();
+ let mut vi = vi.borrow_mut();
+ vi.ty = match val {
+ None => TVoid,
+ Some(v) if v.abs() > u32::max_value() as i64 => TInt(IULongLong, Layout::new(8, 8)),
+ _ => TInt(IUInt, Layout::new(4, 4)),
+ };
+ vi.is_const = true;
+ vi.val = val;
+ ctx.current_module_mut().globals.push(var);
+
+ return CXChildVisit_Continue;
+ }
+ _ => 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)
+ ctx.logger.error(msg);
} else {
- ctx.logger.warn(msg)
+ ctx.logger.warn(msg);
}
}
-pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<Vec<Global>, ()> {
+pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<ModuleMap, ()> {
let mut ctx = ClangParserCtx {
options: options,
name: HashMap::new(),
builtin_defs: vec!(),
- globals: vec!(),
+ module_map: ModuleMap::new(),
+ current_module_id: ROOT_MODULE_ID,
logger: logger,
- err_count: 0
+ err_count: 0,
+ anonymous_modules_found: 0,
};
+ ctx.module_map.insert(ROOT_MODULE_ID, Module::new("root".to_owned(), None));
+
let ix = cx::Index::create(false, true);
if ix.is_null() {
ctx.logger.error("Clang failed to create index");
return Err(())
}
- let unit = TranslationUnit::parse(&ix, "", &ctx.options.clang_args[..], &[], 0);
+ let unit = TranslationUnit::parse(&ix, "", &ctx.options.clang_args[..], &[], CXTranslationUnit_DetailedPreprocessingRecord);
if unit.is_null() {
ctx.logger.error("No input files given");
return Err(())
@@ -619,7 +1017,7 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<Vec<Global>
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);
+ log_err_warn(&mut ctx, &msg, is_err);
}
if ctx.err_count > 0 {
@@ -646,5 +1044,5 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<Vec<Global>
return Err(())
}
- Ok(ctx.globals)
+ Ok(ctx.module_map)
}
diff --git a/src/types.rs b/src/types.rs
index d36b3835..7846c7c9 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -1,6 +1,8 @@
use std::cell::RefCell;
use std::fmt;
use std::rc::Rc;
+use std::collections::HashMap;
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use syntax::abi;
@@ -9,6 +11,45 @@ pub use self::Type::*;
pub use self::IKind::*;
pub use self::FKind::*;
+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<ModuleId, Module>;
+
+#[derive(Clone)]
+pub struct Module {
+ pub name: String,
+ pub globals: Vec<Global>,
+ pub parent_id: Option<ModuleId>,
+ // Just for convenience
+ pub children_ids: Vec<ModuleId>,
+}
+
+impl Module {
+ pub fn new(name: String, parent_id: Option<ModuleId>) -> Self {
+ Module {
+ name: name,
+ globals: vec![],
+ parent_id: parent_id,
+ children_ids: vec![],
+ }
+ }
+
+ #[allow(dead_code)]
+ pub fn add_global(&mut self, g: Global) {
+ self.globals.push(g)
+ }
+}
+
#[derive(Clone)]
pub enum Global {
GType(Rc<RefCell<TypeInfo>>),
@@ -83,7 +124,7 @@ pub enum Type {
TVoid,
TInt(IKind, Layout),
TFloat(FKind, Layout),
- TPtr(Box<Type>, bool, Layout),
+ TPtr(Box<Type>, bool, bool, Layout),
TArray(Box<Type>, usize, Layout),
TFuncProto(FuncSig),
TFuncPtr(FuncSig),
@@ -95,26 +136,26 @@ pub enum Type {
impl Type {
pub fn size(&self) -> usize {
match *self {
- TInt(_, l)
- | TFloat(_, l)
- | TPtr(_, _, l)
- | TArray(_, _, l) => l.size,
+ TInt(_, l) => l.size,
+ TFloat(_, l) => l.size,
+ TPtr(_, _, _, l) => l.size,
+ TArray(_, _, l) => l.size,
TNamed(ref ti) => ti.borrow().ty.size(),
TComp(ref ci) => ci.borrow().layout.size,
TEnum(ref ei) => ei.borrow().layout.size,
- TVoid
- | TFuncProto(..)
- | TFuncPtr(..) => 0,
+ TVoid => 0,
+ TFuncProto(..) => 0,
+ TFuncPtr(..) => 0,
}
}
#[allow(dead_code)]
pub fn align(&self) -> usize {
match *self {
- TInt(_, l)
- | TFloat(_, l)
- | TPtr(_, _, l)
- | TArray(_, _, l) => l.align,
+ TInt(_, l) => l.align,
+ TFloat(_, l) => l.align,
+ TPtr(_, _, _, l) => l.align,
+ TArray(_, _, l) => l.align,
TNamed(ref ti) => ti.borrow().ty.align(),
TComp(ref ci) => ci.borrow().layout.align,
TEnum(ref ei) => ei.borrow().layout.align,
@@ -124,6 +165,7 @@ impl Type {
}
}
+ #[allow(dead_code)]
pub fn can_derive_debug(&self) -> bool {
match *self {
TArray(_, size, _) => size <= 32,
@@ -175,6 +217,7 @@ pub enum IKind {
}
impl IKind {
+ #[allow(dead_code)]
pub fn is_signed(self) -> bool {
match self {
IBool => false,
@@ -203,6 +246,7 @@ pub enum CompMember {
Field(FieldInfo),
Comp(Rc<RefCell<CompInfo>>),
CompField(Rc<RefCell<CompInfo>>, FieldInfo),
+ Enum(Rc<RefCell<EnumInfo>>),
}
#[derive(Copy, Clone, PartialEq)]
@@ -215,16 +259,49 @@ pub enum CompKind {
pub struct CompInfo {
pub kind: CompKind,
pub name: String,
+ pub module_id: ModuleId,
+ pub filename: String,
+ pub comment: String,
pub members: Vec<CompMember>,
+ pub args: Vec<Type>,
+ pub methods: Vec<VarInfo>,
+ pub vmethods: Vec<VarInfo>,
+ pub ref_template: Option<Type>,
+ pub has_vtable: bool,
+ pub has_destructor: bool,
+ pub hide: bool,
+ pub base_members: usize,
pub layout: Layout,
}
+static mut UNNAMED_COUNTER: u32 = 0;
+
+fn unnamed_name(name: String, filename: &String) -> String {
+ return 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, kind: CompKind, members: Vec<CompMember>, layout: Layout) -> CompInfo {
+ pub fn new(name: String, module_id: ModuleId, filename: String, comment: String, kind: CompKind, members: Vec<CompMember>, layout: Layout) -> CompInfo {
CompInfo {
kind: kind,
- name: name,
+ 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,
+ hide: false,
+ base_members: 0,
layout: layout,
}
}
@@ -240,14 +317,16 @@ impl fmt::Debug for CompInfo {
pub struct FieldInfo {
pub name: String,
pub ty: Type,
+ pub comment: String,
pub bitfields: Option<Vec<(String, u32)>>,
}
impl FieldInfo {
- pub fn new(name: String, ty: Type, bitfields: Option<Vec<(String, u32)>>) -> FieldInfo {
+ pub fn new(name: String, ty: Type, comment: String, bitfields: Option<Vec<(String, u32)>>) -> FieldInfo {
FieldInfo {
name: name,
ty: ty,
+ comment: comment,
bitfields: bitfields,
}
}
@@ -256,15 +335,21 @@ impl FieldInfo {
#[derive(Clone, PartialEq)]
pub struct EnumInfo {
pub name: String,
+ pub module_id: ModuleId,
+ pub comment: String,
+ pub filename: String,
pub items: Vec<EnumItem>,
pub kind: IKind,
pub layout: Layout,
}
impl EnumInfo {
- pub fn new(name: String, kind: IKind, items: Vec<EnumItem>, layout: Layout) -> EnumInfo {
+ pub fn new(name: String, module_id: ModuleId, filename: String, kind: IKind, items: Vec<EnumItem>, layout: Layout) -> EnumInfo {
EnumInfo {
- name: name,
+ name: unnamed_name(name, &filename),
+ module_id: module_id,
+ comment: String::new(),
+ filename: filename,
items: items,
kind: kind,
layout: layout,
@@ -281,13 +366,15 @@ impl fmt::Debug for EnumInfo {
#[derive(Clone, PartialEq)]
pub struct EnumItem {
pub name: String,
+ pub comment: String,
pub val: i64
}
impl EnumItem {
- pub fn new(name: String, val: i64) -> EnumItem {
+ pub fn new(name: String, comment: String, val: i64) -> EnumItem {
EnumItem {
name: name,
+ comment: comment,
val: val
}
}
@@ -296,14 +383,20 @@ impl EnumItem {
#[derive(Clone, PartialEq)]
pub struct TypeInfo {
pub name: String,
- pub ty: Type
+ pub module_id: ModuleId,
+ pub comment: String,
+ pub ty: Type,
+ pub layout: Layout,
}
impl TypeInfo {
- pub fn new(name: String, ty: Type) -> TypeInfo {
+ pub fn new(name: String, module_id: ModuleId, ty: Type, layout: Layout) -> TypeInfo {
TypeInfo {
name: name,
- ty: ty
+ module_id: module_id,
+ comment: String::new(),
+ ty: ty,
+ layout: layout,
}
}
}
@@ -314,22 +407,33 @@ impl fmt::Debug for TypeInfo {
}
}
-#[derive(Clone)]
+#[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<i64>,
- pub is_const: bool
+ pub is_const: bool,
+ pub is_static: bool,
}
impl VarInfo {
- pub fn new(name: String, ty: Type) -> 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_const: false,
+ is_static: false,
}
}
}
diff --git a/tests/headers/class.hpp b/tests/headers/class.hpp
new file mode 100644
index 00000000..53894ab3
--- /dev/null
+++ b/tests/headers/class.hpp
@@ -0,0 +1,3 @@
+class C {
+ int a;
+};
diff --git a/tests/headers/namespace.h b/tests/headers/namespace.h
new file mode 100644
index 00000000..055e7258
--- /dev/null
+++ b/tests/headers/namespace.h
@@ -0,0 +1,45 @@
+
+
+void top_level();
+
+namespace whatever {
+ typedef int whatever_int_t;
+
+ void in_whatever();
+}
+
+namespace {
+ namespace empty {}
+
+ void foo();
+ struct A {
+ whatever::whatever_int_t b;
+ public:
+ int lets_hope_this_works();
+ };
+}
+
+template<typename T>
+class C: public A {
+ T m_c;
+};
+
+
+template<>
+class C<int>;
+
+
+namespace w {
+ typedef unsigned int whatever_int_t;
+
+ template<typename T>
+ class D {
+ C<T> m_c;
+ };
+
+ whatever_int_t heh(); // this should return w::whatever_int_t, and not whatever::whatever_int_t
+
+ C<int> foo();
+
+ C<float> barr(); // <- This is the problematic one
+}
diff --git a/tests/headers/template.hpp b/tests/headers/template.hpp
new file mode 100644
index 00000000..80825b74
--- /dev/null
+++ b/tests/headers/template.hpp
@@ -0,0 +1,5 @@
+template<typename T> class Foo {
+ T m_member;
+};
+
+void bar(Foo<int> foo);
diff --git a/tests/support.rs b/tests/support.rs
index a82529fe..0ac92f5f 100644
--- a/tests/support.rs
+++ b/tests/support.rs
@@ -43,7 +43,7 @@ pub fn assert_bind_eq(options: BindgenOptions,
let mut parser = parse::new_parser_from_source_str(ext_cx.parse_sess(), ext_cx.cfg(), "".to_string(), reference_items_str.to_string());
let mut reference_items = Vec::new();
- while let Some(item) = parser.parse_item().unwrap() {
+ while let Ok(Some(item)) = parser.parse_item() {
reference_items.push(item);
}
diff --git a/tests/test_builtins.rs b/tests/test_builtins.rs
index a19d048c..c1ddce72 100644
--- a/tests/test_builtins.rs
+++ b/tests/test_builtins.rs
@@ -4,6 +4,7 @@ use bindgen;
fn test_builtin_va_list() {
let bindings = bindgen::builder().header("tests/headers/builtin_va_list.h")
.emit_builtins().generate().unwrap().to_string();
+ println!("{}", bindings);
assert!(bindings.contains("__builtin_va_list"));
}
diff --git a/tests/test_cxx.rs b/tests/test_cxx.rs
new file mode 100644
index 00000000..ea4e516f
--- /dev/null
+++ b/tests/test_cxx.rs
@@ -0,0 +1,34 @@
+use bindgen;
+use bindgen::BindgenOptions;
+use support::assert_bind_eq;
+
+fn cxx_options() -> BindgenOptions {
+ let mut options = BindgenOptions::default();
+ options.rename_types = false;
+
+ options
+}
+
+#[test]
+fn test_cxx_class() {
+ assert_bind_eq(cxx_options(), "headers/class.hpp", "
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct C {
+ pub a: ::std::os::raw::c_int,
+ }");
+}
+
+#[test]
+fn test_cxx_template() {
+ assert_bind_eq(cxx_options(), "headers/template.hpp", "
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct Foo<T> {
+ pub m_member: T,
+ }
+ extern \"C\" {
+ #[link_name = \"_Z3bar3FooIiE\"]
+ pub fn bar(foo: Foo<::std::os::raw::c_int>);
+ }");
+}
diff --git a/tests/test_decl.rs b/tests/test_decl.rs
index 6858d416..58f7faba 100644
--- a/tests/test_decl.rs
+++ b/tests/test_decl.rs
@@ -4,7 +4,7 @@ use support::assert_bind_eq;
fn ptr_to_array() {
assert_bind_eq(Default::default(), "headers/decl_ptr_to_array.h", "
extern \"C\" {
- pub static mut foo: [::std::os::raw::c_int; 1usize];
+ pub static mut foo: [i32; 1usize];
}
");
}
diff --git a/tests/test_enum.rs b/tests/test_enum.rs
index e8c56c14..0a8a2bb8 100644
--- a/tests/test_enum.rs
+++ b/tests/test_enum.rs
@@ -8,13 +8,11 @@ fn default_without_rust_enums() -> BindgenOptions {
#[test]
fn with_simple_enum() {
assert_bind_eq(Default::default(), "headers/enum.h", "
- #[derive(Clone, Copy)]
#[repr(u32)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_Foo { Bar = 0, Qux = 1, }
- #[derive(Clone, Copy)]
#[repr(i32)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_Neg { MinusOne = -1, One = 1, }
");
assert_bind_eq(default_without_rust_enums(), "headers/enum.h", "
@@ -30,17 +28,14 @@ fn with_simple_enum() {
#[test]
fn with_packed_enums() {
assert_bind_eq(Default::default(), "headers/enum_packed.h", "
- #[derive(Clone, Copy)]
#[repr(u8)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_Foo { Bar = 0, Qux = 1, }
- #[derive(Clone, Copy)]
#[repr(i8)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_Neg { MinusOne = -1, One = 1, }
- #[derive(Clone, Copy)]
#[repr(u16)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_Bigger { Much = 255, Larger = 256, }
");
assert_bind_eq(default_without_rust_enums(), "headers/enum_packed.h", "
@@ -60,9 +55,8 @@ fn with_packed_enums() {
fn with_duplicate_enum_value() {
assert_bind_eq(Default::default(), "headers/enum_dupe.h", "
pub const Dupe: Enum_Foo = Enum_Foo::Bar;
- #[derive(Clone, Copy)]
#[repr(u32)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_Foo { Bar = 1, }
");
assert_bind_eq(default_without_rust_enums(), "headers/enum_dupe.h", "
@@ -75,25 +69,24 @@ fn with_duplicate_enum_value() {
#[test]
fn with_explicitly_typed_cxx_enum() {
assert_bind_eq(Default::default(), "headers/enum_explicit_type.hpp", "
- #[derive(Clone, Copy)]
#[repr(u8)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_Foo { Bar = 0, Qux = 1, }
- #[derive(Clone, Copy)]
+
#[repr(i8)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_Neg { MinusOne = -1, One = 1, }
- #[derive(Clone, Copy)]
+
#[repr(u16)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_Bigger { Much = 255, Larger = 256, }
- #[derive(Clone, Copy)]
+
#[repr(i64)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_MuchLong { MuchLow = -4294967296, }
- #[derive(Clone, Copy)]
+
#[repr(u64)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_MuchLongLong { MuchHigh = 4294967296, }
");
assert_bind_eq(default_without_rust_enums(), "headers/enum_explicit_type.hpp", "
@@ -116,17 +109,15 @@ fn with_explicitly_typed_cxx_enum() {
#[test]
fn with_overflowed_enum_value() {
assert_bind_eq(Default::default(), "headers/overflowed_enum.hpp", "
- #[derive(Clone, Copy)]
#[repr(u32)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_Foo {
BAP_ARM = 9698489,
BAP_X86 = 11960045,
BAP_X86_64 = 3128633167,
}
- #[derive(Clone, Copy)]
#[repr(u16)]
- #[derive(Debug)]
+ #[derive(Copy, Clone, Debug)]
pub enum Enum_Bar { One = 1, Big = 2, }
");
assert_bind_eq(default_without_rust_enums(), "headers/overflowed_enum.hpp", "
diff --git a/tests/test_extern.rs b/tests/test_extern.rs
index 25b06f0a..0d093593 100644
--- a/tests/test_extern.rs
+++ b/tests/test_extern.rs
@@ -3,6 +3,6 @@ use support::assert_bind_eq;
#[test]
fn extern_c_in_hpp() {
assert_bind_eq(Default::default(), "headers/extern.hpp", "
- pub type foo = extern \"C\" fn(bar: ::std::os::raw::c_int) -> ::std::os::raw::c_int;
+ pub type foo = extern \"C\" fn(bar: i32) -> i32;
");
}
diff --git a/tests/test_func.rs b/tests/test_func.rs
index e0b80d68..434612ef 100644
--- a/tests/test_func.rs
+++ b/tests/test_func.rs
@@ -15,21 +15,12 @@ fn func_ptr() {
fn func_ptr_in_struct() {
assert_bind_eq(Default::default(), "headers/func_ptr_in_struct.h", "
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
+ #[derive(Copy, Clone)]
pub struct Struct_Foo {
pub bar: ::std::option::Option<
- extern \"C\" fn(x: ::std::os::raw::c_int,
+ unsafe extern \"C\" fn(x: ::std::os::raw::c_int,
y: ::std::os::raw::c_int) -> Enum_baz>,
}
-
- impl ::std::clone::Clone for Struct_Foo {
- fn clone(&self) -> Self { *self }
- }
-
- impl ::std::default::Default for Struct_Foo {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
");
}
diff --git a/tests/test_struct.rs b/tests/test_struct.rs
index 2360f208..9f0625b4 100644
--- a/tests/test_struct.rs
+++ b/tests/test_struct.rs
@@ -4,125 +4,68 @@ use support::assert_bind_eq;
fn with_anon_struct() {
assert_bind_eq(Default::default(), "headers/struct_with_anon_struct.h", "
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
+ #[derive(Copy, Clone)]
pub struct Struct_foo {
- pub bar: Struct_Unnamed1,
- }
- impl ::std::clone::Clone for Struct_foo {
- fn clone(&self) -> Self { *self }
- }
- impl ::std::default::Default for Struct_foo {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+ pub bar: Struct_struct_with_anon_struct_h_unnamed_1,
}
+
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
- pub struct Struct_Unnamed1 {
+ #[derive(Copy, Clone)]
+ pub struct Struct_struct_with_anon_struct_h_unnamed_1 {
pub a: ::std::os::raw::c_int,
pub b: ::std::os::raw::c_int,
- }
- impl ::std::clone::Clone for Struct_Unnamed1 {
- fn clone(&self) -> Self { *self }
- }
- impl ::std::default::Default for Struct_Unnamed1 {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
- ");
+ }");
}
#[test]
fn with_anon_struct_array() {
assert_bind_eq(Default::default(), "headers/struct_with_anon_struct_array.h", "
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
+ #[derive(Copy, Clone)]
pub struct Struct_foo {
- pub bar: [Struct_Unnamed1; 2usize],
- pub baz: [[[Struct_Unnamed2; 4usize]; 3usize]; 2usize],
- }
-
- impl ::std::clone::Clone for Struct_foo {
- fn clone(&self) -> Self { *self }
- }
-
- impl ::std::default::Default for Struct_foo {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+ pub bar: [Struct_struct_with_anon_struct_array_h_unnamed_1; 2usize],
+ pub baz: [[[Struct_struct_with_anon_struct_array_h_unnamed_2; 4usize]; 3usize]; 2usize],
}
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
- pub struct Struct_Unnamed1 {
+ #[derive(Copy, Clone)]
+ pub struct Struct_struct_with_anon_struct_array_h_unnamed_1 {
pub a: ::std::os::raw::c_int,
pub b: ::std::os::raw::c_int,
}
- impl ::std::clone::Clone for Struct_Unnamed1 {
- fn clone(&self) -> Self { *self }
- }
-
- impl ::std::default::Default for Struct_Unnamed1 {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
-
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
- pub struct Struct_Unnamed2 {
+ #[derive(Copy, Clone)]
+ pub struct Struct_struct_with_anon_struct_array_h_unnamed_2 {
pub a: ::std::os::raw::c_int,
pub b: ::std::os::raw::c_int,
- }
-
- impl ::std::clone::Clone for Struct_Unnamed2 {
- fn clone(&self) -> Self { *self }
- }
-
- impl ::std::default::Default for Struct_Unnamed2 {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
- ");
+ }");
}
#[test]
fn with_anon_struct_pointer() {
assert_bind_eq(Default::default(), "headers/struct_with_anon_struct_pointer.h", "
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
+ #[derive(Copy, Clone)]
pub struct Struct_foo {
- pub bar: *mut Struct_Unnamed1,
- }
- impl ::std::clone::Clone for Struct_foo {
- fn clone(&self) -> Self { *self }
- }
- impl ::std::default::Default for Struct_foo {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+ pub bar: *mut Struct_struct_with_anon_struct_pointer_h_unnamed_1,
}
+
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
- pub struct Struct_Unnamed1 {
+ #[derive(Copy, Clone)]
+ pub struct Struct_struct_with_anon_struct_pointer_h_unnamed_1 {
pub a: ::std::os::raw::c_int,
pub b: ::std::os::raw::c_int,
- }
- impl ::std::clone::Clone for Struct_Unnamed1 {
- fn clone(&self) -> Self { *self }
- }
- impl ::std::default::Default for Struct_Unnamed1 {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
- ");
+ }");
}
#[test]
fn with_anon_union() {
assert_bind_eq(Default::default(), "headers/struct_with_anon_union.h", "
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
+ #[derive(Copy, Clone)]
pub struct Struct_foo {
- pub bar: Union_Unnamed1,
+ pub bar: Union_unnamed1,
}
impl ::std::clone::Clone for Struct_foo {
fn clone(&self) -> Self { *self }
@@ -133,10 +76,10 @@ fn with_anon_union() {
#[repr(C)]
#[derive(Copy)]
#[derive(Debug)]
- pub struct Union_Unnamed1 {
+ pub struct Union_unnamed1 {
pub _bindgen_data_: [u32; 1usize],
}
- impl Union_Unnamed1 {
+ impl Union_unnamed1 {
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))
@@ -146,12 +89,6 @@ fn with_anon_union() {
::std::mem::transmute(raw.offset(0))
}
}
- impl ::std::clone::Clone for Union_Unnamed1 {
- fn clone(&self) -> Self { *self }
- }
- impl ::std::default::Default for Union_Unnamed1 {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
");
}
@@ -187,8 +124,7 @@ fn with_anon_unnamed_struct() {
fn with_anon_unnamed_union() {
assert_bind_eq(Default::default(), "headers/struct_with_anon_unnamed_union.h", "
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
+ #[derive(Copy, Clone)]
pub struct Struct_foo {
pub _bindgen_data_1_: [u32; 1usize],
}
@@ -264,34 +200,16 @@ fn with_nesting() {
fn containing_fwd_decl_struct() {
assert_bind_eq(Default::default(), "headers/struct_containing_forward_declared_struct.h", "
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
+ #[derive(Copy, Clone)]
pub struct Struct_a {
pub val_a: *mut Struct_b,
}
- impl ::std::clone::Clone for Struct_a {
- fn clone(&self) -> Self { *self }
- }
-
- impl ::std::default::Default for Struct_a {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
-
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
+ #[derive(Copy, Clone)]
pub struct Struct_b {
pub val_b: ::std::os::raw::c_int,
}
-
- impl ::std::clone::Clone for Struct_b {
- fn clone(&self) -> Self { *self }
- }
-
- impl ::std::default::Default for Struct_b {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
");
}
@@ -322,30 +240,16 @@ fn with_bitfields() {
fn with_fwd_decl_struct() {
assert_bind_eq(Default::default(), "headers/forward_declared_struct.h", "
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
+ #[derive(Copy, Clone)]
pub struct Struct_a {
pub b: ::std::os::raw::c_int,
}
- impl ::std::clone::Clone for Struct_a {
- fn clone(&self) -> Self { *self }
- }
- impl ::std::default::Default for Struct_a {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
+
#[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
+ #[derive(Copy, Clone)]
pub struct Struct_c {
pub d: ::std::os::raw::c_int,
- }
- impl ::std::clone::Clone for Struct_c {
- fn clone(&self) -> Self { *self }
- }
- impl ::std::default::Default for Struct_c {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
- ");
+ }");
}
@@ -353,69 +257,9 @@ fn with_fwd_decl_struct() {
fn packed_struct() {
assert_bind_eq(Default::default(), "headers/struct_with_packing.h", "
#[repr(C, packed)]
- #[derive(Copy)]
- #[derive(Debug)]
+ #[derive(Copy, Clone)]
pub struct 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 }
- }
- impl ::std::default::Default for Struct_a {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
- ");
-}
-
-#[test]
-fn derive_debug_big_array() {
- assert_bind_eq(Default::default(), "headers/struct_with_derive_debug.h", "
- #[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
- pub struct Struct_LittleArray {
- pub a: [::std::os::raw::c_int; 32usize],
- }
- impl ::std::clone::Clone for Struct_LittleArray {
- fn clone(&self) -> Self { *self }
- }
- impl ::std::default::Default for Struct_LittleArray {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
- #[repr(C)]
- #[derive(Copy)]
- pub struct Struct_BigArray {
- pub a: [::std::os::raw::c_int; 33usize],
- }
- impl ::std::clone::Clone for Struct_BigArray {
- fn clone(&self) -> Self { *self }
- }
- impl ::std::default::Default for Struct_BigArray {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
- #[repr(C)]
- #[derive(Copy)]
- #[derive(Debug)]
- pub struct Struct_WithLittleArray {
- pub a: Struct_LittleArray,
- }
- impl ::std::clone::Clone for Struct_WithLittleArray {
- fn clone(&self) -> Self { *self }
- }
- impl ::std::default::Default for Struct_WithLittleArray {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
- #[repr(C)]
- #[derive(Copy)]
- pub struct Struct_WithBigArray {
- pub a: Struct_BigArray,
- }
- impl ::std::clone::Clone for Struct_WithBigArray {
- fn clone(&self) -> Self { *self }
- }
- impl ::std::default::Default for Struct_WithBigArray {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
- }
- ");
+ }");
}
diff --git a/tests/tests.rs b/tests/tests.rs
index 33a75511..2e7072fe 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -7,6 +7,7 @@ mod support;
// Unused until we can generate code for tests
//mod test_cmath;
+mod test_cxx;
mod test_enum;
mod test_decl;
mod test_extern;