diff options
Diffstat (limited to 'src/codegen/mod.rs')
-rw-r--r-- | src/codegen/mod.rs | 280 |
1 files changed, 153 insertions, 127 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 77941fa3..7bc8985b 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -2,8 +2,8 @@ mod helpers; mod struct_layout; use self::helpers::{BlobTyBuilder, attributes}; +use self::struct_layout::{StructLayoutTracker, bytes_from_bits_pow2}; use self::struct_layout::{align_to, bytes_from_bits}; -use self::struct_layout::{bytes_from_bits_pow2, StructLayoutTracker}; use aster; use ir::annotations::FieldAccessorKind; @@ -20,7 +20,8 @@ use ir::item_kind::ItemKind; use ir::layout::Layout; use ir::module::Module; use ir::objc::ObjCInterface; -use ir::ty::{Type, TypeKind}; +use ir::template::{AsNamed, TemplateInstantiation}; +use ir::ty::{TemplateDeclaration, Type, TypeKind}; use ir::var::Var; use std::borrow::Cow; @@ -137,11 +138,6 @@ impl<'a> CodegenResult<'a> { } } - fn next_id(&mut self) -> usize { - self.codegen_id.set(self.codegen_id.get() + 1); - self.codegen_id.get() - } - fn saw_union(&mut self) { self.saw_union = true; } @@ -522,19 +518,20 @@ impl CodeGenerator for Type { TypeKind::Pointer(..) | TypeKind::BlockPointer | TypeKind::Reference(..) | - TypeKind::TemplateInstantiation(..) | TypeKind::Function(..) | TypeKind::ResolvedTypeRef(..) | + TypeKind::Opaque | TypeKind::Named => { // These items don't need code generation, they only need to be // converted to rust types in fields, arguments, and such. return; } + TypeKind::TemplateInstantiation(ref inst) => { + inst.codegen(ctx, result, whitelisted_items, item) + } TypeKind::Comp(ref ci) => { ci.codegen(ctx, result, whitelisted_items, item) } - // NB: The code below will pick the correct - // applicable_template_args. TypeKind::TemplateAlias(inner, _) | TypeKind::Alias(inner) => { let inner_item = ctx.resolve_item(inner); @@ -557,10 +554,9 @@ impl CodeGenerator for Type { return; } - let mut applicable_template_args = - item.applicable_template_args(ctx); + let mut used_template_params = item.used_template_params(ctx); let inner_rust_type = if item.is_opaque(ctx) { - applicable_template_args.clear(); + used_template_params = None; // Pray if there's no layout. let layout = self.layout(ctx).unwrap_or_else(Layout::zero); BlobTyBuilder::new(layout).build() @@ -603,7 +599,7 @@ impl CodeGenerator for Type { // https://github.com/rust-lang/rust/issues/26264 let simple_enum_path = match inner_rust_type.node { ast::TyKind::Path(None, ref p) => { - if applicable_template_args.is_empty() && + if used_template_params.is_none() && inner_item.expect_type() .canonical_type(ctx) .is_enum() && @@ -627,17 +623,21 @@ impl CodeGenerator for Type { typedef.use_().build(p).as_(rust_name) } else { let mut generics = typedef.type_(rust_name).generics(); - for template_arg in applicable_template_args.iter() { - let template_arg = ctx.resolve_type(*template_arg); - if template_arg.is_named() { - if template_arg.is_invalid_named_type() { - warn!("Item contained invalid template \ - parameter: {:?}", - item); - return; + if let Some(ref params) = used_template_params { + for template_param in params { + if let Some(id) = + template_param.as_named(ctx, &()) { + let template_param = ctx.resolve_type(id); + if template_param.is_invalid_named_type() { + warn!("Item contained invalid template \ + parameter: {:?}", + item); + return; + } + generics = + generics.ty_param_id(template_param.name() + .unwrap()); } - generics = - generics.ty_param_id(template_arg.name().unwrap()); } } generics.build().build_ty(inner_rust_type) @@ -768,7 +768,7 @@ impl<'a> Bitfield<'a> { let field_align = field_ty_layout.align; if field_size_in_bits != 0 && - (width == 0 || width as usize > unfilled_bits_in_last_unit) { + (width == 0 || width as usize > unfilled_bits_in_last_unit) { field_size_in_bits = align_to(field_size_in_bits, field_align); // Push the new field. let ty = @@ -829,6 +829,53 @@ impl<'a> Bitfield<'a> { } } +impl CodeGenerator for TemplateInstantiation { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + // Although uses of instantiations don't need code generation, and are + // just converted to rust types in fields, vars, etc, we take this + // opportunity to generate tests for their layout here. + + let layout = item.kind().expect_type().layout(ctx); + + if let Some(layout) = layout { + let size = layout.size; + let align = layout.align; + + let name = item.canonical_name(ctx); + let fn_name = format!("__bindgen_test_layout_{}_instantiation_{}", + name, + item.id().as_usize()); + let fn_name = ctx.rust_ident_raw(&fn_name); + + let prefix = ctx.trait_prefix(); + let ident = item.to_rust_ty(ctx); + let size_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::size_of::<$ident>()); + let align_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::align_of::<$ident>()); + + let item = quote_item!( + ctx.ext_cx(), + #[test] + fn $fn_name() { + assert_eq!($size_of_expr, $size, + concat!("Size of template specialization: ", stringify!($ident))); + assert_eq!($align_of_expr, $align, + concat!("Alignment of template specialization: ", stringify!($ident))); + }) + .unwrap(); + + result.push(item); + } + } +} + impl CodeGenerator for CompInfo { type Extra = Item; @@ -847,12 +894,11 @@ impl CodeGenerator for CompInfo { return; } - let applicable_template_args = item.applicable_template_args(ctx); + let used_template_params = item.used_template_params(ctx); // generate tuple struct if struct or union is a forward declaration, // skip for now if template parameters are needed. - if self.is_forward_declaration() && - applicable_template_args.is_empty() { + if self.is_forward_declaration() && used_template_params.is_none() { let struct_name = item.canonical_name(ctx); let struct_name = ctx.rust_ident_raw(&struct_name); let tuple_struct = quote_item!(ctx.ext_cx(), @@ -865,35 +911,6 @@ impl CodeGenerator for CompInfo { return; } - if self.is_template_specialization() { - let layout = item.kind().expect_type().layout(ctx); - - if let Some(layout) = layout { - let fn_name = format!("__bindgen_test_layout_template_{}", - result.next_id()); - let fn_name = ctx.rust_ident_raw(&fn_name); - let ident = item.to_rust_ty(ctx); - let prefix = ctx.trait_prefix(); - let size_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::size_of::<$ident>()); - let align_of_expr = quote_expr!(ctx.ext_cx(), - ::$prefix::mem::align_of::<$ident>()); - let size = layout.size; - let align = layout.align; - let item = quote_item!(ctx.ext_cx(), - #[test] - fn $fn_name() { - assert_eq!($size_of_expr, $size, - concat!("Size of template specialization: ", stringify!($ident))); - assert_eq!($align_of_expr, $align, - concat!("Alignment of template specialization: ", stringify!($ident))); - }) - .unwrap(); - result.push(item); - } - return; - } - let mut attributes = vec![]; let mut needs_clone_impl = false; let mut needs_default_impl = false; @@ -923,7 +940,7 @@ impl CodeGenerator for CompInfo { if item.can_derive_copy(ctx, ()) && !item.annotations().disallow_copy() { derives.push("Copy"); - if !applicable_template_args.is_empty() { + if used_template_params.is_some() { // FIXME: This requires extra logic if you have a big array in a // templated struct. The reason for this is that the magic: // fn clone(&self) -> Self { *self } @@ -940,8 +957,6 @@ impl CodeGenerator for CompInfo { attributes.push(attributes::derives(&derives)) } - let mut template_args_used = - vec![false; applicable_template_args.len()]; let canonical_name = item.canonical_name(ctx); let builder = if is_union && ctx.options().unstable_rust { aster::AstBuilder::new() @@ -1004,13 +1019,6 @@ impl CodeGenerator for CompInfo { continue; } - for (i, ty_id) in applicable_template_args.iter().enumerate() { - let template_arg_ty = ctx.resolve_type(*ty_id); - if base_ty.signature_contains_named_type(ctx, template_arg_ty) { - template_args_used[i] = true; - } - } - let inner = base.ty.to_rust_ty(ctx); let field_name = if i == 0 { "_base".into() @@ -1092,13 +1100,6 @@ impl CodeGenerator for CompInfo { continue; } - for (i, ty_id) in applicable_template_args.iter().enumerate() { - let template_arg = ctx.resolve_type(*ty_id); - if field_ty.signature_contains_named_type(ctx, template_arg) { - template_args_used[i] = true; - } - } - let ty = field.ty().to_rust_ty(ctx); // NB: In unstable rust we use proper `union` types. @@ -1108,7 +1109,8 @@ impl CodeGenerator for CompInfo { } else { quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>) } - } else if let Some(item) = field_ty.is_incomplete_array(ctx) { + } else if let Some(item) = + field_ty.is_incomplete_array(ctx) { result.saw_incomplete_array(); let inner = item.to_rust_ty(ctx); @@ -1257,9 +1259,6 @@ impl CodeGenerator for CompInfo { if item.is_opaque(ctx) { fields.clear(); methods.clear(); - for i in 0..template_args_used.len() { - template_args_used[i] = false; - } match layout { Some(l) => { @@ -1276,7 +1275,9 @@ impl CodeGenerator for CompInfo { } } else if !is_union && !self.is_unsized(ctx) { if let Some(padding_field) = - layout.and_then(|layout| struct_layout.pad_struct(&canonical_name, layout)) { + layout.and_then(|layout| { + struct_layout.pad_struct(&canonical_name, layout) + }) { fields.push(padding_field); } @@ -1299,35 +1300,17 @@ impl CodeGenerator for CompInfo { fields.push(field); } - // Append any extra template arguments that nobody has used so far. - for (i, ty) in applicable_template_args.iter().enumerate() { - if !template_args_used[i] { - let name = ctx.resolve_type(*ty).name().unwrap(); + let mut generics = aster::AstBuilder::new().generics(); + + if let Some(ref params) = used_template_params { + for ty in params.iter() { + let param = ctx.resolve_type(*ty); + let name = param.name().unwrap(); let ident = ctx.rust_ident(name); - let prefix = ctx.trait_prefix(); - let phantom = quote_ty!(ctx.ext_cx(), - ::$prefix::marker::PhantomData<$ident>); - let field = StructFieldBuilder::named(format!("_phantom_{}", - i)) - .pub_() - .build_ty(phantom); - fields.push(field) + generics = generics.ty_param_id(ident); } } - - let mut generics = aster::AstBuilder::new().generics(); - for template_arg in applicable_template_args.iter() { - // Take into account that here only arrive named types, not - // template specialisations that would need to be - // instantiated. - // - // TODO: Add template args from the parent, here and in - // `to_rust_ty`!! - let template_arg = ctx.resolve_type(*template_arg); - generics = generics.ty_param_id(template_arg.name().unwrap()); - } - let generics = generics.build(); let rust_struct = builder.with_generics(generics.clone()) @@ -1353,7 +1336,7 @@ impl CodeGenerator for CompInfo { canonical_name); } - if applicable_template_args.is_empty() { + if used_template_params.is_none() { for var in self.inner_vars() { ctx.resolve_item(*var) .codegen(ctx, result, whitelisted_items, &()); @@ -2193,16 +2176,54 @@ impl ToRustTy for Type { let path = item.namespace_aware_canonical_path(ctx); aster::AstBuilder::new().ty().path().ids(path).build() } - TypeKind::TemplateInstantiation(inner, ref template_args) => { - // PS: Sorry for the duplication here. - let mut inner_ty = inner.to_rust_ty(ctx).unwrap(); + TypeKind::TemplateInstantiation(ref inst) => { + let decl = inst.template_definition(); + let mut ty = decl.to_rust_ty(ctx).unwrap(); - if let ast::TyKind::Path(_, ref mut path) = inner_ty.node { - let template_args = template_args.iter() - .map(|arg| arg.to_rust_ty(ctx)) + // If we gave up when making a type for the template definition, + // check if maybe we can make a better opaque blob for the + // instantiation. + if ty == aster::AstBuilder::new().ty().unit().unwrap() { + if let Some(layout) = self.layout(ctx) { + ty = BlobTyBuilder::new(layout).build().unwrap() + } + } + + let decl_params = if let Some(params) = + decl.self_template_params(ctx) { + params + } else { + // This can happen if we generated an opaque type for a + // partial template specialization, in which case we just + // use the opaque type's layout. If we don't have a layout, + // we cross our fingers and hope for the best :-/ + debug_assert!(ctx.resolve_type_through_type_refs(decl) + .is_opaque()); + let layout = self.layout(ctx).unwrap_or(Layout::zero()); + ty = BlobTyBuilder::new(layout).build().unwrap(); + + vec![] + }; + + // TODO: If the decl type is a template class/struct + // declaration's member template declaration, it could rely on + // generic template parameters from its outer template + // class/struct. When we emit bindings for it, it could require + // *more* type arguments than we have here, and we will need to + // reconstruct them somehow. We don't have any means of doing + // that reconstruction at this time. + + if let ast::TyKind::Path(_, ref mut path) = ty.node { + let template_args = inst.template_arguments() + .iter() + .zip(decl_params.iter()) + // Only pass type arguments for the type parameters that + // the decl uses. + .filter(|&(_, param)| ctx.uses_template_parameter(decl, *param)) + .map(|(arg, _)| arg.to_rust_ty(ctx)) .collect::<Vec<_>>(); - path.segments.last_mut().unwrap().parameters = if + path.segments.last_mut().unwrap().parameters = if template_args.is_empty() { None } else { @@ -2216,18 +2237,19 @@ impl ToRustTy for Type { } } - P(inner_ty) + P(ty) } TypeKind::ResolvedTypeRef(inner) => inner.to_rust_ty(ctx), TypeKind::TemplateAlias(inner, _) | TypeKind::Alias(inner) => { - let applicable_named_args = item.applicable_template_args(ctx) + let template_params = item.used_template_params(ctx) + .unwrap_or(vec![]) .into_iter() - .filter(|arg| ctx.resolve_type(*arg).is_named()) + .filter(|param| param.is_named(ctx, &())) .collect::<Vec<_>>(); let spelling = self.name().expect("Unnamed alias?"); - if item.is_opaque(ctx) && !applicable_named_args.is_empty() { + if item.is_opaque(ctx) && !template_params.is_empty() { // Pray if there's no available layout. let layout = self.layout(ctx).unwrap_or_else(Layout::zero); BlobTyBuilder::new(layout).build() @@ -2236,15 +2258,13 @@ impl ToRustTy for Type { inner) { ty } else { - utils::build_templated_path(item, - ctx, - applicable_named_args) + utils::build_templated_path(item, ctx, template_params) } } TypeKind::Comp(ref info) => { - let template_args = item.applicable_template_args(ctx); + let template_params = item.used_template_params(ctx); if info.has_non_type_template_params() || - (item.is_opaque(ctx) && !template_args.is_empty()) { + (item.is_opaque(ctx) && template_params.is_some()) { return match self.layout(ctx) { Some(layout) => BlobTyBuilder::new(layout).build(), None => { @@ -2256,7 +2276,13 @@ impl ToRustTy for Type { }; } - utils::build_templated_path(item, ctx, template_args) + utils::build_templated_path(item, + ctx, + template_params.unwrap_or(vec![])) + } + TypeKind::Opaque => { + BlobTyBuilder::new(self.layout(ctx).unwrap_or(Layout::zero())) + .build() } TypeKind::BlockPointer => { let void = raw_type(ctx, "c_void"); @@ -2742,19 +2768,19 @@ mod utils { pub fn build_templated_path(item: &Item, ctx: &BindgenContext, - template_args: Vec<ItemId>) + template_params: Vec<ItemId>) -> P<ast::Ty> { let path = item.namespace_aware_canonical_path(ctx); let builder = aster::AstBuilder::new().ty().path(); - let template_args = template_args.iter() - .map(|arg| arg.to_rust_ty(ctx)) + let template_params = template_params.iter() + .map(|param| param.to_rust_ty(ctx)) .collect::<Vec<_>>(); // XXX: I suck at aster. if path.len() == 1 { return builder.segment(&path[0]) - .with_tys(template_args) + .with_tys(template_params) .build() .build(); } @@ -2765,7 +2791,7 @@ mod utils { builder = if i == path.len() - 2 { // XXX Extra clone courtesy of the borrow checker. builder.segment(&segment) - .with_tys(template_args.clone()) + .with_tys(template_params.clone()) .build() } else { builder.segment(&segment).build() |