summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <ecoal95@gmail.com>2016-11-14 22:15:23 +0100
committerEmilio Cobos Álvarez <ecoal95@gmail.com>2016-11-15 10:31:43 +0100
commit2003f9c82245a67ed28ae1c9c1ec24cc5b07fa7e (patch)
treeaac367d056f759aaa039379fef8b06d4e6dfe0bc
parent004a19537f1f40e77aacdc13a2f56a8553e63dc9 (diff)
ir: Explicitly discard specialized templated type aliases as already resolved.
-rwxr-xr-xsrc/clang.rs23
-rw-r--r--src/ir/context.rs107
-rw-r--r--tests/expectations/tests/type_alias_partial_template_especialization.rs12
-rw-r--r--tests/expectations/tests/type_alias_template_specialized.rs19
-rw-r--r--tests/headers/type_alias_partial_template_especialization.hpp7
-rw-r--r--tests/headers/type_alias_template_specialized.hpp9
6 files changed, 135 insertions, 42 deletions
diff --git a/src/clang.rs b/src/clang.rs
index 385fd09a..7da755ea 100755
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -317,6 +317,24 @@ impl Cursor {
}
}
+ /// Returns whether the given location contains a cursor with the given
+ /// kind in the first level of nesting underneath (doesn't look
+ /// recursively).
+ pub fn contains_cursor(&self, kind: Enum_CXCursorKind) -> bool {
+ let mut found = false;
+
+ self.visit(|c| {
+ if c.kind() == kind {
+ found = true;
+ CXChildVisit_Break
+ } else {
+ CXChildVisit_Continue
+ }
+ });
+
+ found
+ }
+
/// Is the referent an inlined function?
#[cfg(not(feature="llvm_stable"))]
pub fn is_inlined_function(&self) -> bool {
@@ -721,6 +739,11 @@ impl Type {
pub fn is_valid(&self) -> bool {
self.kind() != CXType_Invalid
}
+
+ /// Is this a valid and exposed type?
+ pub fn is_valid_and_exposed(&self) -> bool {
+ self.is_valid() && self.kind() != CXType_Unexposed
+ }
}
/// An iterator for a type's template arguments.
diff --git a/src/ir/context.rs b/src/ir/context.rs
index c7949bef..1b446ace 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -499,16 +499,12 @@ impl<'ctx> BindgenContext<'ctx> {
wrapping: ItemId,
parent_id: ItemId,
ty: &clang::Type,
- location: clang::Cursor)
+ location: clang::Cursor,
+ declaration: clang::Cursor)
-> ItemId {
use clangll::*;
let mut args = vec![];
- let mut found_invalid_template_ref = false;
location.visit(|c| {
- if c.kind() == CXCursor_TemplateRef &&
- c.cur_type().kind() == CXType_Invalid {
- found_invalid_template_ref = true;
- }
if c.kind() == CXCursor_TypeRef {
// The `with_id` id will potentially end up unused if we give up
// on this type (for example, its a tricky partial template
@@ -527,39 +523,46 @@ impl<'ctx> BindgenContext<'ctx> {
let item = {
let wrapping_type = self.resolve_type(wrapping);
- let old_args = match *wrapping_type.kind() {
- TypeKind::Comp(ref ci) => ci.template_args(),
- _ => panic!("how?"),
- };
- // The following assertion actually fails with partial template
- // specialization. But as far as I know there's no way at all to
- // grab the specialized types from neither the AST or libclang.
- //
- // This flaw was already on the old parser, but I now think it has
- // no clear solution.
- //
- // For an easy example in which there's no way at all of getting the
- // `int` type, except manually parsing the spelling:
- //
- // template<typename T, typename U>
- // class Incomplete {
- // T d;
- // U p;
- // };
- //
- // template<typename U>
- // class Foo {
- // Incomplete<U, int> bar;
- // };
- //
- // debug_assert_eq!(old_args.len(), args.len());
- //
- // That being said, this is not so common, so just error! and hope
- // for the best, returning the previous type, who knows.
- if old_args.len() != args.len() {
- error!("Found partial template specialization, \
- expect dragons!");
- return wrapping;
+ if let TypeKind::Comp(ref ci) = *wrapping_type.kind() {
+ let old_args = ci.template_args();
+
+ // The following assertion actually fails with partial template
+ // specialization. But as far as I know there's no way at all to
+ // grab the specialized types from neither the AST or libclang,
+ // which sucks. The same happens for specialized type alias
+ // template declarations, where we have that ugly hack up there.
+ //
+ // This flaw was already on the old parser, but I now think it
+ // has no clear solution (apart from patching libclang to
+ // somehow expose them, of course).
+ //
+ // For an easy example in which there's no way at all of getting
+ // the `int` type, except manually parsing the spelling:
+ //
+ // template<typename T, typename U>
+ // class Incomplete {
+ // T d;
+ // U p;
+ // };
+ //
+ // template<typename U>
+ // class Foo {
+ // Incomplete<U, int> bar;
+ // };
+ //
+ // debug_assert_eq!(old_args.len(), args.len());
+ //
+ // That being said, this is not so common, so just error! and
+ // hope for the best, returning the previous type, who knows.
+ if old_args.len() != args.len() {
+ error!("Found partial template specialization, \
+ expect dragons!");
+ return wrapping;
+ }
+ } else {
+ assert_eq!(declaration.kind(),
+ ::clangll::CXCursor_TypeAliasTemplateDecl,
+ "Expected wrappable type");
}
let type_kind = TypeKind::TemplateRef(wrapping, args);
@@ -586,7 +589,9 @@ impl<'ctx> BindgenContext<'ctx> {
location: Option<clang::Cursor>)
-> Option<ItemId> {
use clangll::{CXCursor_ClassTemplate,
- CXCursor_ClassTemplatePartialSpecialization};
+ CXCursor_ClassTemplatePartialSpecialization,
+ CXCursor_TypeAliasTemplateDecl,
+ CXCursor_TypeRef};
debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}",
ty,
location,
@@ -630,15 +635,33 @@ impl<'ctx> BindgenContext<'ctx> {
// argument names don't matter in the global context.
if (declaration.kind() == CXCursor_ClassTemplate ||
declaration.kind() ==
- CXCursor_ClassTemplatePartialSpecialization) &&
+ CXCursor_ClassTemplatePartialSpecialization ||
+ declaration.kind() == CXCursor_TypeAliasTemplateDecl) &&
*ty != canonical_declaration.cur_type() &&
location.is_some() &&
parent_id.is_some() {
+ // For specialized type aliases, there's no way to get the
+ // template parameters as of this writing (for a struct
+ // specialization we wouldn't be in this branch anyway).
+ //
+ // Explicitly return `None` if there aren't any
+ // unspecialized parameters (contains any `TypeRef`) so we
+ // resolve the canonical type if there is one and it's
+ // exposed.
+ //
+ // This is _tricky_, I know :(
+ if declaration.kind() == CXCursor_TypeAliasTemplateDecl &&
+ !location.unwrap().contains_cursor(CXCursor_TypeRef) &&
+ ty.canonical_type().is_valid_and_exposed() {
+ return None;
+ }
+
return Some(self.build_template_wrapper(with_id,
id,
parent_id.unwrap(),
ty,
- location.unwrap()));
+ location.unwrap(),
+ declaration));
}
return Some(self.build_ty_wrapper(with_id, id, parent_id, ty));
diff --git a/tests/expectations/tests/type_alias_partial_template_especialization.rs b/tests/expectations/tests/type_alias_partial_template_especialization.rs
new file mode 100644
index 00000000..70b5f66c
--- /dev/null
+++ b/tests/expectations/tests/type_alias_partial_template_especialization.rs
@@ -0,0 +1,12 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+pub type MaybeWrapped<A> = A;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Rooted<T> {
+ pub ptr: MaybeWrapped<T>,
+}
diff --git a/tests/expectations/tests/type_alias_template_specialized.rs b/tests/expectations/tests/type_alias_template_specialized.rs
new file mode 100644
index 00000000..989f2015
--- /dev/null
+++ b/tests/expectations/tests/type_alias_template_specialized.rs
@@ -0,0 +1,19 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy)]
+pub struct Rooted {
+ pub ptr: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_Rooted() {
+ assert_eq!(::std::mem::size_of::<Rooted>() , 4usize);
+ assert_eq!(::std::mem::align_of::<Rooted>() , 4usize);
+}
+impl Clone for Rooted {
+ fn clone(&self) -> Self { *self }
+}
diff --git a/tests/headers/type_alias_partial_template_especialization.hpp b/tests/headers/type_alias_partial_template_especialization.hpp
new file mode 100644
index 00000000..dfc36786
--- /dev/null
+++ b/tests/headers/type_alias_partial_template_especialization.hpp
@@ -0,0 +1,7 @@
+// bindgen-flags: -- -std=c++14
+template <typename A> using MaybeWrapped = A;
+
+template<class T>
+class Rooted {
+ MaybeWrapped<T> ptr;
+};
diff --git a/tests/headers/type_alias_template_specialized.hpp b/tests/headers/type_alias_template_specialized.hpp
new file mode 100644
index 00000000..a2d32b56
--- /dev/null
+++ b/tests/headers/type_alias_template_specialized.hpp
@@ -0,0 +1,9 @@
+// bindgen-flags: --whitelist-type Rooted -- -std=c++14
+
+template <typename a> using MaybeWrapped = a;
+class Rooted {
+ MaybeWrapped<int> ptr;
+};
+
+/// <div rustbindgen replaces="MaybeWrapped"></div>
+template <typename a> using replaces_MaybeWrapped = a;