Skip to content

Commit 4932c6f

Browse files
committed
Derive partialeq "manually" when possible
Remove derive-partialeq-template-inst test. Add comments. Don't implement PartialEq for incomplete arrays Handle opaque bases and template instantiations Extract constrain_type. Extract `is whitelisted?` check Add failing partialeq-anonfield join for comps Fix: return insert if not whitelisted Delegate TypeRefs and alias to constrain_join. Delegate Template instantiations to constrain_join Add derive-partialeq-pointer.hpp test Update comment. Fix layout alignment larger that array limit Add missing test for derive-partialeq-anonfield.rs Clean Clean Fix typo in opaque-template-inst-member test Remove redudant stmt Add comment on can_supersede. Format impl_partialeq and leave a comment Extract requires_storage into it's own function. Clean
1 parent c160b20 commit 4932c6f

36 files changed

+2021
-690
lines changed

src/codegen/impl_partialeq.rs

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
2+
use ir::comp::{CompInfo, CompKind, Field, FieldMethods};
3+
use ir::context::BindgenContext;
4+
use ir::item::{IsOpaque, Item};
5+
use ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
6+
use quote;
7+
8+
/// Generate a manual implementation of `PartialEq` trait for the
9+
/// specified compound type.
10+
pub fn gen_partialeq_impl(
11+
ctx: &BindgenContext,
12+
comp_info: &CompInfo,
13+
item: &Item,
14+
ty_for_impl: &quote::Tokens,
15+
) -> Option<quote::Tokens> {
16+
let mut tokens = vec![];
17+
18+
if item.is_opaque(ctx, &()) {
19+
tokens.push(quote! {
20+
&self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..]
21+
});
22+
} else if comp_info.kind() == CompKind::Union {
23+
tokens.push(quote! {
24+
&self.bindgen_union_field[..] == &other.bindgen_union_field[..]
25+
});
26+
} else {
27+
for base in comp_info.base_members().iter() {
28+
if !base.requires_storage(ctx) {
29+
continue;
30+
}
31+
32+
let ty_item = ctx.resolve_item(base.ty);
33+
let field_name = &base.field_name;
34+
35+
if ty_item.is_opaque(ctx, &()) {
36+
let field_name = ctx.rust_ident(field_name);
37+
tokens.push(quote! {
38+
&self. #field_name [..] == &other. #field_name [..]
39+
});
40+
} else {
41+
tokens.push(gen_field(ctx, ty_item, field_name));
42+
}
43+
}
44+
45+
for field in comp_info.fields() {
46+
match *field {
47+
Field::DataMember(ref fd) => {
48+
let ty_item = ctx.resolve_item(fd.ty());
49+
let name = fd.name().unwrap();
50+
tokens.push(gen_field(ctx, ty_item, name));
51+
}
52+
Field::Bitfields(ref bu) => for bitfield in bu.bitfields() {
53+
let name_ident = ctx.rust_ident_raw(bitfield.name());
54+
tokens.push(quote! {
55+
self.#name_ident () == other.#name_ident ()
56+
});
57+
},
58+
}
59+
}
60+
}
61+
62+
Some(quote! {
63+
fn eq(&self, other: & #ty_for_impl) -> bool {
64+
#( #tokens )&&*
65+
}
66+
})
67+
}
68+
69+
fn gen_field(ctx: &BindgenContext, ty_item: &Item, name: &str) -> quote::Tokens {
70+
fn quote_equals(name_ident: quote::Ident) -> quote::Tokens {
71+
quote! { self.#name_ident == other.#name_ident }
72+
}
73+
74+
let name_ident = ctx.rust_ident(name);
75+
let ty = ty_item.expect_type();
76+
77+
match *ty.kind() {
78+
TypeKind::Void |
79+
TypeKind::NullPtr |
80+
TypeKind::Int(..) |
81+
TypeKind::Complex(..) |
82+
TypeKind::Float(..) |
83+
TypeKind::Enum(..) |
84+
TypeKind::TypeParam |
85+
TypeKind::UnresolvedTypeRef(..) |
86+
TypeKind::BlockPointer |
87+
TypeKind::Reference(..) |
88+
TypeKind::ObjCInterface(..) |
89+
TypeKind::ObjCId |
90+
TypeKind::ObjCSel |
91+
TypeKind::Comp(..) |
92+
TypeKind::Pointer(_) |
93+
TypeKind::Function(..) |
94+
TypeKind::Opaque => quote_equals(name_ident),
95+
96+
TypeKind::TemplateInstantiation(ref inst) => {
97+
if inst.is_opaque(ctx, &ty_item) {
98+
quote! {
99+
&self. #name_ident [..] == &other. #name_ident [..]
100+
}
101+
} else {
102+
quote_equals(name_ident)
103+
}
104+
}
105+
106+
TypeKind::Array(_, len) => if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
107+
quote_equals(name_ident)
108+
} else {
109+
quote! {
110+
&self. #name_ident [..] == &other. #name_ident [..]
111+
}
112+
},
113+
114+
TypeKind::ResolvedTypeRef(t) |
115+
TypeKind::TemplateAlias(t, _) |
116+
TypeKind::Alias(t) => {
117+
let inner_item = ctx.resolve_item(t);
118+
gen_field(ctx, inner_item, name)
119+
}
120+
}
121+
}

src/codegen/mod.rs

+56-35
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod impl_debug;
2+
mod impl_partialeq;
23
mod error;
34
mod helpers;
45
pub mod struct_layout;
@@ -13,7 +14,7 @@ use ir::comp::{Base, Bitfield, BitfieldUnit, CompInfo, CompKind, Field,
1314
use ir::context::{BindgenContext, ItemId};
1415
use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault,
1516
CanDeriveHash, CanDerivePartialOrd, CanDeriveOrd,
16-
CanDerivePartialEq, CanDeriveEq};
17+
CanDerivePartialEq, CanDeriveEq, CannotDeriveReason};
1718
use ir::dot;
1819
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
1920
use ir::function::{Abi, Function, FunctionSig};
@@ -1419,6 +1420,7 @@ impl CodeGenerator for CompInfo {
14191420
let mut needs_clone_impl = false;
14201421
let mut needs_default_impl = false;
14211422
let mut needs_debug_impl = false;
1423+
let mut needs_partialeq_impl = false;
14221424
if let Some(comment) = item.comment(ctx) {
14231425
attributes.push(attributes::doc(comment));
14241426
}
@@ -1474,6 +1476,14 @@ impl CodeGenerator for CompInfo {
14741476

14751477
if item.can_derive_partialeq(ctx) {
14761478
derives.push("PartialEq");
1479+
} else {
1480+
needs_partialeq_impl =
1481+
ctx.options().derive_partialeq &&
1482+
ctx.options().impl_partialeq &&
1483+
ctx.lookup_item_id_can_derive_partialeq_or_partialord(item.id())
1484+
.map_or(true, |x| {
1485+
x == CannotDeriveReason::ArrayTooLarge
1486+
});
14771487
}
14781488

14791489
if item.can_derive_eq(ctx) {
@@ -1534,25 +1544,14 @@ impl CodeGenerator for CompInfo {
15341544
}
15351545

15361546
for base in self.base_members() {
1537-
// Virtual bases are already taken into account by the vtable
1538-
// pointer.
1539-
//
1540-
// FIXME(emilio): Is this always right?
1541-
if base.is_virtual() {
1542-
continue;
1543-
}
1544-
1545-
let base_ty = ctx.resolve_type(base.ty);
1546-
// NB: We won't include unsized types in our base chain because they
1547-
// would contribute to our size given the dummy field we insert for
1548-
// unsized types.
1549-
if base_ty.is_unsized(ctx, &base.ty) {
1547+
if !base.requires_storage(ctx) {
15501548
continue;
15511549
}
15521550

15531551
let inner = base.ty.to_rust_ty_or_opaque(ctx, &());
15541552
let field_name = ctx.rust_ident(&base.field_name);
15551553

1554+
let base_ty = ctx.resolve_type(base.ty);
15561555
struct_layout.saw_base(base_ty);
15571556

15581557
fields.push(quote! {
@@ -1666,33 +1665,34 @@ impl CodeGenerator for CompInfo {
16661665
}
16671666
}
16681667

1669-
let mut generics = quote! {};
1668+
let mut generic_param_names = vec![];
16701669

16711670
if let Some(ref params) = used_template_params {
1672-
if !params.is_empty() {
1673-
let mut param_names = vec![];
1671+
for (idx, ty) in params.iter().enumerate() {
1672+
let param = ctx.resolve_type(*ty);
1673+
let name = param.name().unwrap();
1674+
let ident = ctx.rust_ident(name);
1675+
generic_param_names.push(ident.clone());
16741676

1675-
for (idx, ty) in params.iter().enumerate() {
1676-
let param = ctx.resolve_type(*ty);
1677-
let name = param.name().unwrap();
1678-
let ident = ctx.rust_ident(name);
1679-
param_names.push(ident.clone());
1680-
1681-
let prefix = ctx.trait_prefix();
1682-
let field_name = ctx.rust_ident(format!("_phantom_{}", idx));
1683-
fields.push(quote! {
1684-
pub #field_name : ::#prefix::marker::PhantomData<
1685-
::#prefix::cell::UnsafeCell<#ident>
1686-
> ,
1687-
});
1688-
}
1689-
1690-
generics = quote! {
1691-
< #( #param_names ),* >
1692-
};
1677+
let prefix = ctx.trait_prefix();
1678+
let field_name = ctx.rust_ident(format!("_phantom_{}", idx));
1679+
fields.push(quote! {
1680+
pub #field_name : ::#prefix::marker::PhantomData<
1681+
::#prefix::cell::UnsafeCell<#ident>
1682+
> ,
1683+
});
16931684
}
16941685
}
16951686

1687+
let generics = if !generic_param_names.is_empty() {
1688+
let generic_param_names = generic_param_names.clone();
1689+
quote! {
1690+
< #( #generic_param_names ),* >
1691+
}
1692+
} else {
1693+
quote! { }
1694+
};
1695+
16961696
tokens.append(quote! {
16971697
#generics {
16981698
#( #fields )*
@@ -1896,6 +1896,27 @@ impl CodeGenerator for CompInfo {
18961896
});
18971897
}
18981898

1899+
if needs_partialeq_impl {
1900+
if let Some(impl_) = impl_partialeq::gen_partialeq_impl(ctx, self, item, &ty_for_impl) {
1901+
1902+
let partialeq_bounds = if !generic_param_names.is_empty() {
1903+
let bounds = generic_param_names.iter().map(|t| {
1904+
quote! { #t: PartialEq }
1905+
});
1906+
quote! { where #( #bounds ),* }
1907+
} else {
1908+
quote! { }
1909+
};
1910+
1911+
let prefix = ctx.trait_prefix();
1912+
result.push(quote! {
1913+
impl #generics ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds {
1914+
#impl_
1915+
}
1916+
});
1917+
}
1918+
}
1919+
18991920
if !methods.is_empty() {
19001921
result.push(quote! {
19011922
impl #generics #ty_for_impl {

0 commit comments

Comments
 (0)