From d0f07f98b59fe1d6256e5dd821d4dee90e450a48 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 18 Feb 2016 12:15:02 -0800 Subject: [PATCH 01/25] Spit errors and warnings to stdout. The correct thing to do here is to use env_logger, but that was causing cargo troubles for me, and this is preferable to swallowing them. --- src/bin/bindgen.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs index 2e31983e1f..99ad96d65d 100644 --- a/src/bin/bindgen.rs +++ b/src/bin/bindgen.rs @@ -18,11 +18,11 @@ struct StdLogger; impl Logger for StdLogger { fn error(&self, msg: &str) { - error!("{}", msg); + println!("{}", msg); } fn warn(&self, msg: &str) { - warn!("{}", msg); + println!("{}", msg); } } From 6be9f9fbc97e7ce809edd1f3be5763b524044779 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 18 Feb 2016 14:45:45 -0800 Subject: [PATCH 02/25] Add the -ignore-functions argument. --- src/bin/bindgen.rs | 6 ++++++ src/lib.rs | 3 +++ src/parser.rs | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs index 99ad96d65d..4a90b3dc35 100644 --- a/src/bin/bindgen.rs +++ b/src/bin/bindgen.rs @@ -99,6 +99,10 @@ fn parse_args(args: &[String]) -> ParseResult { options.builtins = true; ix += 1; } + "-ignore-functions" => { + options.ignore_functions = true; + ix += 1; + } "-allow-unknown-types" => { options.fail_on_unknown_type = false; ix += 1; @@ -138,6 +142,8 @@ 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. -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) diff --git a/src/lib.rs b/src/lib.rs index cd73860bf0..304b2f881c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,6 +104,7 @@ pub struct BindgenOptions { pub builtins: bool, pub links: Vec<(String, LinkType)>, pub emit_ast: bool, + pub ignore_functions: bool, pub fail_on_unknown_type: bool, pub override_enum_ty: String, pub clang_args: Vec, @@ -116,6 +117,7 @@ impl Default for BindgenOptions { builtins: false, links: Vec::new(), emit_ast: false, + ignore_functions: false, fail_on_unknown_type: true, override_enum_ty: "".to_string(), clang_args: Vec::new() @@ -224,6 +226,7 @@ fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result, pub emit_ast: bool, pub fail_on_unknown_type: bool, + pub ignore_functions: bool, pub override_enum_ty: Option, pub clang_args: Vec, } @@ -590,6 +591,10 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, 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; From 589c26e421de6284213f57fe3821035a2f810034 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 18 Feb 2016 16:41:32 -0800 Subject: [PATCH 03/25] Handle 1 << 63 as enum value. --- src/gen.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index ae56e3af97..5286152e1f 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -1132,10 +1132,18 @@ fn cenum_to_rs(ctx: &mut GenCtx, name: String, comment: String, items: Vec Date: Wed, 2 Mar 2016 20:06:52 -0800 Subject: [PATCH 04/25] Don't try to convert standard int types in rust_type_id. It looks like mwu added this, but I'm pretty sure it's a category error. This function appears to be designed to reproducibly permute C identifiers so that they don't conflict with builtin rust types. It's specifically _not_ a type translator (which would happen at the type level, rather than the string level), and using it as such with callers like ctypedef_to_rs causes us to generate things like: type u64 = u64; While processing stdint.h, which is clearly wrong. --- src/gen.rs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 5286152e1f..3dbeccb854 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -76,20 +76,8 @@ fn rust_type_id(ctx: &mut GenCtx, name: String) -> String { s.push_str(&name); s } else { - match name.as_str() { - "int8_t" => "i8".to_string(), - "uint8_t" => "u8".to_string(), - "int16_t" => "i16".to_string(), - "uint16_t" => "u16".to_string(), - "int32_t" => "i32".to_string(), - "uint32_t" => "u32".to_string(), - "int64_t" => "i64".to_string(), - "uint64_t" => "u64".to_string(), - _ => { - let (n, _) = rust_id(ctx, name); - n - } - } + let (n, _) = rust_id(ctx, name); + n } } From 949151af46499cfd4eca076fb75877052611fc04 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Thu, 3 Mar 2016 16:48:11 -0800 Subject: [PATCH 05/25] Stop patching in placeholder names for CompInfo and EnumInfo instances during code generator. As best as I can tell, it's done this way (rather than my way) because bindgen tries to recognize struct and enums typedefs of the form: /* This is a common idiom in C, not so much in C++ */ typdef struct { ... } Foo; The intention, I think, is to avoid generating rust code for a struct with a placeholder name followed by a typedef, and just give the struct the right name initially. This seems like a reasonable goal, though not a particularly important one. However, in my testing this never actually happens, because we end up calling unnamed_name anyway during the GComp(ci) case of gen_mod before we get to evaluting the typedef. So let's just remove that stuff and simplify the code. This lets us remove all the borrow_mut calls during code generation, which seems necessary for soundness. --- src/gen.rs | 53 ++++++---------------------------------------------- src/types.rs | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 49 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 3dbeccb854..f46b372054 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -24,7 +24,6 @@ use types::*; struct GenCtx<'r> { ext_cx: base::ExtCtxt<'r>, - unnamed_ty: usize, span: Span } @@ -81,15 +80,6 @@ fn rust_type_id(ctx: &mut GenCtx, name: String) -> String { } } -fn unnamed_name(ctx: &mut GenCtx, name: String, filename: String) -> String { - return if name.is_empty() { - ctx.unnamed_ty += 1; - format!("{}_unnamed_{}", filename, ctx.unnamed_ty) - } else { - name - }; -} - fn comp_name(kind: CompKind, name: &String) -> String { match kind { CompKind::Struct => struct_name(name), @@ -250,7 +240,6 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> 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 }; ctx.ext_cx.bt_push(ExpnInfo { @@ -300,35 +289,19 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> defs.extend(ctypedef_to_rs(&mut ctx, t.name.clone(), t.comment.clone(), &t.ty).into_iter()) }, GCompDecl(ci) => { - { - let mut c = ci.borrow_mut(); - c.name = unnamed_name(&mut ctx, c.name.clone(), c.filename.clone()); - } let c = ci.borrow().clone(); defs.push(opaque_to_rs(&mut ctx, comp_name(c.kind, &c.name))); }, GComp(ci) => { - { - let mut c = ci.borrow_mut(); - c.name = unnamed_name(&mut ctx, c.name.clone(), c.filename.clone()); - } let c = ci.borrow().clone(); defs.extend(comp_to_rs(&mut ctx, comp_name(c.kind, &c.name), c).into_iter()) }, GEnumDecl(ei) => { - { - let mut e = ei.borrow_mut(); - e.name = unnamed_name(&mut ctx, e.name.clone(), e.filename.clone()); - } let e = ei.borrow().clone(); defs.push(opaque_to_rs(&mut ctx, enum_name(&e.name))); }, GEnum(ei) => { - { - let mut e = ei.borrow_mut(); - e.name = unnamed_name(&mut ctx, e.name.clone(), e.filename.clone()); - } let e = ei.borrow().clone(); defs.extend(cenum_to_rs(&mut ctx, enum_name(&e.name), e.comment, e.items, e.layout).into_iter()) }, @@ -659,24 +632,12 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, name: String, comment: String, ty: &Type) -> return match *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, name, c) - } else { - vec!(mk_item(ctx, name, comment, ty)) - } + assert!(!ci.borrow().name.is_empty()); + vec!(mk_item(ctx, name, comment, 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().clone(); - cenum_to_rs(ctx, name, e.comment, e.items, e.layout) - } else { - vec!(mk_item(ctx, name, comment, ty)) - } + assert!(!ei.borrow().name.is_empty()); + vec!(mk_item(ctx, name, comment, ty)) }, _ => vec!(mk_item(ctx, name, comment, ty)) } @@ -1614,16 +1575,14 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { mk_ty(ctx, false, vec!(id)) }, &TComp(ref ci) => { - let mut c = ci.borrow_mut(); - c.name = unnamed_name(ctx, c.name.clone(), c.filename.clone()); + let mut c = ci.borrow(); let args = c.args.iter().map(|gt| { P(cty_to_rs(ctx, gt, allow_bool)) }).collect(); mk_ty_args(ctx, false, vec!(comp_name(c.kind, &c.name)), args) }, &TEnum(ref ei) => { - let mut e = ei.borrow_mut(); - e.name = unnamed_name(ctx, e.name.clone(), e.filename.clone()); + let mut e = ei.borrow(); mk_ty(ctx, false, vec!(enum_name(&e.name))) } }; diff --git a/src/types.rs b/src/types.rs index 64adeeb32c..7f389462e2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -194,11 +194,22 @@ pub struct CompInfo { 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, filename: String, comment: String, kind: CompKind, members: Vec, layout: Layout) -> CompInfo { CompInfo { kind: kind, - name: name, + name: unnamed_name(name, &filename), filename: filename, comment: comment, members: members, @@ -253,7 +264,7 @@ pub struct EnumInfo { impl EnumInfo { pub fn new(name: String, filename: String, kind: IKind, items: Vec, layout: Layout) -> EnumInfo { EnumInfo { - name: name, + name: unnamed_name(name, &filename), comment: String::new(), filename: filename, items: items, From 283d0376bcca61d1313e9104a6e28014459c128c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Sat, 5 Mar 2016 01:00:58 +0100 Subject: [PATCH 06/25] gen: Allow empty union members --- src/gen.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index f46b372054..b7fddc9f87 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -1246,17 +1246,25 @@ fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &String, } fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String, - field_type: &Type, bitfields: &Vec<(String, u32)>) -> ast::ImplItem { + field_type: &Type, bitfields: &[(String, u32)]) -> ast::ImplItem { let field_type = cty_to_rs(ctx, field_type, false); 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::PatIdent( ast::BindingMode::ByValue(ast::MutImmutable), - respan(ctx.span, ctx.ext_cx.ident_of(name)), + respan(ctx.span, ident), None ), span: ctx.span @@ -1275,8 +1283,15 @@ fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String, 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 = ctx.ext_cx.ident_of(&name); + 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) ); From 62ad73e6d74c59957f98d3880c814532f44f5d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 7 Mar 2016 21:10:26 +0100 Subject: [PATCH 07/25] Use full paths in generation. --- src/gen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gen.rs b/src/gen.rs index b7fddc9f87..310db2bddd 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -759,7 +759,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec), + ty: quote_ty!(&ctx.ext_cx, ::std::marker::PhantomData<$inner_type>), attrs: vec!(), })); } From 6d372e092b1bdbc7af7e536093431af784463e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 7 Mar 2016 21:10:53 +0100 Subject: [PATCH 08/25] Fix test compilation --- tests/support.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/support.rs b/tests/support.rs index a83bbc0230..f2a5abb14a 100644 --- a/tests/support.rs +++ b/tests/support.rs @@ -38,7 +38,7 @@ pub fn assert_bind_eq(filename: &str, reference_items_str: &str) 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() { + while let Ok(Some(item)) = parser.parse_item() { reference_items.push(item); } @@ -47,7 +47,7 @@ pub fn assert_bind_eq(filename: &str, reference_items_str: &str) // rendered versions, which is not beautiful, but should work. let reference_rendered = render_items(&reference_items); let generated_rendered = render_items(&generated_items); - + if reference_rendered != generated_rendered { println!("Generated bindings for {} do not match the reference bindings.", filename); println!(""); From ccdd256e8a8a8e0e755400e102b544bbb76f712f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 7 Mar 2016 23:21:31 +0100 Subject: [PATCH 09/25] parser: Add support for parsing namespaces --- src/clang.rs | 6 +++++ src/parser.rs | 50 +++++++++++++++++++++++++++++++++++---- tests/headers/namespace.h | 11 +++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 tests/headers/namespace.h diff --git a/src/clang.rs b/src/clang.rs index 5d49f41c34..a75abe0328 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -37,6 +37,12 @@ impl Cursor { 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) diff --git a/src/parser.rs b/src/parser.rs index b215a5493f..d3081a698a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -16,6 +16,7 @@ use clangll::*; use super::Logger; +#[derive(Clone)] pub struct ClangParserOptions { pub builtin_names: HashSet, pub builtins: bool, @@ -33,7 +34,9 @@ struct ClangParserCtx<'a> { globals: Vec, builtin_defs: Vec, logger: &'a (Logger+'a), - err_count: i32 + err_count: i32, + anonymous_namespaces_found: usize, + namespaces: HashMap>, } fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool { @@ -735,7 +738,7 @@ fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option { } fn visit_top<'r>(cursor: &Cursor, - ctx: &mut ClangParserCtx, + mut ctx: &mut ClangParserCtx, unit: &TranslationUnit) -> Enum_CXVisitorResult { if !match_pattern(ctx, cursor) { return CXChildVisit_Continue; @@ -853,7 +856,39 @@ fn visit_top<'r>(cursor: &Cursor, return CXChildVisit_Continue; } CXCursor_Namespace => { - 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_namespaces_found += 1; + format!("__anonymous{}", ctx.anonymous_namespaces_found) + }); + + let mut ns_ctx = ctx.namespaces.entry(namespace_name).or_insert( + ClangParserCtx { + options: ctx.options.clone(), + name: HashMap::new(), + builtin_defs: vec!(), + globals: vec!(), + logger: ctx.logger, + err_count: 0, + anonymous_namespaces_found: 0, + namespaces: HashMap::new(), + } + ); + + cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ns_ctx, &unit)); + + return CXChildVisit_Continue; } CXCursor_MacroDefinition => { let val = parse_int_literal_tokens(cursor, unit, 1); @@ -896,7 +931,9 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result builtin_defs: vec!(), globals: vec!(), logger: logger, - err_count: 0 + err_count: 0, + anonymous_namespaces_found: 0, + namespaces: HashMap::new(), }; let ix = cx::Index::create(false, true); @@ -942,5 +979,10 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result return Err(()) } + // XXX: Return namespaces or some sort of tree structure instead of a Vec + for ns in ctx.namespaces.values() { + ctx.globals.extend(ns.globals.clone()); + } + Ok(ctx.globals) } diff --git a/tests/headers/namespace.h b/tests/headers/namespace.h new file mode 100644 index 0000000000..0e651f895a --- /dev/null +++ b/tests/headers/namespace.h @@ -0,0 +1,11 @@ + + +namespace { + void foo(); + namespace wut { + } +} + +namespace whatever { + void foo(); +} From 7707540ec0c41519de11e1898a97ee693e6f6b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 9 Mar 2016 21:16:11 +0100 Subject: [PATCH 10/25] Partial C++ namespaces support We currently generate the modules as expected, but we don't resolve the names from external namespaces well. --- src/gen.rs | 136 ++++++++++++++++++++++---------------- src/lib.rs | 18 ++--- src/parser.rs | 20 ++++-- src/types.rs | 38 +++++++++++ tests/headers/namespace.h | 19 ++++-- 5 files changed, 153 insertions(+), 78 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 310db2bddd..4c806f7980 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -2,8 +2,6 @@ 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::ast; use syntax::codemap::{Span, Spanned, respan, ExpnInfo, NameAndSpan, MacroBang}; @@ -28,7 +26,7 @@ struct GenCtx<'r> { } fn first((val, _): (A, B)) -> A { - return val; + val } fn ref_eq<'a, 'b, T>(thing: &'a T, other: &'b T) -> bool { @@ -226,7 +224,7 @@ fn gen_unmangle_method(ctx: &mut GenCtx, P(item) } -pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> Vec> { +pub fn gen_mods(links: &[(String, LinkType)], mut root_module: Module, span: Span) -> Vec> { // Create a dummy ExtCtxt. We only need this for string interning and that uses TLS. let mut features = Features::new(); features.allow_quote = true; @@ -250,6 +248,47 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> span: None } }); + + gen_mod(&mut ctx, &mut root_module, links, span).items +} + +fn gen_mod(mut ctx: &mut GenCtx, + mut module: &mut Module, + links: &[(String, LinkType)], + span: Span) -> ast::Mod { + + let mut globals = gen_globals(&mut ctx, links, module.globals()); + globals.extend(module.submodules().drain().filter_map(|(name, mut module)| { + let module = gen_mod(ctx, &mut module, links, span.clone()); + + // mod foo; represents a module in another file, not an empty module, + // so... + if !module.items.is_empty() { + Some(P(ast::Item { + ident: ctx.ext_cx.ident_of(&name), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemMod(module), + vis: ast::Public, + span: span.clone(), + })) + } else { + None + } + })); + + + ast::Mod { + inner: span, + items: globals, + } +} + + + +fn gen_globals(mut ctx: &mut GenCtx, + links: &[(String, LinkType)], + globs: &[Global]) -> Vec> { let uniq_globs = tag_dup_decl(globs); let mut fs = vec!(); @@ -314,7 +353,7 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> } } - let vars = vs.into_iter().map(|v| { + let vars: Vec<_> = vs.into_iter().map(|v| { match v { GVar(vi) => { let v = vi.borrow(); @@ -358,19 +397,12 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> let mut map: HashMap> = 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) { + if !vars.is_empty() { defs.push(mk_extern(&mut ctx, links, vars, abi::C)); } @@ -386,37 +418,33 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> fn mk_extern(ctx: &mut GenCtx, links: &[(String, LinkType)], foreign_items: Vec>, abi: abi::Abi) -> P { - 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::MetaNameValue( - InternedString::new("name"), - respan(ctx.span, ast::LitStr(intern(l).as_str(), ast::CookedStr)) - ))); - let link_args = match k { - None => vec!(link_name), - Some(ref k) => vec!(link_name, P(respan(ctx.span, ast::MetaNameValue( - InternedString::new("kind"), - respan(ctx.span, ast::LitStr(intern(k).as_str(), ast::CookedStr)) - )))) - }; - respan(ctx.span, ast::Attribute_ { - id: mk_attr_id(), - style: ast::AttrStyle::Outer, - value: P(respan(ctx.span, ast::MetaList( - InternedString::new("link"), - link_args) - )), - is_sugared_doc: false - }) - }).collect() - }; + 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::MetaNameValue( + InternedString::new("name"), + respan(ctx.span, ast::LitStr(intern(l).as_str(), ast::CookedStr)) + ))); + let link_args = match k { + None => vec!(link_name), + Some(ref k) => vec!(link_name, P(respan(ctx.span, ast::MetaNameValue( + InternedString::new("kind"), + respan(ctx.span, ast::LitStr(intern(k).as_str(), ast::CookedStr)) + )))) + }; + respan(ctx.span, ast::Attribute_ { + id: mk_attr_id(), + style: ast::AttrStyle::Outer, + value: P(respan(ctx.span, ast::MetaList( + InternedString::new("link"), + link_args) + )), + is_sugared_doc: false + }) + }).collect(); let mut items = Vec::new(); items.extend(foreign_items.into_iter()); @@ -488,7 +516,7 @@ fn remove_redundant_decl(gs: Vec) -> Vec { ).collect(); } -fn tag_dup_decl(gs: Vec) -> Vec { +fn tag_dup_decl(gs: &[Global]) -> Vec { fn check(name1: &str, name2: &str) -> bool { !name1.is_empty() && name1 == name2 } @@ -553,7 +581,7 @@ fn tag_dup_decl(gs: Vec) -> Vec { } if gs.is_empty() { - return gs; + return vec![]; } let len = gs.len(); @@ -1590,14 +1618,14 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { mk_ty(ctx, false, vec!(id)) }, &TComp(ref ci) => { - let mut c = ci.borrow(); + let c = ci.borrow(); let args = c.args.iter().map(|gt| { P(cty_to_rs(ctx, gt, allow_bool)) }).collect(); mk_ty_args(ctx, false, vec!(comp_name(c.kind, &c.name)), args) }, &TEnum(ref ei) => { - let mut e = ei.borrow(); + let e = ei.borrow(); mk_ty(ctx, false, vec!(enum_name(&e.name))) } }; @@ -1632,11 +1660,7 @@ fn cty_has_destructor(ty: &Type) -> bool { }) { return true; } - if let Some(ref ty) = c.ref_template { - true - } else { - false - } + c.ref_template.is_some() }, &TNamed(ref ti) => { cty_has_destructor(&ti.borrow().ty) @@ -1668,11 +1692,11 @@ fn mk_ty_args(ctx: &GenCtx, global: bool, segments: Vec, args: Vec ast::Ty { diff --git a/src/lib.rs b/src/lib.rs index 304b2f881c..02ee31cb49 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ use syntax::print::pprust; use syntax::print::pp::eof; use syntax::ptr::P; -use types::Global; +use types::Module; mod types; mod clangll; @@ -146,21 +146,15 @@ impl Bindings { /// Deprecated - use a `Builder` instead pub fn generate(options: &BindgenOptions, logger: Option<&Logger>, span: Option) -> Result { 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 root_module = try!(parse_headers(options, logger)); let module = ast::Mod { inner: span, - items: gen::gen_mod(&options.links[..], globals, span) + items: gen::gen_mods(&options.links[..], root_module, span) }; Ok(Bindings { @@ -204,7 +198,7 @@ impl Logger for DummyLogger { fn warn(&self, _msg: &str) { } } -fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result, ()> { +fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result { fn str_to_ikind(s: &str) -> Option { match s { "uchar" => Some(types::IUChar), diff --git a/src/parser.rs b/src/parser.rs index d3081a698a..64b12170a5 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5,6 +5,7 @@ use std::cell::RefCell; use std::ops::Deref; use std::rc::Rc; use std::path::Path; +use std::mem; use syntax::abi; @@ -924,7 +925,7 @@ fn log_err_warn(ctx: &mut ClangParserCtx, msg: &str, is_err: bool) { } } -pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result, ()> { +pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result { let mut ctx = ClangParserCtx { options: options, name: HashMap::new(), @@ -979,10 +980,19 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result return Err(()) } - // XXX: Return namespaces or some sort of tree structure instead of a Vec - for ns in ctx.namespaces.values() { - ctx.globals.extend(ns.globals.clone()); + let mut root = Module::new(); + + fn add_submodules<'a>(module: &mut Module, + mut ctx: ClangParserCtx<'a>) { + mem::replace(module.globals(), ctx.globals); + for (name, ns) in ctx.namespaces.drain() { + let mut new = Module::new(); + add_submodules(&mut new, ns); + module.add_submodule(name, new); + } } - Ok(ctx.globals) + add_submodules(&mut root, ctx); + + Ok(root) } diff --git a/src/types.rs b/src/types.rs index 7f389462e2..3704a940d5 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,7 @@ use std::cell::RefCell; use std::fmt; use std::rc::Rc; +use std::collections::HashMap; use syntax::abi; @@ -9,6 +10,43 @@ pub use self::Type::*; pub use self::IKind::*; pub use self::FKind::*; +#[derive(Clone)] +pub struct Module { + globals: Vec, + submodules: HashMap, +} + +impl Module { + pub fn new() -> Self { + Self::with_globals(vec![]) + } + + pub fn with_globals(globals: Vec) -> Self { + Module { + globals: globals, + submodules: HashMap::new(), + } + } + + pub fn globals(&mut self) -> &mut Vec { + &mut self.globals + } + + pub fn submodules(&mut self) -> &mut HashMap { + &mut self.submodules + } + + pub fn add_submodule(&mut self, name: String, module: Module) { + debug_assert!(!self.submodules.contains_key(&name)); + self.submodules.insert(name, module); + } + + #[allow(dead_code)] + pub fn add_global(&mut self, g: Global) { + self.globals.push(g) + } +} + #[derive(Clone)] pub enum Global { GType(Rc>), diff --git a/tests/headers/namespace.h b/tests/headers/namespace.h index 0e651f895a..74bf0db64e 100644 --- a/tests/headers/namespace.h +++ b/tests/headers/namespace.h @@ -1,11 +1,20 @@ -namespace { - void foo(); - namespace wut { - } -} +void top_level(); namespace whatever { + typedef int whatever_int_t; + + void in_whatever(); +} + +namespace { + namespace empty {} + void foo(); + + class A { + whatever::whatever_int_t b; + }; } + From ddd02a10ecd475b9cd68aabd43976e5d95303210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 9 Mar 2016 21:30:22 +0100 Subject: [PATCH 11/25] Remove unnecesary return statements --- src/gen.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 4c806f7980..3290774723 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -1705,11 +1705,11 @@ fn mk_ptrty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty { mutbl: if is_const { ast::MutImmutable } else { ast::MutMutable } }); - return ast::Ty { + ast::Ty { id: ast::DUMMY_NODE_ID, node: ty, span: ctx.span - }; + } } fn mk_refty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty { @@ -1721,11 +1721,11 @@ fn mk_refty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty { } ); - return ast::Ty { + ast::Ty { id: ast::DUMMY_NODE_ID, node: ty, span: ctx.span - }; + } } fn mk_arrty(ctx: &GenCtx, base: &ast::Ty, n: usize) -> ast::Ty { @@ -1741,11 +1741,11 @@ fn mk_arrty(ctx: &GenCtx, base: &ast::Ty, n: usize) -> ast::Ty { }) ); - return ast::Ty { + ast::Ty { id: ast::DUMMY_NODE_ID, node: ty, span: ctx.span - }; + } } fn mk_fn_proto_ty(ctx: &mut GenCtx, decl: &ast::FnDecl, abi: abi::Abi) -> ast::Ty { @@ -1804,7 +1804,7 @@ fn mk_fnty(ctx: &mut GenCtx, decl: &ast::FnDecl, abi: abi::Abi) -> ast::Ty { } ]; - return ast::Ty { + ast::Ty { id: ast::DUMMY_NODE_ID, node: ast::TyPath( None, @@ -1815,5 +1815,5 @@ fn mk_fnty(ctx: &mut GenCtx, decl: &ast::FnDecl, abi: abi::Abi) -> ast::Ty { }, ), span: ctx.span - }; + } } From b49628ce44d57b9a6c6909abe6fe0ab60a232983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 9 Mar 2016 21:39:07 +0100 Subject: [PATCH 12/25] Put namespaces behind a flag Overall now that they aren't complete still. --- src/bin/bindgen.rs | 4 ++++ src/lib.rs | 3 +++ src/parser.rs | 15 ++++++--------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs index 4a90b3dc35..759baa0517 100644 --- a/src/bin/bindgen.rs +++ b/src/bin/bindgen.rs @@ -114,6 +114,10 @@ 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; + } _ => { options.clang_args.push(args[ix].clone()); ix += 1; diff --git a/src/lib.rs b/src/lib.rs index 02ee31cb49..a26d637104 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,6 +106,7 @@ pub struct BindgenOptions { pub emit_ast: bool, pub ignore_functions: bool, pub fail_on_unknown_type: bool, + pub enable_cxx_namespaces: bool, pub override_enum_ty: String, pub clang_args: Vec, } @@ -119,6 +120,7 @@ impl Default for BindgenOptions { emit_ast: false, ignore_functions: false, fail_on_unknown_type: true, + enable_cxx_namespaces: false, override_enum_ty: "".to_string(), clang_args: Vec::new() } @@ -222,6 +224,7 @@ fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result, pub clang_args: Vec, } @@ -52,15 +53,7 @@ fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool { } let name = file.name(); - let mut found = false; - ctx.options.match_pat.iter().all(|pat| { - if (&name).contains(pat) { - found = true; - } - true - }); - - return found; + ctx.options.match_pat.iter().any(|pat| name.contains(pat)) } fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { @@ -857,6 +850,10 @@ fn visit_top<'r>(cursor: &Cursor, return CXChildVisit_Continue; } CXCursor_Namespace => { + if !ctx.options.enable_cxx_namespaces { + return CXChildVisit_Recurse; + } + let namespace_name = match unit.tokens(cursor) { None => None, Some(tokens) => { From bbaf49582624488381bed8e3f6347af5e1e24f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 9 Mar 2016 22:14:29 +0100 Subject: [PATCH 13/25] Moar refactoring --- src/gen.rs | 84 +++++++++++++++++++++++++-------------------------- src/parser.rs | 11 +++---- 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 3290774723..1d455ff087 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -453,14 +453,14 @@ fn mk_extern(ctx: &mut GenCtx, links: &[(String, LinkType)], items: items }); - return P(ast::Item { - ident: ctx.ext_cx.ident_of(""), - attrs: attrs, - id: ast::DUMMY_NODE_ID, - node: ext, - vis: ast::Inherited, - span: ctx.span - }); + P(ast::Item { + ident: ctx.ext_cx.ident_of(""), + attrs: attrs, + id: ast::DUMMY_NODE_ID, + node: ext, + vis: ast::Inherited, + span: ctx.span + }) } fn mk_impl(ctx: &mut GenCtx, ty: P, @@ -511,9 +511,9 @@ fn remove_redundant_decl(gs: Vec) -> Vec { } ).collect(); - return gs.into_iter().filter(|g| + gs.into_iter().filter(|g| !typedefs.iter().any(|t| check_decl(g, t)) - ).collect(); + ).collect() } fn tag_dup_decl(gs: &[Global]) -> Vec { @@ -648,17 +648,17 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, name: String, comment: String, ty: &Type) -> empty_generics() ); - return P(ast::Item { - ident: ctx.ext_cx.ident_of(&rust_name), - attrs: mk_doc_attr(ctx, comment), - id: ast::DUMMY_NODE_ID, - node: base, - vis: ast::Public, - span: ctx.span - }); + P(ast::Item { + ident: ctx.ext_cx.ident_of(&rust_name), + attrs: mk_doc_attr(ctx, comment), + id: ast::DUMMY_NODE_ID, + node: base, + vis: ast::Public, + span: ctx.span + }) } - return match *ty { + match *ty { TComp(ref ci) => { assert!(!ci.borrow().name.is_empty()); vec!(mk_item(ctx, name, comment, ty)) @@ -694,12 +694,12 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec true, _ => false }) { + args.iter().any(|f| f == &TVoid) { return vec!(); } let id = rust_type_id(ctx, name.clone()); - let id_ty = P(mk_ty(ctx, false, vec!(id.clone()))); + let id_ty = P(mk_ty(ctx, false, &[id.clone()])); if ci.has_vtable { let mut vffields = vec!(); @@ -727,7 +727,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec Vec ast::Ty { } else { "bool" }; - mk_ty(ctx, false, vec!(input_type.to_string())) + mk_ty(ctx, false, &[input_type.to_owned()]) } fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &String, @@ -1365,7 +1365,7 @@ fn mk_blob_field(ctx: &GenCtx, name: &str, layout: Layout) -> Spanned ast::Ty { - return match ty { - &TVoid => mk_ty(ctx, true, vec!("libc".to_string(), "c_void".to_string())), + match ty { + &TVoid => mk_ty(ctx, true, &["libc".to_owned(), "c_void".to_owned()]), &TInt(i, ref layout) => match i { IBool => { let ty_name = match layout.size { @@ -1574,22 +1574,22 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { 8 => "u64", _ => "u8", }; - mk_ty(ctx, false, vec!(ty_name.to_string())) + mk_ty(ctx, false, &[ty_name.to_owned()]) }, - ISChar => mk_ty(ctx, true, vec!("libc".to_string(), "c_char".to_string())), + ISChar => mk_ty(ctx, true, &["libc".to_owned(), "c_char".to_owned()]), IInt | IShort | - ILongLong => mk_ty(ctx, false, vec!(format!("i{}", layout.size * 8))), + ILongLong => mk_ty(ctx, false, &[format!("i{}", layout.size * 8)]), IUChar | IUInt | IUShort | - IULongLong => mk_ty(ctx, false, vec!(format!("u{}", layout.size * 8))), - ILong => mk_ty(ctx, true, vec!("libc".to_string(), "c_long".to_string())), - IULong => mk_ty(ctx, true, vec!("libc".to_string(), "c_ulong".to_string())), + IULongLong => mk_ty(ctx, false, &[format!("u{}", layout.size * 8)]), + ILong => mk_ty(ctx, true, &["libc".to_owned(), "c_long".to_owned()]), + IULong => mk_ty(ctx, true, &["libc".to_owned(), "c_ulong".to_owned()]), }, &TFloat(f, _) => match f { - FFloat => mk_ty(ctx, false, vec!("f32".to_string())), - FDouble => mk_ty(ctx, false, vec!("f64".to_string())) + FFloat => mk_ty(ctx, false, &["f32".to_owned()]), + FDouble => mk_ty(ctx, false, &["f64".to_owned()]) }, &TPtr(ref t, is_const, _is_ref, _) => { let id = cty_to_rs(ctx, &**t, allow_bool); @@ -1615,20 +1615,20 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { }, &TNamed(ref ti) => { let id = rust_type_id(ctx, ti.borrow().name.clone()); - mk_ty(ctx, false, vec!(id)) + mk_ty(ctx, false, &[id]) }, &TComp(ref ci) => { let c = ci.borrow(); let args = c.args.iter().map(|gt| { P(cty_to_rs(ctx, gt, allow_bool)) }).collect(); - mk_ty_args(ctx, false, vec!(comp_name(c.kind, &c.name)), args) + mk_ty_args(ctx, false, &[comp_name(c.kind, &c.name)], args) }, &TEnum(ref ei) => { let e = ei.borrow(); - mk_ty(ctx, false, vec!(enum_name(&e.name))) + mk_ty(ctx, false, &[enum_name(&e.name)]) } - }; + } } fn cty_is_translatable(ty: &Type) -> bool { @@ -1669,11 +1669,11 @@ fn cty_has_destructor(ty: &Type) -> bool { } } -fn mk_ty(ctx: &GenCtx, global: bool, segments: Vec) -> 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: Vec, args: Vec>) -> ast::Ty { +fn mk_ty_args(ctx: &GenCtx, global: bool, segments: &[String], args: Vec>) -> ast::Ty { let ty = ast::TyPath( None, ast::Path { diff --git a/src/parser.rs b/src/parser.rs index a333959200..55c99e467d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -913,12 +913,11 @@ fn visit_top<'r>(cursor: &Cursor, } fn log_err_warn(ctx: &mut ClangParserCtx, msg: &str, is_err: bool) { - match is_err { - true => { - ctx.err_count += 1; - ctx.logger.error(msg) - }, - false => ctx.logger.warn(msg) + if is_err { + ctx.err_count += 1; + ctx.logger.error(msg); + } else { + ctx.logger.warn(msg); } } From eb44cd7e667cff53cd8325b2ba26cc1f33911e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 9 Mar 2016 22:15:45 +0100 Subject: [PATCH 14/25] Finally take rid of all the warnings --- src/clangll.rs | 1 - src/gen.rs | 1 + src/lib.rs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clangll.rs b/src/clangll.rs index 1cef3d14f6..e32e99fd34 100644 --- a/src/clangll.rs +++ b/src/clangll.rs @@ -5,7 +5,6 @@ #![allow(unused_attributes)] #![allow(non_snake_case)] #![allow(non_upper_case_globals)] -#![allow(raw_pointer_derive)] pub type ptrdiff_t = ::libc::c_long; pub type size_t = ::libc::c_ulong; diff --git a/src/gen.rs b/src/gen.rs index 1d455ff087..6a93c05166 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -1712,6 +1712,7 @@ 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::TyRptr( None, diff --git a/src/lib.rs b/src/lib.rs index a26d637104..06be24645b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![crate_name = "bindgen"] #![crate_type = "dylib"] -#![feature(convert, quote)] +#![feature(quote)] extern crate syntex_syntax as syntax; extern crate libc; From 25a2e48af79e386abe860515e437b87d39452f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 9 Mar 2016 22:22:22 +0100 Subject: [PATCH 15/25] Even moar --- src/gen.rs | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 6a93c05166..67c91339b6 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -56,25 +56,16 @@ fn rust_id(ctx: &mut GenCtx, name: String) -> (String, bool) { } 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_string(); - s.push_str(&name); - s - } else { - let (n, _) = rust_id(ctx, name); - n + 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)) } } @@ -134,7 +125,7 @@ fn gen_unmangle_method(ctx: &mut GenCtx, unnamed += 1; format!("arg{}", unnamed) } else { - rust_id(ctx, n.clone()).0 + first(rust_id(ctx, n.clone())) }; let expr = ast::Expr { id: ast::DUMMY_NODE_ID, @@ -1179,7 +1170,7 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize, // TODO: Implement bitfield accessors if f.bitfields.is_some() { return None; } - let (f_name, _) = rust_id(ctx, f.name.clone()); + let f_name = first(rust_id(ctx, f.name.clone())); let ret_ty = P(cty_to_rs(ctx, &TPtr(Box::new(f.ty.clone()), false, false, Layout::zero()), true)); // When the offset is zero, generate slightly prettier code. From 59c3345cea0c8c949ca23e133a193ca66e222609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 10 Mar 2016 01:44:02 +0100 Subject: [PATCH 16/25] gen: Avoid so much cloning --- src/gen.rs | 66 +++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 67c91339b6..0f7b9eeb6d 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -44,25 +44,25 @@ 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 { +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.push_str(name); (s, true) } else { - (name, false) + (name.to_owned(), false) } } -fn rust_type_id(ctx: &mut GenCtx, name: String) -> String { - match &*name { +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.push_str(name); s } _ => first(rust_id(ctx, name)) @@ -76,16 +76,16 @@ fn comp_name(kind: CompKind, name: &String) -> String { } } -fn struct_name(name: &String) -> String { - format!("{}", name) +fn struct_name(name: &str) -> String { + name.to_owned() } -fn union_name(name: &String) -> String { - format!("{}", name) +fn union_name(name: &str) -> String { + name.to_owned() } -fn enum_name(name: &String) -> String { - format!("{}", name) +fn enum_name(name: &str) -> String { + name.to_owned() } fn gen_unmangle_method(ctx: &mut GenCtx, @@ -125,7 +125,7 @@ fn gen_unmangle_method(ctx: &mut GenCtx, unnamed += 1; format!("arg{}", unnamed) } else { - first(rust_id(ctx, n.clone())) + first(rust_id(ctx, &n)) }; let expr = ast::Expr { id: ast::DUMMY_NODE_ID, @@ -195,7 +195,7 @@ fn gen_unmangle_method(ctx: &mut GenCtx, count += 1; counts.insert(v.name.clone(), count); - let mut attrs = mk_doc_attr(ctx, v.comment.clone()); + let mut attrs = mk_doc_attr(ctx, &v.comment); attrs.push(respan(ctx.span, ast::Attribute_ { id: mk_attr_id(), style: ast::AttrStyle::Outer, @@ -689,7 +689,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec Vec rust_type_id(ctx, f.name.clone()) + None => rust_type_id(ctx, &f.name) }; let mut offset: u32 = 0; @@ -868,7 +868,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec Vec P { empty_generics() ); - let id = rust_type_id(ctx, name); + let id = rust_type_id(ctx, &name); return P(ast::Item { ident: ctx.ext_cx.ident_of(&id), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, @@ -1049,7 +1049,7 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, layout: Layout, members: Vec P "i32", }; - let mut attrs = mk_doc_attr(ctx, comment); + let mut attrs = mk_doc_attr(ctx, &comment); attrs.push(respan(ctx.span, ast::Attribute_ { id: mk_attr_id(), style: ast::AttrStyle::Outer, @@ -1170,7 +1170,7 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize, // TODO: Implement bitfield accessors if f.bitfields.is_some() { return None; } - let f_name = first(rust_id(ctx, f.name.clone())); + 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)); // When the offset is zero, generate slightly prettier code. @@ -1420,14 +1420,14 @@ fn mk_deriving_copy_attr(ctx: &mut GenCtx) -> ast::Attribute { }) } -fn mk_doc_attr(ctx: &mut GenCtx, doc: String) -> Vec { +fn mk_doc_attr(ctx: &mut GenCtx, doc: &str) -> Vec { if doc.is_empty() { return vec!(); } let attr_val = P(respan(ctx.span, ast::MetaNameValue( InternedString::new("doc"), - respan(ctx.span, ast::LitStr(intern(&doc).as_str(), ast::CookedStr)) + respan(ctx.span, ast::LitStr(intern(doc).as_str(), ast::CookedStr)) ))); vec!(respan(ctx.span, ast::Attribute_ { @@ -1442,7 +1442,7 @@ fn cvar_to_rs(ctx: &mut GenCtx, name: String, mangled: String, ty: &Type, is_const: bool) -> P { - 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 !mangled.is_empty() { @@ -1484,7 +1484,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) @@ -1534,9 +1534,9 @@ fn cfunc_to_rs(ctx: &mut GenCtx, empty_generics() ); - let (rust_name, was_mangled) = rust_id(ctx, name.clone()); + let (rust_name, was_mangled) = rust_id(ctx, &name); - let mut attrs = mk_doc_attr(ctx, comment); + let mut attrs = mk_doc_attr(ctx, &comment); if !mangled.is_empty() { attrs.push(mk_link_name_attr(ctx, mangled)); } else if was_mangled { @@ -1605,7 +1605,7 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { mk_fn_proto_ty(ctx, &decl, sig.abi) }, &TNamed(ref ti) => { - let id = rust_type_id(ctx, ti.borrow().name.clone()); + let id = rust_type_id(ctx, &ti.borrow().name); mk_ty(ctx, false, &[id]) }, &TComp(ref ci) => { From e7ae3d47428ca32d4c8a379405fe26ffeb1b1d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 10 Mar 2016 01:44:50 +0100 Subject: [PATCH 17/25] parser: Refactor the way submodules are stored This way we can share the global map, while having each module custom globals. --- src/lib.rs | 4 +- src/parser.rs | 124 +++++++++++++++++++++++++++++--------------------- src/types.rs | 59 ++++++++++++++---------- 3 files changed, 107 insertions(+), 80 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 06be24645b..0fc1cee4da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ use syntax::print::pprust; use syntax::print::pp::eof; use syntax::ptr::P; -use types::Module; +use types::ModuleMap; mod types; mod clangll; @@ -200,7 +200,7 @@ impl Logger for DummyLogger { fn warn(&self, _msg: &str) { } } -fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result { +fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result { fn str_to_ikind(s: &str) -> Option { match s { "uchar" => Some(types::IUChar), diff --git a/src/parser.rs b/src/parser.rs index 55c99e467d..6622ba7ac7 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -33,12 +33,30 @@ pub struct ClangParserOptions { struct ClangParserCtx<'a> { options: ClangParserOptions, name: HashMap, - globals: Vec, builtin_defs: Vec, + module_map: ModuleMap, + current_module_id: ModuleId, logger: &'a (Logger+'a), err_count: i32, - anonymous_namespaces_found: usize, - namespaces: HashMap>, + anonymous_modules_found: usize, +} + +impl<'a> ClangParserCtx<'a> { + fn module(&self, id: &ModuleId) -> &Module { + self.module_map.get(id).expect("Module not found!") + } + + fn module_mut(&mut self, id: &ModuleId) -> &mut Module { + self.module_map.get_mut(&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 { @@ -73,11 +91,11 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { }; let glob_decl = match cursor.kind() { CXCursor_StructDecl => { - let ci = Rc::new(RefCell::new(CompInfo::new(spelling, filename, comment, CompKind::Struct, vec!(), layout))); + 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, filename, comment, CompKind::Union, vec!(), layout))); + let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Union, vec!(), layout))); GCompDecl(ci) } CXCursor_EnumDecl => { @@ -97,11 +115,11 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { _ => IInt, } }; - let ei = Rc::new(RefCell::new(EnumInfo::new(spelling, filename, kind, vec!(), layout))); + 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, filename, comment, CompKind::Struct, vec!(), layout))); + let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Struct, vec!(), layout))); GCompDecl(ci) } CXCursor_ClassDecl => { @@ -116,12 +134,12 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { list } }; - let ci = Rc::new(RefCell::new(CompInfo::new(spelling, filename, comment, CompKind::Struct, vec!(), layout))); + let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_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, TVoid, layout))); + let ti = Rc::new(RefCell::new(TypeInfo::new(spelling, ctx.current_module_id, TVoid, layout))); GType(ti) } CXCursor_VarDecl => { @@ -158,7 +176,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()>(ctx: &mut ClangParserCtx, cursor: &Cursor, f: F) { @@ -253,6 +271,7 @@ fn mk_fn_sig(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Fu fn conv_decl_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Type { let ty_decl = &ty.declaration(); + println!("Declaration kind: {} {}", ty_decl.spelling(), kind_to_str(ty_decl.kind())); return match ty_decl.kind() { CXCursor_StructDecl | CXCursor_UnionDecl | @@ -296,7 +315,7 @@ fn conv_decl_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il: } CXCursor_NoDeclFound | CXCursor_TypeAliasDecl => { let layout = Layout::new(ty.size(), ty.align()); - TNamed(Rc::new(RefCell::new(TypeInfo::new(ty.spelling().replace("const ", ""), TVoid, layout)))) + 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; @@ -312,7 +331,7 @@ fn conv_decl_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il: } 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()); + println!("conv_ty: ty=`{}` sp=`{}` loc=`{}`", type_to_str(ty.kind()), cursor.spelling(), cursor.location()); let layout = Layout::new(ty.size(), ty.align()); return match ty.kind() { @@ -414,6 +433,7 @@ impl Annotations { fn visit_composite(cursor: &Cursor, parent: &Cursor, ctx: &mut ClangParserCtx, ci: &mut CompInfo) -> Enum_CXVisitorResult { + println!("visit_composite: {} {} {}", kind_to_str(cursor.kind()), cursor.spelling(), cursor.location()); fn is_bitfield_continuation(field: &il::FieldInfo, ty: &il::Type, width: u32) -> bool { match (&field.bitfields, ty) { @@ -542,7 +562,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, 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(), TVoid, layout))))); + 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); @@ -650,7 +670,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, 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(), TVoid, Layout::zero()))))), cursor.cur_type().is_const(), false, Layout::zero()))); + 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()))); } } @@ -734,6 +754,7 @@ fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option { fn visit_top<'r>(cursor: &Cursor, mut ctx: &mut ClangParserCtx, unit: &TranslationUnit) -> Enum_CXVisitorResult { + println!("visit_top: {}", cursor.location()); if !match_pattern(ctx, cursor) { return CXChildVisit_Continue; } @@ -757,7 +778,7 @@ fn visit_top<'r>(cursor: &Cursor, if anno.hide { ci.borrow_mut().hide = true; } - ctx_.globals.push(GComp(ci)); + ctx_.current_module_mut().globals.push(GComp(ci)); }); return CXChildVisit_Continue; } @@ -770,7 +791,7 @@ fn visit_top<'r>(cursor: &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)); }); return CXChildVisit_Continue; } @@ -796,7 +817,7 @@ fn visit_top<'r>(cursor: &Cursor, 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); return CXChildVisit_Continue; } @@ -820,7 +841,7 @@ fn visit_top<'r>(cursor: &Cursor, vi.val = visit_literal(c, unit); CXChildVisit_Continue }); - ctx.globals.push(var); + ctx.current_module_mut().globals.push(var); return CXChildVisit_Continue; } @@ -840,7 +861,7 @@ fn visit_top<'r>(cursor: &Cursor, let mut ti = ti.borrow_mut(); ti.ty = ty.clone(); ti.comment = cursor.raw_comment(); - ctx.globals.push(typedef); + ctx.current_module_mut().globals.push(typedef); opaque_ty(ctx, &under_ty); @@ -867,24 +888,33 @@ fn visit_top<'r>(cursor: &Cursor, } } }.unwrap_or_else(|| { - ctx.anonymous_namespaces_found += 1; - format!("__anonymous{}", ctx.anonymous_namespaces_found) + ctx.anonymous_modules_found += 1; + format!("__anonymous{}", ctx.anonymous_modules_found) }); - let mut ns_ctx = ctx.namespaces.entry(namespace_name).or_insert( - ClangParserCtx { - options: ctx.options.clone(), - name: HashMap::new(), - builtin_defs: vec!(), - globals: vec!(), - logger: ctx.logger, - err_count: 0, - anonymous_namespaces_found: 0, - namespaces: HashMap::new(), + // 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 => { + println!("Creating namespace {}", namespace_name); + 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; - cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ns_ctx, &unit)); + 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; } @@ -904,7 +934,7 @@ fn visit_top<'r>(cursor: &Cursor, }; vi.is_const = true; vi.val = val; - ctx.globals.push(var); + ctx.current_module_mut().globals.push(var); return CXChildVisit_Continue; } @@ -921,18 +951,20 @@ fn log_err_warn(ctx: &mut ClangParserCtx, msg: &str, is_err: bool) { } } -pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result { +pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result { 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, - anonymous_namespaces_found: 0, - namespaces: HashMap::new(), + 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"); @@ -976,19 +1008,5 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result return Err(()) } - let mut root = Module::new(); - - fn add_submodules<'a>(module: &mut Module, - mut ctx: ClangParserCtx<'a>) { - mem::replace(module.globals(), ctx.globals); - for (name, ns) in ctx.namespaces.drain() { - let mut new = Module::new(); - add_submodules(&mut new, ns); - module.add_submodule(name, new); - } - } - - add_submodules(&mut root, ctx); - - Ok(root) + Ok(ctx.module_map) } diff --git a/src/types.rs b/src/types.rs index 3704a940d5..1b047e538d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,6 +2,7 @@ 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; @@ -10,37 +11,39 @@ 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; + #[derive(Clone)] pub struct Module { - globals: Vec, - submodules: HashMap, + pub name: String, + pub globals: Vec, + pub parent_id: Option, + // Just for convenience + pub children_ids: Vec, } impl Module { - pub fn new() -> Self { - Self::with_globals(vec![]) - } - - pub fn with_globals(globals: Vec) -> Self { + pub fn new(name: String, parent_id: Option) -> Self { Module { - globals: globals, - submodules: HashMap::new(), + name: name, + globals: vec![], + parent_id: parent_id, + children_ids: vec![], } } - pub fn globals(&mut self) -> &mut Vec { - &mut self.globals - } - - pub fn submodules(&mut self) -> &mut HashMap { - &mut self.submodules - } - - pub fn add_submodule(&mut self, name: String, module: Module) { - debug_assert!(!self.submodules.contains_key(&name)); - self.submodules.insert(name, module); - } - #[allow(dead_code)] pub fn add_global(&mut self, g: Global) { self.globals.push(g) @@ -218,6 +221,7 @@ 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, @@ -244,9 +248,10 @@ fn unnamed_name(name: String, filename: &String) -> String { } impl CompInfo { - pub fn new(name: String, filename: String, comment: String, kind: CompKind, members: Vec, layout: Layout) -> CompInfo { + pub fn new(name: String, module_id: ModuleId, filename: String, comment: String, kind: CompKind, members: Vec, layout: Layout) -> CompInfo { CompInfo { kind: kind, + module_id: module_id, name: unnamed_name(name, &filename), filename: filename, comment: comment, @@ -292,6 +297,7 @@ impl FieldInfo { #[derive(Clone, PartialEq)] pub struct EnumInfo { pub name: String, + pub module_id: ModuleId, pub comment: String, pub filename: String, pub items: Vec, @@ -300,9 +306,10 @@ pub struct EnumInfo { } impl EnumInfo { - pub fn new(name: String, filename: String, kind: IKind, items: Vec, layout: Layout) -> EnumInfo { + pub fn new(name: String, module_id: ModuleId, filename: String, kind: IKind, items: Vec, layout: Layout) -> EnumInfo { EnumInfo { name: unnamed_name(name, &filename), + module_id: module_id, comment: String::new(), filename: filename, items: items, @@ -338,15 +345,17 @@ impl EnumItem { #[derive(Clone, PartialEq)] pub struct TypeInfo { pub name: String, + pub module_id: ModuleId, pub comment: String, pub ty: Type, pub layout: Layout, } impl TypeInfo { - pub fn new(name: String, ty: Type, layout: Layout) -> TypeInfo { + pub fn new(name: String, module_id: ModuleId, ty: Type, layout: Layout) -> TypeInfo { TypeInfo { name: name, + module_id: module_id, comment: String::new(), ty: ty, layout: layout, From abdbc86f1e2ec8fbaab09bd5d670b160ae1e8af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 10 Mar 2016 01:51:31 +0100 Subject: [PATCH 18/25] gen: Checkpoint before the refactoring This actually keeps working as before. --- src/gen.rs | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 0f7b9eeb6d..7d764bcf18 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -22,7 +22,8 @@ use types::*; struct GenCtx<'r> { ext_cx: base::ExtCtxt<'r>, - span: Span + span: Span, + module_map: ModuleMap, } fn first((val, _): (A, B)) -> A { @@ -215,7 +216,7 @@ fn gen_unmangle_method(ctx: &mut GenCtx, P(item) } -pub fn gen_mods(links: &[(String, LinkType)], mut root_module: Module, span: Span) -> Vec> { +pub fn gen_mods(links: &[(String, LinkType)], mut map: ModuleMap, span: Span) -> Vec> { // Create a dummy ExtCtxt. We only need this for string interning and that uses TLS. let mut features = Features::new(); features.allow_quote = true; @@ -229,7 +230,8 @@ pub fn gen_mods(links: &[(String, LinkType)], mut root_module: Module, span: Spa let mut feature_gated_cfgs = vec![]; let mut ctx = GenCtx { ext_cx: base::ExtCtxt::new(sess, Vec::new(), cfg, &mut feature_gated_cfgs), - span: span + span: span, + module_map: map, }; ctx.ext_cx.bt_push(ExpnInfo { call_site: ctx.span, @@ -240,17 +242,22 @@ pub fn gen_mods(links: &[(String, LinkType)], mut root_module: Module, span: Spa } }); - gen_mod(&mut ctx, &mut root_module, links, span).items + gen_mod(&mut ctx, ROOT_MODULE_ID, links, span).items } fn gen_mod(mut ctx: &mut GenCtx, - mut module: &mut Module, + module_id: ModuleId, links: &[(String, LinkType)], span: Span) -> ast::Mod { - let mut globals = gen_globals(&mut ctx, links, module.globals()); - globals.extend(module.submodules().drain().filter_map(|(name, mut module)| { - let module = gen_mod(ctx, &mut module, links, span.clone()); + // XXX avoid this clone + let module = ctx.module_map.get(&module_id).unwrap().clone(); + + let mut globals = gen_globals(&mut ctx, module_id, links, &module.globals); + + globals.extend(module.children_ids.iter().filter_map(|id| { + let name = ctx.module_map.get(id).unwrap().name.clone(); + let module = gen_mod(ctx, *id, links, span.clone()); // mod foo; represents a module in another file, not an empty module, // so... @@ -278,6 +285,7 @@ fn gen_mod(mut ctx: &mut GenCtx, fn gen_globals(mut ctx: &mut GenCtx, + current_module: ModuleId, links: &[(String, LinkType)], globs: &[Global]) -> Vec> { let uniq_globs = tag_dup_decl(globs); @@ -316,7 +324,7 @@ fn gen_globals(mut ctx: &mut GenCtx, match g { GType(ti) => { let t = ti.borrow().clone(); - defs.extend(ctypedef_to_rs(&mut ctx, t.name.clone(), t.comment.clone(), &t.ty).into_iter()) + defs.extend(ctypedef_to_rs(&mut ctx, t).into_iter()) }, GCompDecl(ci) => { let c = ci.borrow().clone(); @@ -622,8 +630,8 @@ fn tag_dup_decl(gs: &[Global]) -> Vec { return res; } -fn ctypedef_to_rs(ctx: &mut GenCtx, name: String, comment: String, ty: &Type) -> Vec> { - fn mk_item(ctx: &mut GenCtx, name: String, comment: String, ty: &Type) -> P { +fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> Vec> { + fn mk_item(ctx: &mut GenCtx, name: &str, comment: &str, ty: &Type) -> P { let rust_name = rust_type_id(ctx, name); let rust_ty = if cty_is_translatable(ty) { cty_to_rs(ctx, ty, true) @@ -649,16 +657,16 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, name: String, comment: String, ty: &Type) -> }) } - match *ty { + match ty.ty { TComp(ref ci) => { assert!(!ci.borrow().name.is_empty()); - vec!(mk_item(ctx, name, comment, ty)) + vec!(mk_item(ctx, &ty.name, &ty.comment, &ty.ty)) }, TEnum(ref ei) => { assert!(!ei.borrow().name.is_empty()); - vec!(mk_item(ctx, name, comment, ty)) + vec!(mk_item(ctx, &ty.name, &ty.comment, &ty.ty)) }, - _ => vec!(mk_item(ctx, name, comment, ty)) + _ => vec!(mk_item(ctx, &ty.name, &ty.comment, &ty.ty)), } } @@ -1024,18 +1032,19 @@ fn opaque_to_rs(ctx: &mut GenCtx, name: String) -> P { fn cunion_to_rs(ctx: &mut GenCtx, name: String, layout: Layout, members: Vec) -> Vec> { fn mk_item(ctx: &mut GenCtx, name: String, item: ast::Item_, vis: ast::Visibility, attrs: Vec) -> P { - return P(ast::Item { + P(ast::Item { ident: ctx.ext_cx.ident_of(&name), attrs: attrs, id: ast::DUMMY_NODE_ID, node: item, vis: vis, span: ctx.span - }); + }) } - let ci = Rc::new(RefCell::new(CompInfo::new(name.clone(), name.clone(), "".to_owned(), CompKind::Union, members.clone(), layout))); - let union = TNamed(Rc::new(RefCell::new(TypeInfo::new(name.clone(), TComp(ci), layout)))); + // XXX what module id is correct? + let ci = Rc::new(RefCell::new(CompInfo::new(name.clone(), ROOT_MODULE_ID, name.clone(), "".to_owned(), CompKind::Union, members.clone(), layout))); + let union = TNamed(Rc::new(RefCell::new(TypeInfo::new(name.clone(), 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 From 14f00d0172f1d27066c71fb1e3e5df1292bcd599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 10 Mar 2016 02:16:42 +0100 Subject: [PATCH 19/25] gen: Make modules (almost) work for typedef'd types We generate almost valid code, we just have to add some use statements. Or maybe is a better idea to add an unintelligible name to the root mod, and actually output a root mod plus a use root::* before. --- src/gen.rs | 24 ++++++++++++++++++++++-- src/parser.rs | 6 ------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 7d764bcf18..a80074b8bb 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -26,6 +26,23 @@ struct GenCtx<'r> { module_map: ModuleMap, } +impl<'r> GenCtx<'r> { + fn full_path_for_module(&self, id: ModuleId) -> Vec { + let mut ret = vec![]; + + let mut current_id = Some(id); + while let Some(current) = current_id { + let module = &self.module_map.get(¤t).unwrap(); + ret.push(module.name.clone()); + current_id = module.parent_id; + } + + ret.pop(); // The root isn't really here + ret.reverse(); + ret + } +} + fn first((val, _): (A, B)) -> A { val } @@ -70,7 +87,7 @@ fn rust_type_id(ctx: &mut GenCtx, name: &str) -> String { } } -fn comp_name(kind: CompKind, name: &String) -> String { +fn comp_name(kind: CompKind, name: &str) -> String { match kind { CompKind::Struct => struct_name(name), CompKind::Union => union_name(name), @@ -1615,7 +1632,10 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { }, &TNamed(ref ti) => { let id = rust_type_id(ctx, &ti.borrow().name); - mk_ty(ctx, false, &[id]) + + let mut path = ctx.full_path_for_module(ti.borrow().module_id); + path.push(id); + mk_ty(ctx, false, &path) }, &TComp(ref ci) => { let c = ci.borrow(); diff --git a/src/parser.rs b/src/parser.rs index 6622ba7ac7..31cc137640 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -271,7 +271,6 @@ fn mk_fn_sig(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Fu fn conv_decl_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Type { let ty_decl = &ty.declaration(); - println!("Declaration kind: {} {}", ty_decl.spelling(), kind_to_str(ty_decl.kind())); return match ty_decl.kind() { CXCursor_StructDecl | CXCursor_UnionDecl | @@ -331,8 +330,6 @@ fn conv_decl_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il: } fn conv_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Type { - println!("conv_ty: ty=`{}` sp=`{}` loc=`{}`", type_to_str(ty.kind()), cursor.spelling(), cursor.location()); - let layout = Layout::new(ty.size(), ty.align()); return match ty.kind() { CXType_Void | CXType_Invalid => TVoid, @@ -433,7 +430,6 @@ impl Annotations { fn visit_composite(cursor: &Cursor, parent: &Cursor, ctx: &mut ClangParserCtx, ci: &mut CompInfo) -> Enum_CXVisitorResult { - println!("visit_composite: {} {} {}", kind_to_str(cursor.kind()), cursor.spelling(), cursor.location()); fn is_bitfield_continuation(field: &il::FieldInfo, ty: &il::Type, width: u32) -> bool { match (&field.bitfields, ty) { @@ -754,7 +750,6 @@ fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option { fn visit_top<'r>(cursor: &Cursor, mut ctx: &mut ClangParserCtx, unit: &TranslationUnit) -> Enum_CXVisitorResult { - println!("visit_top: {}", cursor.location()); if !match_pattern(ctx, cursor) { return CXChildVisit_Continue; } @@ -901,7 +896,6 @@ fn visit_top<'r>(cursor: &Cursor, let mod_id = match mod_id { Some(id) => id, None => { - println!("Creating namespace {}", namespace_name); let parent_id = ctx.current_module_id; let id = ModuleId::next(); ctx.module_map.get_mut(&parent_id).unwrap().children_ids.push(id); From e90066a5bebe308bd28c46b795c398eca3de083b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 10 Mar 2016 02:23:40 +0100 Subject: [PATCH 20/25] gen: Document the current submodule approach and some desirable alternative --- src/gen.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/gen.rs b/src/gen.rs index a80074b8bb..8c39a29fb2 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -37,6 +37,39 @@ impl<'r> GenCtx<'r> { current_id = module.parent_id; } + // XXX This is done because we don't actually print the root module. + // + // We include a lot of top-level "use's" instead. + // + // It might be desirable something like: + // + // ``` + // use __randomlygeneratednameforroot::*; + // mod __randomlygeneratednameforroot { + // pub mod b { + // pub type ty = i32; + // } + // pub mod a { + // static C: __randomlygeneratednameforroot::b::ty; + // } + // } + // ``` + // + // Vs: + // + // ``` + // pub mod b { + // use a; + // pub type ty = i32; + // } + // + // pub mod a { + // use b; + // static C: b::ty; + // } + // ``` + // + // Or even switching via flag back and forth. ret.pop(); // The root isn't really here ret.reverse(); ret From 008978db88ec59c9759b72bdb4091aebfa645e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 10 Mar 2016 02:59:32 +0100 Subject: [PATCH 21/25] gen: Make it actually compilable \o/ --- src/gen.rs | 129 +++++++++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 59 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 8c39a29fb2..4ef0c28ea8 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -37,40 +37,6 @@ impl<'r> GenCtx<'r> { current_id = module.parent_id; } - // XXX This is done because we don't actually print the root module. - // - // We include a lot of top-level "use's" instead. - // - // It might be desirable something like: - // - // ``` - // use __randomlygeneratednameforroot::*; - // mod __randomlygeneratednameforroot { - // pub mod b { - // pub type ty = i32; - // } - // pub mod a { - // static C: __randomlygeneratednameforroot::b::ty; - // } - // } - // ``` - // - // Vs: - // - // ``` - // pub mod b { - // use a; - // pub type ty = i32; - // } - // - // pub mod a { - // use b; - // static C: b::ty; - // } - // ``` - // - // Or even switching via flag back and forth. - ret.pop(); // The root isn't really here ret.reverse(); ret } @@ -292,50 +258,95 @@ pub fn gen_mods(links: &[(String, LinkType)], mut map: ModuleMap, span: Span) -> } }); - gen_mod(&mut ctx, ROOT_MODULE_ID, links, span).items + if let Some(root_mod) = gen_mod(&mut ctx, ROOT_MODULE_ID, links, span) { + let root_export = P(ast::Item { + ident: ctx.ext_cx.ident_of(""), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemUse(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::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) -> ast::Mod { + span: Span) -> Option> { // XXX avoid this clone let module = ctx.module_map.get(&module_id).unwrap().clone(); - let mut globals = gen_globals(&mut ctx, module_id, links, &module.globals); + // 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::ItemUse(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::Public, + span: span.clone(), + })] + } else { + vec![] + }; - globals.extend(module.children_ids.iter().filter_map(|id| { - let name = ctx.module_map.get(id).unwrap().name.clone(); - let module = gen_mod(ctx, *id, links, span.clone()); + globals.extend(gen_globals(&mut ctx, links, &module.globals).into_iter()); - // mod foo; represents a module in another file, not an empty module, - // so... - if !module.items.is_empty() { - Some(P(ast::Item { - ident: ctx.ext_cx.ident_of(&name), - attrs: vec![], - id: ast::DUMMY_NODE_ID, - node: ast::ItemMod(module), - vis: ast::Public, - span: span.clone(), - })) - } else { - None - } + globals.extend(module.children_ids.iter().filter_map(|id| { + gen_mod(ctx, *id, links, span.clone()) })); - - ast::Mod { - inner: span, - items: globals, + 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::ItemMod(ast::Mod { + inner: span, + items: globals, + }), + vis: ast::Public, + span: span.clone(), + })) + } else { + None } } fn gen_globals(mut ctx: &mut GenCtx, - current_module: ModuleId, links: &[(String, LinkType)], globs: &[Global]) -> Vec> { let uniq_globs = tag_dup_decl(globs); From 76506ce5b20da4aea9596110ac702fc8d48abe7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 10 Mar 2016 04:39:26 +0100 Subject: [PATCH 22/25] gen: Make the code generation usable for every type. There's just an edge case I've detected, and it's when we remove the instantiation of C, and another module uses it, because that means we only know of its existance in that other module. Probably we might want to use cursor_getSemanticParent to get the real class instead of the instantiated, but I'm not too confident about that. --- src/gen.rs | 121 ++++++++++++++++++++++++++++---------- src/lib.rs | 7 ++- src/parser.rs | 5 -- tests/headers/namespace.h | 25 +++++++- 4 files changed, 118 insertions(+), 40 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 4ef0c28ea8..c5ebbb651c 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -24,10 +24,16 @@ struct GenCtx<'r> { ext_cx: base::ExtCtxt<'r>, span: Span, module_map: ModuleMap, + enable_cxx_namespaces: bool, + current_module_id: ModuleId, } impl<'r> GenCtx<'r> { fn full_path_for_module(&self, id: ModuleId) -> Vec { + if !self.enable_cxx_namespaces { + return vec![]; + } + let mut ret = vec![]; let mut current_id = Some(id); @@ -37,6 +43,10 @@ impl<'r> GenCtx<'r> { 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 } @@ -232,12 +242,15 @@ fn gen_unmangle_method(ctx: &mut GenCtx, P(item) } -pub fn gen_mods(links: &[(String, LinkType)], mut map: ModuleMap, span: Span) -> Vec> { +pub fn gen_mods(links: &[(String, LinkType)], + map: ModuleMap, + enable_namespaces: bool, + span: Span) -> Vec> { // Create a dummy ExtCtxt. We only need this for string interning and that uses TLS. let mut features = Features::new(); features.allow_quote = true; let cfg = ExpansionConfig { - crate_name: "xxx".to_string(), + crate_name: "xxx".to_owned(), features: Some(&features), recursion_limit: 64, trace_mac: false, @@ -248,7 +261,10 @@ pub fn gen_mods(links: &[(String, LinkType)], mut map: ModuleMap, span: Span) -> ext_cx: base::ExtCtxt::new(sess, Vec::new(), cfg, &mut feature_gated_cfgs), span: span, module_map: map, + enable_cxx_namespaces: enable_namespaces, + current_module_id: ROOT_MODULE_ID, }; + ctx.ext_cx.bt_push(ExpnInfo { call_site: ctx.span, callee: NameAndSpan { @@ -259,6 +275,21 @@ pub fn gen_mods(links: &[(String, LinkType)], mut map: ModuleMap, span: Span) -> }); if let Some(root_mod) = gen_mod(&mut ctx, ROOT_MODULE_ID, links, span) { + if !ctx.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::ItemMod(ref root) => { + return root.items.clone() + } + _ => unreachable!(), + } + } + let root_export = P(ast::Item { ident: ctx.ext_cx.ident_of(""), attrs: vec![], @@ -321,6 +352,8 @@ fn gen_mod(mut ctx: &mut GenCtx, 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| { @@ -406,7 +439,7 @@ fn gen_globals(mut ctx: &mut GenCtx, }, GVar(vi) => { let v = vi.borrow(); - let ty = cty_to_rs(&mut ctx, &v.ty, v.is_const); + 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)); }, _ => { } @@ -695,9 +728,9 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> Vec> { fn mk_item(ctx: &mut GenCtx, name: &str, comment: &str, ty: &Type) -> P { let rust_name = rust_type_id(ctx, name); let rust_ty = if cty_is_translatable(ty) { - cty_to_rs(ctx, ty, true) + cty_to_rs(ctx, ty, true, true) } else { - cty_to_rs(ctx, &TVoid, true) + cty_to_rs(ctx, &TVoid, true, true) }; let base = ast::ItemTy( P(ast::Ty { @@ -742,7 +775,7 @@ fn comp_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec> { let layout = ci.layout; let members = &ci.members; - let args = &ci.args; + let template_args = &ci.args; let methodlist = &ci.methods; let mut fields = vec!(); let mut methods = vec!(); @@ -754,7 +787,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec Vec Vec Vec { ctx.ext_cx.ident_of(&ti.borrow().name) @@ -1128,7 +1164,7 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, layout: Layout, members: Vec ast::ImplItem { let input_type = type_for_bitfield_width(ctx, width); - let field_type = cty_to_rs(ctx, &field_type, false); + 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); @@ -1336,7 +1372,7 @@ fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &String, 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); + 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() { @@ -1521,7 +1557,7 @@ fn cvar_to_rs(ctx: &mut GenCtx, name: String, attrs.push(mk_link_name_attr(ctx, name)); } - let val_ty = P(cty_to_rs(ctx, ty, true)); + let val_ty = P(cty_to_rs(ctx, ty, true, true)); return P(ast::ForeignItem { ident: ctx.ext_cx.ident_of(&rust_name), @@ -1542,8 +1578,8 @@ fn cfuncty_to_rs(ctx: &mut GenCtx, TVoid => ast::DefaultReturn(ctx.span), // Disable references in returns for now TPtr(ref t, is_const, _, ref layout) => - ast::Return(P(cty_to_rs(ctx, &TPtr(t.clone(), is_const, false, layout.clone()), true))), - _ => ast::Return(P(cty_to_rs(ctx, rty, true))) + ast::Return(P(cty_to_rs(ctx, &TPtr(t.clone(), is_const, false, layout.clone()), true, true))), + _ => ast::Return(P(cty_to_rs(ctx, rty, true, true))) }; let mut unnamed: usize = 0; @@ -1563,8 +1599,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, _, ref l) => cty_to_rs(ctx, &TPtr(typ.clone(), false, false, l.clone()), true), - _ => cty_to_rs(ctx, t, true), + &TArray(ref typ, _, ref l) => cty_to_rs(ctx, &TPtr(typ.clone(), false, false, l.clone()), true, true), + _ => cty_to_rs(ctx, t, true, true), }); ast::Arg { @@ -1623,7 +1659,7 @@ fn cfunc_to_rs(ctx: &mut GenCtx, }); } -fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { +fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool, use_full_path: bool) -> ast::Ty { match ty { &TVoid => mk_ty(ctx, true, &["libc".to_owned(), "c_void".to_owned()]), &TInt(i, ref layout) => match i { @@ -1653,7 +1689,7 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { FDouble => mk_ty(ctx, false, &["f64".to_owned()]) }, &TPtr(ref t, is_const, _is_ref, _) => { - let id = cty_to_rs(ctx, &**t, allow_bool); + let id = cty_to_rs(ctx, &**t, allow_bool, use_full_path); /* if is_ref { mk_refty(ctx, &id, is_const) @@ -1663,7 +1699,7 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { // } }, &TArray(ref t, s, _) => { - let ty = cty_to_rs(ctx, &**t, allow_bool); + let ty = cty_to_rs(ctx, &**t, allow_bool, use_full_path); mk_arrty(ctx, &ty, s) }, &TFuncPtr(ref sig) => { @@ -1677,20 +1713,42 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { &TNamed(ref ti) => { let id = rust_type_id(ctx, &ti.borrow().name); - let mut path = ctx.full_path_for_module(ti.borrow().module_id); - path.push(id); - mk_ty(ctx, false, &path) + if use_full_path { + let mut path = ctx.full_path_for_module(ti.borrow().module_id); + path.push(id); + mk_ty(ctx, false, &path) + } else { + mk_ty(ctx, false, &[id]) + } }, &TComp(ref ci) => { let c = ci.borrow(); + let id = comp_name(c.kind, &c.name); + let args = c.args.iter().map(|gt| { - P(cty_to_rs(ctx, gt, allow_bool)) + P(cty_to_rs(ctx, gt, allow_bool, false)) }).collect(); - mk_ty_args(ctx, false, &[comp_name(c.kind, &c.name)], args) + + if use_full_path { + let mut path = ctx.full_path_for_module(c.module_id); + path.push(id); + mk_ty_args(ctx, false, &path, args) + } else { + mk_ty_args(ctx, false, &[id], args) + } + }, &TEnum(ref ei) => { let e = ei.borrow(); - mk_ty(ctx, false, &[enum_name(&e.name)]) + let id = enum_name(&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]) + } } } } @@ -1738,17 +1796,18 @@ fn mk_ty(ctx: &GenCtx, global: bool, segments: &[String]) -> ast::Ty { } fn mk_ty_args(ctx: &GenCtx, global: bool, segments: &[String], args: Vec>) -> ast::Ty { + let segment_count = segments.len(); let ty = ast::TyPath( 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), parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { lifetimes: vec!(), - types: OwnedSlice::from_vec(args.clone()), + types: OwnedSlice::from_vec(if i == segment_count - 1 { args.clone() } else { vec![] }), bindings: OwnedSlice::empty(), }), } diff --git a/src/lib.rs b/src/lib.rs index 0fc1cee4da..390c008338 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -152,11 +152,14 @@ impl Bindings { let span = span.unwrap_or(DUMMY_SP); - let root_module = try!(parse_headers(options, logger)); + let module_map = try!(parse_headers(options, logger)); let module = ast::Mod { inner: span, - items: gen::gen_mods(&options.links[..], root_module, span) + items: gen::gen_mods(&options.links[..], + module_map, + options.enable_cxx_namespaces, + span) }; Ok(Bindings { diff --git a/src/parser.rs b/src/parser.rs index 31cc137640..c598eb5f77 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5,7 +5,6 @@ use std::cell::RefCell; use std::ops::Deref; use std::rc::Rc; use std::path::Path; -use std::mem; use syntax::abi; @@ -46,10 +45,6 @@ impl<'a> ClangParserCtx<'a> { self.module_map.get(id).expect("Module not found!") } - fn module_mut(&mut self, id: &ModuleId) -> &mut Module { - self.module_map.get_mut(&id).expect("Module not found!") - } - fn current_module(&self) -> &Module { self.module(&self.current_module_id) } diff --git a/tests/headers/namespace.h b/tests/headers/namespace.h index 74bf0db64e..19e474636c 100644 --- a/tests/headers/namespace.h +++ b/tests/headers/namespace.h @@ -12,9 +12,30 @@ namespace { namespace empty {} void foo(); - - class A { + struct A { whatever::whatever_int_t b; + public: + int lets_hope_this_works(); }; } +template +class C: public A { + T m_c; +}; + + +template<> +class C; + + +namespace w { + + template + class D { + C m_c; + void wat(); + }; + + C foo(); +} From 4887f42af40ec7979554cb86120e1791dd454bbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 10 Mar 2016 05:15:53 +0100 Subject: [PATCH 23/25] Fix a corner case when a template was instantiated in another module. --- src/clang.rs | 4 ++-- src/parser.rs | 18 +++++++++++++++++- tests/headers/namespace.h | 2 ++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/clang.rs b/src/clang.rs index a75abe0328..7aad4f7e65 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -252,7 +252,7 @@ pub struct Type { impl Type { // common pub fn kind(&self) -> Enum_CXTypeKind { - return self.x.kind; + self.x.kind } pub fn declaration(&self) -> Cursor { @@ -340,7 +340,7 @@ impl Type { for i in 0..num { args.push(Type { x: clang_getArgType(self.x, i as c_uint) }); } - return args; + args } } diff --git a/src/parser.rs b/src/parser.rs index c598eb5f77..276ae9778f 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -129,7 +129,23 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { list } }; - let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Struct, vec!(), layout))); + + 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 + } + }).expect("Template class wasn't declared when parsing specialisation!") + }; + + let ci = Rc::new(RefCell::new(CompInfo::new(spelling, module_id, filename, comment, CompKind::Struct, vec!(), layout))); ci.borrow_mut().args = args; GCompDecl(ci) } diff --git a/tests/headers/namespace.h b/tests/headers/namespace.h index 19e474636c..d0e115ca09 100644 --- a/tests/headers/namespace.h +++ b/tests/headers/namespace.h @@ -38,4 +38,6 @@ namespace w { }; C foo(); + + C barr(); // <- This is the problematic one } From 7dbed756412b299bed2026cff6019fd4db808bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 10 Mar 2016 05:19:32 +0100 Subject: [PATCH 24/25] Added an example of the namespace resolution. --- tests/headers/namespace.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/headers/namespace.h b/tests/headers/namespace.h index d0e115ca09..055e725837 100644 --- a/tests/headers/namespace.h +++ b/tests/headers/namespace.h @@ -30,13 +30,15 @@ class C; namespace w { + typedef unsigned int whatever_int_t; template class D { C m_c; - void wat(); }; + whatever_int_t heh(); // this should return w::whatever_int_t, and not whatever::whatever_int_t + C foo(); C barr(); // <- This is the problematic one From 87210ea5cba09383a43b2b79163efa9d9bde25a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 10 Mar 2016 05:27:21 +0100 Subject: [PATCH 25/25] Don't panic when not finding the specialised template This can be annoying if filtering files out. --- src/parser.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/parser.rs b/src/parser.rs index 276ae9778f..9e8a07915b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -142,7 +142,10 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { } else { None } - }).expect("Template class wasn't declared when parsing specialisation!") + }).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)));