summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/codegen/mod.rs19
-rw-r--r--src/ir/analysis/derive_hash.rs337
-rw-r--r--src/ir/analysis/mod.rs2
-rw-r--r--src/ir/context.rs38
-rw-r--r--src/ir/derive.rs27
-rw-r--r--src/ir/function.rs19
-rw-r--r--src/ir/item.rs8
-rw-r--r--src/ir/layout.rs11
-rw-r--r--src/lib.rs15
-rw-r--r--src/options.rs7
10 files changed, 474 insertions, 9 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 5c00a53d..9521fb1e 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -13,7 +13,7 @@ use ir::comp::{Base, BitfieldUnit, Bitfield, CompInfo, CompKind, Field,
FieldData, FieldMethods, Method, MethodKind};
use ir::comment;
use ir::context::{BindgenContext, ItemId};
-use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
+use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveHash};
use ir::dot;
use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
use ir::function::{Abi, Function, FunctionSig};
@@ -1440,6 +1440,10 @@ impl CodeGenerator for CompInfo {
}
}
+ if item.can_derive_hash(ctx) {
+ derives.push("Hash");
+ }
+
if !derives.is_empty() {
attributes.push(attributes::derives(&derives))
}
@@ -3394,12 +3398,23 @@ mod utils {
)
.unwrap();
+ // The actual memory of the filed will be hashed, so that's why these
+ // field doesn't do anything with the hash.
+ let union_field_hash_impl = quote_item!(&ctx.ext_cx(),
+ impl<T> ::$prefix::hash::Hash for __BindgenUnionField<T> {
+ fn hash<H: ::$prefix::hash::Hasher>(&self, _state: &mut H) {
+ }
+ }
+ )
+ .unwrap();
+
let items = vec![union_field_decl,
union_field_impl,
union_field_default_impl,
union_field_clone_impl,
union_field_copy_impl,
- union_field_debug_impl];
+ union_field_debug_impl,
+ union_field_hash_impl];
let old_items = mem::replace(result, items);
result.extend(old_items.into_iter());
diff --git a/src/ir/analysis/derive_hash.rs b/src/ir/analysis/derive_hash.rs
new file mode 100644
index 00000000..2456143c
--- /dev/null
+++ b/src/ir/analysis/derive_hash.rs
@@ -0,0 +1,337 @@
+//! Determining which types for which we can emit `#[derive(Hash)]`.
+
+use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
+use std::collections::HashSet;
+use std::collections::HashMap;
+use ir::context::{BindgenContext, ItemId};
+use ir::item::IsOpaque;
+use ir::traversal::EdgeKind;
+use ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
+use ir::ty::TypeKind;
+use ir::comp::Field;
+use ir::comp::FieldMethods;
+use ir::derive::CanTriviallyDeriveHash;
+use ir::comp::CompKind;
+
+/// An analysis that finds for each IR item whether hash cannot be derived.
+///
+/// We use the monotone constraint function `cannot_derive_hash`, defined as
+/// follows:
+///
+/// * If T is Opaque and layout of the type is known, get this layout as opaque
+/// type and check whether it can be derived using trivial checks.
+/// * If T is Array type, hash cannot be derived if the length of the array is
+/// larger than the limit or the type of data the array contains cannot derive
+/// hash.
+/// * If T is a type alias, a templated alias or an indirection to another type,
+/// hash cannot be derived if the type T refers to cannot be derived hash.
+/// * If T is a compound type, hash cannot be derived if any of its base member
+/// or field cannot be derived hash.
+/// * If T is a pointer, T cannot be derived hash if T is a function pointer
+/// and the function signature cannot be derived hash.
+/// * If T is an instantiation of an abstract template definition, T cannot be
+/// derived hash if any of the template arguments or template definition
+/// cannot derive hash.
+#[derive(Debug, Clone)]
+pub struct CannotDeriveHash<'ctx, 'gen>
+ where 'gen: 'ctx
+{
+ ctx: &'ctx BindgenContext<'gen>,
+
+ // The incremental result of this analysis's computation. Everything in this
+ // set cannot derive hash.
+ cannot_derive_hash: HashSet<ItemId>,
+
+ // Dependencies saying that if a key ItemId has been inserted into the
+ // `cannot_derive_hash` 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
+ // can derive hash or not.
+ dependencies: HashMap<ItemId, Vec<ItemId>>,
+}
+
+impl<'ctx, 'gen> CannotDeriveHash<'ctx, 'gen> {
+ fn consider_edge(kind: EdgeKind) -> bool {
+ match kind {
+ // These are the only edges that can affect whether a type can derive
+ // hash or not.
+ 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 cannot_derive_hash set", id);
+
+ let was_not_already_in_set = self.cannot_derive_hash.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 CannotDeriveHash<'ctx, 'gen> {
+ type Node = ItemId;
+ type Extra = &'ctx BindgenContext<'gen>;
+ type Output = HashSet<ItemId>;
+
+ fn new(ctx: &'ctx BindgenContext<'gen>) -> CannotDeriveHash<'ctx, 'gen> {
+ let cannot_derive_hash = HashSet::new();
+ let dependencies = generate_dependencies(ctx, Self::consider_edge);
+
+ CannotDeriveHash {
+ ctx,
+ cannot_derive_hash,
+ 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.cannot_derive_hash.contains(&id) {
+ trace!(" already know it cannot derive Hash");
+ 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;
+ }
+ };
+
+ if item.is_opaque(self.ctx, &()) {
+ let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| {
+ l.opaque().can_trivially_derive_hash()
+ });
+ return if layout_can_derive {
+ trace!(" we can trivially derive Hash for the layout");
+ ConstrainResult::Same
+ } else {
+ trace!(" we cannot derive Hash for the layout");
+ self.insert(id)
+ };
+ }
+
+ if ty.layout(self.ctx).map_or(false, |l| l.align > RUST_DERIVE_IN_ARRAY_LIMIT) {
+ // We have to be conservative: the struct *could* have enough
+ // padding that we emit an array that is longer than
+ // `RUST_DERIVE_IN_ARRAY_LIMIT`. If we moved padding calculations
+ // into the IR and computed them before this analysis, then we could
+ // be precise rather than conservative here.
+ return self.insert(id);
+ }
+
+ match *ty.kind() {
+ // Handle the simple cases. These can derive hash without further
+ // information.
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Named |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::BlockPointer |
+ TypeKind::Reference(..) |
+ TypeKind::ObjCInterface(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel => {
+ trace!(" simple type that can always derive Hash");
+ ConstrainResult::Same
+ }
+
+ TypeKind::Complex(..) |
+ TypeKind::Float(..) => {
+ trace!(" float cannot derive Hash");
+ self.insert(id)
+ }
+
+ TypeKind::Array(t, len) => {
+ if self.cannot_derive_hash.contains(&t) {
+ trace!(" arrays of T for which we cannot derive Hash \
+ also cannot derive Hash");
+ return self.insert(id);
+ }
+
+ if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
+ trace!(" array is small enough to derive Hash");
+ ConstrainResult::Same
+ } else {
+ trace!(" array is too large to derive Hash");
+ self.insert(id)
+ }
+ }
+
+ TypeKind::Pointer(inner) => {
+ let inner_type = self.ctx.resolve_type(inner).canonical_type(self.ctx);
+ if let TypeKind::Function(ref sig) = *inner_type.kind() {
+ if !sig.can_trivially_derive_hash() {
+ trace!(" function pointer that can't trivially derive Hash");
+ return self.insert(id);
+ }
+ }
+ trace!(" pointers can derive Hash");
+ ConstrainResult::Same
+ }
+
+ TypeKind::Function(ref sig) => {
+ if !sig.can_trivially_derive_hash() {
+ trace!(" function that can't trivially derive Hash");
+ return self.insert(id);
+ }
+ trace!(" function can derive Hash");
+ ConstrainResult::Same
+ }
+
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) => {
+ if self.cannot_derive_hash.contains(&t) {
+ trace!(" aliases and type refs to T which cannot derive \
+ Hash also cannot derive Hash");
+ self.insert(id)
+ } else {
+ trace!(" aliases and type refs to T which can derive \
+ Hash can also derive Hash");
+ ConstrainResult::Same
+ }
+ }
+
+ TypeKind::Comp(ref info) => {
+ assert!(
+ !info.has_non_type_template_params(),
+ "The early ty.is_opaque check should have handled this case"
+ );
+
+ if info.kind() == CompKind::Union {
+ if self.ctx.options().unstable_rust {
+ trace!(" cannot derive Hash for Rust unions");
+ return self.insert(id);
+ }
+
+ if ty.layout(self.ctx)
+ .map_or(true,
+ |l| l.opaque().can_trivially_derive_hash()) {
+ trace!(" union layout can trivially derive Hash");
+ return ConstrainResult::Same;
+ } else {
+ trace!(" union layout cannot derive Hash");
+ return self.insert(id);
+ }
+ }
+
+ let bases_cannot_derive = info.base_members()
+ .iter()
+ .any(|base| !self.ctx.whitelisted_items().contains(&base.ty) ||
+ self.cannot_derive_hash.contains(&base.ty));
+ if bases_cannot_derive {
+ trace!(" base members cannot derive Hash, so we can't \
+ either");
+ return self.insert(id);
+ }
+
+ let fields_cannot_derive = info.fields()
+ .iter()
+ .any(|f| {
+ match *f {
+ Field::DataMember(ref data) => {
+ !self.ctx.whitelisted_items().contains(&data.ty()) ||
+ self.cannot_derive_hash.contains(&data.ty())
+ }
+ Field::Bitfields(ref bfu) => {
+ bfu.bitfields()
+ .iter().any(|b| {
+ !self.ctx.whitelisted_items().contains(&b.ty()) ||
+ self.cannot_derive_hash.contains(&b.ty())
+ })
+ }
+ }
+ });
+ if fields_cannot_derive {
+ trace!(" fields cannot derive Hash, so we can't either");
+ return self.insert(id);
+ }
+
+ trace!(" comp can derive Hash");
+ ConstrainResult::Same
+ }
+
+ TypeKind::TemplateInstantiation(ref template) => {
+ let args_cannot_derive = template.template_arguments()
+ .iter()
+ .any(|arg| self.cannot_derive_hash.contains(&arg));
+ if args_cannot_derive {
+ trace!(" template args cannot derive Hash, so \
+ insantiation can't either");
+ return self.insert(id);
+ }
+
+ assert!(
+ !template.template_definition().is_opaque(self.ctx, &()),
+ "The early ty.is_opaque check should have handled this case"
+ );
+ let def_cannot_derive = self.cannot_derive_hash
+ .contains(&template.template_definition());
+ if def_cannot_derive {
+ trace!(" template definition cannot derive Hash, so \
+ insantiation can't either");
+ return self.insert(id);
+ }
+
+ trace!(" template instantiation can derive Hash");
+ ConstrainResult::Same
+ }
+
+ TypeKind::Opaque => {
+ unreachable!(
+ "The early ty.is_opaque check should have handled this case"
+ )
+ }
+ }
+ }
+
+ 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<CannotDeriveHash<'ctx, 'gen>> for HashSet<ItemId> {
+ fn from(analysis: CannotDeriveHash<'ctx, 'gen>) -> Self {
+ analysis.cannot_derive_hash
+ }
+}
diff --git a/src/ir/analysis/mod.rs b/src/ir/analysis/mod.rs
index f77c0886..28ca09aa 100644
--- a/src/ir/analysis/mod.rs
+++ b/src/ir/analysis/mod.rs
@@ -51,6 +51,8 @@ mod derive_copy;
pub use self::derive_copy::CannotDeriveCopy;
mod has_type_param_in_array;
pub use self::has_type_param_in_array::HasTypeParameterInArray;
+mod derive_hash;
+pub use self::derive_hash::CannotDeriveHash;
use ir::context::{BindgenContext, ItemId};
use ir::traversal::{EdgeKind, Trace};
diff --git a/src/ir/context.rs b/src/ir/context.rs
index 2e0899ed..5caebeda 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -1,12 +1,13 @@
//! Common context that is passed around during parsing and codegen.
-use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
+use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveHash};
use super::int::IntKind;
use super::item::{IsOpaque, HasTypeParamInArray, Item, ItemAncestors, ItemCanonicalPath, ItemSet};
use super::item_kind::ItemKind;
use super::module::{Module, ModuleKind};
use super::analysis::{analyze, UsedTemplateParameters, CannotDeriveDebug, HasVtableAnalysis,
- CannotDeriveDefault, CannotDeriveCopy, HasTypeParameterInArray};
+ CannotDeriveDefault, CannotDeriveCopy, HasTypeParameterInArray,
+ CannotDeriveHash};
use super::template::{TemplateInstantiation, TemplateParameters};
use super::traversal::{self, Edge, ItemTraversal};
use super::ty::{FloatKind, Type, TypeKind};
@@ -58,6 +59,12 @@ impl<'a> CanDeriveCopy<'a> for ItemId {
}
}
+impl CanDeriveHash for ItemId {
+ fn can_derive_hash(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_hash && ctx.lookup_item_id_can_derive_hash(*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
@@ -194,6 +201,12 @@ pub struct BindgenContext<'ctx> {
/// and is always `None` before that and `Some` after.
cannot_derive_copy_in_array: Option<HashSet<ItemId>>,
+ /// The set of (`ItemId`s of) types that can't derive hash.
+ ///
+ /// This is populated when we enter codegen by `compute_can_derive_hash`
+ /// and is always `None` before that and `Some` after.
+ cannot_derive_hash: Option<HashSet<ItemId>>,
+
/// The set of (`ItemId's of`) types that has vtable.
///
/// Populated when we enter codegen by `compute_has_vtable`; always `None`
@@ -334,6 +347,7 @@ impl<'ctx> BindgenContext<'ctx> {
cannot_derive_default: None,
cannot_derive_copy: None,
cannot_derive_copy_in_array: None,
+ cannot_derive_hash: None,
have_vtable: None,
has_type_param_in_array: None,
};
@@ -812,6 +826,7 @@ impl<'ctx> BindgenContext<'ctx> {
self.compute_cannot_derive_default();
self.compute_cannot_derive_copy();
self.compute_has_type_param_in_array();
+ self.compute_cannot_derive_hash();
let ret = cb(self);
self.gen_ctx = None;
@@ -1818,8 +1833,25 @@ impl<'ctx> BindgenContext<'ctx> {
self.cannot_derive_copy = Some(analyze::<CannotDeriveCopy>(self));
}
+ /// Compute whether we can derive hash.
+ fn compute_cannot_derive_hash(&mut self) {
+ assert!(self.cannot_derive_hash.is_none());
+ self.cannot_derive_hash = Some(analyze::<CannotDeriveHash>(self));
+ }
+
/// Look up whether the item with `id` can
- /// derive debug or not.
+ /// derive hash or not.
+ pub fn lookup_item_id_can_derive_hash(&self, id: ItemId) -> bool {
+ assert!(self.in_codegen_phase(),
+ "We only compute can_derive_debug when we enter codegen");
+
+ // Look up the computed value for whether the item with `id` can
+ // derive hash or not.
+ !self.cannot_derive_hash.as_ref().unwrap().contains(&id)
+ }
+
+ /// Look up whether the item with `id` can
+ /// derive copy or not.
pub fn lookup_item_id_can_derive_copy(&self, id: ItemId) -> bool {
assert!(self.in_codegen_phase(),
"We only compute can_derive_debug when we enter codegen");
diff --git a/src/ir/derive.rs b/src/ir/derive.rs
index 6d8c2c87..128ef9f2 100644
--- a/src/ir/derive.rs
+++ b/src/ir/derive.rs
@@ -71,3 +71,30 @@ pub trait CanTriviallyDeriveDefault {
/// otherwise.
fn can_trivially_derive_default(&self) -> bool;
}
+
+/// A trait that encapsulates the logic for whether or not we can derive `Hash`
+/// 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 default or not, because of the limit rust has on 32 items as max in the
+/// array.
+pub trait CanDeriveHash {
+
+ /// Return `true` if `Default` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_derive_hash(&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
+/// analysis. It's a helper trait for fix point analysis.
+pub trait CanTriviallyDeriveHash {
+
+ /// Return `true` if `Hash` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_trivially_derive_hash(&self) -> bool;
+}
diff --git a/src/ir/function.rs b/src/ir/function.rs
index 99ab8772..20c026a4 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -8,11 +8,13 @@ use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::TypeKind;
use clang;
use clang_sys::{self, CXCallingConv};
-use ir::derive::CanTriviallyDeriveDebug;
+use ir::derive::{CanTriviallyDeriveDebug, CanTriviallyDeriveHash};
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
use std::io;
use syntax::abi;
+const RUST_DERIVE_FUNPTR_LIMIT: usize = 12;
+
/// What kind of a function are we looking at?
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FunctionKind {
@@ -481,7 +483,20 @@ impl Trace for FunctionSig {
// Note that copy is always derived, so we don't need to implement it.
impl CanTriviallyDeriveDebug for FunctionSig {
fn can_trivially_derive_debug(&self) -> bool {
- const RUST_DERIVE_FUNPTR_LIMIT: usize = 12;
+ if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT {
+ return false;
+ }
+
+ match self.abi {
+ Abi::Known(abi::Abi::C) |
+ Abi::Unknown(..) => true,
+ _ => false,
+ }
+ }
+}
+
+impl CanTriviallyDeriveHash for FunctionSig {
+ fn can_trivially_derive_hash(&self) -> bool {
if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT {
return false;
}
diff --git a/src/ir/item.rs b/src/ir/item.rs
index a17f26fb..237618c8 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -5,7 +5,7 @@ use super::annotations::Annotations;
use super::comment;
use super::comp::MethodKind;
use super::context::{BindgenContext, ItemId, PartialType};
-use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
+use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveHash};
use super::dot::DotAttributes;
use super::function::{Function, FunctionKind};
use super::item_kind::ItemKind;
@@ -294,6 +294,12 @@ impl<'a> CanDeriveCopy<'a> for Item {
}
}
+impl CanDeriveHash for Item {
+ fn can_derive_hash(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_hash && ctx.lookup_item_id_can_derive_hash(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).
diff --git a/src/ir/layout.rs b/src/ir/layout.rs
index 9ec04d20..bac664f1 100644
--- a/src/ir/layout.rs
+++ b/src/ir/layout.rs
@@ -1,7 +1,8 @@
//! Intermediate representation for the physical layout of some type.
use super::derive::{CanTriviallyDeriveDebug,
- CanTriviallyDeriveDefault, CanTriviallyDeriveCopy};
+ CanTriviallyDeriveDefault, CanTriviallyDeriveCopy,
+ CanTriviallyDeriveHash};
use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind};
use clang;
use std::{cmp, mem};
@@ -123,3 +124,11 @@ impl CanTriviallyDeriveCopy for Opaque {
.map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
}
}
+
+impl CanTriviallyDeriveHash for Opaque {
+
+ fn can_trivially_derive_hash(&self) -> bool {
+ self.array_size()
+ .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 3a853829..bb42117d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -242,6 +242,10 @@ impl Builder {
output_vector.push("--with-derive-default".into());
}
+ if self.options.derive_hash {
+ output_vector.push("--with-derive-hash".into());
+ }
+
if !self.options.generate_comments {
output_vector.push("--no-doc-comments".into());
}
@@ -652,6 +656,12 @@ impl Builder {
self
}
+ /// Set whether `Hash` should be derived by default.
+ pub fn derive_hash(mut self, doit: bool) -> Self {
+ self.options.derive_hash = doit;
+ self
+ }
+
/// Emit Clang AST.
pub fn emit_clang_ast(mut self) -> Builder {
self.options.emit_ast = true;
@@ -955,6 +965,10 @@ pub struct BindgenOptions {
/// and types.
pub derive_default: bool,
+ /// True if we should derive Hash trait implementations for C/C++ structures
+ /// and types.
+ pub derive_hash: bool,
+
/// True if we can use unstable Rust code in the bindings, false if we
/// cannot.
pub unstable_rust: bool,
@@ -1064,6 +1078,7 @@ impl Default for BindgenOptions {
layout_tests: true,
derive_debug: true,
derive_default: false,
+ derive_hash: false,
enable_cxx_namespaces: false,
disable_name_namespacing: false,
unstable_rust: false,
diff --git a/src/options.rs b/src/options.rs
index f2ed5494..706936af 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -62,6 +62,9 @@ pub fn builder_from_flags<I>
Arg::with_name("with-derive-default")
.long("with-derive-default")
.help("Derive Default on any type."),
+ Arg::with_name("with-derive-hash")
+ .long("with-derive-hash")
+ .help("Derive hash on any type."),
Arg::with_name("no-doc-comments")
.long("no-doc-comments")
.help("Avoid including doc comments in the output, see: \
@@ -265,6 +268,10 @@ pub fn builder_from_flags<I>
builder = builder.derive_default(true);
}
+ if matches.is_present("with-derive-hash") {
+ builder = builder.derive_hash(true);
+ }
+
if matches.is_present("no-derive-default") {
builder = builder.derive_default(false);
}