Skip to content

Commit 978b531

Browse files
author
bors-servo
authored
Auto merge of rust-lang#919 - photoszzt:has_float, r=fitzgen
Can derive Eq Fix: rust-lang#880 r? @fitzgen
2 parents 723e93d + ff9d000 commit 978b531

File tree

200 files changed

+803
-414
lines changed

Some content is hidden

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

200 files changed

+803
-414
lines changed

src/codegen/mod.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use ir::comp::{Base, Bitfield, BitfieldUnit, CompInfo, CompKind, Field,
1515
FieldData, FieldMethods, Method, MethodKind};
1616
use ir::context::{BindgenContext, ItemId};
1717
use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault,
18-
CanDeriveHash, CanDerivePartialEq};
18+
CanDeriveHash, CanDerivePartialEq, CanDeriveEq};
1919
use ir::dot;
2020
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
2121
use ir::function::{Abi, Function, FunctionSig};
@@ -1516,6 +1516,10 @@ impl CodeGenerator for CompInfo {
15161516
derives.push("PartialEq");
15171517
}
15181518

1519+
if item.can_derive_eq(ctx) {
1520+
derives.push("Eq");
1521+
}
1522+
15191523
if !derives.is_empty() {
15201524
attributes.push(attributes::derives(&derives))
15211525
}
@@ -3617,14 +3621,21 @@ mod utils {
36173621
}
36183622
).unwrap();
36193623

3624+
let union_field_eq_impl = quote_item!(&ctx.ext_cx(),
3625+
impl<T> ::$prefix::cmp::Eq for __BindgenUnionField<T> {
3626+
}
3627+
)
3628+
.unwrap();
3629+
36203630
let items = vec![union_field_decl,
36213631
union_field_impl,
36223632
union_field_default_impl,
36233633
union_field_clone_impl,
36243634
union_field_copy_impl,
36253635
union_field_debug_impl,
36263636
union_field_hash_impl,
3627-
union_field_partialeq_impl];
3637+
union_field_partialeq_impl,
3638+
union_field_eq_impl];
36283639

36293640
let old_items = mem::replace(result, items);
36303641
result.extend(old_items.into_iter());

src/ir/analysis/has_float.rs

+239
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
//! Determining which types has float.
2+
3+
use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
4+
use std::collections::HashSet;
5+
use std::collections::HashMap;
6+
use ir::context::{BindgenContext, ItemId};
7+
use ir::traversal::EdgeKind;
8+
use ir::ty::TypeKind;
9+
use ir::comp::Field;
10+
use ir::comp::FieldMethods;
11+
12+
/// An analysis that finds for each IR item whether it has float or not.
13+
///
14+
/// We use the monotone constraint function `has_float`,
15+
/// defined as follows:
16+
///
17+
/// * If T is float or complex float, T trivially has.
18+
/// * If T is a type alias, a templated alias or an indirection to another type,
19+
/// it has float if the type T refers to has.
20+
/// * If T is a compound type, it has float if any of base memter or field
21+
/// has.
22+
/// * If T is an instantiation of an abstract template definition, T has
23+
/// float if any of the template arguments or template definition
24+
/// has.
25+
#[derive(Debug, Clone)]
26+
pub struct HasFloat<'ctx, 'gen>
27+
where 'gen: 'ctx
28+
{
29+
ctx: &'ctx BindgenContext<'gen>,
30+
31+
// The incremental result of this analysis's computation. Everything in this
32+
// set has float.
33+
has_float: HashSet<ItemId>,
34+
35+
// Dependencies saying that if a key ItemId has been inserted into the
36+
// `has_float` set, then each of the ids in Vec<ItemId> need to be
37+
// considered again.
38+
//
39+
// This is a subset of the natural IR graph with reversed edges, where we
40+
// only include the edges from the IR graph that can affect whether a type
41+
// has float or not.
42+
dependencies: HashMap<ItemId, Vec<ItemId>>,
43+
}
44+
45+
impl<'ctx, 'gen> HasFloat<'ctx, 'gen> {
46+
fn consider_edge(kind: EdgeKind) -> bool {
47+
match kind {
48+
EdgeKind::BaseMember |
49+
EdgeKind::Field |
50+
EdgeKind::TypeReference |
51+
EdgeKind::VarType |
52+
EdgeKind::TemplateArgument |
53+
EdgeKind::TemplateDeclaration |
54+
EdgeKind::TemplateParameterDefinition => true,
55+
56+
EdgeKind::Constructor |
57+
EdgeKind::Destructor |
58+
EdgeKind::FunctionReturn |
59+
EdgeKind::FunctionParameter |
60+
EdgeKind::InnerType |
61+
EdgeKind::InnerVar |
62+
EdgeKind::Method => false,
63+
EdgeKind::Generic => false,
64+
}
65+
}
66+
67+
fn insert(&mut self, id: ItemId) -> ConstrainResult {
68+
trace!("inserting {:?} into the has_float set", id);
69+
70+
let was_not_already_in_set = self.has_float.insert(id);
71+
assert!(
72+
was_not_already_in_set,
73+
"We shouldn't try and insert {:?} twice because if it was \
74+
already in the set, `constrain` should have exited early.",
75+
id
76+
);
77+
78+
ConstrainResult::Changed
79+
}
80+
}
81+
82+
impl<'ctx, 'gen> MonotoneFramework for HasFloat<'ctx, 'gen> {
83+
type Node = ItemId;
84+
type Extra = &'ctx BindgenContext<'gen>;
85+
type Output = HashSet<ItemId>;
86+
87+
fn new(ctx: &'ctx BindgenContext<'gen>) -> HasFloat<'ctx, 'gen> {
88+
let has_float = HashSet::new();
89+
let dependencies = generate_dependencies(ctx, Self::consider_edge);
90+
91+
HasFloat {
92+
ctx,
93+
has_float,
94+
dependencies,
95+
}
96+
}
97+
98+
fn initial_worklist(&self) -> Vec<ItemId> {
99+
self.ctx.whitelisted_items().iter().cloned().collect()
100+
}
101+
102+
fn constrain(&mut self, id: ItemId) -> ConstrainResult {
103+
trace!("constrain: {:?}", id);
104+
105+
if self.has_float.contains(&id) {
106+
trace!(" already know it do not have float");
107+
return ConstrainResult::Same;
108+
}
109+
110+
let item = self.ctx.resolve_item(id);
111+
let ty = match item.as_type() {
112+
Some(ty) => ty,
113+
None => {
114+
trace!(" not a type; ignoring");
115+
return ConstrainResult::Same;
116+
}
117+
};
118+
119+
match *ty.kind() {
120+
TypeKind::Void |
121+
TypeKind::NullPtr |
122+
TypeKind::Int(..) |
123+
TypeKind::Function(..) |
124+
TypeKind::Enum(..) |
125+
TypeKind::Reference(..) |
126+
TypeKind::BlockPointer |
127+
TypeKind::TypeParam |
128+
TypeKind::Opaque |
129+
TypeKind::Pointer(..) |
130+
TypeKind::UnresolvedTypeRef(..) |
131+
TypeKind::ObjCInterface(..) |
132+
TypeKind::ObjCId |
133+
TypeKind::ObjCSel => {
134+
trace!(" simple type that do not have float");
135+
ConstrainResult::Same
136+
}
137+
138+
TypeKind::Float(..) |
139+
TypeKind::Complex(..) => {
140+
trace!(" float type has float");
141+
self.insert(id)
142+
}
143+
144+
TypeKind::Array(t, _) => {
145+
if self.has_float.contains(&t) {
146+
trace!(" Array with type T that has float also has float");
147+
return self.insert(id)
148+
}
149+
trace!(" Array with type T that do not have float also do not have float");
150+
ConstrainResult::Same
151+
}
152+
153+
TypeKind::ResolvedTypeRef(t) |
154+
TypeKind::TemplateAlias(t, _) |
155+
TypeKind::Alias(t) => {
156+
if self.has_float.contains(&t) {
157+
trace!(" aliases and type refs to T which have float \
158+
also have float");
159+
self.insert(id)
160+
} else {
161+
trace!(" aliases and type refs to T which do not have float \
162+
also do not have floaarrayt");
163+
ConstrainResult::Same
164+
}
165+
}
166+
167+
TypeKind::Comp(ref info) => {
168+
let bases_have = info.base_members()
169+
.iter()
170+
.any(|base| self.has_float.contains(&base.ty));
171+
if bases_have {
172+
trace!(" bases have float, so we also have");
173+
return self.insert(id);
174+
}
175+
let fields_have = info.fields()
176+
.iter()
177+
.any(|f| {
178+
match *f {
179+
Field::DataMember(ref data) => {
180+
self.has_float.contains(&data.ty())
181+
}
182+
Field::Bitfields(ref bfu) => {
183+
bfu.bitfields()
184+
.iter().any(|b| {
185+
self.has_float.contains(&b.ty())
186+
})
187+
},
188+
}
189+
});
190+
if fields_have {
191+
trace!(" fields have float, so we also have");
192+
return self.insert(id);
193+
}
194+
195+
trace!(" comp doesn't have float");
196+
ConstrainResult::Same
197+
}
198+
199+
TypeKind::TemplateInstantiation(ref template) => {
200+
let args_have = template.template_arguments()
201+
.iter()
202+
.any(|arg| self.has_float.contains(&arg));
203+
if args_have {
204+
trace!(" template args have float, so \
205+
insantiation also has float");
206+
return self.insert(id);
207+
}
208+
209+
let def_has = self.has_float
210+
.contains(&template.template_definition());
211+
if def_has {
212+
trace!(" template definition has float, so \
213+
insantiation also has");
214+
return self.insert(id);
215+
}
216+
217+
trace!(" template instantiation do not have float");
218+
ConstrainResult::Same
219+
}
220+
}
221+
}
222+
223+
fn each_depending_on<F>(&self, id: ItemId, mut f: F)
224+
where F: FnMut(ItemId),
225+
{
226+
if let Some(edges) = self.dependencies.get(&id) {
227+
for item in edges {
228+
trace!("enqueue {:?} into worklist", item);
229+
f(*item);
230+
}
231+
}
232+
}
233+
}
234+
235+
impl<'ctx, 'gen> From<HasFloat<'ctx, 'gen>> for HashSet<ItemId> {
236+
fn from(analysis: HasFloat<'ctx, 'gen>) -> Self {
237+
analysis.has_float
238+
}
239+
}

src/ir/analysis/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ mod derive_hash;
5555
pub use self::derive_hash::CannotDeriveHash;
5656
mod derive_partial_eq;
5757
pub use self::derive_partial_eq::CannotDerivePartialEq;
58+
mod has_float;
59+
pub use self::has_float::HasFloat;
5860

5961
use ir::context::{BindgenContext, ItemId};
6062
use ir::traversal::{EdgeKind, Trace};

src/ir/context.rs

+43-8
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
use super::analysis::{CannotDeriveCopy, CannotDeriveDebug,
44
CannotDeriveDefault, CannotDeriveHash,
55
CannotDerivePartialEq, HasTypeParameterInArray,
6-
HasVtableAnalysis, UsedTemplateParameters, analyze};
6+
HasVtableAnalysis, UsedTemplateParameters, HasFloat,
7+
analyze};
78
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault,
8-
CanDeriveHash, CanDerivePartialEq};
9+
CanDeriveHash, CanDerivePartialEq, CanDeriveEq};
910
use super::int::IntKind;
1011
use super::item::{HasTypeParamInArray, IsOpaque, Item, ItemAncestors,
1112
ItemCanonicalPath, ItemSet};
@@ -76,6 +77,14 @@ impl CanDerivePartialEq for ItemId {
7677
}
7778
}
7879

80+
impl CanDeriveEq for ItemId {
81+
fn can_derive_eq(&self, ctx: &BindgenContext) -> bool {
82+
ctx.options().derive_eq &&
83+
ctx.lookup_item_id_can_derive_partialeq(*self) &&
84+
!ctx.lookup_item_id_has_float(&self)
85+
}
86+
}
87+
7988
/// A key used to index a resolved type, so we only process it once.
8089
///
8190
/// This is almost always a USR string (an unique identifier generated by
@@ -235,6 +244,12 @@ pub struct BindgenContext<'ctx> {
235244
/// Populated when we enter codegen by `compute_has_type_param_in_array`; always `None`
236245
/// before that and `Some` after.
237246
has_type_param_in_array: Option<HashSet<ItemId>>,
247+
248+
/// The set of (`ItemId's of`) types that has float.
249+
///
250+
/// Populated when we enter codegen by `compute_has_float`; always `None`
251+
/// before that and `Some` after.
252+
has_float: Option<HashSet<ItemId>>,
238253
}
239254

240255
/// A traversal of whitelisted items.
@@ -376,6 +391,7 @@ impl<'ctx> BindgenContext<'ctx> {
376391
cannot_derive_partialeq: None,
377392
have_vtable: None,
378393
has_type_param_in_array: None,
394+
has_float: None,
379395
};
380396

381397
me.add_item(root_module, None, None);
@@ -890,8 +906,9 @@ impl<'ctx> BindgenContext<'ctx> {
890906
self.compute_cannot_derive_default();
891907
self.compute_cannot_derive_copy();
892908
self.compute_has_type_param_in_array();
909+
self.compute_has_float();
893910
self.compute_cannot_derive_hash();
894-
self.compute_cannot_derive_partialeq();
911+
self.compute_cannot_derive_partialeq_or_eq();
895912

896913
let ret = cb(self);
897914
self.gen_ctx = None;
@@ -2018,12 +2035,12 @@ impl<'ctx> BindgenContext<'ctx> {
20182035
!self.cannot_derive_hash.as_ref().unwrap().contains(&id)
20192036
}
20202037

2021-
/// Compute whether we can derive partialeq.
2022-
fn compute_cannot_derive_partialeq(&mut self) {
2038+
/// Compute whether we can derive PartialEq. This method is also used in calculating
2039+
/// whether we can derive Eq
2040+
fn compute_cannot_derive_partialeq_or_eq(&mut self) {
20232041
assert!(self.cannot_derive_partialeq.is_none());
2024-
if self.options.derive_partialeq {
2025-
self.cannot_derive_partialeq =
2026-
Some(analyze::<CannotDerivePartialEq>(self));
2042+
if self.options.derive_partialeq || self.options.derive_eq {
2043+
self.cannot_derive_partialeq = Some(analyze::<CannotDerivePartialEq>(self));
20272044
}
20282045
}
20292046

@@ -2072,6 +2089,24 @@ impl<'ctx> BindgenContext<'ctx> {
20722089
// type parameter in array or not.
20732090
self.has_type_param_in_array.as_ref().unwrap().contains(id)
20742091
}
2092+
2093+
/// Compute whether the type has float.
2094+
fn compute_has_float(&mut self) {
2095+
assert!(self.has_float.is_none());
2096+
if self.options.derive_eq {
2097+
self.has_float = Some(analyze::<HasFloat>(self));
2098+
}
2099+
}
2100+
2101+
/// Look up whether the item with `id` has array or not.
2102+
pub fn lookup_item_id_has_float(&self, id: &ItemId) -> bool {
2103+
assert!(self.in_codegen_phase(),
2104+
"We only compute has float when we enter codegen");
2105+
2106+
// Look up the computed value for whether the item with `id` has
2107+
// float or not.
2108+
self.has_float.as_ref().unwrap().contains(id)
2109+
}
20752110
}
20762111

20772112
/// A builder struct for configuring item resolution options.

0 commit comments

Comments
 (0)