diff --git a/src/codegen/impl_debug.rs b/src/codegen/impl_debug.rs index d429e32898..fd4865111b 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 d7f98c139a..0956eb7ae2 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 0000000000..dbfe35a4a9 --- /dev/null +++ b/src/ir/analysis/derive.rs @@ -0,0 +1,670 @@ +//! 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, + + // 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 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>, +} + +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>( + &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() { + 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; + + 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 { + // 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(&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> for HashMap { + fn from(analysis: CannotDerive<'ctx>) -> Self { + extra_assert!( + analysis + .can_derive + .values() + .all(|v| *v != CanDerive::Yes) + ); + + analysis.can_derive + } +} + +/// Convert a `HashMap` into a `HashSet`. +/// +/// 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) -> HashSet { + 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 55d30097b4..0000000000 --- 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, - - // Dependencies saying that if a key ItemId has been inserted into the - // `cannot_derive_copy` set, then each of - // the ids in Vec 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>, -} - -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>(&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>(&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; - - 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 { - 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(&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> for HashSet { - 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 6580a68b69..0000000000 --- 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, - - // Dependencies saying that if a key ItemId has been inserted into the - // `cannot_derive_debug` set, then each of the ids in Vec 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>, -} - -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>(&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>(&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; - - 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 { - 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(&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> for HashSet { - 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 904cabaa37..0000000000 --- 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, - - // Dependencies saying that if a key ItemId has been inserted into the - // `cannot_derive_default` set, then each of the ids in Vec 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>, -} - -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>(&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>(&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; - - 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 { - 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(&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> for HashSet { - 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 6c8b3976dd..0000000000 --- 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, - - // Dependencies saying that if a key ItemId has been inserted into the - // `cannot_derive_hash` set, then each of the ids in Vec 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>, -} - -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>(&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; - - 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 { - 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(&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> for HashSet { - 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 a64fdf3855..0000000000 --- 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, - - // 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 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>, -} - -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>( - &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; - - 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 { - // 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(&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> - for HashMap { - 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 7d6241bad1..9de6833b8b 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 2626b3e523..914a89b2fd 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::(self)); + self.cannot_derive_debug = Some(as_cannot_derive_set(analyze::((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::(self)); + Some(as_cannot_derive_set(analyze::((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::(self)); + self.cannot_derive_copy = Some(as_cannot_derive_set(analyze::((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::(self)); + self.cannot_derive_hash = Some(as_cannot_derive_set(analyze::((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::(self)); + self.cannot_derive_partialeq_or_partialord = Some(analyze::((self, DeriveTrait::PartialEqOrPartialOrd))); } } diff --git a/src/ir/derive.rs b/src/ir/derive.rs index 71854d2e52..d434b0a0fe 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 b20cc6345c..dc3cfc416a 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 c70d2884da..8438d2c46f 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/derive-fn-ptr.rs b/tests/expectations/tests/derive-fn-ptr.rs index 4b7105e97d..7f158b3bc9 100644 --- a/tests/expectations/tests/derive-fn-ptr.rs +++ b/tests/expectations/tests/derive-fn-ptr.rs @@ -1,8 +1,11 @@ /* automatically generated by rust-bindgen */ - -#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] - +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] pub type my_fun_t = ::std::option::Option< unsafe extern "C" fn( @@ -25,7 +28,7 @@ pub type my_fun_t = ::std::option::Option< ), >; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Default, Copy, Clone)] pub struct Foo { pub callback: my_fun_t, } @@ -52,11 +55,6 @@ fn bindgen_test_layout_Foo() { ) ); } -impl Default for Foo { - fn default() -> Self { - unsafe { ::std::mem::zeroed() } - } -} pub type my_fun2_t = ::std::option::Option< unsafe extern "C" fn( arg1: ::std::os::raw::c_int, @@ -74,7 +72,7 @@ pub type my_fun2_t = ::std::option::Option< ), >; #[repr(C)] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] pub struct Bar { pub callback: my_fun2_t, } @@ -101,8 +99,3 @@ fn bindgen_test_layout_Bar() { ) ); } -impl Default for Bar { - fn default() -> Self { - unsafe { ::std::mem::zeroed() } - } -} diff --git a/tests/expectations/tests/func_ptr_in_struct.rs b/tests/expectations/tests/func_ptr_in_struct.rs index d66ce84d1d..f23984e825 100644 --- a/tests/expectations/tests/func_ptr_in_struct.rs +++ b/tests/expectations/tests/func_ptr_in_struct.rs @@ -1,6 +1,11 @@ /* automatically generated by rust-bindgen */ -#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] #[repr(i32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -8,7 +13,7 @@ pub enum baz { __bindgen_cannot_repr_c_on_empty_enum = 0, } #[repr(C)] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] pub struct Foo { pub bar: ::std::option::Option< unsafe extern "C" fn(x: ::std::os::raw::c_int, y: ::std::os::raw::c_int) -> baz, @@ -32,8 +37,3 @@ fn bindgen_test_layout_Foo() { concat!("Offset of field: ", stringify!(Foo), "::", stringify!(bar)) ); } -impl Default for Foo { - fn default() -> Self { - unsafe { ::std::mem::zeroed() } - } -} diff --git a/tests/expectations/tests/issue-1216-variadic-member.rs b/tests/expectations/tests/issue-1216-variadic-member.rs index 677993c042..e509956090 100644 --- a/tests/expectations/tests/issue-1216-variadic-member.rs +++ b/tests/expectations/tests/issue-1216-variadic-member.rs @@ -1,12 +1,17 @@ /* automatically generated by rust-bindgen */ -#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] extern "C" { pub fn f(a: ::std::os::raw::c_int, ...); } #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone)] pub struct Foo { pub f: ::std::option::Option< unsafe extern "C" fn( @@ -35,8 +40,3 @@ fn bindgen_test_layout_Foo() { concat!("Offset of field: ", stringify!(Foo), "::", stringify!(f)) ); } -impl Default for Foo { - fn default() -> Self { - unsafe { ::std::mem::zeroed() } - } -} diff --git a/tests/expectations/tests/issue-1285.rs b/tests/expectations/tests/issue-1285.rs index 77df620b02..8497c3f241 100644 --- a/tests/expectations/tests/issue-1285.rs +++ b/tests/expectations/tests/issue-1285.rs @@ -7,15 +7,58 @@ non_upper_case_globals )] +#[repr(C)] +pub struct __BindgenUnionField(::std::marker::PhantomData); +impl __BindgenUnionField { + #[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 ::std::default::Default for __BindgenUnionField { + #[inline] + fn default() -> Self { + Self::new() + } +} +impl ::std::clone::Clone for __BindgenUnionField { + #[inline] + fn clone(&self) -> Self { + Self::new() + } +} +impl ::std::marker::Copy for __BindgenUnionField {} +impl ::std::fmt::Debug for __BindgenUnionField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + fmt.write_str("__BindgenUnionField") + } +} +impl ::std::hash::Hash for __BindgenUnionField { + fn hash(&self, _state: &mut H) {} +} +impl ::std::cmp::PartialEq for __BindgenUnionField { + fn eq(&self, _other: &__BindgenUnionField) -> bool { + true + } +} +impl ::std::cmp::Eq for __BindgenUnionField {} #[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() { diff --git a/tests/expectations/tests/layout_cmdline_token.rs b/tests/expectations/tests/layout_cmdline_token.rs index e8b72843fb..2ea596fc96 100644 --- a/tests/expectations/tests/layout_cmdline_token.rs +++ b/tests/expectations/tests/layout_cmdline_token.rs @@ -72,7 +72,7 @@ pub type cmdline_parse_token_hdr_t = cmdline_token_hdr; /// get_help() fills the dstbuf with the help for the token. It returns /// -1 on error and 0 on success. #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Default, Copy, Clone)] pub struct cmdline_token_ops { /// parse(token ptr, buf, res pts, buf len) pub parse: ::std::option::Option< @@ -162,11 +162,6 @@ fn bindgen_test_layout_cmdline_token_ops() { ) ); } -impl Default for cmdline_token_ops { - fn default() -> Self { - unsafe { ::std::mem::zeroed() } - } -} #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum cmdline_numtype { diff --git a/tests/expectations/tests/libclang-3.8/call-conv-field.rs b/tests/expectations/tests/libclang-3.8/call-conv-field.rs index bad20dea8b..1800b6350b 100644 --- a/tests/expectations/tests/libclang-3.8/call-conv-field.rs +++ b/tests/expectations/tests/libclang-3.8/call-conv-field.rs @@ -1,16 +1,18 @@ /* automatically generated by rust-bindgen */ - -#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] #![cfg(not(test))] - #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Default, Copy, Clone)] pub struct JNINativeInterface_ { pub GetVersion: ::std::option::Option< - unsafe extern "stdcall" fn(env: *mut ::std::os::raw::c_void) - -> ::std::os::raw::c_int, + unsafe extern "stdcall" fn(env: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int, >, pub __hack: ::std::os::raw::c_ulonglong, } @@ -47,11 +49,6 @@ fn bindgen_test_layout_JNINativeInterface_() { ) ); } -impl Default for JNINativeInterface_ { - fn default() -> Self { - unsafe { ::std::mem::zeroed() } - } -} extern "C" { #[link_name = "\u{1}_bar@0"] pub fn bar(); diff --git a/tests/expectations/tests/libclang-3.9/call-conv-field.rs b/tests/expectations/tests/libclang-3.9/call-conv-field.rs index 375eb9ad83..6cf8ec5b8e 100644 --- a/tests/expectations/tests/libclang-3.9/call-conv-field.rs +++ b/tests/expectations/tests/libclang-3.9/call-conv-field.rs @@ -6,7 +6,7 @@ #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Default, Copy, Clone)] pub struct JNINativeInterface_ { pub GetVersion: ::std::option::Option< unsafe extern "stdcall" fn(env: *mut ::std::os::raw::c_void) @@ -47,11 +47,6 @@ fn bindgen_test_layout_JNINativeInterface_() { ) ); } -impl Default for JNINativeInterface_ { - fn default() -> Self { - unsafe { ::std::mem::zeroed() } - } -} extern "stdcall" { #[link_name = "\u{1}_bar@0"] pub fn bar(); diff --git a/tests/expectations/tests/libclang-4/call-conv-field.rs b/tests/expectations/tests/libclang-4/call-conv-field.rs index 375eb9ad83..6cf8ec5b8e 100644 --- a/tests/expectations/tests/libclang-4/call-conv-field.rs +++ b/tests/expectations/tests/libclang-4/call-conv-field.rs @@ -6,7 +6,7 @@ #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Default, Copy, Clone)] pub struct JNINativeInterface_ { pub GetVersion: ::std::option::Option< unsafe extern "stdcall" fn(env: *mut ::std::os::raw::c_void) @@ -47,11 +47,6 @@ fn bindgen_test_layout_JNINativeInterface_() { ) ); } -impl Default for JNINativeInterface_ { - fn default() -> Self { - unsafe { ::std::mem::zeroed() } - } -} extern "stdcall" { #[link_name = "\u{1}_bar@0"] pub fn bar(); diff --git a/tests/expectations/tests/libclang-5/call-conv-field.rs b/tests/expectations/tests/libclang-5/call-conv-field.rs index e167e5ebd2..76712fe790 100644 --- a/tests/expectations/tests/libclang-5/call-conv-field.rs +++ b/tests/expectations/tests/libclang-5/call-conv-field.rs @@ -9,7 +9,7 @@ #![cfg(not(test))] #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Default, Copy, Clone)] pub struct JNINativeInterface_ { pub GetVersion: ::std::option::Option< unsafe extern "stdcall" fn(env: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int, @@ -50,11 +50,6 @@ fn bindgen_test_layout_JNINativeInterface_() { ) ); } -impl Default for JNINativeInterface_ { - fn default() -> Self { - unsafe { ::std::mem::zeroed() } - } -} extern "stdcall" { #[link_name = "\u{1}_bar@0"] pub fn bar(); diff --git a/tests/tests.rs b/tests/tests.rs index 65da0656ba..092824f154 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,9 +1,11 @@ +#[cfg(feature = "logging")] +extern crate env_logger; extern crate clap; extern crate diff; extern crate bindgen; extern crate shlex; -use bindgen::{Builder, builder, clang_version}; +use bindgen::{Builder, clang_version}; use std::env; use std::fs; use std::io::{self, BufRead, BufReader, Error, ErrorKind, Read, Write}; @@ -210,7 +212,17 @@ fn compare_generated_header( Err(Error::new(ErrorKind::Other, "Header and binding differ! Run with BINDGEN_OVERWRITE_EXPECTED=1 in the environment to automatically overwrite the expectation.")) } +fn builder() -> Builder { + #[cfg(feature = "logging")] + let _ = env_logger::try_init(); + + bindgen::builder() +} + fn create_bindgen_builder(header: &PathBuf) -> Result, Error> { + #[cfg(feature = "logging")] + let _ = env_logger::try_init(); + let source = fs::File::open(header)?; let reader = BufReader::new(source);