diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2016-10-18 09:07:42 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-18 09:07:42 -0500 |
commit | ab6c4384624f170d4a2adc62ecacb94535a9e72d (patch) | |
tree | 464ad46f18cdc2977291bcb161d0060184767fde | |
parent | b162e9209dd0eaaf84538fc1cb1cdf6bb1d1669f (diff) | |
parent | 2a3f93074dd2898669dbbce6e97e5cc4405d7cb1 (diff) |
Auto merge of #85 - emilio:template-alias, r=nox
Handle templated aliases.
Fixes #83.
cc @fitzgen
r? @nox
-rw-r--r-- | src/clang.rs | 4 | ||||
-rw-r--r-- | src/clangll.rs | 5 | ||||
-rw-r--r-- | src/codegen/mod.rs | 8 | ||||
-rw-r--r-- | src/ir/item.rs | 79 | ||||
-rw-r--r-- | src/ir/ty.rs | 68 | ||||
-rw-r--r-- | tests/expectations/template_alias.rs | 12 | ||||
-rw-r--r-- | tests/expectations/template_alias_basic.rs | 7 | ||||
-rw-r--r-- | tests/expectations/template_alias_namespace.rs | 21 | ||||
-rw-r--r-- | tests/expectations/template_typedef_transitive_param.rs | 18 | ||||
-rw-r--r-- | tests/headers/template_alias.hpp | 13 | ||||
-rw-r--r-- | tests/headers/template_alias_basic.hpp | 4 | ||||
-rw-r--r-- | tests/headers/template_alias_namespace.hpp | 13 | ||||
-rw-r--r-- | tests/headers/template_typedef_transitive_param.hpp | 7 |
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; +}; |