summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Fitzgerald <fitzgen@gmail.com>2017-02-15 14:43:38 -0800
committerNick Fitzgerald <fitzgen@gmail.com>2017-03-07 11:04:00 -0800
commit1c4332a1aa3dd299c133f72efb8b28dd5c8aa9d4 (patch)
treee476309d4730ba1a611acc6db59ab880ab3d8d00
parent17275f87004044d8702a80467880f568738357c2 (diff)
Completely rework templates
* Find each item's used template parameters when we begin the codegen phase * Add TemplateDeclaration::used_template_params() This method is available during the codegen phase, and uses the information gleaned by the `ir::named::UsedTemplateParameters` analysis. * Remove Item::{applicable_template_args,signature_contains_named_type} They are replaced by the template parameter usage analysis and TemplateDeclaration::used_template_params. * Parse and de-duplicate named template type parameters * Do not attempt to determine template parameter usage when not recursively whitelisting * Add a proper TemplateInstantiation type This makes it so that CompInfo is always either a compound type definition, or a template compound type definition, never an instantiation of a template. It also pulls out TypeKind::TemplateInstantiation(<inline stuff>) to a proper ir::TemplateInstantiation type, and TypeKind::TemplateInstantiation just wraps ir::TemplateInstantiation into TypeKind. * Allow template definitions to lack template parameters because of opaque template definitions * Detect and ignore cycles deriving Copy/Debug and whether a type has a vtable * Bail out early in the face of partial template specialization We don't support it, and shouldn't continue trying to parse a type from this cursor. * Do not consider inner type's parameter usage as our own parameter usage * Do not require a parent_id for template instantiations It is not necessary, and in fact was preventing us from creating template instantiations in some places, resulting in such nonsense as a generic template definition as a base for another type. * Only join if this is NOT a named template type or a template instantiation Otherwise, we'll always consider all of a template instantiation's arguments as used, when they should only be considered used if the template definition uses that template parameter. * Consider function return and parameter types as used Although we should not follow class method edges because we cannot create new monomorphizations of methods, code can create aliases of function pointers whose return or parameter types are template parameters, and those template parameters should be considered used. * Add the AsNamed trait for things which might be a named template type This sees through ResolvedTypeReferences to get at the final named type and its canonical item id. By using this in the named template parameter usage analysis, we ensure we don't have bugs where there are ResolvedTypeReferences in the usage sets rather than the canonical named item id, which could cause template parameters to be ignored accidentally. * Do not consider an inner var's template parameter usage as our own * Make the expectations' tests less noisy * Use opaque blobs for unknown template definition types When we don't know how to generate a Rust type from a template definition (eg because it uses non-type template parameters), then we should fall back to using the instantiation's layout to generate the opaque blob. * Implement CanDeriveDebug for TemplateInstantiation We need the template instantiation's layout to determine if we can derive debug for it when the instantiation's template definition has non-type parameters. * Stop thrashing malloc when unioning ItemSets in UsedTemplateParameters Previously, we were cloning an ItemSet, which requires a malloc for non-empty sets, when taking its union with our current id's set. Now, instead of doing that, we wrap each ItemSet in an Option, and take the set out of the hash map when modifying it. This allows us to side-step the borrow checker and HashMap's lack of an analog to `slice::split_at_mut` and mutate what is logically a value in the hash map while also using immutable references of values that are physically in the hash map. * Add some tests explicitly about template parameter usage * Updated test expectations now that we are inferring template parameter usage * Reinstate the layout tests for template instantiations * Generate opaque blobs for uses of partially specialized templates This adds `TypeKind::Opaque` which signifies that we do not understand anything about the given type and that we should just generate an opaque blob based on the type's layout. It explicitly uses the opaque type kind for partially specialized templates. * Add note about None vs Some([]) in TemplateDeclaration * Do not rely on TypeKind implementing PartialEq * Prefer assert_eq!(lhs, rhs) to assert!(lhs == rhs) * Expand some comments for ir::named::UsedTemplateParameters * Expand Item::is_opaque to consider TypeKind::Opaque * Use opaque types instead of panicking Use opaque types as our last resort when resolving type references after we have collected unresolved type references instead of panicking. * Find template definitions that don't want to be found * Recognize associated template types and make them opaque
-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;
+ };
+};