diff --git a/src/clang.rs b/src/clang.rs index 5e2ab3af88..b8086d9943 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -6,6 +6,7 @@ use cexpr; use clang_sys::*; +use regex; use std::{mem, ptr, slice}; use std::ffi::{CStr, CString}; use std::fmt; @@ -126,11 +127,11 @@ impl Cursor { } /// Return the number of template arguments used by this cursor's referent, - /// if the referent is either a template specialization or declaration. - /// Returns `None` otherwise. + /// if the referent is either a template instantiation. Returns `None` + /// otherwise. /// - /// NOTE: This may not return `Some` for some non-fully specialized - /// templates, see #193 and #194. + /// NOTE: This may not return `Some` for partial template specializations, + /// see #193 and #194. pub fn num_template_args(&self) -> Option { // 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 { 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 . 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 + /// class Foo { + /// typename T::Associated member; + /// }; + /// ``` + pub fn is_associated_type(&self) -> bool { + // This is terrible :( + fn hacky_parse_associated_type>(spelling: S) -> bool { + lazy_static! { + static ref ASSOC_TYPE_RE: regex::Regex = + regex::Regex::new(r"typename type\-parameter\-\d+\-\d+::.+").unwrap(); + } + ASSOC_TYPE_RE.is_match(spelling.as_ref()) + } + + self.kind() == CXType_Unexposed && + (hacky_parse_associated_type(self.spelling()) || + hacky_parse_associated_type(self.canonical_type().spelling())) + } } /// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 77941fa34f..7bc8985b04 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -2,8 +2,8 @@ mod helpers; mod struct_layout; use self::helpers::{BlobTyBuilder, attributes}; +use self::struct_layout::{StructLayoutTracker, bytes_from_bits_pow2}; use self::struct_layout::{align_to, bytes_from_bits}; -use self::struct_layout::{bytes_from_bits_pow2, StructLayoutTracker}; use aster; use ir::annotations::FieldAccessorKind; @@ -20,7 +20,8 @@ use ir::item_kind::ItemKind; use ir::layout::Layout; use ir::module::Module; use ir::objc::ObjCInterface; -use ir::ty::{Type, TypeKind}; +use ir::template::{AsNamed, TemplateInstantiation}; +use ir::ty::{TemplateDeclaration, Type, TypeKind}; use ir::var::Var; use std::borrow::Cow; @@ -137,11 +138,6 @@ impl<'a> CodegenResult<'a> { } } - fn next_id(&mut self) -> usize { - self.codegen_id.set(self.codegen_id.get() + 1); - self.codegen_id.get() - } - fn saw_union(&mut self) { self.saw_union = true; } @@ -522,19 +518,20 @@ impl CodeGenerator for Type { TypeKind::Pointer(..) | TypeKind::BlockPointer | TypeKind::Reference(..) | - TypeKind::TemplateInstantiation(..) | TypeKind::Function(..) | TypeKind::ResolvedTypeRef(..) | + TypeKind::Opaque | TypeKind::Named => { // These items don't need code generation, they only need to be // converted to rust types in fields, arguments, and such. return; } + TypeKind::TemplateInstantiation(ref inst) => { + inst.codegen(ctx, result, whitelisted_items, item) + } TypeKind::Comp(ref ci) => { ci.codegen(ctx, result, whitelisted_items, item) } - // NB: The code below will pick the correct - // applicable_template_args. TypeKind::TemplateAlias(inner, _) | TypeKind::Alias(inner) => { let inner_item = ctx.resolve_item(inner); @@ -557,10 +554,9 @@ impl CodeGenerator for Type { return; } - let mut applicable_template_args = - item.applicable_template_args(ctx); + let mut used_template_params = item.used_template_params(ctx); let inner_rust_type = if item.is_opaque(ctx) { - applicable_template_args.clear(); + used_template_params = None; // Pray if there's no layout. let layout = self.layout(ctx).unwrap_or_else(Layout::zero); BlobTyBuilder::new(layout).build() @@ -603,7 +599,7 @@ impl CodeGenerator for Type { // https://github.com/rust-lang/rust/issues/26264 let simple_enum_path = match inner_rust_type.node { ast::TyKind::Path(None, ref p) => { - if applicable_template_args.is_empty() && + if used_template_params.is_none() && inner_item.expect_type() .canonical_type(ctx) .is_enum() && @@ -627,17 +623,21 @@ impl CodeGenerator for Type { typedef.use_().build(p).as_(rust_name) } else { let mut generics = typedef.type_(rust_name).generics(); - for template_arg in applicable_template_args.iter() { - let template_arg = ctx.resolve_type(*template_arg); - if template_arg.is_named() { - if template_arg.is_invalid_named_type() { - warn!("Item contained invalid template \ - parameter: {:?}", - item); - return; + if let Some(ref params) = used_template_params { + for template_param in params { + if let Some(id) = + template_param.as_named(ctx, &()) { + let template_param = ctx.resolve_type(id); + if template_param.is_invalid_named_type() { + warn!("Item contained invalid template \ + parameter: {:?}", + item); + return; + } + generics = + generics.ty_param_id(template_param.name() + .unwrap()); } - generics = - generics.ty_param_id(template_arg.name().unwrap()); } } generics.build().build_ty(inner_rust_type) @@ -768,7 +768,7 @@ impl<'a> Bitfield<'a> { let field_align = field_ty_layout.align; if field_size_in_bits != 0 && - (width == 0 || width as usize > unfilled_bits_in_last_unit) { + (width == 0 || width as usize > unfilled_bits_in_last_unit) { field_size_in_bits = align_to(field_size_in_bits, field_align); // Push the new field. let ty = @@ -829,6 +829,53 @@ impl<'a> Bitfield<'a> { } } +impl CodeGenerator for TemplateInstantiation { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + // Although uses of instantiations don't need code generation, and are + // just converted to rust types in fields, vars, etc, we take this + // opportunity to generate tests for their layout here. + + let layout = item.kind().expect_type().layout(ctx); + + if let Some(layout) = layout { + let size = layout.size; + let align = layout.align; + + let name = item.canonical_name(ctx); + let fn_name = format!("__bindgen_test_layout_{}_instantiation_{}", + name, + item.id().as_usize()); + let fn_name = ctx.rust_ident_raw(&fn_name); + + let prefix = ctx.trait_prefix(); + let ident = item.to_rust_ty(ctx); + let size_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::size_of::<$ident>()); + let align_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::align_of::<$ident>()); + + let item = quote_item!( + ctx.ext_cx(), + #[test] + fn $fn_name() { + assert_eq!($size_of_expr, $size, + concat!("Size of template specialization: ", stringify!($ident))); + assert_eq!($align_of_expr, $align, + concat!("Alignment of template specialization: ", stringify!($ident))); + }) + .unwrap(); + + result.push(item); + } + } +} + impl CodeGenerator for CompInfo { type Extra = Item; @@ -847,12 +894,11 @@ impl CodeGenerator for CompInfo { return; } - let applicable_template_args = item.applicable_template_args(ctx); + let used_template_params = item.used_template_params(ctx); // generate tuple struct if struct or union is a forward declaration, // skip for now if template parameters are needed. - if self.is_forward_declaration() && - applicable_template_args.is_empty() { + if self.is_forward_declaration() && used_template_params.is_none() { let struct_name = item.canonical_name(ctx); let struct_name = ctx.rust_ident_raw(&struct_name); let tuple_struct = quote_item!(ctx.ext_cx(), @@ -865,35 +911,6 @@ impl CodeGenerator for CompInfo { return; } - if self.is_template_specialization() { - let layout = item.kind().expect_type().layout(ctx); - - if let Some(layout) = layout { - let fn_name = format!("__bindgen_test_layout_template_{}", - result.next_id()); - let fn_name = ctx.rust_ident_raw(&fn_name); - let ident = item.to_rust_ty(ctx); - let prefix = ctx.trait_prefix(); - let size_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::size_of::<$ident>()); - let align_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::align_of::<$ident>()); - let size = layout.size; - let align = layout.align; - let item = quote_item!(ctx.ext_cx(), - #[test] - fn $fn_name() { - assert_eq!($size_of_expr, $size, - concat!("Size of template specialization: ", stringify!($ident))); - assert_eq!($align_of_expr, $align, - concat!("Alignment of template specialization: ", stringify!($ident))); - }) - .unwrap(); - result.push(item); - } - return; - } - let mut attributes = vec![]; let mut needs_clone_impl = false; let mut needs_default_impl = false; @@ -923,7 +940,7 @@ impl CodeGenerator for CompInfo { if item.can_derive_copy(ctx, ()) && !item.annotations().disallow_copy() { derives.push("Copy"); - if !applicable_template_args.is_empty() { + if used_template_params.is_some() { // FIXME: This requires extra logic if you have a big array in a // templated struct. The reason for this is that the magic: // fn clone(&self) -> Self { *self } @@ -940,8 +957,6 @@ impl CodeGenerator for CompInfo { attributes.push(attributes::derives(&derives)) } - let mut template_args_used = - vec![false; applicable_template_args.len()]; let canonical_name = item.canonical_name(ctx); let builder = if is_union && ctx.options().unstable_rust { aster::AstBuilder::new() @@ -1004,13 +1019,6 @@ impl CodeGenerator for CompInfo { continue; } - for (i, ty_id) in applicable_template_args.iter().enumerate() { - let template_arg_ty = ctx.resolve_type(*ty_id); - if base_ty.signature_contains_named_type(ctx, template_arg_ty) { - template_args_used[i] = true; - } - } - let inner = base.ty.to_rust_ty(ctx); let field_name = if i == 0 { "_base".into() @@ -1092,13 +1100,6 @@ impl CodeGenerator for CompInfo { continue; } - for (i, ty_id) in applicable_template_args.iter().enumerate() { - let template_arg = ctx.resolve_type(*ty_id); - if field_ty.signature_contains_named_type(ctx, template_arg) { - template_args_used[i] = true; - } - } - let ty = field.ty().to_rust_ty(ctx); // NB: In unstable rust we use proper `union` types. @@ -1108,7 +1109,8 @@ impl CodeGenerator for CompInfo { } else { quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>) } - } else if let Some(item) = field_ty.is_incomplete_array(ctx) { + } else if let Some(item) = + field_ty.is_incomplete_array(ctx) { result.saw_incomplete_array(); let inner = item.to_rust_ty(ctx); @@ -1257,9 +1259,6 @@ impl CodeGenerator for CompInfo { if item.is_opaque(ctx) { fields.clear(); methods.clear(); - for i in 0..template_args_used.len() { - template_args_used[i] = false; - } match layout { Some(l) => { @@ -1276,7 +1275,9 @@ impl CodeGenerator for CompInfo { } } else if !is_union && !self.is_unsized(ctx) { if let Some(padding_field) = - layout.and_then(|layout| struct_layout.pad_struct(&canonical_name, layout)) { + layout.and_then(|layout| { + struct_layout.pad_struct(&canonical_name, layout) + }) { fields.push(padding_field); } @@ -1299,35 +1300,17 @@ impl CodeGenerator for CompInfo { fields.push(field); } - // Append any extra template arguments that nobody has used so far. - for (i, ty) in applicable_template_args.iter().enumerate() { - if !template_args_used[i] { - let name = ctx.resolve_type(*ty).name().unwrap(); + let mut generics = aster::AstBuilder::new().generics(); + + if let Some(ref params) = used_template_params { + for ty in params.iter() { + let param = ctx.resolve_type(*ty); + let name = param.name().unwrap(); let ident = ctx.rust_ident(name); - let prefix = ctx.trait_prefix(); - let phantom = quote_ty!(ctx.ext_cx(), - ::$prefix::marker::PhantomData<$ident>); - let field = StructFieldBuilder::named(format!("_phantom_{}", - i)) - .pub_() - .build_ty(phantom); - fields.push(field) + generics = generics.ty_param_id(ident); } } - - let mut generics = aster::AstBuilder::new().generics(); - for template_arg in applicable_template_args.iter() { - // Take into account that here only arrive named types, not - // template specialisations that would need to be - // instantiated. - // - // TODO: Add template args from the parent, here and in - // `to_rust_ty`!! - let template_arg = ctx.resolve_type(*template_arg); - generics = generics.ty_param_id(template_arg.name().unwrap()); - } - let generics = generics.build(); let rust_struct = builder.with_generics(generics.clone()) @@ -1353,7 +1336,7 @@ impl CodeGenerator for CompInfo { canonical_name); } - if applicable_template_args.is_empty() { + if used_template_params.is_none() { for var in self.inner_vars() { ctx.resolve_item(*var) .codegen(ctx, result, whitelisted_items, &()); @@ -2193,16 +2176,54 @@ impl ToRustTy for Type { let path = item.namespace_aware_canonical_path(ctx); aster::AstBuilder::new().ty().path().ids(path).build() } - TypeKind::TemplateInstantiation(inner, ref template_args) => { - // PS: Sorry for the duplication here. - let mut inner_ty = inner.to_rust_ty(ctx).unwrap(); + TypeKind::TemplateInstantiation(ref inst) => { + let decl = inst.template_definition(); + let mut ty = decl.to_rust_ty(ctx).unwrap(); - if let ast::TyKind::Path(_, ref mut path) = inner_ty.node { - let template_args = template_args.iter() - .map(|arg| arg.to_rust_ty(ctx)) + // If we gave up when making a type for the template definition, + // check if maybe we can make a better opaque blob for the + // instantiation. + if ty == aster::AstBuilder::new().ty().unit().unwrap() { + if let Some(layout) = self.layout(ctx) { + ty = BlobTyBuilder::new(layout).build().unwrap() + } + } + + let decl_params = if let Some(params) = + decl.self_template_params(ctx) { + params + } else { + // This can happen if we generated an opaque type for a + // partial template specialization, in which case we just + // use the opaque type's layout. If we don't have a layout, + // we cross our fingers and hope for the best :-/ + debug_assert!(ctx.resolve_type_through_type_refs(decl) + .is_opaque()); + let layout = self.layout(ctx).unwrap_or(Layout::zero()); + ty = BlobTyBuilder::new(layout).build().unwrap(); + + vec![] + }; + + // TODO: If the decl type is a template class/struct + // declaration's member template declaration, it could rely on + // generic template parameters from its outer template + // class/struct. When we emit bindings for it, it could require + // *more* type arguments than we have here, and we will need to + // reconstruct them somehow. We don't have any means of doing + // that reconstruction at this time. + + if let ast::TyKind::Path(_, ref mut path) = ty.node { + let template_args = inst.template_arguments() + .iter() + .zip(decl_params.iter()) + // Only pass type arguments for the type parameters that + // the decl uses. + .filter(|&(_, param)| ctx.uses_template_parameter(decl, *param)) + .map(|(arg, _)| arg.to_rust_ty(ctx)) .collect::>(); - 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::>(); 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) + template_params: Vec) -> P { 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::>(); // XXX: I suck at aster. if path.len() == 1 { return builder.segment(&path[0]) - .with_tys(template_args) + .with_tys(template_params) .build() .build(); } @@ -2765,7 +2791,7 @@ mod utils { builder = if i == path.len() - 2 { // XXX Extra clone courtesy of the borrow checker. builder.segment(&segment) - .with_tys(template_args.clone()) + .with_tys(template_params.clone()) .build() } else { builder.segment(&segment).build() diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs index 724bef98fa..351f76428e 100644 --- a/src/codegen/struct_layout.rs +++ b/src/codegen/struct_layout.rs @@ -167,17 +167,20 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> { None => return None, }; - if let TypeKind::Array(inner, len) = *field_ty.canonical_type(self.ctx).kind() { + if let TypeKind::Array(inner, len) = + *field_ty.canonical_type(self.ctx).kind() { // FIXME(emilio): As an _ultra_ hack, we correct the layout returned // by arrays of structs that have a bigger alignment than what we // can support. // // This means that the structs in the array are super-unsafe to // access, since they won't be properly aligned, but *shrug*. - if let Some(layout) = self.ctx.resolve_type(inner).layout(self.ctx) { + if let Some(layout) = self.ctx + .resolve_type(inner) + .layout(self.ctx) { if layout.align > mem::size_of::<*mut ()>() { - field_layout.size = - align_to(layout.size, layout.align) * len; + field_layout.size = align_to(layout.size, layout.align) * + len; field_layout.align = mem::size_of::<*mut ()>(); } } @@ -197,7 +200,8 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> { }; // Otherwise the padding is useless. - let need_padding = padding_bytes >= field_layout.align || field_layout.align > mem::size_of::<*mut ()>(); + let need_padding = padding_bytes >= field_layout.align || + field_layout.align > mem::size_of::<*mut ()>(); self.latest_offset += padding_bytes; @@ -206,14 +210,16 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> { self.latest_offset); debug!("align field {} to {}/{} with {} padding bytes {:?}", - field_name, - self.latest_offset, - field_offset.unwrap_or(0) / 8, - padding_bytes, - field_layout); + field_name, + self.latest_offset, + field_offset.unwrap_or(0) / 8, + padding_bytes, + field_layout); if need_padding && padding_bytes != 0 { - Some(Layout::new(padding_bytes, cmp::min(field_layout.align, mem::size_of::<*mut ()>()))) + Some(Layout::new(padding_bytes, + cmp::min(field_layout.align, + mem::size_of::<*mut ()>()))) } else { None } @@ -221,7 +227,8 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> { self.latest_offset += field_layout.size; self.latest_field_layout = Some(field_layout); - self.max_field_align = cmp::max(self.max_field_align, field_layout.align); + self.max_field_align = cmp::max(self.max_field_align, + field_layout.align); self.last_field_was_bitfield = false; debug!("Offset: {}: {} -> {}", @@ -232,11 +239,15 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> { padding_layout.map(|layout| self.padding_field(layout)) } - pub fn pad_struct(&mut self, name: &str, layout: Layout) -> Option { + pub fn pad_struct(&mut self, + name: &str, + layout: Layout) + -> Option { if layout.size < self.latest_offset { error!("Calculated wrong layout for {}, too more {} bytes", - name, self.latest_offset - layout.size); - return None + name, + self.latest_offset - layout.size); + return None; } let padding_bytes = layout.size - self.latest_offset; @@ -248,14 +259,14 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> { // regardless, because bitfields don't respect alignment as strictly as // other fields. if padding_bytes > 0 && - (padding_bytes >= layout.align || - (self.last_field_was_bitfield && - padding_bytes >= self.latest_field_layout.unwrap().align) || - layout.align > mem::size_of::<*mut ()>()) { + (padding_bytes >= layout.align || + (self.last_field_was_bitfield && + padding_bytes >= self.latest_field_layout.unwrap().align) || + layout.align > mem::size_of::<*mut ()>()) { let layout = if self.comp.packed() { Layout::new(padding_bytes, 1) } else if self.last_field_was_bitfield || - layout.align > mem::size_of::<*mut ()>() { + layout.align > mem::size_of::<*mut ()>() { // We've already given up on alignment here. Layout::for_size(padding_bytes) } else { @@ -316,12 +327,14 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> { // If it was, we may or may not need to align, depending on what the // current field alignment and the bitfield size and alignment are. - debug!("align_to_bitfield? {}: {:?} {:?}", self.last_field_was_bitfield, - layout, new_field_layout); + debug!("align_to_bitfield? {}: {:?} {:?}", + self.last_field_was_bitfield, + layout, + new_field_layout); if self.last_field_was_bitfield && - new_field_layout.align <= layout.size % layout.align && - new_field_layout.size <= layout.size % layout.align { + new_field_layout.align <= layout.size % layout.align && + new_field_layout.size <= layout.size % layout.align { // The new field will be coalesced into some of the remaining bits. // // FIXME(emilio): I think this may not catch everything? diff --git a/src/ir/comp.rs b/src/ir/comp.rs index b97879f710..814204c268 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -6,7 +6,7 @@ use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; use super::item::Item; use super::layout::Layout; use super::traversal::{EdgeKind, Trace, Tracer}; -use super::ty::{TemplateDeclaration, Type}; +use super::ty::TemplateDeclaration; use clang; use parse::{ClangItemParser, ParseError}; use std::cell::Cell; @@ -238,10 +238,11 @@ pub struct CompInfo { /// The members of this struct or union. fields: Vec, - /// 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, + /// 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, /// The method declarations inside this class, if in C++ mode. methods: Vec, @@ -252,9 +253,6 @@ pub struct CompInfo { /// Vector of classes this one inherits from. base_members: Vec, - /// The parent reference template if any. - ref_template: Option, - /// 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 { - 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 { 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::>(); - - 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> { - if self.template_args.is_empty() { + fn self_template_params(&self, + _ctx: &BindgenContext) + -> Option> { + 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(&self, context: &BindgenContext, tracer: &mut T, item: &Item) where T: Tracer, { - // TODO: We should properly distinguish template instantiations from - // template declarations at the type level. Why are some template - // instantiations represented here instead of as - // TypeKind::TemplateInstantiation? - if let Some(template) = self.specialized_template() { - // This is an instantiation of a template declaration with concrete - // template type arguments. - tracer.visit_kind(template, EdgeKind::TemplateDeclaration); - let args = item.applicable_template_args(context); - for a in args { - tracer.visit_kind(a, EdgeKind::TemplateArgument); - } - } else { - let params = item.applicable_template_args(context); - // This is a template declaration with abstract template type - // parameters. - for p in params { - tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition); - } + let params = item.all_template_params(context).unwrap_or(vec![]); + for p in params { + tracer.visit_kind(p, EdgeKind::TemplateParameterDefinition); } for base in self.base_members() { diff --git a/src/ir/context.rs b/src/ir/context.rs index 27a43f20bf..6795a864e7 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -5,6 +5,8 @@ use super::int::IntKind; use super::item::{Item, ItemCanonicalPath, ItemSet}; use super::item_kind::ItemKind; use super::module::{Module, ModuleKind}; +use super::named::{UsedTemplateParameters, analyze}; +use super::template::TemplateInstantiation; use super::traversal::{self, Edge, ItemTraversal}; use super::ty::{FloatKind, TemplateDeclaration, Type, TypeKind}; use BindgenOptions; @@ -102,6 +104,10 @@ pub struct BindgenContext<'ctx> { /// item ids during parsing. types: HashMap, + /// Maps from a cursor to the item id of the named template type parameter + /// for that cursor. + named_types: HashMap, + /// A cursor to module map. Similar reason than above. modules: HashMap, @@ -149,6 +155,11 @@ pub struct BindgenContext<'ctx> { /// Whether a bindgen complex was generated generated_bindegen_complex: Cell, + + /// 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>, } /// 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 { + 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, Option)> { + -> Vec<(ItemId, clang::Type, clang::Cursor, Option)> { 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::(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 { + pub fn get_resolved_type(&self, + decl: &clang::CanonicalTypeDeclaration) + -> Option { 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, - 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, + 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> { + fn self_template_params(&self, + _ctx: &BindgenContext) + -> Option> { // Maybe at some point we will eagerly parse named types, but for now we // don't and this information is unavailable. None diff --git a/src/ir/dot.rs b/src/ir/dot.rs index b7a117bba1..e7e1f47bd8 100644 --- a/src/ir/dot.rs +++ b/src/ir/dot.rs @@ -1,23 +1,26 @@ //! Generating Graphviz `dot` files from our IR. +use super::context::{BindgenContext, ItemId}; +use super::traversal::Trace; use std::fs::File; use std::io::{self, Write}; use std::path::Path; -use super::context::{BindgenContext, ItemId}; -use super::traversal::Trace; /// A trait for anything that can write attributes as `` rows to a dot /// file. pub trait DotAttributes { /// Write this thing's attributes to the given output. Each attribute must /// be its own `...`. - fn dot_attributes(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()> + fn dot_attributes(&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

(ctx: &BindgenContext, path: P) -> io::Result<()> - where P: AsRef + where P: AsRef, { let file = try!(File::create(path)); let mut dot_file = io::BufWriter::new(file); @@ -32,16 +35,21 @@ pub fn write_dot_file

(ctx: &BindgenContext, path: P) -> io::Result<()> try!(item.dot_attributes(ctx, &mut dot_file)); try!(writeln!(&mut dot_file, r#"

>];"#)); - item.trace(ctx, &mut |sub_id: ItemId, _edge_kind| { + item.trace(ctx, + &mut |sub_id: ItemId, _edge_kind| { if err.is_some() { return; } - match writeln!(&mut dot_file, "{} -> {};", id.as_usize(), sub_id.as_usize()) { - Ok(_) => {}, + match writeln!(&mut dot_file, + "{} -> {};", + id.as_usize(), + sub_id.as_usize()) { + Ok(_) => {} Err(e) => err = Some(Err(e)), } - }, &()); + }, + &()); if let Some(err) = err { return err; diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs index 3470e03373..d2385a29e8 100644 --- a/src/ir/enum_ty.rs +++ b/src/ir/enum_ty.rs @@ -60,7 +60,7 @@ impl Enum { let declaration = ty.declaration().canonical(); let repr = declaration.enum_type() - .and_then(|et| Item::from_ty(&et, None, None, ctx).ok()); + .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok()); let mut variants = vec![]; // Assume signedness since the default type by the C standard is an int. @@ -99,7 +99,7 @@ impl Enum { Annotations::new(&cursor) .and_then(|anno| if anno.hide() { Some(EnumVariantCustomBehavior::Hide) - } else if + } else if anno.constify_enum_variant() { Some(EnumVariantCustomBehavior::Constify) } else { diff --git a/src/ir/function.rs b/src/ir/function.rs index ad336c4ba3..e82ba83cf2 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -5,9 +5,9 @@ use super::dot::DotAttributes; use super::item::Item; use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::TypeKind; -use ir::derive::CanDeriveDebug; use clang; use clang_sys::CXCallingConv; +use ir::derive::CanDeriveDebug; use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; use std::io; use syntax::abi; @@ -63,11 +63,16 @@ impl Function { } impl DotAttributes for Function { - fn dot_attributes(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()> - where W: io::Write + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, { if let Some(ref mangled) = self.mangled_name { - try!(writeln!(out, "mangled name{}", mangled)); + try!(writeln!(out, + "mangled name{}", + mangled)); } Ok(()) @@ -188,8 +193,7 @@ impl FunctionSig { let name = arg.spelling(); let name = if name.is_empty() { None } else { Some(name) }; - let ty = - Item::from_ty_or_ref(arg_ty, Some(*arg), None, ctx); + let ty = Item::from_ty_or_ref(arg_ty, *arg, None, ctx); (name, ty) }) .collect() @@ -200,10 +204,8 @@ impl FunctionSig { let mut args = vec![]; cursor.visit(|c| { if c.kind() == CXCursor_ParmDecl { - let ty = Item::from_ty_or_ref(c.cur_type(), - Some(c), - None, - ctx); + let ty = + Item::from_ty_or_ref(c.cur_type(), c, None, ctx); let name = c.spelling(); let name = if name.is_empty() { None } else { Some(name) }; @@ -246,7 +248,7 @@ impl FunctionSig { } else { try!(ty.ret_type().ok_or(ParseError::Continue)) }; - let ret = Item::from_ty_or_ref(ty_ret_type, None, None, ctx); + let ret = Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx); let abi = get_abi(ty.call_conv()); if abi.is_none() { @@ -317,10 +319,8 @@ impl ClangSubItemParser for Function { } // Grab the signature using Item::from_ty. - let sig = try!(Item::from_ty(&cursor.cur_type(), - Some(cursor), - None, - context)); + let sig = + try!(Item::from_ty(&cursor.cur_type(), cursor, None, context)); let name = cursor.spelling(); assert!(!name.is_empty(), "Empty function name?"); @@ -368,7 +368,8 @@ impl CanDeriveDebug for FunctionSig { } match self.abi { - Some(abi::Abi::C) | None => true, + Some(abi::Abi::C) | + None => true, _ => false, } } diff --git a/src/ir/item.rs b/src/ir/item.rs index 21b27f071c..93df9c7730 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -3,10 +3,12 @@ use super::annotations::Annotations; use super::context::{BindgenContext, ItemId, PartialType}; use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; -use super::dot::{DotAttributes}; +use super::dot::DotAttributes; use super::function::Function; use super::item_kind::ItemKind; +use super::layout::Opaque; use super::module::Module; +use super::template::AsNamed; use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::{TemplateDeclaration, Type, TypeKind}; use clang; @@ -15,8 +17,8 @@ use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; use std::fmt::Write; -use std::iter; use std::io; +use std::iter; /// A trait to get the canonical name from an item. /// @@ -128,6 +130,35 @@ impl<'a, 'b> Iterator for ItemAncestorsIter<'a, 'b> } } +impl AsNamed for ItemId { + type Extra = (); + + fn as_named(&self, ctx: &BindgenContext, _: &()) -> Option { + ctx.resolve_item(*self).as_named(ctx, &()) + } +} + +impl AsNamed for Item { + type Extra = (); + + fn as_named(&self, ctx: &BindgenContext, _: &()) -> Option { + self.kind.as_named(ctx, self) + } +} + +impl AsNamed for ItemKind { + type Extra = Item; + + fn as_named(&self, ctx: &BindgenContext, item: &Item) -> Option { + 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, + detect_derive_copy_cycle: Cell, +} + +impl AsRef 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 - /// struct Foo { - /// T bar; - /// - /// struct Baz { - /// U bas; - /// }; - /// }; - /// ``` - /// - /// Both `Foo` and `Baz` contain both `T` and `U` template parameters in - /// their signature: - /// - /// * `Foo` - /// * `Bar` - /// - /// But the Rust structure for `Foo` would look like: - /// - /// ```rust - /// struct Foo { - /// bar: T, - /// _phantom0: ::std::marker::PhantomData, - /// } - /// ``` - /// - /// because none of its member fields contained the `U` type in the - /// signature. Similarly, `Bar` would contain a `PhantomData` 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 - /// class Foo { - /// typedef T element_type; - /// typedef int Bar; - /// - /// template - /// 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 = ::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 { - 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; impl DotAttributes for Item { - fn dot_attributes(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()> - where W: io::Write + fn dot_attributes(&self, + ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, { try!(writeln!(out, "{:?} @@ -930,20 +829,26 @@ impl DotAttributes for Item { } impl TemplateDeclaration for ItemId { - fn self_template_params(&self, ctx: &BindgenContext) -> Option> { + fn self_template_params(&self, + ctx: &BindgenContext) + -> Option> { 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> { + fn self_template_params(&self, + ctx: &BindgenContext) + -> Option> { self.kind.self_template_params(ctx) } } impl TemplateDeclaration for ItemKind { - fn self_template_params(&self, ctx: &BindgenContext) -> Option> { + fn self_template_params(&self, + ctx: &BindgenContext) + -> Option> { 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, + location: clang::Cursor, parent_id: Option, 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, + location: clang::Cursor, parent_id: Option, 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, + location: clang::Cursor, parent_id: Option, ctx: &mut BindgenContext) -> Result { 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, + location: clang::Cursor, parent_id: Option, ctx: &mut BindgenContext) -> Result { use clang_sys::*; + debug!("Item::from_ty_with_id: {:?}\n\ + \tty = {:?},\n\ + \tlocation = {:?}", + id, + ty, + location); + + if ty.kind() == clang_sys::CXType_Unexposed || + location.cur_type().kind() == clang_sys::CXType_Unexposed { + + if ty.is_associated_type() || + location.cur_type().is_associated_type() { + return Ok(Item::new_opaque_type(id, ty, ctx)); + } + + if let Some(id) = Item::named_type(Some(id), location, ctx) { + return Ok(id); + } + } + let decl = { let decl = ty.declaration(); decl.definition().unwrap_or(decl) }; let comment = decl.raw_comment() - .or_else(|| location.as_ref().and_then(|l| l.raw_comment())); + .or_else(|| location.raw_comment()); let annotations = Annotations::new(&decl) - .or_else(|| location.as_ref().and_then(|l| Annotations::new(l))); + .or_else(|| Annotations::new(&location)); if let Some(ref annotations) = annotations { if let Some(ref replaced) = annotations.use_instead_of() { @@ -1212,7 +1140,7 @@ impl ClangItemParser for Item { } if let Some(ty) = - ctx.builtin_or_resolved_ty(id, parent_id, ty, location) { + ctx.builtin_or_resolved_ty(id, parent_id, ty, Some(location)) { return Ok(ty); } @@ -1220,11 +1148,10 @@ impl ClangItemParser for Item { let mut valid_decl = decl.kind() != CXCursor_NoDeclFound; let declaration_to_look_for = if valid_decl { decl.canonical() - } else if location.is_some() && - location.unwrap().kind() == + } else if location.kind() == CXCursor_ClassTemplate { valid_decl = true; - location.unwrap() + location } else { decl }; @@ -1255,51 +1182,47 @@ impl ClangItemParser for Item { relevant_parent_id, ItemKind::Type(item)), declaration, - location); + Some(location)); Ok(id) } Err(ParseError::Continue) => Err(ParseError::Continue), Err(ParseError::Recurse) => { debug!("Item::from_ty recursing in the ast"); let mut result = Err(ParseError::Recurse); - if let Some(ref location) = location { - // Need to pop here, otherwise we'll get stuck. - // - // TODO: Find a nicer interface, really. Also, the - // declaration_to_look_for suspiciously shares a lot of - // logic with ir::context, so we should refactor that. - if valid_decl { - let finished = ctx.finish_parsing(); - assert_eq!(*finished.decl(), declaration_to_look_for); - } - location.visit(|cur| { - visit_child(cur, id, ty, parent_id, ctx, &mut result) - }); + // Need to pop here, otherwise we'll get stuck. + // + // TODO: Find a nicer interface, really. Also, the + // declaration_to_look_for suspiciously shares a lot of + // logic with ir::context, so we should refactor that. + if valid_decl { + let finished = ctx.finish_parsing(); + assert_eq!(*finished.decl(), declaration_to_look_for); + } - if valid_decl { - let partial_ty = - PartialType::new(declaration_to_look_for, id); - ctx.begin_parsing(partial_ty); - } + location.visit(|cur| { + visit_child(cur, id, ty, parent_id, ctx, &mut result) + }); + + if valid_decl { + let partial_ty = PartialType::new(declaration_to_look_for, + id); + ctx.begin_parsing(partial_ty); } + // If we have recursed into the AST all we know, and we still - // haven't found what we've got, let's just make a named type. + // haven't found what we've got, let's just try and make a named + // type. // // This is what happens with some template members, for example. - // - // FIXME: Maybe we should restrict this to things with parent? - // It's harmless, but if we restrict that, then - // tests/headers/nsStyleAutoArray.hpp crashes. if let Err(ParseError::Recurse) = result { warn!("Unknown type, assuming named template type: \ id = {:?}; spelling = {}", id, ty.spelling()); - Ok(Self::named_type_with_id(id, - ty.spelling(), - relevant_parent_id, - ctx)) + Item::named_type(Some(id), location, ctx) + .map(Ok) + .unwrap_or(Err(ParseError::Recurse)) } else { result } @@ -1317,40 +1240,150 @@ impl ClangItemParser for Item { /// A named type is a template parameter, e.g., the "T" in Foo. 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(id: ItemId, - name: S, - parent_id: ItemId, - ctx: &mut BindgenContext) - -> ItemId - where S: Into, - { - // 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, + location: clang::Cursor, + ctx: &mut BindgenContext) + -> Option { + let ty = location.cur_type(); + + debug!("Item::named_type:\n\ + \twith_id = {:?},\n\ + \tty = {} {:?},\n\ + \tlocation: {:?}", + with_id, + ty.spelling(), + ty, + location); + + if ty.kind() != clang_sys::CXType_Unexposed { + // If the given cursor's type's kind is not Unexposed, then we + // aren't looking at a template parameter. This check may need to be + // updated in the future if they start properly exposing template + // type parameters. + return None; + } - ctx.add_item(Item::new(id, - None, - None, - parent_id, - ItemKind::Type(Type::named(name))), - None, - None); + let ty_spelling = ty.spelling(); - id - } + // Clang does not expose any information about template type parameters + // via their clang::Type, nor does it give us their canonical cursors + // the straightforward way. However, there are three situations from + // which we can find the definition of the template type parameter, if + // the cursor is indeed looking at some kind of a template type + // parameter or use of one: + // + // 1. The cursor is pointing at the template type parameter's + // definition. This is the trivial case. + // + // (kind = TemplateTypeParameter, ...) + // + // 2. The cursor is pointing at a TypeRef whose referenced() cursor is + // situation (1). + // + // (kind = TypeRef, + // referenced = (kind = TemplateTypeParameter, ...), + // ...) + // + // 3. The cursor is pointing at some use of a template type parameter + // (for example, in a FieldDecl), and this cursor has a child cursor + // whose spelling is the same as the parent's type's spelling, and whose + // kind is a TypeRef of the situation (2) variety. + // + // (kind = FieldDecl, + // type = (kind = Unexposed, + // spelling = "T", + // ...), + // children = + // (kind = TypeRef, + // spelling = "T", + // referenced = (kind = TemplateTypeParameter, + // spelling = "T", + // ...), + // ...) + // ...) + // + // TODO: The alternative to this hacky pattern matching would be to + // maintain proper scopes of template parameters while parsing and use + // de Brujin indices to access template parameters, which clang exposes + // in the cursor's type's canonical type's spelling: + // "type-parameter-x-y". That is probably a better approach long-term, + // but maintaining these scopes properly would require more changes to + // the whole libclang -> IR parsing code. + + fn is_template_with_spelling(refd: &clang::Cursor, + spelling: &str) + -> bool { + refd.kind() == clang_sys::CXCursor_TemplateTypeParameter && + refd.spelling() == spelling + } - fn named_type(name: S, - parent_id: ItemId, - ctx: &mut BindgenContext) - -> ItemId - where S: Into, - { - let id = ctx.next_item_id(); - Self::named_type_with_id(id, name, parent_id, ctx) + let definition = if is_template_with_spelling(&location, + &ty_spelling) { + // Situation (1) + location + } else if location.kind() == + clang_sys::CXCursor_TypeRef { + // Situation (2) + match location.referenced() { + Some(refd) if is_template_with_spelling(&refd, + &ty_spelling) => refd, + _ => return None, + } + } else { + // Situation (3) + let mut definition = None; + + location.visit(|child| { + let child_ty = child.cur_type(); + if child_ty.kind() == clang_sys::CXCursor_TypeRef && + child_ty.spelling() == ty_spelling { + match child.referenced() { + Some(refd) if is_template_with_spelling(&refd, &ty_spelling) => { + definition = Some(refd); + return clang_sys::CXChildVisit_Break; + } + _ => {} + } + } + + clang_sys::CXChildVisit_Continue + }); + + if let Some(def) = definition { + def + } else { + return None; + } + }; + assert!(is_template_with_spelling(&definition, &ty_spelling)); + + // Named types are always parented to the root module. They are never + // referenced with namespace prefixes, and they can't inherit anything + // from their parent either, so it is simplest to just hang them off + // something we know will always exist. + let parent = ctx.root_module(); + + if let Some(id) = ctx.get_named_type(&definition) { + if let Some(with_id) = with_id { + return Some(ctx.build_ty_wrapper(with_id, id, Some(parent), &ty)); + } else { + return Some(id); + } + } + + // See tests/headers/const_tparam.hpp and + // tests/headers/variadic_tname.hpp. + let name = ty_spelling.replace("const ", "") + .replace(".", ""); + + let id = with_id.unwrap_or_else(|| ctx.next_item_id()); + let item = Item::new(id, + None, + None, + parent, + ItemKind::Type(Type::named(name))); + ctx.add_named_type(item, definition); + Some(id) } } diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs index 6dfd6764ce..419f9d4421 100644 --- a/src/ir/item_kind.rs +++ b/src/ir/item_kind.rs @@ -1,12 +1,12 @@ //! Different variants of an `Item` in our intermediate representation. -use std::io; use super::context::BindgenContext; use super::dot::DotAttributes; use super::function::Function; use super::module::Module; use super::ty::Type; use super::var::Var; +use std::io; /// A item we parse and translate. #[derive(Debug)] @@ -41,7 +41,7 @@ impl ItemKind { ItemKind::Module(..) => "Module", ItemKind::Type(..) => "Type", ItemKind::Function(..) => "Function", - ItemKind::Var(..) => "Var" + ItemKind::Var(..) => "Var", } } @@ -127,10 +127,15 @@ impl ItemKind { } impl DotAttributes for ItemKind { - fn dot_attributes(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()> - where W: io::Write + fn dot_attributes(&self, + ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, { - try!(writeln!(out, "kind{}", self.kind_name())); + try!(writeln!(out, + "kind{}", + self.kind_name())); match *self { ItemKind::Module(ref module) => module.dot_attributes(ctx, out), diff --git a/src/ir/layout.rs b/src/ir/layout.rs index f21a501caf..21382b2d99 100644 --- a/src/ir/layout.rs +++ b/src/ir/layout.rs @@ -2,7 +2,8 @@ use super::context::BindgenContext; use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; -use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT; +use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind}; +use clang; use std::{cmp, mem}; /// A type that represents the struct layout of a type. @@ -20,7 +21,8 @@ pub struct Layout { fn test_layout_for_size() { let ptr_size = mem::size_of::<*mut ()>(); assert_eq!(Layout::for_size(ptr_size), Layout::new(ptr_size, ptr_size)); - assert_eq!(Layout::for_size(3 * ptr_size), Layout::new(3 * ptr_size, ptr_size)); + assert_eq!(Layout::for_size(3 * ptr_size), + Layout::new(3 * ptr_size, ptr_size)); } impl Layout { @@ -38,7 +40,8 @@ impl Layout { /// alignment possible. pub fn for_size(size: usize) -> Self { let mut next_align = 2; - while size % next_align == 0 && next_align <= mem::size_of::<*mut ()>() { + while size % next_align == 0 && + next_align <= mem::size_of::<*mut ()>() { next_align *= 2; } Layout { @@ -65,9 +68,17 @@ impl Layout { } /// When we are treating a type as opaque, it is just a blob with a `Layout`. +#[derive(Clone, Debug, PartialEq)] pub struct Opaque(pub Layout); impl Opaque { + /// Construct a new opaque type from the given clang type. + pub fn from_clang_ty(ty: &clang::Type) -> Type { + let layout = Layout::new(ty.size(), ty.align()); + let ty_kind = TypeKind::Opaque; + Type::new(None, Some(layout), ty_kind, false) + } + /// Return the known rust type we should use to create a correctly-aligned /// field with this layout. pub fn known_rust_type_for_array(&self) -> Option<&'static str> { diff --git a/src/ir/mod.rs b/src/ir/mod.rs index ba549c5115..d703e53dbb 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -16,6 +16,7 @@ pub mod item_kind; pub mod layout; pub mod module; pub mod named; +pub mod template; pub mod traversal; pub mod ty; pub mod var; diff --git a/src/ir/module.rs b/src/ir/module.rs index 6787e3f902..ee3912c5f1 100644 --- a/src/ir/module.rs +++ b/src/ir/module.rs @@ -1,11 +1,11 @@ //! Intermediate representation for modules (AKA C++ namespaces). -use std::io; use super::context::{BindgenContext, ItemId}; use super::dot::DotAttributes; use clang; use parse::{ClangSubItemParser, ParseError, ParseResult}; use parse_one; +use std::io; /// Whether this module is inline or not. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -59,12 +59,13 @@ impl Module { } impl DotAttributes for Module { - fn dot_attributes(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()> - where W: io::Write + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, { - writeln!(out, - "ModuleKind{:?}", - self.kind) + writeln!(out, "ModuleKind{:?}", self.kind) } } diff --git a/src/ir/named.rs b/src/ir/named.rs index 3c6766629e..7cae195bf0 100644 --- a/src/ir/named.rs +++ b/src/ir/named.rs @@ -126,12 +126,13 @@ //! //! [spa]: https://cs.au.dk/~amoeller/spa/spa.pdf -use std::collections::HashMap; -use std::fmt; use super::context::{BindgenContext, ItemId}; use super::item::ItemSet; +use super::template::AsNamed; use super::traversal::{EdgeKind, Trace}; use super::ty::{TemplateDeclaration, TypeKind}; +use std::collections::HashMap; +use std::fmt; /// An analysis in the monotone framework. /// @@ -163,7 +164,7 @@ pub trait MonotoneFramework: Sized + fmt::Debug { /// The final output of this analysis. Once we have reached a fix-point, we /// convert `self` into this type, and return it as the final result of the /// analysis. - type Output: From; + type Output: From + 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::`. -#[allow(dead_code)] pub fn analyze(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(extra: Analysis::Extra) -> Analysis::Output /// self_template_param_usage(_) = { } /// ``` #[derive(Debug, Clone)] -pub struct UsedTemplateParameters<'a> { - ctx: &'a BindgenContext<'a>, - used: HashMap, +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>, + dependencies: HashMap>, } -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; - fn new(ctx: &'a BindgenContext<'a>) -> UsedTemplateParameters<'a> { + fn new(ctx: &'ctx BindgenContext<'gen>) + -> UsedTemplateParameters<'ctx, 'gen> { let mut used = HashMap::new(); let mut dependencies = HashMap::new(); for item in ctx.whitelisted_items() { dependencies.entry(item).or_insert(vec![]); - used.insert(item, ItemSet::new()); + used.insert(item, Some(ItemSet::new())); { // We reverse our natural IR graph edges to find dependencies // between nodes. - item.trace(ctx, &mut |sub_item, _| { - dependencies.entry(sub_item).or_insert(vec![]).push(item); - }, &()); + item.trace(ctx, + &mut |sub_item, _| { + dependencies.entry(sub_item) + .or_insert(vec![]) + .push(item); + }, + &()); } // Additionally, whether a template instantiation's template @@ -326,14 +339,18 @@ impl<'a> MonotoneFramework for UsedTemplateParameters<'a> { ctx.resolve_item(item) .as_type() .map(|ty| match ty.kind() { - &TypeKind::TemplateInstantiation(decl, ref args) => { - let decl = ctx.resolve_type(decl); + &TypeKind::TemplateInstantiation(ref inst) => { + let decl = ctx.resolve_type(inst.template_definition()); + let args = inst.template_arguments(); + // Although template definitions should always have + // template parameters, there is a single exception: + // opaque templates. Hence the unwrap_or. let params = decl.self_template_params(ctx) - .expect("a template instantiation's referenced \ - template declaration should have template \ - parameters"); + .unwrap_or(vec![]); for (arg, param) in args.iter().zip(params.iter()) { - dependencies.entry(*arg).or_insert(vec![]).push(*param); + dependencies.entry(*arg) + .or_insert(vec![]) + .push(*param); } } _ => {} @@ -352,59 +369,81 @@ impl<'a> MonotoneFramework for UsedTemplateParameters<'a> { } fn constrain(&mut self, id: ItemId) -> bool { - let original_len = self.used[&id].len(); + // Invariant: all hash map entries' values are `Some` upon entering and + // exiting this method. + debug_assert!(self.used.values().all(|v| v.is_some())); + + // Take the set for this id out of the hash map while we mutate it based + // on other hash map entries. We *must* put it back into the hash map at + // the end of this method. This allows us to side-step HashMap's lack of + // an analog to slice::split_at_mut. + let mut used_by_this_id = + self.used.get_mut(&id).unwrap().take().unwrap(); + + let original_len = used_by_this_id.len(); - // First, add this item's self template parameter usage. let item = self.ctx.resolve_item(id); let ty_kind = item.as_type().map(|ty| ty.kind()); match ty_kind { + // Named template type parameters trivially use themselves. Some(&TypeKind::Named) => { - // This is a trivial use of the template type parameter. - self.used.get_mut(&id).unwrap().insert(id); + used_by_this_id.insert(id); } - Some(&TypeKind::TemplateInstantiation(decl, ref args)) => { - // A template instantiation's concrete template argument is - // only used if the template declaration uses the - // corresponding template parameter. + + // A template instantiation's concrete template argument is + // only used if the template declaration uses the + // corresponding template parameter. + Some(&TypeKind::TemplateInstantiation(ref inst)) => { + let decl = self.ctx.resolve_type(inst.template_definition()); + let args = inst.template_arguments(); + let params = decl.self_template_params(self.ctx) - .expect("a template instantiation's referenced \ - template declaration should have template \ - parameters"); + .unwrap_or(vec![]); for (arg, param) in args.iter().zip(params.iter()) { - if self.used[&decl].contains(param) { - if self.ctx.resolve_item(*arg).is_named() { - self.used.get_mut(&id).unwrap().insert(*arg); + let used_by_definition = self.used + [&inst.template_definition()] + .as_ref() + .unwrap(); + if used_by_definition.contains(param) { + if let Some(named) = arg.as_named(self.ctx, &()) { + used_by_this_id.insert(named); } } } } - _ => {} - } - // Second, add the union of each of its referent item's template - // parameter usage. - item.trace(self.ctx, &mut |sub_id, edge_kind| { - if sub_id == id || !Self::consider_edge(edge_kind) { - return; + // Otherwise, add the union of each of its referent item's template + // parameter usage. + _ => { + item.trace(self.ctx, + &mut |sub_id, edge_kind| { + if sub_id == id || !Self::consider_edge(edge_kind) { + return; + } + + let used_by_sub_id = self.used[&sub_id] + .as_ref() + .unwrap() + .iter() + .cloned(); + used_by_this_id.extend(used_by_sub_id); + }, + &()); } + } - // This clone is unfortunate because we are potentially thrashing - // malloc. We could investigate replacing the ItemSet values with - // Rc> 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(&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> for HashMap { - fn from(used_templ_params: UsedTemplateParameters) -> Self { +impl<'ctx, 'gen> From> + for HashMap { + 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(&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(nodes: A) -> HashSet - where A: AsRef<[usize]> + where A: AsRef<[usize]>, { nodes.as_ref().iter().cloned().map(Node).collect() } let mut expected = HashMap::new(); - expected.insert(Node(1), nodes([3,4,5,6,7,8])); + expected.insert(Node(1), nodes([3, 4, 5, 6, 7, 8])); expected.insert(Node(2), nodes([2])); - expected.insert(Node(3), nodes([3,4,5,6,7,8])); - expected.insert(Node(4), nodes([3,4,5,6,7,8])); - expected.insert(Node(5), nodes([3,4,5,6,7,8])); + expected.insert(Node(3), nodes([3, 4, 5, 6, 7, 8])); + expected.insert(Node(4), nodes([3, 4, 5, 6, 7, 8])); + expected.insert(Node(5), nodes([3, 4, 5, 6, 7, 8])); expected.insert(Node(6), nodes([8])); - expected.insert(Node(7), nodes([3,4,5,6,7,8])); + expected.insert(Node(7), nodes([3, 4, 5, 6, 7, 8])); expected.insert(Node(8), nodes([])); println!("expected = {:#?}", expected); diff --git a/src/ir/template.rs b/src/ir/template.rs new file mode 100644 index 0000000000..627ac225f8 --- /dev/null +++ b/src/ir/template.rs @@ -0,0 +1,193 @@ +//! Template declaration and instantiation related things. +//! +//! The nomenclature surrounding templates is often confusing, so here are a few +//! brief definitions: +//! +//! * "Template definition": a class/struct/alias/function definition that takes +//! generic template parameters. For example: +//! +//! ```c++ +//! template +//! class List { +//! // ... +//! }; +//! ``` +//! +//! * "Template instantiation": an instantiation is a use of a template with +//! concrete template arguments. For example, `List`. +//! +//! * "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 { +//! // 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; + + /// 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, +} + +impl TemplateInstantiation { + /// Construct a new template instantiation from the given parts. + pub fn new(template_definition: ItemId, + template_args: I) + -> TemplateInstantiation + where I: IntoIterator, + { + 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; + + fn can_derive_debug(&self, + ctx: &BindgenContext, + layout: Option) + -> 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(&self, _ctx: &BindgenContext, tracer: &mut T, _: &()) + where T: Tracer, + { + tracer.visit_kind(self.definition, EdgeKind::TemplateDeclaration); + for &item in self.template_arguments() { + tracer.visit_kind(item, EdgeKind::TemplateArgument); + } + } +} diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs index 30772aadba..95d2a45675 100644 --- a/src/ir/traversal.rs +++ b/src/ir/traversal.rs @@ -318,7 +318,7 @@ pub trait Tracer { } impl Tracer for F - where F: FnMut(ItemId, EdgeKind) + where F: FnMut(ItemId, EdgeKind), { fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { (*self)(item, kind) diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 51652000e1..6c8e736355 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -8,22 +8,31 @@ use super::enum_ty::Enum; use super::function::FunctionSig; use super::int::IntKind; use super::item::{Item, ItemAncestors}; -use super::layout::Layout; +use super::layout::{Layout, Opaque}; use super::objc::ObjCInterface; +use super::template::{AsNamed, TemplateInstantiation}; use super::traversal::{EdgeKind, Trace, Tracer}; use clang::{self, Cursor}; use parse::{ClangItemParser, ParseError, ParseResult}; +use std::cell::Cell; use std::io; use std::mem; /// Template declaration (and such declaration's template parameters) related /// methods. /// +/// This trait's methods distinguish between `None` and `Some([])` for +/// declarations that are not templates and template declarations with zero +/// parameters, in general. +/// /// Consider this example: /// /// ```c++ /// template /// class Foo { +/// T use_of_t; +/// U use_of_u; +/// /// template /// using Bar = V*; /// @@ -32,6 +41,18 @@ use std::mem; /// U y; /// Bar z; /// }; +/// +/// template +/// class Lol { +/// // No use of W, but here's a use of T. +/// T t; +/// }; +/// +/// template +/// class Wtf { +/// // X is not used because W is not used. +/// Lol lololol; +/// }; /// }; /// /// class Qux { @@ -40,16 +61,29 @@ use std::mem; /// ``` /// /// The following table depicts the results of each trait method when invoked on -/// `Foo`, `Bar`, and `Qux`. +/// each of the declarations above: /// -/// +------+----------------------+--------------------------+------------------------+ -/// |Decl. | self_template_params | num_self_template_params | all_template_parameters| -/// +------+----------------------+--------------------------+------------------------+ -/// |Foo | Some([T, U]) | Some(2) | Some([T, U]) | -/// |Bar | Some([V]) | Some(1) | Some([T, U, V]) | -/// |Inner | None | None | Some([T, U]) | -/// |Qux | None | None | None | -/// +------+----------------------+--------------------------+------------------------+ +/// +------+----------------------+--------------------------+------------------------+---- +/// |Decl. | self_template_params | num_self_template_params | all_template_parameters| ... +/// +------+----------------------+--------------------------+------------------------+---- +/// |Foo | Some([T, U]) | Some(2) | Some([T, U]) | ... +/// |Bar | Some([V]) | Some(1) | Some([T, U, V]) | ... +/// |Inner | None | None | Some([T, U]) | ... +/// |Lol | Some([W]) | Some(1) | Some([T, U, W]) | ... +/// |Wtf | Some([X]) | Some(1) | Some([T, U, X]) | ... +/// |Qux | None | None | None | ... +/// +------+----------------------+--------------------------+------------------------+---- +/// +/// ----+------+-----+----------------------+ +/// ... |Decl. | ... | used_template_params | +/// ----+------+-----+----------------------+ +/// ... |Foo | ... | Some([T, U]) | +/// ... |Bar | ... | Some([V]) | +/// ... |Inner | ... | None | +/// ... |Lol | ... | Some([T]) | +/// ... |Wtf | ... | Some([T]) | +/// ... |Qux | ... | None | +/// ----+------+-----+----------------------+ pub trait TemplateDeclaration { /// Get the set of `ItemId`s that make up this template declaration's free /// template parameters. @@ -59,7 +93,9 @@ pub trait TemplateDeclaration { /// parameters. Of course, Rust does not allow generic parameters to be /// anything but types, so we must treat them as opaque, and avoid /// instantiating them. - fn self_template_params(&self, ctx: &BindgenContext) -> Option>; + fn self_template_params(&self, + ctx: &BindgenContext) + -> Option>; /// Get the number of free template parameters this template declaration /// has. @@ -87,7 +123,7 @@ pub trait TemplateDeclaration { /// `Foo::Inner`. `Foo` *must* be instantiated with template /// arguments before we can gain access to the `Inner` member type. fn all_template_params(&self, ctx: &BindgenContext) -> Option> - where Self: ItemAncestors + where Self: ItemAncestors, { let each_self_params: Vec> = self.ancestors(ctx) .filter_map(|id| id.self_template_params(ctx)) @@ -96,11 +132,30 @@ pub trait TemplateDeclaration { None } else { Some(each_self_params.into_iter() - .rev() - .flat_map(|params| params) - .collect()) + .rev() + .flat_map(|params| params) + .collect()) } } + + /// Get only the set of template parameters that this item uses. This is a + /// subset of `all_template_params` and does not necessarily contain any of + /// `self_template_params`. + fn used_template_params(&self, ctx: &BindgenContext) -> Option> + where Self: AsRef, + { + assert!(ctx.in_codegen_phase(), + "template parameter usage is not computed until codegen"); + + let id = *self.as_ref(); + ctx.resolve_item(id) + .all_template_params(ctx) + .map(|all_params| { + all_params.into_iter() + .filter(|p| ctx.uses_template_parameter(id, *p)) + .collect() + }) + } } /// The base representation of a type in bindgen. @@ -118,6 +173,9 @@ pub struct Type { kind: TypeKind, /// Whether this type is const-qualified. is_const: bool, + /// Don't go into an infinite loop when detecting if we have a vtable or + /// not. + detect_has_vtable_cycle: Cell, } /// The maximum number of items in an array for which Rust implements common @@ -148,6 +206,7 @@ impl Type { layout: layout, kind: kind, is_const: is_const, + detect_has_vtable_cycle: Cell::new(false), } } @@ -174,7 +233,15 @@ impl Type { } } - /// Is this a named type? + /// Is this type of kind `TypeKind::Opaque`? + pub fn is_opaque(&self) -> bool { + match self.kind { + TypeKind::Opaque => true, + _ => false, + } + } + + /// Is this type of kind `TypeKind::Named`? pub fn is_named(&self) -> bool { match self.kind { TypeKind::Named => true, @@ -304,67 +371,39 @@ impl Type { /// Whether this type has a vtable. pub fn has_vtable(&self, ctx: &BindgenContext) -> bool { + if self.detect_has_vtable_cycle.get() { + return false; + } + + self.detect_has_vtable_cycle.set(true); + // FIXME: Can we do something about template parameters? Huh... - match self.kind { - TypeKind::TemplateInstantiation(t, _) | + let result = match self.kind { TypeKind::TemplateAlias(t, _) | TypeKind::Alias(t) | TypeKind::ResolvedTypeRef(t) => ctx.resolve_type(t).has_vtable(ctx), TypeKind::Comp(ref info) => info.has_vtable(ctx), + TypeKind::TemplateInstantiation(ref inst) => inst.has_vtable(ctx), _ => false, - } + }; + self.detect_has_vtable_cycle.set(false); + + result } /// Returns whether this type has a destructor. pub fn has_destructor(&self, ctx: &BindgenContext) -> bool { match self.kind { - TypeKind::TemplateInstantiation(t, _) | TypeKind::TemplateAlias(t, _) | TypeKind::Alias(t) | TypeKind::ResolvedTypeRef(t) => { ctx.resolve_type(t).has_destructor(ctx) } - TypeKind::Comp(ref info) => info.has_destructor(ctx), - _ => false, - } - } - - /// See the comment in `Item::signature_contains_named_type`. - pub fn signature_contains_named_type(&self, - ctx: &BindgenContext, - ty: &Type) - -> bool { - let name = match *ty.kind() { - TypeKind::Named => ty.name(), - ref other @ _ => unreachable!("Not a named type: {:?}", other), - }; - - match self.kind { - TypeKind::Named => self.name() == name, - TypeKind::ResolvedTypeRef(t) | - TypeKind::Array(t, _) | - TypeKind::Pointer(t) | - TypeKind::Alias(t) => { - ctx.resolve_type(t) - .signature_contains_named_type(ctx, ty) - } - TypeKind::Function(ref sig) => { - sig.argument_types().iter().any(|&(_, arg)| { - ctx.resolve_type(arg) - .signature_contains_named_type(ctx, ty) - }) || - ctx.resolve_type(sig.return_type()) - .signature_contains_named_type(ctx, ty) - } - TypeKind::TemplateAlias(_, ref template_args) | - TypeKind::TemplateInstantiation(_, ref template_args) => { - template_args.iter().any(|arg| { - ctx.resolve_type(*arg) - .signature_contains_named_type(ctx, ty) - }) + TypeKind::TemplateInstantiation(ref inst) => { + inst.has_destructor(ctx) } - TypeKind::Comp(ref ci) => ci.signature_contains_named_type(ctx, ty), + TypeKind::Comp(ref info) => info.has_destructor(ctx), _ => false, } } @@ -387,7 +426,9 @@ impl Type { /// i.e. is alphanumeric (including '_') and does not start with a digit. pub fn is_valid_identifier(name: &str) -> bool { let mut chars = name.chars(); - let first_valid = chars.next().map(|c| c.is_alphabetic() || c == '_').unwrap_or(false); + let first_valid = chars.next() + .map(|c| c.is_alphabetic() || c == '_') + .unwrap_or(false); first_valid && chars.all(|c| c.is_alphanumeric() || c == '_') } @@ -403,7 +444,7 @@ impl Type { /// Returns the canonical type of this type, that is, the "inner type". /// /// For example, for a `typedef`, the canonical type would be the - /// `typedef`ed type, for a template specialization, would be the template + /// `typedef`ed type, for a template instantiation, would be the template /// its specializing, and so on. Return None if the type is unresolved. pub fn safe_canonical_type<'tr>(&'tr self, ctx: &'tr BindgenContext) @@ -412,6 +453,7 @@ impl Type { TypeKind::Named | TypeKind::Array(..) | TypeKind::Comp(..) | + TypeKind::Opaque | TypeKind::Int(..) | TypeKind::Float(..) | TypeKind::Complex(..) | @@ -428,10 +470,13 @@ impl Type { TypeKind::ResolvedTypeRef(inner) | TypeKind::Alias(inner) | - TypeKind::TemplateAlias(inner, _) | - TypeKind::TemplateInstantiation(inner, _) => { + TypeKind::TemplateAlias(inner, _) => { ctx.resolve_type(inner).safe_canonical_type(ctx) } + TypeKind::TemplateInstantiation(ref inst) => { + ctx.resolve_type(inst.template_definition()) + .safe_canonical_type(ctx) + } TypeKind::UnresolvedTypeRef(..) => None, } @@ -452,9 +497,32 @@ impl Type { } } +impl AsNamed for Type { + type Extra = Item; + + fn as_named(&self, ctx: &BindgenContext, item: &Item) -> Option { + self.kind.as_named(ctx, item) + } +} + +impl AsNamed for TypeKind { + type Extra = Item; + + fn as_named(&self, ctx: &BindgenContext, item: &Item) -> Option { + match *self { + TypeKind::Named => Some(item.id()), + TypeKind::ResolvedTypeRef(id) => id.as_named(ctx, &()), + _ => None, + } + } +} + impl DotAttributes for Type { - fn dot_attributes(&self, ctx: &BindgenContext, out: &mut W) -> io::Result<()> - where W: io::Write + fn dot_attributes(&self, + ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, { if let Some(ref layout) = self.layout { try!(writeln!(out, @@ -476,8 +544,11 @@ impl DotAttributes for Type { } impl DotAttributes for TypeKind { - fn dot_attributes(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()> - where W: io::Write + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, { write!(out, "TypeKind{}", @@ -485,6 +556,7 @@ impl DotAttributes for TypeKind { TypeKind::Void => "Void", TypeKind::NullPtr => "NullPtr", TypeKind::Comp(..) => "Comp", + TypeKind::Opaque => "Opaque", TypeKind::Int(..) => "Int", TypeKind::Float(..) => "Float", TypeKind::Complex(..) => "Complex", @@ -502,9 +574,7 @@ impl DotAttributes for TypeKind { TypeKind::ObjCId => "ObjCId", TypeKind::ObjCSel => "ObjCSel", TypeKind::ObjCInterface(..) => "ObjCInterface", - TypeKind::UnresolvedTypeRef(..) => { - unreachable!("there shouldn't be any more of these anymore") - } + TypeKind::UnresolvedTypeRef(..) => unreachable!("there shouldn't be any more of these anymore"), }) } } @@ -555,13 +625,17 @@ fn is_invalid_named_type_empty_name() { impl TemplateDeclaration for Type { - fn self_template_params(&self, ctx: &BindgenContext) -> Option> { + fn self_template_params(&self, + ctx: &BindgenContext) + -> Option> { self.kind.self_template_params(ctx) } } impl TemplateDeclaration for TypeKind { - fn self_template_params(&self, ctx: &BindgenContext) -> Option> { + fn self_template_params(&self, + ctx: &BindgenContext) + -> Option> { match *self { TypeKind::ResolvedTypeRef(id) => { ctx.resolve_type(id).self_template_params(ctx) @@ -569,6 +643,7 @@ impl TemplateDeclaration for TypeKind { TypeKind::Comp(ref comp) => comp.self_template_params(ctx), TypeKind::TemplateAlias(_, ref args) => Some(args.clone()), + TypeKind::Opaque | TypeKind::TemplateInstantiation(..) | TypeKind::Void | TypeKind::NullPtr | @@ -607,11 +682,15 @@ impl CanDeriveDebug for Type { } TypeKind::Pointer(inner) => { let inner = ctx.resolve_type(inner); - if let TypeKind::Function(ref sig) = *inner.canonical_type(ctx).kind() { + if let TypeKind::Function(ref sig) = + *inner.canonical_type(ctx).kind() { return sig.can_derive_debug(ctx, ()); } return true; } + TypeKind::TemplateInstantiation(ref inst) => { + inst.can_derive_debug(ctx, self.layout(ctx)) + } _ => true, } } @@ -632,6 +711,10 @@ impl CanDeriveDefault for Type { TypeKind::Comp(ref info) => { info.can_derive_default(ctx, self.layout(ctx)) } + TypeKind::Opaque => { + self.layout + .map_or(true, |l| l.opaque().can_derive_default(ctx, ())) + } TypeKind::Void | TypeKind::Named | TypeKind::TemplateInstantiation(..) | @@ -664,11 +747,17 @@ impl<'a> CanDeriveCopy<'a> for Type { } TypeKind::ResolvedTypeRef(t) | TypeKind::TemplateAlias(t, _) | - TypeKind::TemplateInstantiation(t, _) | TypeKind::Alias(t) => t.can_derive_copy(ctx, ()), + TypeKind::TemplateInstantiation(ref inst) => { + inst.can_derive_copy(ctx, ()) + } TypeKind::Comp(ref info) => { info.can_derive_copy(ctx, (item, self.layout(ctx))) } + TypeKind::Opaque => { + self.layout + .map_or(true, |l| l.opaque().can_derive_copy(ctx, ())) + } _ => true, } } @@ -724,6 +813,11 @@ pub enum TypeKind { /// A compound type, that is, a class, struct, or union. Comp(CompInfo), + /// An opaque type that we just don't understand. All usage of this shoulf + /// result in an opaque blob of bytes generated from the containing type's + /// layout. + Opaque, + /// An integer type, of a given kind. `bool` and `char` are also considered /// integers. Int(IntKind), @@ -760,9 +854,9 @@ pub enum TypeKind { /// A reference to a type, as in: int& foo(). Reference(ItemId), - /// An instantiation of an abstract template declaration (first tuple - /// member) with a set of concrete template arguments (second tuple member). - TemplateInstantiation(ItemId, Vec), + /// An instantiation of an abstract template definition with a set of + /// concrete template arguments. + TemplateInstantiation(TemplateInstantiation), /// A reference to a yet-to-resolve type. This stores the clang cursor /// itself, and postpones its resolution. @@ -772,7 +866,7 @@ pub enum TypeKind { /// /// see tests/headers/typeref.hpp to see somewhere where this is a problem. UnresolvedTypeRef(clang::Type, - Option, + clang::Cursor, /* parent_id */ Option), @@ -806,15 +900,18 @@ impl Type { match self.kind { TypeKind::Void => true, TypeKind::Comp(ref ci) => ci.is_unsized(ctx), + TypeKind::Opaque => self.layout.map_or(true, |l| l.size == 0), TypeKind::Array(inner, size) => { size == 0 || ctx.resolve_type(inner).is_unsized(ctx) } TypeKind::ResolvedTypeRef(inner) | TypeKind::Alias(inner) | - TypeKind::TemplateAlias(inner, _) | - TypeKind::TemplateInstantiation(inner, _) => { + TypeKind::TemplateAlias(inner, _) => { ctx.resolve_type(inner).is_unsized(ctx) } + TypeKind::TemplateInstantiation(ref inst) => { + ctx.resolve_type(inst.template_definition()).is_unsized(ctx) + } TypeKind::Named | TypeKind::Int(..) | TypeKind::Float(..) | @@ -843,17 +940,16 @@ impl Type { /// comments in every special case justify why they're there. pub fn from_clang_ty(potential_id: ItemId, ty: &clang::Type, - location: Option, + location: Cursor, parent_id: Option, ctx: &mut BindgenContext) -> Result, ParseError> { use clang_sys::*; { - let already_resolved = - ctx.builtin_or_resolved_ty(potential_id, - parent_id, - ty, - location); + let already_resolved = ctx.builtin_or_resolved_ty(potential_id, + parent_id, + ty, + Some(location)); if let Some(ty) = already_resolved { debug!("{:?} already resolved: {:?}", ty, location); return Ok(ParseResult::AlreadyResolved(ty)); @@ -874,409 +970,409 @@ impl Type { // Parse objc protocols as if they were interfaces let mut ty_kind = ty.kind(); - if let Some(loc) = location { - match loc.kind() { - CXCursor_ObjCProtocolDecl | - CXCursor_ObjCCategoryDecl => ty_kind = CXType_ObjCInterface, - _ => {} - } + match location.kind() { + CXCursor_ObjCProtocolDecl | + CXCursor_ObjCCategoryDecl => ty_kind = CXType_ObjCInterface, + _ => {} } - let kind = match ty_kind { - CXType_Unexposed if *ty != canonical_ty && - canonical_ty.kind() != CXType_Invalid && - ty.ret_type().is_none() && - // Sometime clang desugars some types more than - // what we need, specially with function - // pointers. - // - // We should also try the solution of inverting - // those checks instead of doing this, that is, - // something like: - // - // CXType_Unexposed if ty.ret_type().is_some() - // => { ... } - // - // etc. - !canonical_ty.spelling().contains("type-parameter") => { - debug!("Looking for canonical type: {:?}", canonical_ty); - return Self::from_clang_ty(potential_id, - &canonical_ty, - location, - parent_id, - ctx); - } - CXType_Unexposed | CXType_Invalid => { - // For some reason Clang doesn't give us any hint in some - // situations where we should generate a function pointer (see - // tests/headers/func_ptr_in_struct.h), so we do a guess here - // trying to see if it has a valid return type. - if ty.ret_type().is_some() { - let signature = try!(FunctionSig::from_ty(ty, - &location.unwrap_or(cursor), - ctx)); - TypeKind::Function(signature) - // Same here, with template specialisations we can safely - // assume this is a Comp(..) - } else if ty.is_fully_specialized_template() { - debug!("Template specialization: {:?}, {:?} {:?}", - ty, - location, - canonical_ty); - let complex = - CompInfo::from_ty(potential_id, ty, location, ctx) + if location.kind() == CXCursor_ClassTemplatePartialSpecialization { + // Sorry! (Not sorry) + warn!("Found a partial template specialization; bindgen does not \ + support partial template specialization! Constructing \ + opaque type instead."); + return Ok(ParseResult::New(Opaque::from_clang_ty(&canonical_ty), + None)); + } + + let kind = if location.kind() == CXCursor_TemplateRef || + (ty.template_args().is_some() && + ty_kind != CXType_Typedef) { + // This is a template instantiation. + let inst = TemplateInstantiation::from_ty(&ty, ctx); + TypeKind::TemplateInstantiation(inst) + } else { + match ty_kind { + CXType_Unexposed if *ty != canonical_ty && + canonical_ty.kind() != CXType_Invalid && + ty.ret_type().is_none() && + // Sometime clang desugars some types more than + // what we need, specially with function + // pointers. + // + // We should also try the solution of inverting + // those checks instead of doing this, that is, + // something like: + // + // CXType_Unexposed if ty.ret_type().is_some() + // => { ... } + // + // etc. + !canonical_ty.spelling().contains("type-parameter") => { + debug!("Looking for canonical type: {:?}", canonical_ty); + return Self::from_clang_ty(potential_id, + &canonical_ty, + location, + parent_id, + ctx); + } + CXType_Unexposed | CXType_Invalid => { + // For some reason Clang doesn't give us any hint in some + // situations where we should generate a function pointer (see + // tests/headers/func_ptr_in_struct.h), so we do a guess here + // trying to see if it has a valid return type. + if ty.ret_type().is_some() { + let signature = + try!(FunctionSig::from_ty(ty, &location, ctx)); + TypeKind::Function(signature) + // Same here, with template specialisations we can safely + // assume this is a Comp(..) + } else if ty.is_fully_instantiated_template() { + debug!("Template specialization: {:?}, {:?} {:?}", + ty, + location, + canonical_ty); + let complex = CompInfo::from_ty(potential_id, + ty, + Some(location), + ctx) .expect("C'mon"); - TypeKind::Comp(complex) - } else if let Some(location) = location { - match location.kind() { - CXCursor_ClassTemplatePartialSpecialization | - CXCursor_CXXBaseSpecifier | - CXCursor_ClassTemplate => { - if location.kind() == CXCursor_CXXBaseSpecifier { - // In the case we're parsing a base specifier - // inside an unexposed or invalid type, it means - // that we're parsing one of two things: - // - // * A template parameter. - // * A complex class that isn't exposed. - // - // This means, unfortunately, that there's no - // good way to differentiate between them. - // - // Probably we could try to look at the - // declaration and complicate more this logic, - // but we'll keep it simple... if it's a valid - // C++ identifier, we'll consider it as a - // template parameter. - // - // This is because: - // - // * We expect every other base that is a - // proper identifier (that is, a simple - // struct/union declaration), to be exposed, - // so this path can't be reached in that - // case. - // - // * Quite conveniently, complex base - // specifiers preserve their full names (that - // is: Foo instead of Foo). We can take - // advantage of this. - // - // If we find some edge case where this doesn't - // work (which I guess is unlikely, see the - // different test cases[1][2][3][4]), we'd need - // to find more creative ways of differentiating - // these two cases. - // - // [1]: inherit_named.hpp - // [2]: forward-inherit-struct-with-fields.hpp - // [3]: forward-inherit-struct.hpp - // [4]: inherit-namespaced.hpp - if location.spelling() - .chars() - .all(|c| c.is_alphanumeric() || c == '_') { - return Err(ParseError::Recurse); + TypeKind::Comp(complex) + } else { + match location.kind() { + CXCursor_CXXBaseSpecifier | + CXCursor_ClassTemplate => { + if location.kind() == + CXCursor_CXXBaseSpecifier { + // In the case we're parsing a base specifier + // inside an unexposed or invalid type, it means + // that we're parsing one of two things: + // + // * A template parameter. + // * A complex class that isn't exposed. + // + // This means, unfortunately, that there's no + // good way to differentiate between them. + // + // Probably we could try to look at the + // declaration and complicate more this logic, + // but we'll keep it simple... if it's a valid + // C++ identifier, we'll consider it as a + // template parameter. + // + // This is because: + // + // * We expect every other base that is a + // proper identifier (that is, a simple + // struct/union declaration), to be exposed, + // so this path can't be reached in that + // case. + // + // * Quite conveniently, complex base + // specifiers preserve their full names (that + // is: Foo instead of Foo). We can take + // advantage of this. + // + // If we find some edge case where this doesn't + // work (which I guess is unlikely, see the + // different test cases[1][2][3][4]), we'd need + // to find more creative ways of differentiating + // these two cases. + // + // [1]: inherit_named.hpp + // [2]: forward-inherit-struct-with-fields.hpp + // [3]: forward-inherit-struct.hpp + // [4]: inherit-namespaced.hpp + if location.spelling() + .chars() + .all(|c| { + c.is_alphanumeric() || c == '_' + }) { + return Err(ParseError::Recurse); + } + } else { + name = location.spelling(); } - } else { - name = location.spelling(); + + let complex = CompInfo::from_ty(potential_id, + ty, + Some(location), + ctx) + .expect("C'mon"); + TypeKind::Comp(complex) } - let complex = CompInfo::from_ty(potential_id, - ty, - Some(location), - ctx) - .expect("C'mon"); - TypeKind::Comp(complex) - } - CXCursor_TypeAliasTemplateDecl => { - debug!("TypeAliasTemplateDecl"); - - // We need to manually unwind this one. - let mut inner = Err(ParseError::Continue); - let mut args = vec![]; - - location.visit(|cur| { - match cur.kind() { - CXCursor_TypeAliasDecl => { - let current = cur.cur_type(); - - debug_assert!(current.kind() == - CXType_Typedef); - - name = current.spelling(); - - let inner_ty = cur.typedef_type() - .expect("Not valid Type?"); - inner = - Item::from_ty(&inner_ty, - Some(cur), - Some(potential_id), - ctx); - } - CXCursor_TemplateTypeParameter => { - // See the comment in src/ir/comp.rs - // about the same situation. - if cur.spelling().is_empty() { - return CXChildVisit_Continue; + CXCursor_TypeAliasTemplateDecl => { + debug!("TypeAliasTemplateDecl"); + + // We need to manually unwind this one. + let mut inner = Err(ParseError::Continue); + let mut args = vec![]; + + location.visit(|cur| { + match cur.kind() { + CXCursor_TypeAliasDecl => { + let current = cur.cur_type(); + + debug_assert!(current.kind() == + CXType_Typedef); + + name = current.spelling(); + + let inner_ty = cur.typedef_type() + .expect("Not valid Type?"); + inner = + Item::from_ty(&inner_ty, + cur, + Some(potential_id), + ctx); } - - let param = - Item::named_type(cur.spelling(), - potential_id, - ctx); - args.push(param); + CXCursor_TemplateTypeParameter => { + // See the comment in src/ir/comp.rs + // about the same situation. + if cur.spelling().is_empty() { + return CXChildVisit_Continue; + } + + let param = + Item::named_type(None, + cur, + ctx) + .expect("Item::named_type shouldn't \ + ever fail if we are looking \ + at a TemplateTypeParameter"); + args.push(param); + } + _ => {} } - _ => {} - } - CXChildVisit_Continue - }); - - let inner_type = match inner { - Ok(inner) => inner, - Err(..) => { - error!("Failed to parse template alias \ - {:?}", - location); - return Err(ParseError::Continue); - } - }; + CXChildVisit_Continue + }); + + let inner_type = match inner { + Ok(inner) => inner, + Err(..) => { + error!("Failed to parse template alias \ + {:?}", + location); + return Err(ParseError::Continue); + } + }; - TypeKind::TemplateAlias(inner_type, args) - } - CXCursor_TemplateRef => { - let referenced = location.referenced().unwrap(); - let referenced_ty = referenced.cur_type(); - - debug!("TemplateRef: location = {:?}; referenced = \ - {:?}; referenced_ty = {:?}", - location, - referenced, - referenced_ty); - - return Self::from_clang_ty(potential_id, - &referenced_ty, - Some(referenced), - parent_id, - ctx); - } - CXCursor_TypeRef => { - let referenced = location.referenced().unwrap(); - let referenced_ty = referenced.cur_type(); - let declaration = referenced_ty.declaration(); - - debug!("TypeRef: location = {:?}; referenced = \ - {:?}; referenced_ty = {:?}", - location, - referenced, - referenced_ty); - - let item = - Item::from_ty_or_ref_with_id(potential_id, - referenced_ty, - Some(declaration), - parent_id, - ctx); - return Ok(ParseResult::AlreadyResolved(item)); - } - CXCursor_NamespaceRef => { - return Err(ParseError::Continue); - } - _ => { - if ty.kind() == CXType_Unexposed { - warn!("Unexposed type {:?}, recursing inside, \ - loc: {:?}", - ty, - location); - return Err(ParseError::Recurse); + TypeKind::TemplateAlias(inner_type, args) + } + CXCursor_TemplateRef => { + let referenced = location.referenced().unwrap(); + let referenced_ty = referenced.cur_type(); + + debug!("TemplateRef: location = {:?}; referenced = \ + {:?}; referenced_ty = {:?}", + location, + referenced, + referenced_ty); + + return Self::from_clang_ty(potential_id, + &referenced_ty, + referenced, + parent_id, + ctx); } + CXCursor_TypeRef => { + let referenced = location.referenced().unwrap(); + let referenced_ty = referenced.cur_type(); + let declaration = referenced_ty.declaration(); + + debug!("TypeRef: location = {:?}; referenced = \ + {:?}; referenced_ty = {:?}", + location, + referenced, + referenced_ty); + + let item = + Item::from_ty_or_ref_with_id(potential_id, + referenced_ty, + declaration, + parent_id, + ctx); + return Ok(ParseResult::AlreadyResolved(item)); + } + CXCursor_NamespaceRef => { + return Err(ParseError::Continue); + } + _ => { + if ty.kind() == CXType_Unexposed { + warn!("Unexposed type {:?}, recursing inside, \ + loc: {:?}", + ty, + location); + return Err(ParseError::Recurse); + } - // If the type name is empty we're probably - // over-recursing to find a template parameter name - // or something like that, so just don't be too - // noisy with it since it causes confusion, see for - // example the discussion in: - // - // https://github.com/jamesmunns/teensy3-rs/issues/9 - if !ty.spelling().is_empty() { - warn!("invalid type {:?}", ty); - } else { warn!("invalid type {:?}", ty); + return Err(ParseError::Continue); } - return Err(ParseError::Continue); } } - } else { - // TODO: Don't duplicate this! - if ty.kind() == CXType_Unexposed { - warn!("Unexposed type {:?}, recursing inside", ty); - return Err(ParseError::Recurse); + } + CXType_Auto => { + if canonical_ty == *ty { + debug!("Couldn't find deduced type: {:?}", ty); + return Err(ParseError::Continue); } - if !ty.spelling().is_empty() { - warn!("invalid type {:?}", ty); - } else { - warn!("invalid type {:?}", ty); + return Self::from_clang_ty(potential_id, + &canonical_ty, + location, + parent_id, + ctx); + } + // NOTE: We don't resolve pointers eagerly because the pointee type + // might not have been parsed, and if it contains templates or + // something else we might get confused, see the comment inside + // TypeRef. + // + // We might need to, though, if the context is already in the + // process of resolving them. + CXType_ObjCObjectPointer | + CXType_MemberPointer | + CXType_Pointer => { + // Fun fact: the canonical type of a pointer type may sometimes + // contain information we need but isn't present in the concrete + // type (yeah, I'm equally wat'd). + // + // Yet we still have trouble if we unconditionally trust the + // canonical type, like too-much desugaring (sigh). + // + // See tests/headers/call-conv-field.h for an example. + // + // Since for now the only identifier cause of breakage is the + // ABI for function pointers, and different ABI mixed with + // problematic stuff like that one is _extremely_ unlikely and + // can be bypassed via blacklisting, we do the check explicitly + // (as hacky as it is). + // + // Yet we should probably (somehow) get the best of both worlds, + // presumably special-casing function pointers as a whole, yet + // someone is going to need to care about typedef'd function + // pointers, etc, which isn't trivial given function pointers + // are mostly unexposed. I don't have the time for it right now. + let mut pointee = ty.pointee_type().unwrap(); + let canonical_pointee = canonical_ty.pointee_type() + .unwrap(); + if pointee.call_conv() != canonical_pointee.call_conv() { + pointee = canonical_pointee; } - return Err(ParseError::Continue); + let inner = + Item::from_ty_or_ref(pointee, location, None, ctx); + TypeKind::Pointer(inner) } - } - CXType_Auto => { - if canonical_ty == *ty { - debug!("Couldn't find deduced type: {:?}", ty); - return Err(ParseError::Continue); + CXType_BlockPointer => TypeKind::BlockPointer, + // XXX: RValueReference is most likely wrong, but I don't think we + // can even add bindings for that, so huh. + CXType_RValueReference | + CXType_LValueReference => { + let inner = Item::from_ty_or_ref(ty.pointee_type() + .unwrap(), + location, + None, + ctx); + TypeKind::Reference(inner) } - - return Self::from_clang_ty(potential_id, - &canonical_ty, - location, - parent_id, - ctx); - } - // NOTE: We don't resolve pointers eagerly because the pointee type - // might not have been parsed, and if it contains templates or - // something else we might get confused, see the comment inside - // TypeRef. - // - // We might need to, though, if the context is already in the - // process of resolving them. - CXType_ObjCObjectPointer | - CXType_MemberPointer | - CXType_Pointer => { - // Fun fact: the canonical type of a pointer type may sometimes - // contain information we need but isn't present in the concrete - // type (yeah, I'm equally wat'd). - // - // Yet we still have trouble if we unconditionally trust the - // canonical type, like too-much desugaring (sigh). - // - // See tests/headers/call-conv-field.h for an example. - // - // Since for now the only identifier cause of breakage is the - // ABI for function pointers, and different ABI mixed with - // problematic stuff like that one is _extremely_ unlikely and - // can be bypassed via blacklisting, we do the check explicitly - // (as hacky as it is). - // - // Yet we should probably (somehow) get the best of both worlds, - // presumably special-casing function pointers as a whole, yet - // someone is going to need to care about typedef'd function - // pointers, etc, which isn't trivial given function pointers - // are mostly unexposed. I don't have the time for it right now. - let mut pointee = ty.pointee_type().unwrap(); - let canonical_pointee = canonical_ty.pointee_type().unwrap(); - if pointee.call_conv() != canonical_pointee.call_conv() { - pointee = canonical_pointee; + // XXX DependentSizedArray is wrong + CXType_VariableArray | + CXType_DependentSizedArray => { + let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(), + location, + None, + ctx) + .expect("Not able to resolve array element?"); + TypeKind::Pointer(inner) } - let inner = Item::from_ty_or_ref(pointee, - location, - None, - ctx); - TypeKind::Pointer(inner) - } - CXType_BlockPointer => TypeKind::BlockPointer, - // XXX: RValueReference is most likely wrong, but I don't think we - // can even add bindings for that, so huh. - CXType_RValueReference | - CXType_LValueReference => { - let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(), - location, - None, - ctx); - TypeKind::Reference(inner) - } - // XXX DependentSizedArray is wrong - CXType_VariableArray | - CXType_DependentSizedArray => { - let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(), - location, - None, - ctx) - .expect("Not able to resolve array element?"); - TypeKind::Pointer(inner) - } - CXType_IncompleteArray => { - let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(), - location, - None, - ctx) - .expect("Not able to resolve array element?"); - TypeKind::Array(inner, 0) - } - CXType_FunctionNoProto | - CXType_FunctionProto => { - let signature = try!(FunctionSig::from_ty(ty, - &location.unwrap_or(cursor), - ctx)); - TypeKind::Function(signature) - } - CXType_Typedef => { - let inner = cursor.typedef_type().expect("Not valid Type?"); - let inner = Item::from_ty_or_ref(inner, location, None, ctx); - TypeKind::Alias(inner) - } - CXType_Enum => { - let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?"); + CXType_IncompleteArray => { + let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(), + location, + None, + ctx) + .expect("Not able to resolve array element?"); + TypeKind::Array(inner, 0) + } + CXType_FunctionNoProto | + CXType_FunctionProto => { + let signature = + try!(FunctionSig::from_ty(ty, &location, ctx)); + TypeKind::Function(signature) + } + CXType_Typedef => { + let inner = cursor.typedef_type().expect("Not valid Type?"); + let inner = + Item::from_ty_or_ref(inner, location, None, ctx); + TypeKind::Alias(inner) + } + CXType_Enum => { + let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?"); - if name.is_empty() { - let pretty_name = ty.spelling(); - if Self::is_valid_identifier(&pretty_name) { - name = pretty_name; + if name.is_empty() { + let pretty_name = ty.spelling(); + if Self::is_valid_identifier(&pretty_name) { + name = pretty_name; + } } - } - TypeKind::Enum(enum_) - } - CXType_Record => { - let complex = - CompInfo::from_ty(potential_id, ty, location, ctx) + TypeKind::Enum(enum_) + } + CXType_Record => { + let complex = CompInfo::from_ty(potential_id, + ty, + Some(location), + ctx) .expect("Not a complex type?"); - if name.is_empty() { - // The pretty-printed name may contain typedefed name, - // but may also be "struct (anonymous at .h:1)" - let pretty_name = ty.spelling(); - if Self::is_valid_identifier(&pretty_name) { - name = pretty_name; + if name.is_empty() { + // The pretty-printed name may contain typedefed name, + // but may also be "struct (anonymous at .h:1)" + let pretty_name = ty.spelling(); + if Self::is_valid_identifier(&pretty_name) { + name = pretty_name; + } } - } - TypeKind::Comp(complex) - } - // FIXME: We stub vectors as arrays since in 99% of the cases the - // layout is going to be correct, and there's no way we can generate - // vector types properly in Rust for now. - // - // That being said, that should be fixed eventually. - CXType_Vector | - CXType_ConstantArray => { - let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(), - location, - None, - ctx) - .expect("Not able to resolve array element?"); - TypeKind::Array(inner, ty.num_elements().unwrap()) - } - CXType_Elaborated => { - return Self::from_clang_ty(potential_id, - &ty.named(), - location, - parent_id, - ctx); - } - CXType_ObjCId => TypeKind::ObjCId, - CXType_ObjCSel => TypeKind::ObjCSel, - CXType_ObjCClass | - CXType_ObjCInterface => { - let interface = ObjCInterface::from_ty(&location.unwrap(), ctx) - .expect("Not a valid objc interface?"); - name = interface.rust_name(); - TypeKind::ObjCInterface(interface) - } - _ => { - error!("unsupported type: kind = {:?}; ty = {:?}; at {:?}", - ty.kind(), - ty, - location); - return Err(ParseError::Continue); + TypeKind::Comp(complex) + } + // FIXME: We stub vectors as arrays since in 99% of the cases the + // layout is going to be correct, and there's no way we can generate + // vector types properly in Rust for now. + // + // That being said, that should be fixed eventually. + CXType_Vector | + CXType_ConstantArray => { + let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(), + location, + None, + ctx) + .expect("Not able to resolve array element?"); + TypeKind::Array(inner, ty.num_elements().unwrap()) + } + CXType_Elaborated => { + return Self::from_clang_ty(potential_id, + &ty.named(), + location, + parent_id, + ctx); + } + CXType_ObjCId => TypeKind::ObjCId, + CXType_ObjCSel => TypeKind::ObjCSel, + CXType_ObjCClass | + CXType_ObjCInterface => { + let interface = ObjCInterface::from_ty(&location, ctx) + .expect("Not a valid objc interface?"); + name = interface.rust_name(); + TypeKind::ObjCInterface(interface) + } + _ => { + error!("unsupported type: kind = {:?}; ty = {:?}; at {:?}", + ty.kind(), + ty, + location); + return Err(ParseError::Continue); + } } }; @@ -1306,14 +1402,12 @@ impl Trace for Type { TypeKind::TemplateAlias(inner, ref template_params) => { tracer.visit_kind(inner, EdgeKind::TypeReference); for &item in template_params { - tracer.visit_kind(item, EdgeKind::TemplateParameterDefinition); + tracer.visit_kind(item, + EdgeKind::TemplateParameterDefinition); } } - TypeKind::TemplateInstantiation(inner, ref template_args) => { - tracer.visit_kind(inner, EdgeKind::TemplateDeclaration); - for &item in template_args { - tracer.visit_kind(item, EdgeKind::TemplateArgument); - } + TypeKind::TemplateInstantiation(ref inst) => { + inst.trace(context, tracer, &()); } TypeKind::Comp(ref ci) => ci.trace(context, tracer, item), TypeKind::Function(ref sig) => sig.trace(context, tracer, &()), @@ -1331,6 +1425,7 @@ impl Trace for Type { } // None of these variants have edges to other items and types. + TypeKind::Opaque | TypeKind::UnresolvedTypeRef(_, _, None) | TypeKind::Named | TypeKind::Void | diff --git a/src/ir/var.rs b/src/ir/var.rs index 7b610da480..350bfe4ae7 100644 --- a/src/ir/var.rs +++ b/src/ir/var.rs @@ -87,15 +87,20 @@ impl Var { } impl DotAttributes for Var { - fn dot_attributes(&self, _ctx: &BindgenContext, out: &mut W) -> io::Result<()> - where W: io::Write + fn dot_attributes(&self, + _ctx: &BindgenContext, + out: &mut W) + -> io::Result<()> + where W: io::Write, { if self.is_const { try!(writeln!(out, "consttrue")); } if let Some(ref mangled) = self.mangled_name { - try!(writeln!(out, "mangled name{}", mangled)); + try!(writeln!(out, + "mangled name{}", + mangled)); } Ok(()) @@ -202,7 +207,7 @@ impl ClangSubItemParser for Var { // XXX this is redundant, remove! let is_const = ty.is_const(); - let ty = match Item::from_ty(&ty, Some(cursor), None, ctx) { + let ty = match Item::from_ty(&ty, cursor, None, ctx) { Ok(ty) => ty, Err(e) => { assert_eq!(ty.kind(), diff --git a/src/parse.rs b/src/parse.rs index 0e4164f0b3..73bb7b25d8 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -49,7 +49,7 @@ pub trait ClangItemParser: Sized { /// Parse this item from the given Clang type. fn from_ty(ty: &clang::Type, - location: Option, + location: clang::Cursor, parent: Option, ctx: &mut BindgenContext) -> Result; @@ -58,7 +58,7 @@ pub trait ClangItemParser: Sized { /// newly parsed item. fn from_ty_with_id(id: ItemId, ty: &clang::Type, - location: Option, + location: clang::Cursor, parent: Option, ctx: &mut BindgenContext) -> Result; @@ -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, + location: clang::Cursor, parent_id: Option, 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, + location: clang::Cursor, parent_id: Option, context: &mut BindgenContext) -> ItemId; /// Create a named template type. - fn named_type(name: S, - parent: ItemId, - context: &mut BindgenContext) - -> ItemId - where S: Into; - - /// Identical to `named_type`, but use `id` as the resulting item's - /// `ItemId`. - fn named_type_with_id(id: ItemId, - name: S, - parent: ItemId, - context: &mut BindgenContext) - -> ItemId - where S: Into; + fn named_type(with_id: Option, + location: clang::Cursor, + ctx: &mut BindgenContext) + -> Option; /// Create a builtin type. fn builtin_type(kind: TypeKind, diff --git a/src/uses.rs b/src/uses.rs index 47f72da6fb..0799011b36 100644 --- a/src/uses.rs +++ b/src/uses.rs @@ -37,6 +37,7 @@ use ir::context::BindgenContext; use ir::item::{Item, ItemAncestors, ItemCanonicalName}; +use ir::ty::TemplateDeclaration; use std::io; // Like `canonical_path`, except we always take namespaces into account, ignore @@ -83,9 +84,9 @@ pub fn generate_dummy_uses(ctx: &mut BindgenContext, // these. !ty.is_builtin_or_named() && // And finally, we won't be creating any dummy - // specializations, so ignore template declarations and - // partial specializations. - item.applicable_template_args(ctx).is_empty() + // instantiations, so ignore template declarations and + // instantiations. + item.all_template_params(ctx).is_none() } else { false } diff --git a/tests/expectations/lib.rs b/tests/expectations/lib.rs old mode 100644 new mode 100755 index e69de29bb2..562dc5548d --- a/tests/expectations/lib.rs +++ b/tests/expectations/lib.rs @@ -0,0 +1,3 @@ +#![allow(dead_code)] +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] diff --git a/tests/expectations/tests/381-decltype-alias.rs b/tests/expectations/tests/381-decltype-alias.rs index 45b0cfdd55..632cdd312b 100644 --- a/tests/expectations/tests/381-decltype-alias.rs +++ b/tests/expectations/tests/381-decltype-alias.rs @@ -5,11 +5,8 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct std_allocator_traits<_Alloc> { +#[derive(Debug, Default, Copy, Clone)] +pub struct std_allocator_traits { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData<_Alloc>, -} -impl <_Alloc> Default for std_allocator_traits<_Alloc> { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } +pub type std_allocator_traits___size_type<_Alloc> = _Alloc; diff --git a/tests/expectations/tests/anon_enum_trait.rs b/tests/expectations/tests/anon_enum_trait.rs index 31eaca8399..92c697a884 100644 --- a/tests/expectations/tests/anon_enum_trait.rs +++ b/tests/expectations/tests/anon_enum_trait.rs @@ -5,10 +5,9 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DataType<_Tp> { +#[derive(Debug, Default, Copy, Clone)] +pub struct DataType { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData<_Tp>, } pub type DataType_value_type<_Tp> = _Tp; pub type DataType_work_type<_Tp> = DataType_value_type<_Tp>; @@ -27,9 +26,6 @@ pub const DataType_type_: DataType__bindgen_ty_1 = #[repr(i32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum DataType__bindgen_ty_1 { generic_type = 0, } -impl <_Tp> Default for DataType<_Tp> { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} #[repr(C)] #[derive(Debug, Default, Copy)] pub struct Foo { diff --git a/tests/expectations/tests/anon_union.rs b/tests/expectations/tests/anon_union.rs index 4418bc7780..eb600cc737 100644 --- a/tests/expectations/tests/anon_union.rs +++ b/tests/expectations/tests/anon_union.rs @@ -30,12 +30,11 @@ impl ::std::fmt::Debug for __BindgenUnionField { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct TErrorResult { +pub struct TErrorResult { pub mResult: ::std::os::raw::c_int, - pub __bindgen_anon_1: TErrorResult__bindgen_ty_1, + pub __bindgen_anon_1: TErrorResult__bindgen_ty_1, pub mMightHaveUnreported: bool, pub mUnionState: TErrorResult_UnionState, - pub _phantom_0: ::std::marker::PhantomData, } 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 { +pub struct TErrorResult_Message { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] -pub struct TErrorResult_DOMExceptionInfo { +pub struct TErrorResult_DOMExceptionInfo { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] -pub struct TErrorResult__bindgen_ty_1 { - pub mMessage: __BindgenUnionField<*mut TErrorResult_Message>, - pub mDOMExceptionInfo: __BindgenUnionField<*mut TErrorResult_DOMExceptionInfo>, +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, } -impl Default for TErrorResult { +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::>() , - 24usize , concat ! ( +fn __bindgen_test_layout_TErrorResult_instantiation_21() { + assert_eq!(::std::mem::size_of::() , 24usize , concat ! ( "Size of template specialization: " , stringify ! ( - TErrorResult<::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() , - 8usize , concat ! ( + TErrorResult ) )); + assert_eq!(::std::mem::align_of::() , 8usize , concat ! ( "Alignment of template specialization: " , stringify ! ( - TErrorResult<::std::os::raw::c_int> ) )); + TErrorResult ) )); } diff --git a/tests/expectations/tests/auto.rs b/tests/expectations/tests/auto.rs index 4551f70314..7f9bbf44ad 100644 --- a/tests/expectations/tests/auto.rs +++ b/tests/expectations/tests/auto.rs @@ -21,13 +21,9 @@ impl Clone for Foo { fn clone(&self) -> Self { *self } } #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Bar { +#[derive(Debug, Default, Copy, Clone)] +pub struct Bar { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for Bar { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } extern "C" { #[link_name = "_Z5Test2v"] diff --git a/tests/expectations/tests/bad-namespace-parenthood-inheritance.rs b/tests/expectations/tests/bad-namespace-parenthood-inheritance.rs index b0c91e8ca9..4074dd02eb 100644 --- a/tests/expectations/tests/bad-namespace-parenthood-inheritance.rs +++ b/tests/expectations/tests/bad-namespace-parenthood-inheritance.rs @@ -5,13 +5,9 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct std_char_traits<_CharT> { +#[derive(Debug, Default, Copy, Clone)] +pub struct std_char_traits { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData<_CharT>, -} -impl <_CharT> Default for std_char_traits<_CharT> { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] #[derive(Debug, Default, Copy)] diff --git a/tests/expectations/tests/class_nested.rs b/tests/expectations/tests/class_nested.rs index 6ddcf91b23..b92976f6a0 100644 --- a/tests/expectations/tests/class_nested.rs +++ b/tests/expectations/tests/class_nested.rs @@ -77,7 +77,7 @@ extern "C" { pub static mut var: A_B; } #[test] -fn __bindgen_test_layout_template_1() { +fn __bindgen_test_layout_A_D_instantiation_16() { assert_eq!(::std::mem::size_of::>() , 4usize , concat ! ( "Size of template specialization: " , stringify ! ( diff --git a/tests/expectations/tests/class_with_dtor.rs b/tests/expectations/tests/class_with_dtor.rs index 4c1d271878..495889f256 100644 --- a/tests/expectations/tests/class_with_dtor.rs +++ b/tests/expectations/tests/class_with_dtor.rs @@ -34,7 +34,7 @@ impl Default for WithoutDtor { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[test] -fn __bindgen_test_layout_template_1() { +fn __bindgen_test_layout_HandleWithDtor_instantiation_10() { assert_eq!(::std::mem::size_of::>() , 8usize , concat ! ( "Size of template specialization: " , stringify ! ( diff --git a/tests/expectations/tests/constant-non-specialized-tp.rs b/tests/expectations/tests/constant-non-specialized-tp.rs index f2aa5a7584..a17e261ba7 100644 --- a/tests/expectations/tests/constant-non-specialized-tp.rs +++ b/tests/expectations/tests/constant-non-specialized-tp.rs @@ -5,26 +5,17 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Test { +#[derive(Debug, Default, Copy, Clone)] +pub struct Test { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for Test { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Outer { +#[derive(Debug, Default, Copy, Clone)] +pub struct Outer { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] -pub struct Outer_Inner { +pub struct Outer_Inner { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for Outer { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/constructor-tp.rs b/tests/expectations/tests/constructor-tp.rs index ee04d3c5d9..6ba52f22d1 100644 --- a/tests/expectations/tests/constructor-tp.rs +++ b/tests/expectations/tests/constructor-tp.rs @@ -5,13 +5,9 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo { +#[derive(Debug, Default, Copy, Clone)] +pub struct Foo { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] #[derive(Debug, Default, Copy)] diff --git a/tests/expectations/tests/crtp.rs b/tests/expectations/tests/crtp.rs index 7143f50e6d..8a83e19850 100644 --- a/tests/expectations/tests/crtp.rs +++ b/tests/expectations/tests/crtp.rs @@ -5,13 +5,9 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Base { +#[derive(Debug, Default, Copy, Clone)] +pub struct Base { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for Base { - 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 { +#[derive(Debug, Default)] +pub struct BaseWithDestructor { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for BaseWithDestructor { - 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::>() , 1usize , concat ! ( - "Size of template specialization: " , stringify ! ( - Base ) )); - assert_eq!(::std::mem::align_of::>() , 1usize , concat ! ( - "Alignment of template specialization: " , stringify ! ( - Base ) )); +fn __bindgen_test_layout_Base_instantiation_9() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of template specialization: " , stringify ! ( Base ) )); + assert_eq!(::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( Base ) + )); } #[test] -fn __bindgen_test_layout_template_2() { - assert_eq!(::std::mem::size_of::>() - , 1usize , concat ! ( +fn __bindgen_test_layout_BaseWithDestructor_instantiation_12() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! + ( "Size of template specialization: " , stringify ! ( - BaseWithDestructor ) )); - assert_eq!(::std::mem::align_of::>() - , 1usize , concat ! ( + BaseWithDestructor ) )); + assert_eq!(::std::mem::align_of::() , 1usize , concat + ! ( "Alignment of template specialization: " , stringify ! ( - BaseWithDestructor ) )); + BaseWithDestructor ) )); } diff --git a/tests/expectations/tests/dash_language.rs b/tests/expectations/tests/dash_language.rs index 24df101487..385c39c6a3 100644 --- a/tests/expectations/tests/dash_language.rs +++ b/tests/expectations/tests/dash_language.rs @@ -5,11 +5,7 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo { +#[derive(Debug, Default, Copy, Clone)] +pub struct Foo { pub bar: ::std::os::raw::c_int, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/empty_template_param_name.rs b/tests/expectations/tests/empty_template_param_name.rs index 6ee8fce396..2bd5a570c9 100644 --- a/tests/expectations/tests/empty_template_param_name.rs +++ b/tests/expectations/tests/empty_template_param_name.rs @@ -6,11 +6,7 @@ pub type __void_t = ::std::os::raw::c_void; #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __iterator_traits<_Iterator> { +#[derive(Debug, Default, Copy, Clone)] +pub struct __iterator_traits { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData<_Iterator>, -} -impl <_Iterator> Default for __iterator_traits<_Iterator> { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/enum_in_template_with_typedef.rs b/tests/expectations/tests/enum_in_template_with_typedef.rs index e4725b8386..2b95696399 100644 --- a/tests/expectations/tests/enum_in_template_with_typedef.rs +++ b/tests/expectations/tests/enum_in_template_with_typedef.rs @@ -5,10 +5,9 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct std_fbstring_core { +#[derive(Debug, Default, Copy, Clone)] +pub struct std_fbstring_core { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } 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 Default for std_fbstring_core { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} diff --git a/tests/expectations/tests/eval-variadic-template-parameter.rs b/tests/expectations/tests/eval-variadic-template-parameter.rs index acc6f34c61..701aab9fec 100644 --- a/tests/expectations/tests/eval-variadic-template-parameter.rs +++ b/tests/expectations/tests/eval-variadic-template-parameter.rs @@ -5,11 +5,7 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct B { +#[derive(Debug, Default, Copy, Clone)] +pub struct B { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for B { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/forward-inherit-struct.rs b/tests/expectations/tests/forward-inherit-struct.rs index 1057e70c06..322854dd85 100644 --- a/tests/expectations/tests/forward-inherit-struct.rs +++ b/tests/expectations/tests/forward-inherit-struct.rs @@ -6,19 +6,14 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Rooted { +pub struct Rooted { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } -impl Default for Rooted { +impl Default for Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct js_RootedBase { +#[derive(Debug, Default, Copy, Clone)] +pub struct js_RootedBase { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for js_RootedBase { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/in_class_typedef.rs b/tests/expectations/tests/in_class_typedef.rs index 3634a6313c..613c8cab72 100644 --- a/tests/expectations/tests/in_class_typedef.rs +++ b/tests/expectations/tests/in_class_typedef.rs @@ -5,20 +5,15 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo { +#[derive(Debug, Default, Copy, Clone)] +pub struct Foo { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } pub type Foo_elem_type = T; pub type Foo_ptr_type = *mut T; #[repr(C)] #[derive(Debug, Default, Copy, Clone)] -pub struct Foo_Bar { +pub struct Foo_Bar { pub x: ::std::os::raw::c_int, pub y: ::std::os::raw::c_int, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/inherit-namespaced.rs b/tests/expectations/tests/inherit-namespaced.rs index e5d5f875ee..fcd8de9731 100644 --- a/tests/expectations/tests/inherit-namespaced.rs +++ b/tests/expectations/tests/inherit-namespaced.rs @@ -5,20 +5,15 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct js_RootedBase { +#[derive(Debug, Default, Copy, Clone)] +pub struct js_RootedBase { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for js_RootedBase { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Rooted { +pub struct Rooted { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } -impl Default for Rooted { +impl Default for Rooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/inherit_named.rs b/tests/expectations/tests/inherit_named.rs index 31c4bee911..703df9ea54 100644 --- a/tests/expectations/tests/inherit_named.rs +++ b/tests/expectations/tests/inherit_named.rs @@ -5,13 +5,9 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Wohoo { +#[derive(Debug, Default, Copy, Clone)] +pub struct Wohoo { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for Wohoo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] #[derive(Debug, Copy, Clone)] diff --git a/tests/expectations/tests/inner_template_self.rs b/tests/expectations/tests/inner_template_self.rs index 3510fa7c77..d75c280d05 100644 --- a/tests/expectations/tests/inner_template_self.rs +++ b/tests/expectations/tests/inner_template_self.rs @@ -6,17 +6,17 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct LinkedList { - pub next: *mut LinkedList, - pub prev: *mut LinkedList, +pub struct LinkedList { + pub next: *mut LinkedList, + pub prev: *mut LinkedList, } -impl Default for LinkedList { +impl Default for LinkedList { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] #[derive(Debug, Copy)] pub struct InstantiateIt { - pub m_list: LinkedList<::std::os::raw::c_int>, + pub m_list: LinkedList, } #[test] fn bindgen_test_layout_InstantiateIt() { diff --git a/tests/expectations/tests/issue-358.rs b/tests/expectations/tests/issue-358.rs index d3be3c4374..e574bd017e 100644 --- a/tests/expectations/tests/issue-358.rs +++ b/tests/expectations/tests/issue-358.rs @@ -6,11 +6,10 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct JS_PersistentRooted { +pub struct JS_PersistentRooted { pub _base: a, - pub _phantom_0: ::std::marker::PhantomData, } -impl Default for JS_PersistentRooted { +impl Default for JS_PersistentRooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] diff --git a/tests/expectations/tests/issue-446.rs b/tests/expectations/tests/issue-446.rs index fa736bccf6..13204c1ac2 100644 --- a/tests/expectations/tests/issue-446.rs +++ b/tests/expectations/tests/issue-446.rs @@ -6,17 +6,17 @@ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct List { - pub next: *mut List, +pub struct List { + pub next: *mut List, } -impl Default for List { +impl Default for List { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct PersistentRooted { - pub root_list: List>, +pub struct PersistentRooted { + pub root_list: List, } -impl Default for PersistentRooted { +impl Default for PersistentRooted { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/issue-493.rs b/tests/expectations/tests/issue-493.rs index a2246ca6a3..155834a304 100644 --- a/tests/expectations/tests/issue-493.rs +++ b/tests/expectations/tests/issue-493.rs @@ -29,28 +29,21 @@ impl ::std::fmt::Debug for __BindgenUnionField { } } #[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, 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>, - pub __lxx: __BindgenUnionField>, +pub struct basic_string___ulx { + pub __lx: __BindgenUnionField, + pub __lxx: __BindgenUnionField, 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>, - pub __s: __BindgenUnionField>, - pub __r: __BindgenUnionField>, +pub struct basic_string___rep__bindgen_ty_1 { + pub __l: __BindgenUnionField, + pub __s: __BindgenUnionField, + pub __r: __BindgenUnionField, pub bindgen_union_field: [u8; 0usize], - pub _phantom_0: ::std::marker::PhantomData<_CharT>, - pub _phantom_1: ::std::marker::PhantomData<_Traits>, - pub _phantom_2: ::std::marker::PhantomData<_Allocator>, -} -impl <_CharT, _Traits, _Allocator> Default for - basic_string___rep__bindgen_ty_1<_CharT, _Traits, _Allocator> { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } -impl <_CharT, _Traits, _Allocator> Default for - basic_string___rep<_CharT, _Traits, _Allocator> { +impl Default for basic_string___rep__bindgen_ty_1 { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } -impl <_CharT, _Traits, _Allocator> Default for - basic_string<_CharT, _Traits, _Allocator> { +impl Default for basic_string___rep { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/issue-544-stylo-creduce-2.rs b/tests/expectations/tests/issue-544-stylo-creduce-2.rs new file mode 100644 index 0000000000..c0fae8452e --- /dev/null +++ b/tests/expectations/tests/issue-544-stylo-creduce-2.rs @@ -0,0 +1,15 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +pub struct Foo { + pub member: Foo_SecondAlias, +} +pub type Foo_FirstAlias = [u8; 0usize]; +pub type Foo_SecondAlias = [u8; 0usize]; +impl Default for Foo { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/issue-544-stylo-creduce.rs b/tests/expectations/tests/issue-544-stylo-creduce.rs new file mode 100644 index 0000000000..88cc0d87d0 --- /dev/null +++ b/tests/expectations/tests/issue-544-stylo-creduce.rs @@ -0,0 +1,14 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct a { + pub _address: u8, +} +impl Clone for a { + fn clone(&self) -> Self { *self } +} diff --git a/tests/expectations/tests/maddness-is-avoidable.rs b/tests/expectations/tests/maddness-is-avoidable.rs index 2fb5e540e3..09c1c921db 100644 --- a/tests/expectations/tests/maddness-is-avoidable.rs +++ b/tests/expectations/tests/maddness-is-avoidable.rs @@ -5,22 +5,12 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtr { +#[derive(Debug, Default, Copy, Clone)] +pub struct RefPtr { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtr_Proxy { +#[derive(Debug, Default, Copy, Clone)] +pub struct RefPtr_Proxy { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, - pub _phantom_1: ::std::marker::PhantomData, - pub _phantom_2: ::std::marker::PhantomData, -} -impl Default for RefPtr_Proxy { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for RefPtr { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/no_copy.rs b/tests/expectations/tests/no_copy.rs index 3590241fce..a75f891ce5 100644 --- a/tests/expectations/tests/no_copy.rs +++ b/tests/expectations/tests/no_copy.rs @@ -6,11 +6,7 @@ /**
*/ #[repr(C)] -#[derive(Debug)] -pub struct CopiableButWait { +#[derive(Debug, Default)] +pub struct CopiableButWait { pub whatever: ::std::os::raw::c_int, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for CopiableButWait { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/opaque_pointer.rs b/tests/expectations/tests/opaque_pointer.rs index 15b01db448..2e1890a8b4 100644 --- a/tests/expectations/tests/opaque_pointer.rs +++ b/tests/expectations/tests/opaque_pointer.rs @@ -27,16 +27,15 @@ impl Clone for OtherOpaque { */ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Opaque { - pub _phantom_0: ::std::marker::PhantomData, +pub struct Opaque { } -impl Default for Opaque { +impl Default for Opaque { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] #[derive(Debug, Copy)] pub struct WithOpaquePtr { - pub whatever: *mut Opaque<::std::os::raw::c_int>, + pub whatever: *mut (), pub other: u32, pub t: OtherOpaque, } diff --git a/tests/expectations/tests/opaque_typedef.rs b/tests/expectations/tests/opaque_typedef.rs index d6d5ac5de6..51951faf14 100644 --- a/tests/expectations/tests/opaque_typedef.rs +++ b/tests/expectations/tests/opaque_typedef.rs @@ -5,14 +5,10 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RandomTemplate { +#[derive(Debug, Default, Copy, Clone)] +pub struct RandomTemplate { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for RandomTemplate { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } /**
*/ pub type ShouldBeOpaque = [u8; 0usize]; -pub type ShouldNotBeOpaque = RandomTemplate; +pub type ShouldNotBeOpaque = RandomTemplate; diff --git a/tests/expectations/tests/partial-specialization-and-inheritance.rs b/tests/expectations/tests/partial-specialization-and-inheritance.rs new file mode 100644 index 0000000000..2422593465 --- /dev/null +++ b/tests/expectations/tests/partial-specialization-and-inheritance.rs @@ -0,0 +1,44 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Base { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Derived { + pub b: bool, +} +#[test] +fn __bindgen_test_layout__bindgen_ty_id_20_instantiation_14() { + assert_eq!(::std::mem::size_of::<[u32; 2usize]>() , 8usize , concat ! ( + "Size of template specialization: " , stringify ! ( + [u32; 2usize] ) )); + assert_eq!(::std::mem::align_of::<[u32; 2usize]>() , 4usize , concat ! ( + "Alignment of template specialization: " , stringify ! ( + [u32; 2usize] ) )); +} +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct Usage { + pub _address: u8, +} +extern "C" { + #[link_name = "_ZN5Usage13static_memberE"] + pub static mut Usage_static_member: [u32; 2usize]; +} +#[test] +fn bindgen_test_layout_Usage() { + assert_eq!(::std::mem::size_of::() , 1usize , concat ! ( + "Size of: " , stringify ! ( Usage ) )); + assert_eq! (::std::mem::align_of::() , 1usize , concat ! ( + "Alignment of " , stringify ! ( Usage ) )); +} +impl Clone for Usage { + fn clone(&self) -> Self { *self } +} diff --git a/tests/expectations/tests/replace_use.rs b/tests/expectations/tests/replace_use.rs index d93121d3dd..6cdc326383 100644 --- a/tests/expectations/tests/replace_use.rs +++ b/tests/expectations/tests/replace_use.rs @@ -8,18 +8,14 @@ *
*/ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct nsTArray { +#[derive(Debug, Default, Copy, Clone)] +pub struct nsTArray { pub y: ::std::os::raw::c_uint, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for nsTArray { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] #[derive(Debug, Copy)] pub struct Test { - pub a: nsTArray<::std::os::raw::c_long>, + pub a: nsTArray, } #[test] fn bindgen_test_layout_Test() { diff --git a/tests/expectations/tests/size_t_template.rs b/tests/expectations/tests/size_t_template.rs index 4d81651e9d..b2680869a9 100644 --- a/tests/expectations/tests/size_t_template.rs +++ b/tests/expectations/tests/size_t_template.rs @@ -5,7 +5,6 @@ #[repr(C)] -#[derive(Debug, Copy)] pub struct C { pub arr: [u32; 3usize], } @@ -21,9 +20,6 @@ fn bindgen_test_layout_C() { "Alignment of field: " , stringify ! ( C ) , "::" , stringify ! ( arr ) )); } -impl Clone for C { - fn clone(&self) -> Self { *self } -} impl Default for C { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/struct_with_typedef_template_arg.rs b/tests/expectations/tests/struct_with_typedef_template_arg.rs index f882c65d54..93620e5948 100644 --- a/tests/expectations/tests/struct_with_typedef_template_arg.rs +++ b/tests/expectations/tests/struct_with_typedef_template_arg.rs @@ -5,14 +5,9 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Proxy { +#[derive(Debug, Default, Copy, Clone)] +pub struct Proxy { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, - pub _phantom_1: ::std::marker::PhantomData, } pub type Proxy_foo = ::std::option::Option; -impl Default for Proxy { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} diff --git a/tests/expectations/tests/template-fun-ty.rs b/tests/expectations/tests/template-fun-ty.rs index b894920ff0..05351d7d7b 100644 --- a/tests/expectations/tests/template-fun-ty.rs +++ b/tests/expectations/tests/template-fun-ty.rs @@ -5,36 +5,22 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo { +#[derive(Debug, Default, Copy, Clone)] +pub struct Foo { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } pub type Foo_FunctionPtr = ::std::option::Option T>; -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtr { +#[derive(Debug, Default, Copy, Clone)] +pub struct RefPtr { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct RefPtr_Proxy { +#[derive(Debug, Default, Copy, Clone)] +pub struct RefPtr_Proxy { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, - pub _phantom_1: ::std::marker::PhantomData, - pub _phantom_2: ::std::marker::PhantomData, } pub type RefPtr_Proxy_member_function = ::std::option::Option R>; -impl Default for RefPtr_Proxy { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} -impl Default for RefPtr { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} pub type Returner = ::std::option::Option T>; diff --git a/tests/expectations/tests/template-param-usage-0.rs b/tests/expectations/tests/template-param-usage-0.rs new file mode 100644 index 0000000000..494001f771 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-0.rs @@ -0,0 +1,14 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-1.rs b/tests/expectations/tests/template-param-usage-1.rs new file mode 100644 index 0000000000..0fd8719bf2 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-1.rs @@ -0,0 +1,11 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct DoesNotUseTemplateParameter { + pub x: ::std::os::raw::c_int, +} diff --git a/tests/expectations/tests/template-param-usage-10.rs b/tests/expectations/tests/template-param-usage-10.rs new file mode 100644 index 0000000000..95d200b576 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-10.rs @@ -0,0 +1,25 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoublyIndirectUsage { + pub doubly_indirect: DoublyIndirectUsage_IndirectUsage, +} +pub type DoublyIndirectUsage_Aliased = T; +pub type DoublyIndirectUsage_Typedefed = U; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoublyIndirectUsage_IndirectUsage { + pub member: DoublyIndirectUsage_Aliased, + pub another: DoublyIndirectUsage_Typedefed, +} +impl Default for DoublyIndirectUsage_IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for DoublyIndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-11.rs b/tests/expectations/tests/template-param-usage-11.rs new file mode 100644 index 0000000000..a8959b9951 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-11.rs @@ -0,0 +1,11 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct DoesNotUseT { + pub _address: u8, +} diff --git a/tests/expectations/tests/template-param-usage-12.rs b/tests/expectations/tests/template-param-usage-12.rs new file mode 100644 index 0000000000..0c31111e78 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-12.rs @@ -0,0 +1,23 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct BaseUsesT { + pub t: *mut T, +} +impl Default for BaseUsesT { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpUsesU { + pub _base: BaseUsesT>, + pub usage: U, +} +impl Default for CrtpUsesU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-13.rs b/tests/expectations/tests/template-param-usage-13.rs new file mode 100644 index 0000000000..c77da0973e --- /dev/null +++ b/tests/expectations/tests/template-param-usage-13.rs @@ -0,0 +1,20 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct BaseIgnoresT { + pub x: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpUsesU { + pub _base: BaseIgnoresT, + pub usage: U, +} +impl Default for CrtpUsesU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-14.rs b/tests/expectations/tests/template-param-usage-14.rs new file mode 100644 index 0000000000..fae4afdca8 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-14.rs @@ -0,0 +1,20 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct BaseIgnoresT { + pub x: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpIgnoresU { + pub _base: BaseIgnoresT, + pub y: ::std::os::raw::c_int, +} +impl Default for CrtpIgnoresU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-15.rs b/tests/expectations/tests/template-param-usage-15.rs new file mode 100644 index 0000000000..a653e08904 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-15.rs @@ -0,0 +1,23 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct BaseUsesT { + pub usage: *mut T, +} +impl Default for BaseUsesT { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CrtpIgnoresU { + pub _base: BaseUsesT, + pub y: ::std::os::raw::c_int, +} +impl Default for CrtpIgnoresU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-2.rs b/tests/expectations/tests/template-param-usage-2.rs new file mode 100644 index 0000000000..6dc21b6865 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-2.rs @@ -0,0 +1,22 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter_AlsoUsesTemplateParameter { + pub also: T, +} +impl Default for UsesTemplateParameter_AlsoUsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-3.rs b/tests/expectations/tests/template-param-usage-3.rs new file mode 100644 index 0000000000..a7ff22f900 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-3.rs @@ -0,0 +1,24 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { + pub also: T, + pub more: U, +} +impl Default for + UsesTemplateParameter_AlsoUsesTemplateParameterAndMore { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-4.rs b/tests/expectations/tests/template-param-usage-4.rs new file mode 100644 index 0000000000..31f8872dbb --- /dev/null +++ b/tests/expectations/tests/template-param-usage-4.rs @@ -0,0 +1,19 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct UsesTemplateParameter { + pub t: T, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct UsesTemplateParameter_DoesNotUseTemplateParameters { + pub x: ::std::os::raw::c_int, +} +impl Default for UsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-5.rs b/tests/expectations/tests/template-param-usage-5.rs new file mode 100644 index 0000000000..5a9caf32d0 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-5.rs @@ -0,0 +1,15 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct IndirectlyUsesTemplateParameter { + pub aliased: IndirectlyUsesTemplateParameter_Aliased, +} +pub type IndirectlyUsesTemplateParameter_Aliased = T; +impl Default for IndirectlyUsesTemplateParameter { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-6.rs b/tests/expectations/tests/template-param-usage-6.rs new file mode 100644 index 0000000000..37b7fe6413 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-6.rs @@ -0,0 +1,12 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct DoesNotUseTemplateParameter { + pub x: ::std::os::raw::c_int, +} +pub type DoesNotUseTemplateParameter_ButAliasDoesUseIt = T; diff --git a/tests/expectations/tests/template-param-usage-7.rs b/tests/expectations/tests/template-param-usage-7.rs new file mode 100644 index 0000000000..b0584479a7 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-7.rs @@ -0,0 +1,16 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoesNotUseU { + pub t: T, + pub v: V, +} +impl Default for DoesNotUseU { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} +pub type Alias = DoesNotUseU<::std::os::raw::c_int, ::std::os::raw::c_schar>; diff --git a/tests/expectations/tests/template-param-usage-8.rs b/tests/expectations/tests/template-param-usage-8.rs new file mode 100644 index 0000000000..b181cc0911 --- /dev/null +++ b/tests/expectations/tests/template-param-usage-8.rs @@ -0,0 +1,17 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct IndirectUsage { + pub member1: IndirectUsage_Typedefed, + pub member2: IndirectUsage_Aliased, +} +pub type IndirectUsage_Typedefed = T; +pub type IndirectUsage_Aliased = U; +impl Default for IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template-param-usage-9.rs b/tests/expectations/tests/template-param-usage-9.rs new file mode 100644 index 0000000000..d0a3f29f6a --- /dev/null +++ b/tests/expectations/tests/template-param-usage-9.rs @@ -0,0 +1,22 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct DoesNotUse { + pub _address: u8, +} +pub type DoesNotUse_Aliased = T; +pub type DoesNotUse_Typedefed = U; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DoesNotUse_IndirectUsage { + pub member: DoesNotUse_Aliased, + pub another: DoesNotUse_Typedefed, +} +impl Default for DoesNotUse_IndirectUsage { + fn default() -> Self { unsafe { ::std::mem::zeroed() } } +} diff --git a/tests/expectations/tests/template.rs b/tests/expectations/tests/template.rs index 3c829f070e..911b0e6ae1 100644 --- a/tests/expectations/tests/template.rs +++ b/tests/expectations/tests/template.rs @@ -6,37 +6,34 @@ #[repr(C)] #[derive(Debug)] -pub struct Foo { +pub struct Foo { pub m_member: T, pub m_member_ptr: *mut T, pub m_member_arr: [T; 1usize], - pub _phantom_1: ::std::marker::PhantomData, } -impl Default for Foo { +impl Default for Foo { 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 { +pub struct D { pub m_foo: D_MyFoo, - pub _phantom_0: ::std::marker::PhantomData, } -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 { +pub struct D_U { pub m_nested_foo: D_MyFoo, pub m_baz: Z, - pub _phantom_0: ::std::marker::PhantomData, } -impl Default for D_U { +impl Default for D_U { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } -impl Default for D { +impl Default for D { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] @@ -104,10 +101,9 @@ impl Default for PODButContainsDtor { /**
*/ #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct Opaque { - pub _phantom_0: ::std::marker::PhantomData, +pub struct Opaque { } -impl Default for Opaque { +impl Default for Opaque { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] @@ -143,11 +139,10 @@ impl Default for NestedReplaced { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct NestedBase { +pub struct NestedBase { pub buff: *mut T, - pub _phantom_1: ::std::marker::PhantomData, } -impl Default for NestedBase { +impl Default for NestedBase { 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 { +#[derive(Debug, Default, Copy, Clone)] +pub struct Templated { pub m_untemplated: Untemplated, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for Templated { - 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 Default for ReplacedWithoutDestructorFwd { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct TemplateWithVar { +#[derive(Debug, Default, Copy, Clone)] +pub struct TemplateWithVar { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for TemplateWithVar { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[test] -fn __bindgen_test_layout_template_1() { - assert_eq!(::std::mem::size_of::>() - , 24usize , concat ! ( +fn __bindgen_test_layout_Foo_instantiation_95() { + assert_eq!(::std::mem::size_of::>() , 24usize , + concat ! ( "Size of template specialization: " , stringify ! ( - Foo<::std::os::raw::c_int, ::std::os::raw::c_int> ) )); - assert_eq!(::std::mem::align_of::>() - , 8usize , concat ! ( + Foo<::std::os::raw::c_int> ) )); + assert_eq!(::std::mem::align_of::>() , 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::>() , 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::>() , 4usize , concat ! ( "Size of template specialization: " , stringify ! ( diff --git a/tests/expectations/tests/template_typedef_transitive_param.rs b/tests/expectations/tests/template_typedef_transitive_param.rs index cc801f3574..265ab5ce1f 100644 --- a/tests/expectations/tests/template_typedef_transitive_param.rs +++ b/tests/expectations/tests/template_typedef_transitive_param.rs @@ -5,10 +5,9 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Wrapper { +#[derive(Debug, Default, Copy, Clone)] +pub struct Wrapper { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -19,6 +18,3 @@ impl Default for Wrapper_Wrapped { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } pub type Wrapper_Type = Wrapper_Wrapped; -impl Default for Wrapper { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} diff --git a/tests/expectations/tests/template_typedefs.rs b/tests/expectations/tests/template_typedefs.rs index 9213c0d234..c987bf8e05 100644 --- a/tests/expectations/tests/template_typedefs.rs +++ b/tests/expectations/tests/template_typedefs.rs @@ -7,11 +7,9 @@ pub type foo = ::std::option::Option; #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct Foo { +#[derive(Debug, Default, Copy, Clone)] +pub struct Foo { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, - pub _phantom_1: ::std::marker::PhantomData, } pub type Foo_Char = T; pub type Foo_FooPtrTypedef = *mut Foo_Char; @@ -20,6 +18,3 @@ pub type Foo_nsCOMArrayEnumFunc = aData: *mut ::std::os::raw::c_void) -> bool>; -impl Default for Foo { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} diff --git a/tests/expectations/tests/templateref_opaque.rs b/tests/expectations/tests/templateref_opaque.rs index dfe941af83..89808f3010 100644 --- a/tests/expectations/tests/templateref_opaque.rs +++ b/tests/expectations/tests/templateref_opaque.rs @@ -5,22 +5,14 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct detail_PointerType { +#[derive(Debug, Default, Copy, Clone)] +pub struct detail_PointerType { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, } pub type detail_PointerType_Type = *mut T; -impl Default for detail_PointerType { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } -} #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct UniquePtr { +#[derive(Debug, Default, Copy, Clone)] +pub struct UniquePtr { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -pub type UniquePtr_Pointer = detail_PointerType; -impl Default for UniquePtr { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } +pub type UniquePtr_Pointer = detail_PointerType; diff --git a/tests/expectations/tests/typeref.rs b/tests/expectations/tests/typeref.rs index 47b7a66a55..c9982b6706 100644 --- a/tests/expectations/tests/typeref.rs +++ b/tests/expectations/tests/typeref.rs @@ -31,7 +31,7 @@ impl ::std::fmt::Debug for __BindgenUnionField { #[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 { - pub __bindgen_anon_1: mozilla_StyleShapeSource__bindgen_ty_1, - pub _phantom_0: ::std::marker::PhantomData, +#[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 { +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, -} -impl Default for mozilla_StyleShapeSource { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] #[derive(Debug, Copy)] diff --git a/tests/expectations/tests/union_template.rs b/tests/expectations/tests/union_template.rs index 2eba0f0a4f..e02f196440 100644 --- a/tests/expectations/tests/union_template.rs +++ b/tests/expectations/tests/union_template.rs @@ -29,37 +29,30 @@ impl ::std::fmt::Debug for __BindgenUnionField { } } #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct NastyStruct { +#[derive(Debug, Default, Copy, Clone)] +pub struct NastyStruct { pub mIsSome: bool, - pub mStorage: NastyStruct__bindgen_ty_1, - pub __bindgen_anon_1: NastyStruct__bindgen_ty_2, - pub _phantom_0: ::std::marker::PhantomData, + 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 { +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, } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] -pub struct NastyStruct__bindgen_ty_2 { +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, -} -impl Default for NastyStruct { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] -pub struct Whatever { +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, } diff --git a/tests/expectations/tests/variadic_template_function.rs b/tests/expectations/tests/variadic_template_function.rs index 32be9f682b..66fd73ed52 100644 --- a/tests/expectations/tests/variadic_template_function.rs +++ b/tests/expectations/tests/variadic_template_function.rs @@ -5,11 +5,7 @@ #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct VariadicFunctionObject { +#[derive(Debug, Default, Copy, Clone)] +pub struct VariadicFunctionObject { pub _address: u8, - pub _phantom_0: ::std::marker::PhantomData, -} -impl Default for VariadicFunctionObject { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } } diff --git a/tests/expectations/tests/what_is_going_on.rs b/tests/expectations/tests/what_is_going_on.rs index 46af013991..e5194c02c6 100644 --- a/tests/expectations/tests/what_is_going_on.rs +++ b/tests/expectations/tests/what_is_going_on.rs @@ -22,12 +22,11 @@ impl Clone for UnknownUnits { pub type Float = f32; #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct PointTyped { +pub struct PointTyped { pub x: F, pub y: F, - pub _phantom_0: ::std::marker::PhantomData, } -impl Default for PointTyped { +impl Default for PointTyped { fn default() -> Self { unsafe { ::std::mem::zeroed() } } } -pub type IntPoint = PointTyped; +pub type IntPoint = PointTyped; diff --git a/tests/expectations/tests/whitelist_basic.rs b/tests/expectations/tests/whitelist_basic.rs index d67fb7a36a..8af4aba352 100644 --- a/tests/expectations/tests/whitelist_basic.rs +++ b/tests/expectations/tests/whitelist_basic.rs @@ -9,7 +9,6 @@ pub struct WhitelistMe { pub foo: ::std::os::raw::c_int, pub bar: WhitelistMe_Inner, - pub _phantom_0: ::std::marker::PhantomData, } #[repr(C)] #[derive(Debug, Copy, Clone)] diff --git a/tests/headers/issue-544-stylo-creduce-2.hpp b/tests/headers/issue-544-stylo-creduce-2.hpp new file mode 100644 index 0000000000..f3467f4528 --- /dev/null +++ b/tests/headers/issue-544-stylo-creduce-2.hpp @@ -0,0 +1,8 @@ +// bindgen-flags: -- -std=c++14 + +template +struct Foo { + template using FirstAlias = typename T::Associated; + template using SecondAlias = Foo>; + SecondAlias member; +}; diff --git a/tests/headers/issue-544-stylo-creduce.hpp b/tests/headers/issue-544-stylo-creduce.hpp new file mode 100644 index 0000000000..ba9f82575c --- /dev/null +++ b/tests/headers/issue-544-stylo-creduce.hpp @@ -0,0 +1,5 @@ +// bindgen-flags: -- -std=c++14 + +template class a; +template class a { a(const a &); }; +template a::a(const a &) {} diff --git a/tests/headers/partial-specialization-and-inheritance.hpp b/tests/headers/partial-specialization-and-inheritance.hpp new file mode 100644 index 0000000000..4eb8f54583 --- /dev/null +++ b/tests/headers/partial-specialization-and-inheritance.hpp @@ -0,0 +1,40 @@ +// bindgen-unstable + +// This was originally a test case generated by creducing errors in SpiderMonkey +// bindings generation. I've tried to make it understandable by giving more +// meaningful names to everything, and a couple comments. +// +// We don't support partial template specialization, but we *should* +// successfully parse this header, and generate bindings for it, but the usage +// of the partial template specialization should result in opaque blobs. + +// A base class providing a method. +template +class Base { +public: + void some_method(T, T); +}; + +// A template with a default representation. +template +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 +class Derived : public Base { + 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 static_member; +}; diff --git a/tests/headers/template-param-usage-0.hpp b/tests/headers/template-param-usage-0.hpp new file mode 100644 index 0000000000..57c11a105e --- /dev/null +++ b/tests/headers/template-param-usage-0.hpp @@ -0,0 +1,6 @@ +// bindgen-flags: -- -std=c++14 + +template +class UsesTemplateParameter { + T t; +}; diff --git a/tests/headers/template-param-usage-1.hpp b/tests/headers/template-param-usage-1.hpp new file mode 100644 index 0000000000..dba41489d8 --- /dev/null +++ b/tests/headers/template-param-usage-1.hpp @@ -0,0 +1,6 @@ +// bindgen-flags: -- -std=c++14 + +template +class DoesNotUseTemplateParameter { + int x; +}; diff --git a/tests/headers/template-param-usage-10.hpp b/tests/headers/template-param-usage-10.hpp new file mode 100644 index 0000000000..a6f3ccd871 --- /dev/null +++ b/tests/headers/template-param-usage-10.hpp @@ -0,0 +1,14 @@ +// bindgen-flags: -- -std=c++14 + +template +class DoublyIndirectUsage { + using Aliased = T; + typedef U Typedefed; + + class IndirectUsage { + Aliased member; + Typedefed another; + }; + + IndirectUsage doubly_indirect; +}; diff --git a/tests/headers/template-param-usage-11.hpp b/tests/headers/template-param-usage-11.hpp new file mode 100644 index 0000000000..8780f5d357 --- /dev/null +++ b/tests/headers/template-param-usage-11.hpp @@ -0,0 +1,6 @@ +// bindgen-flags: -- -std=c++14 + +template +class DoesNotUseT { + static T but_static_member_does; +}; diff --git a/tests/headers/template-param-usage-12.hpp b/tests/headers/template-param-usage-12.hpp new file mode 100644 index 0000000000..9b4cea1988 --- /dev/null +++ b/tests/headers/template-param-usage-12.hpp @@ -0,0 +1,11 @@ +// bindgen-flags: -- -std=c++14 + +template +class BaseUsesT { + T* t; +}; + +template +class CrtpUsesU : public BaseUsesT> { + U usage; +}; diff --git a/tests/headers/template-param-usage-13.hpp b/tests/headers/template-param-usage-13.hpp new file mode 100644 index 0000000000..87db1a10e1 --- /dev/null +++ b/tests/headers/template-param-usage-13.hpp @@ -0,0 +1,11 @@ +// bindgen-flags: -- -std=c++14 + +template +class BaseIgnoresT { + int x; +}; + +template +class CrtpUsesU : public BaseIgnoresT> { + U usage; +}; diff --git a/tests/headers/template-param-usage-14.hpp b/tests/headers/template-param-usage-14.hpp new file mode 100644 index 0000000000..1901629656 --- /dev/null +++ b/tests/headers/template-param-usage-14.hpp @@ -0,0 +1,11 @@ +// bindgen-flags: -- -std=c++14 + +template +class BaseIgnoresT { + int x; +}; + +template +class CrtpIgnoresU : public BaseIgnoresT> { + int y; +}; diff --git a/tests/headers/template-param-usage-15.hpp b/tests/headers/template-param-usage-15.hpp new file mode 100644 index 0000000000..bac7ada77b --- /dev/null +++ b/tests/headers/template-param-usage-15.hpp @@ -0,0 +1,11 @@ +// bindgen-flags: -- -std=c++14 + +template +class BaseUsesT { + T* usage; +}; + +template +class CrtpIgnoresU : public BaseUsesT> { + int y; +}; diff --git a/tests/headers/template-param-usage-2.hpp b/tests/headers/template-param-usage-2.hpp new file mode 100644 index 0000000000..302140ab95 --- /dev/null +++ b/tests/headers/template-param-usage-2.hpp @@ -0,0 +1,10 @@ +// bindgen-flags: -- -std=c++14 + +template +class UsesTemplateParameter { + T t; + + class AlsoUsesTemplateParameter { + T also; + }; +}; diff --git a/tests/headers/template-param-usage-3.hpp b/tests/headers/template-param-usage-3.hpp new file mode 100644 index 0000000000..57396a8a7f --- /dev/null +++ b/tests/headers/template-param-usage-3.hpp @@ -0,0 +1,12 @@ +// bindgen-flags: -- -std=c++14 + +template +class UsesTemplateParameter { + T t; + + template + class AlsoUsesTemplateParameterAndMore { + T also; + U more; + }; +}; diff --git a/tests/headers/template-param-usage-4.hpp b/tests/headers/template-param-usage-4.hpp new file mode 100644 index 0000000000..0415d69210 --- /dev/null +++ b/tests/headers/template-param-usage-4.hpp @@ -0,0 +1,11 @@ +// bindgen-flags: -- -std=c++14 + +template +class UsesTemplateParameter { + T t; + + template + class DoesNotUseTemplateParameters { + int x; + }; +}; diff --git a/tests/headers/template-param-usage-5.hpp b/tests/headers/template-param-usage-5.hpp new file mode 100644 index 0000000000..04b9bf80b7 --- /dev/null +++ b/tests/headers/template-param-usage-5.hpp @@ -0,0 +1,8 @@ +// bindgen-flags: -- -std=c++14 + +template +class IndirectlyUsesTemplateParameter { + using Aliased = T; + + Aliased aliased; +}; diff --git a/tests/headers/template-param-usage-6.hpp b/tests/headers/template-param-usage-6.hpp new file mode 100644 index 0000000000..ee0519c515 --- /dev/null +++ b/tests/headers/template-param-usage-6.hpp @@ -0,0 +1,8 @@ +// bindgen-flags: -- -std=c++14 + +template +class DoesNotUseTemplateParameter { + using ButAliasDoesUseIt = T; + + int x; +}; diff --git a/tests/headers/template-param-usage-7.hpp b/tests/headers/template-param-usage-7.hpp new file mode 100644 index 0000000000..99d4cc71b4 --- /dev/null +++ b/tests/headers/template-param-usage-7.hpp @@ -0,0 +1,10 @@ +// bindgen-flags: -- -std=c++14 + +template +class DoesNotUseU { + T t; + V v; +}; + +// The bool should go away becuase U is not used. +using Alias = DoesNotUseU; diff --git a/tests/headers/template-param-usage-8.hpp b/tests/headers/template-param-usage-8.hpp new file mode 100644 index 0000000000..96eabc0649 --- /dev/null +++ b/tests/headers/template-param-usage-8.hpp @@ -0,0 +1,10 @@ +// bindgen-flags: -- -std=c++14 + +template +class IndirectUsage { + typedef T Typedefed; + using Aliased = U; + + Typedefed member1; + Aliased member2; +}; diff --git a/tests/headers/template-param-usage-9.hpp b/tests/headers/template-param-usage-9.hpp new file mode 100644 index 0000000000..b9bd202ca8 --- /dev/null +++ b/tests/headers/template-param-usage-9.hpp @@ -0,0 +1,12 @@ +// bindgen-flags: -- -std=c++14 + +template +class DoesNotUse { + using Aliased = T; + typedef U Typedefed; + + class IndirectUsage { + Aliased member; + Typedefed another; + }; +};