summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/codegen/mod.rs2
-rw-r--r--src/ir/analysis/derive_copy.rs309
-rw-r--r--src/ir/analysis/derive_debug.rs6
-rw-r--r--src/ir/analysis/has_type_param_in_array.rs239
-rw-r--r--src/ir/analysis/mod.rs4
-rw-r--r--src/ir/comp.rs71
-rw-r--r--src/ir/context.rs71
-rw-r--r--src/ir/derive.rs52
-rw-r--r--src/ir/function.rs4
-rw-r--r--src/ir/item.rs68
-rw-r--r--src/ir/layout.rs19
-rw-r--r--src/ir/template.rs15
-rw-r--r--src/ir/ty.rs42
13 files changed, 658 insertions, 244 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 637e3a65..5c00a53d 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -1424,7 +1424,7 @@ impl CodeGenerator for CompInfo {
needs_default_impl = ctx.options().derive_default;
}
- if item.can_derive_copy(ctx, ()) &&
+ if item.can_derive_copy(ctx) &&
!item.annotations().disallow_copy() {
derives.push("Copy");
if used_template_params.is_some() {
diff --git a/src/ir/analysis/derive_copy.rs b/src/ir/analysis/derive_copy.rs
new file mode 100644
index 00000000..f4997632
--- /dev/null
+++ b/src/ir/analysis/derive_copy.rs
@@ -0,0 +1,309 @@
+//! Determining which types for which we can emit `#[derive(Copy)]`.
+
+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::TypeKind;
+use ir::comp::Field;
+use ir::comp::FieldMethods;
+use ir::derive::CanTriviallyDeriveCopy;
+use ir::comp::CompKind;
+use ir::template::TemplateParameters;
+
+/// 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, 'gen>
+ where 'gen: 'ctx
+{
+ ctx: &'ctx BindgenContext<'gen>,
+
+ // 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, 'gen> CannotDeriveCopy<'ctx, 'gen> {
+ 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(&mut self, id: ItemId) -> ConstrainResult {
+ 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
+ }
+}
+
+impl<'ctx, 'gen> MonotoneFramework for CannotDeriveCopy<'ctx, 'gen> {
+ type Node = ItemId;
+ type Extra = &'ctx BindgenContext<'gen>;
+ type Output = HashSet<ItemId>;
+
+ fn new(ctx: &'ctx BindgenContext<'gen>) -> CannotDeriveCopy<'ctx, 'gen> {
+ let cannot_derive_copy = HashSet::new();
+ 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;
+ }
+
+ 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_copy()
+ });
+ 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::Complex(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Named |
+ TypeKind::BlockPointer |
+ 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.cannot_derive_copy.contains(&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) => {
+ let cant_derive_copy = self.cannot_derive_copy.contains(&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 info.has_destructor(self.ctx) {
+ trace!(" comp has destructor which cannot derive copy");
+ return self.insert(id);
+ }
+
+ if info.kind() == CompKind::Union {
+ if !self.ctx.options().unstable_rust {
+ // 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_some() ||
+ item.used_template_params(self.ctx).is_some() {
+ trace!(" comp cannot derive copy because issue 36640");
+ return self.insert(id);
+ }
+ }
+
+ let bases_cannot_derive = info.base_members()
+ .iter()
+ .any(|base| self.cannot_derive_copy.contains(&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.cannot_derive_copy.contains(&data.ty())
+ }
+ Field::Bitfields(ref bfu) => {
+ bfu.bitfields()
+ .iter().any(|b| {
+ self.cannot_derive_copy.contains(&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.cannot_derive_copy.contains(&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.cannot_derive_copy
+ .contains(&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, 'gen> From<CannotDeriveCopy<'ctx, 'gen>> for HashSet<ItemId> {
+ fn from(analysis: CannotDeriveCopy<'ctx, 'gen>) -> Self {
+ analysis.cannot_derive_copy
+ }
+}
diff --git a/src/ir/analysis/derive_debug.rs b/src/ir/analysis/derive_debug.rs
index ef3b1e00..8990d1cc 100644
--- a/src/ir/analysis/derive_debug.rs
+++ b/src/ir/analysis/derive_debug.rs
@@ -130,7 +130,7 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> {
if ty.is_opaque(self.ctx, item) {
let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| {
- l.opaque().can_trivially_derive_debug(self.ctx, ())
+ l.opaque().can_trivially_derive_debug()
});
return if layout_can_derive {
trace!(" we can trivially derive Debug for the layout");
@@ -215,7 +215,7 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> {
if ty.layout(self.ctx)
.map_or(true,
- |l| l.opaque().can_trivially_derive_debug(self.ctx, ())) {
+ |l| l.opaque().can_trivially_derive_debug()) {
trace!(" union layout can trivially derive Debug");
return ConstrainResult::Same;
} else {
@@ -260,7 +260,7 @@ impl<'ctx, 'gen> MonotoneFramework for CannotDeriveDebug<'ctx, 'gen> {
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, ()) {
+ if !sig.can_trivially_derive_debug() {
trace!(" function pointer that can't trivially derive Debug");
return self.insert(id);
}
diff --git a/src/ir/analysis/has_type_param_in_array.rs b/src/ir/analysis/has_type_param_in_array.rs
new file mode 100644
index 00000000..b141dd64
--- /dev/null
+++ b/src/ir/analysis/has_type_param_in_array.rs
@@ -0,0 +1,239 @@
+//! Determining which types has typed parameters in array.
+
+use super::{ConstrainResult, MonotoneFramework, generate_dependencies};
+use std::collections::HashSet;
+use std::collections::HashMap;
+use ir::context::{BindgenContext, ItemId};
+use ir::traversal::EdgeKind;
+use ir::ty::TypeKind;
+use ir::comp::Field;
+use ir::comp::FieldMethods;
+
+/// An analysis that finds for each IR item whether it has array or not.
+///
+/// We use the monotone constraint function `has_type_parameter_in_array`,
+/// defined as follows:
+///
+/// * If T is Array type with type parameter, T trivially has.
+/// * If T is a type alias, a templated alias or an indirection to another type,
+/// it has type parameter in array if the type T refers to has.
+/// * If T is a compound type, it has array if any of base memter or field
+/// has type paramter in array.
+/// * If T is an instantiation of an abstract template definition, T has
+/// type parameter in array if any of the template arguments or template definition
+/// has.
+#[derive(Debug, Clone)]
+pub struct HasTypeParameterInArray<'ctx, 'gen>
+ where 'gen: 'ctx
+{
+ ctx: &'ctx BindgenContext<'gen>,
+
+ // The incremental result of this analysis's computation. Everything in this
+ // set has array.
+ has_type_parameter_in_array: HashSet<ItemId>,
+
+ // Dependencies saying that if a key ItemId has been inserted into the
+ // `has_type_parameter_in_array` set, then each of the ids in Vec<ItemId> need to be
+ // considered again.
+ //
+ // This is a subset of the natural IR graph with reversed edges, where we
+ // only include the edges from the IR graph that can affect whether a type
+ // has array or not.
+ dependencies: HashMap<ItemId, Vec<ItemId>>,
+}
+
+impl<'ctx, 'gen> HasTypeParameterInArray<'ctx, 'gen> {
+ 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(&mut self, id: ItemId) -> ConstrainResult {
+ trace!("inserting {:?} into the has_type_parameter_in_array set", id);
+
+ let was_not_already_in_set = self.has_type_parameter_in_array.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 HasTypeParameterInArray<'ctx, 'gen> {
+ type Node = ItemId;
+ type Extra = &'ctx BindgenContext<'gen>;
+ type Output = HashSet<ItemId>;
+
+ fn new(ctx: &'ctx BindgenContext<'gen>) -> HasTypeParameterInArray<'ctx, 'gen> {
+ let has_type_parameter_in_array = HashSet::new();
+ let dependencies = generate_dependencies(ctx, Self::consider_edge);
+
+ HasTypeParameterInArray {
+ ctx,
+ has_type_parameter_in_array,
+ dependencies,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<ItemId> {
+ self.ctx.whitelisted_items().iter().cloned().collect()
+ }
+
+ fn constrain(&mut self, id: ItemId) -> ConstrainResult {
+ trace!("constrain: {:?}", id);
+
+ if self.has_type_parameter_in_array.contains(&id) {
+ trace!(" already know it do not have array");
+ return ConstrainResult::Same;
+ }
+
+ let item = self.ctx.resolve_item(id);
+ let ty = match item.as_type() {
+ Some(ty) => ty,
+ None => {
+ trace!(" not a type; ignoring");
+ return ConstrainResult::Same;
+ }
+ };
+
+ match *ty.kind() {
+ // Handle the simple cases. These can derive copy without further
+ // information.
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::BlockPointer |
+ TypeKind::Named |
+ TypeKind::Opaque |
+ TypeKind::Pointer(..) |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::ObjCInterface(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel => {
+ trace!(" simple type that do not have array");
+ ConstrainResult::Same
+ }
+
+ TypeKind::Array(t, _) => {
+ let inner_ty = self.ctx.resolve_type(t).canonical_type(self.ctx);
+ match *inner_ty.kind() {
+ TypeKind::Named => {
+ trace!(" Array with Named type has type parameter");
+ self.insert(id)
+ }
+ _ => {
+ trace!(" Array without Named type does have type parameter");
+ ConstrainResult::Same
+ }
+ }
+ }
+
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) => {
+ if self.has_type_parameter_in_array.contains(&t) {
+ trace!(" aliases and type refs to T which have array \
+ also have array");
+ self.insert(id)
+ } else {
+ trace!(" aliases and type refs to T which do not have array \
+ also do not have array");
+ ConstrainResult::Same
+ }
+ }
+
+ TypeKind::Comp(ref info) => {
+ let bases_have = info.base_members()
+ .iter()
+ .any(|base| self.has_type_parameter_in_array.contains(&base.ty));
+ if bases_have {
+ trace!(" bases have array, so we also have");
+ return self.insert(id);
+ }
+ let fields_have = info.fields()
+ .iter()
+ .any(|f| {
+ match *f {
+ Field::DataMember(ref data) => {
+ self.has_type_parameter_in_array.contains(&data.ty())
+ }
+ Field::Bitfields(..) => false,
+ }
+ });
+ if fields_have {
+ trace!(" fields have array, so we also have");
+ return self.insert(id);
+ }
+
+ trace!(" comp doesn't have array");
+ ConstrainResult::Same
+ }
+
+ TypeKind::TemplateInstantiation(ref template) => {
+ let args_have = template.template_arguments()
+ .iter()
+ .any(|arg| self.has_type_parameter_in_array.contains(&arg));
+ if args_have {
+ trace!(" template args have array, so \
+ insantiation also has array");
+ return self.insert(id);
+ }
+
+ let def_has = self.has_type_parameter_in_array
+ .contains(&template.template_definition());
+ if def_has {
+ trace!(" template definition has array, so \
+ insantiation also has");
+ return self.insert(id);
+ }
+
+ trace!(" template instantiation do not have array");
+ ConstrainResult::Same
+ }
+ }
+ }
+
+ fn each_depending_on<F>(&self, id: ItemId, mut f: F)
+ where F: FnMut(ItemId),
+ {
+ if let Some(edges) = self.dependencies.get(&id) {
+ for item in edges {
+ trace!("enqueue {:?} into worklist", item);
+ f(*item);
+ }
+ }
+ }
+}
+
+impl<'ctx, 'gen> From<HasTypeParameterInArray<'ctx, 'gen>> for HashSet<ItemId> {
+ fn from(analysis: HasTypeParameterInArray<'ctx, 'gen>) -> Self {
+ analysis.has_type_parameter_in_array
+ }
+}
diff --git a/src/ir/analysis/mod.rs b/src/ir/analysis/mod.rs
index ec150ec4..f77c0886 100644
--- a/src/ir/analysis/mod.rs
+++ b/src/ir/analysis/mod.rs
@@ -47,6 +47,10 @@ pub use self::has_vtable::HasVtableAnalysis;
pub use self::has_vtable::HasVtable;
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;
use ir::context::{BindgenContext, ItemId};
use ir::traversal::{EdgeKind, Trace};
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index b3cb3ca5..81bb8d8c 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -2,7 +2,6 @@
use super::annotations::Annotations;
use super::context::{BindgenContext, ItemId};
-use super::derive::CanDeriveCopy;
use super::dot::DotAttributes;
use super::item::{IsOpaque, Item};
use super::layout::Layout;
@@ -702,29 +701,6 @@ impl FieldMethods for FieldData {
}
}
-impl<'a> CanDeriveCopy<'a> for Field {
- type Extra = ();
-
- fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
- match *self {
- Field::DataMember(ref data) => data.ty.can_derive_copy(ctx, ()),
- Field::Bitfields(BitfieldUnit { ref bitfields, .. }) => bitfields.iter().all(|b| {
- b.ty().can_derive_copy(ctx, ())
- }),
- }
- }
-
- fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
- match *self {
- Field::DataMember(ref data) => data.ty.can_derive_copy_in_array(ctx, ()),
- Field::Bitfields(BitfieldUnit { ref bitfields, .. }) => bitfields.iter().all(|b| {
- b.ty().can_derive_copy_in_array(ctx, ())
- }),
- }
- }
-}
-
-
/// The kind of inheritance a base class is using.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BaseKind {
@@ -1404,53 +1380,6 @@ impl TemplateParameters for CompInfo {
}
}
-impl<'a> CanDeriveCopy<'a> for CompInfo {
- type Extra = (&'a Item, Option<Layout>);
-
- fn can_derive_copy(&self,
- ctx: &BindgenContext,
- (item, layout): (&Item, Option<Layout>))
- -> bool {
- if self.has_non_type_template_params() {
- return layout.map_or(true, |l| l.opaque().can_derive_copy(ctx, ()));
- }
-
- // 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.has_destructor(ctx) {
- return false;
- }
-
- if self.kind == CompKind::Union {
- if !ctx.options().unstable_rust {
- // NOTE: If there's no template parameters we can derive copy
- // unconditionally, since arrays are magical for rustc, and
- // __BindgenUnionField always implements copy.
- return true;
- }
-
- // https://github.com/rust-lang/rust/issues/36640
- if !self.template_params.is_empty() ||
- item.used_template_params(ctx).is_some() {
- return false;
- }
- }
-
- self.base_members
- .iter()
- .all(|base| base.ty.can_derive_copy(ctx, ())) &&
- self.fields().iter().all(|field| field.can_derive_copy(ctx, ()))
- }
-
- fn can_derive_copy_in_array(&self,
- ctx: &BindgenContext,
- extra: (&Item, Option<Layout>))
- -> bool {
- self.can_derive_copy(ctx, extra)
- }
-}
-
impl Trace for CompInfo {
type Extra = Item;
diff --git a/src/ir/context.rs b/src/ir/context.rs
index aea9b803..2e0899ed 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -2,11 +2,11 @@
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
use super::int::IntKind;
-use super::item::{IsOpaque, Item, ItemAncestors, ItemCanonicalPath, ItemSet};
+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};
+ CannotDeriveDefault, CannotDeriveCopy, HasTypeParameterInArray};
use super::template::{TemplateInstantiation, TemplateParameters};
use super::traversal::{self, Edge, ItemTraversal};
use super::ty::{FloatKind, Type, TypeKind};
@@ -53,14 +53,8 @@ impl CanDeriveDefault for ItemId {
}
impl<'a> CanDeriveCopy<'a> for ItemId {
- type Extra = ();
-
- fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
- ctx.resolve_item(*self).can_derive_copy(ctx, ())
- }
-
- fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
- ctx.resolve_item(*self).can_derive_copy_in_array(ctx, ())
+ fn can_derive_copy(&self, ctx: &BindgenContext) -> bool {
+ ctx.lookup_item_id_can_derive_copy(*self)
}
}
@@ -188,11 +182,29 @@ pub struct BindgenContext<'ctx> {
/// and is always `None` before that and `Some` after.
cannot_derive_default: Option<HashSet<ItemId>>,
+ /// The set of (`ItemId`s of) types that can't derive copy.
+ ///
+ /// This is populated when we enter codegen by `compute_cannot_derive_copy`
+ /// and is always `None` before that and `Some` after.
+ cannot_derive_copy: Option<HashSet<ItemId>>,
+
+ /// The set of (`ItemId`s of) types that can't derive copy in array.
+ ///
+ /// This is populated when we enter codegen by `compute_cannot_derive_copy`
+ /// 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 has vtable.
///
/// Populated when we enter codegen by `compute_has_vtable`; always `None`
/// before that and `Some` after.
have_vtable: Option<HashSet<ItemId>>,
+
+ /// The set of (`ItemId's of`) types that has array.
+ ///
+ /// Populated when we enter codegen by `compute_has_type_param_in_array`; always `None`
+ /// before that and `Some` after.
+ has_type_param_in_array: Option<HashSet<ItemId>>,
}
/// A traversal of whitelisted items.
@@ -320,7 +332,10 @@ impl<'ctx> BindgenContext<'ctx> {
needs_mangling_hack: needs_mangling_hack,
cannot_derive_debug: None,
cannot_derive_default: None,
+ cannot_derive_copy: None,
+ cannot_derive_copy_in_array: None,
have_vtable: None,
+ has_type_param_in_array: None,
};
me.add_item(root_module, None, None);
@@ -795,6 +810,8 @@ impl<'ctx> BindgenContext<'ctx> {
self.find_used_template_parameters();
self.compute_cannot_derive_debug();
self.compute_cannot_derive_default();
+ self.compute_cannot_derive_copy();
+ self.compute_has_type_param_in_array();
let ret = cb(self);
self.gen_ctx = None;
@@ -1794,6 +1811,40 @@ impl<'ctx> BindgenContext<'ctx> {
// derive default or not.
!self.cannot_derive_default.as_ref().unwrap().contains(&id)
}
+
+ /// Compute whether we can derive debug.
+ fn compute_cannot_derive_copy(&mut self) {
+ assert!(self.cannot_derive_copy.is_none());
+ self.cannot_derive_copy = Some(analyze::<CannotDeriveCopy>(self));
+ }
+
+ /// Look up whether the item with `id` can
+ /// derive debug 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");
+
+ // Look up the computed value for whether the item with `id` can
+ // derive `Copy` or not.
+ !id.has_type_param_in_array(self) &&
+ !self.cannot_derive_copy.as_ref().unwrap().contains(&id)
+ }
+
+ /// Compute whether the type has array.
+ fn compute_has_type_param_in_array(&mut self) {
+ assert!(self.has_type_param_in_array.is_none());
+ self.has_type_param_in_array = Some(analyze::<HasTypeParameterInArray>(self));
+ }
+
+ /// Look up whether the item with `id` has array or not.
+ pub fn lookup_item_id_has_type_param_in_array(&self, id: &ItemId) -> bool {
+ assert!(self.in_codegen_phase(),
+ "We only compute has array when we enter codegen");
+
+ // Look up the computed value for whether the item with `id` has
+ // array or not.
+ self.has_type_param_in_array.as_ref().unwrap().contains(id)
+ }
}
/// A builder struct for configuring item resolution options.
diff --git a/src/ir/derive.rs b/src/ir/derive.rs
index 5bc9cfdd..6d8c2c87 100644
--- a/src/ir/derive.rs
+++ b/src/ir/derive.rs
@@ -20,59 +20,29 @@ pub trait CanDeriveDebug {
/// implementing this trait cannot use recursion or lookup result from fix point
/// analysis. It's a helper trait for fix point analysis.
pub trait CanTriviallyDeriveDebug {
-
- /// Serve the same purpose as the Extra in CanDeriveDebug.
- type Extra;
-
/// Return `true` if `Debug` can be derived for this thing, `false`
/// otherwise.
- fn can_trivially_derive_debug(&self,
- ctx: &BindgenContext,
- extra: Self::Extra)
- -> bool;
+ fn can_trivially_derive_debug(&self) -> bool;
}
/// A trait that encapsulates the logic for whether or not we can derive `Copy`
/// for a given thing.
pub trait CanDeriveCopy<'a> {
- /// Implementations can define this type to get access to any extra
- /// information required to determine whether they can derive `Copy`. If
- /// extra information is unneeded, then this should simply be the unit type.
- type Extra;
-
/// Return `true` if `Copy` can be derived for this thing, `false`
/// otherwise.
fn can_derive_copy(&'a self,
- ctx: &'a BindgenContext,
- extra: Self::Extra)
+ ctx: &'a BindgenContext)
-> bool;
+}
- /// For some reason, deriving copies of an array of a type that is not known
- /// to be `Copy` is a compile error. e.g.:
- ///
- /// ```rust
- /// #[derive(Copy, Clone)]
- /// struct A<T> {
- /// member: T,
- /// }
- /// ```
- ///
- /// is fine, while:
- ///
- /// ```rust,ignore
- /// #[derive(Copy, Clone)]
- /// struct A<T> {
- /// member: [T; 1],
- /// }
- /// ```
- ///
- /// is an error.
- ///
- /// That's the whole point of the existence of `can_derive_copy_in_array`.
- fn can_derive_copy_in_array(&'a self,
- ctx: &'a BindgenContext,
- extra: Self::Extra)
- -> bool;
+/// A trait that encapsulates the logic for whether or not we can derive `Copy`.
+/// The difference between this trait and the CanDeriveCopy 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 CanTriviallyDeriveCopy {
+ /// Return `true` if `Copy` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_trivially_derive_copy(&self) -> bool;
}
/// A trait that encapsulates the logic for whether or not we can derive `Default`
diff --git a/src/ir/function.rs b/src/ir/function.rs
index fbb6121e..99ab8772 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -480,9 +480,7 @@ impl Trace for FunctionSig {
//
// Note that copy is always derived, so we don't need to implement it.
impl CanTriviallyDeriveDebug for FunctionSig {
- type Extra = ();
-
- fn can_trivially_derive_debug(&self, _ctx: &BindgenContext, _: ()) -> bool {
+ 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;
diff --git a/src/ir/item.rs b/src/ir/item.rs
index 8b605795..a17f26fb 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -75,6 +75,12 @@ pub trait IsOpaque {
fn is_opaque(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool;
}
+/// A trait for determining if some IR thing has type parameter in array or not.
+pub trait HasTypeParamInArray {
+ /// Returns `true` if the thing has Array, and `false` otherwise.
+ fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool;
+}
+
/// A trait for iterating over an item and its parents and up its ancestor chain
/// up to (but not including) the implicit root module.
pub trait ItemAncestors {
@@ -283,46 +289,8 @@ impl CanDeriveDefault for Item {
}
impl<'a> CanDeriveCopy<'a> for Item {
- type Extra = ();
-
- fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
- if self.detect_derive_copy_cycle.get() {
- return true;
- }
-
- self.detect_derive_copy_cycle.set(true);
-
- let result = match self.kind {
- ItemKind::Type(ref ty) => {
- if self.is_opaque(ctx, &()) {
- ty.layout(ctx)
- .map_or(true, |l| l.opaque().can_derive_copy(ctx, ()))
- } else {
- ty.can_derive_copy(ctx, self)
- }
- }
- _ => false,
- };
-
- self.detect_derive_copy_cycle.set(false);
-
- result
- }
-
- fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
- match self.kind {
- ItemKind::Type(ref ty) => {
- if self.is_opaque(ctx, &()) {
- ty.layout(ctx)
- .map_or(true, |l| {
- l.opaque().can_derive_copy_in_array(ctx, ())
- })
- } else {
- ty.can_derive_copy_in_array(ctx, self)
- }
- }
- _ => false,
- }
+ fn can_derive_copy(&self, ctx: &BindgenContext) -> bool {
+ ctx.lookup_item_id_can_derive_copy(self.id())
}
}
@@ -379,9 +347,6 @@ pub struct Item {
parent_id: ItemId,
/// The item kind.
kind: ItemKind,
- /// Detect cycles when determining if we can derive copy or not, and
- /// avoid infinite recursion.
- detect_derive_copy_cycle: Cell<bool>,
}
impl AsRef<ItemId> for Item {
@@ -408,7 +373,6 @@ impl Item {
comment: comment,
annotations: annotations.unwrap_or_default(),
kind: kind,
- detect_derive_copy_cycle: Cell::new(false),
}
}
@@ -951,6 +915,22 @@ impl HasVtable for Item {
}
}
+impl HasTypeParamInArray for ItemId {
+ fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ ctx.lookup_item_id_has_type_param_in_array(self)
+ }
+}
+
+impl HasTypeParamInArray for Item {
+ fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(ctx.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ ctx.lookup_item_id_has_type_param_in_array(&self.id())
+ }
+}
+
/// A set of items.
pub type ItemSet = BTreeSet<ItemId>;
diff --git a/src/ir/layout.rs b/src/ir/layout.rs
index b0ec171a..9ec04d20 100644
--- a/src/ir/layout.rs
+++ b/src/ir/layout.rs
@@ -1,8 +1,7 @@
//! Intermediate representation for the physical layout of some type.
-use super::context::BindgenContext;
-use super::derive::{CanDeriveCopy, CanTriviallyDeriveDebug,
- CanTriviallyDeriveDefault};
+use super::derive::{CanTriviallyDeriveDebug,
+ CanTriviallyDeriveDefault, CanTriviallyDeriveCopy};
use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind};
use clang;
use std::{cmp, mem};
@@ -104,9 +103,7 @@ impl Opaque {
}
impl CanTriviallyDeriveDebug for Opaque {
- type Extra = ();
-
- fn can_trivially_derive_debug(&self, _: &BindgenContext, _: ()) -> bool {
+ fn can_trivially_derive_debug(&self) -> bool {
self.array_size()
.map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
}
@@ -120,15 +117,9 @@ impl CanTriviallyDeriveDefault for Opaque {
}
}
-impl<'a> CanDeriveCopy<'a> for Opaque {
- type Extra = ();
-
- fn can_derive_copy(&self, _: &BindgenContext, _: ()) -> bool {
+impl CanTriviallyDeriveCopy for Opaque {
+ fn can_trivially_derive_copy(&self) -> bool {
self.array_size()
.map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
}
-
- fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
- self.can_derive_copy(ctx, ())
- }
}
diff --git a/src/ir/template.rs b/src/ir/template.rs
index 6147365e..30189908 100644
--- a/src/ir/template.rs
+++ b/src/ir/template.rs
@@ -28,7 +28,6 @@
//! ```
use super::context::{BindgenContext, ItemId};
-use super::derive::{CanDeriveCopy};
use super::item::{IsOpaque, Item, ItemAncestors, ItemCanonicalPath};
use super::traversal::{EdgeKind, Trace, Tracer};
use clang;
@@ -333,20 +332,6 @@ impl IsOpaque for TemplateInstantiation {
}
}
-impl<'a> CanDeriveCopy<'a> for TemplateInstantiation {
- type Extra = ();
-
- fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
- self.definition.can_derive_copy(ctx, ()) &&
- self.args.iter().all(|arg| arg.can_derive_copy(ctx, ()))
- }
-
- fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
- self.definition.can_derive_copy_in_array(ctx, ()) &&
- self.args.iter().all(|arg| arg.can_derive_copy_in_array(ctx, ()))
- }
-}
-
impl Trace for TemplateInstantiation {
type Extra = ();
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index 13b5f2ee..0af7b7c2 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -2,7 +2,6 @@
use super::comp::CompInfo;
use super::context::{BindgenContext, ItemId};
-use super::derive::CanDeriveCopy;
use super::dot::DotAttributes;
use super::enum_ty::Enum;
use super::function::FunctionSig;
@@ -526,47 +525,6 @@ impl TemplateParameters for TypeKind {
}
}
-impl<'a> CanDeriveCopy<'a> for Type {
- type Extra = &'a Item;
-
- fn can_derive_copy(&self, ctx: &BindgenContext, item: &Item) -> bool {
- match self.kind {
- TypeKind::Array(t, len) => {
- len > 0 &&
- t.can_derive_copy_in_array(ctx, ())
- }
- TypeKind::ResolvedTypeRef(t) |
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) => t.can_derive_copy(ctx, ()),
- TypeKind::TemplateInstantiation(ref inst) => {
- inst.can_derive_copy(ctx, ())
- }
- TypeKind::Comp(ref info) => {
- info.can_derive_copy(ctx, (item, self.layout(ctx)))
- }
- TypeKind::Opaque => {
- self.layout
- .map_or(true, |l| l.opaque().can_derive_copy(ctx, ()))
- }
- _ => true,
- }
- }
-
- fn can_derive_copy_in_array(&self,
- ctx: &BindgenContext,
- item: &Item)
- -> bool {
- match self.kind {
- TypeKind::ResolvedTypeRef(t) |
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::Array(t, _) => t.can_derive_copy_in_array(ctx, ()),
- TypeKind::Named => false,
- _ => self.can_derive_copy(ctx, item),
- }
- }
-}
-
/// The kind of float this type represents.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FloatKind {