summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/codegen/mod.rs54
-rw-r--r--src/ir/comp.rs61
-rw-r--r--src/ir/context.rs10
-rw-r--r--src/ir/derive.rs21
-rw-r--r--src/ir/item.rs22
-rw-r--r--src/ir/layout.rs11
-rw-r--r--src/ir/ty.rs35
-rw-r--r--src/lib.rs11
-rw-r--r--src/options.rs15
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;
diff --git a/src/lib.rs b/src/lib.rs
index 84a2ee67..38ff3619 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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);
}