summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbindgen/src/clang.rs13
-rw-r--r--libbindgen/src/ir/comp.rs18
-rw-r--r--libbindgen/src/ir/context.rs6
-rw-r--r--libbindgen/src/ir/item.rs23
-rw-r--r--libbindgen/src/ir/ty.rs2
-rw-r--r--libbindgen/src/lib.rs23
-rw-r--r--libbindgen/tests/expectations/tests/disable-namespacing.rs7
-rw-r--r--libbindgen/tests/expectations/tests/nested_within_namespace.rs53
-rw-r--r--libbindgen/tests/headers/disable-namespacing.hpp9
-rw-r--r--libbindgen/tests/headers/nested_within_namespace.hpp15
-rw-r--r--src/options.rs7
11 files changed, 159 insertions, 17 deletions
diff --git a/libbindgen/src/clang.rs b/libbindgen/src/clang.rs
index 72069644..7c6d3199 100644
--- a/libbindgen/src/clang.rs
+++ b/libbindgen/src/clang.rs
@@ -760,6 +760,19 @@ impl Type {
pub fn is_valid_and_exposed(&self) -> bool {
self.is_valid() && self.kind() != CXType_Unexposed
}
+
+ /// Is this type a fully specialized template?
+ pub fn is_fully_specialized_template(&self) -> bool {
+ // Yep, the spelling of this containing type-parameter is extremely
+ // nasty... But can happen in <type_traits>. Unfortunately I couldn't
+ // reduce it enough :(
+ !self.spelling().contains("type-parameter") &&
+ self.template_args()
+ .map_or(false, |mut args| {
+ args.len() > 0 &&
+ !args.any(|t| t.spelling().contains("type-parameter"))
+ })
+ }
}
/// An iterator for a type's template arguments.
diff --git a/libbindgen/src/ir/comp.rs b/libbindgen/src/ir/comp.rs
index d19d1209..d2ace023 100644
--- a/libbindgen/src/ir/comp.rs
+++ b/libbindgen/src/ir/comp.rs
@@ -498,17 +498,29 @@ impl CompInfo {
None => vec![],
Some(arg_types) => {
let num_arg_types = arg_types.len();
+ let mut specialization = true;
let args = arg_types.filter(|t| t.kind() != CXType_Invalid)
- .map(|t| Item::from_ty_or_ref(t, None, None, ctx))
+ .filter_map(|t| {
+ if t.spelling().starts_with("type-parameter") {
+ specialization = false;
+ None
+ } else {
+ Some(Item::from_ty_or_ref(t, None, None, ctx))
+ }
+ })
.collect::<Vec<_>>();
- if args.len() != num_arg_types {
+ if specialization && args.len() != num_arg_types {
ci.has_non_type_template_params = true;
warn!("warning: Template parameter is not a type");
}
- args
+ if specialization {
+ args
+ } else {
+ vec![]
+ }
}
};
diff --git a/libbindgen/src/ir/context.rs b/libbindgen/src/ir/context.rs
index 67db2a59..a0e57610 100644
--- a/libbindgen/src/ir/context.rs
+++ b/libbindgen/src/ir/context.rs
@@ -367,10 +367,8 @@ impl<'ctx> BindgenContext<'ctx> {
_ => continue,
}
- let name = item.real_canonical_name(self,
- self.options()
- .enable_cxx_namespaces,
- true);
+ let in_namespace = self.options().enable_cxx_namespaces;
+ let name = item.real_canonical_name(self, in_namespace, true);
let replacement = self.replacements.get(&name);
if let Some(replacement) = replacement {
diff --git a/libbindgen/src/ir/item.rs b/libbindgen/src/ir/item.rs
index 1f15ff0f..1d643a45 100644
--- a/libbindgen/src/ir/item.rs
+++ b/libbindgen/src/ir/item.rs
@@ -688,14 +688,14 @@ impl Item {
return base_name;
}
- if within_namespace {
- return ctx.rust_mangle(&base_name).into_owned();
- }
-
// Concatenate this item's ancestors' names together.
let mut names: Vec<_> = target.parent_id()
.ancestors(ctx)
.filter(|id| *id != ctx.root_module())
+ .take_while(|id| {
+ // Stop iterating ancestors once we reach a namespace.
+ !within_namespace || !ctx.resolve_item(*id).is_module()
+ })
.map(|id| {
let item = ctx.resolve_item(id);
let target = ctx.resolve_item(item.name_target(ctx, false));
@@ -703,8 +703,13 @@ impl Item {
})
.filter(|name| !name.is_empty())
.collect();
+
names.reverse();
- names.push(base_name);
+
+ if !base_name.is_empty() {
+ names.push(base_name);
+ }
+
let name = names.join("_");
ctx.rust_mangle(&name).into_owned()
@@ -1152,11 +1157,11 @@ impl ItemCanonicalName for Item {
debug_assert!(ctx.in_codegen_phase(),
"You're not supposed to call this yet");
if self.canonical_name_cache.borrow().is_none() {
+ let in_namespace = ctx.options().enable_cxx_namespaces ||
+ ctx.options().disable_name_namespacing;
+
*self.canonical_name_cache.borrow_mut() =
- Some(self.real_canonical_name(ctx,
- ctx.options()
- .enable_cxx_namespaces,
- false));
+ Some(self.real_canonical_name(ctx, in_namespace, false));
}
return self.canonical_name_cache.borrow().as_ref().unwrap().clone();
}
diff --git a/libbindgen/src/ir/ty.rs b/libbindgen/src/ir/ty.rs
index 7f01e388..33e20861 100644
--- a/libbindgen/src/ir/ty.rs
+++ b/libbindgen/src/ir/ty.rs
@@ -554,7 +554,7 @@ impl Type {
TypeKind::Function(signature)
// Same here, with template specialisations we can safely
// assume this is a Comp(..)
- } else if ty.template_args().map_or(false, |x| x.len() > 0) {
+ } else if ty.is_fully_specialized_template() {
debug!("Template specialization: {:?}", ty);
let complex =
CompInfo::from_ty(potential_id, ty, location, ctx)
diff --git a/libbindgen/src/lib.rs b/libbindgen/src/lib.rs
index 10961e36..f25c6cdf 100644
--- a/libbindgen/src/lib.rs
+++ b/libbindgen/src/lib.rs
@@ -243,6 +243,25 @@ impl Builder {
self
}
+ /// Disable auto-namespacing of names if namespaces are disabled.
+ ///
+ /// By default, if namespaces are disabled, bindgen tries to mangle the
+ /// names to from `foo::bar::Baz` to look like `foo_bar_Baz`, instead of
+ /// just `Baz`.
+ ///
+ /// This option disables that behavior.
+ ///
+ /// Note that this intentionally doesn't change the names using for
+ /// whitelisting and blacklisting, that should still be mangled with the
+ /// namespaces.
+ ///
+ /// Note, also, that using this option may cause duplicated names to be
+ /// generated.
+ pub fn disable_name_namespacing(mut self) -> Builder {
+ self.options.disable_name_namespacing = true;
+ self
+ }
+
/// Ignore functions.
pub fn ignore_functions(mut self) -> Builder {
self.options.ignore_functions = true;
@@ -341,6 +360,9 @@ pub struct BindgenOptions {
/// generated bindings.
pub enable_cxx_namespaces: bool,
+ /// True if we should avoid mangling names with namespaces.
+ pub disable_name_namespacing: bool,
+
/// True if we shold derive Debug trait implementations for C/C++ structures
/// and types.
pub derive_debug: bool,
@@ -400,6 +422,7 @@ impl Default for BindgenOptions {
ignore_methods: false,
derive_debug: true,
enable_cxx_namespaces: false,
+ disable_name_namespacing: false,
unstable_rust: true,
use_core: false,
ctypes_prefix: None,
diff --git a/libbindgen/tests/expectations/tests/disable-namespacing.rs b/libbindgen/tests/expectations/tests/disable-namespacing.rs
new file mode 100644
index 00000000..5c166946
--- /dev/null
+++ b/libbindgen/tests/expectations/tests/disable-namespacing.rs
@@ -0,0 +1,7 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+pub type Baz = ::std::os::raw::c_int;
diff --git a/libbindgen/tests/expectations/tests/nested_within_namespace.rs b/libbindgen/tests/expectations/tests/nested_within_namespace.rs
new file mode 100644
index 00000000..949b5adb
--- /dev/null
+++ b/libbindgen/tests/expectations/tests/nested_within_namespace.rs
@@ -0,0 +1,53 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+pub mod root {
+ #[allow(unused_imports)]
+ use root;
+ pub mod foo {
+ #[allow(unused_imports)]
+ use root;
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct Bar {
+ pub foo: ::std::os::raw::c_int,
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct Bar_Baz {
+ pub foo: ::std::os::raw::c_int,
+ }
+ #[test]
+ fn bindgen_test_layout_Bar_Baz() {
+ assert_eq!(::std::mem::size_of::<Bar_Baz>() , 4usize);
+ assert_eq!(::std::mem::align_of::<Bar_Baz>() , 4usize);
+ }
+ impl Clone for Bar_Baz {
+ fn clone(&self) -> Self { *self }
+ }
+ #[test]
+ fn bindgen_test_layout_Bar() {
+ assert_eq!(::std::mem::size_of::<Bar>() , 4usize);
+ assert_eq!(::std::mem::align_of::<Bar>() , 4usize);
+ }
+ impl Clone for Bar {
+ fn clone(&self) -> Self { *self }
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy)]
+ pub struct Baz {
+ pub baz: ::std::os::raw::c_int,
+ }
+ #[test]
+ fn bindgen_test_layout_Baz() {
+ assert_eq!(::std::mem::size_of::<Baz>() , 4usize);
+ assert_eq!(::std::mem::align_of::<Baz>() , 4usize);
+ }
+ impl Clone for Baz {
+ fn clone(&self) -> Self { *self }
+ }
+ }
+}
diff --git a/libbindgen/tests/headers/disable-namespacing.hpp b/libbindgen/tests/headers/disable-namespacing.hpp
new file mode 100644
index 00000000..11191361
--- /dev/null
+++ b/libbindgen/tests/headers/disable-namespacing.hpp
@@ -0,0 +1,9 @@
+// bindgen-flags: --disable-name-namespacing
+
+namespace foo {
+namespace bar {
+
+typedef int Baz;
+
+}
+}
diff --git a/libbindgen/tests/headers/nested_within_namespace.hpp b/libbindgen/tests/headers/nested_within_namespace.hpp
new file mode 100644
index 00000000..a9b7c1ec
--- /dev/null
+++ b/libbindgen/tests/headers/nested_within_namespace.hpp
@@ -0,0 +1,15 @@
+// bindgen-flags: --enable-cxx-namespaces
+
+namespace foo {
+ class Bar {
+ int foo;
+
+ class Baz {
+ int foo;
+ };
+ };
+
+ class Baz {
+ int baz;
+ };
+}
diff --git a/src/options.rs b/src/options.rs
index 2ea74a27..9632619f 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -58,6 +58,9 @@ pub fn builder_from_flags<I>(args: I)
Arg::with_name("enable-cxx-namespaces")
.long("enable-cxx-namespaces")
.help("Enable support for C++ namespaces."),
+ Arg::with_name("disable-name-namespacing")
+ .long("disable-name-namespacing")
+ .help("Disable name namespacing if namespaces are disabled."),
Arg::with_name("framework")
.long("framework-link")
.help("Link to framework.")
@@ -194,6 +197,10 @@ pub fn builder_from_flags<I>(args: I)
builder = builder.enable_cxx_namespaces();
}
+ if matches.is_present("disable-name-namespacing") {
+ builder = builder.disable_name_namespacing();
+ }
+
if let Some(links) = matches.values_of("framework") {
for framework in links {
builder = builder.link_framework(framework);