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
This commit is contained in:
Nick Fitzgerald 2017-02-15 14:43:38 -08:00
parent 17275f8700
commit 1c4332a1aa
98 changed files with 2448 additions and 1631 deletions

View File

@ -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

View File

@ -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,33 +1300,15 @@ 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 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)
}
}
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());
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);
generics = generics.ty_param_id(ident);
}
}
let generics = generics.build();
@ -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()

View File

@ -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?

View File

@ -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() {

View File

@ -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

View File

@ -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;

View File

@ -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 {

View File

@ -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,
}
}

View File

@ -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)
});
if valid_decl {
let partial_ty =
PartialType::new(declaration_to_look_for, id);
ctx.begin_parsing(partial_ty);
}
// 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)
});
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();
ctx.add_item(Item::new(id,
None,
None,
parent_id,
ItemKind::Type(Type::named(name))),
None,
None);
debug!("Item::named_type:\n\
\twith_id = {:?},\n\
\tty = {} {:?},\n\
\tlocation: {:?}",
with_id,
ty.spelling(),
ty,
location);
id
}
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;
}
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 ty_spelling = ty.spelling();
// 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
}
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)
}
}

View File

@ -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),

View File

@ -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> {

View File

@ -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;

View File

@ -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)
}
}

View File

@ -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);
}
}
}
}
_ => {}
// 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);
},
&());
}
}
// 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;
}
// 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);

193
src/ir/template.rs Normal file
View File

@ -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);
}
}
}

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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(),

View File

@ -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,

View File

@ -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
}

3
tests/expectations/lib.rs Normal file → Executable file
View File

@ -0,0 +1,3 @@
#![allow(dead_code)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]

View File

@ -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;

View File

@ -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 {

View File

@ -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 ) ));
}

View File

@ -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"]

View File

@ -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)]

View File

@ -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 ! (

View File

@ -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 ! (

View File

@ -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> {
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 {
pub _address: u8,
pub _phantom_0: ::std::marker::PhantomData<T>,
}
impl <T> Default for Outer<T> {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Outer_Inner {
pub _address: u8,
}

View File

@ -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)]

View File

@ -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 ) ));
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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)]

View File

@ -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() {

View File

@ -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)]

View File

@ -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() } }
}

View File

@ -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> {
impl Default for basic_string___rep__bindgen_ty_1 {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
impl <_CharT, _Traits, _Allocator> Default for
basic_string___rep<_CharT, _Traits, _Allocator> {
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() } }
}

View File

@ -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() } }
}

View File

@ -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 }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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,
}

View File

@ -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;

View File

@ -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 }
}

View File

@ -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() {

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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, Default, Copy, Clone)]
pub struct RefPtr {
pub _address: u8,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct RefPtr<T> {
#[derive(Debug, Default, Copy, Clone)]
pub struct RefPtr_Proxy {
pub _address: u8,
pub _phantom_0: ::std::marker::PhantomData<T>,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct RefPtr_Proxy<T, R, Args> {
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>;

View File

@ -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() } }
}

View File

@ -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,
}

View File

@ -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() } }
}

View File

@ -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,
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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;

View File

@ -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>;

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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 ! (

View File

@ -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() } }
}

View File

@ -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() } }
}

View File

@ -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;

View File

@ -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)]

View File

@ -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>,
}

View File

@ -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() } }
}

View File

@ -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>;

View File

@ -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)]

View File

@ -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;
};

View File

@ -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 &) {}

View File

@ -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;
};

View File

@ -0,0 +1,6 @@
// bindgen-flags: -- -std=c++14
template <typename T>
class UsesTemplateParameter {
T t;
};

View File

@ -0,0 +1,6 @@
// bindgen-flags: -- -std=c++14
template <typename T>
class DoesNotUseTemplateParameter {
int x;
};

View File

@ -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;
};

View File

@ -0,0 +1,6 @@
// bindgen-flags: -- -std=c++14
template <typename T>
class DoesNotUseT {
static T but_static_member_does;
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -0,0 +1,10 @@
// bindgen-flags: -- -std=c++14
template <typename T>
class UsesTemplateParameter {
T t;
class AlsoUsesTemplateParameter {
T also;
};
};

View File

@ -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;
};
};

View File

@ -0,0 +1,11 @@
// bindgen-flags: -- -std=c++14
template <typename T>
class UsesTemplateParameter {
T t;
template <typename U>
class DoesNotUseTemplateParameters {
int x;
};
};

View File

@ -0,0 +1,8 @@
// bindgen-flags: -- -std=c++14
template <typename T>
class IndirectlyUsesTemplateParameter {
using Aliased = T;
Aliased aliased;
};

View File

@ -0,0 +1,8 @@
// bindgen-flags: -- -std=c++14
template <typename T>
class DoesNotUseTemplateParameter {
using ButAliasDoesUseIt = T;
int x;
};

View File

@ -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>;

View File

@ -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;
};

View File

@ -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;
};
};