diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/codegen/mod.rs | 54 | ||||
-rw-r--r-- | src/ir/comp.rs | 61 | ||||
-rw-r--r-- | src/ir/context.rs | 10 | ||||
-rw-r--r-- | src/ir/derive.rs | 21 | ||||
-rw-r--r-- | src/ir/item.rs | 22 | ||||
-rw-r--r-- | src/ir/layout.rs | 11 | ||||
-rw-r--r-- | src/ir/ty.rs | 35 | ||||
-rw-r--r-- | src/lib.rs | 11 | ||||
-rw-r--r-- | src/options.rs | 15 |
9 files changed, 231 insertions, 9 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 0fdfaad0..5ee43173 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -8,7 +8,7 @@ use aster; use ir::annotations::FieldAccessorKind; use ir::comp::{Base, CompInfo, CompKind, Field, Method, MethodKind}; use ir::context::{BindgenContext, ItemId}; -use ir::derive::{CanDeriveCopy, CanDeriveDebug}; +use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue}; use ir::function::{Function, FunctionSig}; use ir::int::IntKind; @@ -688,10 +688,16 @@ impl<'a> CodeGenerator for Vtable<'a> { assert_eq!(item.id(), self.item_id); // For now, generate an empty struct, later we should generate function // pointers and whatnot. + let mut attributes = vec![attributes::repr("C")]; + + if ctx.options().derive_default { + attributes.push(attributes::derives(&["Default"])) + } + let vtable = aster::AstBuilder::new() .item() .pub_() - .with_attr(attributes::repr("C")) + .with_attrs(attributes) .struct_(self.canonical_name(ctx)) .build(); result.push(vtable); @@ -879,6 +885,7 @@ impl CodeGenerator for CompInfo { let mut attributes = vec![]; let mut needs_clone_impl = false; + let mut needs_default_impl = false; if ctx.options().generate_comments { if let Some(comment) = item.comment() { attributes.push(attributes::doc(comment)); @@ -896,6 +903,12 @@ impl CodeGenerator for CompInfo { derives.push("Debug"); } + if item.can_derive_default(ctx, ()) { + derives.push("Default"); + } else { + needs_default_impl = ctx.options().derive_default; + } + if item.can_derive_copy(ctx, ()) && !item.annotations().disallow_copy() { derives.push("Copy"); @@ -1440,8 +1453,14 @@ impl CodeGenerator for CompInfo { // NB: We can't use to_rust_ty here since for opaque types this tries to // use the specialization knowledge to generate a blob field. - let ty_for_impl = - aster::AstBuilder::new().ty().path().id(&canonical_name).build(); + let ty_for_impl = aster::AstBuilder::new() + .ty() + .path() + .segment(&canonical_name) + .with_generics(generics.clone()) + .build() + .build(); + if needs_clone_impl { let impl_ = quote_item!(ctx.ext_cx(), impl X { @@ -1467,6 +1486,32 @@ impl CodeGenerator for CompInfo { result.push(clone_impl); } + if needs_default_impl { + let prefix = ctx.trait_prefix(); + let impl_ = quote_item!(ctx.ext_cx(), + impl X { + fn default() -> Self { unsafe { ::$prefix::mem::zeroed() } } + } + ); + + let impl_ = match impl_.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), + _ => unreachable!(), + }; + + let default_impl = aster::AstBuilder::new() + .item() + .impl_() + .trait_() + .id("Default") + .build() + .with_generics(generics.clone()) + .with_items(impl_) + .build_ty(ty_for_impl.clone()); + + result.push(default_impl); + } + if !methods.is_empty() { let methods = aster::AstBuilder::new() .item() @@ -2582,6 +2627,7 @@ mod utils { let incomplete_array_decl = quote_item!(ctx.ext_cx(), #[repr(C)] + #[derive(Default)] pub struct __IncompleteArrayField<T>( ::$prefix::marker::PhantomData<T>); ) diff --git a/src/ir/comp.rs b/src/ir/comp.rs index 53efd278..1ca39559 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -2,7 +2,7 @@ use super::annotations::Annotations; use super::context::{BindgenContext, ItemId}; -use super::derive::{CanDeriveCopy, CanDeriveDebug}; +use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; use super::item::Item; use super::layout::Layout; use super::ty::Type; @@ -171,6 +171,14 @@ impl CanDeriveDebug for Field { } } +impl CanDeriveDefault for Field { + type Extra = (); + + fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool { + self.ty.can_derive_default(ctx, ()) + } +} + impl<'a> CanDeriveCopy<'a> for Field { type Extra = (); @@ -296,6 +304,10 @@ pub struct CompInfo { /// around the template arguments. detect_derive_debug_cycle: Cell<bool>, + /// Used to detect if we've run in a can_derive_default cycle while cycling + /// around the template arguments. + detect_derive_default_cycle: Cell<bool>, + /// Used to detect if we've run in a has_destructor cycle while cycling /// around the template arguments. detect_has_destructor_cycle: Cell<bool>, @@ -326,6 +338,7 @@ impl CompInfo { is_anonymous: false, found_unknown_attr: false, detect_derive_debug_cycle: Cell::new(false), + detect_derive_default_cycle: Cell::new(false), detect_has_destructor_cycle: Cell::new(false), is_forward_declaration: false, } @@ -952,6 +965,52 @@ impl CanDeriveDebug for CompInfo { } } +impl CanDeriveDefault for CompInfo { + type Extra = Option<Layout>; + + fn can_derive_default(&self, + ctx: &BindgenContext, + layout: Option<Layout>) + -> bool { + // We can reach here recursively via template parameters of a member, + // for example. + if self.detect_derive_default_cycle.get() { + warn!("Derive default cycle detected!"); + return true; + } + + if self.kind == CompKind::Union { + if ctx.options().unstable_rust { + return false; + } + + return layout.unwrap_or_else(Layout::zero) + .opaque() + .can_derive_debug(ctx, ()); + } + + self.detect_derive_default_cycle.set(true); + + let can_derive_default = !self.has_vtable(ctx) && + !self.needs_explicit_vtable(ctx) && + 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, ())); + + self.detect_derive_default_cycle.set(false); + + can_derive_default + } +} + impl<'a> CanDeriveCopy<'a> for CompInfo { type Extra = (&'a Item, Option<Layout>); diff --git a/src/ir/context.rs b/src/ir/context.rs index 38ecdf17..a7482394 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -1,6 +1,6 @@ //! Common context that is passed around during parsing and codegen. -use super::derive::{CanDeriveCopy, CanDeriveDebug}; +use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; use super::int::IntKind; use super::item::{Item, ItemCanonicalPath}; use super::item_kind::ItemKind; @@ -42,6 +42,14 @@ impl CanDeriveDebug for ItemId { } } +impl CanDeriveDefault for ItemId { + type Extra = (); + + fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool { + ctx.resolve_item(*self).can_derive_default(ctx, ()) + } +} + impl<'a> CanDeriveCopy<'a> for ItemId { type Extra = (); diff --git a/src/ir/derive.rs b/src/ir/derive.rs index d13a8117..6d9f368b 100644 --- a/src/ir/derive.rs +++ b/src/ir/derive.rs @@ -65,3 +65,24 @@ pub trait CanDeriveCopy<'a> { extra: Self::Extra) -> bool; } + +/// A trait that encapsulates the logic for whether or not we can derive `Default` +/// for a given thing. +/// +/// This should ideally be a no-op that just returns `true`, but instead needs +/// to be a recursive method that checks whether all the proper members can +/// derive default or not, because of the limit rust has on 32 items as max in the +/// array. +pub trait CanDeriveDefault { + /// Implementations can define this type to get access to any extra + /// information required to determine whether they can derive `Default`. If + /// extra information is unneeded, then this should simply be the unit type. + type Extra; + + /// Return `true` if `Default` can be derived for this thing, `false` + /// otherwise. + fn can_derive_default(&self, + ctx: &BindgenContext, + extra: Self::Extra) + -> bool; +}
\ No newline at end of file diff --git a/src/ir/item.rs b/src/ir/item.rs index a5d10e41..c8de95c0 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -2,7 +2,7 @@ use super::annotations::Annotations; use super::context::{BindgenContext, ItemId}; -use super::derive::{CanDeriveCopy, CanDeriveDebug}; +use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; use super::function::Function; use super::item_kind::ItemKind; use super::module::Module; @@ -235,6 +235,26 @@ impl CanDeriveDebug for Item { } } +impl CanDeriveDefault for Item { + type Extra = (); + + fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool { + ctx.options().derive_default && + match self.kind { + ItemKind::Type(ref ty) => { + if self.is_opaque(ctx) { + ty.layout(ctx) + .map_or(false, + |l| l.opaque().can_derive_default(ctx, ())) + } else { + ty.can_derive_default(ctx, ()) + } + } + _ => false, + } + } +} + impl<'a> CanDeriveCopy<'a> for Item { type Extra = (); diff --git a/src/ir/layout.rs b/src/ir/layout.rs index e8c6c32b..03d43b51 100644 --- a/src/ir/layout.rs +++ b/src/ir/layout.rs @@ -1,7 +1,7 @@ //! Intermediate representation for the physical layout of some type. use super::context::BindgenContext; -use super::derive::{CanDeriveCopy, CanDeriveDebug}; +use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT; use std::cmp; @@ -79,6 +79,15 @@ impl CanDeriveDebug for Opaque { } } +impl CanDeriveDefault for Opaque { + type Extra = (); + + fn can_derive_default(&self, _: &BindgenContext, _: ()) -> bool { + self.array_size() + .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) + } +} + impl<'a> CanDeriveCopy<'a> for Opaque { type Extra = (); diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 5903430c..c3a35f0f 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -2,7 +2,7 @@ use super::comp::CompInfo; use super::context::{BindgenContext, ItemId}; -use super::derive::{CanDeriveCopy, CanDeriveDebug}; +use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; use super::enum_ty::Enum; use super::function::FunctionSig; use super::int::IntKind; @@ -412,6 +412,39 @@ impl CanDeriveDebug for Type { } } +impl CanDeriveDefault for Type { + type Extra = (); + + fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool { + match self.kind { + TypeKind::Array(t, len) => { + len <= RUST_DERIVE_IN_ARRAY_LIMIT && + t.can_derive_default(ctx, ()) + } + TypeKind::ResolvedTypeRef(t) | + TypeKind::TemplateAlias(t, _) | + TypeKind::Alias(t) => t.can_derive_default(ctx, ()), + TypeKind::Comp(ref info) => { + info.can_derive_default(ctx, self.layout(ctx)) + } + TypeKind::Void | + TypeKind::Named | + TypeKind::TemplateRef(..) | + TypeKind::Reference(..) | + TypeKind::NullPtr | + TypeKind::Pointer(..) | + TypeKind::BlockPointer | + TypeKind::ObjCInterface(..) | + TypeKind::Enum(..) => false, + TypeKind::Function(..) | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Complex(..) => true, + TypeKind::UnresolvedTypeRef(..) => unreachable!(), + } + } +} + impl<'a> CanDeriveCopy<'a> for Type { type Extra = &'a Item; @@ -320,6 +320,12 @@ impl Builder { self } + /// Set whether `Default` should be derived by default. + pub fn derive_default(mut self, doit: bool) -> Self { + self.options.derive_default = doit; + self + } + /// Emit Clang AST. pub fn emit_clang_ast(mut self) -> Builder { self.options.emit_ast = true; @@ -496,6 +502,10 @@ pub struct BindgenOptions { /// and types. pub derive_debug: bool, + /// True if we shold derive Default trait implementations for C/C++ structures + /// and types. + pub derive_default: bool, + /// True if we can use unstable Rust code in the bindings, false if we /// cannot. pub unstable_rust: bool, @@ -581,6 +591,7 @@ impl Default for BindgenOptions { emit_ast: false, emit_ir: false, derive_debug: true, + derive_default: false, enable_cxx_namespaces: false, disable_name_namespacing: false, unstable_rust: true, diff --git a/src/options.rs b/src/options.rs index 8d11be2d..cc5f4845 100644 --- a/src/options.rs +++ b/src/options.rs @@ -42,6 +42,13 @@ pub fn builder_from_flags<I>(args: I) Arg::with_name("no-derive-debug") .long("no-derive-debug") .help("Avoid deriving Debug on any type."), + Arg::with_name("no-derive-default") + .long("no-derive-default") + .hidden(true) + .help("Avoid deriving Default on any type."), + Arg::with_name("with-derive-default") + .long("with-derive-default") + .help("Deriving Default on any type."), Arg::with_name("no-doc-comments") .long("no-doc-comments") .help("Avoid including doc comments in the output, see: \ @@ -212,6 +219,14 @@ pub fn builder_from_flags<I>(args: I) builder = builder.derive_debug(false); } + if matches.is_present("with-derive-default") { + builder = builder.derive_default(true); + } + + if matches.is_present("no-derive-default") { + builder = builder.derive_default(false); + } + if let Some(prefix) = matches.value_of("ctypes-prefix") { builder = builder.ctypes_prefix(prefix); } |