diff options
-rw-r--r-- | src/codegen/mod.rs | 2 | ||||
-rw-r--r-- | src/ir/analysis/derive_copy.rs | 309 | ||||
-rw-r--r-- | src/ir/analysis/derive_debug.rs | 6 | ||||
-rw-r--r-- | src/ir/analysis/has_type_param_in_array.rs | 239 | ||||
-rw-r--r-- | src/ir/analysis/mod.rs | 4 | ||||
-rw-r--r-- | src/ir/comp.rs | 71 | ||||
-rw-r--r-- | src/ir/context.rs | 71 | ||||
-rw-r--r-- | src/ir/derive.rs | 52 | ||||
-rw-r--r-- | src/ir/function.rs | 4 | ||||
-rw-r--r-- | src/ir/item.rs | 68 | ||||
-rw-r--r-- | src/ir/layout.rs | 19 | ||||
-rw-r--r-- | src/ir/template.rs | 15 | ||||
-rw-r--r-- | src/ir/ty.rs | 42 |
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 { |