summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/clang.rs48
-rw-r--r--src/codegen/mod.rs280
-rw-r--r--src/codegen/struct_layout.rs61
-rw-r--r--src/ir/comp.rs181
-rw-r--r--src/ir/context.rs169
-rw-r--r--src/ir/dot.rs24
-rw-r--r--src/ir/enum_ty.rs4
-rw-r--r--src/ir/function.rs33
-rw-r--r--src/ir/item.rs581
-rw-r--r--src/ir/item_kind.rs15
-rw-r--r--src/ir/layout.rs17
-rw-r--r--src/ir/mod.rs1
-rw-r--r--src/ir/module.rs13
-rw-r--r--src/ir/named.rs204
-rw-r--r--src/ir/template.rs193
-rw-r--r--src/ir/traversal.rs2
-rw-r--r--src/ir/ty.rs1031
-rw-r--r--src/ir/var.rs13
-rw-r--r--src/parse.rs26
-rw-r--r--src/uses.rs7
-rwxr-xr-x[-rw-r--r--]tests/expectations/lib.rs3
-rw-r--r--tests/expectations/tests/381-decltype-alias.rs9
-rw-r--r--tests/expectations/tests/anon_enum_trait.rs8
-rw-r--r--tests/expectations/tests/anon_union.rs34
-rw-r--r--tests/expectations/tests/auto.rs8
-rw-r--r--tests/expectations/tests/bad-namespace-parenthood-inheritance.rs8
-rw-r--r--tests/expectations/tests/class_nested.rs2
-rw-r--r--tests/expectations/tests/class_with_dtor.rs2
-rw-r--r--tests/expectations/tests/constant-non-specialized-tp.rs19
-rw-r--r--tests/expectations/tests/constructor-tp.rs8
-rw-r--r--tests/expectations/tests/crtp.rs43
-rw-r--r--tests/expectations/tests/dash_language.rs8
-rw-r--r--tests/expectations/tests/empty_template_param_name.rs8
-rw-r--r--tests/expectations/tests/enum_in_template_with_typedef.rs8
-rw-r--r--tests/expectations/tests/eval-variadic-template-parameter.rs8
-rw-r--r--tests/expectations/tests/forward-inherit-struct.rs13
-rw-r--r--tests/expectations/tests/in_class_typedef.rs11
-rw-r--r--tests/expectations/tests/inherit-namespaced.rs13
-rw-r--r--tests/expectations/tests/inherit_named.rs8
-rw-r--r--tests/expectations/tests/inner_template_self.rs10
-rw-r--r--tests/expectations/tests/issue-358.rs5
-rw-r--r--tests/expectations/tests/issue-446.rs12
-rw-r--r--tests/expectations/tests/issue-493.rs85
-rw-r--r--tests/expectations/tests/issue-544-stylo-creduce-2.rs15
-rw-r--r--tests/expectations/tests/issue-544-stylo-creduce.rs14
-rw-r--r--tests/expectations/tests/maddness-is-avoidable.rs18
-rw-r--r--tests/expectations/tests/no_copy.rs8
-rw-r--r--tests/expectations/tests/opaque_pointer.rs7
-rw-r--r--tests/expectations/tests/opaque_typedef.rs10
-rw-r--r--tests/expectations/tests/partial-specialization-and-inheritance.rs44
-rw-r--r--tests/expectations/tests/replace_use.rs10
-rw-r--r--tests/expectations/tests/size_t_template.rs4
-rw-r--r--tests/expectations/tests/struct_with_typedef_template_arg.rs9
-rw-r--r--tests/expectations/tests/template-fun-ty.rs26
-rw-r--r--tests/expectations/tests/template-param-usage-0.rs14
-rw-r--r--tests/expectations/tests/template-param-usage-1.rs11
-rw-r--r--tests/expectations/tests/template-param-usage-10.rs25
-rw-r--r--tests/expectations/tests/template-param-usage-11.rs11
-rw-r--r--tests/expectations/tests/template-param-usage-12.rs23
-rw-r--r--tests/expectations/tests/template-param-usage-13.rs20
-rw-r--r--tests/expectations/tests/template-param-usage-14.rs20
-rw-r--r--tests/expectations/tests/template-param-usage-15.rs23
-rw-r--r--tests/expectations/tests/template-param-usage-2.rs22
-rw-r--r--tests/expectations/tests/template-param-usage-3.rs24
-rw-r--r--tests/expectations/tests/template-param-usage-4.rs19
-rw-r--r--tests/expectations/tests/template-param-usage-5.rs15
-rw-r--r--tests/expectations/tests/template-param-usage-6.rs12
-rw-r--r--tests/expectations/tests/template-param-usage-7.rs16
-rw-r--r--tests/expectations/tests/template-param-usage-8.rs17
-rw-r--r--tests/expectations/tests/template-param-usage-9.rs22
-rw-r--r--tests/expectations/tests/template.rs63
-rw-r--r--tests/expectations/tests/template_typedef_transitive_param.rs8
-rw-r--r--tests/expectations/tests/template_typedefs.rs9
-rw-r--r--tests/expectations/tests/templateref_opaque.rs18
-rw-r--r--tests/expectations/tests/typeref.rs15
-rw-r--r--tests/expectations/tests/union_template.rs21
-rw-r--r--tests/expectations/tests/variadic_template_function.rs8
-rw-r--r--tests/expectations/tests/what_is_going_on.rs7
-rw-r--r--tests/expectations/tests/whitelist_basic.rs1
-rw-r--r--tests/headers/issue-544-stylo-creduce-2.hpp8
-rw-r--r--tests/headers/issue-544-stylo-creduce.hpp5
-rw-r--r--tests/headers/partial-specialization-and-inheritance.hpp40
-rw-r--r--tests/headers/template-param-usage-0.hpp6
-rw-r--r--tests/headers/template-param-usage-1.hpp6
-rw-r--r--tests/headers/template-param-usage-10.hpp14
-rw-r--r--tests/headers/template-param-usage-11.hpp6
-rw-r--r--tests/headers/template-param-usage-12.hpp11
-rw-r--r--tests/headers/template-param-usage-13.hpp11
-rw-r--r--tests/headers/template-param-usage-14.hpp11
-rw-r--r--tests/headers/template-param-usage-15.hpp11
-rw-r--r--tests/headers/template-param-usage-2.hpp10
-rw-r--r--tests/headers/template-param-usage-3.hpp12
-rw-r--r--tests/headers/template-param-usage-4.hpp11
-rw-r--r--tests/headers/template-param-usage-5.hpp8
-rw-r--r--tests/headers/template-param-usage-6.hpp8
-rw-r--r--tests/headers/template-param-usage-7.hpp10
-rw-r--r--tests/headers/template-param-usage-8.hpp10
-rw-r--r--tests/headers/template-param-usage-9.hpp12
98 files changed, 2436 insertions, 1619 deletions
diff --git a/src/clang.rs b/src/clang.rs
index 5e2ab3af..b8086d99 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -6,6 +6,7 @@
use cexpr;
use clang_sys::*;
+use regex;
use std::{mem, ptr, slice};
use std::ffi::{CStr, CString};
use std::fmt;
@@ -126,11 +127,11 @@ impl Cursor {
}
/// Return the number of template arguments used by this cursor's referent,
- /// if the referent is either a template specialization or declaration.
- /// Returns `None` otherwise.
+ /// if the referent is either a template instantiation. Returns `None`
+ /// otherwise.
///
- /// NOTE: This may not return `Some` for some non-fully specialized
- /// templates, see #193 and #194.
+ /// NOTE: This may not return `Some` for partial template specializations,
+ /// see #193 and #194.
pub fn num_template_args(&self) -> Option<u32> {
// XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while
// `clang_Cursor_getNumTemplateArguments` is totally unreliable.
@@ -302,7 +303,11 @@ impl Cursor {
x: clang_getCursorDefinition(self.x),
};
- if ret.is_valid() { Some(ret) } else { None }
+ if ret.is_valid() && ret.kind() != CXCursor_NoDeclFound {
+ Some(ret)
+ } else {
+ None
+ }
}
}
@@ -331,8 +336,9 @@ impl Cursor {
}
}
- /// Given that this cursor points to a template specialization, get a cursor
- /// pointing to the template definition that is being specialized.
+ /// Given that this cursor points to either a template specialization or a
+ /// template instantiation, get a cursor pointing to the template definition
+ /// that is being specialized.
pub fn specialized(&self) -> Option<Cursor> {
unsafe {
let ret = Cursor {
@@ -895,8 +901,8 @@ impl Type {
self.is_valid() && self.kind() != CXType_Unexposed
}
- /// Is this type a fully specialized template?
- pub fn is_fully_specialized_template(&self) -> bool {
+ /// Is this type a fully instantiated template?
+ pub fn is_fully_instantiated_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 :(
@@ -908,6 +914,30 @@ impl Type {
_ => true,
}
}
+
+ /// Is this type an associated template type? Eg `T::Associated` in
+ /// this example:
+ ///
+ /// ```c++
+ /// template <typename T>
+ /// class Foo {
+ /// typename T::Associated member;
+ /// };
+ /// ```
+ pub fn is_associated_type(&self) -> bool {
+ // This is terrible :(
+ fn hacky_parse_associated_type<S: AsRef<str>>(spelling: S) -> bool {
+ lazy_static! {
+ static ref ASSOC_TYPE_RE: regex::Regex =
+ regex::Regex::new(r"typename type\-parameter\-\d+\-\d+::.+").unwrap();
+ }
+ ASSOC_TYPE_RE.is_match(spelling.as_ref())
+ }
+
+ self.kind() == CXType_Unexposed &&
+ (hacky_parse_associated_type(self.spelling()) ||
+ hacky_parse_associated_type(self.canonical_type().spelling()))
+ }
}
/// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 77941fa3..7bc8985b 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -2,8 +2,8 @@ mod helpers;
mod struct_layout;
use self::helpers::{BlobTyBuilder, attributes};
+use self::struct_layout::{StructLayoutTracker, bytes_from_bits_pow2};
use self::struct_layout::{align_to, bytes_from_bits};
-use self::struct_layout::{bytes_from_bits_pow2, StructLayoutTracker};
use aster;
use ir::annotations::FieldAccessorKind;
@@ -20,7 +20,8 @@ use ir::item_kind::ItemKind;
use ir::layout::Layout;
use ir::module::Module;
use ir::objc::ObjCInterface;
-use ir::ty::{Type, TypeKind};
+use ir::template::{AsNamed, TemplateInstantiation};
+use ir::ty::{TemplateDeclaration, Type, TypeKind};
use ir::var::Var;
use std::borrow::Cow;
@@ -137,11 +138,6 @@ impl<'a> CodegenResult<'a> {
}
}
- fn next_id(&mut self) -> usize {
- self.codegen_id.set(self.codegen_id.get() + 1);
- self.codegen_id.get()
- }
-
fn saw_union(&mut self) {
self.saw_union = true;
}
@@ -522,19 +518,20 @@ impl CodeGenerator for Type {
TypeKind::Pointer(..) |
TypeKind::BlockPointer |
TypeKind::Reference(..) |
- TypeKind::TemplateInstantiation(..) |
TypeKind::Function(..) |
TypeKind::ResolvedTypeRef(..) |
+ TypeKind::Opaque |
TypeKind::Named => {
// These items don't need code generation, they only need to be
// converted to rust types in fields, arguments, and such.
return;
}
+ TypeKind::TemplateInstantiation(ref inst) => {
+ inst.codegen(ctx, result, whitelisted_items, item)
+ }
TypeKind::Comp(ref ci) => {
ci.codegen(ctx, result, whitelisted_items, item)
}
- // NB: The code below will pick the correct
- // applicable_template_args.
TypeKind::TemplateAlias(inner, _) |
TypeKind::Alias(inner) => {
let inner_item = ctx.resolve_item(inner);
@@ -557,10 +554,9 @@ impl CodeGenerator for Type {
return;
}
- let mut applicable_template_args =
- item.applicable_template_args(ctx);
+ let mut used_template_params = item.used_template_params(ctx);
let inner_rust_type = if item.is_opaque(ctx) {
- applicable_template_args.clear();
+ used_template_params = None;
// Pray if there's no layout.
let layout = self.layout(ctx).unwrap_or_else(Layout::zero);
BlobTyBuilder::new(layout).build()
@@ -603,7 +599,7 @@ impl CodeGenerator for Type {
// https://github.com/rust-lang/rust/issues/26264
let simple_enum_path = match inner_rust_type.node {
ast::TyKind::Path(None, ref p) => {
- if applicable_template_args.is_empty() &&
+ if used_template_params.is_none() &&
inner_item.expect_type()
.canonical_type(ctx)
.is_enum() &&
@@ -627,17 +623,21 @@ impl CodeGenerator for Type {
typedef.use_().build(p).as_(rust_name)
} else {
let mut generics = typedef.type_(rust_name).generics();
- for template_arg in applicable_template_args.iter() {
- let template_arg = ctx.resolve_type(*template_arg);
- if template_arg.is_named() {
- if template_arg.is_invalid_named_type() {
- warn!("Item contained invalid template \
- parameter: {:?}",
- item);
- return;
+ if let Some(ref params) = used_template_params {
+ for template_param in params {
+ if let Some(id) =
+ template_param.as_named(ctx, &()) {
+ let template_param = ctx.resolve_type(id);
+ if template_param.is_invalid_named_type() {
+ warn!("Item contained invalid template \
+ parameter: {:?}",
+ item);
+ return;
+ }
+ generics =
+ generics.ty_param_id(template_param.name()
+ .unwrap());
}
- generics =
- generics.ty_param_id(template_arg.name().unwrap());
}
}
generics.build().build_ty(inner_rust_type)
@@ -768,7 +768,7 @@ impl<'a> Bitfield<'a> {
let field_align = field_ty_layout.align;
if field_size_in_bits != 0 &&
- (width == 0 || width as usize > unfilled_bits_in_last_unit) {
+ (width == 0 || width as usize > unfilled_bits_in_last_unit) {
field_size_in_bits = align_to(field_size_in_bits, field_align);
// Push the new field.
let ty =
@@ -829,6 +829,53 @@ impl<'a> Bitfield<'a> {
}
}
+impl CodeGenerator for TemplateInstantiation {
+ type Extra = Item;
+
+ fn codegen<'a>(&self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'a>,
+ _whitelisted_items: &ItemSet,
+ item: &Item) {
+ // Although uses of instantiations don't need code generation, and are
+ // just converted to rust types in fields, vars, etc, we take this
+ // opportunity to generate tests for their layout here.
+
+ let layout = item.kind().expect_type().layout(ctx);
+
+ if let Some(layout) = layout {
+ let size = layout.size;
+ let align = layout.align;
+
+ let name = item.canonical_name(ctx);
+ let fn_name = format!("__bindgen_test_layout_{}_instantiation_{}",
+ name,
+ item.id().as_usize());
+ let fn_name = ctx.rust_ident_raw(&fn_name);
+
+ let prefix = ctx.trait_prefix();
+ let ident = item.to_rust_ty(ctx);
+ let size_of_expr = quote_expr!(ctx.ext_cx(),
+ ::$prefix::mem::size_of::<$ident>());
+ let align_of_expr = quote_expr!(ctx.ext_cx(),
+ ::$prefix::mem::align_of::<$ident>());
+
+ let item = quote_item!(
+ ctx.ext_cx(),
+ #[test]
+ fn $fn_name() {
+ assert_eq!($size_of_expr, $size,
+ concat!("Size of template specialization: ", stringify!($ident)));
+ assert_eq!($align_of_expr, $align,
+ concat!("Alignment of template specialization: ", stringify!($ident)));
+ })
+ .unwrap();
+
+ result.push(item);
+ }
+ }
+}
+
impl CodeGenerator for CompInfo {
type Extra = Item;
@@ -847,12 +894,11 @@ impl CodeGenerator for CompInfo {
return;
}
- let applicable_template_args = item.applicable_template_args(ctx);
+ let used_template_params = item.used_template_params(ctx);
// generate tuple struct if struct or union is a forward declaration,
// skip for now if template parameters are needed.
- if self.is_forward_declaration() &&
- applicable_template_args.is_empty() {
+ if self.is_forward_declaration() && used_template_params.is_none() {
let struct_name = item.canonical_name(ctx);
let struct_name = ctx.rust_ident_raw(&struct_name);
let tuple_struct = quote_item!(ctx.ext_cx(),
@@ -865,35 +911,6 @@ impl CodeGenerator for CompInfo {
return;
}
- if self.is_template_specialization() {
- let layout = item.kind().expect_type().layout(ctx);
-
- if let Some(layout) = layout {
- let fn_name = format!("__bindgen_test_layout_template_{}",
- result.next_id());
- let fn_name = ctx.rust_ident_raw(&fn_name);
- let ident = item.to_rust_ty(ctx);
- let prefix = ctx.trait_prefix();
- let size_of_expr = quote_expr!(ctx.ext_cx(),
- ::$prefix::mem::size_of::<$ident>());
- let align_of_expr = quote_expr!(ctx.ext_cx(),
- ::$prefix::mem::align_of::<$ident>());
- let size = layout.size;
- let align = layout.align;
- let item = quote_item!(ctx.ext_cx(),
- #[test]
- fn $fn_name() {
- assert_eq!($size_of_expr, $size,
- concat!("Size of template specialization: ", stringify!($ident)));
- assert_eq!($align_of_expr, $align,
- concat!("Alignment of template specialization: ", stringify!($ident)));
- })
- .unwrap();
- result.push(item);
- }
- return;
- }
-
let mut attributes = vec![];
let mut needs_clone_impl = false;
let mut needs_default_impl = false;
@@ -923,7 +940,7 @@ impl CodeGenerator for CompInfo {
if item.can_derive_copy(ctx, ()) &&
!item.annotations().disallow_copy() {
derives.push("Copy");
- if !applicable_template_args.is_empty() {
+ if used_template_params.is_some() {
// FIXME: This requires extra logic if you have a big array in a
// templated struct. The reason for this is that the magic:
// fn clone(&self) -> Self { *self }
@@ -940,8 +957,6 @@ impl CodeGenerator for CompInfo {
attributes.push(attributes::derives(&derives))
}
- let mut template_args_used =
- vec![false; applicable_template_args.len()];
let canonical_name = item.canonical_name(ctx);
let builder = if is_union && ctx.options().unstable_rust {
aster::AstBuilder::new()
@@ -1004,13 +1019,6 @@ impl CodeGenerator for CompInfo {
continue;
}
- for (i, ty_id) in applicable_template_args.iter().enumerate() {
- let template_arg_ty = ctx.resolve_type(*ty_id);
- if base_ty.signature_contains_named_type(ctx, template_arg_ty) {
- template_args_used[i] = true;
- }
- }
-
let inner = base.ty.to_rust_ty(ctx);
let field_name = if i == 0 {
"_base".into()
@@ -1092,13 +1100,6 @@ impl CodeGenerator for CompInfo {
continue;
}
- for (i, ty_id) in applicable_template_args.iter().enumerate() {
- let template_arg = ctx.resolve_type(*ty_id);
- if field_ty.signature_contains_named_type(ctx, template_arg) {
- template_args_used[i] = true;
- }
- }
-
let ty = field.ty().to_rust_ty(ctx);
// NB: In unstable rust we use proper `union` types.
@@ -1108,7 +1109,8 @@ impl CodeGenerator for CompInfo {
} else {
quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>)
}
- } else if let Some(item) = field_ty.is_incomplete_array(ctx) {
+ } else if let Some(item) =
+ field_ty.is_incomplete_array(ctx) {
result.saw_incomplete_array();
let inner = item.to_rust_ty(ctx);
@@ -1257,9 +1259,6 @@ impl CodeGenerator for CompInfo {
if item.is_opaque(ctx) {
fields.clear();
methods.clear();
- for i in 0..template_args_used.len() {
- template_args_used[i] = false;
- }
match layout {
Some(l) => {
@@ -1276,7 +1275,9 @@ impl CodeGenerator for CompInfo {
}
} else if !is_union && !self.is_unsized(ctx) {
if let Some(padding_field) =
- layout.and_then(|layout| struct_layout.pad_struct(&canonical_name, layout)) {
+ layout.and_then(|layout| {
+ struct_layout.pad_struct(&canonical_name, layout)
+ }) {
fields.push(padding_field);
}
@@ -1299,35 +1300,17 @@ impl CodeGenerator for CompInfo {
fields.push(field);
}
- // Append any extra template arguments that nobody has used so far.
- for (i, ty) in applicable_template_args.iter().enumerate() {
- if !template_args_used[i] {
- let name = ctx.resolve_type(*ty).name().unwrap();
+ let mut generics = aster::AstBuilder::new().generics();
+
+ if let Some(ref params) = used_template_params {
+ for ty in params.iter() {
+ let param = ctx.resolve_type(*ty);
+ let name = param.name().unwrap();
let ident = ctx.rust_ident(name);
- let prefix = ctx.trait_prefix();
- let phantom = quote_ty!(ctx.ext_cx(),
- ::$prefix::marker::PhantomData<$ident>);
- let field = StructFieldBuilder::named(format!("_phantom_{}",
- i))
- .pub_()
- .build_ty(phantom);
- fields.push(field)
+ generics = generics.ty_param_id(ident);
}
}
-
- let mut generics = aster::AstBuilder::new().generics();
- for template_arg in applicable_template_args.iter() {
- // Take into account that here only arrive named types, not
- // template specialisations that would need to be
- // instantiated.
- //
- // TODO: Add template args from the parent, here and in
- // `to_rust_ty`!!
- let template_arg = ctx.resolve_type(*template_arg);
- generics = generics.ty_param_id(template_arg.name().unwrap());
- }
-
let generics = generics.build();
let rust_struct = builder.with_generics(generics.clone())
@@ -1353,7 +1336,7 @@ impl CodeGenerator for CompInfo {
canonical_name);
}
- if applicable_template_args.is_empty() {
+ if used_template_params.is_none() {
for var in self.inner_vars() {
ctx.resolve_item(*var)
.codegen(ctx, result, whitelisted_items, &());
@@ -2193,16 +2176,54 @@ impl ToRustTy for Type {
let path = item.namespace_aware_canonical_path(ctx);
aster::AstBuilder::new().ty().path().ids(path).build()
}
- TypeKind::TemplateInstantiation(inner, ref template_args) => {
- // PS: Sorry for the duplication here.
- let mut inner_ty = inner.to_rust_ty(ctx).unwrap();
+ TypeKind::TemplateInstantiation(ref inst) => {
+ let decl = inst.template_definition();
+ let mut ty = decl.to_rust_ty(ctx).unwrap();
- if let ast::TyKind::Path(_, ref mut path) = inner_ty.node {
- let template_args = template_args.iter()
- .map(|arg| arg.to_rust_ty(ctx))
+ // If we gave up when making a type for the template definition,
+ // check if maybe we can make a better opaque blob for the
+ // instantiation.
+ if ty == aster::AstBuilder::new().ty().unit().unwrap() {
+ if let Some(layout) = self.layout(ctx) {
+ ty = BlobTyBuilder::new(layout).build().unwrap()
+ }
+ }
+
+ let decl_params = if let Some(params) =
+ decl.self_template_params(ctx) {
+ params
+ } else {
+ // This can happen if we generated an opaque type for a
+ // partial template specialization, in which case we just
+ // use the opaque type's layout. If we don't have a layout,
+ // we cross our fingers and hope for the best :-/
+ debug_assert!(ctx.resolve_type_through_type_refs(decl)
+ .is_opaque());
+ let layout = self.layout(ctx).unwrap_or(Layout::zero());
+ ty = BlobTyBuilder::new(layout).build().unwrap();
+
+ vec![]
+ };
+
+ // TODO: If the decl type is a template class/struct
+ // declaration's member template declaration, it could rely on
+ // generic template parameters from its outer template
+ // class/struct. When we emit bindings for it, it could require
+ // *more* type arguments than we have here, and we will need to
+ // reconstruct them somehow. We don't have any means of doing
+ // that reconstruction at this time.
+
+ if let ast::TyKind::Path(_, ref mut path) = ty.node {
+ let template_args = inst.template_arguments()
+ .iter()
+ .zip(decl_params.iter())
+ // Only pass type arguments for the type parameters that
+ // the decl uses.
+ .filter(|&(_, param)| ctx.uses_template_parameter(decl, *param))
+ .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 {
@@ -2216,18 +2237,19 @@ impl ToRustTy for Type {
}
}
- P(inner_ty)
+ P(ty)
}
TypeKind::ResolvedTypeRef(inner) => inner.to_rust_ty(ctx),
TypeKind::TemplateAlias(inner, _) |
TypeKind::Alias(inner) => {
- let applicable_named_args = item.applicable_template_args(ctx)
+ let template_params = item.used_template_params(ctx)
+ .unwrap_or(vec![])
.into_iter()
- .filter(|arg| ctx.resolve_type(*arg).is_named())
+ .filter(|param| param.is_named(ctx, &()))
.collect::<Vec<_>>();
let spelling = self.name().expect("Unnamed alias?");
- if item.is_opaque(ctx) && !applicable_named_args.is_empty() {
+ if item.is_opaque(ctx) && !template_params.is_empty() {
// Pray if there's no available layout.
let layout = self.layout(ctx).unwrap_or_else(Layout::zero);
BlobTyBuilder::new(layout).build()
@@ -2236,15 +2258,13 @@ impl ToRustTy for Type {
inner) {
ty
} else {
- utils::build_templated_path(item,
- ctx,
- applicable_named_args)
+ utils::build_templated_path(item, ctx, template_params)
}
}
TypeKind::Comp(ref info) => {
- let template_args = item.applicable_template_args(ctx);
+ let template_params = item.used_template_params(ctx);
if info.has_non_type_template_params() ||
- (item.is_opaque(ctx) && !template_args.is_empty()) {
+ (item.is_opaque(ctx) && template_params.is_some()) {
return match self.layout(ctx) {
Some(layout) => BlobTyBuilder::new(layout).build(),
None => {
@@ -2256,7 +2276,13 @@ impl ToRustTy for Type {
};
}
- utils::build_templated_path(item, ctx, template_args)
+ utils::build_templated_path(item,
+ ctx,
+ template_params.unwrap_or(vec![]))
+ }
+ TypeKind::Opaque => {
+ BlobTyBuilder::new(self.layout(ctx).unwrap_or(Layout::zero()))
+ .build()
}
TypeKind::BlockPointer => {
let void = raw_type(ctx, "c_void");
@@ -2742,19 +2768,19 @@ mod utils {
pub fn build_templated_path(item: &Item,
ctx: &BindgenContext,
- template_args: Vec<ItemId>)
+ template_params: Vec<ItemId>)
-> P<ast::Ty> {
let path = item.namespace_aware_canonical_path(ctx);
let builder = aster::AstBuilder::new().ty().path();
- let template_args = template_args.iter()
- .map(|arg| arg.to_rust_ty(ctx))
+ let template_params = template_params.iter()
+ .map(|param| param.to_rust_ty(ctx))
.collect::<Vec<_>>();
// XXX: I suck at aster.
if path.len() == 1 {
return builder.segment(&path[0])
- .with_tys(template_args)
+ .with_tys(template_params)
.build()
.build();
}
@@ -2765,7 +2791,7 @@ mod utils {
builder = if i == path.len() - 2 {
// XXX Extra clone courtesy of the borrow checker.
builder.segment(&segment)
- .with_tys(template_args.clone())
+ .with_tys(template_params.clone())
.build()
} else {
builder.segment(&segment).build()
diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs
index 724bef98..351f7642 100644
--- a/src/codegen/struct_layout.rs
+++ b/src/codegen/struct_layout.rs
@@ -167,17 +167,20 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
None => return None,
};
- if let TypeKind::Array(inner, len) = *field_ty.canonical_type(self.ctx).kind() {
+ if let TypeKind::Array(inner, len) =
+ *field_ty.canonical_type(self.ctx).kind() {
// FIXME(emilio): As an _ultra_ hack, we correct the layout returned
// by arrays of structs that have a bigger alignment than what we
// can support.
//
// This means that the structs in the array are super-unsafe to
// access, since they won't be properly aligned, but *shrug*.
- if let Some(layout) = self.ctx.resolve_type(inner).layout(self.ctx) {
+ if let Some(layout) = self.ctx
+ .resolve_type(inner)
+ .layout(self.ctx) {
if layout.align > mem::size_of::<*mut ()>() {
- field_layout.size =
- align_to(layout.size, layout.align) * len;
+ field_layout.size = align_to(layout.size, layout.align) *
+ len;
field_layout.align = mem::size_of::<*mut ()>();
}
}
@@ -197,7 +200,8 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
};
// Otherwise the padding is useless.
- let need_padding = padding_bytes >= field_layout.align || field_layout.align > mem::size_of::<*mut ()>();
+ let need_padding = padding_bytes >= field_layout.align ||
+ field_layout.align > mem::size_of::<*mut ()>();
self.latest_offset += padding_bytes;
@@ -206,14 +210,16 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
self.latest_offset);
debug!("align field {} to {}/{} with {} padding bytes {:?}",
- field_name,
- self.latest_offset,
- field_offset.unwrap_or(0) / 8,
- padding_bytes,
- field_layout);
+ field_name,
+ self.latest_offset,
+ field_offset.unwrap_or(0) / 8,
+ padding_bytes,
+ field_layout);
if need_padding && padding_bytes != 0 {
- Some(Layout::new(padding_bytes, cmp::min(field_layout.align, mem::size_of::<*mut ()>())))
+ Some(Layout::new(padding_bytes,
+ cmp::min(field_layout.align,
+ mem::size_of::<*mut ()>())))
} else {
None
}
@@ -221,7 +227,8 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
self.latest_offset += field_layout.size;
self.latest_field_layout = Some(field_layout);
- self.max_field_align = cmp::max(self.max_field_align, field_layout.align);
+ self.max_field_align = cmp::max(self.max_field_align,
+ field_layout.align);
self.last_field_was_bitfield = false;
debug!("Offset: {}: {} -> {}",
@@ -232,11 +239,15 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
padding_layout.map(|layout| self.padding_field(layout))
}
- pub fn pad_struct(&mut self, name: &str, layout: Layout) -> Option<ast::StructField> {
+ pub fn pad_struct(&mut self,
+ name: &str,
+ layout: Layout)
+ -> Option<ast::StructField> {
if layout.size < self.latest_offset {
error!("Calculated wrong layout for {}, too more {} bytes",
- name, self.latest_offset - layout.size);
- return None
+ name,
+ self.latest_offset - layout.size);
+ return None;
}
let padding_bytes = layout.size - self.latest_offset;
@@ -248,14 +259,14 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
// regardless, because bitfields don't respect alignment as strictly as
// other fields.
if padding_bytes > 0 &&
- (padding_bytes >= layout.align ||
- (self.last_field_was_bitfield &&
- padding_bytes >= self.latest_field_layout.unwrap().align) ||
- layout.align > mem::size_of::<*mut ()>()) {
+ (padding_bytes >= layout.align ||
+ (self.last_field_was_bitfield &&
+ padding_bytes >= self.latest_field_layout.unwrap().align) ||
+ layout.align > mem::size_of::<*mut ()>()) {
let layout = if self.comp.packed() {
Layout::new(padding_bytes, 1)
} else if self.last_field_was_bitfield ||
- layout.align > mem::size_of::<*mut ()>() {
+ layout.align > mem::size_of::<*mut ()>() {
// We've already given up on alignment here.
Layout::for_size(padding_bytes)
} else {
@@ -316,12 +327,14 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
// If it was, we may or may not need to align, depending on what the
// current field alignment and the bitfield size and alignment are.
- debug!("align_to_bitfield? {}: {:?} {:?}", self.last_field_was_bitfield,
- layout, new_field_layout);
+ debug!("align_to_bitfield? {}: {:?} {:?}",
+ self.last_field_was_bitfield,
+ layout,
+ new_field_layout);
if self.last_field_was_bitfield &&
- new_field_layout.align <= layout.size % layout.align &&
- new_field_layout.size <= layout.size % layout.align {
+ new_field_layout.align <= layout.size % layout.align &&
+ new_field_layout.size <= layout.size % layout.align {
// The new field will be coalesced into some of the remaining bits.
//
// FIXME(emilio): I think this may not catch everything?
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index b97879f7..814204c2 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -6,7 +6,7 @@ use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
use super::item::Item;
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
-use super::ty::{TemplateDeclaration, Type};
+use super::ty::TemplateDeclaration;
use clang;
use parse::{ClangItemParser, ParseError};
use std::cell::Cell;
@@ -238,10 +238,11 @@ pub struct CompInfo {
/// The members of this struct or union.
fields: Vec<Field>,
- /// The template parameters of this class. These are non-concrete, and
- /// should always be a Type(TypeKind::Named(name)), but still they need to
- /// be registered with an unique type id in the context.
- template_args: Vec<ItemId>,
+ /// The abstract template parameters of this class. These are NOT concrete
+ /// template arguments, and should always be a
+ /// Type(TypeKind::Named(name)). For concrete template arguments, see the
+ /// TypeKind::TemplateInstantiation.
+ template_params: Vec<ItemId>,
/// The method declarations inside this class, if in C++ mode.
methods: Vec<Method>,
@@ -252,9 +253,6 @@ pub struct CompInfo {
/// Vector of classes this one inherits from.
base_members: Vec<Base>,
- /// The parent reference template if any.
- ref_template: Option<ItemId>,
-
/// The inner types that were declared inside this class, in something like:
///
/// class Foo {
@@ -320,11 +318,10 @@ impl CompInfo {
CompInfo {
kind: kind,
fields: vec![],
- template_args: vec![],
+ template_params: vec![],
methods: vec![],
constructors: vec![],
base_members: vec![],
- ref_template: None,
inner_types: vec![],
inner_vars: vec![],
has_vtable: false,
@@ -345,9 +342,7 @@ impl CompInfo {
!self.has_vtable(ctx) && self.fields.is_empty() &&
self.base_members.iter().all(|base| {
ctx.resolve_type(base.ty).canonical_type(ctx).is_unsized(ctx)
- }) &&
- self.ref_template
- .map_or(true, |template| ctx.resolve_type(template).is_unsized(ctx))
+ })
}
/// Does this compound type have a destructor?
@@ -364,16 +359,6 @@ impl CompInfo {
match self.kind {
CompKind::Union => false,
CompKind::Struct => {
- // NB: We can't rely on a type with type parameters
- // not having destructor.
- //
- // This is unfortunate, but...
- self.ref_template.as_ref().map_or(false, |t| {
- ctx.resolve_type(*t).has_destructor(ctx)
- }) ||
- self.template_args.iter().any(|t| {
- ctx.resolve_type(*t).has_destructor(ctx)
- }) ||
self.base_members.iter().any(|base| {
ctx.resolve_type(base.ty).has_destructor(ctx)
}) ||
@@ -389,16 +374,6 @@ impl CompInfo {
has_destructor
}
- /// Is this type a template specialization?
- pub fn is_template_specialization(&self) -> bool {
- self.ref_template.is_some()
- }
-
- /// Get the template declaration this specialization is specializing.
- pub fn specialized_template(&self) -> Option<ItemId> {
- self.ref_template
- }
-
/// Compute the layout of this type.
///
/// This is called as a fallback under some circumstances where LLVM doesn't
@@ -411,7 +386,7 @@ impl CompInfo {
use std::cmp;
// We can't do better than clang here, sorry.
if self.kind == CompKind::Struct {
- return None
+ return None;
}
let mut max_size = 0;
@@ -434,12 +409,6 @@ impl CompInfo {
&self.fields
}
- /// Get this type's set of free template arguments. Empty if this is not a
- /// template.
- pub fn template_args(&self) -> &[ItemId] {
- &self.template_args
- }
-
/// Does this type have any template parameters that aren't types
/// (e.g. int)?
pub fn has_non_type_template_params(&self) -> bool {
@@ -452,9 +421,6 @@ impl CompInfo {
self.base_members().iter().any(|base| {
ctx.resolve_type(base.ty)
.has_vtable(ctx)
- }) ||
- self.ref_template.map_or(false, |template| {
- ctx.resolve_type(template).has_vtable(ctx)
})
}
@@ -485,10 +451,9 @@ impl CompInfo {
ctx: &mut BindgenContext)
-> Result<Self, ParseError> {
use clang_sys::*;
- // Sigh... For class templates we want the location, for
- // specialisations, we want the declaration... So just try both.
- //
- // TODO: Yeah, this code reads really bad.
+ assert!(ty.template_args().is_none(),
+ "We handle template instantiations elsewhere");
+
let mut cursor = ty.declaration();
let mut kind = Self::kind_from_cursor(&cursor);
if kind.is_err() {
@@ -510,35 +475,6 @@ impl CompInfo {
CXCursor_ClassDecl => !cur.is_definition(),
_ => false,
});
- 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
- 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)
- .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 specialization && args.len() != num_arg_types {
- ci.has_non_type_template_params = true;
- warn!("warning: Template parameter is not a type");
- }
-
- if specialization { args } else { vec![] }
- }
- };
-
- ci.ref_template = cursor.specialized()
- .and_then(|c| Item::parse(c, None, ctx).ok());
let mut maybe_anonymous_struct_field = None;
cursor.visit(|cur| {
@@ -576,7 +512,7 @@ impl CompInfo {
let bit_width = cur.bit_width();
let field_type = Item::from_ty_or_ref(cur.cur_type(),
- Some(cur),
+ cur,
Some(potential_id),
ctx);
@@ -616,6 +552,7 @@ impl CompInfo {
}
CXCursor_EnumDecl |
CXCursor_TypeAliasDecl |
+ CXCursor_TypeAliasTemplateDecl |
CXCursor_TypedefDecl |
CXCursor_StructDecl |
CXCursor_UnionDecl |
@@ -668,9 +605,10 @@ impl CompInfo {
return CXChildVisit_Continue;
}
- let param =
- Item::named_type(cur.spelling(), potential_id, ctx);
- ci.template_args.push(param);
+ let param = Item::named_type(None, cur, ctx)
+ .expect("Item::named_type should't fail when pointing \
+ at a TemplateTypeParameter");
+ ci.template_params.push(param);
}
CXCursor_CXXBaseSpecifier => {
let is_virtual_base = cur.is_virtual_base();
@@ -682,10 +620,8 @@ impl CompInfo {
BaseKind::Normal
};
- let type_id = Item::from_ty_or_ref(cur.cur_type(),
- Some(cur),
- None,
- ctx);
+ let type_id =
+ Item::from_ty_or_ref(cur.cur_type(), cur, None, ctx);
ci.base_members.push(Base {
ty: type_id,
kind: kind,
@@ -711,7 +647,7 @@ impl CompInfo {
// Methods of template functions not only use to be inlined,
// but also instantiated, and we wouldn't be able to call
// them, so just bail out.
- if !ci.template_args.is_empty() {
+ if !ci.template_params.is_empty() {
return CXChildVisit_Continue;
}
@@ -778,7 +714,7 @@ impl CompInfo {
_ => {
warn!("unhandled comp member `{}` (kind {:?}) in `{}` ({})",
cur.spelling(),
- cur.kind(),
+ clang::kind_to_str(cur.kind()),
cursor.spelling(),
cur.location());
}
@@ -816,25 +752,6 @@ impl CompInfo {
})
}
- /// Do any of the types that participate in this type's "signature" use the
- /// named type `ty`?
- ///
- /// See also documentation for `ir::Item::signature_contains_named_type`.
- pub fn signature_contains_named_type(&self,
- ctx: &BindgenContext,
- ty: &Type)
- -> bool {
- // We don't generate these, so rather don't make the codegen step to
- // think we got it covered.
- if self.has_non_type_template_params() {
- return false;
- }
- self.template_args.iter().any(|arg| {
- ctx.resolve_type(*arg)
- .signature_contains_named_type(ctx, ty)
- })
- }
-
/// Get the set of types that were declared within this compound type
/// (e.g. nested class definitions).
pub fn inner_types(&self) -> &[ItemId] {
@@ -882,11 +799,13 @@ impl CompInfo {
}
impl TemplateDeclaration for CompInfo {
- fn self_template_params(&self, _ctx: &BindgenContext) -> Option<Vec<ItemId>> {
- if self.template_args.is_empty() {
+ fn self_template_params(&self,
+ _ctx: &BindgenContext)
+ -> Option<Vec<ItemId>> {
+ if self.template_params.is_empty() {
None
} else {
- Some(self.template_args.clone())
+ Some(self.template_params.clone())
}
}
}
@@ -925,13 +844,9 @@ impl CanDeriveDebug for CompInfo {
self.base_members
.iter()
.all(|base| base.ty.can_derive_debug(ctx, ())) &&
- self.template_args
- .iter()
- .all(|id| id.can_derive_debug(ctx, ())) &&
self.fields
.iter()
- .all(|f| f.can_derive_debug(ctx, ())) &&
- self.ref_template.map_or(true, |id| id.can_derive_debug(ctx, ()))
+ .all(|f| f.can_derive_debug(ctx, ()))
};
self.detect_derive_debug_cycle.set(false);
@@ -961,7 +876,7 @@ impl CanDeriveDefault for CompInfo {
return layout.unwrap_or_else(Layout::zero)
.opaque()
- .can_derive_debug(ctx, ());
+ .can_derive_default(ctx, ());
}
self.detect_derive_default_cycle.set(true);
@@ -971,14 +886,9 @@ impl CanDeriveDefault for CompInfo {
self.base_members
.iter()
.all(|base| base.ty.can_derive_default(ctx, ())) &&
- self.template_args
- .iter()
- .all(|id| id.can_derive_default(ctx, ())) &&
self.fields
.iter()
- .all(|f| f.can_derive_default(ctx, ())) &&
- self.ref_template
- .map_or(true, |id| id.can_derive_default(ctx, ()));
+ .all(|f| f.can_derive_default(ctx, ()));
self.detect_derive_default_cycle.set(false);
@@ -1013,17 +923,12 @@ impl<'a> CanDeriveCopy<'a> for CompInfo {
}
// https://github.com/rust-lang/rust/issues/36640
- if !self.template_args.is_empty() || self.ref_template.is_some() ||
- !item.applicable_template_args(ctx).is_empty() {
+ if !self.template_params.is_empty() ||
+ item.used_template_params(ctx).is_some() {
return false;
}
}
- // With template args, use a safe subset of the types,
- // since copyability depends on the types itself.
- self.ref_template
- .as_ref()
- .map_or(true, |t| t.can_derive_copy(ctx, ())) &&
self.base_members
.iter()
.all(|base| base.ty.can_derive_copy(ctx, ())) &&
@@ -1044,25 +949,9 @@ impl Trace for CompInfo {
fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
where T: Tracer,
{
- // TODO: We should properly distinguish template instantiations from
- // template declarations at the type level. Why are some template
- // instantiations represented here instead of as
- // TypeKind::TemplateInstantiation?
- if let Some(template) = self.specialized_template() {
- // This is an instantiation of a template declaration with concrete
- // template type arguments.
- tracer.visit_kind(template, EdgeKind::TemplateDeclaration);
- let args = item.applicable_template_args(context);
- for a in args {
- tracer.visit_kind(a, EdgeKind::TemplateArgument);
- }
- } else {
- let params = item.applicable_template_args(context);
- // This is a template declaration with abstract template type
- // parameters.
- for p in params {
- tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition);
- }
+ let params = item.all_template_params(context).unwrap_or(vec![]);
+ for p in params {
+ tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition);
}
for base in self.base_members() {
diff --git a/src/ir/context.rs b/src/ir/context.rs
index 27a43f20..6795a864 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -5,6 +5,8 @@ use super::int::IntKind;
use super::item::{Item, ItemCanonicalPath, ItemSet};
use super::item_kind::ItemKind;
use super::module::{Module, ModuleKind};
+use super::named::{UsedTemplateParameters, analyze};
+use super::template::TemplateInstantiation;
use super::traversal::{self, Edge, ItemTraversal};
use super::ty::{FloatKind, TemplateDeclaration, Type, TypeKind};
use BindgenOptions;
@@ -102,6 +104,10 @@ pub struct BindgenContext<'ctx> {
/// item ids during parsing.
types: HashMap<TypeKey, ItemId>,
+ /// Maps from a cursor to the item id of the named template type parameter
+ /// for that cursor.
+ named_types: HashMap<clang::Cursor, ItemId>,
+
/// A cursor to module map. Similar reason than above.
modules: HashMap<Cursor, ItemId>,
@@ -149,6 +155,11 @@ pub struct BindgenContext<'ctx> {
/// Whether a bindgen complex was generated
generated_bindegen_complex: Cell<bool>,
+
+ /// Map from an item's id to the set of template parameter items that it
+ /// uses. See `ir::named` for more details. Always `Some` during the codegen
+ /// phase.
+ used_template_parameters: Option<HashMap<ItemId, ItemSet>>,
}
/// A traversal of whitelisted items.
@@ -173,12 +184,13 @@ impl<'ctx> BindgenContext<'ctx> {
&options.clang_args,
&[],
parse_options)
- .expect("TranslationUnit::parse");
+ .expect("TranslationUnit::parse failed");
let root_module = Self::build_root_module(ItemId(0));
let mut me = BindgenContext {
items: Default::default(),
types: Default::default(),
+ named_types: Default::default(),
modules: Default::default(),
next_item_id: ItemId(1),
root_module: root_module.id(),
@@ -193,6 +205,7 @@ impl<'ctx> BindgenContext<'ctx> {
translation_unit: translation_unit,
options: options,
generated_bindegen_complex: Cell::new(false),
+ used_template_parameters: None,
};
me.add_item(root_module, None, None);
@@ -238,7 +251,8 @@ impl<'ctx> BindgenContext<'ctx> {
declaration,
location);
debug_assert!(declaration.is_some() || !item.kind().is_type() ||
- item.kind().expect_type().is_builtin_or_named(),
+ item.kind().expect_type().is_builtin_or_named() ||
+ item.kind().expect_type().is_opaque(),
"Adding a type without declaration?");
let id = item.id();
@@ -256,7 +270,8 @@ impl<'ctx> BindgenContext<'ctx> {
}
let old_item = self.items.insert(id, item);
- assert!(old_item.is_none(), "Inserted type twice?");
+ assert!(old_item.is_none(),
+ "should not have already associated an item with the given id");
// Unnamed items can have an USR, but they can't be referenced from
// other sites explicitly and the USR can match if the unnamed items are
@@ -299,6 +314,35 @@ impl<'ctx> BindgenContext<'ctx> {
}
}
+ /// Add a new named template type parameter to this context's item set.
+ pub fn add_named_type(&mut self, item: Item, definition: clang::Cursor) {
+ debug!("BindgenContext::add_named_type: item = {:?}; definition = {:?}",
+ item,
+ definition);
+
+ assert!(item.expect_type().is_named(),
+ "Should directly be a named type, not a resolved reference or anything");
+ assert_eq!(definition.kind(),
+ clang_sys::CXCursor_TemplateTypeParameter);
+
+ let id = item.id();
+ let old_item = self.items.insert(id, item);
+ assert!(old_item.is_none(),
+ "should not have already associated an item with the given id");
+
+ let old_named_ty = self.named_types.insert(definition, id);
+ assert!(old_named_ty.is_none(),
+ "should not have already associated a named type with this id");
+ }
+
+ /// Get the named type defined at the given cursor location, if we've
+ /// already added one.
+ pub fn get_named_type(&self, definition: &clang::Cursor) -> Option<ItemId> {
+ assert_eq!(definition.kind(),
+ clang_sys::CXCursor_TemplateTypeParameter);
+ self.named_types.get(definition).cloned()
+ }
+
// TODO: Move all this syntax crap to other part of the code.
/// Given that we are in the codegen phase, get the syntex context.
@@ -352,7 +396,7 @@ impl<'ctx> BindgenContext<'ctx> {
/// Gather all the unresolved type references.
fn collect_typerefs
(&mut self)
- -> Vec<(ItemId, clang::Type, Option<clang::Cursor>, Option<ItemId>)> {
+ -> Vec<(ItemId, clang::Type, clang::Cursor, Option<ItemId>)> {
debug_assert!(!self.collected_typerefs);
self.collected_typerefs = true;
let mut typerefs = vec![];
@@ -423,7 +467,7 @@ impl<'ctx> BindgenContext<'ctx> {
};
match *ty.kind() {
- TypeKind::Comp(ref ci) if !ci.is_template_specialization() => {}
+ TypeKind::Comp(..) |
TypeKind::TemplateAlias(..) |
TypeKind::Alias(..) => {}
_ => continue,
@@ -529,6 +573,8 @@ impl<'ctx> BindgenContext<'ctx> {
self.process_replacements();
}
+ self.find_used_template_parameters();
+
let ret = cb(self);
self.gen_ctx = None;
ret
@@ -555,6 +601,45 @@ impl<'ctx> BindgenContext<'ctx> {
traversal::all_edges)
}
+ fn find_used_template_parameters(&mut self) {
+ if self.options.whitelist_recursively {
+ let used_params = analyze::<UsedTemplateParameters>(self);
+ self.used_template_parameters = Some(used_params);
+ } else {
+ // If you aren't recursively whitelisting, then we can't really make
+ // any sense of template parameter usage, and you're on your own.
+ let mut used_params = HashMap::new();
+ for id in self.whitelisted_items() {
+ used_params.entry(id)
+ .or_insert(id.self_template_params(self)
+ .map_or(Default::default(),
+ |params| params.into_iter().collect()));
+ }
+ self.used_template_parameters = Some(used_params);
+ }
+ }
+
+ /// Return `true` if `item` uses the given `template_param`, `false`
+ /// otherwise.
+ ///
+ /// This method may only be called during the codegen phase, because the
+ /// template usage information is only computed as we enter the codegen
+ /// phase.
+ pub fn uses_template_parameter(&self,
+ item: ItemId,
+ template_param: ItemId)
+ -> bool {
+ assert!(self.in_codegen_phase(),
+ "We only compute template parameter usage as we enter codegen");
+
+ self.used_template_parameters
+ .as_ref()
+ .expect("should have found template parameter usage if we're in codegen")
+ .get(&item)
+ .map(|items_used_params| items_used_params.contains(&template_param))
+ .unwrap_or(false)
+ }
+
// This deserves a comment. Builtin types don't get a valid declaration, so
// we can't add it to the cursor->type map.
//
@@ -613,6 +698,21 @@ impl<'ctx> BindgenContext<'ctx> {
}
}
+ /// Resolve the given `ItemId` into a `Type`, and keep doing so while we see
+ /// `ResolvedTypeRef`s to other items until we get to the final `Type`.
+ pub fn resolve_type_through_type_refs(&self, item_id: ItemId) -> &Type {
+ assert!(self.collected_typerefs());
+
+ let mut id = item_id;
+ loop {
+ let ty = self.resolve_type(id);
+ match *ty.kind() {
+ TypeKind::ResolvedTypeRef(next_id) => id = next_id,
+ _ => return ty,
+ }
+ }
+ }
+
/// Get the current module.
pub fn current_module(&self) -> ItemId {
self.current_module
@@ -753,7 +853,7 @@ impl<'ctx> BindgenContext<'ctx> {
// template declaration as the parent. It is already parsed and
// has a known-resolvable `ItemId`.
let ty = Item::from_ty_or_ref(child.cur_type(),
- Some(*child),
+ *child,
Some(template),
self);
args.push(ty);
@@ -770,7 +870,7 @@ impl<'ctx> BindgenContext<'ctx> {
// Do a happy little parse. See comment in the TypeRef
// match arm about parent IDs.
let ty = Item::from_ty_or_ref(child.cur_type(),
- Some(*child),
+ *child,
Some(template),
self);
args.push(ty);
@@ -792,9 +892,9 @@ impl<'ctx> BindgenContext<'ctx> {
sub_args.reverse();
let sub_name = Some(template_decl_cursor.spelling());
+ let sub_inst = TemplateInstantiation::new(template_decl_id, sub_args);
let sub_kind =
- TypeKind::TemplateInstantiation(template_decl_id,
- sub_args);
+ TypeKind::TemplateInstantiation(sub_inst);
let sub_ty = Type::new(sub_name,
template_decl_cursor.cur_type()
.fallible_layout()
@@ -844,7 +944,8 @@ impl<'ctx> BindgenContext<'ctx> {
}
args.reverse();
- let type_kind = TypeKind::TemplateInstantiation(template, args);
+ let type_kind = TypeKind::TemplateInstantiation(
+ TemplateInstantiation::new(template, args));
let name = ty.spelling();
let name = if name.is_empty() { None } else { Some(name) };
let ty = Type::new(name,
@@ -863,9 +964,9 @@ impl<'ctx> BindgenContext<'ctx> {
/// If we have already resolved the type for the given type declaration,
/// return its `ItemId`. Otherwise, return `None`.
- fn get_resolved_type(&self,
- decl: &clang::CanonicalTypeDeclaration)
- -> Option<ItemId> {
+ pub fn get_resolved_type(&self,
+ decl: &clang::CanonicalTypeDeclaration)
+ -> Option<ItemId> {
self.types
.get(&TypeKey::Declaration(*decl.cursor()))
.or_else(|| {
@@ -904,16 +1005,15 @@ impl<'ctx> BindgenContext<'ctx> {
// of it, or
// * we have already parsed and resolved this type, and
// there's nothing left to do.
- //
- // Note that we only do the former if the `parent_id` exists,
- // and we have a location for building the new arguments. The
- // template argument names don't matter in the global context.
if decl.cursor().is_template_like() &&
*ty != decl.cursor().cur_type() &&
- location.is_some() &&
- parent_id.is_some() {
+ location.is_some() {
let location = location.unwrap();
- let parent_id = parent_id.unwrap();
+
+ // It is always safe to hang instantiations off of the root
+ // module. They use their template definition for naming,
+ // and don't need the parent for anything else.
+ let parent_id = self.root_module();
// For specialized type aliases, there's no way to get the
// template parameters as of this writing (for a struct
@@ -947,17 +1047,20 @@ impl<'ctx> BindgenContext<'ctx> {
self.build_builtin_ty(ty)
}
- // This is unfortunately a lot of bloat, but is needed to properly track
- // constness et. al.
- //
- // We should probably make the constness tracking separate, so it doesn't
- // bloat that much, but hey, we already bloat the heck out of builtin types.
- fn build_ty_wrapper(&mut self,
- with_id: ItemId,
- wrapped_id: ItemId,
- parent_id: Option<ItemId>,
- ty: &clang::Type)
- -> ItemId {
+ /// Make a new item that is a resolved type reference to the `wrapped_id`.
+ ///
+ /// This is unfortunately a lot of bloat, but is needed to properly track
+ /// constness et. al.
+ ///
+ /// We should probably make the constness tracking separate, so it doesn't
+ /// bloat that much, but hey, we already bloat the heck out of builtin
+ /// types.
+ pub fn build_ty_wrapper(&mut self,
+ with_id: ItemId,
+ wrapped_id: ItemId,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type)
+ -> ItemId {
let spelling = ty.spelling();
let is_const = ty.is_const();
let layout = ty.fallible_layout().ok();
@@ -1331,7 +1434,9 @@ impl PartialType {
}
impl TemplateDeclaration for PartialType {
- fn self_template_params(&self, _ctx: &BindgenContext) -> Option<Vec<ItemId>> {
+ fn self_template_params(&self,
+ _ctx: &BindgenContext)
+ -> Option<Vec<ItemId>> {
// Maybe at some point we will eagerly parse named types, but for now we
// don't and this information is unavailable.
None
diff --git a/src/ir/dot.rs b/src/ir/dot.rs
index b7a117bb..e7e1f47b 100644
--- a/src/ir/dot.rs
+++ b/src/ir/dot.rs
@@ -1,23 +1,26 @@
//! Generating Graphviz `dot` files from our IR.
+use super::context::{BindgenContext, ItemId};
+use super::traversal::Trace;
use std::fs::File;
use std::io::{self, Write};
use std::path::Path;
-use super::context::{BindgenContext, ItemId};
-use super::traversal::Trace;
/// A trait for anything that can write attributes as `<table>` rows to a dot
/// file.
pub trait DotAttributes {
/// Write this thing's attributes to the given output. Each attribute must
/// be its own `<tr>...</tr>`.
- fn dot_attributes<W>(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()>
+ fn dot_attributes<W>(&self,
+ ctx: &BindgenContext,
+ out: &mut W)
+ -> io::Result<()>
where W: io::Write;
}
/// Write a graphviz dot file containing our IR.
pub fn write_dot_file<P>(ctx: &BindgenContext, path: P) -> io::Result<()>
- where P: AsRef<Path>
+ where P: AsRef<Path>,
{
let file = try!(File::create(path));
let mut dot_file = io::BufWriter::new(file);
@@ -32,16 +35,21 @@ pub fn write_dot_file<P>(ctx: &BindgenContext, path: P) -> io::Result<()>
try!(item.dot_attributes(ctx, &mut dot_file));
try!(writeln!(&mut dot_file, r#"</table> >];"#));
- item.trace(ctx, &mut |sub_id: ItemId, _edge_kind| {
+ item.trace(ctx,
+ &mut |sub_id: ItemId, _edge_kind| {
if err.is_some() {
return;
}
- match writeln!(&mut dot_file, "{} -> {};", id.as_usize(), sub_id.as_usize()) {
- Ok(_) => {},
+ match writeln!(&mut dot_file,
+ "{} -> {};",
+ id.as_usize(),
+ sub_id.as_usize()) {
+ Ok(_) => {}
Err(e) => err = Some(Err(e)),
}
- }, &());
+ },
+ &());
if let Some(err) = err {
return err;
diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs
index 3470e033..d2385a29 100644
--- a/src/ir/enum_ty.rs
+++ b/src/ir/enum_ty.rs
@@ -60,7 +60,7 @@ impl Enum {
let declaration = ty.declaration().canonical();
let repr = declaration.enum_type()
- .and_then(|et| Item::from_ty(&et, None, None, ctx).ok());
+ .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok());
let mut variants = vec![];
// Assume signedness since the default type by the C standard is an int.
@@ -99,7 +99,7 @@ impl Enum {
Annotations::new(&cursor)
.and_then(|anno| if anno.hide() {
Some(EnumVariantCustomBehavior::Hide)
- } else if
+ } else if
anno.constify_enum_variant() {
Some(EnumVariantCustomBehavior::Constify)
} else {
diff --git a/src/ir/function.rs b/src/ir/function.rs
index ad336c4b..e82ba83c 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -5,9 +5,9 @@ use super::dot::DotAttributes;
use super::item::Item;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::TypeKind;
-use ir::derive::CanDeriveDebug;
use clang;
use clang_sys::CXCallingConv;
+use ir::derive::CanDeriveDebug;
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
use std::io;
use syntax::abi;
@@ -63,11 +63,16 @@ impl Function {
}
impl DotAttributes for Function {
- fn dot_attributes<W>(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()>
- where W: io::Write
+ fn dot_attributes<W>(&self,
+ _ctx: &BindgenContext,
+ out: &mut W)
+ -> io::Result<()>
+ where W: io::Write,
{
if let Some(ref mangled) = self.mangled_name {
- try!(writeln!(out, "<tr><td>mangled name</td><td>{}</td></tr>", mangled));
+ try!(writeln!(out,
+ "<tr><td>mangled name</td><td>{}</td></tr>",
+ mangled));
}
Ok(())
@@ -188,8 +193,7 @@ impl FunctionSig {
let name = arg.spelling();
let name =
if name.is_empty() { None } else { Some(name) };
- let ty =
- Item::from_ty_or_ref(arg_ty, Some(*arg), None, ctx);
+ let ty = Item::from_ty_or_ref(arg_ty, *arg, None, ctx);
(name, ty)
})
.collect()
@@ -200,10 +204,8 @@ impl FunctionSig {
let mut args = vec![];
cursor.visit(|c| {
if c.kind() == CXCursor_ParmDecl {
- let ty = Item::from_ty_or_ref(c.cur_type(),
- Some(c),
- None,
- ctx);
+ let ty =
+ Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
let name = c.spelling();
let name =
if name.is_empty() { None } else { Some(name) };
@@ -246,7 +248,7 @@ impl FunctionSig {
} else {
try!(ty.ret_type().ok_or(ParseError::Continue))
};
- let ret = Item::from_ty_or_ref(ty_ret_type, None, None, ctx);
+ let ret = Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx);
let abi = get_abi(ty.call_conv());
if abi.is_none() {
@@ -317,10 +319,8 @@ impl ClangSubItemParser for Function {
}
// Grab the signature using Item::from_ty.
- let sig = try!(Item::from_ty(&cursor.cur_type(),
- Some(cursor),
- None,
- context));
+ let sig =
+ try!(Item::from_ty(&cursor.cur_type(), cursor, None, context));
let name = cursor.spelling();
assert!(!name.is_empty(), "Empty function name?");
@@ -368,7 +368,8 @@ impl CanDeriveDebug for FunctionSig {
}
match self.abi {
- Some(abi::Abi::C) | None => true,
+ Some(abi::Abi::C) |
+ None => true,
_ => false,
}
}
diff --git a/src/ir/item.rs b/src/ir/item.rs
index 21b27f07..93df9c77 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -3,10 +3,12 @@
use super::annotations::Annotations;
use super::context::{BindgenContext, ItemId, PartialType};
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
-use super::dot::{DotAttributes};
+use super::dot::DotAttributes;
use super::function::Function;
use super::item_kind::ItemKind;
+use super::layout::Opaque;
use super::module::Module;
+use super::template::AsNamed;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::{TemplateDeclaration, Type, TypeKind};
use clang;
@@ -15,8 +17,8 @@ use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
use std::cell::{Cell, RefCell};
use std::collections::BTreeSet;
use std::fmt::Write;
-use std::iter;
use std::io;
+use std::iter;
/// A trait to get the canonical name from an item.
///
@@ -128,6 +130,35 @@ impl<'a, 'b> Iterator for ItemAncestorsIter<'a, 'b>
}
}
+impl AsNamed for ItemId {
+ type Extra = ();
+
+ fn as_named(&self, ctx: &BindgenContext, _: &()) -> Option<ItemId> {
+ ctx.resolve_item(*self).as_named(ctx, &())
+ }
+}
+
+impl AsNamed for Item {
+ type Extra = ();
+
+ fn as_named(&self, ctx: &BindgenContext, _: &()) -> Option<ItemId> {
+ self.kind.as_named(ctx, self)
+ }
+}
+
+impl AsNamed for ItemKind {
+ type Extra = Item;
+
+ fn as_named(&self, ctx: &BindgenContext, item: &Item) -> Option<ItemId> {
+ match *self {
+ ItemKind::Type(ref ty) => ty.as_named(ctx, item),
+ ItemKind::Module(..) |
+ ItemKind::Function(..) |
+ ItemKind::Var(..) => None,
+ }
+ }
+}
+
// Pure convenience
impl ItemCanonicalName for ItemId {
fn canonical_name(&self, ctx: &BindgenContext) -> String {
@@ -224,8 +255,14 @@ impl CanDeriveDebug for Item {
type Extra = ();
fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
- ctx.options().derive_debug &&
- match self.kind {
+ if self.detect_derive_debug_cycle.get() {
+ return true;
+ }
+
+ self.detect_derive_debug_cycle.set(true);
+
+ let result = ctx.options().derive_debug &&
+ match self.kind {
ItemKind::Type(ref ty) => {
if self.is_opaque(ctx) {
ty.layout(ctx)
@@ -235,7 +272,11 @@ impl CanDeriveDebug for Item {
}
}
_ => false,
- }
+ };
+
+ self.detect_derive_debug_cycle.set(false);
+
+ result
}
}
@@ -263,7 +304,13 @@ impl<'a> CanDeriveCopy<'a> for Item {
type Extra = ();
fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
- match self.kind {
+ if self.detect_derive_copy_cycle.get() {
+ return true;
+ }
+
+ self.detect_derive_copy_cycle.set(true);
+
+ let result = match self.kind {
ItemKind::Type(ref ty) => {
if self.is_opaque(ctx) {
ty.layout(ctx)
@@ -273,7 +320,11 @@ impl<'a> CanDeriveCopy<'a> for Item {
}
}
_ => false,
- }
+ };
+
+ self.detect_derive_copy_cycle.set(false);
+
+ result
}
fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
@@ -346,6 +397,16 @@ pub struct Item {
parent_id: ItemId,
/// The item kind.
kind: ItemKind,
+ /// Detect cycles when determining if we can derive debug/copy or not, and
+ /// avoid infinite recursion.
+ detect_derive_debug_cycle: Cell<bool>,
+ detect_derive_copy_cycle: Cell<bool>,
+}
+
+impl AsRef<ItemId> for Item {
+ fn as_ref(&self) -> &ItemId {
+ &self.id
+ }
}
impl Item {
@@ -366,9 +427,22 @@ impl Item {
comment: comment,
annotations: annotations.unwrap_or_default(),
kind: kind,
+ detect_derive_debug_cycle: Cell::new(false),
+ detect_derive_copy_cycle: Cell::new(false),
}
}
+ fn new_opaque_type(with_id: ItemId,
+ ty: &clang::Type,
+ ctx: &mut BindgenContext)
+ -> ItemId {
+ let ty = Opaque::from_clang_ty(ty);
+ let kind = ItemKind::Type(ty);
+ let parent = ctx.root_module();
+ ctx.add_item(Item::new(with_id, None, None, parent, kind), None, None);
+ with_id
+ }
+
/// Get this `Item`'s identifier.
pub fn id(&self) -> ItemId {
self.id
@@ -474,184 +548,12 @@ impl Item {
self.kind().as_type()
}
- /// Is this item a named template type parameter?
- pub fn is_named(&self) -> bool {
- self.as_type()
- .map(|ty| ty.is_named())
- .unwrap_or(false)
- }
-
/// Get a reference to this item's underlying `Function`. Panic if this is
/// some other kind of item.
pub fn expect_function(&self) -> &Function {
self.kind().expect_function()
}
- /// Checks whether an item contains in its "type signature" some named type.
- ///
- /// This function is used to avoid unused template parameter errors in Rust
- /// when generating typedef declarations, and also to know whether we need
- /// to generate a `PhantomData` member for a template parameter.
- ///
- /// For example, in code like the following:
- ///
- /// ```c++
- /// template<typename T, typename U>
- /// struct Foo {
- /// T bar;
- ///
- /// struct Baz {
- /// U bas;
- /// };
- /// };
- /// ```
- ///
- /// Both `Foo` and `Baz` contain both `T` and `U` template parameters in
- /// their signature:
- ///
- /// * `Foo<T, U>`
- /// * `Bar<T, U>`
- ///
- /// But the Rust structure for `Foo` would look like:
- ///
- /// ```rust
- /// struct Foo<T, U> {
- /// bar: T,
- /// _phantom0: ::std::marker::PhantomData<U>,
- /// }
- /// ```
- ///
- /// because none of its member fields contained the `U` type in the
- /// signature. Similarly, `Bar` would contain a `PhantomData<T>` type, for
- /// the same reason.
- ///
- /// Note that this is somewhat similar to `applicable_template_args`, but
- /// this also takes into account other kind of types, like arrays,
- /// (`[T; 40]`), pointers: `*mut T`, etc...
- ///
- /// Normally we could do this check just in the `Type` kind, but we also
- /// need to check the `applicable_template_args` more generally, since we
- /// could need a type transitively from our parent, see the test added in
- /// commit 2a3f93074dd2898669dbbce6e97e5cc4405d7cb1.
- ///
- /// It's kind of unfortunate (in the sense that it's a sort of complex
- /// process), but I think it should get 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)
- })
- }
-
- /// Returns the template arguments that apply to a struct. This is a concept
- /// needed because of type declarations inside templates, for example:
- ///
- /// ```c++
- /// template<typename T>
- /// class Foo {
- /// typedef T element_type;
- /// typedef int Bar;
- ///
- /// template<typename U>
- /// class Baz {
- /// };
- /// };
- /// ```
- ///
- /// In this case, the applicable template arguments for the different types
- /// would be:
- ///
- /// * `Foo`: [`T`]
- /// * `Foo::element_type`: [`T`]
- /// * `Foo::Bar`: [`T`]
- /// * `Foo::Baz`: [`T`, `U`]
- ///
- /// You might notice that we can't generate something like:
- ///
- /// ```rust,ignore
- /// type Foo_Bar<T> = ::std::os::raw::c_int;
- /// ```
- ///
- /// since that would be invalid Rust. Still, conceptually, `Bar` *could* use
- /// the template parameter type `T`, and that's exactly what this method
- /// represents. The unused template parameters get stripped in the
- /// `signature_contains_named_type` check.
- pub fn applicable_template_args(&self,
- ctx: &BindgenContext)
- -> Vec<ItemId> {
- let ty = match *self.kind() {
- ItemKind::Type(ref ty) => ty,
- _ => return vec![],
- };
-
- fn parent_contains(ctx: &BindgenContext,
- parent_template_args: &[ItemId],
- item: ItemId)
- -> bool {
- let item_ty = ctx.resolve_type(item);
- parent_template_args.iter().any(|parent_item| {
- let parent_ty = ctx.resolve_type(*parent_item);
- match (parent_ty.kind(), item_ty.kind()) {
- (&TypeKind::Named, &TypeKind::Named) => {
- parent_ty.name() == item_ty.name()
- }
- _ => false,
- }
- })
- }
-
- match *ty.kind() {
- TypeKind::Named => vec![self.id()],
- TypeKind::Array(inner, _) |
- TypeKind::Pointer(inner) |
- TypeKind::Reference(inner) |
- TypeKind::ResolvedTypeRef(inner) => {
- ctx.resolve_item(inner).applicable_template_args(ctx)
- }
- TypeKind::Alias(inner) => {
- let parent_args = ctx.resolve_item(self.parent_id())
- .applicable_template_args(ctx);
- let inner = ctx.resolve_item(inner);
-
- // Avoid unused type parameters, sigh.
- parent_args.iter()
- .cloned()
- .filter(|arg| {
- let arg = ctx.resolve_type(*arg);
- arg.is_named() &&
- inner.signature_contains_named_type(ctx, arg)
- })
- .collect()
- }
- // XXX Is this completely correct? Partial template specialization
- // is hard anyways, sigh...
- TypeKind::TemplateAlias(_, ref args) |
- TypeKind::TemplateInstantiation(_, ref args) => args.clone(),
- // In a template specialization we've got all we want.
- TypeKind::Comp(ref ci) if ci.is_template_specialization() => {
- ci.template_args().iter().cloned().collect()
- }
- TypeKind::Comp(ref ci) => {
- let mut parent_template_args =
- ctx.resolve_item(self.parent_id())
- .applicable_template_args(ctx);
-
- for ty in ci.template_args() {
- if !parent_contains(ctx, &parent_template_args, *ty) {
- parent_template_args.push(*ty);
- }
- }
-
- parent_template_args
- }
- _ => vec![],
- }
- }
-
/// Is this item a module?
pub fn is_module(&self) -> bool {
match self.kind {
@@ -680,6 +582,7 @@ impl Item {
debug_assert!(ctx.in_codegen_phase(),
"You're not supposed to call this yet");
self.annotations.opaque() ||
+ self.as_type().map_or(false, |ty| ty.is_opaque()) ||
ctx.opaque_by_name(&self.canonical_path(ctx))
}
@@ -719,19 +622,12 @@ impl Item {
match *item.kind() {
ItemKind::Type(ref ty) => {
match *ty.kind() {
- // If we're a template specialization, our name is our
- // parent's name.
- TypeKind::Comp(ref ci)
- if ci.is_template_specialization() => {
- let specialized =
- ci.specialized_template().unwrap();
- item = ctx.resolve_item(specialized);
- }
- // Same as above.
- TypeKind::ResolvedTypeRef(inner) |
- TypeKind::TemplateInstantiation(inner, _) => {
+ TypeKind::ResolvedTypeRef(inner) => {
item = ctx.resolve_item(inner);
}
+ TypeKind::TemplateInstantiation(ref inst) => {
+ item = ctx.resolve_item(inst.template_definition());
+ }
_ => return item.id(),
}
}
@@ -845,7 +741,7 @@ impl Item {
// Named template type arguments are never namespaced, and never
// mangled.
- if target.as_type().map_or(false, |ty| ty.is_named()) {
+ if target.is_named(ctx, &()) {
return base_name;
}
@@ -917,8 +813,11 @@ impl Item {
pub type ItemSet = BTreeSet<ItemId>;
impl DotAttributes for Item {
- fn dot_attributes<W>(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()>
- where W: io::Write
+ fn dot_attributes<W>(&self,
+ ctx: &BindgenContext,
+ out: &mut W)
+ -> io::Result<()>
+ where W: io::Write,
{
try!(writeln!(out,
"<tr><td>{:?}</td></tr>
@@ -930,20 +829,26 @@ impl DotAttributes for Item {
}
impl TemplateDeclaration for ItemId {
- fn self_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
+ fn self_template_params(&self,
+ ctx: &BindgenContext)
+ -> Option<Vec<ItemId>> {
ctx.resolve_item_fallible(*self)
.and_then(|item| item.self_template_params(ctx))
}
}
impl TemplateDeclaration for Item {
- fn self_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
+ fn self_template_params(&self,
+ ctx: &BindgenContext)
+ -> Option<Vec<ItemId>> {
self.kind.self_template_params(ctx)
}
}
impl TemplateDeclaration for ItemKind {
- fn self_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
+ fn self_template_params(&self,
+ ctx: &BindgenContext)
+ -> Option<Vec<ItemId>> {
match *self {
ItemKind::Type(ref ty) => ty.self_template_params(ctx),
// If we start emitting bindings to explicitly instantiated
@@ -969,7 +874,7 @@ fn visit_child(cur: clang::Cursor,
return CXChildVisit_Break;
}
- *result = Item::from_ty_with_id(id, ty, Some(cur), parent_id, ctx);
+ *result = Item::from_ty_with_id(id, ty, cur, parent_id, ctx);
match *result {
Ok(..) => CXChildVisit_Break,
@@ -1062,8 +967,8 @@ impl ClangItemParser for Item {
// twice, handle them separately.
{
let applicable_cursor = cursor.definition().unwrap_or(cursor);
- match Self::from_ty(&applicable_cursor.cur_type(),
- Some(applicable_cursor),
+ match Item::from_ty(&applicable_cursor.cur_type(),
+ applicable_cursor,
parent_id,
ctx) {
Ok(ty) => return Ok(ty),
@@ -1105,7 +1010,7 @@ impl ClangItemParser for Item {
}
fn from_ty_or_ref(ty: clang::Type,
- location: Option<clang::Cursor>,
+ location: clang::Cursor,
parent_id: Option<ItemId>,
ctx: &mut BindgenContext)
-> ItemId {
@@ -1125,7 +1030,7 @@ impl ClangItemParser for Item {
/// `BindgenContext::resolve_typerefs`.
fn from_ty_or_ref_with_id(potential_id: ItemId,
ty: clang::Type,
- location: Option<clang::Cursor>,
+ location: clang::Cursor,
parent_id: Option<ItemId>,
ctx: &mut BindgenContext)
-> ItemId {
@@ -1137,16 +1042,20 @@ impl ClangItemParser for Item {
if ctx.collected_typerefs() {
debug!("refs already collected, resolving directly");
- return Self::from_ty_with_id(potential_id,
+ return Item::from_ty_with_id(potential_id,
&ty,
location,
parent_id,
ctx)
- .expect("Unable to resolve type");
+ .unwrap_or_else(|_| {
+ Item::new_opaque_type(potential_id, &ty, ctx)
+ });
}
- if let Some(ty) =
- ctx.builtin_or_resolved_ty(potential_id, parent_id, &ty, location) {
+ if let Some(ty) = ctx.builtin_or_resolved_ty(potential_id,
+ parent_id,
+ &ty,
+ Some(location)) {
debug!("{:?} already resolved: {:?}", ty, location);
return ty;
}
@@ -1169,14 +1078,13 @@ impl ClangItemParser for Item {
potential_id
}
-
fn from_ty(ty: &clang::Type,
- location: Option<clang::Cursor>,
+ location: clang::Cursor,
parent_id: Option<ItemId>,
ctx: &mut BindgenContext)
-> Result<ItemId, ParseError> {
let id = ctx.next_item_id();
- Self::from_ty_with_id(id, ty, location, parent_id, ctx)
+ Item::from_ty_with_id(id, ty, location, parent_id, ctx)
}
/// This is one of the trickiest methods you'll find (probably along with
@@ -1189,21 +1097,41 @@ impl ClangItemParser for Item {
/// context.
fn from_ty_with_id(id: ItemId,
ty: &clang::Type,
- location: Option<clang::Cursor>,
+ location: clang::Cursor,
parent_id: Option<ItemId>,
ctx: &mut BindgenContext)
-> Result<ItemId, ParseError> {
use clang_sys::*;
+ debug!("Item::from_ty_with_id: {:?}\n\
+ \tty = {:?},\n\
+ \tlocation = {:?}",
+ id,
+ ty,
+ location);
+
+ if ty.kind() == clang_sys::CXType_Unexposed ||
+ location.cur_type().kind() == clang_sys::CXType_Unexposed {
+
+ if ty.is_associated_type() ||
+ location.cur_type().is_associated_type() {
+ return Ok(Item::new_opaque_type(id, ty, ctx));
+ }
+
+ if let Some(id) = Item::named_type(Some(id), location, ctx) {
+ return Ok(id);
+ }
+ }
+
let decl = {
let decl = ty.declaration();
decl.definition().unwrap_or(decl)
};
let comment = decl.raw_comment()
- .or_else(|| location.as_ref().and_then(|l| l.raw_comment()));
+ .or_else(|| location.raw_comment());
let annotations = Annotations::new(&decl)
- .or_else(|| location.as_ref().and_then(|l| Annotations::new(l)));
+ .or_else(|| Annotations::new(&location));
if let Some(ref annotations) = annotations {
if let Some(ref replaced) = annotations.use_instead_of() {
@@ -1212,7 +1140,7 @@ impl ClangItemParser for Item {
}
if let Some(ty) =
- ctx.builtin_or_resolved_ty(id, parent_id, ty, location) {
+ ctx.builtin_or_resolved_ty(id, parent_id, ty, Some(location)) {
return Ok(ty);
}
@@ -1220,11 +1148,10 @@ impl ClangItemParser for Item {
let mut valid_decl = decl.kind() != CXCursor_NoDeclFound;
let declaration_to_look_for = if valid_decl {
decl.canonical()
- } else if location.is_some() &&
- location.unwrap().kind() ==
+ } else if location.kind() ==
CXCursor_ClassTemplate {
valid_decl = true;
- location.unwrap()
+ location
} else {
decl
};
@@ -1255,51 +1182,47 @@ impl ClangItemParser for Item {
relevant_parent_id,
ItemKind::Type(item)),
declaration,
- location);
+ Some(location));
Ok(id)
}
Err(ParseError::Continue) => Err(ParseError::Continue),
Err(ParseError::Recurse) => {
debug!("Item::from_ty recursing in the ast");
let mut result = Err(ParseError::Recurse);
- if let Some(ref location) = location {
- // Need to pop here, otherwise we'll get stuck.
- //
- // TODO: Find a nicer interface, really. Also, the
- // declaration_to_look_for suspiciously shares a lot of
- // logic with ir::context, so we should refactor that.
- if valid_decl {
- let finished = ctx.finish_parsing();
- assert_eq!(*finished.decl(), declaration_to_look_for);
- }
- location.visit(|cur| {
- visit_child(cur, id, ty, parent_id, ctx, &mut result)
- });
+ // Need to pop here, otherwise we'll get stuck.
+ //
+ // TODO: Find a nicer interface, really. Also, the
+ // declaration_to_look_for suspiciously shares a lot of
+ // logic with ir::context, so we should refactor that.
+ if valid_decl {
+ let finished = ctx.finish_parsing();
+ assert_eq!(*finished.decl(), declaration_to_look_for);
+ }
- if valid_decl {
- let partial_ty =
- PartialType::new(declaration_to_look_for, id);
- ctx.begin_parsing(partial_ty);
- }
+ location.visit(|cur| {
+ visit_child(cur, id, ty, parent_id, ctx, &mut result)
+ });
+
+ if valid_decl {
+ let partial_ty = PartialType::new(declaration_to_look_for,
+ id);
+ ctx.begin_parsing(partial_ty);
}
+
// If we have recursed into the AST all we know, and we still
- // haven't found what we've got, let's just make a named type.
+ // haven't found what we've got, let's just try and make a named
+ // type.
//
// This is what happens with some template members, for example.
- //
- // FIXME: Maybe we should restrict this to things with parent?
- // It's harmless, but if we restrict that, then
- // tests/headers/nsStyleAutoArray.hpp crashes.
if let Err(ParseError::Recurse) = result {
warn!("Unknown type, assuming named template type: \
id = {:?}; spelling = {}",
id,
ty.spelling());
- Ok(Self::named_type_with_id(id,
- ty.spelling(),
- relevant_parent_id,
- ctx))
+ Item::named_type(Some(id), location, ctx)
+ .map(Ok)
+ .unwrap_or(Err(ParseError::Recurse))
} else {
result
}
@@ -1317,40 +1240,150 @@ impl ClangItemParser for Item {
/// A named type is a template parameter, e.g., the "T" in Foo<T>. They're
/// always local so it's the only exception when there's no declaration for
/// a type.
- ///
- /// It must have an id, and must not be the current module id. Ideally we
- /// could assert the parent id is a Comp(..) type, but that info isn't
- /// available yet.
- fn named_type_with_id<S>(id: ItemId,
- name: S,
- parent_id: ItemId,
- ctx: &mut BindgenContext)
- -> ItemId
- where S: Into<String>,
- {
- // see tests/headers/const_tparam.hpp
- // and tests/headers/variadic_tname.hpp
- let name = name.into().replace("const ", "").replace(".", "");
+ fn named_type(with_id: Option<ItemId>,
+ location: clang::Cursor,
+ ctx: &mut BindgenContext)
+ -> Option<ItemId> {
+ let ty = location.cur_type();
+
+ debug!("Item::named_type:\n\
+ \twith_id = {:?},\n\
+ \tty = {} {:?},\n\
+ \tlocation: {:?}",
+ with_id,
+ ty.spelling(),
+ ty,
+ location);
+
+ if ty.kind() != clang_sys::CXType_Unexposed {
+ // If the given cursor's type's kind is not Unexposed, then we
+ // aren't looking at a template parameter. This check may need to be
+ // updated in the future if they start properly exposing template
+ // type parameters.
+ return None;
+ }
- ctx.add_item(Item::new(id,
- None,
- None,
- parent_id,
- ItemKind::Type(Type::named(name))),
- None,
- None);
+ let ty_spelling = ty.spelling();
- id
- }
+ // Clang does not expose any information about template type parameters
+ // via their clang::Type, nor does it give us their canonical cursors
+ // the straightforward way. However, there are three situations from
+ // which we can find the definition of the template type parameter, if
+ // the cursor is indeed looking at some kind of a template type
+ // parameter or use of one:
+ //
+ // 1. The cursor is pointing at the template type parameter's
+ // definition. This is the trivial case.
+ //
+ // (kind = TemplateTypeParameter, ...)
+ //
+ // 2. The cursor is pointing at a TypeRef whose referenced() cursor is
+ // situation (1).
+ //
+ // (kind = TypeRef,
+ // referenced = (kind = TemplateTypeParameter, ...),
+ // ...)
+ //
+ // 3. The cursor is pointing at some use of a template type parameter
+ // (for example, in a FieldDecl), and this cursor has a child cursor
+ // whose spelling is the same as the parent's type's spelling, and whose
+ // kind is a TypeRef of the situation (2) variety.
+ //
+ // (kind = FieldDecl,
+ // type = (kind = Unexposed,
+ // spelling = "T",
+ // ...),
+ // children =
+ // (kind = TypeRef,
+ // spelling = "T",
+ // referenced = (kind = TemplateTypeParameter,
+ // spelling = "T",
+ // ...),
+ // ...)
+ // ...)
+ //
+ // TODO: The alternative to this hacky pattern matching would be to
+ // maintain proper scopes of template parameters while parsing and use
+ // de Brujin indices to access template parameters, which clang exposes
+ // in the cursor's type's canonical type's spelling:
+ // "type-parameter-x-y". That is probably a better approach long-term,
+ // but maintaining these scopes properly would require more changes to
+ // the whole libclang -> IR parsing code.
+
+ fn is_template_with_spelling(refd: &clang::Cursor,
+ spelling: &str)
+ -> bool {
+ refd.kind() == clang_sys::CXCursor_TemplateTypeParameter &&
+ refd.spelling() == spelling
+ }
- fn named_type<S>(name: S,
- parent_id: ItemId,
- ctx: &mut BindgenContext)
- -> ItemId
- where S: Into<String>,
- {
- let id = ctx.next_item_id();
- Self::named_type_with_id(id, name, parent_id, ctx)
+ let definition = if is_template_with_spelling(&location,
+ &ty_spelling) {
+ // Situation (1)
+ location
+ } else if location.kind() ==
+ clang_sys::CXCursor_TypeRef {
+ // Situation (2)
+ match location.referenced() {
+ Some(refd) if is_template_with_spelling(&refd,
+ &ty_spelling) => refd,
+ _ => return None,
+ }
+ } else {
+ // Situation (3)
+ let mut definition = None;
+
+ location.visit(|child| {
+ let child_ty = child.cur_type();
+ if child_ty.kind() == clang_sys::CXCursor_TypeRef &&
+ child_ty.spelling() == ty_spelling {
+ match child.referenced() {
+ Some(refd) if is_template_with_spelling(&refd, &ty_spelling) => {
+ definition = Some(refd);
+ return clang_sys::CXChildVisit_Break;
+ }
+ _ => {}
+ }
+ }
+
+ clang_sys::CXChildVisit_Continue
+ });
+
+ if let Some(def) = definition {
+ def
+ } else {
+ return None;
+ }
+ };
+ assert!(is_template_with_spelling(&definition, &ty_spelling));
+
+ // Named types are always parented to the root module. They are never
+ // referenced with namespace prefixes, and they can't inherit anything
+ // from their parent either, so it is simplest to just hang them off
+ // something we know will always exist.
+ let parent = ctx.root_module();
+
+ if let Some(id) = ctx.get_named_type(&definition) {
+ if let Some(with_id) = with_id {
+ return Some(ctx.build_ty_wrapper(with_id, id, Some(parent), &ty));
+ } else {
+ return Some(id);
+ }
+ }
+
+ // See tests/headers/const_tparam.hpp and
+ // tests/headers/variadic_tname.hpp.
+ let name = ty_spelling.replace("const ", "")
+ .replace(".", "");
+
+ let id = with_id.unwrap_or_else(|| ctx.next_item_id());
+ let item = Item::new(id,
+ None,
+ None,
+ parent,
+ ItemKind::Type(Type::named(name)));
+ ctx.add_named_type(item, definition);
+ Some(id)
}
}
diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs
index 6dfd6764..419f9d44 100644
--- a/src/ir/item_kind.rs
+++ b/src/ir/item_kind.rs
@@ -1,12 +1,12 @@
//! Different variants of an `Item` in our intermediate representation.
-use std::io;
use super::context::BindgenContext;
use super::dot::DotAttributes;
use super::function::Function;
use super::module::Module;
use super::ty::Type;
use super::var::Var;
+use std::io;
/// A item we parse and translate.
#[derive(Debug)]
@@ -41,7 +41,7 @@ impl ItemKind {
ItemKind::Module(..) => "Module",
ItemKind::Type(..) => "Type",
ItemKind::Function(..) => "Function",
- ItemKind::Var(..) => "Var"
+ ItemKind::Var(..) => "Var",
}
}
@@ -127,10 +127,15 @@ impl ItemKind {
}
impl DotAttributes for ItemKind {
- fn dot_attributes<W>(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()>
- where W: io::Write
+ fn dot_attributes<W>(&self,
+ ctx: &BindgenContext,
+ out: &mut W)
+ -> io::Result<()>
+ where W: io::Write,
{
- try!(writeln!(out, "<tr><td>kind</td><td>{}</td></tr>", self.kind_name()));
+ try!(writeln!(out,
+ "<tr><td>kind</td><td>{}</td></tr>",
+ self.kind_name()));
match *self {
ItemKind::Module(ref module) => module.dot_attributes(ctx, out),
diff --git a/src/ir/layout.rs b/src/ir/layout.rs
index f21a501c..21382b2d 100644
--- a/src/ir/layout.rs
+++ b/src/ir/layout.rs
@@ -2,7 +2,8 @@
use super::context::BindgenContext;
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
-use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
+use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind};
+use clang;
use std::{cmp, mem};
/// A type that represents the struct layout of a type.
@@ -20,7 +21,8 @@ pub struct Layout {
fn test_layout_for_size() {
let ptr_size = mem::size_of::<*mut ()>();
assert_eq!(Layout::for_size(ptr_size), Layout::new(ptr_size, ptr_size));
- assert_eq!(Layout::for_size(3 * ptr_size), Layout::new(3 * ptr_size, ptr_size));
+ assert_eq!(Layout::for_size(3 * ptr_size),
+ Layout::new(3 * ptr_size, ptr_size));
}
impl Layout {
@@ -38,7 +40,8 @@ impl Layout {
/// alignment possible.
pub fn for_size(size: usize) -> Self {
let mut next_align = 2;
- while size % next_align == 0 && next_align <= mem::size_of::<*mut ()>() {
+ while size % next_align == 0 &&
+ next_align <= mem::size_of::<*mut ()>() {
next_align *= 2;
}
Layout {
@@ -65,9 +68,17 @@ impl Layout {
}
/// When we are treating a type as opaque, it is just a blob with a `Layout`.
+#[derive(Clone, Debug, PartialEq)]
pub struct Opaque(pub Layout);
impl Opaque {
+ /// Construct a new opaque type from the given clang type.
+ pub fn from_clang_ty(ty: &clang::Type) -> Type {
+ let layout = Layout::new(ty.size(), ty.align());
+ let ty_kind = TypeKind::Opaque;
+ Type::new(None, Some(layout), ty_kind, false)
+ }
+
/// Return the known rust type we should use to create a correctly-aligned
/// field with this layout.
pub fn known_rust_type_for_array(&self) -> Option<&'static str> {
diff --git a/src/ir/mod.rs b/src/ir/mod.rs
index ba549c51..d703e53d 100644
--- a/src/ir/mod.rs
+++ b/src/ir/mod.rs
@@ -16,6 +16,7 @@ pub mod item_kind;
pub mod layout;
pub mod module;
pub mod named;
+pub mod template;
pub mod traversal;
pub mod ty;
pub mod var;
diff --git a/src/ir/module.rs b/src/ir/module.rs
index 6787e3f9..ee3912c5 100644
--- a/src/ir/module.rs
+++ b/src/ir/module.rs
@@ -1,11 +1,11 @@
//! Intermediate representation for modules (AKA C++ namespaces).
-use std::io;
use super::context::{BindgenContext, ItemId};
use super::dot::DotAttributes;
use clang;
use parse::{ClangSubItemParser, ParseError, ParseResult};
use parse_one;
+use std::io;
/// Whether this module is inline or not.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -59,12 +59,13 @@ impl Module {
}
impl DotAttributes for Module {
- fn dot_attributes<W>(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()>
- where W: io::Write
+ fn dot_attributes<W>(&self,
+ _ctx: &BindgenContext,
+ out: &mut W)
+ -> io::Result<()>
+ where W: io::Write,
{
- writeln!(out,
- "<tr><td>ModuleKind</td><td>{:?}</td></tr>",
- self.kind)
+ writeln!(out, "<tr><td>ModuleKind</td><td>{:?}</td></tr>", self.kind)
}
}
diff --git a/src/ir/named.rs b/src/ir/named.rs
index 3c676662..7cae195b 100644
--- a/src/ir/named.rs
+++ b/src/ir/named.rs
@@ -126,12 +126,13 @@
//!
//! [spa]: https://cs.au.dk/~amoeller/spa/spa.pdf
-use std::collections::HashMap;
-use std::fmt;
use super::context::{BindgenContext, ItemId};
use super::item::ItemSet;
+use super::template::AsNamed;
use super::traversal::{EdgeKind, Trace};
use super::ty::{TemplateDeclaration, TypeKind};
+use std::collections::HashMap;
+use std::fmt;
/// An analysis in the monotone framework.
///
@@ -163,7 +164,7 @@ pub trait MonotoneFramework: Sized + fmt::Debug {
/// The final output of this analysis. Once we have reached a fix-point, we
/// convert `self` into this type, and return it as the final result of the
/// analysis.
- type Output: From<Self>;
+ type Output: From<Self> + fmt::Debug;
/// Construct a new instance of this analysis.
fn new(extra: Self::Extra) -> Self;
@@ -191,12 +192,8 @@ pub trait MonotoneFramework: Sized + fmt::Debug {
}
/// Run an analysis in the monotone framework.
-// TODO: This allow(...) is just temporary until we replace
-// `Item::signature_contains_named_type` with
-// `analyze::<UsedTemplateParameters>`.
-#[allow(dead_code)]
pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output
- where Analysis: MonotoneFramework
+ where Analysis: MonotoneFramework,
{
let mut analysis = Analysis::new(extra);
let mut worklist = analysis.initial_worklist();
@@ -256,13 +253,19 @@ pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output
/// self_template_param_usage(_) = { }
/// ```
#[derive(Debug, Clone)]
-pub struct UsedTemplateParameters<'a> {
- ctx: &'a BindgenContext<'a>,
- used: HashMap<ItemId, ItemSet>,
+pub struct UsedTemplateParameters<'ctx, 'gen>
+ where 'gen: 'ctx,
+{
+ ctx: &'ctx BindgenContext<'gen>,
+
+ // The Option is only there for temporary moves out of the hash map. See the
+ // comments in `UsedTemplateParameters::constrain` below.
+ used: HashMap<ItemId, Option<ItemSet>>,
+
dependencies: HashMap<ItemId, Vec<ItemId>>,
}
-impl<'a> UsedTemplateParameters<'a> {
+impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> {
fn consider_edge(kind: EdgeKind) -> bool {
match kind {
// For each of these kinds of edges, if the referent uses a template
@@ -271,19 +274,24 @@ impl<'a> UsedTemplateParameters<'a> {
EdgeKind::TemplateArgument |
EdgeKind::BaseMember |
EdgeKind::Field |
- EdgeKind::InnerType |
- EdgeKind::InnerVar |
EdgeKind::Constructor |
EdgeKind::VarType |
+ EdgeKind::FunctionReturn |
+ EdgeKind::FunctionParameter |
EdgeKind::TypeReference => true,
- // We can't emit machine code for new instantiations of function
- // templates and class templates' methods (and don't detect explicit
- // instantiations) so we must ignore template parameters that are
- // only used by functions.
- EdgeKind::Method |
- EdgeKind::FunctionReturn |
- EdgeKind::FunctionParameter => false,
+ // An inner var or type using a template parameter is orthogonal
+ // from whether we use it. See template-param-usage-{6,11}.hpp.
+ EdgeKind::InnerVar | EdgeKind::InnerType => false,
+
+ // We can't emit machine code for new monomorphizations of class
+ // templates' methods (and don't detect explicit instantiations) so
+ // we must ignore template parameters that are only used by
+ // methods. This doesn't apply to a function type's return or
+ // parameter types, however, because of type aliases of function
+ // pointers that use template parameters, eg
+ // tests/headers/struct_with_typedef_template_arg.hpp
+ EdgeKind::Method => false,
// If we considered these edges, we would end up mistakenly claiming
// that every template parameter always used.
@@ -299,25 +307,30 @@ impl<'a> UsedTemplateParameters<'a> {
}
}
-impl<'a> MonotoneFramework for UsedTemplateParameters<'a> {
+impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
type Node = ItemId;
- type Extra = &'a BindgenContext<'a>;
+ type Extra = &'ctx BindgenContext<'gen>;
type Output = HashMap<ItemId, ItemSet>;
- fn new(ctx: &'a BindgenContext<'a>) -> UsedTemplateParameters<'a> {
+ fn new(ctx: &'ctx BindgenContext<'gen>)
+ -> UsedTemplateParameters<'ctx, 'gen> {
let mut used = HashMap::new();
let mut dependencies = HashMap::new();
for item in ctx.whitelisted_items() {
dependencies.entry(item).or_insert(vec![]);
- used.insert(item, ItemSet::new());
+ used.insert(item, Some(ItemSet::new()));
{
// We reverse our natural IR graph edges to find dependencies
// between nodes.
- item.trace(ctx, &mut |sub_item, _| {
- dependencies.entry(sub_item).or_insert(vec![]).push(item);
- }, &());
+ item.trace(ctx,
+ &mut |sub_item, _| {
+ dependencies.entry(sub_item)
+ .or_insert(vec![])
+ .push(item);
+ },
+ &());
}
// Additionally, whether a template instantiation's template
@@ -326,14 +339,18 @@ impl<'a> MonotoneFramework for UsedTemplateParameters<'a> {
ctx.resolve_item(item)
.as_type()
.map(|ty| match ty.kind() {
- &TypeKind::TemplateInstantiation(decl, ref args) => {
- let decl = ctx.resolve_type(decl);
+ &TypeKind::TemplateInstantiation(ref inst) => {
+ let decl = ctx.resolve_type(inst.template_definition());
+ let args = inst.template_arguments();
+ // Although template definitions should always have
+ // template parameters, there is a single exception:
+ // opaque templates. Hence the unwrap_or.
let params = decl.self_template_params(ctx)
- .expect("a template instantiation's referenced \
- template declaration should have template \
- parameters");
+ .unwrap_or(vec![]);
for (arg, param) in args.iter().zip(params.iter()) {
- dependencies.entry(*arg).or_insert(vec![]).push(*param);
+ dependencies.entry(*arg)
+ .or_insert(vec![])
+ .push(*param);
}
}
_ => {}
@@ -352,59 +369,81 @@ impl<'a> MonotoneFramework for UsedTemplateParameters<'a> {
}
fn constrain(&mut self, id: ItemId) -> bool {
- let original_len = self.used[&id].len();
+ // Invariant: all hash map entries' values are `Some` upon entering and
+ // exiting this method.
+ debug_assert!(self.used.values().all(|v| v.is_some()));
+
+ // Take the set for this id out of the hash map while we mutate it based
+ // on other hash map entries. We *must* put it back into the hash map at
+ // the end of this method. This allows us to side-step HashMap's lack of
+ // an analog to slice::split_at_mut.
+ let mut used_by_this_id =
+ self.used.get_mut(&id).unwrap().take().unwrap();
+
+ let original_len = used_by_this_id.len();
- // First, add this item's self template parameter usage.
let item = self.ctx.resolve_item(id);
let ty_kind = item.as_type().map(|ty| ty.kind());
match ty_kind {
+ // Named template type parameters trivially use themselves.
Some(&TypeKind::Named) => {
- // This is a trivial use of the template type parameter.
- self.used.get_mut(&id).unwrap().insert(id);
+ used_by_this_id.insert(id);
}
- Some(&TypeKind::TemplateInstantiation(decl, ref args)) => {
- // A template instantiation's concrete template argument is
- // only used if the template declaration uses the
- // corresponding template parameter.
+
+ // A template instantiation's concrete template argument is
+ // only used if the template declaration uses the
+ // corresponding template parameter.
+ Some(&TypeKind::TemplateInstantiation(ref inst)) => {
+ let decl = self.ctx.resolve_type(inst.template_definition());
+ let args = inst.template_arguments();
+
let params = decl.self_template_params(self.ctx)
- .expect("a template instantiation's referenced \
- template declaration should have template \
- parameters");
+ .unwrap_or(vec![]);
for (arg, param) in args.iter().zip(params.iter()) {
- if self.used[&decl].contains(param) {
- if self.ctx.resolve_item(*arg).is_named() {
- self.used.get_mut(&id).unwrap().insert(*arg);
+ let used_by_definition = self.used
+ [&inst.template_definition()]
+ .as_ref()
+ .unwrap();
+ if used_by_definition.contains(param) {
+ if let Some(named) = arg.as_named(self.ctx, &()) {
+ used_by_this_id.insert(named);
}
}
}
}
- _ => {}
- }
- // Second, add the union of each of its referent item's template
- // parameter usage.
- item.trace(self.ctx, &mut |sub_id, edge_kind| {
- if sub_id == id || !Self::consider_edge(edge_kind) {
- return;
+ // Otherwise, add the union of each of its referent item's template
+ // parameter usage.
+ _ => {
+ item.trace(self.ctx,
+ &mut |sub_id, edge_kind| {
+ if sub_id == id || !Self::consider_edge(edge_kind) {
+ return;
+ }
+
+ let used_by_sub_id = self.used[&sub_id]
+ .as_ref()
+ .unwrap()
+ .iter()
+ .cloned();
+ used_by_this_id.extend(used_by_sub_id);
+ },
+ &());
}
+ }
- // This clone is unfortunate because we are potentially thrashing
- // malloc. We could investigate replacing the ItemSet values with
- // Rc<RefCell<ItemSet>> to make the borrow checker happy, but it
- // isn't clear that the added indirection wouldn't outweigh the cost
- // of malloc'ing a new ItemSet here. Ideally, `HashMap` would have a
- // `split_entries` method analogous to `slice::split_at_mut`...
- let to_add = self.used[&sub_id].clone();
- self.used.get_mut(&id).unwrap().extend(to_add);
- }, &());
-
- let new_len = self.used[&id].len();
+ let new_len = used_by_this_id.len();
assert!(new_len >= original_len);
+
+ // Put the set back in the hash map and restore our invariant.
+ self.used.insert(id, Some(used_by_this_id));
+ debug_assert!(self.used.values().all(|v| v.is_some()));
+
new_len != original_len
}
fn each_depending_on<F>(&self, item: ItemId, mut f: F)
- where F: FnMut(Self::Node)
+ where F: FnMut(ItemId),
{
if let Some(edges) = self.dependencies.get(&item) {
for item in edges {
@@ -414,16 +453,20 @@ impl<'a> MonotoneFramework for UsedTemplateParameters<'a> {
}
}
-impl<'a> From<UsedTemplateParameters<'a>> for HashMap<ItemId, ItemSet> {
- fn from(used_templ_params: UsedTemplateParameters) -> Self {
+impl<'ctx, 'gen> From<UsedTemplateParameters<'ctx, 'gen>>
+ for HashMap<ItemId, ItemSet> {
+ fn from(used_templ_params: UsedTemplateParameters<'ctx, 'gen>) -> Self {
used_templ_params.used
+ .into_iter()
+ .map(|(k, v)| (k, v.unwrap()))
+ .collect()
}
}
#[cfg(test)]
mod tests {
- use std::collections::{HashMap, HashSet};
use super::*;
+ use std::collections::{HashMap, HashSet};
// Here we find the set of nodes that are reachable from any given
// node. This is a lattice mapping nodes to subsets of all nodes. Our join
@@ -489,7 +532,7 @@ mod tests {
g.0.insert(Node(8), vec![]);
g
}
-
+
fn reverse(&self) -> Graph {
let mut reversed = Graph::default();
for (node, edges) in self.0.iter() {
@@ -537,8 +580,9 @@ mod tests {
// Yes, what follows is a **terribly** inefficient set union
// implementation. Don't copy this code outside of this test!
- let original_size = self.reachable.entry(node).or_insert(HashSet::new()).len();
-
+ let original_size =
+ self.reachable.entry(node).or_insert(HashSet::new()).len();
+
for sub_node in self.graph.0[&node].iter() {
self.reachable.get_mut(&node).unwrap().insert(*sub_node);
@@ -557,7 +601,7 @@ mod tests {
}
fn each_depending_on<F>(&self, node: Node, mut f: F)
- where F: FnMut(Node)
+ where F: FnMut(Node),
{
for dep in self.reversed.0[&node].iter() {
f(*dep);
@@ -578,19 +622,19 @@ mod tests {
println!("reachable = {:#?}", reachable);
fn nodes<A>(nodes: A) -> HashSet<Node>
- where A: AsRef<[usize]>
+ where A: AsRef<[usize]>,
{
nodes.as_ref().iter().cloned().map(Node).collect()
}
let mut expected = HashMap::new();
- expected.insert(Node(1), nodes([3,4,5,6,7,8]));
+ expected.insert(Node(1), nodes([3, 4, 5, 6, 7, 8]));
expected.insert(Node(2), nodes([2]));
- expected.insert(Node(3), nodes([3,4,5,6,7,8]));
- expected.insert(Node(4), nodes([3,4,5,6,7,8]));
- expected.insert(Node(5), nodes([3,4,5,6,7,8]));
+ expected.insert(Node(3), nodes([3, 4, 5, 6, 7, 8]));
+ expected.insert(Node(4), nodes([3, 4, 5, 6, 7, 8]));
+ expected.insert(Node(5), nodes([3, 4, 5, 6, 7, 8]));
expected.insert(Node(6), nodes([8]));
- expected.insert(Node(7), nodes([3,4,5,6,7,8]));
+ expected.insert(Node(7), nodes([3, 4, 5, 6, 7, 8]));
expected.insert(Node(8), nodes([]));
println!("expected = {:#?}", expected);
diff --git a/src/ir/template.rs b/src/ir/template.rs
new file mode 100644
index 00000000..627ac225
--- /dev/null
+++ b/src/ir/template.rs
@@ -0,0 +1,193 @@
+//! Template declaration and instantiation related things.
+//!
+//! The nomenclature surrounding templates is often confusing, so here are a few
+//! brief definitions:
+//!
+//! * "Template definition": a class/struct/alias/function definition that takes
+//! generic template parameters. For example:
+//!
+//! ```c++
+//! template<typename T>
+//! class List<T> {
+//! // ...
+//! };
+//! ```
+//!
+//! * "Template instantiation": an instantiation is a use of a template with
+//! concrete template arguments. For example, `List<int>`.
+//!
+//! * "Template specialization": an alternative template definition providing a
+//! custom definition for instantiations with the matching template
+//! arguments. This C++ feature is unsupported by bindgen. For example:
+//!
+//! ```c++
+//! template<>
+//! class List<int> {
+//! // Special layout for int lists...
+//! };
+//! ```
+
+use super::context::{BindgenContext, ItemId};
+use super::derive::{CanDeriveCopy, CanDeriveDebug};
+use super::item::Item;
+use super::layout::Layout;
+use super::traversal::{EdgeKind, Trace, Tracer};
+use clang;
+use parse::ClangItemParser;
+
+/// A trait for things which may or may not be a named template type parameter.
+pub trait AsNamed {
+ /// Any extra information the implementor might need to make this decision.
+ type Extra;
+
+ /// Convert this thing to the item id of a named template type parameter.
+ fn as_named(&self,
+ ctx: &BindgenContext,
+ extra: &Self::Extra)
+ -> Option<ItemId>;
+
+ /// Is this a named template type parameter?
+ fn is_named(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool {
+ self.as_named(ctx, extra).is_some()
+ }
+}
+
+/// A concrete instantiation of a generic template.
+#[derive(Clone, Debug)]
+pub struct TemplateInstantiation {
+ /// The template definition which this is instantiating.
+ definition: ItemId,
+ /// The concrete template arguments, which will be substituted in the
+ /// definition for the generic template parameters.
+ args: Vec<ItemId>,
+}
+
+impl TemplateInstantiation {
+ /// Construct a new template instantiation from the given parts.
+ pub fn new<I>(template_definition: ItemId,
+ template_args: I)
+ -> TemplateInstantiation
+ where I: IntoIterator<Item = ItemId>,
+ {
+ TemplateInstantiation {
+ definition: template_definition,
+ args: template_args.into_iter().collect(),
+ }
+ }
+
+ /// Get the template definition for this instantiation.
+ pub fn template_definition(&self) -> ItemId {
+ self.definition
+ }
+
+ /// Get the concrete template arguments used in this instantiation.
+ pub fn template_arguments(&self) -> &[ItemId] {
+ &self.args[..]
+ }
+
+ /// Parse a `TemplateInstantiation` from a clang `Type`.
+ pub fn from_ty(ty: &clang::Type,
+ ctx: &mut BindgenContext)
+ -> TemplateInstantiation {
+ use clang_sys::*;
+
+ let template_args = ty.template_args()
+ .map_or(vec![], |args| {
+ args.filter(|t| t.kind() != CXType_Invalid)
+ .map(|t| {
+ Item::from_ty_or_ref(t, t.declaration(), None, ctx)
+ })
+ .collect()
+ });
+
+ let definition = ty.declaration()
+ .specialized()
+ .or_else(|| {
+ let mut template_ref = None;
+ ty.declaration().visit(|child| {
+ if child.kind() == CXCursor_TemplateRef {
+ template_ref = Some(child);
+ return CXVisit_Break;
+ }
+
+ // Instantiations of template aliases might have the
+ // TemplateRef to the template alias definition arbitrarily
+ // deep, so we need to recurse here and not only visit
+ // direct children.
+ CXChildVisit_Recurse
+ });
+
+ template_ref.and_then(|cur| cur.referenced())
+ })
+ .expect("Should have found the template definition one way or another");
+
+ let template_definition =
+ Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx);
+
+ TemplateInstantiation::new(template_definition, template_args)
+ }
+
+ /// Does this instantiation have a vtable?
+ pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
+ ctx.resolve_type(self.definition).has_vtable(ctx) ||
+ self.args.iter().any(|arg| ctx.resolve_type(*arg).has_vtable(ctx))
+ }
+
+ /// Does this instantiation have a destructor?
+ pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
+ ctx.resolve_type(self.definition).has_destructor(ctx) ||
+ self.args.iter().any(|arg| ctx.resolve_type(*arg).has_destructor(ctx))
+ }
+}
+
+impl<'a> CanDeriveCopy<'a> for TemplateInstantiation {
+ type Extra = ();
+
+ fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
+ self.definition.can_derive_copy(ctx, ()) &&
+ self.args.iter().all(|arg| arg.can_derive_copy(ctx, ()))
+ }
+
+ fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
+ self.definition.can_derive_copy_in_array(ctx, ()) &&
+ self.args.iter().all(|arg| arg.can_derive_copy_in_array(ctx, ()))
+ }
+}
+
+impl CanDeriveDebug for TemplateInstantiation {
+ type Extra = Option<Layout>;
+
+ fn can_derive_debug(&self,
+ ctx: &BindgenContext,
+ layout: Option<Layout>)
+ -> bool {
+ self.args.iter().all(|arg| arg.can_derive_debug(ctx, ())) &&
+ ctx.resolve_type(self.definition)
+ .as_comp()
+ .and_then(|c| {
+ // For non-type template parameters, we generate an opaque
+ // blob, and in this case the instantiation has a better
+ // idea of the layout than the definition does.
+ if c.has_non_type_template_params() {
+ let opaque = layout.unwrap_or(Layout::zero()).opaque();
+ Some(opaque.can_derive_debug(ctx, ()))
+ } else {
+ None
+ }
+ })
+ .unwrap_or_else(|| self.definition.can_derive_debug(ctx, ()))
+ }
+}
+
+impl Trace for TemplateInstantiation {
+ type Extra = ();
+
+ fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
+ where T: Tracer,
+ {
+ tracer.visit_kind(self.definition, EdgeKind::TemplateDeclaration);
+ for &item in self.template_arguments() {
+ tracer.visit_kind(item, EdgeKind::TemplateArgument);
+ }
+ }
+}
diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs
index 30772aad..95d2a456 100644
--- a/src/ir/traversal.rs
+++ b/src/ir/traversal.rs
@@ -318,7 +318,7 @@ pub trait Tracer {
}
impl<F> Tracer for F
- where F: FnMut(ItemId, EdgeKind)
+ where F: FnMut(ItemId, EdgeKind),
{
fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) {
(*self)(item, kind)
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index 51652000..6c8e7363 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -8,22 +8,31 @@ use super::enum_ty::Enum;
use super::function::FunctionSig;
use super::int::IntKind;
use super::item::{Item, ItemAncestors};
-use super::layout::Layout;
+use super::layout::{Layout, Opaque};
use super::objc::ObjCInterface;
+use super::template::{AsNamed, TemplateInstantiation};
use super::traversal::{EdgeKind, Trace, Tracer};
use clang::{self, Cursor};
use parse::{ClangItemParser, ParseError, ParseResult};
+use std::cell::Cell;
use std::io;
use std::mem;
/// Template declaration (and such declaration's template parameters) related
/// methods.
///
+/// This trait's methods distinguish between `None` and `Some([])` for
+/// declarations that are not templates and template declarations with zero
+/// parameters, in general.
+///
/// Consider this example:
///
/// ```c++
/// template <typename T, typename U>
/// class Foo {
+/// T use_of_t;
+/// U use_of_u;
+///
/// template <typename V>
/// using Bar = V*;
///
@@ -32,6 +41,18 @@ use std::mem;
/// U y;
/// Bar<int> z;
/// };
+///
+/// template <typename W>
+/// class Lol {
+/// // No use of W, but here's a use of T.
+/// T t;
+/// };
+///
+/// template <typename X>
+/// class Wtf {
+/// // X is not used because W is not used.
+/// Lol<X> lololol;
+/// };
/// };
///
/// class Qux {
@@ -40,16 +61,29 @@ use std::mem;
/// ```
///
/// The following table depicts the results of each trait method when invoked on
-/// `Foo`, `Bar`, and `Qux`.
+/// each of the declarations above:
///
-/// +------+----------------------+--------------------------+------------------------+
-/// |Decl. | self_template_params | num_self_template_params | all_template_parameters|
-/// +------+----------------------+--------------------------+------------------------+
-/// |Foo | Some([T, U]) | Some(2) | Some([T, U]) |
-/// |Bar | Some([V]) | Some(1) | Some([T, U, V]) |
-/// |Inner | None | None | Some([T, U]) |
-/// |Qux | None | None | None |
-/// +------+----------------------+--------------------------+------------------------+
+/// +------+----------------------+--------------------------+------------------------+----
+/// |Decl. | self_template_params | num_self_template_params | all_template_parameters| ...
+/// +------+----------------------+--------------------------+------------------------+----
+/// |Foo | Some([T, U]) | Some(2) | Some([T, U]) | ...
+/// |Bar | Some([V]) | Some(1) | Some([T, U, V]) | ...
+/// |Inner | None | None | Some([T, U]) | ...
+/// |Lol | Some([W]) | Some(1) | Some([T, U, W]) | ...
+/// |Wtf | Some([X]) | Some(1) | Some([T, U, X]) | ...
+/// |Qux | None | None | None | ...
+/// +------+----------------------+--------------------------+------------------------+----
+///
+/// ----+------+-----+----------------------+
+/// ... |Decl. | ... | used_template_params |
+/// ----+------+-----+----------------------+
+/// ... |Foo | ... | Some([T, U]) |
+/// ... |Bar | ... | Some([V]) |
+/// ... |Inner | ... | None |
+/// ... |Lol | ... | Some([T]) |
+/// ... |Wtf | ... | Some([T]) |
+/// ... |Qux | ... | None |
+/// ----+------+-----+----------------------+
pub trait TemplateDeclaration {
/// Get the set of `ItemId`s that make up this template declaration's free
/// template parameters.
@@ -59,7 +93,9 @@ pub trait TemplateDeclaration {
/// parameters. Of course, Rust does not allow generic parameters to be
/// anything but types, so we must treat them as opaque, and avoid
/// instantiating them.
- fn self_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>;
+ fn self_template_params(&self,
+ ctx: &BindgenContext)
+ -> Option<Vec<ItemId>>;
/// Get the number of free template parameters this template declaration
/// has.
@@ -87,7 +123,7 @@ pub trait TemplateDeclaration {
/// `Foo<int,char>::Inner`. `Foo` *must* be instantiated with template
/// arguments before we can gain access to the `Inner` member type.
fn all_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
- where Self: ItemAncestors
+ where Self: ItemAncestors,
{
let each_self_params: Vec<Vec<_>> = self.ancestors(ctx)
.filter_map(|id| id.self_template_params(ctx))
@@ -96,11 +132,30 @@ pub trait TemplateDeclaration {
None
} else {
Some(each_self_params.into_iter()
- .rev()
- .flat_map(|params| params)
- .collect())
+ .rev()
+ .flat_map(|params| params)
+ .collect())
}
}
+
+ /// Get only the set of template parameters that this item uses. This is a
+ /// subset of `all_template_params` and does not necessarily contain any of
+ /// `self_template_params`.
+ fn used_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
+ where Self: AsRef<ItemId>,
+ {
+ assert!(ctx.in_codegen_phase(),
+ "template parameter usage is not computed until codegen");
+
+ let id = *self.as_ref();
+ ctx.resolve_item(id)
+ .all_template_params(ctx)
+ .map(|all_params| {
+ all_params.into_iter()
+ .filter(|p| ctx.uses_template_parameter(id, *p))
+ .collect()
+ })
+ }
}
/// The base representation of a type in bindgen.
@@ -118,6 +173,9 @@ pub struct Type {
kind: TypeKind,
/// Whether this type is const-qualified.
is_const: bool,
+ /// Don't go into an infinite loop when detecting if we have a vtable or
+ /// not.
+ detect_has_vtable_cycle: Cell<bool>,
}
/// The maximum number of items in an array for which Rust implements common
@@ -148,6 +206,7 @@ impl Type {
layout: layout,
kind: kind,
is_const: is_const,
+ detect_has_vtable_cycle: Cell::new(false),
}
}
@@ -174,7 +233,15 @@ impl Type {
}
}
- /// Is this a named type?
+ /// Is this type of kind `TypeKind::Opaque`?
+ pub fn is_opaque(&self) -> bool {
+ match self.kind {
+ TypeKind::Opaque => true,
+ _ => false,
+ }
+ }
+
+ /// Is this type of kind `TypeKind::Named`?
pub fn is_named(&self) -> bool {
match self.kind {
TypeKind::Named => true,
@@ -304,67 +371,39 @@ impl Type {
/// Whether this type has a vtable.
pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
+ if self.detect_has_vtable_cycle.get() {
+ return false;
+ }
+
+ self.detect_has_vtable_cycle.set(true);
+
// FIXME: Can we do something about template parameters? Huh...
- match self.kind {
- TypeKind::TemplateInstantiation(t, _) |
+ let result = match self.kind {
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(t) |
TypeKind::ResolvedTypeRef(t) => ctx.resolve_type(t).has_vtable(ctx),
TypeKind::Comp(ref info) => info.has_vtable(ctx),
+ TypeKind::TemplateInstantiation(ref inst) => inst.has_vtable(ctx),
_ => false,
- }
+ };
+ self.detect_has_vtable_cycle.set(false);
+
+ result
}
/// Returns whether this type has a destructor.
pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
match self.kind {
- TypeKind::TemplateInstantiation(t, _) |
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(t) |
TypeKind::ResolvedTypeRef(t) => {
ctx.resolve_type(t).has_destructor(ctx)
}
- TypeKind::Comp(ref info) => info.has_destructor(ctx),
- _ => false,
- }
- }
-
- /// See the comment in `Item::signature_contains_named_type`.
- pub fn signature_contains_named_type(&self,
- ctx: &BindgenContext,
- ty: &Type)
- -> bool {
- let name = match *ty.kind() {
- TypeKind::Named => ty.name(),
- ref other @ _ => unreachable!("Not a named type: {:?}", other),
- };
-
- match self.kind {
- TypeKind::Named => self.name() == name,
- TypeKind::ResolvedTypeRef(t) |
- TypeKind::Array(t, _) |
- TypeKind::Pointer(t) |
- TypeKind::Alias(t) => {
- ctx.resolve_type(t)
- .signature_contains_named_type(ctx, ty)
- }
- TypeKind::Function(ref sig) => {
- sig.argument_types().iter().any(|&(_, arg)| {
- ctx.resolve_type(arg)
- .signature_contains_named_type(ctx, ty)
- }) ||
- ctx.resolve_type(sig.return_type())
- .signature_contains_named_type(ctx, ty)
- }
- TypeKind::TemplateAlias(_, ref template_args) |
- TypeKind::TemplateInstantiation(_, ref template_args) => {
- template_args.iter().any(|arg| {
- ctx.resolve_type(*arg)
- .signature_contains_named_type(ctx, ty)
- })
+ TypeKind::TemplateInstantiation(ref inst) => {
+ inst.has_destructor(ctx)
}
- TypeKind::Comp(ref ci) => ci.signature_contains_named_type(ctx, ty),
+ TypeKind::Comp(ref info) => info.has_destructor(ctx),
_ => false,
}
}
@@ -387,7 +426,9 @@ impl Type {
/// i.e. is alphanumeric (including '_') and does not start with a digit.
pub fn is_valid_identifier(name: &str) -> bool {
let mut chars = name.chars();
- let first_valid = chars.next().map(|c| c.is_alphabetic() || c == '_').unwrap_or(false);
+ let first_valid = chars.next()
+ .map(|c| c.is_alphabetic() || c == '_')
+ .unwrap_or(false);
first_valid && chars.all(|c| c.is_alphanumeric() || c == '_')
}
@@ -403,7 +444,7 @@ impl Type {
/// Returns the canonical type of this type, that is, the "inner type".
///
/// For example, for a `typedef`, the canonical type would be the
- /// `typedef`ed type, for a template specialization, would be the template
+ /// `typedef`ed type, for a template instantiation, would be the template
/// its specializing, and so on. Return None if the type is unresolved.
pub fn safe_canonical_type<'tr>(&'tr self,
ctx: &'tr BindgenContext)
@@ -412,6 +453,7 @@ impl Type {
TypeKind::Named |
TypeKind::Array(..) |
TypeKind::Comp(..) |
+ TypeKind::Opaque |
TypeKind::Int(..) |
TypeKind::Float(..) |
TypeKind::Complex(..) |
@@ -428,10 +470,13 @@ impl Type {
TypeKind::ResolvedTypeRef(inner) |
TypeKind::Alias(inner) |
- TypeKind::TemplateAlias(inner, _) |
- TypeKind::TemplateInstantiation(inner, _) => {
+ TypeKind::TemplateAlias(inner, _) => {
ctx.resolve_type(inner).safe_canonical_type(ctx)
}
+ TypeKind::TemplateInstantiation(ref inst) => {
+ ctx.resolve_type(inst.template_definition())
+ .safe_canonical_type(ctx)
+ }
TypeKind::UnresolvedTypeRef(..) => None,
}
@@ -452,9 +497,32 @@ impl Type {
}
}
+impl AsNamed for Type {
+ type Extra = Item;
+
+ fn as_named(&self, ctx: &BindgenContext, item: &Item) -> Option<ItemId> {
+ self.kind.as_named(ctx, item)
+ }
+}
+
+impl AsNamed for TypeKind {
+ type Extra = Item;
+
+ fn as_named(&self, ctx: &BindgenContext, item: &Item) -> Option<ItemId> {
+ match *self {
+ TypeKind::Named => Some(item.id()),
+ TypeKind::ResolvedTypeRef(id) => id.as_named(ctx, &()),
+ _ => None,
+ }
+ }
+}
+
impl DotAttributes for Type {
- fn dot_attributes<W>(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()>
- where W: io::Write
+ fn dot_attributes<W>(&self,
+ ctx: &BindgenContext,
+ out: &mut W)
+ -> io::Result<()>
+ where W: io::Write,
{
if let Some(ref layout) = self.layout {
try!(writeln!(out,
@@ -476,8 +544,11 @@ impl DotAttributes for Type {
}
impl DotAttributes for TypeKind {
- fn dot_attributes<W>(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()>
- where W: io::Write
+ fn dot_attributes<W>(&self,
+ _ctx: &BindgenContext,
+ out: &mut W)
+ -> io::Result<()>
+ where W: io::Write,
{
write!(out,
"<tr><td>TypeKind</td><td>{}</td></tr>",
@@ -485,6 +556,7 @@ impl DotAttributes for TypeKind {
TypeKind::Void => "Void",
TypeKind::NullPtr => "NullPtr",
TypeKind::Comp(..) => "Comp",
+ TypeKind::Opaque => "Opaque",
TypeKind::Int(..) => "Int",
TypeKind::Float(..) => "Float",
TypeKind::Complex(..) => "Complex",
@@ -502,9 +574,7 @@ impl DotAttributes for TypeKind {
TypeKind::ObjCId => "ObjCId",
TypeKind::ObjCSel => "ObjCSel",
TypeKind::ObjCInterface(..) => "ObjCInterface",
- TypeKind::UnresolvedTypeRef(..) => {
- unreachable!("there shouldn't be any more of these anymore")
- }
+ TypeKind::UnresolvedTypeRef(..) => unreachable!("there shouldn't be any more of these anymore"),
})
}
}
@@ -555,13 +625,17 @@ fn is_invalid_named_type_empty_name() {
impl TemplateDeclaration for Type {
- fn self_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
+ fn self_template_params(&self,
+ ctx: &BindgenContext)
+ -> Option<Vec<ItemId>> {
self.kind.self_template_params(ctx)
}
}
impl TemplateDeclaration for TypeKind {
- fn self_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> {
+ fn self_template_params(&self,
+ ctx: &BindgenContext)
+ -> Option<Vec<ItemId>> {
match *self {
TypeKind::ResolvedTypeRef(id) => {
ctx.resolve_type(id).self_template_params(ctx)
@@ -569,6 +643,7 @@ impl TemplateDeclaration for TypeKind {
TypeKind::Comp(ref comp) => comp.self_template_params(ctx),
TypeKind::TemplateAlias(_, ref args) => Some(args.clone()),
+ TypeKind::Opaque |
TypeKind::TemplateInstantiation(..) |
TypeKind::Void |
TypeKind::NullPtr |
@@ -607,11 +682,15 @@ impl CanDeriveDebug for Type {
}
TypeKind::Pointer(inner) => {
let inner = ctx.resolve_type(inner);
- if let TypeKind::Function(ref sig) = *inner.canonical_type(ctx).kind() {
+ if let TypeKind::Function(ref sig) =
+ *inner.canonical_type(ctx).kind() {
return sig.can_derive_debug(ctx, ());
}
return true;
}
+ TypeKind::TemplateInstantiation(ref inst) => {
+ inst.can_derive_debug(ctx, self.layout(ctx))
+ }
_ => true,
}
}
@@ -632,6 +711,10 @@ impl CanDeriveDefault for Type {
TypeKind::Comp(ref info) => {
info.can_derive_default(ctx, self.layout(ctx))
}
+ TypeKind::Opaque => {
+ self.layout
+ .map_or(true, |l| l.opaque().can_derive_default(ctx, ()))
+ }
TypeKind::Void |
TypeKind::Named |
TypeKind::TemplateInstantiation(..) |
@@ -664,11 +747,17 @@ impl<'a> CanDeriveCopy<'a> for Type {
}
TypeKind::ResolvedTypeRef(t) |
TypeKind::TemplateAlias(t, _) |
- TypeKind::TemplateInstantiation(t, _) |
TypeKind::Alias(t) => t.can_derive_copy(ctx, ()),
+ TypeKind::TemplateInstantiation(ref inst) => {
+ inst.can_derive_copy(ctx, ())
+ }
TypeKind::Comp(ref info) => {
info.can_derive_copy(ctx, (item, self.layout(ctx)))
}
+ TypeKind::Opaque => {
+ self.layout
+ .map_or(true, |l| l.opaque().can_derive_copy(ctx, ()))
+ }
_ => true,
}
}
@@ -724,6 +813,11 @@ pub enum TypeKind {
/// A compound type, that is, a class, struct, or union.
Comp(CompInfo),
+ /// An opaque type that we just don't understand. All usage of this shoulf
+ /// result in an opaque blob of bytes generated from the containing type's
+ /// layout.
+ Opaque,
+
/// An integer type, of a given kind. `bool` and `char` are also considered
/// integers.
Int(IntKind),
@@ -760,9 +854,9 @@ pub enum TypeKind {
/// A reference to a type, as in: int& foo().
Reference(ItemId),
- /// An instantiation of an abstract template declaration (first tuple
- /// member) with a set of concrete template arguments (second tuple member).
- TemplateInstantiation(ItemId, Vec<ItemId>),
+ /// An instantiation of an abstract template definition with a set of
+ /// concrete template arguments.
+ TemplateInstantiation(TemplateInstantiation),
/// A reference to a yet-to-resolve type. This stores the clang cursor
/// itself, and postpones its resolution.
@@ -772,7 +866,7 @@ pub enum TypeKind {
///
/// see tests/headers/typeref.hpp to see somewhere where this is a problem.
UnresolvedTypeRef(clang::Type,
- Option<clang::Cursor>,
+ clang::Cursor,
/* parent_id */
Option<ItemId>),
@@ -806,15 +900,18 @@ impl Type {
match self.kind {
TypeKind::Void => true,
TypeKind::Comp(ref ci) => ci.is_unsized(ctx),
+ TypeKind::Opaque => self.layout.map_or(true, |l| l.size == 0),
TypeKind::Array(inner, size) => {
size == 0 || ctx.resolve_type(inner).is_unsized(ctx)
}
TypeKind::ResolvedTypeRef(inner) |
TypeKind::Alias(inner) |
- TypeKind::TemplateAlias(inner, _) |
- TypeKind::TemplateInstantiation(inner, _) => {
+ TypeKind::TemplateAlias(inner, _) => {
ctx.resolve_type(inner).is_unsized(ctx)
}
+ TypeKind::TemplateInstantiation(ref inst) => {
+ ctx.resolve_type(inst.template_definition()).is_unsized(ctx)
+ }
TypeKind::Named |
TypeKind::Int(..) |
TypeKind::Float(..) |
@@ -843,17 +940,16 @@ impl Type {
/// comments in every special case justify why they're there.
pub fn from_clang_ty(potential_id: ItemId,
ty: &clang::Type,
- location: Option<Cursor>,
+ location: Cursor,
parent_id: Option<ItemId>,
ctx: &mut BindgenContext)
-> Result<ParseResult<Self>, ParseError> {
use clang_sys::*;
{
- let already_resolved =
- ctx.builtin_or_resolved_ty(potential_id,
- parent_id,
- ty,
- location);
+ let already_resolved = ctx.builtin_or_resolved_ty(potential_id,
+ parent_id,
+ ty,
+ Some(location));
if let Some(ty) = already_resolved {
debug!("{:?} already resolved: {:?}", ty, location);
return Ok(ParseResult::AlreadyResolved(ty));
@@ -874,409 +970,409 @@ impl Type {
// Parse objc protocols as if they were interfaces
let mut ty_kind = ty.kind();
- if let Some(loc) = location {
- match loc.kind() {
- CXCursor_ObjCProtocolDecl |
- CXCursor_ObjCCategoryDecl => ty_kind = CXType_ObjCInterface,
- _ => {}
- }
+ match location.kind() {
+ CXCursor_ObjCProtocolDecl |
+ CXCursor_ObjCCategoryDecl => ty_kind = CXType_ObjCInterface,
+ _ => {}
}
- let kind = match ty_kind {
- CXType_Unexposed if *ty != canonical_ty &&
- canonical_ty.kind() != CXType_Invalid &&
- ty.ret_type().is_none() &&
- // Sometime clang desugars some types more than
- // what we need, specially with function
- // pointers.
- //
- // We should also try the solution of inverting
- // those checks instead of doing this, that is,
- // something like:
- //
- // CXType_Unexposed if ty.ret_type().is_some()
- // => { ... }
- //
- // etc.
- !canonical_ty.spelling().contains("type-parameter") => {
- debug!("Looking for canonical type: {:?}", canonical_ty);
- return Self::from_clang_ty(potential_id,
- &canonical_ty,
- location,
- parent_id,
- ctx);
- }
- CXType_Unexposed | CXType_Invalid => {
- // For some reason Clang doesn't give us any hint in some
- // situations where we should generate a function pointer (see
- // tests/headers/func_ptr_in_struct.h), so we do a guess here
- // trying to see if it has a valid return type.
- if ty.ret_type().is_some() {
- let signature = try!(FunctionSig::from_ty(ty,
- &location.unwrap_or(cursor),
- ctx));
- TypeKind::Function(signature)
- // Same here, with template specialisations we can safely
- // assume this is a Comp(..)
- } else if ty.is_fully_specialized_template() {
- debug!("Template specialization: {:?}, {:?} {:?}",
- ty,
- location,
- canonical_ty);
- let complex =
- CompInfo::from_ty(potential_id, ty, location, ctx)
+ if location.kind() == CXCursor_ClassTemplatePartialSpecialization {
+ // Sorry! (Not sorry)
+ warn!("Found a partial template specialization; bindgen does not \
+ support partial template specialization! Constructing \
+ opaque type instead.");
+ return Ok(ParseResult::New(Opaque::from_clang_ty(&canonical_ty),
+ None));
+ }
+
+ let kind = if location.kind() == CXCursor_TemplateRef ||
+ (ty.template_args().is_some() &&
+ ty_kind != CXType_Typedef) {
+ // This is a template instantiation.
+ let inst = TemplateInstantiation::from_ty(&ty, ctx);
+ TypeKind::TemplateInstantiation(inst)
+ } else {
+ match ty_kind {
+ CXType_Unexposed if *ty != canonical_ty &&
+ canonical_ty.kind() != CXType_Invalid &&
+ ty.ret_type().is_none() &&
+ // Sometime clang desugars some types more than
+ // what we need, specially with function
+ // pointers.
+ //
+ // We should also try the solution of inverting
+ // those checks instead of doing this, that is,
+ // something like:
+ //
+ // CXType_Unexposed if ty.ret_type().is_some()
+ // => { ... }
+ //
+ // etc.
+ !canonical_ty.spelling().contains("type-parameter") => {
+ debug!("Looking for canonical type: {:?}", canonical_ty);
+ return Self::from_clang_ty(potential_id,
+ &canonical_ty,
+ location,
+ parent_id,
+ ctx);
+ }
+ CXType_Unexposed | CXType_Invalid => {
+ // For some reason Clang doesn't give us any hint in some
+ // situations where we should generate a function pointer (see
+ // tests/headers/func_ptr_in_struct.h), so we do a guess here
+ // trying to see if it has a valid return type.
+ if ty.ret_type().is_some() {
+ let signature =
+ try!(FunctionSig::from_ty(ty, &location, ctx));
+ TypeKind::Function(signature)
+ // Same here, with template specialisations we can safely
+ // assume this is a Comp(..)
+ } else if ty.is_fully_instantiated_template() {
+ debug!("Template specialization: {:?}, {:?} {:?}",
+ ty,
+ location,
+ canonical_ty);
+ let complex = CompInfo::from_ty(potential_id,
+ ty,
+ Some(location),
+ ctx)
.expect("C'mon");
- TypeKind::Comp(complex)
- } else if let Some(location) = location {
- match location.kind() {
- CXCursor_ClassTemplatePartialSpecialization |
- CXCursor_CXXBaseSpecifier |
- CXCursor_ClassTemplate => {
- if location.kind() == CXCursor_CXXBaseSpecifier {
- // In the case we're parsing a base specifier
- // inside an unexposed or invalid type, it means
- // that we're parsing one of two things:
- //
- // * A template parameter.
- // * A complex class that isn't exposed.
- //
- // This means, unfortunately, that there's no
- // good way to differentiate between them.
- //
- // Probably we could try to look at the
- // declaration and complicate more this logic,
- // but we'll keep it simple... if it's a valid
- // C++ identifier, we'll consider it as a
- // template parameter.
- //
- // This is because:
- //
- // * We expect every other base that is a
- // proper identifier (that is, a simple
- // struct/union declaration), to be exposed,
- // so this path can't be reached in that
- // case.
- //
- // * Quite conveniently, complex base
- // specifiers preserve their full names (that
- // is: Foo<T> instead of Foo). We can take
- // advantage of this.
- //
- // If we find some edge case where this doesn't
- // work (which I guess is unlikely, see the
- // different test cases[1][2][3][4]), we'd need
- // to find more creative ways of differentiating
- // these two cases.
- //
- // [1]: inherit_named.hpp
- // [2]: forward-inherit-struct-with-fields.hpp
- // [3]: forward-inherit-struct.hpp
- // [4]: inherit-namespaced.hpp
- if location.spelling()
- .chars()
- .all(|c| c.is_alphanumeric() || c == '_') {
- return Err(ParseError::Recurse);
+ TypeKind::Comp(complex)
+ } else {
+ match location.kind() {
+ CXCursor_CXXBaseSpecifier |
+ CXCursor_ClassTemplate => {
+ if location.kind() ==
+ CXCursor_CXXBaseSpecifier {
+ // In the case we're parsing a base specifier
+ // inside an unexposed or invalid type, it means
+ // that we're parsing one of two things:
+ //
+ // * A template parameter.
+ // * A complex class that isn't exposed.
+ //
+ // This means, unfortunately, that there's no
+ // good way to differentiate between them.
+ //
+ // Probably we could try to look at the
+ // declaration and complicate more this logic,
+ // but we'll keep it simple... if it's a valid
+ // C++ identifier, we'll consider it as a
+ // template parameter.
+ //
+ // This is because:
+ //
+ // * We expect every other base that is a
+ // proper identifier (that is, a simple
+ // struct/union declaration), to be exposed,
+ // so this path can't be reached in that
+ // case.
+ //
+ // * Quite conveniently, complex base
+ // specifiers preserve their full names (that
+ // is: Foo<T> instead of Foo). We can take
+ // advantage of this.
+ //
+ // If we find some edge case where this doesn't
+ // work (which I guess is unlikely, see the
+ // different test cases[1][2][3][4]), we'd need
+ // to find more creative ways of differentiating
+ // these two cases.
+ //
+ // [1]: inherit_named.hpp
+ // [2]: forward-inherit-struct-with-fields.hpp
+ // [3]: forward-inherit-struct.hpp
+ // [4]: inherit-namespaced.hpp
+ if location.spelling()
+ .chars()
+ .all(|c| {
+ c.is_alphanumeric() || c == '_'
+ }) {
+ return Err(ParseError::Recurse);
+ }
+ } else {
+ name = location.spelling();
}
- } else {
- name = location.spelling();
+
+ let complex = CompInfo::from_ty(potential_id,
+ ty,
+ Some(location),
+ ctx)
+ .expect("C'mon");
+ TypeKind::Comp(complex)
}
- let complex = CompInfo::from_ty(potential_id,
- ty,
- Some(location),
- ctx)
- .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 => {
- let current = cur.cur_type();
-
- debug_assert!(current.kind() ==
- CXType_Typedef);
-
- name = current.spelling();
-
- let inner_ty = cur.typedef_type()
- .expect("Not valid Type?");
- inner =
- Item::from_ty(&inner_ty,
- 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;
+ 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 => {
+ let current = cur.cur_type();
+
+ debug_assert!(current.kind() ==
+ CXType_Typedef);
+
+ name = current.spelling();
+
+ let inner_ty = cur.typedef_type()
+ .expect("Not valid Type?");
+ inner =
+ Item::from_ty(&inner_ty,
+ cur,
+ Some(potential_id),
+ ctx);
}
-
- let param =
- Item::named_type(cur.spelling(),
- potential_id,
- ctx);
- args.push(param);
+ CXCursor_TemplateTypeParameter => {
+ // See the comment in src/ir/comp.rs
+ // about the same situation.
+ if cur.spelling().is_empty() {
+ return CXChildVisit_Continue;
+ }
+
+ let param =
+ Item::named_type(None,
+ cur,
+ ctx)
+ .expect("Item::named_type shouldn't \
+ ever fail if we are looking \
+ at a TemplateTypeParameter");
+ args.push(param);
+ }
+ _ => {}
}
- _ => {}
- }
- CXChildVisit_Continue
- });
-
- let inner_type = match inner {
- Ok(inner) => inner,
- Err(..) => {
- error!("Failed to parse template alias \
- {:?}",
- location);
- return Err(ParseError::Continue);
- }
- };
+ CXChildVisit_Continue
+ });
+
+ let inner_type = match inner {
+ Ok(inner) => inner,
+ Err(..) => {
+ error!("Failed to parse template alias \
+ {:?}",
+ location);
+ return Err(ParseError::Continue);
+ }
+ };
- TypeKind::TemplateAlias(inner_type, args)
- }
- CXCursor_TemplateRef => {
- let referenced = location.referenced().unwrap();
- let referenced_ty = referenced.cur_type();
-
- debug!("TemplateRef: location = {:?}; referenced = \
- {:?}; referenced_ty = {:?}",
- location,
- referenced,
- referenced_ty);
-
- return Self::from_clang_ty(potential_id,
- &referenced_ty,
- Some(referenced),
- parent_id,
- ctx);
- }
- CXCursor_TypeRef => {
- let referenced = location.referenced().unwrap();
- let referenced_ty = referenced.cur_type();
- let declaration = referenced_ty.declaration();
-
- debug!("TypeRef: location = {:?}; referenced = \
- {:?}; referenced_ty = {:?}",
- location,
- referenced,
- referenced_ty);
-
- let item =
- Item::from_ty_or_ref_with_id(potential_id,
- referenced_ty,
- Some(declaration),
- parent_id,
- ctx);
- return Ok(ParseResult::AlreadyResolved(item));
- }
- CXCursor_NamespaceRef => {
- return Err(ParseError::Continue);
- }
- _ => {
- if ty.kind() == CXType_Unexposed {
- warn!("Unexposed type {:?}, recursing inside, \
- loc: {:?}",
- ty,
- location);
- return Err(ParseError::Recurse);
+ TypeKind::TemplateAlias(inner_type, args)
+ }
+ CXCursor_TemplateRef => {
+ let referenced = location.referenced().unwrap();
+ let referenced_ty = referenced.cur_type();
+
+ debug!("TemplateRef: location = {:?}; referenced = \
+ {:?}; referenced_ty = {:?}",
+ location,
+ referenced,
+ referenced_ty);
+
+ return Self::from_clang_ty(potential_id,
+ &referenced_ty,
+ referenced,
+ parent_id,
+ ctx);
}
+ CXCursor_TypeRef => {
+ let referenced = location.referenced().unwrap();
+ let referenced_ty = referenced.cur_type();
+ let declaration = referenced_ty.declaration();
+
+ debug!("TypeRef: location = {:?}; referenced = \
+ {:?}; referenced_ty = {:?}",
+ location,
+ referenced,
+ referenced_ty);
+
+ let item =
+ Item::from_ty_or_ref_with_id(potential_id,
+ referenced_ty,
+ declaration,
+ parent_id,
+ ctx);
+ return Ok(ParseResult::AlreadyResolved(item));
+ }
+ CXCursor_NamespaceRef => {
+ return Err(ParseError::Continue);
+ }
+ _ => {
+ if ty.kind() == CXType_Unexposed {
+ warn!("Unexposed type {:?}, recursing inside, \
+ loc: {:?}",
+ ty,
+ location);
+ return Err(ParseError::Recurse);
+ }
- // If the type name is empty we're probably
- // over-recursing to find a template parameter name
- // or something like that, so just don't be too
- // noisy with it since it causes confusion, see for
- // example the discussion in:
- //
- // https://github.com/jamesmunns/teensy3-rs/issues/9
- if !ty.spelling().is_empty() {
- warn!("invalid type {:?}", ty);
- } else {
warn!("invalid type {:?}", ty);
+ return Err(ParseError::Continue);
}
- return Err(ParseError::Continue);
}
}
- } else {
- // TODO: Don't duplicate this!
- if ty.kind() == CXType_Unexposed {
- warn!("Unexposed type {:?}, recursing inside", ty);
- return Err(ParseError::Recurse);
+ }
+ CXType_Auto => {
+ if canonical_ty == *ty {
+ debug!("Couldn't find deduced type: {:?}", ty);
+ return Err(ParseError::Continue);
}
- if !ty.spelling().is_empty() {
- warn!("invalid type {:?}", ty);
- } else {
- warn!("invalid type {:?}", ty);
+ return Self::from_clang_ty(potential_id,
+ &canonical_ty,
+ location,
+ parent_id,
+ ctx);
+ }
+ // NOTE: We don't resolve pointers eagerly because the pointee type
+ // might not have been parsed, and if it contains templates or
+ // something else we might get confused, see the comment inside
+ // TypeRef.
+ //
+ // We might need to, though, if the context is already in the
+ // process of resolving them.
+ CXType_ObjCObjectPointer |
+ CXType_MemberPointer |
+ CXType_Pointer => {
+ // Fun fact: the canonical type of a pointer type may sometimes
+ // contain information we need but isn't present in the concrete
+ // type (yeah, I'm equally wat'd).
+ //
+ // Yet we still have trouble if we unconditionally trust the
+ // canonical type, like too-much desugaring (sigh).
+ //
+ // See tests/headers/call-conv-field.h for an example.
+ //
+ // Since for now the only identifier cause of breakage is the
+ // ABI for function pointers, and different ABI mixed with
+ // problematic stuff like that one is _extremely_ unlikely and
+ // can be bypassed via blacklisting, we do the check explicitly
+ // (as hacky as it is).
+ //
+ // Yet we should probably (somehow) get the best of both worlds,
+ // presumably special-casing function pointers as a whole, yet
+ // someone is going to need to care about typedef'd function
+ // pointers, etc, which isn't trivial given function pointers
+ // are mostly unexposed. I don't have the time for it right now.
+ let mut pointee = ty.pointee_type().unwrap();
+ let canonical_pointee = canonical_ty.pointee_type()
+ .unwrap();
+ if pointee.call_conv() != canonical_pointee.call_conv() {
+ pointee = canonical_pointee;
}
- return Err(ParseError::Continue);
+ let inner =
+ Item::from_ty_or_ref(pointee, location, None, ctx);
+ TypeKind::Pointer(inner)
}
- }
- CXType_Auto => {
- if canonical_ty == *ty {
- debug!("Couldn't find deduced type: {:?}", ty);
- return Err(ParseError::Continue);
+ CXType_BlockPointer => TypeKind::BlockPointer,
+ // XXX: RValueReference is most likely wrong, but I don't think we
+ // can even add bindings for that, so huh.
+ CXType_RValueReference |
+ CXType_LValueReference => {
+ let inner = Item::from_ty_or_ref(ty.pointee_type()
+ .unwrap(),
+ location,
+ None,
+ ctx);
+ TypeKind::Reference(inner)
}
-
- return Self::from_clang_ty(potential_id,
- &canonical_ty,
- location,
- parent_id,
- ctx);
- }
- // NOTE: We don't resolve pointers eagerly because the pointee type
- // might not have been parsed, and if it contains templates or
- // something else we might get confused, see the comment inside
- // TypeRef.
- //
- // We might need to, though, if the context is already in the
- // process of resolving them.
- CXType_ObjCObjectPointer |
- CXType_MemberPointer |
- CXType_Pointer => {
- // Fun fact: the canonical type of a pointer type may sometimes
- // contain information we need but isn't present in the concrete
- // type (yeah, I'm equally wat'd).
- //
- // Yet we still have trouble if we unconditionally trust the
- // canonical type, like too-much desugaring (sigh).
- //
- // See tests/headers/call-conv-field.h for an example.
- //
- // Since for now the only identifier cause of breakage is the
- // ABI for function pointers, and different ABI mixed with
- // problematic stuff like that one is _extremely_ unlikely and
- // can be bypassed via blacklisting, we do the check explicitly
- // (as hacky as it is).
- //
- // Yet we should probably (somehow) get the best of both worlds,
- // presumably special-casing function pointers as a whole, yet
- // someone is going to need to care about typedef'd function
- // pointers, etc, which isn't trivial given function pointers
- // are mostly unexposed. I don't have the time for it right now.
- let mut pointee = ty.pointee_type().unwrap();
- let canonical_pointee = canonical_ty.pointee_type().unwrap();
- if pointee.call_conv() != canonical_pointee.call_conv() {
- pointee = canonical_pointee;
+ // XXX DependentSizedArray is wrong
+ CXType_VariableArray |
+ CXType_DependentSizedArray => {
+ let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(),
+ location,
+ None,
+ ctx)
+ .expect("Not able to resolve array element?");
+ TypeKind::Pointer(inner)
}
- let inner = Item::from_ty_or_ref(pointee,
- location,
- None,
- ctx);
- TypeKind::Pointer(inner)
- }
- CXType_BlockPointer => TypeKind::BlockPointer,
- // XXX: RValueReference is most likely wrong, but I don't think we
- // can even add bindings for that, so huh.
- CXType_RValueReference |
- CXType_LValueReference => {
- let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(),
- location,
- None,
- ctx);
- TypeKind::Reference(inner)
- }
- // XXX DependentSizedArray is wrong
- CXType_VariableArray |
- CXType_DependentSizedArray => {
- let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(),
- location,
- None,
- ctx)
- .expect("Not able to resolve array element?");
- TypeKind::Pointer(inner)
- }
- CXType_IncompleteArray => {
- let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(),
- location,
- None,
- ctx)
- .expect("Not able to resolve array element?");
- TypeKind::Array(inner, 0)
- }
- CXType_FunctionNoProto |
- CXType_FunctionProto => {
- let signature = try!(FunctionSig::from_ty(ty,
- &location.unwrap_or(cursor),
- ctx));
- TypeKind::Function(signature)
- }
- CXType_Typedef => {
- let inner = cursor.typedef_type().expect("Not valid Type?");
- let inner = Item::from_ty_or_ref(inner, location, None, ctx);
- TypeKind::Alias(inner)
- }
- CXType_Enum => {
- let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
+ CXType_IncompleteArray => {
+ let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(),
+ location,
+ None,
+ ctx)
+ .expect("Not able to resolve array element?");
+ TypeKind::Array(inner, 0)
+ }
+ CXType_FunctionNoProto |
+ CXType_FunctionProto => {
+ let signature =
+ try!(FunctionSig::from_ty(ty, &location, ctx));
+ TypeKind::Function(signature)
+ }
+ CXType_Typedef => {
+ let inner = cursor.typedef_type().expect("Not valid Type?");
+ let inner =
+ Item::from_ty_or_ref(inner, location, None, ctx);
+ TypeKind::Alias(inner)
+ }
+ CXType_Enum => {
+ let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
- if name.is_empty() {
- let pretty_name = ty.spelling();
- if Self::is_valid_identifier(&pretty_name) {
- name = pretty_name;
+ if name.is_empty() {
+ let pretty_name = ty.spelling();
+ if Self::is_valid_identifier(&pretty_name) {
+ name = pretty_name;
+ }
}
- }
- TypeKind::Enum(enum_)
- }
- CXType_Record => {
- let complex =
- CompInfo::from_ty(potential_id, ty, location, ctx)
+ TypeKind::Enum(enum_)
+ }
+ CXType_Record => {
+ let complex = CompInfo::from_ty(potential_id,
+ ty,
+ Some(location),
+ ctx)
.expect("Not a complex type?");
- if name.is_empty() {
- // The pretty-printed name may contain typedefed name,
- // but may also be "struct (anonymous at .h:1)"
- let pretty_name = ty.spelling();
- if Self::is_valid_identifier(&pretty_name) {
- name = pretty_name;
+ if name.is_empty() {
+ // The pretty-printed name may contain typedefed name,
+ // but may also be "struct (anonymous at .h:1)"
+ let pretty_name = ty.spelling();
+ if Self::is_valid_identifier(&pretty_name) {
+ name = pretty_name;
+ }
}
- }
- TypeKind::Comp(complex)
- }
- // FIXME: We stub vectors as arrays since in 99% of the cases the
- // layout is going to be correct, and there's no way we can generate
- // vector types properly in Rust for now.
- //
- // That being said, that should be fixed eventually.
- CXType_Vector |
- CXType_ConstantArray => {
- let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(),
- location,
- None,
- ctx)
- .expect("Not able to resolve array element?");
- TypeKind::Array(inner, ty.num_elements().unwrap())
- }
- CXType_Elaborated => {
- return Self::from_clang_ty(potential_id,
- &ty.named(),
- location,
- parent_id,
- ctx);
- }
- CXType_ObjCId => TypeKind::ObjCId,
- CXType_ObjCSel => TypeKind::ObjCSel,
- CXType_ObjCClass |
- CXType_ObjCInterface => {
- let interface = ObjCInterface::from_ty(&location.unwrap(), ctx)
- .expect("Not a valid objc interface?");
- name = interface.rust_name();
- TypeKind::ObjCInterface(interface)
- }
- _ => {
- error!("unsupported type: kind = {:?}; ty = {:?}; at {:?}",
- ty.kind(),
- ty,
- location);
- return Err(ParseError::Continue);
+ TypeKind::Comp(complex)
+ }
+ // FIXME: We stub vectors as arrays since in 99% of the cases the
+ // layout is going to be correct, and there's no way we can generate
+ // vector types properly in Rust for now.
+ //
+ // That being said, that should be fixed eventually.
+ CXType_Vector |
+ CXType_ConstantArray => {
+ let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(),
+ location,
+ None,
+ ctx)
+ .expect("Not able to resolve array element?");
+ TypeKind::Array(inner, ty.num_elements().unwrap())
+ }
+ CXType_Elaborated => {
+ return Self::from_clang_ty(potential_id,
+ &ty.named(),
+ location,
+ parent_id,
+ ctx);
+ }
+ CXType_ObjCId => TypeKind::ObjCId,
+ CXType_ObjCSel => TypeKind::ObjCSel,
+ CXType_ObjCClass |
+ CXType_ObjCInterface => {
+ let interface = ObjCInterface::from_ty(&location, ctx)
+ .expect("Not a valid objc interface?");
+ name = interface.rust_name();
+ TypeKind::ObjCInterface(interface)
+ }
+ _ => {
+ error!("unsupported type: kind = {:?}; ty = {:?}; at {:?}",
+ ty.kind(),
+ ty,
+ location);
+ return Err(ParseError::Continue);
+ }
}
};
@@ -1306,14 +1402,12 @@ impl Trace for Type {
TypeKind::TemplateAlias(inner, ref template_params) => {
tracer.visit_kind(inner, EdgeKind::TypeReference);
for &item in template_params {
- tracer.visit_kind(item, EdgeKind::TemplateParameterDefinition);
+ tracer.visit_kind(item,
+ EdgeKind::TemplateParameterDefinition);
}
}
- TypeKind::TemplateInstantiation(inner, ref template_args) => {
- tracer.visit_kind(inner, EdgeKind::TemplateDeclaration);
- for &item in template_args {
- tracer.visit_kind(item, EdgeKind::TemplateArgument);
- }
+ TypeKind::TemplateInstantiation(ref inst) => {
+ inst.trace(context, tracer, &());
}
TypeKind::Comp(ref ci) => ci.trace(context, tracer, item),
TypeKind::Function(ref sig) => sig.trace(context, tracer, &()),
@@ -1331,6 +1425,7 @@ impl Trace for Type {
}
// None of these variants have edges to other items and types.
+ TypeKind::Opaque |
TypeKind::UnresolvedTypeRef(_, _, None) |
TypeKind::Named |
TypeKind::Void |
diff --git a/src/ir/var.rs b/src/ir/var.rs
index 7b610da4..350bfe4a 100644
--- a/src/ir/var.rs
+++ b/src/ir/var.rs
@@ -87,15 +87,20 @@ impl Var {
}
impl DotAttributes for Var {
- fn dot_attributes<W>(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()>
- where W: io::Write
+ fn dot_attributes<W>(&self,
+ _ctx: &BindgenContext,
+ out: &mut W)
+ -> io::Result<()>
+ where W: io::Write,
{
if self.is_const {
try!(writeln!(out, "<tr><td>const</td><td>true</td></tr>"));
}
if let Some(ref mangled) = self.mangled_name {
- try!(writeln!(out, "<tr><td>mangled name</td><td>{}</td></tr>", mangled));
+ try!(writeln!(out,
+ "<tr><td>mangled name</td><td>{}</td></tr>",
+ mangled));
}
Ok(())
@@ -202,7 +207,7 @@ impl ClangSubItemParser for Var {
// XXX this is redundant, remove!
let is_const = ty.is_const();
- let ty = match Item::from_ty(&ty, Some(cursor), None, ctx) {
+ let ty = match Item::from_ty(&ty, cursor, None, ctx) {
Ok(ty) => ty,
Err(e) => {
assert_eq!(ty.kind(),
diff --git a/src/parse.rs b/src/parse.rs
index 0e4164f0..73bb7b25 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -49,7 +49,7 @@ pub trait ClangItemParser: Sized {
/// Parse this item from the given Clang type.
fn from_ty(ty: &clang::Type,
- location: Option<clang::Cursor>,
+ location: clang::Cursor,
parent: Option<ItemId>,
ctx: &mut BindgenContext)
-> Result<ItemId, ParseError>;
@@ -58,7 +58,7 @@ pub trait ClangItemParser: Sized {
/// newly parsed item.
fn from_ty_with_id(id: ItemId,
ty: &clang::Type,
- location: Option<clang::Cursor>,
+ location: clang::Cursor,
parent: Option<ItemId>,
ctx: &mut BindgenContext)
-> Result<ItemId, ParseError>;
@@ -66,7 +66,7 @@ pub trait ClangItemParser: Sized {
/// Parse this item from the given Clang type, or if we haven't resolved all
/// the other items this one depends on, an unresolved reference.
fn from_ty_or_ref(ty: clang::Type,
- location: Option<clang::Cursor>,
+ location: clang::Cursor,
parent_id: Option<ItemId>,
context: &mut BindgenContext)
-> ItemId;
@@ -75,26 +75,16 @@ pub trait ClangItemParser: Sized {
/// `ItemId` for the newly parsed item.
fn from_ty_or_ref_with_id(potential_id: ItemId,
ty: clang::Type,
- location: Option<clang::Cursor>,
+ location: clang::Cursor,
parent_id: Option<ItemId>,
context: &mut BindgenContext)
-> ItemId;
/// Create a named template type.
- fn named_type<S>(name: S,
- parent: ItemId,
- context: &mut BindgenContext)
- -> ItemId
- where S: Into<String>;
-
- /// Identical to `named_type`, but use `id` as the resulting item's
- /// `ItemId`.
- fn named_type_with_id<S>(id: ItemId,
- name: S,
- parent: ItemId,
- context: &mut BindgenContext)
- -> ItemId
- where S: Into<String>;
+ fn named_type(with_id: Option<ItemId>,
+ location: clang::Cursor,
+ ctx: &mut BindgenContext)
+ -> Option<ItemId>;
/// Create a builtin type.
fn builtin_type(kind: TypeKind,
diff --git a/src/uses.rs b/src/uses.rs
index 47f72da6..0799011b 100644
--- a/src/uses.rs
+++ b/src/uses.rs
@@ -37,6 +37,7 @@
use ir::context::BindgenContext;
use ir::item::{Item, ItemAncestors, ItemCanonicalName};
+use ir::ty::TemplateDeclaration;
use std::io;
// Like `canonical_path`, except we always take namespaces into account, ignore
@@ -83,9 +84,9 @@ pub fn generate_dummy_uses<W>(ctx: &mut BindgenContext,
// these.
!ty.is_builtin_or_named() &&
// And finally, we won't be creating any dummy
- // specializations, so ignore template declarations and
- // partial specializations.
- item.applicable_template_args(ctx).is_empty()
+ // instantiations, so ignore template declarations and
+ // instantiations.
+ item.all_template_params(ctx).is_none()
} else {
false
}
diff --git a/tests/expectations/lib.rs b/tests/expectations/lib.rs
index e69de29b..562dc554 100644..100755
--- a/tests/expectations/lib.rs
+++ b/tests/expectations/lib.rs
@@ -0,0 +1,3 @@
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
diff --git a/tests/expectations/tests/381-decltype-alias.rs b/tests/expectations/tests/381-decltype-alias.rs
index 45b0cfdd..632cdd31 100644
--- a/tests/expectations/tests/381-decltype-alias.rs
+++ b/tests/expectations/tests/381-decltype-alias.rs
@@ -5,11 +5,8 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct std_allocator_traits<_Alloc> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct std_allocator_traits {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<_Alloc>,
-}
-impl <_Alloc> Default for std_allocator_traits<_Alloc> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
+pub type std_allocator_traits___size_type<_Alloc> = _Alloc;
diff --git a/tests/expectations/tests/anon_enum_trait.rs b/tests/expectations/tests/anon_enum_trait.rs
index 31eaca83..92c697a8 100644
--- a/tests/expectations/tests/anon_enum_trait.rs
+++ b/tests/expectations/tests/anon_enum_trait.rs
@@ -5,10 +5,9 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct DataType<_Tp> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct DataType {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<_Tp>,
}
pub type DataType_value_type<_Tp> = _Tp;
pub type DataType_work_type<_Tp> = DataType_value_type<_Tp>;
@@ -27,9 +26,6 @@ pub const DataType_type_: DataType__bindgen_ty_1 =
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum DataType__bindgen_ty_1 { generic_type = 0, }
-impl <_Tp> Default for DataType<_Tp> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
-}
#[repr(C)]
#[derive(Debug, Default, Copy)]
pub struct Foo {
diff --git a/tests/expectations/tests/anon_union.rs b/tests/expectations/tests/anon_union.rs
index 4418bc77..eb600cc7 100644
--- a/tests/expectations/tests/anon_union.rs
+++ b/tests/expectations/tests/anon_union.rs
@@ -30,12 +30,11 @@ impl <T> ::std::fmt::Debug for __BindgenUnionField<T> {
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct TErrorResult<T> {
+pub struct TErrorResult {
pub mResult: ::std::os::raw::c_int,
- pub __bindgen_anon_1: TErrorResult__bindgen_ty_1<T>,
+ pub __bindgen_anon_1: TErrorResult__bindgen_ty_1,
pub mMightHaveUnreported: bool,
pub mUnionState: TErrorResult_UnionState,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
pub const TErrorResult_UnionState_HasException: TErrorResult_UnionState =
TErrorResult_UnionState::HasMessage;
@@ -44,31 +43,28 @@ pub const TErrorResult_UnionState_HasException: TErrorResult_UnionState =
pub enum TErrorResult_UnionState { HasMessage = 0, }
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct TErrorResult_Message<T> {
+pub struct TErrorResult_Message {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct TErrorResult_DOMExceptionInfo<T> {
+pub struct TErrorResult_DOMExceptionInfo {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct TErrorResult__bindgen_ty_1<T> {
- pub mMessage: __BindgenUnionField<*mut TErrorResult_Message<T>>,
- pub mDOMExceptionInfo: __BindgenUnionField<*mut TErrorResult_DOMExceptionInfo<T>>,
+pub struct TErrorResult__bindgen_ty_1 {
+ pub mMessage: __BindgenUnionField<*mut TErrorResult_Message>,
+ pub mDOMExceptionInfo: __BindgenUnionField<*mut TErrorResult_DOMExceptionInfo>,
pub bindgen_union_field: u64,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
-impl <T> Default for TErrorResult<T> {
+impl Default for TErrorResult {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct ErrorResult {
- pub _base: TErrorResult<::std::os::raw::c_int>,
+ pub _base: TErrorResult,
}
#[test]
fn bindgen_test_layout_ErrorResult() {
@@ -84,13 +80,11 @@ impl Default for ErrorResult {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[test]
-fn __bindgen_test_layout_template_1() {
- assert_eq!(::std::mem::size_of::<TErrorResult<::std::os::raw::c_int>>() ,
- 24usize , concat ! (
+fn __bindgen_test_layout_TErrorResult_instantiation_21() {
+ assert_eq!(::std::mem::size_of::<TErrorResult>() , 24usize , concat ! (
"Size of template specialization: " , stringify ! (
- TErrorResult<::std::os::raw::c_int> ) ));
- assert_eq!(::std::mem::align_of::<TErrorResult<::std::os::raw::c_int>>() ,
- 8usize , concat ! (
+ TErrorResult ) ));
+ assert_eq!(::std::mem::align_of::<TErrorResult>() , 8usize , concat ! (
"Alignment of template specialization: " , stringify ! (
- TErrorResult<::std::os::raw::c_int> ) ));
+ TErrorResult ) ));
}
diff --git a/tests/expectations/tests/auto.rs b/tests/expectations/tests/auto.rs
index 4551f703..7f9bbf44 100644
--- a/tests/expectations/tests/auto.rs
+++ b/tests/expectations/tests/auto.rs
@@ -21,13 +21,9 @@ impl Clone for Foo {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Bar<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Bar {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for Bar<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
extern "C" {
#[link_name = "_Z5Test2v"]
diff --git a/tests/expectations/tests/bad-namespace-parenthood-inheritance.rs b/tests/expectations/tests/bad-namespace-parenthood-inheritance.rs
index b0c91e8c..4074dd02 100644
--- a/tests/expectations/tests/bad-namespace-parenthood-inheritance.rs
+++ b/tests/expectations/tests/bad-namespace-parenthood-inheritance.rs
@@ -5,13 +5,9 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct std_char_traits<_CharT> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct std_char_traits {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<_CharT>,
-}
-impl <_CharT> Default for std_char_traits<_CharT> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Default, Copy)]
diff --git a/tests/expectations/tests/class_nested.rs b/tests/expectations/tests/class_nested.rs
index 6ddcf91b..b92976f6 100644
--- a/tests/expectations/tests/class_nested.rs
+++ b/tests/expectations/tests/class_nested.rs
@@ -77,7 +77,7 @@ extern "C" {
pub static mut var: A_B;
}
#[test]
-fn __bindgen_test_layout_template_1() {
+fn __bindgen_test_layout_A_D_instantiation_16() {
assert_eq!(::std::mem::size_of::<A_D<::std::os::raw::c_int>>() , 4usize ,
concat ! (
"Size of template specialization: " , stringify ! (
diff --git a/tests/expectations/tests/class_with_dtor.rs b/tests/expectations/tests/class_with_dtor.rs
index 4c1d2718..495889f2 100644
--- a/tests/expectations/tests/class_with_dtor.rs
+++ b/tests/expectations/tests/class_with_dtor.rs
@@ -34,7 +34,7 @@ impl Default for WithoutDtor {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[test]
-fn __bindgen_test_layout_template_1() {
+fn __bindgen_test_layout_HandleWithDtor_instantiation_10() {
assert_eq!(::std::mem::size_of::<HandleWithDtor<::std::os::raw::c_int>>()
, 8usize , concat ! (
"Size of template specialization: " , stringify ! (
diff --git a/tests/expectations/tests/constant-non-specialized-tp.rs b/tests/expectations/tests/constant-non-specialized-tp.rs
index f2aa5a75..a17e261b 100644
--- a/tests/expectations/tests/constant-non-specialized-tp.rs
+++ b/tests/expectations/tests/constant-non-specialized-tp.rs
@@ -5,26 +5,17 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Test<Args> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Test {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<Args>,
-}
-impl <Args> Default for Test<Args> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Outer<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Outer {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct Outer_Inner<T> {
+pub struct Outer_Inner {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for Outer<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/constructor-tp.rs b/tests/expectations/tests/constructor-tp.rs
index ee04d3c5..6ba52f22 100644
--- a/tests/expectations/tests/constructor-tp.rs
+++ b/tests/expectations/tests/constructor-tp.rs
@@ -5,13 +5,9 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Foo<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Foo {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for Foo<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Default, Copy)]
diff --git a/tests/expectations/tests/crtp.rs b/tests/expectations/tests/crtp.rs
index 7143f50e..8a83e198 100644
--- a/tests/expectations/tests/crtp.rs
+++ b/tests/expectations/tests/crtp.rs
@@ -5,13 +5,9 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Base<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Base {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for Base<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Copy)]
@@ -32,13 +28,9 @@ impl Default for Derived {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
-#[derive(Debug)]
-pub struct BaseWithDestructor<T> {
+#[derive(Debug, Default)]
+pub struct BaseWithDestructor {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for BaseWithDestructor<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug)]
@@ -59,22 +51,21 @@ impl Default for DerivedFromBaseWithDestructor {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[test]
-fn __bindgen_test_layout_template_1() {
- assert_eq!(::std::mem::size_of::<Base<Derived>>() , 1usize , concat ! (
- "Size of template specialization: " , stringify ! (
- Base<Derived> ) ));
- assert_eq!(::std::mem::align_of::<Base<Derived>>() , 1usize , concat ! (
- "Alignment of template specialization: " , stringify ! (
- Base<Derived> ) ));
+fn __bindgen_test_layout_Base_instantiation_9() {
+ assert_eq!(::std::mem::size_of::<Base>() , 1usize , concat ! (
+ "Size of template specialization: " , stringify ! ( Base ) ));
+ assert_eq!(::std::mem::align_of::<Base>() , 1usize , concat ! (
+ "Alignment of template specialization: " , stringify ! ( Base )
+ ));
}
#[test]
-fn __bindgen_test_layout_template_2() {
- assert_eq!(::std::mem::size_of::<BaseWithDestructor<DerivedFromBaseWithDestructor>>()
- , 1usize , concat ! (
+fn __bindgen_test_layout_BaseWithDestructor_instantiation_12() {
+ assert_eq!(::std::mem::size_of::<BaseWithDestructor>() , 1usize , concat !
+ (
"Size of template specialization: " , stringify ! (
- BaseWithDestructor<DerivedFromBaseWithDestructor> ) ));
- assert_eq!(::std::mem::align_of::<BaseWithDestructor<DerivedFromBaseWithDestructor>>()
- , 1usize , concat ! (
+ BaseWithDestructor ) ));
+ assert_eq!(::std::mem::align_of::<BaseWithDestructor>() , 1usize , concat
+ ! (
"Alignment of template specialization: " , stringify ! (
- BaseWithDestructor<DerivedFromBaseWithDestructor> ) ));
+ BaseWithDestructor ) ));
}
diff --git a/tests/expectations/tests/dash_language.rs b/tests/expectations/tests/dash_language.rs
index 24df1014..385c39c6 100644
--- a/tests/expectations/tests/dash_language.rs
+++ b/tests/expectations/tests/dash_language.rs
@@ -5,11 +5,7 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Foo<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Foo {
pub bar: ::std::os::raw::c_int,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for Foo<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/empty_template_param_name.rs b/tests/expectations/tests/empty_template_param_name.rs
index 6ee8fce3..2bd5a570 100644
--- a/tests/expectations/tests/empty_template_param_name.rs
+++ b/tests/expectations/tests/empty_template_param_name.rs
@@ -6,11 +6,7 @@
pub type __void_t = ::std::os::raw::c_void;
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct __iterator_traits<_Iterator> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct __iterator_traits {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<_Iterator>,
-}
-impl <_Iterator> Default for __iterator_traits<_Iterator> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/enum_in_template_with_typedef.rs b/tests/expectations/tests/enum_in_template_with_typedef.rs
index e4725b83..2b956963 100644
--- a/tests/expectations/tests/enum_in_template_with_typedef.rs
+++ b/tests/expectations/tests/enum_in_template_with_typedef.rs
@@ -5,10 +5,9 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct std_fbstring_core<Char> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct std_fbstring_core {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<Char>,
}
pub type std_fbstring_core_category_type = u8;
pub const std_fbstring_core_Category_Bar: std_fbstring_core_Category =
@@ -16,6 +15,3 @@ pub const std_fbstring_core_Category_Bar: std_fbstring_core_Category =
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum std_fbstring_core_Category { Foo = 0, }
-impl <Char> Default for std_fbstring_core<Char> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
-}
diff --git a/tests/expectations/tests/eval-variadic-template-parameter.rs b/tests/expectations/tests/eval-variadic-template-parameter.rs
index acc6f34c..701aab9f 100644
--- a/tests/expectations/tests/eval-variadic-template-parameter.rs
+++ b/tests/expectations/tests/eval-variadic-template-parameter.rs
@@ -5,11 +5,7 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct B<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct B {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for B<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/forward-inherit-struct.rs b/tests/expectations/tests/forward-inherit-struct.rs
index 1057e70c..322854dd 100644
--- a/tests/expectations/tests/forward-inherit-struct.rs
+++ b/tests/expectations/tests/forward-inherit-struct.rs
@@ -6,19 +6,14 @@
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct Rooted<T> {
+pub struct Rooted {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
-impl <T> Default for Rooted<T> {
+impl Default for Rooted {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct js_RootedBase<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct js_RootedBase {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for js_RootedBase<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/in_class_typedef.rs b/tests/expectations/tests/in_class_typedef.rs
index 3634a631..613c8cab 100644
--- a/tests/expectations/tests/in_class_typedef.rs
+++ b/tests/expectations/tests/in_class_typedef.rs
@@ -5,20 +5,15 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Foo<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Foo {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
pub type Foo_elem_type<T> = T;
pub type Foo_ptr_type<T> = *mut T;
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct Foo_Bar<T> {
+pub struct Foo_Bar {
pub x: ::std::os::raw::c_int,
pub y: ::std::os::raw::c_int,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for Foo<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/inherit-namespaced.rs b/tests/expectations/tests/inherit-namespaced.rs
index e5d5f875..fcd8de97 100644
--- a/tests/expectations/tests/inherit-namespaced.rs
+++ b/tests/expectations/tests/inherit-namespaced.rs
@@ -5,20 +5,15 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct js_RootedBase<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct js_RootedBase {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for js_RootedBase<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct Rooted<T> {
+pub struct Rooted {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
-impl <T> Default for Rooted<T> {
+impl Default for Rooted {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/inherit_named.rs b/tests/expectations/tests/inherit_named.rs
index 31c4bee9..703df9ea 100644
--- a/tests/expectations/tests/inherit_named.rs
+++ b/tests/expectations/tests/inherit_named.rs
@@ -5,13 +5,9 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Wohoo<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Wohoo {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for Wohoo<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
diff --git a/tests/expectations/tests/inner_template_self.rs b/tests/expectations/tests/inner_template_self.rs
index 3510fa7c..d75c280d 100644
--- a/tests/expectations/tests/inner_template_self.rs
+++ b/tests/expectations/tests/inner_template_self.rs
@@ -6,17 +6,17 @@
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct LinkedList<T> {
- pub next: *mut LinkedList<T>,
- pub prev: *mut LinkedList<T>,
+pub struct LinkedList {
+ pub next: *mut LinkedList,
+ pub prev: *mut LinkedList,
}
-impl <T> Default for LinkedList<T> {
+impl Default for LinkedList {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct InstantiateIt {
- pub m_list: LinkedList<::std::os::raw::c_int>,
+ pub m_list: LinkedList,
}
#[test]
fn bindgen_test_layout_InstantiateIt() {
diff --git a/tests/expectations/tests/issue-358.rs b/tests/expectations/tests/issue-358.rs
index d3be3c43..e574bd01 100644
--- a/tests/expectations/tests/issue-358.rs
+++ b/tests/expectations/tests/issue-358.rs
@@ -6,11 +6,10 @@
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct JS_PersistentRooted<c> {
+pub struct JS_PersistentRooted {
pub _base: a,
- pub _phantom_0: ::std::marker::PhantomData<c>,
}
-impl <c> Default for JS_PersistentRooted<c> {
+impl Default for JS_PersistentRooted {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
diff --git a/tests/expectations/tests/issue-446.rs b/tests/expectations/tests/issue-446.rs
index fa736bcc..13204c1a 100644
--- a/tests/expectations/tests/issue-446.rs
+++ b/tests/expectations/tests/issue-446.rs
@@ -6,17 +6,17 @@
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct List<Elem> {
- pub next: *mut List<Elem>,
+pub struct List {
+ pub next: *mut List,
}
-impl <Elem> Default for List<Elem> {
+impl Default for List {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct PersistentRooted<GcThing> {
- pub root_list: List<PersistentRooted<GcThing>>,
+pub struct PersistentRooted {
+ pub root_list: List,
}
-impl <GcThing> Default for PersistentRooted<GcThing> {
+impl Default for PersistentRooted {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/issue-493.rs b/tests/expectations/tests/issue-493.rs
index a2246ca6..155834a3 100644
--- a/tests/expectations/tests/issue-493.rs
+++ b/tests/expectations/tests/issue-493.rs
@@ -29,28 +29,21 @@ impl <T> ::std::fmt::Debug for __BindgenUnionField<T> {
}
}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct basic_string<_CharT, _Traits, _Allocator> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct basic_string {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<_CharT>,
- pub _phantom_1: ::std::marker::PhantomData<_Traits>,
- pub _phantom_2: ::std::marker::PhantomData<_Allocator>,
}
pub type basic_string_size_type = ::std::os::raw::c_ulonglong;
pub type basic_string_value_type = ::std::os::raw::c_schar;
pub type basic_string_pointer = *mut basic_string_value_type;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct basic_string___long<_CharT, _Traits, _Allocator> {
+pub struct basic_string___long {
pub __cap_: basic_string_size_type,
pub __size_: basic_string_size_type,
pub __data_: basic_string_pointer,
- pub _phantom_0: ::std::marker::PhantomData<_CharT>,
- pub _phantom_1: ::std::marker::PhantomData<_Traits>,
- pub _phantom_2: ::std::marker::PhantomData<_Allocator>,
}
-impl <_CharT, _Traits, _Allocator> Default for
- basic_string___long<_CharT, _Traits, _Allocator> {
+impl Default for basic_string___long {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
pub const basic_string___min_cap: basic_string__bindgen_ty_1 =
@@ -60,42 +53,28 @@ pub const basic_string___min_cap: basic_string__bindgen_ty_1 =
pub enum basic_string__bindgen_ty_1 { __min_cap = 0, }
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct basic_string___short<_CharT, _Traits, _Allocator> {
- pub __bindgen_anon_1: basic_string___short__bindgen_ty_1<_CharT, _Traits,
- _Allocator>,
+pub struct basic_string___short {
+ pub __bindgen_anon_1: basic_string___short__bindgen_ty_1,
pub __data_: *mut basic_string_value_type,
- pub _phantom_0: ::std::marker::PhantomData<_CharT>,
- pub _phantom_1: ::std::marker::PhantomData<_Traits>,
- pub _phantom_2: ::std::marker::PhantomData<_Allocator>,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct basic_string___short__bindgen_ty_1<_CharT, _Traits, _Allocator> {
+pub struct basic_string___short__bindgen_ty_1 {
pub __size_: __BindgenUnionField<::std::os::raw::c_uchar>,
pub __lx: __BindgenUnionField<basic_string_value_type>,
pub bindgen_union_field: u8,
- pub _phantom_0: ::std::marker::PhantomData<_CharT>,
- pub _phantom_1: ::std::marker::PhantomData<_Traits>,
- pub _phantom_2: ::std::marker::PhantomData<_Allocator>,
}
-impl <_CharT, _Traits, _Allocator> Default for
- basic_string___short<_CharT, _Traits, _Allocator> {
+impl Default for basic_string___short {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Copy, Clone)]
-pub struct basic_string___ulx<_CharT, _Traits, _Allocator> {
- pub __lx: __BindgenUnionField<basic_string___long<_CharT, _Traits,
- _Allocator>>,
- pub __lxx: __BindgenUnionField<basic_string___short<_CharT, _Traits,
- _Allocator>>,
+pub struct basic_string___ulx {
+ pub __lx: __BindgenUnionField<basic_string___long>,
+ pub __lxx: __BindgenUnionField<basic_string___short>,
pub bindgen_union_field: [u8; 0usize],
- pub _phantom_0: ::std::marker::PhantomData<_CharT>,
- pub _phantom_1: ::std::marker::PhantomData<_Traits>,
- pub _phantom_2: ::std::marker::PhantomData<_Allocator>,
}
-impl <_CharT, _Traits, _Allocator> Default for
- basic_string___ulx<_CharT, _Traits, _Allocator> {
+impl Default for basic_string___ulx {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
pub const basic_string___n_words: basic_string__bindgen_ty_2 =
@@ -105,48 +84,28 @@ pub const basic_string___n_words: basic_string__bindgen_ty_2 =
pub enum basic_string__bindgen_ty_2 { __n_words = 0, }
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct basic_string___raw<_CharT, _Traits, _Allocator> {
+pub struct basic_string___raw {
pub __words: *mut basic_string_size_type,
- pub _phantom_0: ::std::marker::PhantomData<_CharT>,
- pub _phantom_1: ::std::marker::PhantomData<_Traits>,
- pub _phantom_2: ::std::marker::PhantomData<_Allocator>,
}
-impl <_CharT, _Traits, _Allocator> Default for
- basic_string___raw<_CharT, _Traits, _Allocator> {
+impl Default for basic_string___raw {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Copy, Clone)]
-pub struct basic_string___rep<_CharT, _Traits, _Allocator> {
- pub __bindgen_anon_1: basic_string___rep__bindgen_ty_1<_CharT, _Traits,
- _Allocator>,
- pub _phantom_0: ::std::marker::PhantomData<_CharT>,
- pub _phantom_1: ::std::marker::PhantomData<_Traits>,
- pub _phantom_2: ::std::marker::PhantomData<_Allocator>,
+pub struct basic_string___rep {
+ pub __bindgen_anon_1: basic_string___rep__bindgen_ty_1,
}
#[repr(C)]
#[derive(Copy, Clone)]
-pub struct basic_string___rep__bindgen_ty_1<_CharT, _Traits, _Allocator> {
- pub __l: __BindgenUnionField<basic_string___long<_CharT, _Traits,
- _Allocator>>,
- pub __s: __BindgenUnionField<basic_string___short<_CharT, _Traits,
- _Allocator>>,
- pub __r: __BindgenUnionField<basic_string___raw<_CharT, _Traits,
- _Allocator>>,
+pub struct basic_string___rep__bindgen_ty_1 {
+ pub __l: __BindgenUnionField<basic_string___long>,
+ pub __s: __BindgenUnionField<basic_string___short>,
+ pub __r: __BindgenUnionField<basic_string___raw>,
pub bindgen_union_field: [u8; 0usize],
- pub _phantom_0: ::std::marker::PhantomData<_CharT>,
- pub _phantom_1: ::std::marker::PhantomData<_Traits>,
- pub _phantom_2: ::std::marker::PhantomData<_Allocator>,
-}
-impl <_CharT, _Traits, _Allocator> Default for
- basic_string___rep__bindgen_ty_1<_CharT, _Traits, _Allocator> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
-impl <_CharT, _Traits, _Allocator> Default for
- basic_string___rep<_CharT, _Traits, _Allocator> {
+impl Default for basic_string___rep__bindgen_ty_1 {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
-impl <_CharT, _Traits, _Allocator> Default for
- basic_string<_CharT, _Traits, _Allocator> {
+impl Default for basic_string___rep {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/issue-544-stylo-creduce-2.rs b/tests/expectations/tests/issue-544-stylo-creduce-2.rs
new file mode 100644
index 00000000..c0fae845
--- /dev/null
+++ b/tests/expectations/tests/issue-544-stylo-creduce-2.rs
@@ -0,0 +1,15 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+pub struct Foo {
+ pub member: Foo_SecondAlias,
+}
+pub type Foo_FirstAlias = [u8; 0usize];
+pub type Foo_SecondAlias = [u8; 0usize];
+impl Default for Foo {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/issue-544-stylo-creduce.rs b/tests/expectations/tests/issue-544-stylo-creduce.rs
new file mode 100644
index 00000000..88cc0d87
--- /dev/null
+++ b/tests/expectations/tests/issue-544-stylo-creduce.rs
@@ -0,0 +1,14 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct a {
+ pub _address: u8,
+}
+impl Clone for a {
+ fn clone(&self) -> Self { *self }
+}
diff --git a/tests/expectations/tests/maddness-is-avoidable.rs b/tests/expectations/tests/maddness-is-avoidable.rs
index 2fb5e540..09c1c921 100644
--- a/tests/expectations/tests/maddness-is-avoidable.rs
+++ b/tests/expectations/tests/maddness-is-avoidable.rs
@@ -5,22 +5,12 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct RefPtr<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct RefPtr {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct RefPtr_Proxy<T, R, Args> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct RefPtr_Proxy {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
- pub _phantom_1: ::std::marker::PhantomData<R>,
- pub _phantom_2: ::std::marker::PhantomData<Args>,
-}
-impl <T, R, Args> Default for RefPtr_Proxy<T, R, Args> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
-}
-impl <T> Default for RefPtr<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/no_copy.rs b/tests/expectations/tests/no_copy.rs
index 3590241f..a75f891c 100644
--- a/tests/expectations/tests/no_copy.rs
+++ b/tests/expectations/tests/no_copy.rs
@@ -6,11 +6,7 @@
/** <div rustbindgen nocopy></div> */
#[repr(C)]
-#[derive(Debug)]
-pub struct CopiableButWait<T> {
+#[derive(Debug, Default)]
+pub struct CopiableButWait {
pub whatever: ::std::os::raw::c_int,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for CopiableButWait<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/opaque_pointer.rs b/tests/expectations/tests/opaque_pointer.rs
index 15b01db4..2e1890a8 100644
--- a/tests/expectations/tests/opaque_pointer.rs
+++ b/tests/expectations/tests/opaque_pointer.rs
@@ -27,16 +27,15 @@ impl Clone for OtherOpaque {
*/
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct Opaque<T> {
- pub _phantom_0: ::std::marker::PhantomData<T>,
+pub struct Opaque {
}
-impl <T> Default for Opaque<T> {
+impl Default for Opaque {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct WithOpaquePtr {
- pub whatever: *mut Opaque<::std::os::raw::c_int>,
+ pub whatever: *mut (),
pub other: u32,
pub t: OtherOpaque,
}
diff --git a/tests/expectations/tests/opaque_typedef.rs b/tests/expectations/tests/opaque_typedef.rs
index d6d5ac5d..51951faf 100644
--- a/tests/expectations/tests/opaque_typedef.rs
+++ b/tests/expectations/tests/opaque_typedef.rs
@@ -5,14 +5,10 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct RandomTemplate<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct RandomTemplate {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for RandomTemplate<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
/** <div rustbindgen opaque></div> */
pub type ShouldBeOpaque = [u8; 0usize];
-pub type ShouldNotBeOpaque = RandomTemplate<f32>;
+pub type ShouldNotBeOpaque = RandomTemplate;
diff --git a/tests/expectations/tests/partial-specialization-and-inheritance.rs b/tests/expectations/tests/partial-specialization-and-inheritance.rs
new file mode 100644
index 00000000..24225934
--- /dev/null
+++ b/tests/expectations/tests/partial-specialization-and-inheritance.rs
@@ -0,0 +1,44 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Base {
+ pub _address: u8,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Derived {
+ pub b: bool,
+}
+#[test]
+fn __bindgen_test_layout__bindgen_ty_id_20_instantiation_14() {
+ assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat ! (
+ "Size of template specialization: " , stringify ! (
+ [u32; 2usize] ) ));
+ assert_eq!(::std::mem::align_of::<[u32; 2usize]>() , 4usize , concat ! (
+ "Alignment of template specialization: " , stringify ! (
+ [u32; 2usize] ) ));
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy)]
+pub struct Usage {
+ pub _address: u8,
+}
+extern "C" {
+ #[link_name = "_ZN5Usage13static_memberE"]
+ pub static mut Usage_static_member: [u32; 2usize];
+}
+#[test]
+fn bindgen_test_layout_Usage() {
+ assert_eq!(::std::mem::size_of::<Usage>() , 1usize , concat ! (
+ "Size of: " , stringify ! ( Usage ) ));
+ assert_eq! (::std::mem::align_of::<Usage>() , 1usize , concat ! (
+ "Alignment of " , stringify ! ( Usage ) ));
+}
+impl Clone for Usage {
+ fn clone(&self) -> Self { *self }
+}
diff --git a/tests/expectations/tests/replace_use.rs b/tests/expectations/tests/replace_use.rs
index d93121d3..6cdc3263 100644
--- a/tests/expectations/tests/replace_use.rs
+++ b/tests/expectations/tests/replace_use.rs
@@ -8,18 +8,14 @@
* <div rustbindgen replaces="nsTArray"></div>
*/
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct nsTArray<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct nsTArray {
pub y: ::std::os::raw::c_uint,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for nsTArray<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct Test {
- pub a: nsTArray<::std::os::raw::c_long>,
+ pub a: nsTArray,
}
#[test]
fn bindgen_test_layout_Test() {
diff --git a/tests/expectations/tests/size_t_template.rs b/tests/expectations/tests/size_t_template.rs
index 4d81651e..b2680869 100644
--- a/tests/expectations/tests/size_t_template.rs
+++ b/tests/expectations/tests/size_t_template.rs
@@ -5,7 +5,6 @@
#[repr(C)]
-#[derive(Debug, Copy)]
pub struct C {
pub arr: [u32; 3usize],
}
@@ -21,9 +20,6 @@ fn bindgen_test_layout_C() {
"Alignment of field: " , stringify ! ( C ) , "::" , stringify
! ( arr ) ));
}
-impl Clone for C {
- fn clone(&self) -> Self { *self }
-}
impl Default for C {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/struct_with_typedef_template_arg.rs b/tests/expectations/tests/struct_with_typedef_template_arg.rs
index f882c65d..93620e59 100644
--- a/tests/expectations/tests/struct_with_typedef_template_arg.rs
+++ b/tests/expectations/tests/struct_with_typedef_template_arg.rs
@@ -5,14 +5,9 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Proxy<T, Args> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Proxy {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
- pub _phantom_1: ::std::marker::PhantomData<Args>,
}
pub type Proxy_foo<T> =
::std::option::Option<unsafe extern "C" fn(bar: *mut T)>;
-impl <T, Args> Default for Proxy<T, Args> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
-}
diff --git a/tests/expectations/tests/template-fun-ty.rs b/tests/expectations/tests/template-fun-ty.rs
index b894920f..05351d7d 100644
--- a/tests/expectations/tests/template-fun-ty.rs
+++ b/tests/expectations/tests/template-fun-ty.rs
@@ -5,36 +5,22 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Foo<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Foo {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
pub type Foo_FunctionPtr<T> =
::std::option::Option<unsafe extern "C" fn() -> T>;
-impl <T> Default for Foo<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
-}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct RefPtr<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct RefPtr {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct RefPtr_Proxy<T, R, Args> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct RefPtr_Proxy {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
- pub _phantom_1: ::std::marker::PhantomData<R>,
- pub _phantom_2: ::std::marker::PhantomData<Args>,
}
pub type RefPtr_Proxy_member_function<R, Args> =
::std::option::Option<unsafe extern "C" fn(arg1: Args) -> R>;
-impl <T, R, Args> Default for RefPtr_Proxy<T, R, Args> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
-}
-impl <T> Default for RefPtr<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
-}
pub type Returner<T> = ::std::option::Option<unsafe extern "C" fn() -> T>;
diff --git a/tests/expectations/tests/template-param-usage-0.rs b/tests/expectations/tests/template-param-usage-0.rs
new file mode 100644
index 00000000..494001f7
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-0.rs
@@ -0,0 +1,14 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct UsesTemplateParameter<T> {
+ pub t: T,
+}
+impl <T> Default for UsesTemplateParameter<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template-param-usage-1.rs b/tests/expectations/tests/template-param-usage-1.rs
new file mode 100644
index 00000000..0fd8719b
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-1.rs
@@ -0,0 +1,11 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct DoesNotUseTemplateParameter {
+ pub x: ::std::os::raw::c_int,
+}
diff --git a/tests/expectations/tests/template-param-usage-10.rs b/tests/expectations/tests/template-param-usage-10.rs
new file mode 100644
index 00000000..95d200b5
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-10.rs
@@ -0,0 +1,25 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct DoublyIndirectUsage<T, U> {
+ pub doubly_indirect: DoublyIndirectUsage_IndirectUsage<T, U>,
+}
+pub type DoublyIndirectUsage_Aliased<T> = T;
+pub type DoublyIndirectUsage_Typedefed<U> = U;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct DoublyIndirectUsage_IndirectUsage<T, U> {
+ pub member: DoublyIndirectUsage_Aliased<T>,
+ pub another: DoublyIndirectUsage_Typedefed<U>,
+}
+impl <T, U> Default for DoublyIndirectUsage_IndirectUsage<T, U> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+impl <T, U> Default for DoublyIndirectUsage<T, U> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template-param-usage-11.rs b/tests/expectations/tests/template-param-usage-11.rs
new file mode 100644
index 00000000..a8959b99
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-11.rs
@@ -0,0 +1,11 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct DoesNotUseT {
+ pub _address: u8,
+}
diff --git a/tests/expectations/tests/template-param-usage-12.rs b/tests/expectations/tests/template-param-usage-12.rs
new file mode 100644
index 00000000..0c31111e
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-12.rs
@@ -0,0 +1,23 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct BaseUsesT<T> {
+ pub t: *mut T,
+}
+impl <T> Default for BaseUsesT<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct CrtpUsesU<U> {
+ pub _base: BaseUsesT<CrtpUsesU<U>>,
+ pub usage: U,
+}
+impl <U> Default for CrtpUsesU<U> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template-param-usage-13.rs b/tests/expectations/tests/template-param-usage-13.rs
new file mode 100644
index 00000000..c77da097
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-13.rs
@@ -0,0 +1,20 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct BaseIgnoresT {
+ pub x: ::std::os::raw::c_int,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct CrtpUsesU<U> {
+ pub _base: BaseIgnoresT,
+ pub usage: U,
+}
+impl <U> Default for CrtpUsesU<U> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template-param-usage-14.rs b/tests/expectations/tests/template-param-usage-14.rs
new file mode 100644
index 00000000..fae4afdc
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-14.rs
@@ -0,0 +1,20 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct BaseIgnoresT {
+ pub x: ::std::os::raw::c_int,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct CrtpIgnoresU {
+ pub _base: BaseIgnoresT,
+ pub y: ::std::os::raw::c_int,
+}
+impl Default for CrtpIgnoresU {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template-param-usage-15.rs b/tests/expectations/tests/template-param-usage-15.rs
new file mode 100644
index 00000000..a653e089
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-15.rs
@@ -0,0 +1,23 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct BaseUsesT<T> {
+ pub usage: *mut T,
+}
+impl <T> Default for BaseUsesT<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct CrtpIgnoresU {
+ pub _base: BaseUsesT<CrtpIgnoresU>,
+ pub y: ::std::os::raw::c_int,
+}
+impl Default for CrtpIgnoresU {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template-param-usage-2.rs b/tests/expectations/tests/template-param-usage-2.rs
new file mode 100644
index 00000000..6dc21b68
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-2.rs
@@ -0,0 +1,22 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct UsesTemplateParameter<T> {
+ pub t: T,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct UsesTemplateParameter_AlsoUsesTemplateParameter<T> {
+ pub also: T,
+}
+impl <T> Default for UsesTemplateParameter_AlsoUsesTemplateParameter<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+impl <T> Default for UsesTemplateParameter<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template-param-usage-3.rs b/tests/expectations/tests/template-param-usage-3.rs
new file mode 100644
index 00000000..a7ff22f9
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-3.rs
@@ -0,0 +1,24 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct UsesTemplateParameter<T> {
+ pub t: T,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct UsesTemplateParameter_AlsoUsesTemplateParameterAndMore<T, U> {
+ pub also: T,
+ pub more: U,
+}
+impl <T, U> Default for
+ UsesTemplateParameter_AlsoUsesTemplateParameterAndMore<T, U> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+impl <T> Default for UsesTemplateParameter<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template-param-usage-4.rs b/tests/expectations/tests/template-param-usage-4.rs
new file mode 100644
index 00000000..31f8872d
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-4.rs
@@ -0,0 +1,19 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct UsesTemplateParameter<T> {
+ pub t: T,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct UsesTemplateParameter_DoesNotUseTemplateParameters {
+ pub x: ::std::os::raw::c_int,
+}
+impl <T> Default for UsesTemplateParameter<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template-param-usage-5.rs b/tests/expectations/tests/template-param-usage-5.rs
new file mode 100644
index 00000000..5a9caf32
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-5.rs
@@ -0,0 +1,15 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct IndirectlyUsesTemplateParameter<T> {
+ pub aliased: IndirectlyUsesTemplateParameter_Aliased<T>,
+}
+pub type IndirectlyUsesTemplateParameter_Aliased<T> = T;
+impl <T> Default for IndirectlyUsesTemplateParameter<T> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template-param-usage-6.rs b/tests/expectations/tests/template-param-usage-6.rs
new file mode 100644
index 00000000..37b7fe64
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-6.rs
@@ -0,0 +1,12 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct DoesNotUseTemplateParameter {
+ pub x: ::std::os::raw::c_int,
+}
+pub type DoesNotUseTemplateParameter_ButAliasDoesUseIt<T> = T;
diff --git a/tests/expectations/tests/template-param-usage-7.rs b/tests/expectations/tests/template-param-usage-7.rs
new file mode 100644
index 00000000..b0584479
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-7.rs
@@ -0,0 +1,16 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct DoesNotUseU<T, V> {
+ pub t: T,
+ pub v: V,
+}
+impl <T, V> Default for DoesNotUseU<T, V> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
+pub type Alias = DoesNotUseU<::std::os::raw::c_int, ::std::os::raw::c_schar>;
diff --git a/tests/expectations/tests/template-param-usage-8.rs b/tests/expectations/tests/template-param-usage-8.rs
new file mode 100644
index 00000000..b181cc09
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-8.rs
@@ -0,0 +1,17 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct IndirectUsage<T, U> {
+ pub member1: IndirectUsage_Typedefed<T>,
+ pub member2: IndirectUsage_Aliased<U>,
+}
+pub type IndirectUsage_Typedefed<T> = T;
+pub type IndirectUsage_Aliased<U> = U;
+impl <T, U> Default for IndirectUsage<T, U> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template-param-usage-9.rs b/tests/expectations/tests/template-param-usage-9.rs
new file mode 100644
index 00000000..d0a3f29f
--- /dev/null
+++ b/tests/expectations/tests/template-param-usage-9.rs
@@ -0,0 +1,22 @@
+/* automatically generated by rust-bindgen */
+
+
+#![allow(non_snake_case)]
+
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct DoesNotUse {
+ pub _address: u8,
+}
+pub type DoesNotUse_Aliased<T> = T;
+pub type DoesNotUse_Typedefed<U> = U;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct DoesNotUse_IndirectUsage<T, U> {
+ pub member: DoesNotUse_Aliased<T>,
+ pub another: DoesNotUse_Typedefed<U>,
+}
+impl <T, U> Default for DoesNotUse_IndirectUsage<T, U> {
+ fn default() -> Self { unsafe { ::std::mem::zeroed() } }
+}
diff --git a/tests/expectations/tests/template.rs b/tests/expectations/tests/template.rs
index 3c829f07..911b0e6a 100644
--- a/tests/expectations/tests/template.rs
+++ b/tests/expectations/tests/template.rs
@@ -6,37 +6,34 @@
#[repr(C)]
#[derive(Debug)]
-pub struct Foo<T, U> {
+pub struct Foo<T> {
pub m_member: T,
pub m_member_ptr: *mut T,
pub m_member_arr: [T; 1usize],
- pub _phantom_1: ::std::marker::PhantomData<U>,
}
-impl <T, U> Default for Foo<T, U> {
+impl <T> Default for Foo<T> {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
extern "C" {
#[link_name = "_Z3bar3FooIiiE"]
- pub fn bar(foo: Foo<::std::os::raw::c_int, ::std::os::raw::c_int>);
+ pub fn bar(foo: Foo<::std::os::raw::c_int>);
}
#[repr(C)]
#[derive(Debug)]
-pub struct D<T> {
+pub struct D {
pub m_foo: D_MyFoo,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
-pub type D_MyFoo = Foo<::std::os::raw::c_int, ::std::os::raw::c_int>;
+pub type D_MyFoo = Foo<::std::os::raw::c_int>;
#[repr(C)]
#[derive(Debug)]
-pub struct D_U<T, Z> {
+pub struct D_U<Z> {
pub m_nested_foo: D_MyFoo,
pub m_baz: Z,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
-impl <T, Z> Default for D_U<T, Z> {
+impl <Z> Default for D_U<Z> {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
-impl <T> Default for D<T> {
+impl Default for D {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
@@ -104,10 +101,9 @@ impl Default for PODButContainsDtor {
/** <div rustbindgen opaque> */
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct Opaque<T> {
- pub _phantom_0: ::std::marker::PhantomData<T>,
+pub struct Opaque {
}
-impl <T> Default for Opaque<T> {
+impl Default for Opaque {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
@@ -143,11 +139,10 @@ impl <T> Default for NestedReplaced<T> {
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct NestedBase<T, U> {
+pub struct NestedBase<T> {
pub buff: *mut T,
- pub _phantom_1: ::std::marker::PhantomData<U>,
}
-impl <T, U> Default for NestedBase<T, U> {
+impl <T> Default for NestedBase<T> {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
@@ -184,13 +179,9 @@ impl Clone for Untemplated {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Templated<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Templated {
pub m_untemplated: Untemplated,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for Templated<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
/**
* If the replacement doesn't happen at the parse level the container would be
@@ -237,27 +228,23 @@ impl <T> Default for ReplacedWithoutDestructorFwd<T> {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct TemplateWithVar<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct TemplateWithVar {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for TemplateWithVar<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[test]
-fn __bindgen_test_layout_template_1() {
- assert_eq!(::std::mem::size_of::<Foo<::std::os::raw::c_int, ::std::os::raw::c_int>>()
- , 24usize , concat ! (
+fn __bindgen_test_layout_Foo_instantiation_95() {
+ assert_eq!(::std::mem::size_of::<Foo<::std::os::raw::c_int>>() , 24usize ,
+ concat ! (
"Size of template specialization: " , stringify ! (
- Foo<::std::os::raw::c_int, ::std::os::raw::c_int> ) ));
- assert_eq!(::std::mem::align_of::<Foo<::std::os::raw::c_int, ::std::os::raw::c_int>>()
- , 8usize , concat ! (
+ Foo<::std::os::raw::c_int> ) ));
+ assert_eq!(::std::mem::align_of::<Foo<::std::os::raw::c_int>>() , 8usize ,
+ concat ! (
"Alignment of template specialization: " , stringify ! (
- Foo<::std::os::raw::c_int, ::std::os::raw::c_int> ) ));
+ Foo<::std::os::raw::c_int> ) ));
}
#[test]
-fn __bindgen_test_layout_template_2() {
+fn __bindgen_test_layout_Rooted_instantiation_106() {
assert_eq!(::std::mem::size_of::<Rooted<*mut ::std::os::raw::c_void>>() ,
24usize , concat ! (
"Size of template specialization: " , stringify ! (
@@ -268,7 +255,7 @@ fn __bindgen_test_layout_template_2() {
Rooted<*mut ::std::os::raw::c_void> ) ));
}
#[test]
-fn __bindgen_test_layout_template_3() {
+fn __bindgen_test_layout_WithDtor_instantiation_114() {
assert_eq!(::std::mem::size_of::<WithDtor<::std::os::raw::c_int>>() ,
4usize , concat ! (
"Size of template specialization: " , stringify ! (
diff --git a/tests/expectations/tests/template_typedef_transitive_param.rs b/tests/expectations/tests/template_typedef_transitive_param.rs
index cc801f35..265ab5ce 100644
--- a/tests/expectations/tests/template_typedef_transitive_param.rs
+++ b/tests/expectations/tests/template_typedef_transitive_param.rs
@@ -5,10 +5,9 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Wrapper<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Wrapper {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
@@ -19,6 +18,3 @@ impl <T> Default for Wrapper_Wrapped<T> {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
pub type Wrapper_Type<T> = Wrapper_Wrapped<T>;
-impl <T> Default for Wrapper<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
-}
diff --git a/tests/expectations/tests/template_typedefs.rs b/tests/expectations/tests/template_typedefs.rs
index 9213c0d2..c987bf8e 100644
--- a/tests/expectations/tests/template_typedefs.rs
+++ b/tests/expectations/tests/template_typedefs.rs
@@ -7,11 +7,9 @@
pub type foo =
::std::option::Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct Foo<T, U> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Foo {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
- pub _phantom_1: ::std::marker::PhantomData<U>,
}
pub type Foo_Char<T> = T;
pub type Foo_FooPtrTypedef<T> = *mut Foo_Char<T>;
@@ -20,6 +18,3 @@ pub type Foo_nsCOMArrayEnumFunc<T> =
aData:
*mut ::std::os::raw::c_void)
-> bool>;
-impl <T, U> Default for Foo<T, U> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
-}
diff --git a/tests/expectations/tests/templateref_opaque.rs b/tests/expectations/tests/templateref_opaque.rs
index dfe941af..89808f30 100644
--- a/tests/expectations/tests/templateref_opaque.rs
+++ b/tests/expectations/tests/templateref_opaque.rs
@@ -5,22 +5,14 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct detail_PointerType<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct detail_PointerType {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
pub type detail_PointerType_Type<T> = *mut T;
-impl <T> Default for detail_PointerType<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
-}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct UniquePtr<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct UniquePtr {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-pub type UniquePtr_Pointer<T> = detail_PointerType<T>;
-impl <T> Default for UniquePtr<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
+pub type UniquePtr_Pointer = detail_PointerType;
diff --git a/tests/expectations/tests/typeref.rs b/tests/expectations/tests/typeref.rs
index 47b7a66a..c9982b67 100644
--- a/tests/expectations/tests/typeref.rs
+++ b/tests/expectations/tests/typeref.rs
@@ -31,7 +31,7 @@ impl <T> ::std::fmt::Debug for __BindgenUnionField<T> {
#[repr(C)]
#[derive(Debug, Copy)]
pub struct nsFoo {
- pub mBar: mozilla_StyleShapeSource<::std::os::raw::c_int>,
+ pub mBar: mozilla_StyleShapeSource,
}
#[test]
fn bindgen_test_layout_nsFoo() {
@@ -89,21 +89,16 @@ impl Clone for mozilla_Position {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct mozilla_StyleShapeSource<ReferenceBox> {
- pub __bindgen_anon_1: mozilla_StyleShapeSource__bindgen_ty_1<ReferenceBox>,
- pub _phantom_0: ::std::marker::PhantomData<ReferenceBox>,
+#[derive(Debug, Default, Copy, Clone)]
+pub struct mozilla_StyleShapeSource {
+ pub __bindgen_anon_1: mozilla_StyleShapeSource__bindgen_ty_1,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct mozilla_StyleShapeSource__bindgen_ty_1<ReferenceBox> {
+pub struct mozilla_StyleShapeSource__bindgen_ty_1 {
pub mPosition: __BindgenUnionField<*mut mozilla_Position>,
pub mFragmentOrURL: __BindgenUnionField<*mut mozilla_FragmentOrURL>,
pub bindgen_union_field: u64,
- pub _phantom_0: ::std::marker::PhantomData<ReferenceBox>,
-}
-impl <ReferenceBox> Default for mozilla_StyleShapeSource<ReferenceBox> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Copy)]
diff --git a/tests/expectations/tests/union_template.rs b/tests/expectations/tests/union_template.rs
index 2eba0f0a..e02f1964 100644
--- a/tests/expectations/tests/union_template.rs
+++ b/tests/expectations/tests/union_template.rs
@@ -29,37 +29,30 @@ impl <T> ::std::fmt::Debug for __BindgenUnionField<T> {
}
}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct NastyStruct<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct NastyStruct {
pub mIsSome: bool,
- pub mStorage: NastyStruct__bindgen_ty_1<T>,
- pub __bindgen_anon_1: NastyStruct__bindgen_ty_2<T>,
- pub _phantom_0: ::std::marker::PhantomData<T>,
+ pub mStorage: NastyStruct__bindgen_ty_1,
+ pub __bindgen_anon_1: NastyStruct__bindgen_ty_2,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct NastyStruct__bindgen_ty_1<T> {
+pub struct NastyStruct__bindgen_ty_1 {
pub mFoo: __BindgenUnionField<*mut ::std::os::raw::c_void>,
pub mDummy: __BindgenUnionField<::std::os::raw::c_ulong>,
pub bindgen_union_field: u64,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct NastyStruct__bindgen_ty_2<T> {
+pub struct NastyStruct__bindgen_ty_2 {
pub wat: __BindgenUnionField<::std::os::raw::c_short>,
pub wut: __BindgenUnionField<*mut ::std::os::raw::c_int>,
pub bindgen_union_field: u64,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for NastyStruct<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
-pub struct Whatever<T> {
+pub struct Whatever {
pub mTPtr: __BindgenUnionField<*mut ::std::os::raw::c_void>,
pub mInt: __BindgenUnionField<::std::os::raw::c_int>,
pub bindgen_union_field: u64,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
diff --git a/tests/expectations/tests/variadic_template_function.rs b/tests/expectations/tests/variadic_template_function.rs
index 32be9f68..66fd73ed 100644
--- a/tests/expectations/tests/variadic_template_function.rs
+++ b/tests/expectations/tests/variadic_template_function.rs
@@ -5,11 +5,7 @@
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
-pub struct VariadicFunctionObject<T> {
+#[derive(Debug, Default, Copy, Clone)]
+pub struct VariadicFunctionObject {
pub _address: u8,
- pub _phantom_0: ::std::marker::PhantomData<T>,
-}
-impl <T> Default for VariadicFunctionObject<T> {
- fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
diff --git a/tests/expectations/tests/what_is_going_on.rs b/tests/expectations/tests/what_is_going_on.rs
index 46af0139..e5194c02 100644
--- a/tests/expectations/tests/what_is_going_on.rs
+++ b/tests/expectations/tests/what_is_going_on.rs
@@ -22,12 +22,11 @@ impl Clone for UnknownUnits {
pub type Float = f32;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
-pub struct PointTyped<units, F> {
+pub struct PointTyped<F> {
pub x: F,
pub y: F,
- pub _phantom_0: ::std::marker::PhantomData<units>,
}
-impl <units, F> Default for PointTyped<units, F> {
+impl <F> Default for PointTyped<F> {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
-pub type IntPoint = PointTyped<UnknownUnits, f32>;
+pub type IntPoint = PointTyped<f32>;
diff --git a/tests/expectations/tests/whitelist_basic.rs b/tests/expectations/tests/whitelist_basic.rs
index d67fb7a3..8af4aba3 100644
--- a/tests/expectations/tests/whitelist_basic.rs
+++ b/tests/expectations/tests/whitelist_basic.rs
@@ -9,7 +9,6 @@
pub struct WhitelistMe<T> {
pub foo: ::std::os::raw::c_int,
pub bar: WhitelistMe_Inner<T>,
- pub _phantom_0: ::std::marker::PhantomData<T>,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
diff --git a/tests/headers/issue-544-stylo-creduce-2.hpp b/tests/headers/issue-544-stylo-creduce-2.hpp
new file mode 100644
index 00000000..f3467f45
--- /dev/null
+++ b/tests/headers/issue-544-stylo-creduce-2.hpp
@@ -0,0 +1,8 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+struct Foo {
+ template <typename> using FirstAlias = typename T::Associated;
+ template <typename U> using SecondAlias = Foo<FirstAlias<U>>;
+ SecondAlias<int> member;
+};
diff --git a/tests/headers/issue-544-stylo-creduce.hpp b/tests/headers/issue-544-stylo-creduce.hpp
new file mode 100644
index 00000000..ba9f8257
--- /dev/null
+++ b/tests/headers/issue-544-stylo-creduce.hpp
@@ -0,0 +1,5 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename> class a;
+template <typename b, typename... c> class a<b(c...)> { a(const a &); };
+template <typename b, typename... c> a<b(c...)>::a(const a &) {}
diff --git a/tests/headers/partial-specialization-and-inheritance.hpp b/tests/headers/partial-specialization-and-inheritance.hpp
new file mode 100644
index 00000000..4eb8f545
--- /dev/null
+++ b/tests/headers/partial-specialization-and-inheritance.hpp
@@ -0,0 +1,40 @@
+// bindgen-unstable
+
+// This was originally a test case generated by creducing errors in SpiderMonkey
+// bindings generation. I've tried to make it understandable by giving more
+// meaningful names to everything, and a couple comments.
+//
+// We don't support partial template specialization, but we *should*
+// successfully parse this header, and generate bindings for it, but the usage
+// of the partial template specialization should result in opaque blobs.
+
+// A base class providing a method.
+template <typename T>
+class Base {
+public:
+ void some_method(T, T);
+};
+
+// A template with a default representation.
+template <typename U>
+class Derived {
+ bool b;
+};
+
+// A partial specialization for pointers. Note that this should have a different
+// and larger layout than the template it is specializing.
+template <typename U>
+class Derived<U*> : public Base<U*> {
+ int x;
+ int y;
+};
+
+// A struct that uses the partial specialization and method from the partial
+// specialization's base class.
+struct Usage {
+ Usage() {
+ static_member.some_method(this, this);
+ }
+
+ static Derived<Usage*> static_member;
+};
diff --git a/tests/headers/template-param-usage-0.hpp b/tests/headers/template-param-usage-0.hpp
new file mode 100644
index 00000000..57c11a10
--- /dev/null
+++ b/tests/headers/template-param-usage-0.hpp
@@ -0,0 +1,6 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class UsesTemplateParameter {
+ T t;
+};
diff --git a/tests/headers/template-param-usage-1.hpp b/tests/headers/template-param-usage-1.hpp
new file mode 100644
index 00000000..dba41489
--- /dev/null
+++ b/tests/headers/template-param-usage-1.hpp
@@ -0,0 +1,6 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class DoesNotUseTemplateParameter {
+ int x;
+};
diff --git a/tests/headers/template-param-usage-10.hpp b/tests/headers/template-param-usage-10.hpp
new file mode 100644
index 00000000..a6f3ccd8
--- /dev/null
+++ b/tests/headers/template-param-usage-10.hpp
@@ -0,0 +1,14 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T, typename U, typename NeverUsed>
+class DoublyIndirectUsage {
+ using Aliased = T;
+ typedef U Typedefed;
+
+ class IndirectUsage {
+ Aliased member;
+ Typedefed another;
+ };
+
+ IndirectUsage doubly_indirect;
+};
diff --git a/tests/headers/template-param-usage-11.hpp b/tests/headers/template-param-usage-11.hpp
new file mode 100644
index 00000000..8780f5d3
--- /dev/null
+++ b/tests/headers/template-param-usage-11.hpp
@@ -0,0 +1,6 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class DoesNotUseT {
+ static T but_static_member_does;
+};
diff --git a/tests/headers/template-param-usage-12.hpp b/tests/headers/template-param-usage-12.hpp
new file mode 100644
index 00000000..9b4cea19
--- /dev/null
+++ b/tests/headers/template-param-usage-12.hpp
@@ -0,0 +1,11 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class BaseUsesT {
+ T* t;
+};
+
+template <typename U>
+class CrtpUsesU : public BaseUsesT<CrtpUsesU<U>> {
+ U usage;
+};
diff --git a/tests/headers/template-param-usage-13.hpp b/tests/headers/template-param-usage-13.hpp
new file mode 100644
index 00000000..87db1a10
--- /dev/null
+++ b/tests/headers/template-param-usage-13.hpp
@@ -0,0 +1,11 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class BaseIgnoresT {
+ int x;
+};
+
+template <typename U>
+class CrtpUsesU : public BaseIgnoresT<CrtpUsesU<U>> {
+ U usage;
+};
diff --git a/tests/headers/template-param-usage-14.hpp b/tests/headers/template-param-usage-14.hpp
new file mode 100644
index 00000000..19016296
--- /dev/null
+++ b/tests/headers/template-param-usage-14.hpp
@@ -0,0 +1,11 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class BaseIgnoresT {
+ int x;
+};
+
+template <typename U>
+class CrtpIgnoresU : public BaseIgnoresT<CrtpIgnoresU<U>> {
+ int y;
+};
diff --git a/tests/headers/template-param-usage-15.hpp b/tests/headers/template-param-usage-15.hpp
new file mode 100644
index 00000000..bac7ada7
--- /dev/null
+++ b/tests/headers/template-param-usage-15.hpp
@@ -0,0 +1,11 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class BaseUsesT {
+ T* usage;
+};
+
+template <typename U>
+class CrtpIgnoresU : public BaseUsesT<CrtpIgnoresU<U>> {
+ int y;
+};
diff --git a/tests/headers/template-param-usage-2.hpp b/tests/headers/template-param-usage-2.hpp
new file mode 100644
index 00000000..302140ab
--- /dev/null
+++ b/tests/headers/template-param-usage-2.hpp
@@ -0,0 +1,10 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class UsesTemplateParameter {
+ T t;
+
+ class AlsoUsesTemplateParameter {
+ T also;
+ };
+};
diff --git a/tests/headers/template-param-usage-3.hpp b/tests/headers/template-param-usage-3.hpp
new file mode 100644
index 00000000..57396a8a
--- /dev/null
+++ b/tests/headers/template-param-usage-3.hpp
@@ -0,0 +1,12 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class UsesTemplateParameter {
+ T t;
+
+ template <typename U>
+ class AlsoUsesTemplateParameterAndMore {
+ T also;
+ U more;
+ };
+};
diff --git a/tests/headers/template-param-usage-4.hpp b/tests/headers/template-param-usage-4.hpp
new file mode 100644
index 00000000..0415d692
--- /dev/null
+++ b/tests/headers/template-param-usage-4.hpp
@@ -0,0 +1,11 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class UsesTemplateParameter {
+ T t;
+
+ template <typename U>
+ class DoesNotUseTemplateParameters {
+ int x;
+ };
+};
diff --git a/tests/headers/template-param-usage-5.hpp b/tests/headers/template-param-usage-5.hpp
new file mode 100644
index 00000000..04b9bf80
--- /dev/null
+++ b/tests/headers/template-param-usage-5.hpp
@@ -0,0 +1,8 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class IndirectlyUsesTemplateParameter {
+ using Aliased = T;
+
+ Aliased aliased;
+};
diff --git a/tests/headers/template-param-usage-6.hpp b/tests/headers/template-param-usage-6.hpp
new file mode 100644
index 00000000..ee0519c5
--- /dev/null
+++ b/tests/headers/template-param-usage-6.hpp
@@ -0,0 +1,8 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T>
+class DoesNotUseTemplateParameter {
+ using ButAliasDoesUseIt = T;
+
+ int x;
+};
diff --git a/tests/headers/template-param-usage-7.hpp b/tests/headers/template-param-usage-7.hpp
new file mode 100644
index 00000000..99d4cc71
--- /dev/null
+++ b/tests/headers/template-param-usage-7.hpp
@@ -0,0 +1,10 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T, typename U, typename V>
+class DoesNotUseU {
+ T t;
+ V v;
+};
+
+// The bool should go away becuase U is not used.
+using Alias = DoesNotUseU<int, bool, char>;
diff --git a/tests/headers/template-param-usage-8.hpp b/tests/headers/template-param-usage-8.hpp
new file mode 100644
index 00000000..96eabc06
--- /dev/null
+++ b/tests/headers/template-param-usage-8.hpp
@@ -0,0 +1,10 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T, typename U>
+class IndirectUsage {
+ typedef T Typedefed;
+ using Aliased = U;
+
+ Typedefed member1;
+ Aliased member2;
+};
diff --git a/tests/headers/template-param-usage-9.hpp b/tests/headers/template-param-usage-9.hpp
new file mode 100644
index 00000000..b9bd202c
--- /dev/null
+++ b/tests/headers/template-param-usage-9.hpp
@@ -0,0 +1,12 @@
+// bindgen-flags: -- -std=c++14
+
+template <typename T, typename U>
+class DoesNotUse {
+ using Aliased = T;
+ typedef U Typedefed;
+
+ class IndirectUsage {
+ Aliased member;
+ Typedefed another;
+ };
+};