summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-10-18 09:07:42 -0500
committerGitHub <noreply@github.com>2016-10-18 09:07:42 -0500
commitab6c4384624f170d4a2adc62ecacb94535a9e72d (patch)
tree464ad46f18cdc2977291bcb161d0060184767fde
parentb162e9209dd0eaaf84538fc1cb1cdf6bb1d1669f (diff)
parent2a3f93074dd2898669dbbce6e97e5cc4405d7cb1 (diff)
Auto merge of #85 - emilio:template-alias, r=nox
Handle templated aliases. Fixes #83. cc @fitzgen r? @nox
-rw-r--r--src/clang.rs4
-rw-r--r--src/clangll.rs5
-rw-r--r--src/codegen/mod.rs8
-rw-r--r--src/ir/item.rs79
-rw-r--r--src/ir/ty.rs68
-rw-r--r--tests/expectations/template_alias.rs12
-rw-r--r--tests/expectations/template_alias_basic.rs7
-rw-r--r--tests/expectations/template_alias_namespace.rs21
-rw-r--r--tests/expectations/template_typedef_transitive_param.rs18
-rw-r--r--tests/headers/template_alias.hpp13
-rw-r--r--tests/headers/template_alias_basic.hpp4
-rw-r--r--tests/headers/template_alias_namespace.hpp13
-rw-r--r--tests/headers/template_typedef_transitive_param.hpp7
13 files changed, 241 insertions, 18 deletions
diff --git a/src/clang.rs b/src/clang.rs
index e5943b6f..de405c9d 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -1050,7 +1050,9 @@ pub fn kind_to_str(x: Enum_CXCursorKind) -> &'static str {
//CXCursor_FirstPreprocessing => "FirstPreprocessing",
//CXCursor_LastPreprocessing => "LastPreprocessing",
CXCursor_PackedAttr => "PackedAttr",
-
+ CXCursor_ModuleImportDecl => "ModuleImportDecl",
+ CXCursor_TypeAliasTemplateDecl => "TypeAliasTemplateDecl",
+ CXCursor_StaticAssert => "StaticAssert",
_ => "?",
}
}
diff --git a/src/clangll.rs b/src/clangll.rs
index 47f41ff1..272fa574 100644
--- a/src/clangll.rs
+++ b/src/clangll.rs
@@ -313,8 +313,11 @@ pub const CXCursor_InclusionDirective: c_uint = 503;
pub const CXCursor_FirstPreprocessing: c_uint = 500;
pub const CXCursor_LastPreprocessing: c_uint = 503;
pub const CXCursor_ModuleImportDecl: c_uint = 600;
+pub const CXCursor_TypeAliasTemplateDecl: c_uint = 601;
+pub const CXCursor_StaticAssert: c_uint = 602;
pub const CXCursor_FirstExtraDecl: c_uint = 600;
-pub const CXCursor_LastExtraDecl: c_uint = 600;
+pub const CXCursor_LastExtraDecl: c_uint = 602;
+pub const CXCursor_OverloadCandidate: c_uint = 700;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CXCursor {
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 4ebc48bf..a5159c98 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -341,6 +341,12 @@ impl CodeGenerator for Type {
return;
}
TypeKind::Comp(ref ci) => ci.codegen(ctx, result, item),
+ TypeKind::TemplateAlias(inner, _) => {
+ // NB: The inner Alias will pick the correct
+ // applicable_template_args.
+ let inner_item = ctx.resolve_item(inner);
+ inner_item.expect_type().codegen(ctx, result, inner_item);
+ }
TypeKind::Alias(ref spelling, inner) => {
let inner_item = ctx.resolve_item(inner);
let name = item.canonical_name(ctx);
@@ -1361,6 +1367,7 @@ impl ToRustTy for Type {
let path = item.canonical_path(ctx);
aster::AstBuilder::new().ty().path().ids(path).build()
}
+ TypeKind::TemplateAlias(inner, ref template_args) |
TypeKind::TemplateRef(inner, ref template_args) => {
// PS: Sorry for the duplication here.
let mut inner_ty = inner.to_rust_ty(ctx).unwrap();
@@ -1618,6 +1625,7 @@ impl TypeCollector for Type {
TypeKind::Pointer(inner) |
TypeKind::Reference(inner) |
TypeKind::Array(inner, _) |
+ TypeKind::TemplateAlias(inner, _) |
TypeKind::Alias(_, inner) |
TypeKind::Named(_, Some(inner)) |
TypeKind::ResolvedTypeRef(inner)
diff --git a/src/ir/item.rs b/src/ir/item.rs
index 56ddf639..5b6297bd 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -167,6 +167,20 @@ impl Item {
self.kind().expect_function()
}
+ // This check is needed because even though the type might not contain the
+ // applicable template args itself, they might apply transitively via, for
+ // example, the parent.
+ //
+ // It's kind of unfortunate (in the sense that it's a sort of complex
+ // process, but I think it gets all the cases).
+ fn signature_contains_named_type(&self, ctx: &BindgenContext, ty: &Type) -> bool {
+ debug_assert!(ty.is_named());
+ self.expect_type().signature_contains_named_type(ctx, ty) ||
+ self.applicable_template_args(ctx).iter().any(|template| {
+ ctx.resolve_type(*template).signature_contains_named_type(ctx, ty)
+ })
+ }
+
pub fn applicable_template_args(&self, ctx: &BindgenContext) -> Vec<ItemId> {
let ty = match *self.kind() {
ItemKind::Type(ref ty) => ty,
@@ -197,7 +211,8 @@ impl Item {
TypeKind::Alias(_, inner) => {
let parent_args = ctx.resolve_item(self.parent_id())
.applicable_template_args(ctx);
- let inner = ctx.resolve_type(inner);
+ let inner = ctx.resolve_item(inner);
+
// Avoid unused type parameters, sigh.
parent_args.iter().cloned().filter(|arg| {
let arg = ctx.resolve_type(*arg);
@@ -206,6 +221,7 @@ impl Item {
}
// XXX Is this completely correct? Partial template specialization
// is hard anyways, sigh...
+ TypeKind::TemplateAlias(_, ref args) |
TypeKind::TemplateRef(_, ref args) => {
args.clone()
}
@@ -247,19 +263,22 @@ impl Item {
debug_assert!(ctx.in_codegen_phase(),
"You're not supposed to call this yet");
self.annotations.hide() ||
- ctx.hidden_by_name(&self.real_canonical_name(ctx, false), self.id)
+ ctx.hidden_by_name(&self.real_canonical_name(ctx, false, true), self.id)
}
pub fn is_opaque(&self, ctx: &BindgenContext) -> bool {
debug_assert!(ctx.in_codegen_phase(),
"You're not supposed to call this yet");
self.annotations.opaque() ||
- ctx.opaque_by_name(&self.real_canonical_name(ctx, false))
+ ctx.opaque_by_name(&self.real_canonical_name(ctx, false, true))
}
/// Get the canonical name without taking into account the replaces
/// annotation.
- fn real_canonical_name(&self, ctx: &BindgenContext, count_namespaces: bool) -> String {
+ fn real_canonical_name(&self,
+ ctx: &BindgenContext,
+ count_namespaces: bool,
+ for_name_checking: bool) -> String {
let base_name = match *self.kind() {
ItemKind::Type(ref ty) => {
match *ty.kind() {
@@ -277,11 +296,29 @@ impl Item {
TypeKind::Named(ref name, _) => {
return name.to_owned();
}
- _ => {}
- }
-
- ty.name().map(ToOwned::to_owned)
- .unwrap_or_else(|| format!("_bindgen_ty{}", self.id()))
+ // We call codegen on the inner type, but we do not want
+ // this alias's name to appear in the canonical name just
+ // because it is in the inner type's parent chain, so we use
+ // an empty base name.
+ //
+ // Note that this would be incorrect if this type could be
+ // referenced from, let's say, a member variable, but in
+ // that case the referenced type is the inner alias, so
+ // we're good there. If we wouldn't, a more complex solution
+ // would be needed.
+ TypeKind::TemplateAlias(inner, _) => {
+ if for_name_checking {
+ return ctx.resolve_item(inner).real_canonical_name(ctx, count_namespaces, false);
+ }
+ Some("")
+ }
+ // Else use the proper name, or fallback to a name with an
+ // id.
+ _ => {
+ ty.name()
+ }
+ }.map(ToOwned::to_owned)
+ .unwrap_or_else(|| format!("_bindgen_ty{}", self.id()))
}
ItemKind::Function(ref fun) => {
let mut base = fun.name().to_owned();
@@ -329,7 +366,12 @@ impl Item {
// TODO: allow modification of the mangling functions, maybe even per
// item type?
- format!("{}_{}", parent.canonical_name(ctx), base_name)
+ let parent = parent.canonical_name(ctx);
+ if parent.is_empty() {
+ base_name.to_owned()
+ } else {
+ format!("{}_{}", parent, base_name)
+ }
}
pub fn as_module_mut(&mut self) -> Option<&mut Module> {
@@ -444,7 +486,7 @@ impl ClangItemParser for Item {
if cursor.kind() == clangll::CXCursor_UnexposedDecl {
Err(ParseError::Recurse)
} else {
- error!("Unhandled cursor kind: {}", ::clang::kind_to_str(cursor.kind()));
+ error!("Unhandled cursor kind: {} ({})", ::clang::kind_to_str(cursor.kind()), cursor.kind());
Err(ParseError::Continue)
}
}
@@ -661,7 +703,7 @@ impl ItemCanonicalName for Item {
if let Some(other_canon_type) = self.annotations.use_instead_of() {
return other_canon_type.to_owned();
}
- self.real_canonical_name(ctx, ctx.options().enable_cxx_namespaces)
+ self.real_canonical_name(ctx, ctx.options().enable_cxx_namespaces, false)
}
}
@@ -698,7 +740,18 @@ impl ItemCanonicalPath for Item {
}
let mut parent_path = self.parent_id().canonical_path(&ctx);
- parent_path.push(self.real_canonical_name(ctx, true));
+ if parent_path.last().map_or(false, |parent_name| parent_name.is_empty()) {
+ // This only happens (or should only happen) when we're an alias,
+ // and our parent is a templated alias, in which case the last
+ // component of the path will be empty.
+ let is_alias = match *self.expect_type().kind() {
+ TypeKind::Alias(..) => true,
+ _ => false,
+ };
+ debug_assert!(is_alias, "How can this ever happen?");
+ parent_path.pop().unwrap();
+ }
+ parent_path.push(self.real_canonical_name(ctx, true, false));
parent_path
}
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index bae2fd88..0cf8174e 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -146,13 +146,14 @@ impl Type {
type_resolver.resolve_type(t).can_derive_debug(type_resolver)
}
TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(_, t) => {
type_resolver.resolve_type(t).can_derive_debug(type_resolver)
}
TypeKind::Comp(ref info) => {
info.can_derive_debug(type_resolver, self.layout(type_resolver))
}
- _ => true,
+ _ => true,
}
}
@@ -177,6 +178,7 @@ impl Type {
pub fn can_derive_copy_in_array(&self, type_resolver: &BindgenContext, item: &Item) -> bool {
match self.kind {
TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(_, t) |
TypeKind::Array(t, _) => {
type_resolver.resolve_item(t)
@@ -194,6 +196,7 @@ impl Type {
type_resolver.resolve_item(t).can_derive_copy_in_array(type_resolver)
}
TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
TypeKind::TemplateRef(t, _) |
TypeKind::Alias(_, t) => {
type_resolver.resolve_item(t).can_derive_copy(type_resolver)
@@ -209,6 +212,7 @@ impl Type {
// FIXME: Can we do something about template parameters? Huh...
match self.kind {
TypeKind::TemplateRef(t, _) |
+ TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(_, t) |
TypeKind::ResolvedTypeRef(t) |
TypeKind::Array(t, _) => {
@@ -225,6 +229,7 @@ impl Type {
pub fn has_destructor(&self, type_resolver: &BindgenContext) -> bool {
self.is_opaque(type_resolver) || match self.kind {
TypeKind::TemplateRef(t, _) |
+ TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(_, t) |
TypeKind::ResolvedTypeRef(t) |
TypeKind::Array(t, _) => {
@@ -263,7 +268,8 @@ impl Type {
type_resolver.resolve_type(sig.return_type())
.signature_contains_named_type(type_resolver, ty)
},
- TypeKind::TemplateRef(_inner, ref template_args) => {
+ TypeKind::TemplateAlias(_, ref template_args) |
+ TypeKind::TemplateRef(_, ref template_args) => {
template_args.iter().any(|arg| {
type_resolver.resolve_type(*arg)
.signature_contains_named_type(type_resolver, ty)
@@ -292,6 +298,7 @@ impl Type {
TypeKind::ResolvedTypeRef(inner) |
TypeKind::Alias(_, inner) |
+ TypeKind::TemplateAlias(inner, _) |
TypeKind::TemplateRef(inner, _)
=> type_resolver.resolve_type(inner).canonical_type(type_resolver),
@@ -327,6 +334,9 @@ pub enum TypeKind {
Float(FloatKind),
/// A type alias, with a name, that points to another type.
Alias(String, ItemId),
+ /// A templated alias, pointing to an inner Alias type, with template
+ /// parameters.
+ TemplateAlias(ItemId, Vec<ItemId>),
/// An array of a type and a lenght.
Array(ItemId, usize),
/// A function type, with a given signature.
@@ -371,6 +381,7 @@ impl Type {
}
TypeKind::ResolvedTypeRef(inner) |
TypeKind::Alias(_, inner) |
+ TypeKind::TemplateAlias(inner, _) |
TypeKind::TemplateRef(inner, _)
=> type_resolver.resolve_type(inner).is_unsized(type_resolver),
TypeKind::Named(..) |
@@ -444,6 +455,57 @@ impl Type {
.expect("C'mon");
TypeKind::Comp(complex)
}
+ CXCursor_TypeAliasTemplateDecl => {
+ debug!("TypeAliasTemplateDecl");
+
+ // We need to manually unwind this one.
+ let mut inner = Err(ParseError::Continue);
+ let mut args = vec![];
+
+ location.visit(|cur, _| {
+ match cur.kind() {
+ CXCursor_TypeAliasDecl => {
+ debug_assert!(cur.cur_type().kind() == CXType_Typedef);
+ inner = Item::from_ty(&cur.cur_type(),
+ Some(*cur),
+ Some(potential_id),
+ ctx);
+ }
+ CXCursor_TemplateTypeParameter => {
+ // See the comment in src/ir/comp.rs
+ // about the same situation.
+ if cur.spelling().is_empty() {
+ return CXChildVisit_Continue;
+ }
+
+ let default_type =
+ Item::from_ty(&cur.cur_type(),
+ Some(*cur),
+ Some(potential_id),
+ ctx).ok();
+ let param =
+ Item::named_type(cur.spelling(),
+ default_type,
+ potential_id, ctx);
+ args.push(param);
+ }
+ _ => {}
+ }
+ CXChildVisit_Continue
+ });
+
+ if inner.is_err() {
+ error!("Failed to parse templated type alias {:?}", location);
+ return Err(ParseError::Continue);
+ }
+
+ if args.is_empty() {
+ error!("Failed to get any template parameter, maybe a specialization? {:?}", location);
+ return Err(ParseError::Continue);
+ }
+
+ TypeKind::TemplateAlias(inner.unwrap(), args)
+ }
CXCursor_TemplateRef => {
let referenced = location.referenced();
return Self::from_clang_ty(potential_id,
@@ -521,7 +583,7 @@ impl Type {
let signature = try!(FunctionSig::from_ty(ty, &location.unwrap_or(cursor), ctx));
TypeKind::Function(signature)
}
- CXType_Typedef => {
+ CXType_Typedef => {
let inner = cursor.typedef_type();
let inner =
Item::from_ty_or_ref(inner, location, parent_id, ctx);
diff --git a/tests/expectations/template_alias.rs b/tests/expectations/template_alias.rs
new file mode 100644
index 00000000..6457381f
--- /dev/null
+++ b/tests/expectations/template_alias.rs
@@ -0,0 +1,12 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+pub type Wrapped<T> = T;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Rooted<T> {
+ pub ptr: Wrapped<T>,
+}
diff --git a/tests/expectations/template_alias_basic.rs b/tests/expectations/template_alias_basic.rs
new file mode 100644
index 00000000..656fff33
--- /dev/null
+++ b/tests/expectations/template_alias_basic.rs
@@ -0,0 +1,7 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+pub type Wrapped<T> = T;
diff --git a/tests/expectations/template_alias_namespace.rs b/tests/expectations/template_alias_namespace.rs
new file mode 100644
index 00000000..475c2b05
--- /dev/null
+++ b/tests/expectations/template_alias_namespace.rs
@@ -0,0 +1,21 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+pub mod root {
+ use root;
+ pub mod JS {
+ use root;
+ pub mod detail {
+ use root;
+ pub type Wrapped<T> = T;
+ }
+ #[repr(C)]
+ #[derive(Debug, Copy, Clone)]
+ pub struct Rooted<T> {
+ pub ptr: root::JS::detail::Wrapped<T>,
+ }
+ }
+}
diff --git a/tests/expectations/template_typedef_transitive_param.rs b/tests/expectations/template_typedef_transitive_param.rs
new file mode 100644
index 00000000..166ddc3c
--- /dev/null
+++ b/tests/expectations/template_typedef_transitive_param.rs
@@ -0,0 +1,18 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Wrapper<T> {
+ pub _address: u8,
+ pub _phantom_0: ::std::marker::PhantomData<T>,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct Wrapper_Wrapped<T> {
+ pub t: T,
+}
+pub type Wrapper_Type<T> = Wrapper_Wrapped<T>;
diff --git a/tests/headers/template_alias.hpp b/tests/headers/template_alias.hpp
new file mode 100644
index 00000000..646d9f40
--- /dev/null
+++ b/tests/headers/template_alias.hpp
@@ -0,0 +1,13 @@
+// bindgen-flags: -- -std=c++14
+
+namespace JS {
+namespace detail {
+ template <typename T>
+ using Wrapped = T;
+}
+
+template <typename T>
+struct Rooted {
+ detail::Wrapped<T> ptr;
+};
+}
diff --git a/tests/headers/template_alias_basic.hpp b/tests/headers/template_alias_basic.hpp
new file mode 100644
index 00000000..964f6e27
--- /dev/null
+++ b/tests/headers/template_alias_basic.hpp
@@ -0,0 +1,4 @@
+// bindgen-flags: -- -std=c++11
+
+template<typename T>
+using Wrapped = T;
diff --git a/tests/headers/template_alias_namespace.hpp b/tests/headers/template_alias_namespace.hpp
new file mode 100644
index 00000000..bd637166
--- /dev/null
+++ b/tests/headers/template_alias_namespace.hpp
@@ -0,0 +1,13 @@
+// bindgen-flags: --enable-cxx-namespaces -- -std=c++14
+
+namespace JS {
+namespace detail {
+ template <typename T>
+ using Wrapped = T;
+}
+
+template <typename T>
+struct Rooted {
+ detail::Wrapped<T> ptr;
+};
+}
diff --git a/tests/headers/template_typedef_transitive_param.hpp b/tests/headers/template_typedef_transitive_param.hpp
new file mode 100644
index 00000000..2269ac36
--- /dev/null
+++ b/tests/headers/template_typedef_transitive_param.hpp
@@ -0,0 +1,7 @@
+template<typename T>
+struct Wrapper {
+ struct Wrapped {
+ T t;
+ };
+ using Type = Wrapped;
+};