diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/codegen/mod.rs | 15 | ||||
-rw-r--r-- | src/ir/analysis/has_float.rs | 239 | ||||
-rw-r--r-- | src/ir/analysis/mod.rs | 2 | ||||
-rw-r--r-- | src/ir/context.rs | 51 | ||||
-rw-r--r-- | src/ir/derive.rs | 16 | ||||
-rw-r--r-- | src/ir/item.rs | 32 | ||||
-rw-r--r-- | src/lib.rs | 23 | ||||
-rw-r--r-- | src/options.rs | 7 |
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>; @@ -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); } |