summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/codegen/impl_debug.rs3
-rw-r--r--src/codegen/mod.rs2
-rw-r--r--src/ir/analysis/derive.rs674
-rw-r--r--src/ir/analysis/derive_copy.rs356
-rw-r--r--src/ir/analysis/derive_debug.rs369
-rw-r--r--src/ir/analysis/derive_default.rs407
-rw-r--r--src/ir/analysis/derive_hash.rs392
-rw-r--r--src/ir/analysis/derive_partialeq_or_partialord.rs420
-rw-r--r--src/ir/analysis/mod.rs12
-rw-r--r--src/ir/context.rs13
-rw-r--r--src/ir/derive.rs53
-rw-r--r--src/ir/function.rs24
-rw-r--r--src/ir/layout.rs44
-rw-r--r--tests/expectations/tests/issue-1285.rs51
14 files changed, 740 insertions, 2080 deletions
diff --git a/src/codegen/impl_debug.rs b/src/codegen/impl_debug.rs
index d429e328..fd486511 100644
--- a/src/codegen/impl_debug.rs
+++ b/src/codegen/impl_debug.rs
@@ -1,6 +1,5 @@
use ir::comp::{BitfieldUnit, CompKind, Field, FieldData, FieldMethods};
use ir::context::BindgenContext;
-use ir::derive::CanTriviallyDeriveDebug;
use ir::item::{HasTypeParamInArray, IsOpaque, Item, ItemCanonicalName};
use ir::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, TypeKind};
use proc_macro2;
@@ -236,7 +235,7 @@ impl<'a> ImplDebug<'a> for Item {
let inner_type = ctx.resolve_type(inner).canonical_type(ctx);
match *inner_type.kind() {
TypeKind::Function(ref sig)
- if !sig.can_trivially_derive_debug(ctx) => {
+ if !sig.function_pointers_can_derive() => {
Some((format!("{}: FunctionPointer", name), vec![]))
}
_ => debug_print(name, quote! { #name_ident }),
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index d7f98c13..0956eb7a 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -1746,7 +1746,7 @@ impl CodeGenerator for CompInfo {
needs_partialeq_impl =
ctx.options().derive_partialeq &&
ctx.options().impl_partialeq &&
- ctx.lookup_can_derive_partialeq_or_partialord(item.id()) == CanDerive::ArrayTooLarge;
+ ctx.lookup_can_derive_partialeq_or_partialord(item.id()) == CanDerive::Manually;
}
if item.can_derive_eq(ctx) {
diff --git a/src/ir/analysis/derive.rs b/src/ir/analysis/derive.rs
new file mode 100644
index 00000000..1025150d
--- /dev/null
+++ b/src/ir/analysis/derive.rs
@@ -0,0 +1,674 @@
+//! Determining which types for which we cannot emit `#[derive(Trait)]`.
+
+use std::fmt;
+
+use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
+use ir::analysis::has_vtable::HasVtable;
+use ir::comp::CompKind;
+use ir::context::{BindgenContext, ItemId};
+use ir::derive::CanDerive;
+use ir::function::FunctionSig;
+use ir::item::{Item, IsOpaque};
+use ir::template::TemplateParameters;
+use ir::traversal::{EdgeKind, Trace};
+use ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
+use ir::ty::{TypeKind, Type};
+use {HashSet, HashMap, Entry};
+
+/// Which trait to consider when doing the `CannotDerive` analysis.
+#[derive(Debug, Copy, Clone)]
+pub enum DeriveTrait {
+ /// The `Copy` trait.
+ Copy,
+ /// The `Debug` trait.
+ Debug,
+ /// The `Default` trait.
+ Default,
+ /// The `Hash` trait.
+ Hash,
+ /// The `PartialEq` and `PartialOrd` traits.
+ PartialEqOrPartialOrd,
+}
+
+/// An analysis that finds for each IR item whether a trait cannot be derived.
+///
+/// We use the monotone constraint function `cannot_derive`, defined as follows
+/// for type T:
+///
+/// * If T is Opaque and the layout of the type is known, get this layout as an
+/// opaquetype and check whether it can derive using trivial checks.
+///
+/// * If T is Array, a trait cannot be derived if the array is incomplete,
+/// if the length of the array is larger than the limit (unless the trait
+/// allows it), or the trait cannot be derived for the type of data the array
+/// contains.
+///
+/// * If T is Vector, a trait cannot be derived if the trait cannot be derived
+/// for the type of data the vector contains.
+///
+/// * If T is a type alias, a templated alias or an indirection to another type,
+/// the trait cannot be derived if the trait cannot be derived for type T
+/// refers to.
+///
+/// * If T is a compound type, the trait cannot be derived if the trait cannot
+/// be derived for any of its base members or fields.
+///
+/// * If T is an instantiation of an abstract template definition, the trait
+/// cannot be derived if any of the template arguments or template definition
+/// cannot derive the trait.
+///
+/// * For all other (simple) types, compiler and standard library limitations
+/// dictate whether the trait is implemented.
+#[derive(Debug, Clone)]
+pub struct CannotDerive<'ctx> {
+ ctx: &'ctx BindgenContext,
+
+ derive_trait: DeriveTrait,
+
+ // The incremental result of this analysis's computation.
+ // Contains information whether particular item can derive `derive_trait`
+ can_derive: HashMap<ItemId, CanDerive>,
+
+ // Dependencies saying that if a key ItemId has been inserted into the
+ // `cannot_derive_partialeq_or_partialord` 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 `derive_trait`.
+ dependencies: HashMap<ItemId, Vec<ItemId>>,
+}
+
+type EdgePredicate = fn(EdgeKind) -> bool;
+
+fn consider_edge_default(kind: EdgeKind) -> bool {
+ match kind {
+ // These are the only edges that can affect whether a type can derive
+ 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 |
+ EdgeKind::Generic => false,
+ }
+}
+
+impl<'ctx> CannotDerive<'ctx> {
+ fn insert<Id: Into<ItemId>>(
+ &mut self,
+ id: Id,
+ can_derive: CanDerive,
+ ) -> ConstrainResult {
+ let id = id.into();
+ trace!("inserting {:?} can_derive<{}>={:?}", id, self.derive_trait, can_derive);
+
+ if let CanDerive::Yes = can_derive {
+ return ConstrainResult::Same;
+ }
+
+ match self.can_derive.entry(id) {
+ Entry::Occupied(mut entry) => if *entry.get() < can_derive {
+ entry.insert(can_derive);
+ ConstrainResult::Changed
+ } else {
+ ConstrainResult::Same
+ },
+ Entry::Vacant(entry) => {
+ entry.insert(can_derive);
+ ConstrainResult::Changed
+ }
+ }
+ }
+
+ fn constrain_type(&mut self, item: &Item, ty: &Type) -> CanDerive {
+ if !self.ctx.whitelisted_items().contains(&item.id()) {
+ trace!(" cannot derive {} for blacklisted type", self.derive_trait);
+ return CanDerive::No;
+ }
+
+ if self.derive_trait.not_by_name(self.ctx, &item) {
+ trace!(" cannot derive {} for explicitly excluded type", self.derive_trait);
+ return CanDerive::No;
+ }
+
+ trace!("ty: {:?}", ty);
+ if item.is_opaque(self.ctx, &()) {
+ if !self.derive_trait.can_derive_union()
+ && ty.is_union()
+ && self.ctx.options().rust_features().untagged_union
+ {
+ trace!(
+ " cannot derive {} for Rust unions", self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ let layout_can_derive = ty.layout(self.ctx)
+ .map_or(CanDerive::Yes, |l| {
+ l.opaque().array_size_within_derive_limit(self.ctx)
+ });
+
+ match layout_can_derive {
+ CanDerive::Yes => {
+ trace!(
+ " we can trivially derive {} for the layout", self.derive_trait
+ );
+ }
+ _ => {
+ trace!(
+ " we cannot derive {} for the layout", self.derive_trait
+ );
+ }
+ };
+ return layout_can_derive;
+ }
+
+ match *ty.kind() {
+ // Handle the simple cases. These can derive traits without further
+ // information.
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Float(..) |
+ TypeKind::Enum(..) |
+ TypeKind::TypeParam |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::Reference(..) |
+ TypeKind::ObjCInterface(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel => {
+ return self.derive_trait.can_derive_simple(ty.kind());
+ }
+ 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 let DeriveTrait::Default = self.derive_trait {
+ return CanDerive::No
+ } else {
+ return self.derive_trait.can_derive_fnptr(sig)
+ }
+ } else {
+ return self.derive_trait.can_derive_pointer();
+ }
+ }
+ TypeKind::Function(ref sig) => {
+ return self.derive_trait.can_derive_fnptr(sig)
+ }
+
+ // Complex cases need more information
+ TypeKind::Array(t, len) => {
+ let inner_type = self.can_derive
+ .get(&t.into())
+ .cloned()
+ .unwrap_or_default();
+ if inner_type != CanDerive::Yes {
+ trace!(
+ " arrays of T for which we cannot derive {} \
+ also cannot derive {}", self.derive_trait, self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ if len == 0 && !self.derive_trait.can_derive_incomplete_array() {
+ trace!(
+ " cannot derive {} for incomplete arrays", self.derive_trait
+ );
+ return CanDerive::No;
+ } else {
+ if self.derive_trait.can_derive_large_array() {
+ trace!(" array can derive {}", self.derive_trait);
+ return CanDerive::Yes;
+ } else {
+ if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
+ trace!(
+ " array is small enough to derive {}", self.derive_trait
+ );
+ return CanDerive::Yes;
+ } else {
+ trace!(
+ " array is too large to derive {}, but it may be implemented", self.derive_trait
+ );
+ return CanDerive::Manually;
+ }
+ }
+ }
+ }
+ TypeKind::Vector(t, len) => {
+ let inner_type = self.can_derive
+ .get(&t.into())
+ .cloned()
+ .unwrap_or_default();
+ if inner_type != CanDerive::Yes {
+ trace!(
+ " vectors of T for which we cannot derive {} \
+ also cannot derive {}", self.derive_trait, self.derive_trait
+ );
+ return CanDerive::No;
+ }
+ assert_ne!(len, 0, "vectors cannot have zero length");
+ return self.derive_trait.can_derive_vector()
+ }
+
+ TypeKind::Comp(ref info) => {
+ assert!(
+ !info.has_non_type_template_params(),
+ "The early ty.is_opaque check should have handled this case"
+ );
+
+ if !self.derive_trait.can_derive_compound_forward_decl()
+ && info.is_forward_declaration() {
+ trace!(" cannot derive {} for forward decls", self.derive_trait);
+ return CanDerive::No;
+ }
+
+ // NOTE: Take into account that while unions in C and C++ are copied by
+ // default, the may have an explicit destructor in C++, so we can't
+ // defer this check just for the union case.
+ if !self.derive_trait.can_derive_compound_with_destructor()
+ && self.ctx.lookup_has_destructor(item.id().expect_type_id(self.ctx))
+ {
+ trace!(" comp has destructor which cannot derive {}", self.derive_trait);
+ return CanDerive::No;
+ }
+
+ if info.kind() == CompKind::Union {
+ if self.derive_trait.can_derive_union() {
+ if self.ctx.options().rust_features().untagged_union &&
+ // https://github.com/rust-lang/rust/issues/36640
+ (!info.self_template_params(self.ctx).is_empty() ||
+ !item.all_template_params(self.ctx).is_empty()) {
+ trace!(
+ " cannot derive {} for Rust union because issue 36640", self.derive_trait
+ );
+ return CanDerive::No;
+ }
+ // fall through to be same as non-union handling
+ } else {
+ if self.ctx.options().rust_features().untagged_union {
+ trace!(
+ " cannot derive {} for Rust unions", self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ let layout_can_derive =
+ ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
+ l.opaque().array_size_within_derive_limit(self.ctx)
+ });
+ match layout_can_derive {
+ CanDerive::Yes => {
+ trace!(
+ " union layout can trivially derive {}", self.derive_trait
+ );
+ }
+ _ => {
+ trace!(
+ " union layout cannot derive {}", self.derive_trait
+ );
+ }
+ };
+ return layout_can_derive;
+ }
+ }
+
+ if !self.derive_trait.can_derive_compound_with_vtable()
+ && item.has_vtable(self.ctx) {
+ trace!(" cannot derive {} for comp with vtable", self.derive_trait);
+ return CanDerive::No;
+ }
+
+ let pred = self.derive_trait.consider_edge_comp();
+ return self.constrain_join(item, pred);
+ }
+
+ TypeKind::ResolvedTypeRef(..) |
+ TypeKind::TemplateAlias(..) |
+ TypeKind::Alias(..) |
+ TypeKind::BlockPointer(..) => {
+ let pred = self.derive_trait.consider_edge_typeref();
+ return self.constrain_join(item, pred);
+ }
+
+ TypeKind::TemplateInstantiation(..) => {
+ let pred = self.derive_trait.consider_edge_tmpl_inst();
+ return self.constrain_join(item, pred);
+ }
+
+ TypeKind::Opaque => unreachable!(
+ "The early ty.is_opaque check should have handled this case"
+ ),
+ }
+ }
+
+ fn constrain_join(&mut self, item: &Item, consider_edge: EdgePredicate) -> CanDerive {
+ let mut candidate = None;
+
+ item.trace(
+ self.ctx,
+ &mut |sub_id, edge_kind| {
+ // Ignore ourselves, since union with ourself is a
+ // no-op. Ignore edges that aren't relevant to the
+ // analysis.
+ if sub_id == item.id() || !consider_edge(edge_kind) {
+ return;
+ }
+
+ let can_derive = self.can_derive
+ .get(&sub_id)
+ .cloned()
+ .unwrap_or_default();
+
+ match can_derive {
+ CanDerive::Yes => trace!(" member {:?} can derive {}", sub_id, self.derive_trait),
+ CanDerive::Manually => trace!(" member {:?} cannot derive {}, but it may be implemented", sub_id, self.derive_trait),
+ CanDerive::No => trace!(" member {:?} cannot derive {}", sub_id, self.derive_trait),
+ }
+
+ *candidate.get_or_insert(CanDerive::Yes) |= can_derive;
+ },
+ &(),
+ );
+
+ if candidate.is_none() {
+ trace!(" can derive {} because there are no members", self.derive_trait);
+ }
+ candidate.unwrap_or_default()
+ }
+}
+
+impl DeriveTrait {
+ fn not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool {
+ match self {
+ DeriveTrait::Copy => ctx.no_copy_by_name(item),
+ DeriveTrait::Hash => ctx.no_hash_by_name(item),
+ DeriveTrait::PartialEqOrPartialOrd => ctx.no_partialeq_by_name(item),
+ _ => false
+ }
+ }
+
+ fn consider_edge_comp(&self) -> EdgePredicate {
+ match self {
+ DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
+ _ => |kind| match kind {
+ EdgeKind::BaseMember |
+ EdgeKind::Field => true,
+ _ => false,
+ }
+ }
+ }
+
+ fn consider_edge_typeref(&self) -> EdgePredicate {
+ match self {
+ DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
+ _ => |kind| kind == EdgeKind::TypeReference
+ }
+ }
+
+ fn consider_edge_tmpl_inst(&self) -> EdgePredicate {
+ match self {
+ DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
+ _ => |kind| match kind {
+ EdgeKind::TemplateArgument |
+ EdgeKind::TemplateDeclaration => true,
+ _ => false,
+ }
+ }
+ }
+
+ fn can_derive_large_array(&self) -> bool {
+ match self {
+ DeriveTrait::Copy => true,
+ _ => false,
+ }
+ }
+
+ fn can_derive_union(&self) -> bool {
+ match self {
+ DeriveTrait::Copy => true,
+ _ => false,
+ }
+ }
+
+ fn can_derive_compound_with_destructor(&self) -> bool {
+ match self {
+ DeriveTrait::Copy => false,
+ _ => true,
+ }
+ }
+
+ fn can_derive_compound_with_vtable(&self) -> bool {
+ match self {
+ DeriveTrait::Default => false,
+ _ => true,
+ }
+ }
+
+ fn can_derive_compound_forward_decl(&self) -> bool {
+ match self {
+ DeriveTrait::Copy | DeriveTrait::Debug => true,
+ _ => false,
+ }
+ }
+
+ fn can_derive_incomplete_array(&self) -> bool {
+ match self {
+ DeriveTrait::Copy | DeriveTrait::Hash | DeriveTrait::PartialEqOrPartialOrd => false,
+ _ => true,
+ }
+ }
+
+ fn can_derive_fnptr(&self, f: &FunctionSig) -> CanDerive {
+ match (self, f.function_pointers_can_derive()) {
+ (DeriveTrait::Copy, _) |
+ (DeriveTrait::Default, _) |
+ (_, true) => {
+ trace!(" function pointer can derive {}", self);
+ CanDerive::Yes
+ }
+ (DeriveTrait::Debug, false) => {
+ trace!(" function pointer cannot derive {}, but it may be implemented", self);
+ CanDerive::Manually
+ }
+ (_, false) => {
+ trace!(" function pointer cannot derive {}", self);
+ CanDerive::No
+ }
+ }
+ }
+
+ fn can_derive_vector(&self) -> CanDerive {
+ match self {
+ DeriveTrait::PartialEqOrPartialOrd => {
+ // FIXME: vectors always can derive PartialEq, but they should
+ // not derive PartialOrd:
+ // https://github.com/rust-lang-nursery/packed_simd/issues/48
+ trace!(" vectors cannot derive PartialOrd");
+ CanDerive::No
+ }
+ _ => {
+ trace!(" vector can derive {}", self);
+ CanDerive::Yes
+ }
+ }
+ }
+
+ fn can_derive_pointer(&self) -> CanDerive {
+ match self {
+ DeriveTrait::Default => {
+ trace!(" pointer cannot derive Default");
+ CanDerive::No
+ }
+ _ => {
+ trace!(" pointer can derive {}", self);
+ CanDerive::Yes
+ }
+ }
+ }
+
+ fn can_derive_simple(&self, kind: &TypeKind) -> CanDerive {
+ match (self, kind) {
+ // === Default ===
+ (DeriveTrait::Default, TypeKind::Void) |
+ (DeriveTrait::Default, TypeKind::NullPtr) |
+ (DeriveTrait::Default, TypeKind::Enum(..)) |
+ (DeriveTrait::Default, TypeKind::Reference(..)) |
+ (DeriveTrait::Default, TypeKind::TypeParam) |
+ (DeriveTrait::Default, TypeKind::ObjCInterface(..)) |
+ (DeriveTrait::Default, TypeKind::ObjCId) |
+ (DeriveTrait::Default, TypeKind::ObjCSel) => {
+ trace!(" types that always cannot derive Default");
+ CanDerive::No
+ },
+ (DeriveTrait::Default, TypeKind::UnresolvedTypeRef(..)) => unreachable!(
+ "Type with unresolved type ref can't reach derive default"
+ ),
+ // === Hash ===
+ (DeriveTrait::Hash, TypeKind::Float(..)) |
+ (DeriveTrait::Hash, TypeKind::Complex(..)) => {
+ trace!(" float cannot derive Hash");
+ CanDerive::No
+ },
+ // === others ===
+ _ => {
+ trace!(" simple type that can always derive {}", self);
+ CanDerive::Yes
+ },
+ }
+ }
+}
+
+impl fmt::Display for DeriveTrait {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let s = match self {
+ DeriveTrait::Copy => "Copy",
+ DeriveTrait::Debug => "Debug",
+ DeriveTrait::Default => "Default",
+ DeriveTrait::Hash => "Hash",
+ DeriveTrait::PartialEqOrPartialOrd => "PartialEq/PartialOrd",
+ };
+ s.fmt(f)
+ }
+}
+
+impl<'ctx> MonotoneFramework for CannotDerive<'ctx> {
+ type Node = ItemId;
+ type Extra = (&'ctx BindgenContext, DeriveTrait);
+ type Output = HashMap<ItemId, CanDerive>;
+
+ fn new(
+ (ctx, derive_trait): (&'ctx BindgenContext, DeriveTrait),
+ ) -> CannotDerive<'ctx> {
+ let can_derive = HashMap::default();
+ let dependencies = generate_dependencies(ctx, consider_edge_default);
+
+ CannotDerive {
+ ctx,
+ derive_trait,
+ can_derive,
+ dependencies,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<ItemId> {
+ // The transitive closure of all whitelisted items, including explicitly
+ // blacklisted items.
+ self.ctx
+ .whitelisted_items()
+ .iter()
+ .cloned()
+ .flat_map(|i| {
+ let mut reachable = vec![i];
+ i.trace(
+ self.ctx,
+ &mut |s, _| {
+ reachable.push(s);
+ },
+ &(),
+ );
+ reachable
+ })
+ .collect()
+ }
+
+ fn constrain(&mut self, id: ItemId) -> ConstrainResult {
+ trace!("constrain: {:?}", id);
+
+ if let Some(CanDerive::No) = self.can_derive.get(&id).cloned() {
+ trace!(
+ " already know it cannot derive {}", self.derive_trait
+ );
+ return ConstrainResult::Same;
+ }
+
+ let item = self.ctx.resolve_item(id);
+ let can_derive = match item.as_type() {
+ Some(ty) => {
+ let mut can_derive = self.constrain_type(item, ty);
+ if let CanDerive::Yes = can_derive {
+ if !self.derive_trait.can_derive_large_array() &&
+ 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.
+ can_derive = CanDerive::Manually;
+ }
+ }
+ can_derive
+ }
+ None => self.constrain_join(item, consider_edge_default),
+ };
+
+ self.insert(id, can_derive)
+ }
+
+ 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> From<CannotDerive<'ctx>> for HashMap<ItemId, CanDerive> {
+ fn from(analysis: CannotDerive<'ctx>) -> Self {
+ extra_assert!(
+ analysis
+ .can_derive
+ .values()
+ .all(|v| *v != CanDerive::Yes)
+ );
+
+ analysis.can_derive
+ }
+}
+
+/// Convert a `HashMap<ItemId, CanDerive>` into a `HashSet<ItemId>`.
+///
+/// Elements that are not `CanDerive::Yes` are kept in the set, so that it
+/// represents all items that cannot derive.
+pub fn as_cannot_derive_set(can_derive: HashMap<ItemId, CanDerive>) -> HashSet<ItemId> {
+ can_derive
+ .into_iter()
+ .filter_map(|(k, v)| if v != CanDerive::Yes { Some(k) } else { None } )
+ .collect()
+}
diff --git a/src/ir/analysis/derive_copy.rs b/src/ir/analysis/derive_copy.rs
deleted file mode 100644
index 55d30097..00000000
--- a/src/ir/analysis/derive_copy.rs
+++ /dev/null
@@ -1,356 +0,0 @@
-//! Determining which types for which we can emit `#[derive(Copy)]`.
-
-use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
-use ir::comp::CompKind;
-use ir::comp::Field;
-use ir::comp::FieldMethods;
-use ir::context::{BindgenContext, ItemId};
-use ir::derive::CanTriviallyDeriveCopy;
-use ir::item::IsOpaque;
-use ir::template::TemplateParameters;
-use ir::traversal::EdgeKind;
-use ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
-use ir::ty::TypeKind;
-use {HashMap, HashSet};
-
-/// An analysis that finds for each IR item whether copy cannot be derived.
-///
-/// We use the monotone constraint function `cannot_derive_copy`, 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, copy cannot be derived if the length of the array is
-/// larger than the limit or the type of data the array contains cannot derive
-/// copy.
-/// * If T is a type alias, a templated alias or an indirection to another type,
-/// copy cannot be derived if the type T refers to cannot be derived copy.
-/// * If T is a compound type, copy cannot be derived if any of its base member
-/// or field cannot be derived copy.
-/// * If T is an instantiation of an abstract template definition, T cannot be
-/// derived copy if any of the template arguments or template definition
-/// cannot derive copy.
-#[derive(Debug, Clone)]
-pub struct CannotDeriveCopy<'ctx> {
- ctx: &'ctx BindgenContext,
-
- // The incremental result of this analysis's computation. Everything in this
- // set cannot derive copy.
- cannot_derive_copy: HashSet<ItemId>,
-
- // Dependencies saying that if a key ItemId has been inserted into the
- // `cannot_derive_copy` 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 copy or not.
- dependencies: HashMap<ItemId, Vec<ItemId>>,
-}
-
-impl<'ctx> CannotDeriveCopy<'ctx> {
- fn consider_edge(kind: EdgeKind) -> bool {
- match kind {
- // These are the only edges that can affect whether a type can derive
- // copy 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<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
- let id = id.into();
- trace!("inserting {:?} into the cannot_derive_copy set", id);
-
- let was_not_already_in_set = self.cannot_derive_copy.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
- }
-
- /// A type is not `Copy` if we've determined it is not copy, or if it is
- /// blacklisted.
- fn is_not_copy<Id: Into<ItemId>>(&self, id: Id) -> bool {
- let id = id.into();
- self.cannot_derive_copy.contains(&id) ||
- !self.ctx.whitelisted_items().contains(&id)
- }
-}
-
-impl<'ctx> MonotoneFramework for CannotDeriveCopy<'ctx> {
- type Node = ItemId;
- type Extra = &'ctx BindgenContext;
- type Output = HashSet<ItemId>;
-
- fn new(ctx: &'ctx BindgenContext) -> CannotDeriveCopy<'ctx> {
- let cannot_derive_copy = HashSet::default();
- let dependencies = generate_dependencies(ctx, Self::consider_edge);
-
- CannotDeriveCopy {
- ctx,
- cannot_derive_copy,
- 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_copy.contains(&id) {
- trace!(" already know it cannot derive Copy");
- return ConstrainResult::Same;
- }
-
- // If an item is reachable from the whitelisted items set, but isn't
- // itself whitelisted, then it must be blacklisted. We assume that
- // blacklisted items are not `Copy`, since they are presumably
- // blacklisted because they are too complicated for us to understand.
- if !self.ctx.whitelisted_items().contains(&id) {
- trace!(" blacklisted items are assumed not to be Copy");
- 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 self.ctx.no_copy_by_name(&item) {
- return self.insert(id);
- }
-
- if item.is_opaque(self.ctx, &()) {
- let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| {
- l.opaque().can_trivially_derive_copy(self.ctx)
- });
- return if layout_can_derive {
- trace!(" we can trivially derive Copy for the layout");
- ConstrainResult::Same
- } else {
- trace!(" we cannot derive Copy for the layout");
- self.insert(id)
- };
- }
-
- match *ty.kind() {
- // Handle the simple cases. These can derive copy without further
- // information.
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Int(..) |
- TypeKind::Float(..) |
- TypeKind::Vector(..) |
- TypeKind::Complex(..) |
- TypeKind::Function(..) |
- TypeKind::Enum(..) |
- TypeKind::Reference(..) |
- TypeKind::TypeParam |
- TypeKind::Pointer(..) |
- TypeKind::UnresolvedTypeRef(..) |
- TypeKind::ObjCInterface(..) |
- TypeKind::ObjCId |
- TypeKind::ObjCSel => {
- trace!(" simple type that can always derive Copy");
- ConstrainResult::Same
- }
-
- TypeKind::Array(t, len) => {
- let cant_derive_copy = self.is_not_copy(t);
- if cant_derive_copy {
- trace!(
- " arrays of T for which we cannot derive Copy \
- also cannot derive Copy"
- );
- return self.insert(id);
- }
-
- if len > 0 {
- trace!(" array can derive Copy with positive length");
- ConstrainResult::Same
- } else {
- trace!(" array cannot derive Copy with 0 length");
- self.insert(id)
- }
- }
-
- TypeKind::ResolvedTypeRef(t) |
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::BlockPointer(t) => {
- let cant_derive_copy = self.is_not_copy(t);
- if cant_derive_copy {
- trace!(
- " arrays of T for which we cannot derive Copy \
- also cannot derive Copy"
- );
- return self.insert(id);
- }
- trace!(
- " aliases and type refs to T which can derive \
- Copy can also derive Copy"
- );
- ConstrainResult::Same
- }
-
- TypeKind::Comp(ref info) => {
- assert!(
- !info.has_non_type_template_params(),
- "The early ty.is_opaque check should have handled this case"
- );
-
- // NOTE: Take into account that while unions in C and C++ are copied by
- // default, the may have an explicit destructor in C++, so we can't
- // defer this check just for the union case.
- if self.ctx.lookup_has_destructor(id.expect_type_id(self.ctx)) {
- trace!(" comp has destructor which cannot derive copy");
- return self.insert(id);
- }
-
- if info.kind() == CompKind::Union {
- if !self.ctx.options().rust_features().untagged_union {
- // NOTE: If there's no template parameters we can derive
- // copy unconditionally, since arrays are magical for
- // rustc, and __BindgenUnionField always implements
- // copy.
- trace!(
- " comp can always derive debug if it's a Union and no template parameters"
- );
- return ConstrainResult::Same;
- }
-
- // https://github.com/rust-lang/rust/issues/36640
- if !info.self_template_params(self.ctx).is_empty() ||
- !item.all_template_params(self.ctx).is_empty()
- {
- trace!(
- " comp cannot derive copy because issue 36640"
- );
- return self.insert(id);
- }
- }
-
- let bases_cannot_derive =
- info.base_members().iter().any(|base| {
- self.is_not_copy(base.ty)
- });
- if bases_cannot_derive {
- trace!(
- " base members cannot derive Copy, 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.is_not_copy(data.ty())
- }
- Field::Bitfields(ref bfu) => {
- if bfu.layout().align > RUST_DERIVE_IN_ARRAY_LIMIT {
- trace!(
- " we cannot derive Copy for a bitfield larger then \
- the limit"
- );
- return true;
- }
-
- bfu.bitfields().iter().any(|b| {
- self.is_not_copy(b.ty())
- })
- }
- });
- if fields_cannot_derive {
- trace!(" fields cannot derive Copy, so we can't either");
- return self.insert(id);
- }
-
- trace!(" comp can derive Copy");
- ConstrainResult::Same
- }
-
- TypeKind::TemplateInstantiation(ref template) => {
- let args_cannot_derive =
- template.template_arguments().iter().any(|arg| {
- self.is_not_copy(*arg)
- });
- if args_cannot_derive {
- trace!(
- " template args cannot derive Copy, 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.is_not_copy(
- template.template_definition()
- );
- if def_cannot_derive {
- trace!(
- " template definition cannot derive Copy, so \
- insantiation can't either"
- );
- return self.insert(id);
- }
-
- trace!(" template instantiation can derive Copy");
- 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> From<CannotDeriveCopy<'ctx>> for HashSet<ItemId> {
- fn from(analysis: CannotDeriveCopy<'ctx>) -> Self {
- analysis.cannot_derive_copy
- }
-}
diff --git a/src/ir/analysis/derive_debug.rs b/src/ir/analysis/derive_debug.rs
deleted file mode 100644
index 6580a68b..00000000
--- a/src/ir/analysis/derive_debug.rs
+++ /dev/null
@@ -1,369 +0,0 @@
-//! Determining which types for which we can emit `#[derive(Debug)]`.
-
-use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
-use ir::comp::CompKind;
-use ir::comp::Field;
-use ir::comp::FieldMethods;
-use ir::context::{BindgenContext, ItemId};
-use ir::derive::CanTriviallyDeriveDebug;
-use ir::item::IsOpaque;
-use ir::traversal::EdgeKind;
-use ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
-use ir::ty::TypeKind;
-use {HashMap, HashSet};
-
-/// An analysis that finds for each IR item whether debug cannot be derived.
-///
-/// We use the monotone constraint function `cannot_derive_debug`, 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, debug cannot be derived if the length of the array is
-/// larger than the limit or the type of data the array contains cannot derive
-/// debug.
-/// * If T is a type alias, a templated alias or an indirection to another type,
-/// debug cannot be derived if the type T refers to cannot be derived debug.
-/// * If T is a compound type, debug cannot be derived if any of its base member
-/// or field cannot be derived debug.
-/// * If T is a pointer, T cannot be derived debug if T is a function pointer
-/// and the function signature cannot be derived debug.
-/// * If T is an instantiation of an abstract template definition, T cannot be
-/// derived debug if any of the template arguments or template definition
-/// cannot derive debug.
-#[derive(Debug, Clone)]
-pub struct CannotDeriveDebug<'ctx> {
- ctx: &'ctx BindgenContext,
-
- // The incremental result of this analysis's computation. Everything in this
- // set cannot derive debug.
- cannot_derive_debug: HashSet<ItemId>,
-
- // Dependencies saying that if a key ItemId has been inserted into the
- // `cannot_derive_debug` 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 debug or not.
- dependencies: HashMap<ItemId, Vec<ItemId>>,
-}
-
-impl<'ctx> CannotDeriveDebug<'ctx> {
- fn consider_edge(kind: EdgeKind) -> bool {
- match kind {
- // These are the only edges that can affect whether a type can derive
- // debug 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<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
- let id = id.into();
- trace!("inserting {:?} into the cannot_derive_debug set", id);
-
- let was_not_already_in_set = self.cannot_derive_debug.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
- }
-
- /// A type is not `Debug` if we've determined it is not debug, or if it is
- /// blacklisted.
- fn is_not_debug<Id: Into<ItemId>>(&self, id: Id) -> bool {
- let id = id.into();
- self.cannot_derive_debug.contains(&id) ||
- !self.ctx.whitelisted_items().contains(&id)
- }
-}
-
-impl<'ctx> MonotoneFramework for CannotDeriveDebug<'ctx> {
- type Node = ItemId;
- type Extra = &'ctx BindgenContext;
- type Output = HashSet<ItemId>;
-
- fn new(ctx: &'ctx BindgenContext) -> CannotDeriveDebug<'ctx> {
- let cannot_derive_debug = HashSet::default();
- let dependencies = generate_dependencies(ctx, Self::consider_edge);
-
- CannotDeriveDebug {
- ctx,
- cannot_derive_debug,
- 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_debug.contains(&id) {
- trace!(" already know it cannot derive Debug");
- return ConstrainResult::Same;
- }
-
- // If an item is reachable from the whitelisted items set, but isn't
- // itself whitelisted, then it must be blacklisted. We assume that
- // blacklisted items are not `Copy`, since they are presumably
- // blacklisted because they are too complicated for us to understand.
- if !self.ctx.whitelisted_items().contains(&id) {
- trace!(" blacklisted items are assumed not to be Debug");
- 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_debug(self.ctx)
- });
- return if layout_can_derive &&
- !(ty.is_union() &&
- self.ctx.options().rust_features().untagged_union) {
- trace!(" we can trivially derive Debug for the layout");
- ConstrainResult::Same
- } else {
- trace!(" we cannot derive Debug 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 debug without further
- // information.
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Int(..) |
- TypeKind::Float(..) |
- TypeKind::Complex(..) |
- TypeKind::Function(..) |
- TypeKind::Enum(..) |
- TypeKind::Reference(..) |
- TypeKind::Vector(..) |
- TypeKind::TypeParam |
- TypeKind::UnresolvedTypeRef(..) |
- TypeKind::ObjCInterface(..) |
- TypeKind::ObjCId |
- TypeKind::ObjCSel => {
- trace!(" simple type that can always derive Debug");
- ConstrainResult::Same
- }
-
- TypeKind::Array(t, len) => {
- if self.is_not_debug(t) {
- trace!(
- " arrays of T for which we cannot derive Debug \
- also cannot derive Debug"
- );
- return self.insert(id);
- }
-
- if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
- trace!(" array is small enough to derive Debug");
- ConstrainResult::Same
- } else {
- trace!(" array is too large to derive Debug");
- self.insert(id)
- }
- }
-
- TypeKind::ResolvedTypeRef(t) |
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::BlockPointer(t) => {
- if self.is_not_debug(t) {
- trace!(
- " aliases and type refs to T which cannot derive \
- Debug also cannot derive Debug"
- );
- self.insert(id)
- } else {
- trace!(
- " aliases and type refs to T which can derive \
- Debug can also derive Debug"
- );
- 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().rust_features().untagged_union {
- trace!(" cannot derive Debug for Rust unions");
- return self.insert(id);
- }
-
- if ty.layout(self.ctx).map_or(true, |l| {
- l.opaque().can_trivially_derive_debug(self.ctx)
- })
- {
- trace!(" union layout can trivially derive Debug");
- return ConstrainResult::Same;
- } else {
- trace!(" union layout cannot derive Debug");
- return self.insert(id);
- }
- }
-
- let bases_cannot_derive =
- info.base_members().iter().any(|base| {
- self.is_not_debug(base.ty)
- });
- if bases_cannot_derive {
- trace!(
- " base members cannot derive Debug, 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.is_not_debug(data.ty())
- }
- Field::Bitfields(ref bfu) => {
- if bfu.layout().align > RUST_DERIVE_IN_ARRAY_LIMIT {
- trace!(
- " we cannot derive Debug for a bitfield larger then \
- the limit"
- );
- return true;
- }
-
- bfu.bitfields().iter().any(|b| {
- self.is_not_debug(b.ty())
- })
- }
- });
- if fields_cannot_derive {
- trace!(
- " fields cannot derive Debug, so we can't either"
- );
- return self.insert(id);
- }
-
- trace!(" comp can derive Debug");
- ConstrainResult::Same
- }
-
- 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_debug(self.ctx) {
- trace!(
- " function pointer that can't trivially derive Debug"
- );
- return self.insert(id);
- }
- }
- trace!(" pointers can derive Debug");
- ConstrainResult::Same
- }
-
- TypeKind::TemplateInstantiation(ref template) => {
- let args_cannot_derive =
- template.template_arguments().iter().any(|arg| {
- self.is_not_debug(*arg)
- });
- if args_cannot_derive {
- trace!(
- " template args cannot derive Debug, 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.is_not_debug(
- template.template_definition()
- );
- if def_cannot_derive {
- trace!(
- " template definition cannot derive Debug, so \
- insantiation can't either"
- );
- return self.insert(id);
- }
-
- trace!(" template instantiation can derive Debug");
- 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> From<CannotDeriveDebug<'ctx>> for HashSet<ItemId> {
- fn from(analysis: CannotDeriveDebug<'ctx>) -> Self {
- analysis.cannot_derive_debug
- }
-}
diff --git a/src/ir/analysis/derive_default.rs b/src/ir/analysis/derive_default.rs
deleted file mode 100644
index 904cabaa..00000000
--- a/src/ir/analysis/derive_default.rs
+++ /dev/null
@@ -1,407 +0,0 @@
-//! Determining which types for which we can emit `#[derive(Default)]`.
-
-use super::{ConstrainResult, HasVtable, MonotoneFramework};
-use ir::comp::CompKind;
-use ir::comp::Field;
-use ir::comp::FieldMethods;
-use ir::context::{BindgenContext, ItemId};
-use ir::derive::CanTriviallyDeriveDefault;
-use ir::item::IsOpaque;
-use ir::item::ItemSet;
-use ir::traversal::EdgeKind;
-use ir::traversal::Trace;
-use ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
-use ir::ty::TypeKind;
-use {HashMap, HashSet};
-
-/// An analysis that finds for each IR item whether default cannot be derived.
-///
-/// We use the monotone constraint function `cannot_derive_default`, 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, default cannot be derived if the length of the array is
-/// larger than the limit or the type of data the array contains cannot derive
-/// default.
-/// * If T is a type alias, a templated alias or an indirection to another type,
-/// default cannot be derived if the type T refers to cannot be derived default.
-/// * If T is a compound type, default cannot be derived if any of its base member
-/// or field cannot be derived default.
-#[derive(Debug, Clone)]
-pub struct CannotDeriveDefault<'ctx> {
- ctx: &'ctx BindgenContext,
-
- // The incremental result of this analysis's computation. Everything in this
- // set cannot derive default.
- cannot_derive_default: HashSet<ItemId>,
-
- // Dependencies saying that if a key ItemId has been inserted into the
- // `cannot_derive_default` 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 default or not.
- dependencies: HashMap<ItemId, Vec<ItemId>>,
-}
-
-impl<'ctx> CannotDeriveDefault<'ctx> {
- fn consider_edge(kind: EdgeKind) -> bool {
- match kind {
- // These are the only edges that can affect whether a type can derive
- // default 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<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
- let id = id.into();
- trace!("inserting {:?} into the cannot_derive_default set", id);
-
- let was_not_already_in_set = self.cannot_derive_default.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
- }
-
- fn is_not_default<Id: Into<ItemId>>(&self, id: Id) -> bool {
- let id = id.into();
- self.cannot_derive_default.contains(&id) ||
- !self.ctx.whitelisted_items().contains(&id)
- }
-}
-
-impl<'ctx> MonotoneFramework for CannotDeriveDefault<'ctx> {
- type Node = ItemId;
- type Extra = &'ctx BindgenContext;
- type Output = HashSet<ItemId>;
-
- fn new(ctx: &'ctx BindgenContext) -> CannotDeriveDefault<'ctx> {
- let mut dependencies = HashMap::default();
- let cannot_derive_default = HashSet::default();
-
- let whitelisted_items: HashSet<_> =
- ctx.whitelisted_items().iter().cloned().collect();
-
- let whitelisted_and_blacklisted_items: ItemSet = whitelisted_items
- .iter()
- .cloned()
- .flat_map(|i| {
- let mut reachable = vec![i];
- i.trace(ctx, &mut |s, _| { reachable.push(s); }, &());
- reachable
- })
- .collect();
-
- for item in whitelisted_and_blacklisted_items {
- dependencies.entry(item).or_insert(vec![]);
-
- {
- // We reverse our natural IR graph edges to find dependencies
- // between nodes.
- item.trace(
- ctx,
- &mut |sub_item: ItemId, edge_kind| {
- if ctx.whitelisted_items().contains(&sub_item) &&
- Self::consider_edge(edge_kind)
- {
- dependencies
- .entry(sub_item)
- .or_insert(vec![])
- .push(item);
- }
- },
- &(),
- );
- }
- }
-
- CannotDeriveDefault {
- ctx,
- cannot_derive_default,
- 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_default.contains(&id) {
- trace!(" already know it cannot derive Default");
- return ConstrainResult::Same;
- }
-
- if !self.ctx.whitelisted_items().contains(&id) {
- trace!(" blacklisted items pessimistically cannot derive Default");
- 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_default(self.ctx)
- });
- return if layout_can_derive &&
- !(ty.is_union() &&
- self.ctx.options().rust_features().untagged_union) {
- trace!(" we can trivially derive Default for the layout");
- ConstrainResult::Same
- } else {
- trace!(" we cannot derive Default 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 Default without further
- // information.
- TypeKind::Function(..) |
- TypeKind::Int(..) |
- TypeKind::Float(..) |
- TypeKind::Vector(..) |
- TypeKind::Complex(..) => {
- trace!(" simple type that can always derive Default");
- ConstrainResult::Same
- }
-
- TypeKind::Void |
- TypeKind::TypeParam |
- TypeKind::Reference(..) |
- TypeKind::NullPtr |
- TypeKind::Pointer(..) |
- TypeKind::ObjCId |
- TypeKind::ObjCSel |
- TypeKind::ObjCInterface(..) |
- TypeKind::Enum(..) => {
- trace!(" types that always cannot derive Default");
- self.insert(id)
- }
-
- TypeKind::Array(t, len) => {
- if self.is_not_default(t) {
- trace!(
- " arrays of T for which we cannot derive Default \
- also cannot derive Default"
- );
- return self.insert(id);
- }
-
- if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
- trace!(" array is small enough to derive Default");
- ConstrainResult::Same
- } else {
- trace!(" array is too large to derive Default");
- self.insert(id)
- }
- }
-
- TypeKind::ResolvedTypeRef(t) |
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::BlockPointer(t) => {
- if self.is_not_default(t) {
- trace!(
- " aliases and type refs to T which cannot derive \
- Default also cannot derive Default"
- );
- self.insert(id)
- } else {
- trace!(
- " aliases and type refs to T which can derive \
- Default can also derive Default"
- );
- 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.is_forward_declaration() {
- trace!(" cannot derive Default for forward decls");
- return self.insert(id);
- }
-
- if info.kind() == CompKind::Union {
- if self.ctx.options().rust_features().untagged_union {
- trace!(" cannot derive Default for Rust unions");
- return self.insert(id);
- }
-
- if ty.layout(self.ctx).map_or(true, |l| {
- l.opaque().can_trivially_derive_default(self.ctx)
- })
- {
- trace!(" union layout can trivially derive Default");
- return ConstrainResult::Same;
- } else {
- trace!(" union layout cannot derive Default");
- return self.insert(id);
- }
- }
-
- if item.has_vtable(self.ctx) {
- trace!(" comp with vtable cannot derive Default");
- return self.insert(id);
- }
-
- let bases_cannot_derive =
- info.base_members().iter().any(|base| {
- !self.ctx.whitelisted_items().contains(&base.ty.into()) ||
- self.is_not_default(base.ty)
- });
- if bases_cannot_derive {
- trace!(
- " base members cannot derive Default, 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().into(),
- ) ||
- self.is_not_default(data.ty())
- }
- Field::Bitfields(ref bfu) => {
- if bfu.layout().align > RUST_DERIVE_IN_ARRAY_LIMIT {
- trace!(
- " we cannot derive Default for a bitfield larger then \
- the limit"
- );
- return true;
- }
-
- bfu.bitfields().iter().any(|b| {
- !self.ctx.whitelisted_items().contains(
- &b.ty().into(),
- ) ||
- self.is_not_default(b.ty())
- })
- }
- });
- if fields_cannot_derive {
- trace!(
- " fields cannot derive Default, so we can't either"
- );
- return self.insert(id);
- }
-
- trace!(" comp can derive Default");
- ConstrainResult::Same
- }
-
- TypeKind::TemplateInstantiation(ref template) => {
- let args_cannot_derive =
- template.template_arguments().iter().any(|arg| {
- self.is_not_default(*arg)
- });
- if args_cannot_derive {
- trace!(
- " template args cannot derive Default, 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.is_not_default(template.template_definition());
- if def_cannot_derive {
- trace!(
- " template definition cannot derive Default, so \
- insantiation can't either"
- );
- return self.insert(id);
- }
-
- trace!(" template instantiation can derive Default");
- ConstrainResult::Same
- }
-
- TypeKind::Opaque => {
- unreachable!(
- "The early ty.is_opaque check should have handled this case"
- )
- }
-
- TypeKind::UnresolvedTypeRef(..) => {
- unreachable!(
- "Type with unresolved type ref can't reach derive default"
- )
- }
- }
- }
-
- 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> From<CannotDeriveDefault<'ctx>> for HashSet<ItemId> {
- fn from(analysis: CannotDeriveDefault<'ctx>) -> Self {
- analysis.cannot_derive_default
- }
-}
diff --git a/src/ir/analysis/derive_hash.rs b/src/ir/analysis/derive_hash.rs
deleted file mode 100644
index 6c8b3976..00000000
--- a/src/ir/analysis/derive_hash.rs
+++ /dev/null
@@ -1,392 +0,0 @@
-//! Determining which types for which we can emit `#[derive(Hash)]`.
-
-use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
-use ir::comp::CompKind;
-use ir::comp::Field;
-use ir::comp::FieldMethods;
-use ir::context::{BindgenContext, ItemId};
-use ir::derive::CanTriviallyDeriveHash;
-use ir::item::IsOpaque;
-use ir::traversal::EdgeKind;
-use ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
-use ir::ty::TypeKind;
-use {HashMap, HashSet};
-
-/// 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> {
- ctx: &'ctx BindgenContext,
-
- // 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> CannotDeriveHash<'ctx> {
- 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<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
- let id = id.into();
- 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> MonotoneFramework for CannotDeriveHash<'ctx> {
- type Node = ItemId;
- type Extra = &'ctx BindgenContext;
- type Output = HashSet<ItemId>;
-
- fn new(ctx: &'ctx BindgenContext) -> CannotDeriveHash<'ctx> {
- let cannot_derive_hash = HashSet::default();
- 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 self.ctx.no_hash_by_name(&item) {
- return self.insert(id)
- }
-
- if item.is_opaque(self.ctx, &()) {
- let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| {
- l.opaque().can_trivially_derive_hash(self.ctx)
- });
- return if layout_can_derive &&
- !(ty.is_union() &&
- self.ctx.options().rust_features().untagged_union) {
- 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::TypeParam |
- TypeKind::UnresolvedTypeRef(..) |
- 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.into()) {
- trace!(
- " arrays of T for which we cannot derive Hash \
- also cannot derive Hash"
- );
- return self.insert(id);
- }
-
- if len == 0 {
- trace!(" cannot derive `Hash` for incomplete arrays");
- self.insert(id)
- } else 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::Vector(t, len) => {
- if self.cannot_derive_hash.contains(&t.into()) {
- trace!(
- " vectors of T for which we cannot derive Hash \
- also cannot derive Hash"
- );
- return self.insert(id);
- }
- assert_ne!(len, 0, "vectors cannot have zero length");
- trace!(" vector can derive Hash");
- ConstrainResult::Same
- }
-
- 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(self.ctx) {
- 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(self.ctx) {
- 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) |
- TypeKind::BlockPointer(t) => {
- if self.cannot_derive_hash.contains(&t.into()) {
- 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.is_forward_declaration() {
- trace!(" cannot derive Hash for forward decls");
- return self.insert(id);
- }
-
- if info.kind() == CompKind::Union {
- if self.ctx.options().rust_features().untagged_union {
- 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(self.ctx)
- })
- {
- 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.into()) ||
- self.cannot_derive_hash.contains(&base.ty.into())
- });
- 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().into(),
- ) ||
- self.cannot_derive_hash.contains(&data.ty().into())
- }
- Field::Bitfields(ref bfu) => {
- if bfu.layout().align > RUST_DERIVE_IN_ARRAY_LIMIT {
- trace!(
- " we cannot derive Hash for a bitfield larger then \
- the limit"
- );
- return true;
- }
-
- bfu.bitfields().iter().any(|b| {
- !self.ctx.whitelisted_items().contains(
- &b.ty().into(),
- ) ||
- self.cannot_derive_hash.contains(&b.ty().into())
- })
- }
- });
- 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.into())
- });
- 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().into(),
- );
- 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> From<CannotDeriveHash<'ctx>> for HashSet<ItemId> {
- fn from(analysis: CannotDeriveHash<'ctx>) -> Self {
- analysis.cannot_derive_hash
- }
-}
diff --git a/src/ir/analysis/derive_partialeq_or_partialord.rs b/src/ir/analysis/derive_partialeq_or_partialord.rs
deleted file mode 100644
index a64fdf38..00000000
--- a/src/ir/analysis/derive_partialeq_or_partialord.rs
+++ /dev/null
@@ -1,420 +0,0 @@
-//! Determining which types for which we cannot emit `#[derive(PartialEq,
-//! PartialOrd)]`.
-
-use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
-use ir::comp::CompKind;
-use ir::context::{BindgenContext, ItemId};
-use ir::derive::{CanTriviallyDerivePartialEqOrPartialOrd, CanDerive};
-use ir::item::{Item, IsOpaque};
-use ir::traversal::{EdgeKind, Trace};
-use ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
-use ir::ty::{TypeKind, Type};
-use {HashMap, Entry};
-
-/// An analysis that finds for each IR item whether `PartialEq`/`PartialOrd`
-/// cannot be derived.
-///
-/// We use the monotone constraint function
-/// `cannot_derive_partialeq_or_partialord`, 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, `PartialEq` or partialord cannot be derived if the array is incomplete, if the length of
-/// the array is larger than the limit, or the type of data the array contains cannot derive
-/// `PartialEq`/`PartialOrd`.
-///
-/// * If T is a type alias, a templated alias or an indirection to another type,
-/// `PartialEq`/`PartialOrd` cannot be derived if the type T refers to cannot be
-/// derived `PartialEq`/`PartialOrd`.
-///
-/// * If T is a compound type, `PartialEq`/`PartialOrd` cannot be derived if any
-/// of its base member or field cannot be derived `PartialEq`/`PartialOrd`.
-///
-/// * If T is a pointer, T cannot be derived `PartialEq`/`PartialOrd` if T is a
-/// function pointer and the function signature cannot be derived
-/// `PartialEq`/`PartialOrd`.
-///
-/// * If T is an instantiation of an abstract template definition, T cannot be
-/// derived `PartialEq`/`PartialOrd` if any of the template arguments or
-/// template definition cannot derive `PartialEq`/`PartialOrd`.
-#[derive(Debug, Clone)]
-pub struct CannotDerivePartialEqOrPartialOrd<'ctx> {
- ctx: &'ctx BindgenContext,
-
- // The incremental result of this analysis's computation.
- // Contains information whether particular item can derive `PartialEq`/`PartialOrd`.
- can_derive_partialeq_or_partialord: HashMap<ItemId, CanDerive>,
-
- // Dependencies saying that if a key ItemId has been inserted into the
- // `cannot_derive_partialeq_or_partialord` 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 `PartialEq`/`PartialOrd`.
- dependencies: HashMap<ItemId, Vec<ItemId>>,
-}
-
-impl<'ctx> CannotDerivePartialEqOrPartialOrd<'ctx> {
- fn consider_edge(kind: EdgeKind) -> bool {
- match kind {
- // These are the only edges that can affect whether a type can derive
- // `PartialEq`/`PartialOrd`.
- 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<Id: Into<ItemId>>(
- &mut self,
- id: Id,
- can_derive: CanDerive,
- ) -> ConstrainResult {
- let id = id.into();
- trace!("inserting {:?} can_derive={:?}", id, can_derive);
-
- if let CanDerive::Yes = can_derive {
- return ConstrainResult::Same;
- }
-
- match self.can_derive_partialeq_or_partialord.entry(id) {
- Entry::Occupied(mut entry) => if *entry.get() < can_derive {
- entry.insert(can_derive);
- ConstrainResult::Changed
- } else {
- ConstrainResult::Same
- },
- Entry::Vacant(entry) => {
- entry.insert(can_derive);
- ConstrainResult::Changed
- }
- }
- }
-
- fn constrain_type(&mut self, item: &Item, ty: &Type) -> CanDerive {
- if !self.ctx.whitelisted_items().contains(&item.id()) {
- return CanDerive::No;
- }
-
- if self.ctx.no_partialeq_by_name(&item) {
- return CanDerive::No;
- }
-
- trace!("ty: {:?}", ty);
- if item.is_opaque(self.ctx, &()) {
- if ty.is_union()
- && self.ctx.options().rust_features().untagged_union
- {
- trace!(
- " cannot derive `PartialEq`/`PartialOrd` for Rust unions"
- );
- return CanDerive::No;
- }
-
- let layout_can_derive = ty.layout(self.ctx)
- .map_or(CanDerive::Yes, |l| {
- l.opaque().can_trivially_derive_partialeq_or_partialord(self.ctx)
- });
-
- match layout_can_derive {
- CanDerive::Yes => {
- trace!(
- " we can trivially derive `PartialEq`/`PartialOrd` for the layout"
- );
- }
- _ => {
- trace!(
- " we cannot derive `PartialEq`/`PartialOrd` for the layout"
- );
- }
- };
- return layout_can_derive;
- }
-
- match *ty.kind() {
- // Handle the simple cases. These can derive partialeq/partialord without further
- // information.
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Int(..) |
- TypeKind::Complex(..) |
- TypeKind::Float(..) |
- TypeKind::Enum(..) |
- TypeKind::TypeParam |
- TypeKind::UnresolvedTypeRef(..) |
- TypeKind::Reference(..) |
- TypeKind::ObjCInterface(..) |
- TypeKind::ObjCId |
- TypeKind::ObjCSel => {
- trace!(
- " simple type that can always derive `PartialEq`/`PartialOrd`"
- );
- return CanDerive::Yes;
- }
-
- TypeKind::Array(t, len) => {
- let inner_type = self.can_derive_partialeq_or_partialord
- .get(&t.into())
- .cloned()
- .unwrap_or(CanDerive::Yes);
- if inner_type != CanDerive::Yes {
- trace!(
- " arrays of T for which we cannot derive `PartialEq`/`PartialOrd` \
- also cannot derive `PartialEq`/`PartialOrd`"
- );
- return CanDerive::No;
- }
-
- if len == 0 {
- trace!(
- " cannot derive `PartialEq`/`PartialOrd` for incomplete arrays"
- );
- return CanDerive::No;
- } else if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
- trace!(
- " array is small enough to derive `PartialEq`/`PartialOrd`"
- );
- return CanDerive::Yes;
- } else {
- trace!(
- " array is too large to derive `PartialEq`/`PartialOrd`"
- );
- return CanDerive::ArrayTooLarge;
- }
- }
- TypeKind::Vector(..) => {
- // FIXME: vectors always can derive PartialEq, but they should
- // not derive PartialOrd:
- // https://github.com/rust-lang-nursery/packed_simd/issues/48
- trace!(" vectors cannot derive `PartialEq`/`PartialOrd`");
- return CanDerive::No;
- }
-
- 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_partialeq_or_partialord(self.ctx)
- != CanDerive::Yes
- {
- trace!(
- " function pointer that can't trivially derive `PartialEq`/`PartialOrd`"
- );
- return CanDerive::No;
- }
- }
- trace!(" pointers can derive `PartialEq`/`PartialOrd`");
- return CanDerive::Yes;
- }
-
- TypeKind::Function(ref sig) => {
- if sig.can_trivially_derive_partialeq_or_partialord(self.ctx)
- != CanDerive::Yes
- {
- trace!(
- " function that can't trivially derive `PartialEq`/`PartialOrd`"
- );
- return CanDerive::No;
- }
- trace!(" function can derive `PartialEq`/`PartialOrd`");
- return CanDerive::Yes;
- }
-
- TypeKind::Comp(ref info) => {
- assert!(
- !info.has_non_type_template_params(),
- "The early ty.is_opaque check should have handled this case"
- );
-
- if info.is_forward_declaration() {
- trace!(" cannot derive for forward decls");
- return CanDerive::No;
- }
-
- if info.kind() == CompKind::Union {
- if self.ctx.options().rust_features().untagged_union {
- trace!(
- " cannot derive `PartialEq`/`PartialOrd` for Rust unions"
- );
- return CanDerive::No;
- }
-
- let layout_can_derive =
- ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
- l.opaque()
- .can_trivially_derive_partialeq_or_partialord(self.ctx)
- });
- match layout_can_derive {
- CanDerive::Yes => {
- trace!(
- " union layout can trivially derive `PartialEq`/`PartialOrd`"
- );
- }
- _ => {
- trace!(
- " union layout cannot derive `PartialEq`/`PartialOrd`"
- );
- }
- };
- return layout_can_derive;
- }
- return self.constrain_join(item);
- }
-
- TypeKind::ResolvedTypeRef(..) |
- TypeKind::TemplateAlias(..) |
- TypeKind::Alias(..) |
- TypeKind::BlockPointer(..) |
- TypeKind::TemplateInstantiation(..) => {
- return self.constrain_join(item);
- }
-
- TypeKind::Opaque => unreachable!(
- "The early ty.is_opaque check should have handled this case"
- ),
- }
- }
-
- fn constrain_join(&mut self, item: &Item) -> CanDerive {
- let mut candidate = CanDerive::Yes;
-
- item.trace(
- self.ctx,
- &mut |sub_id, edge_kind| {
- // Ignore ourselves, since union with ourself is a
- // no-op. Ignore edges that aren't relevant to the
- // analysis.
- if sub_id == item.id() || !Self::consider_edge(edge_kind) {
- return;
- }
-
- let can_derive = self.can_derive_partialeq_or_partialord
- .get(&sub_id)
- .cloned()
- .unwrap_or_default();
-
- candidate |= can_derive;
- },
- &(),
- );
-
- candidate
- }
-}
-
-impl<'ctx> MonotoneFramework for CannotDerivePartialEqOrPartialOrd<'ctx> {
- type Node = ItemId;
- type Extra = &'ctx BindgenContext;
- type Output = HashMap<ItemId, CanDerive>;
-
- fn new(
- ctx: &'ctx BindgenContext,
- ) -> CannotDerivePartialEqOrPartialOrd<'ctx> {
- let can_derive_partialeq_or_partialord = HashMap::default();
- let dependencies = generate_dependencies(ctx, Self::consider_edge);
-
- CannotDerivePartialEqOrPartialOrd {
- ctx,
- can_derive_partialeq_or_partialord,
- dependencies,
- }
- }
-
- fn initial_worklist(&self) -> Vec<ItemId> {
- // The transitive closure of all whitelisted items, including explicitly
- // blacklisted items.
- self.ctx
- .whitelisted_items()
- .iter()
- .cloned()
- .flat_map(|i| {
- let mut reachable = vec![i];
- i.trace(
- self.ctx,
- &mut |s, _| {
- reachable.push(s);
- },
- &(),
- );
- reachable
- })
- .collect()
- }
-
- fn constrain(&mut self, id: ItemId) -> ConstrainResult {
- trace!("constrain: {:?}", id);
-
- if let Some(CanDerive::No) =
- self.can_derive_partialeq_or_partialord.get(&id).cloned()
- {
- trace!(
- " already know it cannot derive `PartialEq`/`PartialOrd`"
- );
- return ConstrainResult::Same;
- }
-
- let item = self.ctx.resolve_item(id);
- let can_derive = match item.as_type() {
- Some(ty) => {
- let mut can_derive = self.constrain_type(item, ty);
- if let CanDerive::Yes = can_derive {
- 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.
- can_derive = CanDerive::ArrayTooLarge;
- }
- }
- can_derive
- }
- None => self.constrain_join(item),
- };
-
- self.insert(id, can_derive)
- }
-
- 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> From<CannotDerivePartialEqOrPartialOrd<'ctx>>
- for HashMap<ItemId, CanDerive> {
- fn from(analysis: CannotDerivePartialEqOrPartialOrd<'ctx>) -> Self {
- extra_assert!(
- analysis
- .can_derive_partialeq_or_partialord
- .values()
- .all(|v| { *v != CanDerive::Yes })
- );
-
- analysis.can_derive_partialeq_or_partialord
- }
-}
diff --git a/src/ir/analysis/mod.rs b/src/ir/analysis/mod.rs
index 7d6241ba..9de6833b 100644
--- a/src/ir/analysis/mod.rs
+++ b/src/ir/analysis/mod.rs
@@ -40,22 +40,14 @@
// Re-export individual analyses.
mod template_params;
pub use self::template_params::UsedTemplateParameters;
-mod derive_debug;
-pub use self::derive_debug::CannotDeriveDebug;
+mod derive;
+pub use self::derive::{CannotDerive, DeriveTrait, as_cannot_derive_set};
mod has_vtable;
pub use self::has_vtable::{HasVtable, HasVtableAnalysis, HasVtableResult};
mod has_destructor;
pub use self::has_destructor::HasDestructorAnalysis;
-mod derive_default;
-pub use self::derive_default::CannotDeriveDefault;
-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;
-mod derive_partialeq_or_partialord;
-pub use self::derive_partialeq_or_partialord::CannotDerivePartialEqOrPartialOrd;
mod has_float;
pub use self::has_float::HasFloat;
mod sizedness;
diff --git a/src/ir/context.rs b/src/ir/context.rs
index 2626b3e5..914a89b2 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -1,7 +1,6 @@
//! Common context that is passed around during parsing and codegen.
-use super::analysis::{CannotDeriveCopy, CannotDeriveDebug, CannotDeriveDefault,
- CannotDeriveHash, CannotDerivePartialEqOrPartialOrd,
+use super::analysis::{CannotDerive, DeriveTrait, as_cannot_derive_set,
HasTypeParameterInArray, HasVtableAnalysis,
HasVtableResult, HasDestructorAnalysis,
UsedTemplateParameters, HasFloat, SizednessAnalysis,
@@ -2426,7 +2425,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
let _t = self.timer("compute_cannot_derive_debug");
assert!(self.cannot_derive_debug.is_none());
if self.options.derive_debug {
- self.cannot_derive_debug = Some(analyze::<CannotDeriveDebug>(self));
+ self.cannot_derive_debug = Some(as_cannot_derive_set(analyze::<CannotDerive>((self, DeriveTrait::Debug))));
}
}
@@ -2450,7 +2449,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
assert!(self.cannot_derive_default.is_none());
if self.options.derive_default {
self.cannot_derive_default =
- Some(analyze::<CannotDeriveDefault>(self));
+ Some(as_cannot_derive_set(analyze::<CannotDerive>((self, DeriveTrait::Default))));
}
}
@@ -2472,7 +2471,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
fn compute_cannot_derive_copy(&mut self) {
let _t = self.timer("compute_cannot_derive_copy");
assert!(self.cannot_derive_copy.is_none());
- self.cannot_derive_copy = Some(analyze::<CannotDeriveCopy>(self));
+ self.cannot_derive_copy = Some(as_cannot_derive_set(analyze::<CannotDerive>((self, DeriveTrait::Copy))));
}
/// Compute whether we can derive hash.
@@ -2480,7 +2479,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
let _t = self.timer("compute_cannot_derive_hash");
assert!(self.cannot_derive_hash.is_none());
if self.options.derive_hash {
- self.cannot_derive_hash = Some(analyze::<CannotDeriveHash>(self));
+ self.cannot_derive_hash = Some(as_cannot_derive_set(analyze::<CannotDerive>((self, DeriveTrait::Hash))));
}
}
@@ -2503,7 +2502,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
let _t = self.timer("compute_cannot_derive_partialord_partialeq_or_eq");
assert!(self.cannot_derive_partialeq_or_partialord.is_none());
if self.options.derive_partialord || self.options.derive_partialeq || self.options.derive_eq {
- self.cannot_derive_partialeq_or_partialord = Some(analyze::<CannotDerivePartialEqOrPartialOrd>(self));
+ self.cannot_derive_partialeq_or_partialord = Some(analyze::<CannotDerive>((self, DeriveTrait::PartialEqOrPartialOrd)));
}
}
diff --git a/src/ir/derive.rs b/src/ir/derive.rs
index 71854d2e..d434b0a0 100644
--- a/src/ir/derive.rs
+++ b/src/ir/derive.rs
@@ -24,15 +24,6 @@ pub trait CanDeriveDebug {
fn can_derive_debug(&self, ctx: &BindgenContext) -> bool;
}
-/// A trait that encapsulates the logic for whether or not we can trivially
-/// derive `Debug` without looking at any other types or the results of a fix
-/// point analysis. This is a helper trait for the fix point analysis.
-pub trait CanTriviallyDeriveDebug {
- /// Return `true` if `Debug` can trivially be derived for this thing,
- /// `false` otherwise.
- fn can_trivially_derive_debug(&self, ctx: &BindgenContext) -> bool;
-}
-
/// A trait that encapsulates the logic for whether or not we can derive `Copy`
/// for a given thing.
pub trait CanDeriveCopy {
@@ -41,15 +32,6 @@ pub trait CanDeriveCopy {
fn can_derive_copy(&self, ctx: &BindgenContext) -> bool;
}
-/// A trait that encapsulates the logic for whether or not we can trivially
-/// derive `Copy` without looking at any other types or results of fix point
-/// analyses. This is a helper trait for fix point analysis.
-pub trait CanTriviallyDeriveCopy {
- /// Return `true` if `Copy` can be trivially derived for this thing, `false`
- /// otherwise.
- fn can_trivially_derive_copy(&self, ctx: &BindgenContext) -> bool;
-}
-
/// A trait that encapsulates the logic for whether or not we can derive
/// `Default` for a given thing.
pub trait CanDeriveDefault {
@@ -58,15 +40,6 @@ pub trait CanDeriveDefault {
fn can_derive_default(&self, ctx: &BindgenContext) -> bool;
}
-/// A trait that encapsulates the logic for whether or not we can trivially
-/// derive `Default` without looking at any other types or results of fix point
-/// analyses. This is a helper trait for the fix point analysis.
-pub trait CanTriviallyDeriveDefault {
- /// Return `true` if `Default` can trivially derived for this thing, `false`
- /// otherwise.
- fn can_trivially_derive_default(&self, ctx: &BindgenContext) -> bool;
-}
-
/// A trait that encapsulates the logic for whether or not we can derive `Hash`
/// for a given thing.
pub trait CanDeriveHash {
@@ -105,31 +78,13 @@ pub trait CanDeriveOrd {
fn can_derive_ord(&self, ctx: &BindgenContext) -> bool;
}
-/// A trait that encapsulates the logic for whether or not we can derive `Hash`
-/// without looking at any other types or the results of any fix point
-/// analyses. This is a helper trait for the fix point analysis.
-pub trait CanTriviallyDeriveHash {
- /// Return `true` if `Hash` can trivially be derived for this thing, `false`
- /// otherwise.
- fn can_trivially_derive_hash(&self, ctx: &BindgenContext) -> bool;
-}
-
-/// A trait that encapsulates the logic for whether or not we can trivially
-/// derive `PartialEq` or `PartialOrd` without looking at any other types or
-/// results of fix point analyses. This is a helper for the fix point analysis.
-pub trait CanTriviallyDerivePartialEqOrPartialOrd {
- /// Return `Yes` if `PartialEq` or `PartialOrd` can trivially be derived
- /// for this thing.
- fn can_trivially_derive_partialeq_or_partialord(&self, ctx: &BindgenContext) -> CanDerive;
-}
-
/// Whether it is possible or not to automatically derive trait for an item.
///
/// ```ignore
/// No
/// ^
/// |
-/// ArrayTooLarge
+/// Manually
/// ^
/// |
/// Yes
@@ -146,7 +101,7 @@ pub enum CanDerive {
/// array with more than maximum number of elements is used.
///
/// This means we probably can "manually" implement such trait.
- ArrayTooLarge,
+ Manually,
/// Yes, we can derive automatically.
Yes,
@@ -166,8 +121,8 @@ impl cmp::PartialOrd for CanDerive {
(x, y) if x == y => cmp::Ordering::Equal,
(No, _) => cmp::Ordering::Greater,
(_, No) => cmp::Ordering::Less,
- (ArrayTooLarge, _) => cmp::Ordering::Greater,
- (_, ArrayTooLarge) => cmp::Ordering::Less,
+ (Manually, _) => cmp::Ordering::Greater,
+ (_, Manually) => cmp::Ordering::Less,
_ => unreachable!()
};
Some(ordering)
diff --git a/src/ir/function.rs b/src/ir/function.rs
index b20cc634..dc3cfc41 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -8,8 +8,6 @@ use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::TypeKind;
use clang;
use clang_sys::{self, CXCallingConv};
-use ir::derive::{CanTriviallyDeriveDebug, CanTriviallyDeriveHash,
- CanTriviallyDerivePartialEqOrPartialOrd, CanDerive};
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
use quote;
use quote::TokenStreamExt;
@@ -633,25 +631,3 @@ impl Trace for FunctionSig {
}
}
}
-
-impl CanTriviallyDeriveDebug for FunctionSig {
- fn can_trivially_derive_debug(&self, _: &BindgenContext) -> bool {
- self.function_pointers_can_derive()
- }
-}
-
-impl CanTriviallyDeriveHash for FunctionSig {
- fn can_trivially_derive_hash(&self, _: &BindgenContext) -> bool {
- self.function_pointers_can_derive()
- }
-}
-
-impl CanTriviallyDerivePartialEqOrPartialOrd for FunctionSig {
- fn can_trivially_derive_partialeq_or_partialord(&self, _: &BindgenContext) -> CanDerive {
- if self.function_pointers_can_derive() {
- CanDerive::Yes
- } else {
- CanDerive::No
- }
- }
-}
diff --git a/src/ir/layout.rs b/src/ir/layout.rs
index c70d2884..8438d2c4 100644
--- a/src/ir/layout.rs
+++ b/src/ir/layout.rs
@@ -1,8 +1,6 @@
//! Intermediate representation for the physical layout of some type.
-use super::derive::{CanTriviallyDeriveCopy, CanTriviallyDeriveDebug,
- CanTriviallyDeriveDefault, CanTriviallyDeriveHash,
- CanTriviallyDerivePartialEqOrPartialOrd, CanDerive};
+use super::derive::CanDerive;
use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind};
use ir::context::BindgenContext;
use clang;
@@ -126,45 +124,13 @@ impl Opaque {
/// Return `true` if this opaque layout's array size will fit within the
/// maximum number of array elements that Rust allows deriving traits
/// with. Return `false` otherwise.
- pub fn array_size_within_derive_limit(&self, ctx: &BindgenContext) -> bool {
- self.array_size(ctx).map_or(false, |size| {
+ pub fn array_size_within_derive_limit(&self, ctx: &BindgenContext) -> CanDerive {
+ if self.array_size(ctx).map_or(false, |size| {
size <= RUST_DERIVE_IN_ARRAY_LIMIT
- })
- }
-}
-
-impl CanTriviallyDeriveDebug for Opaque {
- fn can_trivially_derive_debug(&self, ctx: &BindgenContext) -> bool {
- self.array_size_within_derive_limit(ctx)
- }
-}
-
-impl CanTriviallyDeriveDefault for Opaque {
- fn can_trivially_derive_default(&self, ctx: &BindgenContext) -> bool {
- self.array_size_within_derive_limit(ctx)
- }
-}
-
-impl CanTriviallyDeriveCopy for Opaque {
- fn can_trivially_derive_copy(&self, ctx: &BindgenContext) -> bool {
- self.array_size_within_derive_limit(ctx)
- }
-}
-
-impl CanTriviallyDeriveHash for Opaque {
- fn can_trivially_derive_hash(&self, ctx: &BindgenContext) -> bool {
- self.array_size_within_derive_limit(ctx)
- }
-}
-
-impl CanTriviallyDerivePartialEqOrPartialOrd for Opaque {
- fn can_trivially_derive_partialeq_or_partialord(&self, ctx: &BindgenContext) -> CanDerive {
- // TODO(emilio): This is inconsistent with the rest of the
- // CanTriviallyDerive* traits.
- if self.array_size_within_derive_limit(ctx) {
+ }) {
CanDerive::Yes
} else {
- CanDerive::ArrayTooLarge
+ CanDerive::Manually
}
}
}
diff --git a/tests/expectations/tests/issue-1285.rs b/tests/expectations/tests/issue-1285.rs
index 77df620b..8497c3f2 100644
--- a/tests/expectations/tests/issue-1285.rs
+++ b/tests/expectations/tests/issue-1285.rs
@@ -8,14 +8,57 @@
)]
#[repr(C)]
+pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
+impl<T> __BindgenUnionField<T> {
+ #[inline]
+ pub fn new() -> Self {
+ __BindgenUnionField(::std::marker::PhantomData)
+ }
+ #[inline]
+ pub unsafe fn as_ref(&self) -> &T {
+ ::std::mem::transmute(self)
+ }
+ #[inline]
+ pub unsafe fn as_mut(&mut self) -> &mut T {
+ ::std::mem::transmute(self)
+ }
+}
+impl<T> ::std::default::Default for __BindgenUnionField<T> {
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+}
+impl<T> ::std::clone::Clone for __BindgenUnionField<T> {
+ #[inline]
+ fn clone(&self) -> Self {
+ Self::new()
+ }
+}
+impl<T> ::std::marker::Copy for __BindgenUnionField<T> {}
+impl<T> ::std::fmt::Debug for __BindgenUnionField<T> {
+ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ fmt.write_str("__BindgenUnionField")
+ }
+}
+impl<T> ::std::hash::Hash for __BindgenUnionField<T> {
+ fn hash<H: ::std::hash::Hasher>(&self, _state: &mut H) {}
+}
+impl<T> ::std::cmp::PartialEq for __BindgenUnionField<T> {
+ fn eq(&self, _other: &__BindgenUnionField<T>) -> bool {
+ true
+ }
+}
+impl<T> ::std::cmp::Eq for __BindgenUnionField<T> {}
+#[repr(C)]
pub struct foo {
pub bar: foo__bindgen_ty_1,
}
#[repr(C)]
-pub union foo__bindgen_ty_1 {
- pub a: ::std::os::raw::c_uint,
- pub b: ::std::os::raw::c_ushort,
- _bindgen_union_align: u32,
+pub struct foo__bindgen_ty_1 {
+ pub a: __BindgenUnionField<::std::os::raw::c_uint>,
+ pub b: __BindgenUnionField<::std::os::raw::c_ushort>,
+ pub bindgen_union_field: u32,
}
#[test]
fn bindgen_test_layout_foo__bindgen_ty_1() {