Skip to content

Commit 86ce9dd

Browse files
author
bors-servo
authored
Auto merge of #480 - flier:impl-default, r=emilio
Implement `Default` trait We need `Default` trait to handle so many auto generated fields when create new structure.
2 parents ddc07fc + 25b68ba commit 86ce9dd

File tree

161 files changed

+968
-204
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

161 files changed

+968
-204
lines changed

src/codegen/mod.rs

+50-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use aster;
88
use ir::annotations::FieldAccessorKind;
99
use ir::comp::{Base, CompInfo, CompKind, Field, Method, MethodKind};
1010
use ir::context::{BindgenContext, ItemId};
11-
use ir::derive::{CanDeriveCopy, CanDeriveDebug};
11+
use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
1212
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
1313
use ir::function::{Function, FunctionSig};
1414
use ir::int::IntKind;
@@ -688,10 +688,16 @@ impl<'a> CodeGenerator for Vtable<'a> {
688688
assert_eq!(item.id(), self.item_id);
689689
// For now, generate an empty struct, later we should generate function
690690
// pointers and whatnot.
691+
let mut attributes = vec![attributes::repr("C")];
692+
693+
if ctx.options().derive_default {
694+
attributes.push(attributes::derives(&["Default"]))
695+
}
696+
691697
let vtable = aster::AstBuilder::new()
692698
.item()
693699
.pub_()
694-
.with_attr(attributes::repr("C"))
700+
.with_attrs(attributes)
695701
.struct_(self.canonical_name(ctx))
696702
.build();
697703
result.push(vtable);
@@ -879,6 +885,7 @@ impl CodeGenerator for CompInfo {
879885

880886
let mut attributes = vec![];
881887
let mut needs_clone_impl = false;
888+
let mut needs_default_impl = false;
882889
if ctx.options().generate_comments {
883890
if let Some(comment) = item.comment() {
884891
attributes.push(attributes::doc(comment));
@@ -896,6 +903,12 @@ impl CodeGenerator for CompInfo {
896903
derives.push("Debug");
897904
}
898905

906+
if item.can_derive_default(ctx, ()) {
907+
derives.push("Default");
908+
} else {
909+
needs_default_impl = ctx.options().derive_default;
910+
}
911+
899912
if item.can_derive_copy(ctx, ()) &&
900913
!item.annotations().disallow_copy() {
901914
derives.push("Copy");
@@ -1440,8 +1453,14 @@ impl CodeGenerator for CompInfo {
14401453

14411454
// NB: We can't use to_rust_ty here since for opaque types this tries to
14421455
// use the specialization knowledge to generate a blob field.
1443-
let ty_for_impl =
1444-
aster::AstBuilder::new().ty().path().id(&canonical_name).build();
1456+
let ty_for_impl = aster::AstBuilder::new()
1457+
.ty()
1458+
.path()
1459+
.segment(&canonical_name)
1460+
.with_generics(generics.clone())
1461+
.build()
1462+
.build();
1463+
14451464
if needs_clone_impl {
14461465
let impl_ = quote_item!(ctx.ext_cx(),
14471466
impl X {
@@ -1467,6 +1486,32 @@ impl CodeGenerator for CompInfo {
14671486
result.push(clone_impl);
14681487
}
14691488

1489+
if needs_default_impl {
1490+
let prefix = ctx.trait_prefix();
1491+
let impl_ = quote_item!(ctx.ext_cx(),
1492+
impl X {
1493+
fn default() -> Self { unsafe { ::$prefix::mem::zeroed() } }
1494+
}
1495+
);
1496+
1497+
let impl_ = match impl_.unwrap().node {
1498+
ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(),
1499+
_ => unreachable!(),
1500+
};
1501+
1502+
let default_impl = aster::AstBuilder::new()
1503+
.item()
1504+
.impl_()
1505+
.trait_()
1506+
.id("Default")
1507+
.build()
1508+
.with_generics(generics.clone())
1509+
.with_items(impl_)
1510+
.build_ty(ty_for_impl.clone());
1511+
1512+
result.push(default_impl);
1513+
}
1514+
14701515
if !methods.is_empty() {
14711516
let methods = aster::AstBuilder::new()
14721517
.item()
@@ -2582,6 +2627,7 @@ mod utils {
25822627

25832628
let incomplete_array_decl = quote_item!(ctx.ext_cx(),
25842629
#[repr(C)]
2630+
#[derive(Default)]
25852631
pub struct __IncompleteArrayField<T>(
25862632
::$prefix::marker::PhantomData<T>);
25872633
)

src/ir/comp.rs

+60-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use super::annotations::Annotations;
44
use super::context::{BindgenContext, ItemId};
5-
use super::derive::{CanDeriveCopy, CanDeriveDebug};
5+
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
66
use super::item::Item;
77
use super::layout::Layout;
88
use super::ty::Type;
@@ -171,6 +171,14 @@ impl CanDeriveDebug for Field {
171171
}
172172
}
173173

174+
impl CanDeriveDefault for Field {
175+
type Extra = ();
176+
177+
fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool {
178+
self.ty.can_derive_default(ctx, ())
179+
}
180+
}
181+
174182
impl<'a> CanDeriveCopy<'a> for Field {
175183
type Extra = ();
176184

@@ -296,6 +304,10 @@ pub struct CompInfo {
296304
/// around the template arguments.
297305
detect_derive_debug_cycle: Cell<bool>,
298306

307+
/// Used to detect if we've run in a can_derive_default cycle while cycling
308+
/// around the template arguments.
309+
detect_derive_default_cycle: Cell<bool>,
310+
299311
/// Used to detect if we've run in a has_destructor cycle while cycling
300312
/// around the template arguments.
301313
detect_has_destructor_cycle: Cell<bool>,
@@ -326,6 +338,7 @@ impl CompInfo {
326338
is_anonymous: false,
327339
found_unknown_attr: false,
328340
detect_derive_debug_cycle: Cell::new(false),
341+
detect_derive_default_cycle: Cell::new(false),
329342
detect_has_destructor_cycle: Cell::new(false),
330343
is_forward_declaration: false,
331344
}
@@ -952,6 +965,52 @@ impl CanDeriveDebug for CompInfo {
952965
}
953966
}
954967

968+
impl CanDeriveDefault for CompInfo {
969+
type Extra = Option<Layout>;
970+
971+
fn can_derive_default(&self,
972+
ctx: &BindgenContext,
973+
layout: Option<Layout>)
974+
-> bool {
975+
// We can reach here recursively via template parameters of a member,
976+
// for example.
977+
if self.detect_derive_default_cycle.get() {
978+
warn!("Derive default cycle detected!");
979+
return true;
980+
}
981+
982+
if self.kind == CompKind::Union {
983+
if ctx.options().unstable_rust {
984+
return false;
985+
}
986+
987+
return layout.unwrap_or_else(Layout::zero)
988+
.opaque()
989+
.can_derive_debug(ctx, ());
990+
}
991+
992+
self.detect_derive_default_cycle.set(true);
993+
994+
let can_derive_default = !self.has_vtable(ctx) &&
995+
!self.needs_explicit_vtable(ctx) &&
996+
self.base_members
997+
.iter()
998+
.all(|base| base.ty.can_derive_default(ctx, ())) &&
999+
self.template_args
1000+
.iter()
1001+
.all(|id| id.can_derive_default(ctx, ())) &&
1002+
self.fields
1003+
.iter()
1004+
.all(|f| f.can_derive_default(ctx, ())) &&
1005+
self.ref_template
1006+
.map_or(true, |id| id.can_derive_default(ctx, ()));
1007+
1008+
self.detect_derive_default_cycle.set(false);
1009+
1010+
can_derive_default
1011+
}
1012+
}
1013+
9551014
impl<'a> CanDeriveCopy<'a> for CompInfo {
9561015
type Extra = (&'a Item, Option<Layout>);
9571016

src/ir/context.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Common context that is passed around during parsing and codegen.
22
3-
use super::derive::{CanDeriveCopy, CanDeriveDebug};
3+
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
44
use super::int::IntKind;
55
use super::item::{Item, ItemCanonicalPath};
66
use super::item_kind::ItemKind;
@@ -42,6 +42,14 @@ impl CanDeriveDebug for ItemId {
4242
}
4343
}
4444

45+
impl CanDeriveDefault for ItemId {
46+
type Extra = ();
47+
48+
fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool {
49+
ctx.resolve_item(*self).can_derive_default(ctx, ())
50+
}
51+
}
52+
4553
impl<'a> CanDeriveCopy<'a> for ItemId {
4654
type Extra = ();
4755

src/ir/derive.rs

+21
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,24 @@ pub trait CanDeriveCopy<'a> {
6565
extra: Self::Extra)
6666
-> bool;
6767
}
68+
69+
/// A trait that encapsulates the logic for whether or not we can derive `Default`
70+
/// for a given thing.
71+
///
72+
/// This should ideally be a no-op that just returns `true`, but instead needs
73+
/// to be a recursive method that checks whether all the proper members can
74+
/// derive default or not, because of the limit rust has on 32 items as max in the
75+
/// array.
76+
pub trait CanDeriveDefault {
77+
/// Implementations can define this type to get access to any extra
78+
/// information required to determine whether they can derive `Default`. If
79+
/// extra information is unneeded, then this should simply be the unit type.
80+
type Extra;
81+
82+
/// Return `true` if `Default` can be derived for this thing, `false`
83+
/// otherwise.
84+
fn can_derive_default(&self,
85+
ctx: &BindgenContext,
86+
extra: Self::Extra)
87+
-> bool;
88+
}

src/ir/item.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use super::annotations::Annotations;
44
use super::context::{BindgenContext, ItemId};
5-
use super::derive::{CanDeriveCopy, CanDeriveDebug};
5+
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
66
use super::function::Function;
77
use super::item_kind::ItemKind;
88
use super::module::Module;
@@ -235,6 +235,26 @@ impl CanDeriveDebug for Item {
235235
}
236236
}
237237

238+
impl CanDeriveDefault for Item {
239+
type Extra = ();
240+
241+
fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool {
242+
ctx.options().derive_default &&
243+
match self.kind {
244+
ItemKind::Type(ref ty) => {
245+
if self.is_opaque(ctx) {
246+
ty.layout(ctx)
247+
.map_or(false,
248+
|l| l.opaque().can_derive_default(ctx, ()))
249+
} else {
250+
ty.can_derive_default(ctx, ())
251+
}
252+
}
253+
_ => false,
254+
}
255+
}
256+
}
257+
238258
impl<'a> CanDeriveCopy<'a> for Item {
239259
type Extra = ();
240260

src/ir/layout.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Intermediate representation for the physical layout of some type.
22
33
use super::context::BindgenContext;
4-
use super::derive::{CanDeriveCopy, CanDeriveDebug};
4+
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
55
use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
66
use std::cmp;
77

@@ -79,6 +79,15 @@ impl CanDeriveDebug for Opaque {
7979
}
8080
}
8181

82+
impl CanDeriveDefault for Opaque {
83+
type Extra = ();
84+
85+
fn can_derive_default(&self, _: &BindgenContext, _: ()) -> bool {
86+
self.array_size()
87+
.map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
88+
}
89+
}
90+
8291
impl<'a> CanDeriveCopy<'a> for Opaque {
8392
type Extra = ();
8493

src/ir/ty.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use super::comp::CompInfo;
44
use super::context::{BindgenContext, ItemId};
5-
use super::derive::{CanDeriveCopy, CanDeriveDebug};
5+
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
66
use super::enum_ty::Enum;
77
use super::function::FunctionSig;
88
use super::int::IntKind;
@@ -457,6 +457,39 @@ impl CanDeriveDebug for Type {
457457
}
458458
}
459459

460+
impl CanDeriveDefault for Type {
461+
type Extra = ();
462+
463+
fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool {
464+
match self.kind {
465+
TypeKind::Array(t, len) => {
466+
len <= RUST_DERIVE_IN_ARRAY_LIMIT &&
467+
t.can_derive_default(ctx, ())
468+
}
469+
TypeKind::ResolvedTypeRef(t) |
470+
TypeKind::TemplateAlias(t, _) |
471+
TypeKind::Alias(t) => t.can_derive_default(ctx, ()),
472+
TypeKind::Comp(ref info) => {
473+
info.can_derive_default(ctx, self.layout(ctx))
474+
}
475+
TypeKind::Void |
476+
TypeKind::Named |
477+
TypeKind::TemplateRef(..) |
478+
TypeKind::Reference(..) |
479+
TypeKind::NullPtr |
480+
TypeKind::Pointer(..) |
481+
TypeKind::BlockPointer |
482+
TypeKind::ObjCInterface(..) |
483+
TypeKind::Enum(..) => false,
484+
TypeKind::Function(..) |
485+
TypeKind::Int(..) |
486+
TypeKind::Float(..) |
487+
TypeKind::Complex(..) => true,
488+
TypeKind::UnresolvedTypeRef(..) => unreachable!(),
489+
}
490+
}
491+
}
492+
460493
impl<'a> CanDeriveCopy<'a> for Type {
461494
type Extra = &'a Item;
462495

src/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,12 @@ impl Builder {
320320
self
321321
}
322322

323+
/// Set whether `Default` should be derived by default.
324+
pub fn derive_default(mut self, doit: bool) -> Self {
325+
self.options.derive_default = doit;
326+
self
327+
}
328+
323329
/// Emit Clang AST.
324330
pub fn emit_clang_ast(mut self) -> Builder {
325331
self.options.emit_ast = true;
@@ -496,6 +502,10 @@ pub struct BindgenOptions {
496502
/// and types.
497503
pub derive_debug: bool,
498504

505+
/// True if we shold derive Default trait implementations for C/C++ structures
506+
/// and types.
507+
pub derive_default: bool,
508+
499509
/// True if we can use unstable Rust code in the bindings, false if we
500510
/// cannot.
501511
pub unstable_rust: bool,
@@ -586,6 +596,7 @@ impl Default for BindgenOptions {
586596
emit_ast: false,
587597
emit_ir: false,
588598
derive_debug: true,
599+
derive_default: false,
589600
enable_cxx_namespaces: false,
590601
disable_name_namespacing: false,
591602
unstable_rust: true,

0 commit comments

Comments
 (0)