summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/codegen/mod.rs15
-rw-r--r--src/ir/analysis/has_float.rs239
-rw-r--r--src/ir/analysis/mod.rs2
-rw-r--r--src/ir/context.rs51
-rw-r--r--src/ir/derive.rs16
-rw-r--r--src/ir/item.rs32
-rw-r--r--src/lib.rs23
-rw-r--r--src/options.rs7
8 files changed, 374 insertions, 11 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 2ab507da..7066003b 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -15,7 +15,7 @@ use ir::comp::{Base, Bitfield, BitfieldUnit, CompInfo, CompKind, Field,
FieldData, FieldMethods, Method, MethodKind};
use ir::context::{BindgenContext, ItemId};
use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault,
- CanDeriveHash, CanDerivePartialEq};
+ CanDeriveHash, CanDerivePartialEq, CanDeriveEq};
use ir::dot;
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
use ir::function::{Abi, Function, FunctionSig};
@@ -1516,6 +1516,10 @@ impl CodeGenerator for CompInfo {
derives.push("PartialEq");
}
+ if item.can_derive_eq(ctx) {
+ derives.push("Eq");
+ }
+
if !derives.is_empty() {
attributes.push(attributes::derives(&derives))
}
@@ -3617,6 +3621,12 @@ mod utils {
}
).unwrap();
+ let union_field_eq_impl = quote_item!(&ctx.ext_cx(),
+ impl<T> ::$prefix::cmp::Eq for __BindgenUnionField<T> {
+ }
+ )
+ .unwrap();
+
let items = vec![union_field_decl,
union_field_impl,
union_field_default_impl,
@@ -3624,7 +3634,8 @@ mod utils {
union_field_copy_impl,
union_field_debug_impl,
union_field_hash_impl,
- union_field_partialeq_impl];
+ union_field_partialeq_impl,
+ union_field_eq_impl];
let old_items = mem::replace(result, items);
result.extend(old_items.into_iter());
diff --git a/src/ir/analysis/has_float.rs b/src/ir/analysis/has_float.rs
new file mode 100644
index 00000000..85fe241e
--- /dev/null
+++ b/src/ir/analysis/has_float.rs
@@ -0,0 +1,239 @@
+//! Determining which types has float.
+
+use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
+use std::collections::HashSet;
+use std::collections::HashMap;
+use ir::context::{BindgenContext, ItemId};
+use ir::traversal::EdgeKind;
+use ir::ty::TypeKind;
+use ir::comp::Field;
+use ir::comp::FieldMethods;
+
+/// An analysis that finds for each IR item whether it has float or not.
+///
+/// We use the monotone constraint function `has_float`,
+/// defined as follows:
+///
+/// * If T is float or complex float, T trivially has.
+/// * If T is a type alias, a templated alias or an indirection to another type,
+/// it has float if the type T refers to has.
+/// * If T is a compound type, it has float if any of base memter or field
+/// has.
+/// * If T is an instantiation of an abstract template definition, T has
+/// float if any of the template arguments or template definition
+/// has.
+#[derive(Debug, Clone)]
+pub struct HasFloat<'ctx, 'gen>
+ where 'gen: 'ctx
+{
+ ctx: &'ctx BindgenContext<'gen>,
+
+ // The incremental result of this analysis's computation. Everything in this
+ // set has float.
+ has_float: HashSet<ItemId>,
+
+ // Dependencies saying that if a key ItemId has been inserted into the
+ // `has_float` set, then each of the ids in Vec<ItemId> need to be
+ // considered again.
+ //
+ // This is a subset of the natural IR graph with reversed edges, where we
+ // only include the edges from the IR graph that can affect whether a type
+ // has float or not.
+ dependencies: HashMap<ItemId, Vec<ItemId>>,
+}
+
+impl<'ctx, 'gen> HasFloat<'ctx, 'gen> {
+ fn consider_edge(kind: EdgeKind) -> bool {
+ match kind {
+ EdgeKind::BaseMember |
+ EdgeKind::Field |
+ EdgeKind::TypeReference |
+ EdgeKind::VarType |
+ EdgeKind::TemplateArgument |
+ EdgeKind::TemplateDeclaration |
+ EdgeKind::TemplateParameterDefinition => true,
+
+ EdgeKind::Constructor |
+ EdgeKind::Destructor |
+ EdgeKind::FunctionReturn |
+ EdgeKind::FunctionParameter |
+ EdgeKind::InnerType |
+ EdgeKind::InnerVar |
+ EdgeKind::Method => false,
+ EdgeKind::Generic => false,
+ }
+ }
+
+ fn insert(&mut self, id: ItemId) -> ConstrainResult {
+ trace!("inserting {:?} into the has_float set", id);
+
+ let was_not_already_in_set = self.has_float.insert(id);
+ assert!(
+ was_not_already_in_set,
+ "We shouldn't try and insert {:?} twice because if it was \
+ already in the set, `constrain` should have exited early.",
+ id
+ );
+
+ ConstrainResult::Changed
+ }
+}
+
+impl<'ctx, 'gen> MonotoneFramework for HasFloat<'ctx, 'gen> {
+ type Node = ItemId;
+ type Extra = &'ctx BindgenContext<'gen>;
+ type Output = HashSet<ItemId>;
+
+ fn new(ctx: &'ctx BindgenContext<'gen>) -> HasFloat<'ctx, 'gen> {
+ let has_float = HashSet::new();
+ let dependencies = generate_dependencies(ctx, Self::consider_edge);
+
+ HasFloat {
+ ctx,
+ has_float,
+ dependencies,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<ItemId> {
+ self.ctx.whitelisted_items().iter().cloned().collect()
+ }
+
+ fn constrain(&mut self, id: ItemId) -> ConstrainResult {
+ trace!("constrain: {:?}", id);
+
+ if self.has_float.contains(&id) {
+ trace!(" already know it do not have float");
+ return ConstrainResult::Same;
+ }
+
+ let item = self.ctx.resolve_item(id);
+ let ty = match item.as_type() {
+ Some(ty) => ty,
+ None => {
+ trace!(" not a type; ignoring");
+ return ConstrainResult::Same;
+ }
+ };
+
+ match *ty.kind() {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::BlockPointer |
+ TypeKind::TypeParam |
+ TypeKind::Opaque |
+ TypeKind::Pointer(..) |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::ObjCInterface(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel => {
+ trace!(" simple type that do not have float");
+ ConstrainResult::Same
+ }
+
+ TypeKind::Float(..) |
+ TypeKind::Complex(..) => {
+ trace!(" float type has float");
+ self.insert(id)
+ }
+
+ TypeKind::Array(t, _) => {
+ if self.has_float.contains(&t) {
+ trace!(" Array with type T that has float also has float");
+ return self.insert(id)
+ }
+ trace!(" Array with type T that do not have float also do not have float");
+ ConstrainResult::Same
+ }
+
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) => {
+ if self.has_float.contains(&t) {
+ trace!(" aliases and type refs to T which have float \
+ also have float");
+ self.insert(id)
+ } else {
+ trace!(" aliases and type refs to T which do not have float \
+ also do not have floaarrayt");
+ ConstrainResult::Same
+ }
+ }
+
+ TypeKind::Comp(ref info) => {
+ let bases_have = info.base_members()
+ .iter()
+ .any(|base| self.has_float.contains(&base.ty));
+ if bases_have {
+ trace!(" bases have float, so we also have");
+ return self.insert(id);
+ }
+ let fields_have = info.fields()
+ .iter()
+ .any(|f| {
+ match *f {
+ Field::DataMember(ref data) => {
+ self.has_float.contains(&data.ty())
+ }
+ Field::Bitfields(ref bfu) => {
+ bfu.bitfields()
+ .iter().any(|b| {
+ self.has_float.contains(&b.ty())
+ })
+ },
+ }
+ });
+ if fields_have {
+ trace!(" fields have float, so we also have");
+ return self.insert(id);
+ }
+
+ trace!(" comp doesn't have float");
+ ConstrainResult::Same
+ }
+
+ TypeKind::TemplateInstantiation(ref template) => {
+ let args_have = template.template_arguments()
+ .iter()
+ .any(|arg| self.has_float.contains(&arg));
+ if args_have {
+ trace!(" template args have float, so \
+ insantiation also has float");
+ return self.insert(id);
+ }
+
+ let def_has = self.has_float
+ .contains(&template.template_definition());
+ if def_has {
+ trace!(" template definition has float, so \
+ insantiation also has");
+ return self.insert(id);
+ }
+
+ trace!(" template instantiation do not have float");
+ ConstrainResult::Same
+ }
+ }
+ }
+
+ fn each_depending_on<F>(&self, id: ItemId, mut f: F)
+ where F: FnMut(ItemId),
+ {
+ if let Some(edges) = self.dependencies.get(&id) {
+ for item in edges {
+ trace!("enqueue {:?} into worklist", item);
+ f(*item);
+ }
+ }
+ }
+}
+
+impl<'ctx, 'gen> From<HasFloat<'ctx, 'gen>> for HashSet<ItemId> {
+ fn from(analysis: HasFloat<'ctx, 'gen>) -> Self {
+ analysis.has_float
+ }
+}
diff --git a/src/ir/analysis/mod.rs b/src/ir/analysis/mod.rs
index cf4e3b4d..42aa4a8f 100644
--- a/src/ir/analysis/mod.rs
+++ b/src/ir/analysis/mod.rs
@@ -55,6 +55,8 @@ mod derive_hash;
pub use self::derive_hash::CannotDeriveHash;
mod derive_partial_eq;
pub use self::derive_partial_eq::CannotDerivePartialEq;
+mod has_float;
+pub use self::has_float::HasFloat;
use ir::context::{BindgenContext, ItemId};
use ir::traversal::{EdgeKind, Trace};
diff --git a/src/ir/context.rs b/src/ir/context.rs
index eb599dd0..67245c29 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -3,9 +3,10 @@
use super::analysis::{CannotDeriveCopy, CannotDeriveDebug,
CannotDeriveDefault, CannotDeriveHash,
CannotDerivePartialEq, HasTypeParameterInArray,
- HasVtableAnalysis, UsedTemplateParameters, analyze};
+ HasVtableAnalysis, UsedTemplateParameters, HasFloat,
+ analyze};
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault,
- CanDeriveHash, CanDerivePartialEq};
+ CanDeriveHash, CanDerivePartialEq, CanDeriveEq};
use super::int::IntKind;
use super::item::{HasTypeParamInArray, IsOpaque, Item, ItemAncestors,
ItemCanonicalPath, ItemSet};
@@ -76,6 +77,14 @@ impl CanDerivePartialEq for ItemId {
}
}
+impl CanDeriveEq for ItemId {
+ fn can_derive_eq(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_eq &&
+ ctx.lookup_item_id_can_derive_partialeq(*self) &&
+ !ctx.lookup_item_id_has_float(&self)
+ }
+}
+
/// A key used to index a resolved type, so we only process it once.
///
/// This is almost always a USR string (an unique identifier generated by
@@ -235,6 +244,12 @@ pub struct BindgenContext<'ctx> {
/// Populated when we enter codegen by `compute_has_type_param_in_array`; always `None`
/// before that and `Some` after.
has_type_param_in_array: Option<HashSet<ItemId>>,
+
+ /// The set of (`ItemId's of`) types that has float.
+ ///
+ /// Populated when we enter codegen by `compute_has_float`; always `None`
+ /// before that and `Some` after.
+ has_float: Option<HashSet<ItemId>>,
}
/// A traversal of whitelisted items.
@@ -376,6 +391,7 @@ impl<'ctx> BindgenContext<'ctx> {
cannot_derive_partialeq: None,
have_vtable: None,
has_type_param_in_array: None,
+ has_float: None,
};
me.add_item(root_module, None, None);
@@ -890,8 +906,9 @@ impl<'ctx> BindgenContext<'ctx> {
self.compute_cannot_derive_default();
self.compute_cannot_derive_copy();
self.compute_has_type_param_in_array();
+ self.compute_has_float();
self.compute_cannot_derive_hash();
- self.compute_cannot_derive_partialeq();
+ self.compute_cannot_derive_partialeq_or_eq();
let ret = cb(self);
self.gen_ctx = None;
@@ -2018,12 +2035,12 @@ impl<'ctx> BindgenContext<'ctx> {
!self.cannot_derive_hash.as_ref().unwrap().contains(&id)
}
- /// Compute whether we can derive partialeq.
- fn compute_cannot_derive_partialeq(&mut self) {
+ /// Compute whether we can derive PartialEq. This method is also used in calculating
+ /// whether we can derive Eq
+ fn compute_cannot_derive_partialeq_or_eq(&mut self) {
assert!(self.cannot_derive_partialeq.is_none());
- if self.options.derive_partialeq {
- self.cannot_derive_partialeq =
- Some(analyze::<CannotDerivePartialEq>(self));
+ if self.options.derive_partialeq || self.options.derive_eq {
+ self.cannot_derive_partialeq = Some(analyze::<CannotDerivePartialEq>(self));
}
}
@@ -2072,6 +2089,24 @@ impl<'ctx> BindgenContext<'ctx> {
// type parameter in array or not.
self.has_type_param_in_array.as_ref().unwrap().contains(id)
}
+
+ /// Compute whether the type has float.
+ fn compute_has_float(&mut self) {
+ assert!(self.has_float.is_none());
+ if self.options.derive_eq {
+ self.has_float = Some(analyze::<HasFloat>(self));
+ }
+ }
+
+ /// Look up whether the item with `id` has array or not.
+ pub fn lookup_item_id_has_float(&self, id: &ItemId) -> bool {
+ assert!(self.in_codegen_phase(),
+ "We only compute has float when we enter codegen");
+
+ // Look up the computed value for whether the item with `id` has
+ // float or not.
+ self.has_float.as_ref().unwrap().contains(id)
+ }
}
/// A builder struct for configuring item resolution options.
diff --git a/src/ir/derive.rs b/src/ir/derive.rs
index ef511694..909d5e42 100644
--- a/src/ir/derive.rs
+++ b/src/ir/derive.rs
@@ -92,6 +92,22 @@ pub trait CanDerivePartialEq {
fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool;
}
+/// A trait that encapsulates the logic for whether or not we can derive `Eq`
+/// 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 eq or not, because of the limit rust has on 32 items as max in the
+/// array.
+pub trait CanDeriveEq {
+
+ /// Return `true` if `Eq` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_derive_eq(&self,
+ ctx: &BindgenContext)
+ -> bool;
+}
+
/// A trait that encapsulates the logic for whether or not we can derive `Hash`.
/// The difference between this trait and the CanDeriveHash is that the type
/// implementing this trait cannot use recursion or lookup result from fix point
diff --git a/src/ir/item.rs b/src/ir/item.rs
index dfb2697d..b6fe6d43 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -6,7 +6,7 @@ use super::comment;
use super::comp::MethodKind;
use super::context::{BindgenContext, ItemId, PartialType};
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault,
- CanDeriveHash, CanDerivePartialEq};
+ CanDeriveHash, CanDerivePartialEq, CanDeriveEq};
use super::dot::DotAttributes;
use super::function::{Function, FunctionKind};
use super::item_kind::ItemKind;
@@ -83,6 +83,12 @@ pub trait HasTypeParamInArray {
fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool;
}
+/// A trait for determining if some IR thing has float or not.
+pub trait HasFloat {
+ /// Returns `true` if the thing has float, and `false` otherwise.
+ fn has_float(&self, ctx: &BindgenContext) -> bool;
+}
+
/// A trait for iterating over an item and its parents and up its ancestor chain
/// up to (but not including) the implicit root module.
pub trait ItemAncestors {
@@ -340,6 +346,14 @@ impl CanDerivePartialEq for Item {
}
}
+impl CanDeriveEq for Item {
+ fn can_derive_eq(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_eq &&
+ ctx.lookup_item_id_can_derive_partialeq(self.id()) &&
+ !ctx.lookup_item_id_has_float(&self.id())
+ }
+}
+
/// An item is the base of the bindgen representation, it can be either a
/// module, a type, a function, or a variable (see `ItemKind` for more
/// information).
@@ -989,6 +1003,22 @@ impl HasTypeParamInArray for Item {
}
}
+impl HasFloat for ItemId {
+ fn has_float(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ ctx.lookup_item_id_has_float(self)
+ }
+}
+
+impl HasFloat for Item {
+ fn has_float(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ ctx.lookup_item_id_has_float(&self.id())
+ }
+}
+
/// A set of items.
pub type ItemSet = BTreeSet<ItemId>;
diff --git a/src/lib.rs b/src/lib.rs
index 3954ee26..d5dbefae 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -274,6 +274,10 @@ impl Builder {
output_vector.push("--with-derive-partialeq".into());
}
+ if self.options.derive_eq {
+ output_vector.push("--with-derive-eq".into());
+ }
+
if !self.options.generate_comments {
output_vector.push("--no-doc-comments".into());
}
@@ -751,8 +755,22 @@ impl Builder {
}
/// Set whether `PartialEq` should be derived by default.
+ /// If we don't compute partialeq, we also cannot compute
+ /// eq. Set the derive_eq to `false` when doit is `false`.
pub fn derive_partialeq(mut self, doit: bool) -> Self {
self.options.derive_partialeq = doit;
+ if !doit {
+ self.options.derive_eq = false;
+ }
+ self
+ }
+
+ /// Set whether `Eq` should be derived by default.
+ /// We can't compute Eq without computing PartialEq, so
+ /// we set the same option to derive_partialeq.
+ pub fn derive_eq(mut self, doit: bool) -> Self {
+ self.options.derive_eq = doit;
+ self.options.derive_partialeq = doit;
self
}
@@ -1094,6 +1112,10 @@ pub struct BindgenOptions {
/// and types.
pub derive_partialeq: bool,
+ /// True if we should derive Eq trait implementations for C/C++ structures
+ /// and types.
+ pub derive_eq: bool,
+
/// True if we should avoid using libstd to use libcore instead.
pub use_core: bool,
@@ -1237,6 +1259,7 @@ impl Default for BindgenOptions {
derive_default: false,
derive_hash: false,
derive_partialeq: false,
+ derive_eq: false,
enable_cxx_namespaces: false,
disable_name_namespacing: false,
use_core: false,
diff --git a/src/options.rs b/src/options.rs
index 68b127ae..780959e2 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -81,6 +81,9 @@ where
Arg::with_name("with-derive-partialeq")
.long("with-derive-partialeq")
.help("Derive partialeq on any type."),
+ Arg::with_name("with-derive-eq")
+ .long("with-derive-eq")
+ .help("Derive eq on any type. Enable this option also enables --with-derive-partialeq"),
Arg::with_name("no-doc-comments")
.long("no-doc-comments")
.help("Avoid including doc comments in the output, see: \
@@ -325,6 +328,10 @@ where
builder = builder.derive_partialeq(true);
}
+ if matches.is_present("with-derive-eq") {
+ builder = builder.derive_eq(true);
+ }
+
if matches.is_present("no-derive-default") {
builder = builder.derive_default(false);
}