Skip to content

Template instantiation #491

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Feb 10, 2017
122 changes: 106 additions & 16 deletions src/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ impl Cursor {
// `clang_Cursor_getNumTemplateArguments` is totally unreliable.
// Therefore, try former first, and only fallback to the latter if we
// have to.
self.cur_type().num_template_args()
self.cur_type()
.num_template_args()
.or_else(|| {
let n: c_int = unsafe {
clang_Cursor_getNumTemplateArguments(self.x)
};
let n: c_int =
unsafe { clang_Cursor_getNumTemplateArguments(self.x) };

if n >= 0 {
Some(n as u32)
Expand Down Expand Up @@ -361,6 +361,41 @@ impl Cursor {
}
}

/// Collect all of this cursor's children into a vec and return them.
pub fn collect_children(&self) -> Vec<Cursor> {
let mut children = vec![];
self.visit(|c| {
children.push(c);
CXChildVisit_Continue
});
children
}

/// Does this cursor have any children?
pub fn has_children(&self) -> bool {
let mut has_children = false;
self.visit(|_| {
has_children = true;
CXChildVisit_Break
});
has_children
}

/// Does this cursor have at least `n` children?
pub fn has_at_least_num_children(&self, n: usize) -> bool {
assert!(n > 0);
let mut num_left = n;
self.visit(|_| {
num_left -= 1;
if num_left == 0 {
CXChildVisit_Break
} else {
CXChildVisit_Continue
}
});
num_left == 0
}

/// Returns whether the given location contains a cursor with the given
/// kind in the first level of nesting underneath (doesn't look
/// recursively).
Expand Down Expand Up @@ -573,7 +608,7 @@ impl Hash for Cursor {
}

/// The type of a node in clang's AST.
#[derive(Clone)]
#[derive(Clone, Copy)]
pub struct Type {
x: CXType,
}
Expand Down Expand Up @@ -649,6 +684,31 @@ impl Type {
}
}

/// Get the canonical declaration of this type, if it is available.
pub fn canonical_declaration(&self,
location: Option<&Cursor>)
-> Option<CanonicalTypeDeclaration> {
let mut declaration = self.declaration();
if !declaration.is_valid() {
if let Some(location) = location {
let mut location = *location;
if let Some(referenced) = location.referenced() {
location = referenced;
}
if location.is_template_like() {
declaration = location;
}
}
}

let canonical = declaration.canonical();
if canonical.is_valid() && canonical.kind() != CXCursor_NoDeclFound {
Some(CanonicalTypeDeclaration(*self, canonical))
} else {
None
}
}

/// Get a raw display name for this type.
pub fn spelling(&self) -> String {
unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) }
Expand Down Expand Up @@ -723,10 +783,12 @@ impl Type {
/// If this type is a class template specialization, return its
/// template arguments. Otherwise, return None.
pub fn template_args(&self) -> Option<TypeTemplateArgIterator> {
self.num_template_args().map(|n| TypeTemplateArgIterator {
x: self.x,
length: n,
index: 0,
self.num_template_args().map(|n| {
TypeTemplateArgIterator {
x: self.x,
length: n,
index: 0,
}
})
}

Expand Down Expand Up @@ -828,9 +890,8 @@ impl Type {
// 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.template_args().map_or(false, |args| {
args.len() > 0
}) && match self.declaration().kind() {
self.template_args().map_or(false, |args| args.len() > 0) &&
match self.declaration().kind() {
CXCursor_ClassTemplatePartialSpecialization |
CXCursor_TypeAliasTemplateDecl |
CXCursor_TemplateTemplateParameter => false,
Expand All @@ -839,6 +900,26 @@ impl Type {
}
}

/// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its
/// cursor is the canonical declaration for its type. If you have a
/// `CanonicalTypeDeclaration` instance, you know for sure that the type and
/// cursor match up in a canonical declaration relationship, and it simply
/// cannot be otherwise.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CanonicalTypeDeclaration(Type, Cursor);

impl CanonicalTypeDeclaration {
/// Get the type.
pub fn ty(&self) -> &Type {
&self.0
}

/// Get the type's canonical declaration cursor.
pub fn cursor(&self) -> &Cursor {
&self.1
}
}

/// An iterator for a type's template arguments.
pub struct TypeTemplateArgIterator {
x: CXType,
Expand Down Expand Up @@ -1383,7 +1464,10 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
type_to_str(ty.kind())));
}
if let Some(ty) = c.ret_type() {
print_indent(depth, format!(" {}ret-type = {}", prefix, type_to_str(ty.kind())));
print_indent(depth,
format!(" {}ret-type = {}",
prefix,
type_to_str(ty.kind())));
}

if let Some(refd) = c.referenced() {
Expand All @@ -1392,7 +1476,9 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
print_cursor(depth,
String::from(prefix) + "referenced.",
&refd);
print_cursor(depth, String::from(prefix) + "referenced.", &refd);
print_cursor(depth,
String::from(prefix) + "referenced.",
&refd);
}
}

Expand All @@ -1402,7 +1488,9 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
print_cursor(depth,
String::from(prefix) + "canonical.",
&canonical);
print_cursor(depth, String::from(prefix) + "canonical.", &canonical);
print_cursor(depth,
String::from(prefix) + "canonical.",
&canonical);
}

if let Some(specialized) = c.specialized() {
Expand All @@ -1411,7 +1499,9 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
print_cursor(depth,
String::from(prefix) + "specialized.",
&specialized);
print_cursor(depth, String::from(prefix) + "specialized.", &specialized);
print_cursor(depth,
String::from(prefix) + "specialized.",
&specialized);
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions src/codegen/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ pub mod ast_ty {
let prefix = ctx.rust_ident_raw(prefix);
quote_ty!(ctx.ext_cx(), $prefix::$ident)
}
None => {
quote_ty!(ctx.ext_cx(), ::std::os::raw::$ident)
}
None => quote_ty!(ctx.ext_cx(), ::std::os::raw::$ident),
}
}

Expand Down
15 changes: 8 additions & 7 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ impl CodeGenerator for Type {
TypeKind::Pointer(..) |
TypeKind::BlockPointer |
TypeKind::Reference(..) |
TypeKind::TemplateRef(..) |
TypeKind::TemplateInstantiation(..) |
TypeKind::Function(..) |
TypeKind::ResolvedTypeRef(..) |
TypeKind::Named => {
Expand Down Expand Up @@ -1377,9 +1377,10 @@ impl CodeGenerator for CompInfo {
// FIXME when [issue #465](https://github.com/servo/rust-bindgen/issues/465) ready
let too_many_base_vtables = self.base_members()
.iter()
.filter(|base| ctx.resolve_type(base.ty).has_vtable(ctx))
.count() >
1;
.filter(|base| {
ctx.resolve_type(base.ty).has_vtable(ctx)
})
.count() > 1;

let should_skip_field_offset_checks = item.is_opaque(ctx) ||
too_many_base_vtables;
Expand Down Expand Up @@ -2180,7 +2181,7 @@ impl ToRustTy for Type {
let path = item.namespace_aware_canonical_path(ctx);
aster::AstBuilder::new().ty().path().ids(path).build()
}
TypeKind::TemplateRef(inner, ref template_args) => {
TypeKind::TemplateInstantiation(inner, ref template_args) => {
// PS: Sorry for the duplication here.
let mut inner_ty = inner.to_rust_ty(ctx).unwrap();

Expand All @@ -2189,7 +2190,7 @@ impl ToRustTy for Type {
.map(|arg| arg.to_rust_ty(ctx))
.collect::<Vec<_>>();

path.segments.last_mut().unwrap().parameters = if
path.segments.last_mut().unwrap().parameters = if
template_args.is_empty() {
None
} else {
Expand Down Expand Up @@ -2509,8 +2510,8 @@ mod utils {
use super::ItemToRustTy;
use aster;
use ir::context::{BindgenContext, ItemId};
use ir::item::{Item, ItemCanonicalPath};
use ir::function::FunctionSig;
use ir::item::{Item, ItemCanonicalPath};
use ir::ty::TypeKind;
use std::mem;
use syntax::ast;
Expand Down
18 changes: 13 additions & 5 deletions src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
use super::item::Item;
use super::layout::Layout;
use super::ty::Type;
use super::ty::{TemplateDeclaration, Type};
use super::type_collector::{ItemSet, TypeCollector};
use clang;
use parse::{ClangItemParser, ParseError};
Expand Down Expand Up @@ -564,10 +564,8 @@ impl CompInfo {
});
ci.is_anonymous = cursor.is_anonymous();
ci.template_args = match ty.template_args() {
// In forward declarations and not specializations,
// etc, they are in
// the ast, we'll meet them in
// CXCursor_TemplateTypeParameter
// In forward declarations and not specializations, etc, they are in
// the ast, we'll meet them in CXCursor_TemplateTypeParameter
None => vec![],
Some(arg_types) => {
let num_arg_types = arg_types.len();
Expand Down Expand Up @@ -916,6 +914,16 @@ impl CompInfo {
}
}

impl TemplateDeclaration for CompInfo {
fn template_params(&self, _ctx: &BindgenContext) -> Option<Vec<ItemId>> {
if self.template_args.is_empty() {
None
} else {
Some(self.template_args.clone())
}
}
}

impl CanDeriveDebug for CompInfo {
type Extra = Option<Layout>;

Expand Down
Loading