diff --git a/src/codegen/impl_partialeq.rs b/src/codegen/impl_partialeq.rs new file mode 100644 index 0000000000..7ac960037b --- /dev/null +++ b/src/codegen/impl_partialeq.rs @@ -0,0 +1,122 @@ + +use ir::comp::{CompInfo, CompKind, Field, FieldMethods}; +use ir::context::BindgenContext; +use ir::item::{IsOpaque, Item}; +use ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT}; +use quote; + +/// Generate a manual implementation of `PartialEq` trait for the +/// specified compound type. +pub fn gen_partialeq_impl( + ctx: &BindgenContext, + comp_info: &CompInfo, + item: &Item, + ty_for_impl: "e::Tokens, +) -> Option { + let mut tokens = vec![]; + + if item.is_opaque(ctx, &()) { + tokens.push(quote! { + &self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..] + }); + } else if comp_info.kind() == CompKind::Union { + assert!(!ctx.options().rust_features().untagged_union()); + tokens.push(quote! { + &self.bindgen_union_field[..] == &other.bindgen_union_field[..] + }); + } else { + for base in comp_info.base_members().iter() { + if !base.requires_storage(ctx) { + continue; + } + + let ty_item = ctx.resolve_item(base.ty); + let field_name = &base.field_name; + + if ty_item.is_opaque(ctx, &()) { + let field_name = ctx.rust_ident(field_name); + tokens.push(quote! { + &self. #field_name [..] == &other. #field_name [..] + }); + } else { + tokens.push(gen_field(ctx, ty_item, field_name)); + } + } + + for field in comp_info.fields() { + match *field { + Field::DataMember(ref fd) => { + let ty_item = ctx.resolve_item(fd.ty()); + let name = fd.name().unwrap(); + tokens.push(gen_field(ctx, ty_item, name)); + } + Field::Bitfields(ref bu) => for bitfield in bu.bitfields() { + let name_ident = ctx.rust_ident_raw(bitfield.name()); + tokens.push(quote! { + self.#name_ident () == other.#name_ident () + }); + }, + } + } + } + + Some(quote! { + fn eq(&self, other: & #ty_for_impl) -> bool { + #( #tokens )&&* + } + }) +} + +fn gen_field(ctx: &BindgenContext, ty_item: &Item, name: &str) -> quote::Tokens { + fn quote_equals(name_ident: quote::Ident) -> quote::Tokens { + quote! { self.#name_ident == other.#name_ident } + } + + let name_ident = ctx.rust_ident(name); + let ty = ty_item.expect_type(); + + match *ty.kind() { + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::Int(..) | + TypeKind::Complex(..) | + TypeKind::Float(..) | + TypeKind::Enum(..) | + TypeKind::TypeParam | + TypeKind::UnresolvedTypeRef(..) | + TypeKind::BlockPointer | + TypeKind::Reference(..) | + TypeKind::ObjCInterface(..) | + TypeKind::ObjCId | + TypeKind::ObjCSel | + TypeKind::Comp(..) | + TypeKind::Pointer(_) | + TypeKind::Function(..) | + TypeKind::Opaque => quote_equals(name_ident), + + TypeKind::TemplateInstantiation(ref inst) => { + if inst.is_opaque(ctx, &ty_item) { + quote! { + &self. #name_ident [..] == &other. #name_ident [..] + } + } else { + quote_equals(name_ident) + } + } + + TypeKind::Array(_, len) => if len <= RUST_DERIVE_IN_ARRAY_LIMIT { + quote_equals(name_ident) + } else { + quote! { + &self. #name_ident [..] == &other. #name_ident [..] + } + }, + + TypeKind::ResolvedTypeRef(t) | + TypeKind::TemplateAlias(t, _) | + TypeKind::Alias(t) => { + let inner_item = ctx.resolve_item(t); + gen_field(ctx, inner_item, name) + } + } +} diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 264b701b89..9ccd79c17f 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1,4 +1,5 @@ mod impl_debug; +mod impl_partialeq; mod error; mod helpers; pub mod struct_layout; @@ -14,7 +15,7 @@ use ir::comp::{Base, Bitfield, BitfieldUnit, CompInfo, CompKind, Field, use ir::context::{BindgenContext, ItemId}; use ir::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveHash, CanDerivePartialOrd, CanDeriveOrd, - CanDerivePartialEq, CanDeriveEq}; + CanDerivePartialEq, CanDeriveEq, CannotDeriveReason}; use ir::dot; use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue}; use ir::function::{Abi, Function, FunctionSig}; @@ -1420,6 +1421,7 @@ impl CodeGenerator for CompInfo { let mut needs_clone_impl = false; let mut needs_default_impl = false; let mut needs_debug_impl = false; + let mut needs_partialeq_impl = false; if let Some(comment) = item.comment(ctx) { attributes.push(attributes::doc(comment)); } @@ -1475,6 +1477,14 @@ impl CodeGenerator for CompInfo { if item.can_derive_partialeq(ctx) { derives.push("PartialEq"); + } else { + needs_partialeq_impl = + ctx.options().derive_partialeq && + ctx.options().impl_partialeq && + ctx.lookup_can_derive_partialeq_or_partialord(item.id()) + .map_or(true, |x| { + x == CannotDeriveReason::ArrayTooLarge + }); } if item.can_derive_eq(ctx) { @@ -1535,25 +1545,14 @@ impl CodeGenerator for CompInfo { } for base in self.base_members() { - // Virtual bases are already taken into account by the vtable - // pointer. - // - // FIXME(emilio): Is this always right? - if base.is_virtual() { - continue; - } - - let base_ty = ctx.resolve_type(base.ty); - // NB: We won't include unsized types in our base chain because they - // would contribute to our size given the dummy field we insert for - // unsized types. - if base_ty.is_unsized(ctx, base.ty) { + if !base.requires_storage(ctx) { continue; } let inner = base.ty.to_rust_ty_or_opaque(ctx, &()); let field_name = ctx.rust_ident(&base.field_name); + let base_ty = ctx.resolve_type(base.ty); struct_layout.saw_base(base_ty); fields.push(quote! { @@ -1667,33 +1666,34 @@ impl CodeGenerator for CompInfo { } } - let mut generics = quote! {}; + let mut generic_param_names = vec![]; if let Some(ref params) = used_template_params { - if !params.is_empty() { - let mut param_names = vec![]; + for (idx, ty) in params.iter().enumerate() { + let param = ctx.resolve_type(*ty); + let name = param.name().unwrap(); + let ident = ctx.rust_ident(name); + generic_param_names.push(ident.clone()); - for (idx, ty) in params.iter().enumerate() { - let param = ctx.resolve_type(*ty); - let name = param.name().unwrap(); - let ident = ctx.rust_ident(name); - param_names.push(ident.clone()); - - let prefix = ctx.trait_prefix(); - let field_name = ctx.rust_ident(format!("_phantom_{}", idx)); - fields.push(quote! { - pub #field_name : ::#prefix::marker::PhantomData< - ::#prefix::cell::UnsafeCell<#ident> - > , - }); - } - - generics = quote! { - < #( #param_names ),* > - }; + let prefix = ctx.trait_prefix(); + let field_name = ctx.rust_ident(format!("_phantom_{}", idx)); + fields.push(quote! { + pub #field_name : ::#prefix::marker::PhantomData< + ::#prefix::cell::UnsafeCell<#ident> + > , + }); } } + let generics = if !generic_param_names.is_empty() { + let generic_param_names = generic_param_names.clone(); + quote! { + < #( #generic_param_names ),* > + } + } else { + quote! { } + }; + tokens.append(quote! { #generics { #( #fields )* @@ -1896,6 +1896,27 @@ impl CodeGenerator for CompInfo { }); } + if needs_partialeq_impl { + if let Some(impl_) = impl_partialeq::gen_partialeq_impl(ctx, self, item, &ty_for_impl) { + + let partialeq_bounds = if !generic_param_names.is_empty() { + let bounds = generic_param_names.iter().map(|t| { + quote! { #t: PartialEq } + }); + quote! { where #( #bounds ),* } + } else { + quote! { } + }; + + let prefix = ctx.trait_prefix(); + result.push(quote! { + impl #generics ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds { + #impl_ + } + }); + } + } + if !methods.is_empty() { result.push(quote! { impl #generics #ty_for_impl { diff --git a/src/ir/analysis/derive_partial_eq_or_partial_ord.rs b/src/ir/analysis/derive_partial_eq_or_partial_ord.rs index 7efce6e578..f54650dd02 100644 --- a/src/ir/analysis/derive_partial_eq_or_partial_ord.rs +++ b/src/ir/analysis/derive_partial_eq_or_partial_ord.rs @@ -3,16 +3,13 @@ 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::CanTriviallyDerivePartialEqOrPartialOrd; -use ir::item::IsOpaque; -use ir::traversal::EdgeKind; +use ir::derive::{CanTriviallyDerivePartialEqOrPartialOrd, CanDerive, CannotDeriveReason}; +use ir::item::{Item, IsOpaque}; +use ir::traversal::{EdgeKind, Trace}; use ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT; -use ir::ty::TypeKind; +use ir::ty::{TypeKind, Type}; use std::collections::HashMap; -use std::collections::HashSet; /// An analysis that finds for each IR item whether `PartialEq`/`PartialOrd` /// cannot be derived. @@ -23,9 +20,9 @@ use std::collections::HashSet; /// * 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 -/// length of the array is larger than the limit or the type of data the array -/// contains cannot derive `PartialEq`/`PartialOrd`. +/// * 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 @@ -47,7 +44,7 @@ pub struct CannotDerivePartialEqOrPartialOrd<'ctx> { // The incremental result of this analysis's computation. Everything in this // set cannot derive `PartialEq`/`PartialOrd`. - cannot_derive_partialeq_or_partialord: HashSet, + cannot_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 @@ -83,91 +80,66 @@ impl<'ctx> CannotDerivePartialEqOrPartialOrd<'ctx> { } } - fn insert>(&mut self, id: Id) -> ConstrainResult { + fn insert>( + &mut self, + id: Id, + reason: CannotDeriveReason, + ) -> ConstrainResult { let id = id.into(); - trace!("inserting {:?} into the cannot_derive_partialeq_or_partialord set", id); - - let was_not_already_in_set = self.cannot_derive_partialeq_or_partialord.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 + trace!( + "inserting {:?} into the cannot_derive_partialeq_or_partialord because {:?}", + id, + reason ); - + let existing = self.cannot_derive_partialeq_or_partialord + .insert(id, reason); + assert!(can_supersede(existing, Some(reason))); ConstrainResult::Changed } -} - -impl<'ctx> MonotoneFramework for CannotDerivePartialEqOrPartialOrd<'ctx> { - type Node = ItemId; - type Extra = &'ctx BindgenContext; - type Output = HashSet; - - fn new( - ctx: &'ctx BindgenContext, - ) -> CannotDerivePartialEqOrPartialOrd<'ctx> { - let cannot_derive_partialeq_or_partialord = HashSet::new(); - let dependencies = generate_dependencies(ctx, Self::consider_edge); - - CannotDerivePartialEqOrPartialOrd { - ctx, - cannot_derive_partialeq_or_partialord, - 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_partialeq_or_partialord.contains(&id) { - trace!(" already know it cannot derive `PartialEq`/`PartialOrd`"); - return ConstrainResult::Same; + fn constrain_type( + &mut self, + item: &Item, + ty: &Type, + ) -> Option { + if !self.ctx.whitelisted_items().contains(&item.id()) { + return Some(CannotDeriveReason::Other); } - 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_partialeq_by_name(&item) { - return self.insert(id) + return Some(CannotDeriveReason::Other); } trace!("ty: {:?}", ty); if item.is_opaque(self.ctx, &()) { - let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| { - l.opaque().can_trivially_derive_partialeq_or_partialord() - }); - return if layout_can_derive && - !(ty.is_union() && - self.ctx.options().rust_features().untagged_union()) { - trace!(" we can trivially derive `PartialEq`/`PartialOrd` for the layout"); - ConstrainResult::Same - } else { - trace!(" we cannot derive `PartialEq`/`PartialOrd` for the layout"); - self.insert(id) - }; - } + if ty.is_union() + && self.ctx.options().rust_features().untagged_union() + { + trace!( + " cannot derive `PartialEq`/`PartialOrd` for Rust unions" + ); + return Some(CannotDeriveReason::Other); + } - 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); + let layout_can_derive = ty.layout(self.ctx) + .map_or(CanDerive::Yes, |l| { + l.opaque().can_trivially_derive_partialeq_or_partialord() + }); + + return match layout_can_derive { + CanDerive::Yes => { + trace!( + " we can trivially derive `PartialEq`/`PartialOrd` for the layout" + ); + None + } + CanDerive::No(reason) => { + trace!( + " we cannot derive `PartialEq`/`PartialOrd` for the layout" + ); + Some(reason) + } + }; } match *ty.kind() { @@ -186,25 +158,36 @@ impl<'ctx> MonotoneFramework for CannotDerivePartialEqOrPartialOrd<'ctx> { TypeKind::ObjCInterface(..) | TypeKind::ObjCId | TypeKind::ObjCSel => { - trace!(" simple type that can always derive `PartialEq`/`PartialOrd`"); - ConstrainResult::Same + trace!( + " simple type that can always derive `PartialEq`/`PartialOrd`" + ); + return None; } TypeKind::Array(t, len) => { - if self.cannot_derive_partialeq_or_partialord.contains(&t.into()) { + if self.cannot_derive_partialeq_or_partialord.contains_key(&t.into()) { trace!( " arrays of T for which we cannot derive `PartialEq`/`PartialOrd` \ - also cannot derive `PartialEq`/`PartialOrd`" + also cannot derive `PartialEq`/`PartialOrd`" ); - return self.insert(id); + return Some(CannotDeriveReason::Other); } - if len <= RUST_DERIVE_IN_ARRAY_LIMIT { - trace!(" array is small enough to derive `PartialEq`/`PartialOrd`"); - ConstrainResult::Same + if len == 0 { + trace!( + " cannot derive `PartialEq`/`PartialOrd` for incomplete arrays" + ); + return Some(CannotDeriveReason::Other); + } else if len <= RUST_DERIVE_IN_ARRAY_LIMIT { + trace!( + " array is small enough to derive `PartialEq`/`PartialOrd`" + ); + return None; } else { - trace!(" array is too large to derive `PartialEq`/`PartialOrd`"); - self.insert(id) + trace!( + " array is too large to derive `PartialEq`/`PartialOrd`" + ); + return Some(CannotDeriveReason::ArrayTooLarge); } } @@ -212,44 +195,30 @@ impl<'ctx> MonotoneFramework for CannotDerivePartialEqOrPartialOrd<'ctx> { 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() { + if let CanDerive::No(_) = + sig.can_trivially_derive_partialeq_or_partialord() + { trace!( " function pointer that can't trivially derive `PartialEq`/`PartialOrd`" ); - return self.insert(id); + return Some(CannotDeriveReason::Other); } } - trace!(" pointers can derive PartialEq"); - ConstrainResult::Same + trace!(" pointers can derive `PartialEq`/`PartialOrd`"); + return None; } TypeKind::Function(ref sig) => { - if !sig.can_trivially_derive_partialeq_or_partialord() { + if let CanDerive::No(_) = + sig.can_trivially_derive_partialeq_or_partialord() + { trace!( " function that can't trivially derive `PartialEq`/`PartialOrd`" ); - return self.insert(id); + return Some(CannotDeriveReason::Other); } trace!(" function can derive `PartialEq`/`PartialOrd`"); - ConstrainResult::Same - } - - TypeKind::ResolvedTypeRef(t) | - TypeKind::TemplateAlias(t, _) | - TypeKind::Alias(t) => { - if self.cannot_derive_partialeq_or_partialord.contains(&t.into()) { - trace!( - " aliases and type refs to T which cannot derive \ - `PartialEq`/`PartialOrd` also cannot derive `PartialEq`/`PartialOrd`" - ); - self.insert(id) - } else { - trace!( - " aliases and type refs to T which can derive \ - `PartialEq`/`PartialOrd` can also derive `PartialEq`/`PartialOrd`" - ); - ConstrainResult::Same - } + return None; } TypeKind::Comp(ref info) => { @@ -260,114 +229,178 @@ impl<'ctx> MonotoneFramework for CannotDerivePartialEqOrPartialOrd<'ctx> { if info.kind() == CompKind::Union { if self.ctx.options().rust_features().untagged_union() { - trace!(" cannot derive `PartialEq`/`PartialOrd` for Rust unions"); - return self.insert(id); - } - - if ty.layout(self.ctx).map_or(true, |l| { - l.opaque().can_trivially_derive_partialeq_or_partialord() - }) - { trace!( - " union layout can trivially derive `PartialEq`/`PartialOrd`" + " cannot derive `PartialEq`/`PartialOrd` for Rust unions" ); - return ConstrainResult::Same; - } else { - trace!(" union layout cannot derive `PartialEq`/`PartialOrd`"); - return self.insert(id); + return Some(CannotDeriveReason::Other); } - } - let bases_cannot_derive = - info.base_members().iter().any(|base| { - !self.ctx.whitelisted_items().contains(&base.ty.into()) || - self.cannot_derive_partialeq_or_partialord.contains(&base.ty.into()) - }); - if bases_cannot_derive { - trace!( - " base members cannot derive `PartialEq`/`PartialOrd`, so we can't \ - either" + let layout_can_derive = ty.layout(self.ctx).map_or( + CanDerive::Yes, + |l| { + l.opaque() + .can_trivially_derive_partialeq_or_partialord() + }, ); - 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_partialeq_or_partialord.contains( - &data.ty().into(), - ) + return match layout_can_derive { + CanDerive::Yes => { + trace!( + " union layout can trivially derive `PartialEq`/`PartialOrd`" + ); + None } - Field::Bitfields(ref bfu) => { - if bfu.layout().align > RUST_DERIVE_IN_ARRAY_LIMIT { - trace!( - " we cannot derive PartialEq 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_partialeq_or_partialord.contains( - &b.ty().into(), - ) - }) + CanDerive::No(reason) => { + trace!( + " union layout cannot derive `PartialEq`/`PartialOrd`" + ); + Some(reason) } - }); - if fields_cannot_derive { - trace!( - " fields cannot derive `PartialEq`/`PartialOrd`, so we can't either" - ); - return self.insert(id); + }; } + return self.constrain_join(item); + } - trace!(" comp can derive PartialEq"); - ConstrainResult::Same + TypeKind::ResolvedTypeRef(..) | + TypeKind::TemplateAlias(..) | + TypeKind::Alias(..) | + TypeKind::TemplateInstantiation(..) => { + return self.constrain_join(item); } - TypeKind::TemplateInstantiation(ref template) => { - let args_cannot_derive = - template.template_arguments().iter().any(|arg| { - self.cannot_derive_partialeq_or_partialord.contains(&arg.into()) - }); - if args_cannot_derive { - trace!( - " template args cannot derive `PartialEq`/`PartialOrd`, so \ - insantiation can't either" - ); - return self.insert(id); + TypeKind::Opaque => unreachable!( + "The early ty.is_opaque check should have handled this case" + ), + } + } + + fn constrain_join(&mut self, item: &Item) -> Option { + 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() || !Self::consider_edge(edge_kind) { + return; } - 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_partialeq_or_partialord.contains( - &template.template_definition().into(), - ); - if def_cannot_derive { - trace!( - " template definition cannot derive `PartialEq`/`PartialOrd`, so \ - insantiation can't either" - ); - return self.insert(id); + let reason = self.cannot_derive_partialeq_or_partialord + .get(&sub_id) + .cloned(); + + if can_supersede(candidate, reason) { + candidate = reason; } + }, + &(), + ); - trace!(" template instantiation can derive `PartialEq`/`PartialOrd`"); - ConstrainResult::Same - } + candidate + } +} - TypeKind::Opaque => { - unreachable!( - "The early ty.is_opaque check should have handled this case" - ) +/// Check if the one reason could supersede another. +/// +/// To keep this analysis monotone we should go only in one direction. +/// If the abscence of the reason is at the bottom and `CannotDeriveReason::Other` +/// is at the top, then we can only go upwards. +/// +/// Other +/// ^ +/// | +/// ArrayTooLarge +/// ^ +/// | +/// None +/// +fn can_supersede(from: Option, to: Option) -> bool { + fn rank(maybe_reason: Option) -> usize { + match maybe_reason { + None => 0, + Some(CannotDeriveReason::ArrayTooLarge) => 1, + Some(CannotDeriveReason::Other) => 2, + } + } + rank(from) <= rank(to) +} + +impl<'ctx> MonotoneFramework for CannotDerivePartialEqOrPartialOrd<'ctx> { + type Node = ItemId; + type Extra = &'ctx BindgenContext; + type Output = HashMap; + + fn new( + ctx: &'ctx BindgenContext, + ) -> CannotDerivePartialEqOrPartialOrd<'ctx> { + let cannot_derive_partialeq_or_partialord = HashMap::new(); + let dependencies = generate_dependencies(ctx, Self::consider_edge); + + CannotDerivePartialEqOrPartialOrd { + ctx, + cannot_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(CannotDeriveReason::Other) = + self.cannot_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 maybe_reason = match item.as_type() { + Some(ty) => { + self.constrain_type(item, ty).or_else(|| { + 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. + Some(CannotDeriveReason::ArrayTooLarge) + } else { + None + } + }) } + None => self.constrain_join(item), + }; + + if let Some(reason) = maybe_reason { + self.insert(id, reason) + } else { + ConstrainResult::Same } } @@ -384,7 +417,7 @@ impl<'ctx> MonotoneFramework for CannotDerivePartialEqOrPartialOrd<'ctx> { } } -impl<'ctx> From> for HashSet { +impl<'ctx> From> for HashMap { fn from(analysis: CannotDerivePartialEqOrPartialOrd<'ctx>) -> Self { analysis.cannot_derive_partialeq_or_partialord } diff --git a/src/ir/analysis/mod.rs b/src/ir/analysis/mod.rs index 179fa33db0..dfc96f0ada 100644 --- a/src/ir/analysis/mod.rs +++ b/src/ir/analysis/mod.rs @@ -59,8 +59,8 @@ mod derive_partial_eq_or_partial_ord; pub use self::derive_partial_eq_or_partial_ord::CannotDerivePartialEqOrPartialOrd; mod has_float; pub use self::has_float::HasFloat; - use ir::context::{BindgenContext, ItemId}; + use ir::traversal::{EdgeKind, Trace}; use std::collections::HashMap; use std::fmt; diff --git a/src/ir/comp.rs b/src/ir/comp.rs index c1dd369bca..6a90bcbf59 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -806,6 +806,27 @@ impl Base { pub fn is_virtual(&self) -> bool { self.kind == BaseKind::Virtual } + + /// Whether this base class should have it's own field for storage. + pub fn requires_storage(&self, ctx: &BindgenContext) -> bool { + // Virtual bases are already taken into account by the vtable + // pointer. + // + // FIXME(emilio): Is this always right? + if self.is_virtual() { + return false; + } + + let base_ty = ctx.resolve_type(self.ty); + // NB: We won't include unsized types in our base chain because they + // would contribute to our size given the dummy field we insert for + // unsized types. + if base_ty.is_unsized(ctx, self.ty) { + return false; + } + + true + } } /// A compound type. diff --git a/src/ir/context.rs b/src/ir/context.rs index 37b71ba1c9..27a3416247 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -7,7 +7,7 @@ use super::analysis::{CannotDeriveCopy, CannotDeriveDebug, HasFloat, analyze}; use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveHash, CanDerivePartialOrd, CanDeriveOrd, - CanDerivePartialEq, CanDeriveEq}; + CanDerivePartialEq, CanDeriveEq, CannotDeriveReason}; use super::int::IntKind; use super::item::{IsOpaque, Item, ItemAncestors, ItemCanonicalPath, ItemSet}; use super::item_kind::ItemKind; @@ -249,7 +249,7 @@ where { fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_partialord && - ctx.lookup_can_derive_partialeq_or_partialord(*self) + ctx.lookup_can_derive_partialeq_or_partialord(*self).is_none() } } @@ -259,7 +259,7 @@ where { fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_partialeq && - ctx.lookup_can_derive_partialeq_or_partialord(*self) + ctx.lookup_can_derive_partialeq_or_partialord(*self).is_none() } } @@ -269,7 +269,7 @@ where { fn can_derive_eq(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_eq && - ctx.lookup_can_derive_partialeq_or_partialord(*self) && + ctx.lookup_can_derive_partialeq_or_partialord(*self).is_none() && !ctx.lookup_has_float(*self) } } @@ -280,7 +280,7 @@ where { fn can_derive_ord(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_ord && - ctx.lookup_can_derive_partialeq_or_partialord(*self) && + ctx.lookup_can_derive_partialeq_or_partialord(*self).is_none() && !ctx.lookup_has_float(*self) } } @@ -423,12 +423,12 @@ pub struct BindgenContext { /// and is always `None` before that and `Some` after. cannot_derive_hash: Option>, - /// The set of (`ItemId`s of) types that can't derive hash. + /// The map why specified `ItemId`s of) types that can't derive hash. /// /// This is populated when we enter codegen by /// `compute_cannot_derive_partialord_partialeq_or_eq` and is always `None` /// before that and `Some` after. - cannot_derive_partialeq_or_partialord: Option>, + cannot_derive_partialeq_or_partialord: Option>, /// The set of (`ItemId's of`) types that has vtable. /// @@ -2365,7 +2365,7 @@ impl BindgenContext { } /// Look up whether the item with `id` can derive `Partial{Eq,Ord}`. - pub fn lookup_can_derive_partialeq_or_partialord>(&self, id: Id) -> bool { + pub fn lookup_can_derive_partialeq_or_partialord>(&self, id: Id) -> Option { let id = id.into(); assert!( self.in_codegen_phase(), @@ -2374,7 +2374,7 @@ impl BindgenContext { // Look up the computed value for whether the item with `id` can // derive partialeq or not. - !self.cannot_derive_partialeq_or_partialord.as_ref().unwrap().contains(&id) + self.cannot_derive_partialeq_or_partialord.as_ref().unwrap().get(&id).cloned() } /// Look up whether the item with `id` can derive `Copy` or not. diff --git a/src/ir/derive.rs b/src/ir/derive.rs index cafbd3b1a8..52e611336f 100644 --- a/src/ir/derive.rs +++ b/src/ir/derive.rs @@ -117,5 +117,27 @@ pub trait CanTriviallyDeriveHash { pub trait CanTriviallyDerivePartialEqOrPartialOrd { /// Return `true` if `PartialEq` or `PartialOrd` can trivially be derived /// for this thing, `false` otherwise. - fn can_trivially_derive_partialeq_or_partialord(&self) -> bool; + fn can_trivially_derive_partialeq_or_partialord(&self) -> CanDerive; +} + +/// Reason why exactly we cannot automatically derive a trait. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum CannotDeriveReason { + /// The only thing that stops us from automatically deriving is that + /// array with more than maximum number of elements is used. + /// + /// This means we probably can "manually" implement such trait. + ArrayTooLarge, + + /// Any other reason. + Other, +} + +/// Whether it is possible or not to derive trait automatically. +pub enum CanDerive { + /// Yes, we can! + Yes, + + /// No, we cannot. Contains reason why exactly we can't derive. + No(CannotDeriveReason) } diff --git a/src/ir/function.rs b/src/ir/function.rs index ccdfc4f350..3a9f337c93 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -9,7 +9,7 @@ use super::ty::TypeKind; use clang; use clang_sys::{self, CXCallingConv}; use ir::derive::{CanTriviallyDeriveDebug, CanTriviallyDeriveHash, - CanTriviallyDerivePartialEqOrPartialOrd}; + CanTriviallyDerivePartialEqOrPartialOrd, CanDerive, CannotDeriveReason}; use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; use quote; use std::io; @@ -560,7 +560,14 @@ impl CanTriviallyDeriveHash for FunctionSig { } impl CanTriviallyDerivePartialEqOrPartialOrd for FunctionSig { - fn can_trivially_derive_partialeq_or_partialord(&self) -> bool { - self.function_pointers_can_derive() + fn can_trivially_derive_partialeq_or_partialord(&self) -> CanDerive { + if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT { + return CanDerive::No(CannotDeriveReason::Other); + } + + match self.abi { + Abi::C | Abi::Unknown(..) => CanDerive::Yes, + _ => CanDerive::No(CannotDeriveReason::Other), + } } } diff --git a/src/ir/item.rs b/src/ir/item.rs index 010528b6d0..dbc352eb84 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -347,21 +347,21 @@ impl CanDeriveHash for Item { impl CanDerivePartialOrd for Item { fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_partialord && - ctx.lookup_can_derive_partialeq_or_partialord(self.id()) + ctx.lookup_can_derive_partialeq_or_partialord(self.id()).is_none() } } impl CanDerivePartialEq for Item { fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_partialeq && - ctx.lookup_can_derive_partialeq_or_partialord(self.id()) + ctx.lookup_can_derive_partialeq_or_partialord(self.id()).is_none() } } impl CanDeriveEq for Item { fn can_derive_eq(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_eq && - ctx.lookup_can_derive_partialeq_or_partialord(self.id()) && + ctx.lookup_can_derive_partialeq_or_partialord(self.id()).is_none() && !ctx.lookup_has_float(self.id()) } } @@ -369,7 +369,7 @@ impl CanDeriveEq for Item { impl CanDeriveOrd for Item { fn can_derive_ord(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_ord && - ctx.lookup_can_derive_partialeq_or_partialord(self.id()) && + ctx.lookup_can_derive_partialeq_or_partialord(self.id()).is_none() && !ctx.lookup_has_float(self.id()) } } diff --git a/src/ir/layout.rs b/src/ir/layout.rs index 2df15ef2bb..0d9c123f74 100644 --- a/src/ir/layout.rs +++ b/src/ir/layout.rs @@ -2,7 +2,7 @@ use super::derive::{CanTriviallyDeriveCopy, CanTriviallyDeriveDebug, CanTriviallyDeriveDefault, CanTriviallyDeriveHash, - CanTriviallyDerivePartialEqOrPartialOrd}; + CanTriviallyDerivePartialEqOrPartialOrd, CanDerive, CannotDeriveReason}; use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind}; use clang; use std::{cmp, mem}; @@ -140,7 +140,13 @@ impl CanTriviallyDeriveHash for Opaque { } impl CanTriviallyDerivePartialEqOrPartialOrd for Opaque { - fn can_trivially_derive_partialeq_or_partialord(&self) -> bool { - self.array_size_within_derive_limit() + fn can_trivially_derive_partialeq_or_partialord(&self) -> CanDerive { + self.array_size().map_or(CanDerive::No(CannotDeriveReason::Other), |size| { + if size <= RUST_DERIVE_IN_ARRAY_LIMIT { + CanDerive::Yes + } else { + CanDerive::No(CannotDeriveReason::ArrayTooLarge) + } + }) } } diff --git a/src/lib.rs b/src/lib.rs index 9e54ddc976..b540653e62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -239,6 +239,14 @@ impl Builder { output_vector.push("--no-layout-tests".into()); } + if self.options.impl_debug { + output_vector.push("--impl-debug".into()); + } + + if self.options.impl_partialeq { + output_vector.push("--impl-partialeq".into()); + } + if !self.options.derive_copy { output_vector.push("--no-derive-copy".into()); } @@ -247,10 +255,6 @@ impl Builder { output_vector.push("--no-derive-debug".into()); } - if self.options.impl_debug { - output_vector.push("--impl-debug".into()); - } - if !self.options.derive_default { output_vector.push("--no-derive-default".into()); } else { @@ -806,6 +810,18 @@ impl Builder { self } + /// Set whether `Debug` should be implemented, if it can not be derived automatically. + pub fn impl_debug(mut self, doit: bool) -> Self { + self.options.impl_debug = doit; + self + } + + /// Set whether `PartialEq` should be implemented, if it can not be derived automatically. + pub fn impl_partialeq(mut self, doit: bool) -> Self { + self.options.impl_partialeq = doit; + self + } + /// Set whether `Copy` should be derived by default. pub fn derive_copy(mut self, doit: bool) -> Self { self.options.derive_copy = doit; @@ -818,12 +834,6 @@ impl Builder { self } - /// Set whether `Debug` should be implemented, if it can not be derived automatically. - pub fn impl_debug(mut self, doit: bool) -> Self { - self.options.impl_debug = doit; - self - } - /// Set whether `Default` should be derived by default. pub fn derive_default(mut self, doit: bool) -> Self { self.options.derive_default = doit; @@ -1209,6 +1219,14 @@ struct BindgenOptions { /// True if we should generate layout tests for generated structures. layout_tests: bool, + /// True if we should implement the Debug trait for C/C++ structures and types + /// that do not support automatically deriving Debug. + impl_debug: bool, + + /// True if we should implement the PartialEq trait for C/C++ structures and types + /// that do not support autoamically deriving PartialEq. + impl_partialeq: bool, + /// True if we should derive Copy trait implementations for C/C++ structures /// and types. derive_copy: bool, @@ -1217,10 +1235,6 @@ struct BindgenOptions { /// and types. derive_debug: bool, - /// True if we should implement the Debug trait for C/C++ structures and types - /// that do not support automatically deriving Debug. - impl_debug: bool, - /// True if we should derive Default trait implementations for C/C++ structures /// and types. derive_default: bool, @@ -1386,9 +1400,10 @@ impl Default for BindgenOptions { emit_ir: false, emit_ir_graphviz: None, layout_tests: true, + impl_debug: false, + impl_partialeq: false, derive_copy: true, derive_debug: true, - impl_debug: false, derive_default: false, derive_hash: false, derive_partialord: false, diff --git a/src/options.rs b/src/options.rs index aec4a2bda1..64ee249eda 100644 --- a/src/options.rs +++ b/src/options.rs @@ -66,14 +66,18 @@ where Arg::with_name("no-derive-debug") .long("no-derive-debug") .help("Avoid deriving Debug on any type."), - Arg::with_name("impl-debug") - .long("impl-debug") - .help("Create Debug implementation, if it can not be derived \ - automatically."), Arg::with_name("no-derive-default") .long("no-derive-default") .hidden(true) .help("Avoid deriving Default on any type."), + Arg::with_name("impl-debug") + .long("impl-debug") + .help("Create Debug implementation, if it can not be derived \ + automatically."), + Arg::with_name("impl-partialeq") + .long("impl-partialeq") + .help("Create PartialEq implementation, if it can not be derived \ + automatically."), Arg::with_name("with-derive-default") .long("with-derive-default") .help("Derive Default on any type."), @@ -347,6 +351,10 @@ where builder = builder.impl_debug(true); } + if matches.is_present("impl-partialeq") { + builder = builder.impl_partialeq(true); + } + if matches.is_present("with-derive-default") { builder = builder.derive_default(true); } diff --git a/tests/expectations/tests/class_1_0.rs b/tests/expectations/tests/class_1_0.rs index 8ccf4e01c6..669b7364db 100644 --- a/tests/expectations/tests/class_1_0.rs +++ b/tests/expectations/tests/class_1_0.rs @@ -7,13 +7,15 @@ #[repr(C)] #[derive(Default)] pub struct __IncompleteArrayField(::std::marker::PhantomData); -impl __IncompleteArrayField { +impl __IncompleteArrayField { #[inline] pub fn new() -> Self { __IncompleteArrayField(::std::marker::PhantomData) } #[inline] - pub unsafe fn as_ptr(&self) -> *const T { ::std::mem::transmute(self) } + pub unsafe fn as_ptr(&self) -> *const T { + ::std::mem::transmute(self) + } #[inline] pub unsafe fn as_mut_ptr(&mut self) -> *mut T { ::std::mem::transmute(self) @@ -27,47 +29,61 @@ impl __IncompleteArrayField { ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) } } -impl ::std::fmt::Debug for __IncompleteArrayField { +impl ::std::fmt::Debug for __IncompleteArrayField { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fmt.write_str("__IncompleteArrayField") } } -impl ::std::clone::Clone for __IncompleteArrayField { +impl ::std::clone::Clone for __IncompleteArrayField { #[inline] - fn clone(&self) -> Self { Self::new() } + fn clone(&self) -> Self { + Self::new() + } } -impl ::std::marker::Copy for __IncompleteArrayField { } +impl ::std::marker::Copy for __IncompleteArrayField {} #[repr(C)] pub struct __BindgenUnionField(::std::marker::PhantomData); -impl __BindgenUnionField { +impl __BindgenUnionField { #[inline] - pub fn new() -> Self { __BindgenUnionField(::std::marker::PhantomData) } + pub fn new() -> Self { + __BindgenUnionField(::std::marker::PhantomData) + } #[inline] - pub unsafe fn as_ref(&self) -> &T { ::std::mem::transmute(self) } + 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) } + pub unsafe fn as_mut(&mut self) -> &mut T { + ::std::mem::transmute(self) + } } -impl ::std::default::Default for __BindgenUnionField { +impl ::std::default::Default for __BindgenUnionField { #[inline] - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } -impl ::std::clone::Clone for __BindgenUnionField { +impl ::std::clone::Clone for __BindgenUnionField { #[inline] - fn clone(&self) -> Self { Self::new() } + fn clone(&self) -> Self { + Self::new() + } } -impl ::std::marker::Copy for __BindgenUnionField { } -impl ::std::fmt::Debug for __BindgenUnionField { +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::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::PartialEq for __BindgenUnionField { + fn eq(&self, _other: &__BindgenUnionField) -> bool { + true + } } -impl ::std::cmp::Eq for __BindgenUnionField { } +impl ::std::cmp::Eq for __BindgenUnionField {} #[repr(C)] #[derive(Copy)] pub struct C { @@ -76,25 +92,46 @@ pub struct C { } #[test] fn bindgen_test_layout_C() { - assert_eq!(::std::mem::size_of::() , 40usize , concat ! ( - "Size of: " , stringify ! ( C ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( C ) )); - assert_eq! (unsafe { & ( * ( 0 as * const C ) ) . a as * const _ as usize - } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( C ) , "::" , stringify - ! ( a ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const C ) ) . big_array as * const _ as usize } - , 4usize , concat ! ( - "Alignment of field: " , stringify ! ( C ) , "::" , stringify - ! ( big_array ) )); + assert_eq!( + ::std::mem::size_of::(), + 40usize, + concat!("Size of: ", stringify!(C)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(C)) + ); + assert_eq!( + unsafe { &(*(0 as *const C)).a as *const _ as usize }, + 0usize, + concat!("Alignment of field: ", stringify!(C), "::", stringify!(a)) + ); + assert_eq!( + unsafe { &(*(0 as *const C)).big_array as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(C), + "::", + stringify!(big_array) + ) + ); } impl Clone for C { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl Default for C { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +impl ::std::cmp::PartialEq for C { + fn eq(&self, other: &C) -> bool { + self.a == other.a && &self.big_array[..] == &other.big_array[..] + } } #[repr(C)] pub struct C_with_zero_length_array { @@ -104,33 +141,53 @@ pub struct C_with_zero_length_array { } #[test] fn bindgen_test_layout_C_with_zero_length_array() { - assert_eq!(::std::mem::size_of::() , 40usize , - concat ! ( - "Size of: " , stringify ! ( C_with_zero_length_array ) )); - assert_eq! (::std::mem::align_of::() , 4usize , - concat ! ( - "Alignment of " , stringify ! ( C_with_zero_length_array ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const C_with_zero_length_array ) ) . a as * - const _ as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( - C_with_zero_length_array ) , "::" , stringify ! ( a ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const C_with_zero_length_array ) ) . big_array - as * const _ as usize } , 4usize , concat ! ( - "Alignment of field: " , stringify ! ( - C_with_zero_length_array ) , "::" , stringify ! ( big_array ) - )); - assert_eq! (unsafe { - & ( * ( 0 as * const C_with_zero_length_array ) ) . - zero_length_array as * const _ as usize } , 37usize , concat ! - ( - "Alignment of field: " , stringify ! ( - C_with_zero_length_array ) , "::" , stringify ! ( - zero_length_array ) )); + assert_eq!( + ::std::mem::size_of::(), + 40usize, + concat!("Size of: ", stringify!(C_with_zero_length_array)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(C_with_zero_length_array)) + ); + assert_eq!( + unsafe { &(*(0 as *const C_with_zero_length_array)).a as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(C_with_zero_length_array), + "::", + stringify!(a) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const C_with_zero_length_array)).big_array as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(C_with_zero_length_array), + "::", + stringify!(big_array) + ) + ); + assert_eq!( + unsafe { + &(*(0 as *const C_with_zero_length_array)).zero_length_array as *const _ as usize + }, + 37usize, + concat!( + "Alignment of field: ", + stringify!(C_with_zero_length_array), + "::", + stringify!(zero_length_array) + ) + ); } impl Default for C_with_zero_length_array { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } } #[repr(C)] pub struct C_with_incomplete_array { @@ -140,15 +197,21 @@ pub struct C_with_incomplete_array { } #[test] fn bindgen_test_layout_C_with_incomplete_array() { - assert_eq!(::std::mem::size_of::() , 40usize , - concat ! ( - "Size of: " , stringify ! ( C_with_incomplete_array ) )); - assert_eq! (::std::mem::align_of::() , 4usize , - concat ! ( - "Alignment of " , stringify ! ( C_with_incomplete_array ) )); + assert_eq!( + ::std::mem::size_of::(), + 40usize, + concat!("Size of: ", stringify!(C_with_incomplete_array)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(C_with_incomplete_array)) + ); } impl Default for C_with_incomplete_array { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } } #[repr(C)] pub struct C_with_zero_length_array_and_incomplete_array { @@ -159,17 +222,27 @@ pub struct C_with_zero_length_array_and_incomplete_array { } #[test] fn bindgen_test_layout_C_with_zero_length_array_and_incomplete_array() { - assert_eq!(::std::mem::size_of::() - , 40usize , concat ! ( - "Size of: " , stringify ! ( - C_with_zero_length_array_and_incomplete_array ) )); - assert_eq! (::std::mem::align_of::() - , 4usize , concat ! ( - "Alignment of " , stringify ! ( - C_with_zero_length_array_and_incomplete_array ) )); + assert_eq!( + ::std::mem::size_of::(), + 40usize, + concat!( + "Size of: ", + stringify!(C_with_zero_length_array_and_incomplete_array) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!( + "Alignment of ", + stringify!(C_with_zero_length_array_and_incomplete_array) + ) + ); } impl Default for C_with_zero_length_array_and_incomplete_array { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } } #[repr(C)] #[derive(Debug, Default, Hash, PartialEq, Eq)] @@ -178,15 +251,26 @@ pub struct WithDtor { } #[test] fn bindgen_test_layout_WithDtor() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( WithDtor ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( WithDtor ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const WithDtor ) ) . b as * const _ as usize } - , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( WithDtor ) , "::" , - stringify ! ( b ) )); + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(WithDtor)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(WithDtor)) + ); + assert_eq!( + unsafe { &(*(0 as *const WithDtor)).b as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(WithDtor), + "::", + stringify!(b) + ) + ); } #[repr(C)] pub struct IncompleteArrayNonCopiable { @@ -195,16 +279,21 @@ pub struct IncompleteArrayNonCopiable { } #[test] fn bindgen_test_layout_IncompleteArrayNonCopiable() { - assert_eq!(::std::mem::size_of::() , 8usize , - concat ! ( - "Size of: " , stringify ! ( IncompleteArrayNonCopiable ) )); - assert_eq! (::std::mem::align_of::() , 8usize - , concat ! ( - "Alignment of " , stringify ! ( IncompleteArrayNonCopiable ) - )); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(IncompleteArrayNonCopiable)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(IncompleteArrayNonCopiable)) + ); } impl Default for IncompleteArrayNonCopiable { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } } #[repr(C)] #[derive(Debug, Default, Copy, Hash, PartialEq)] @@ -215,23 +304,41 @@ pub struct Union { } #[test] fn bindgen_test_layout_Union() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( Union ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( Union ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const Union ) ) . d as * const _ as usize } , - 0usize , concat ! ( - "Alignment of field: " , stringify ! ( Union ) , "::" , - stringify ! ( d ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const Union ) ) . i as * const _ as usize } , - 0usize , concat ! ( - "Alignment of field: " , stringify ! ( Union ) , "::" , - stringify ! ( i ) )); + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(Union)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Union)) + ); + assert_eq!( + unsafe { &(*(0 as *const Union)).d as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(Union), + "::", + stringify!(d) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const Union)).i as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(Union), + "::", + stringify!(i) + ) + ); } impl Clone for Union { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } #[repr(C)] #[derive(Debug, Default, Copy, Hash, PartialEq)] @@ -240,18 +347,31 @@ pub struct WithUnion { } #[test] fn bindgen_test_layout_WithUnion() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( WithUnion ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( WithUnion ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const WithUnion ) ) . data as * const _ as - usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( WithUnion ) , "::" , - stringify ! ( data ) )); + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(WithUnion)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(WithUnion)) + ); + assert_eq!( + unsafe { &(*(0 as *const WithUnion)).data as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(WithUnion), + "::", + stringify!(data) + ) + ); } impl Clone for WithUnion { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } #[repr(C)] #[derive(Debug, Default, Copy, Hash, PartialEq, Eq)] @@ -260,41 +380,49 @@ pub struct RealAbstractionWithTonsOfMethods { } #[test] fn bindgen_test_layout_RealAbstractionWithTonsOfMethods() { - assert_eq!(::std::mem::size_of::() , - 1usize , concat ! ( - "Size of: " , stringify ! ( RealAbstractionWithTonsOfMethods ) - )); - assert_eq! (::std::mem::align_of::() , - 1usize , concat ! ( - "Alignment of " , stringify ! ( - RealAbstractionWithTonsOfMethods ) )); + assert_eq!( + ::std::mem::size_of::(), + 1usize, + concat!("Size of: ", stringify!(RealAbstractionWithTonsOfMethods)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(RealAbstractionWithTonsOfMethods) + ) + ); } extern "C" { #[link_name = "_ZNK32RealAbstractionWithTonsOfMethods3barEv"] - pub fn RealAbstractionWithTonsOfMethods_bar(this: - *const RealAbstractionWithTonsOfMethods); + pub fn RealAbstractionWithTonsOfMethods_bar(this: *const RealAbstractionWithTonsOfMethods); } extern "C" { #[link_name = "_ZN32RealAbstractionWithTonsOfMethods3barEv"] - pub fn RealAbstractionWithTonsOfMethods_bar1(this: - *mut RealAbstractionWithTonsOfMethods); + pub fn RealAbstractionWithTonsOfMethods_bar1(this: *mut RealAbstractionWithTonsOfMethods); } extern "C" { #[link_name = "_ZN32RealAbstractionWithTonsOfMethods3barEi"] - pub fn RealAbstractionWithTonsOfMethods_bar2(this: - *mut RealAbstractionWithTonsOfMethods, - foo: ::std::os::raw::c_int); + pub fn RealAbstractionWithTonsOfMethods_bar2( + this: *mut RealAbstractionWithTonsOfMethods, + foo: ::std::os::raw::c_int, + ); } extern "C" { #[link_name = "_ZN32RealAbstractionWithTonsOfMethods3staEv"] pub fn RealAbstractionWithTonsOfMethods_sta(); } impl Clone for RealAbstractionWithTonsOfMethods { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl RealAbstractionWithTonsOfMethods { #[inline] - pub unsafe fn bar(&self) { RealAbstractionWithTonsOfMethods_bar(self) } + pub unsafe fn bar(&self) { + RealAbstractionWithTonsOfMethods_bar(self) + } #[inline] pub unsafe fn bar1(&mut self) { RealAbstractionWithTonsOfMethods_bar1(self) @@ -304,5 +432,7 @@ impl RealAbstractionWithTonsOfMethods { RealAbstractionWithTonsOfMethods_bar2(self, foo) } #[inline] - pub unsafe fn sta() { RealAbstractionWithTonsOfMethods_sta() } + pub unsafe fn sta() { + RealAbstractionWithTonsOfMethods_sta() + } } diff --git a/tests/expectations/tests/derive-partialeq-anonfield.rs b/tests/expectations/tests/derive-partialeq-anonfield.rs new file mode 100644 index 0000000000..6e3446d52f --- /dev/null +++ b/tests/expectations/tests/derive-partialeq-anonfield.rs @@ -0,0 +1,57 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + + +#[repr(C)] +#[derive(Copy)] +pub struct rte_mbuf { + pub __bindgen_anon_1: rte_mbuf__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy)] +pub union rte_mbuf__bindgen_ty_1 { + _bindgen_union_align: [u8; 0usize], +} +#[test] +fn bindgen_test_layout_rte_mbuf__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::(), + 0usize, + concat!("Size of: ", stringify!(rte_mbuf__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(rte_mbuf__bindgen_ty_1)) + ); +} +impl Clone for rte_mbuf__bindgen_ty_1 { + fn clone(&self) -> Self { + *self + } +} +impl Default for rte_mbuf__bindgen_ty_1 { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +#[test] +fn bindgen_test_layout_rte_mbuf() { + assert_eq!( + ::std::mem::size_of::(), + 0usize, + concat!("Size of: ", stringify!(rte_mbuf)) + ); +} +impl Clone for rte_mbuf { + fn clone(&self) -> Self { + *self + } +} +impl Default for rte_mbuf { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} diff --git a/tests/expectations/tests/derive-partialeq-base.rs b/tests/expectations/tests/derive-partialeq-base.rs new file mode 100644 index 0000000000..1235665522 --- /dev/null +++ b/tests/expectations/tests/derive-partialeq-base.rs @@ -0,0 +1,82 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + + +#[repr(C)] +#[derive(Copy)] +pub struct Base { + pub large: [::std::os::raw::c_int; 33usize], +} +#[test] +fn bindgen_test_layout_Base() { + assert_eq!( + ::std::mem::size_of::(), + 132usize, + concat!("Size of: ", stringify!(Base)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Base)) + ); + assert_eq!( + unsafe { &(*(0 as *const Base)).large as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(Base), + "::", + stringify!(large) + ) + ); +} +impl Clone for Base { + fn clone(&self) -> Self { + *self + } +} +impl Default for Base { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +impl ::std::cmp::PartialEq for Base { + fn eq(&self, other: &Base) -> bool { + &self.large[..] == &other.large[..] + } +} +#[repr(C)] +#[derive(Copy)] +pub struct ShouldDerivePartialEq { + pub _base: Base, +} +#[test] +fn bindgen_test_layout_ShouldDerivePartialEq() { + assert_eq!( + ::std::mem::size_of::(), + 132usize, + concat!("Size of: ", stringify!(ShouldDerivePartialEq)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(ShouldDerivePartialEq)) + ); +} +impl Clone for ShouldDerivePartialEq { + fn clone(&self) -> Self { + *self + } +} +impl Default for ShouldDerivePartialEq { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +impl ::std::cmp::PartialEq for ShouldDerivePartialEq { + fn eq(&self, other: &ShouldDerivePartialEq) -> bool { + self._base == other._base + } +} diff --git a/tests/expectations/tests/derive-partialeq-bitfield.rs b/tests/expectations/tests/derive-partialeq-bitfield.rs new file mode 100644 index 0000000000..b788f6c31e --- /dev/null +++ b/tests/expectations/tests/derive-partialeq-bitfield.rs @@ -0,0 +1,130 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + + +#[repr(C)] +#[derive(Copy)] +pub struct C { + pub _bitfield_1: u8, + pub large_array: [::std::os::raw::c_int; 50usize], +} +#[test] +fn bindgen_test_layout_C() { + assert_eq!( + ::std::mem::size_of::(), + 204usize, + concat!("Size of: ", stringify!(C)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(C)) + ); + assert_eq!( + unsafe { &(*(0 as *const C)).large_array as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(C), + "::", + stringify!(large_array) + ) + ); +} +impl Clone for C { + fn clone(&self) -> Self { + *self + } +} +impl Default for C { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +impl ::std::cmp::PartialEq for C { + fn eq(&self, other: &C) -> bool { + self.a() == other.a() && self.b() == other.b() && + &self.large_array[..] == &other.large_array[..] + } +} +impl C { + #[inline] + pub fn a(&self) -> bool { + let mut unit_field_val: u8 = unsafe { ::std::mem::uninitialized() }; + unsafe { + ::std::ptr::copy_nonoverlapping( + &self._bitfield_1 as *const _ as *const u8, + &mut unit_field_val as *mut u8 as *mut u8, + ::std::mem::size_of::(), + ) + }; + let mask = 1u64 as u8; + let val = (unit_field_val & mask) >> 0usize; + unsafe { ::std::mem::transmute(val as u8) } + } + #[inline] + pub fn set_a(&mut self, val: bool) { + let mask = 1u64 as u8; + let val = val as u8 as u8; + let mut unit_field_val: u8 = unsafe { ::std::mem::uninitialized() }; + unsafe { + ::std::ptr::copy_nonoverlapping( + &self._bitfield_1 as *const _ as *const u8, + &mut unit_field_val as *mut u8 as *mut u8, + ::std::mem::size_of::(), + ) + }; + unit_field_val &= !mask; + unit_field_val |= (val << 0usize) & mask; + unsafe { + ::std::ptr::copy_nonoverlapping( + &unit_field_val as *const _ as *const u8, + &mut self._bitfield_1 as *mut _ as *mut u8, + ::std::mem::size_of::(), + ); + } + } + #[inline] + pub fn b(&self) -> bool { + let mut unit_field_val: u8 = unsafe { ::std::mem::uninitialized() }; + unsafe { + ::std::ptr::copy_nonoverlapping( + &self._bitfield_1 as *const _ as *const u8, + &mut unit_field_val as *mut u8 as *mut u8, + ::std::mem::size_of::(), + ) + }; + let mask = 254u64 as u8; + let val = (unit_field_val & mask) >> 1usize; + unsafe { ::std::mem::transmute(val as u8) } + } + #[inline] + pub fn set_b(&mut self, val: bool) { + let mask = 254u64 as u8; + let val = val as u8 as u8; + let mut unit_field_val: u8 = unsafe { ::std::mem::uninitialized() }; + unsafe { + ::std::ptr::copy_nonoverlapping( + &self._bitfield_1 as *const _ as *const u8, + &mut unit_field_val as *mut u8 as *mut u8, + ::std::mem::size_of::(), + ) + }; + unit_field_val &= !mask; + unit_field_val |= (val << 1usize) & mask; + unsafe { + ::std::ptr::copy_nonoverlapping( + &unit_field_val as *const _ as *const u8, + &mut self._bitfield_1 as *mut _ as *mut u8, + ::std::mem::size_of::(), + ); + } + } + #[inline] + pub fn new_bitfield_1(a: bool, b: bool) -> u8 { + ((0 | ((a as u8 as u8) << 0usize) & (1u64 as u8)) | + ((b as u8 as u8) << 1usize) & (254u64 as u8)) + } +} diff --git a/tests/expectations/tests/derive-partialeq-core.rs b/tests/expectations/tests/derive-partialeq-core.rs new file mode 100644 index 0000000000..1660f17877 --- /dev/null +++ b/tests/expectations/tests/derive-partialeq-core.rs @@ -0,0 +1,50 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + +extern crate core; + +#[repr(C)] +#[derive(Copy)] +pub struct C { + pub large_array: [::std::os::raw::c_int; 420usize], +} +#[test] +fn bindgen_test_layout_C() { + assert_eq!( + ::core::mem::size_of::(), + 1680usize, + concat!("Size of: ", stringify!(C)) + ); + assert_eq!( + ::core::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(C)) + ); + assert_eq!( + unsafe { &(*(0 as *const C)).large_array as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(C), + "::", + stringify!(large_array) + ) + ); +} +impl Clone for C { + fn clone(&self) -> Self { + *self + } +} +impl Default for C { + fn default() -> Self { + unsafe { ::core::mem::zeroed() } + } +} +impl ::core::cmp::PartialEq for C { + fn eq(&self, other: &C) -> bool { + &self.large_array[..] == &other.large_array[..] + } +} diff --git a/tests/expectations/tests/derive-partialeq-pointer.rs b/tests/expectations/tests/derive-partialeq-pointer.rs new file mode 100644 index 0000000000..b1d3f04c6d --- /dev/null +++ b/tests/expectations/tests/derive-partialeq-pointer.rs @@ -0,0 +1,129 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + + +#[repr(C)] +#[derive(Debug, Copy, Hash, PartialEq, Eq)] +pub struct Bar { + pub b: *mut a, +} +#[test] +fn bindgen_test_layout_Bar() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(Bar)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(Bar)) + ); + assert_eq!( + unsafe { &(*(0 as *const Bar)).b as *const _ as usize }, + 0usize, + concat!("Alignment of field: ", stringify!(Bar), "::", stringify!(b)) + ); +} +impl Clone for Bar { + fn clone(&self) -> Self { + *self + } +} +impl Default for Bar { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +#[repr(C)] +#[derive(Copy)] +pub struct c { + pub __bindgen_anon_1: c__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy)] +pub union c__bindgen_ty_1 { + _bindgen_union_align: u8, + pub _address: u8, +} +#[test] +fn bindgen_test_layout_c__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::(), + 1usize, + concat!("Size of: ", stringify!(c__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(c__bindgen_ty_1)) + ); +} +impl Clone for c__bindgen_ty_1 { + fn clone(&self) -> Self { + *self + } +} +impl Default for c__bindgen_ty_1 { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +#[test] +fn bindgen_test_layout_c() { + assert_eq!( + ::std::mem::size_of::(), + 1usize, + concat!("Size of: ", stringify!(c)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(c)) + ); +} +impl Clone for c { + fn clone(&self) -> Self { + *self + } +} +impl Default for c { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +#[repr(C)] +#[derive(Copy)] +pub struct a { + pub d: c, +} +#[test] +fn bindgen_test_layout_a() { + assert_eq!( + ::std::mem::size_of::(), + 1usize, + concat!("Size of: ", stringify!(a)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(a)) + ); + assert_eq!( + unsafe { &(*(0 as *const a)).d as *const _ as usize }, + 0usize, + concat!("Alignment of field: ", stringify!(a), "::", stringify!(d)) + ); +} +impl Clone for a { + fn clone(&self) -> Self { + *self + } +} +impl Default for a { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} diff --git a/tests/expectations/tests/derive-partialeq-union.rs b/tests/expectations/tests/derive-partialeq-union.rs new file mode 100644 index 0000000000..975dee3670 --- /dev/null +++ b/tests/expectations/tests/derive-partialeq-union.rs @@ -0,0 +1,58 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + + + +/// Deriving PartialEq for rust unions is not supported. +#[repr(C)] +#[derive(Copy)] +pub union ShouldNotDerivePartialEq { + pub a: ::std::os::raw::c_char, + pub b: ::std::os::raw::c_int, + _bindgen_union_align: u32, +} +#[test] +fn bindgen_test_layout_ShouldNotDerivePartialEq() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(ShouldNotDerivePartialEq)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(ShouldNotDerivePartialEq)) + ); + assert_eq!( + unsafe { &(*(0 as *const ShouldNotDerivePartialEq)).a as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(ShouldNotDerivePartialEq), + "::", + stringify!(a) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ShouldNotDerivePartialEq)).b as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(ShouldNotDerivePartialEq), + "::", + stringify!(b) + ) + ); +} +impl Clone for ShouldNotDerivePartialEq { + fn clone(&self) -> Self { + *self + } +} +impl Default for ShouldNotDerivePartialEq { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} diff --git a/tests/expectations/tests/derive-partialeq-union_1_0.rs b/tests/expectations/tests/derive-partialeq-union_1_0.rs new file mode 100644 index 0000000000..32a0635272 --- /dev/null +++ b/tests/expectations/tests/derive-partialeq-union_1_0.rs @@ -0,0 +1,105 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, 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 {} +/// This should manually derive PartialEq. +#[repr(C)] +#[derive(Copy)] +pub struct ShouldDerivePartialEq { + pub a: __BindgenUnionField<[::std::os::raw::c_char; 150usize]>, + pub b: __BindgenUnionField<::std::os::raw::c_int>, + pub bindgen_union_field: [u32; 38usize], +} +#[test] +fn bindgen_test_layout_ShouldDerivePartialEq() { + assert_eq!( + ::std::mem::size_of::(), + 152usize, + concat!("Size of: ", stringify!(ShouldDerivePartialEq)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(ShouldDerivePartialEq)) + ); + assert_eq!( + unsafe { &(*(0 as *const ShouldDerivePartialEq)).a as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(ShouldDerivePartialEq), + "::", + stringify!(a) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ShouldDerivePartialEq)).b as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(ShouldDerivePartialEq), + "::", + stringify!(b) + ) + ); +} +impl Clone for ShouldDerivePartialEq { + fn clone(&self) -> Self { + *self + } +} +impl Default for ShouldDerivePartialEq { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +impl ::std::cmp::PartialEq for ShouldDerivePartialEq { + fn eq(&self, other: &ShouldDerivePartialEq) -> bool { + &self.bindgen_union_field[..] == &other.bindgen_union_field[..] + } +} diff --git a/tests/expectations/tests/issue-648-derive-debug-with-padding.rs b/tests/expectations/tests/issue-648-derive-debug-with-padding.rs index 27b5cfcd26..11c318a213 100644 --- a/tests/expectations/tests/issue-648-derive-debug-with-padding.rs +++ b/tests/expectations/tests/issue-648-derive-debug-with-padding.rs @@ -43,6 +43,11 @@ impl Default for NoDebug { unsafe { ::std::mem::zeroed() } } } +impl ::std::cmp::PartialEq for NoDebug { + fn eq(&self, other: &NoDebug) -> bool { + self.c == other.c + } +} /// This should derive Debug/Hash/PartialEq/Eq because the padding size is less than the max derive /// Debug/Hash/PartialEq/Eq impl for arrays. However, we conservatively don't derive Debug/Hash because /// we determine Debug derive-ability before we compute padding, which happens at @@ -92,3 +97,8 @@ impl Default for ShouldDeriveDebugButDoesNot { unsafe { ::std::mem::zeroed() } } } +impl ::std::cmp::PartialEq for ShouldDeriveDebugButDoesNot { + fn eq(&self, other: &ShouldDeriveDebugButDoesNot) -> bool { + self.c == other.c && self.d == other.d + } +} diff --git a/tests/expectations/tests/layout_array.rs b/tests/expectations/tests/layout_array.rs index 9f2082ecfa..c1a1518799 100644 --- a/tests/expectations/tests/layout_array.rs +++ b/tests/expectations/tests/layout_array.rs @@ -21,30 +21,32 @@ pub struct rte_mempool { /// it will most likely point to a different type of data structure, and /// will be transparent to the application programmer. /// This function should set mp->pool_data. -pub type rte_mempool_alloc_t = - ::std::option::Option ::std::os::raw::c_int>; +pub type rte_mempool_alloc_t = ::std::option::Option< + unsafe extern "C" fn(mp: *mut rte_mempool) -> ::std::os::raw::c_int, +>; /// Free the opaque private data pointed to by mp->pool_data pointer. -pub type rte_mempool_free_t = - ::std::option::Option; +pub type rte_mempool_free_t = ::std::option::Option; /// Enqueue an object into the external pool. -pub type rte_mempool_enqueue_t = - ::std::option::Option ::std::os::raw::c_int>; +pub type rte_mempool_enqueue_t = ::std::option::Option< + unsafe extern "C" fn( + mp: *mut rte_mempool, + obj_table: *const *const ::std::os::raw::c_void, + n: ::std::os::raw::c_uint, + ) -> ::std::os::raw::c_int, +>; /// Dequeue an object from the external pool. -pub type rte_mempool_dequeue_t = - ::std::option::Option ::std::os::raw::c_int>; +pub type rte_mempool_dequeue_t = ::std::option::Option< + unsafe extern "C" fn( + mp: *mut rte_mempool, + obj_table: *mut *mut ::std::os::raw::c_void, + n: ::std::os::raw::c_uint, + ) -> ::std::os::raw::c_int, +>; /// Return the number of available objects in the external pool. -pub type rte_mempool_get_count = - ::std::option::Option ::std::os::raw::c_uint>; +pub type rte_mempool_get_count = ::std::option::Option< + unsafe extern "C" fn(mp: *const rte_mempool) + -> ::std::os::raw::c_uint, +>; /// Structure defining mempool operations structure #[repr(C)] #[derive(Copy)] @@ -65,44 +67,88 @@ pub struct rte_mempool_ops { } #[test] fn bindgen_test_layout_rte_mempool_ops() { - assert_eq!(::std::mem::size_of::() , 128usize , concat ! - ( "Size of: " , stringify ! ( rte_mempool_ops ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const rte_mempool_ops ) ) . name as * const _ - as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( rte_mempool_ops ) , - "::" , stringify ! ( name ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const rte_mempool_ops ) ) . alloc as * const _ - as usize } , 32usize , concat ! ( - "Alignment of field: " , stringify ! ( rte_mempool_ops ) , - "::" , stringify ! ( alloc ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const rte_mempool_ops ) ) . free as * const _ - as usize } , 40usize , concat ! ( - "Alignment of field: " , stringify ! ( rte_mempool_ops ) , - "::" , stringify ! ( free ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const rte_mempool_ops ) ) . enqueue as * const - _ as usize } , 48usize , concat ! ( - "Alignment of field: " , stringify ! ( rte_mempool_ops ) , - "::" , stringify ! ( enqueue ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const rte_mempool_ops ) ) . dequeue as * const - _ as usize } , 56usize , concat ! ( - "Alignment of field: " , stringify ! ( rte_mempool_ops ) , - "::" , stringify ! ( dequeue ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const rte_mempool_ops ) ) . get_count as * - const _ as usize } , 64usize , concat ! ( - "Alignment of field: " , stringify ! ( rte_mempool_ops ) , - "::" , stringify ! ( get_count ) )); + assert_eq!( + ::std::mem::size_of::(), + 128usize, + concat!("Size of: ", stringify!(rte_mempool_ops)) + ); + assert_eq!( + unsafe { &(*(0 as *const rte_mempool_ops)).name as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(rte_mempool_ops), + "::", + stringify!(name) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const rte_mempool_ops)).alloc as *const _ as usize }, + 32usize, + concat!( + "Alignment of field: ", + stringify!(rte_mempool_ops), + "::", + stringify!(alloc) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const rte_mempool_ops)).free as *const _ as usize }, + 40usize, + concat!( + "Alignment of field: ", + stringify!(rte_mempool_ops), + "::", + stringify!(free) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const rte_mempool_ops)).enqueue as *const _ as usize }, + 48usize, + concat!( + "Alignment of field: ", + stringify!(rte_mempool_ops), + "::", + stringify!(enqueue) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const rte_mempool_ops)).dequeue as *const _ as usize }, + 56usize, + concat!( + "Alignment of field: ", + stringify!(rte_mempool_ops), + "::", + stringify!(dequeue) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const rte_mempool_ops)).get_count as *const _ as usize }, + 64usize, + concat!( + "Alignment of field: ", + stringify!(rte_mempool_ops), + "::", + stringify!(get_count) + ) + ); } impl Clone for rte_mempool_ops { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl Default for rte_mempool_ops { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +impl ::std::cmp::PartialEq for rte_mempool_ops { + fn eq(&self, other: &rte_mempool_ops) -> bool { + self.name == other.name && self.alloc == other.alloc && self.free == other.free + && self.enqueue == other.enqueue && self.dequeue == other.dequeue + && self.get_count == other.get_count + } } /// The rte_spinlock_t type. #[repr(C)] @@ -113,18 +159,31 @@ pub struct rte_spinlock_t { } #[test] fn bindgen_test_layout_rte_spinlock_t() { - assert_eq!(::std::mem::size_of::() , 4usize , concat ! ( - "Size of: " , stringify ! ( rte_spinlock_t ) )); - assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( - "Alignment of " , stringify ! ( rte_spinlock_t ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const rte_spinlock_t ) ) . locked as * const _ - as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( rte_spinlock_t ) , "::" - , stringify ! ( locked ) )); + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(rte_spinlock_t)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(rte_spinlock_t)) + ); + assert_eq!( + unsafe { &(*(0 as *const rte_spinlock_t)).locked as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(rte_spinlock_t), + "::", + stringify!(locked) + ) + ); } impl Clone for rte_spinlock_t { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } /// Structure storing the table of registered ops structs, each of which contain /// the function pointers for the mempool ops functions. @@ -146,30 +205,51 @@ pub struct rte_mempool_ops_table { } #[test] fn bindgen_test_layout_rte_mempool_ops_table() { - assert_eq!(::std::mem::size_of::() , 2112usize , - concat ! ( "Size of: " , stringify ! ( rte_mempool_ops_table ) - )); - assert_eq! (unsafe { - & ( * ( 0 as * const rte_mempool_ops_table ) ) . sl as * const - _ as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( rte_mempool_ops_table ) - , "::" , stringify ! ( sl ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const rte_mempool_ops_table ) ) . num_ops as * - const _ as usize } , 4usize , concat ! ( - "Alignment of field: " , stringify ! ( rte_mempool_ops_table ) - , "::" , stringify ! ( num_ops ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const rte_mempool_ops_table ) ) . ops as * - const _ as usize } , 64usize , concat ! ( - "Alignment of field: " , stringify ! ( rte_mempool_ops_table ) - , "::" , stringify ! ( ops ) )); + assert_eq!( + ::std::mem::size_of::(), + 2112usize, + concat!("Size of: ", stringify!(rte_mempool_ops_table)) + ); + assert_eq!( + unsafe { &(*(0 as *const rte_mempool_ops_table)).sl as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(rte_mempool_ops_table), + "::", + stringify!(sl) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const rte_mempool_ops_table)).num_ops as *const _ as usize }, + 4usize, + concat!( + "Alignment of field: ", + stringify!(rte_mempool_ops_table), + "::", + stringify!(num_ops) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const rte_mempool_ops_table)).ops as *const _ as usize }, + 64usize, + concat!( + "Alignment of field: ", + stringify!(rte_mempool_ops_table), + "::", + stringify!(ops) + ) + ); } impl Clone for rte_mempool_ops_table { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl Default for rte_mempool_ops_table { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } } /// Structure to hold malloc heap #[repr(C)] @@ -187,56 +267,100 @@ pub struct malloc_heap__bindgen_ty_1 { } #[test] fn bindgen_test_layout_malloc_heap__bindgen_ty_1() { - assert_eq!(::std::mem::size_of::() , 8usize , - concat ! ( - "Size of: " , stringify ! ( malloc_heap__bindgen_ty_1 ) )); - assert_eq! (::std::mem::align_of::() , 8usize , - concat ! ( - "Alignment of " , stringify ! ( malloc_heap__bindgen_ty_1 ) - )); - assert_eq! (unsafe { - & ( * ( 0 as * const malloc_heap__bindgen_ty_1 ) ) . lh_first - as * const _ as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( - malloc_heap__bindgen_ty_1 ) , "::" , stringify ! ( lh_first ) - )); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(malloc_heap__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(malloc_heap__bindgen_ty_1)) + ); + assert_eq!( + unsafe { &(*(0 as *const malloc_heap__bindgen_ty_1)).lh_first as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(malloc_heap__bindgen_ty_1), + "::", + stringify!(lh_first) + ) + ); } impl Clone for malloc_heap__bindgen_ty_1 { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl Default for malloc_heap__bindgen_ty_1 { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } } #[test] fn bindgen_test_layout_malloc_heap() { - assert_eq!(::std::mem::size_of::() , 128usize , concat ! ( - "Size of: " , stringify ! ( malloc_heap ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const malloc_heap ) ) . lock as * const _ as - usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( malloc_heap ) , "::" , - stringify ! ( lock ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const malloc_heap ) ) . free_head as * const _ - as usize } , 8usize , concat ! ( - "Alignment of field: " , stringify ! ( malloc_heap ) , "::" , - stringify ! ( free_head ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const malloc_heap ) ) . alloc_count as * const - _ as usize } , 112usize , concat ! ( - "Alignment of field: " , stringify ! ( malloc_heap ) , "::" , - stringify ! ( alloc_count ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const malloc_heap ) ) . total_size as * const _ - as usize } , 120usize , concat ! ( - "Alignment of field: " , stringify ! ( malloc_heap ) , "::" , - stringify ! ( total_size ) )); + assert_eq!( + ::std::mem::size_of::(), + 128usize, + concat!("Size of: ", stringify!(malloc_heap)) + ); + assert_eq!( + unsafe { &(*(0 as *const malloc_heap)).lock as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(malloc_heap), + "::", + stringify!(lock) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const malloc_heap)).free_head as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(malloc_heap), + "::", + stringify!(free_head) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const malloc_heap)).alloc_count as *const _ as usize }, + 112usize, + concat!( + "Alignment of field: ", + stringify!(malloc_heap), + "::", + stringify!(alloc_count) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const malloc_heap)).total_size as *const _ as usize }, + 120usize, + concat!( + "Alignment of field: ", + stringify!(malloc_heap), + "::", + stringify!(total_size) + ) + ); } impl Clone for malloc_heap { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl Default for malloc_heap { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +impl ::std::cmp::PartialEq for malloc_heap { + fn eq(&self, other: &malloc_heap) -> bool { + self.lock == other.lock && self.free_head == other.free_head + && self.alloc_count == other.alloc_count && self.total_size == other.total_size + } } #[repr(C)] #[derive(Debug, Default, Copy, Hash, PartialEq, Eq)] @@ -244,5 +368,7 @@ pub struct malloc_elem { pub _address: u8, } impl Clone for malloc_elem { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } diff --git a/tests/expectations/tests/layout_array_too_long.rs b/tests/expectations/tests/layout_array_too_long.rs index 1a3da41ea6..6cfd85a483 100644 --- a/tests/expectations/tests/layout_array_too_long.rs +++ b/tests/expectations/tests/layout_array_too_long.rs @@ -31,31 +31,56 @@ pub struct ip_frag { } #[test] fn bindgen_test_layout_ip_frag() { - assert_eq!(::std::mem::size_of::() , 16usize , concat ! ( - "Size of: " , stringify ! ( ip_frag ) )); - assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( - "Alignment of " , stringify ! ( ip_frag ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag ) ) . ofs as * const _ as usize } - , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag ) , "::" , - stringify ! ( ofs ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag ) ) . len as * const _ as usize } - , 2usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag ) , "::" , - stringify ! ( len ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag ) ) . mb as * const _ as usize } - , 8usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag ) , "::" , - stringify ! ( mb ) )); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(ip_frag)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(ip_frag)) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag)).ofs as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag), + "::", + stringify!(ofs) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag)).len as *const _ as usize }, + 2usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag), + "::", + stringify!(len) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag)).mb as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag), + "::", + stringify!(mb) + ) + ); } impl Clone for ip_frag { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl Default for ip_frag { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } } /// @internal to uniquely indetify fragmented datagram. #[repr(C)] @@ -70,28 +95,51 @@ pub struct ip_frag_key { } #[test] fn bindgen_test_layout_ip_frag_key() { - assert_eq!(::std::mem::size_of::() , 40usize , concat ! ( - "Size of: " , stringify ! ( ip_frag_key ) )); - assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( - "Alignment of " , stringify ! ( ip_frag_key ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_key ) ) . src_dst as * const _ as - usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag_key ) , "::" , - stringify ! ( src_dst ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_key ) ) . id as * const _ as - usize } , 32usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag_key ) , "::" , - stringify ! ( id ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_key ) ) . key_len as * const _ as - usize } , 36usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag_key ) , "::" , - stringify ! ( key_len ) )); + assert_eq!( + ::std::mem::size_of::(), + 40usize, + concat!("Size of: ", stringify!(ip_frag_key)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(ip_frag_key)) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_key)).src_dst as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_key), + "::", + stringify!(src_dst) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_key)).id as *const _ as usize }, + 32usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_key), + "::", + stringify!(id) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_key)).key_len as *const _ as usize }, + 36usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_key), + "::", + stringify!(key_len) + ) + ); } impl Clone for ip_frag_key { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } /// @internal Fragmented packet to reassemble. /// First two entries in the frags[] array are for the last and first fragments. @@ -122,77 +170,141 @@ pub struct ip_frag_pkt__bindgen_ty_1 { } #[test] fn bindgen_test_layout_ip_frag_pkt__bindgen_ty_1() { - assert_eq!(::std::mem::size_of::() , 16usize , - concat ! ( - "Size of: " , stringify ! ( ip_frag_pkt__bindgen_ty_1 ) )); - assert_eq! (::std::mem::align_of::() , 8usize , - concat ! ( - "Alignment of " , stringify ! ( ip_frag_pkt__bindgen_ty_1 ) - )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_pkt__bindgen_ty_1 ) ) . tqe_next - as * const _ as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( - ip_frag_pkt__bindgen_ty_1 ) , "::" , stringify ! ( tqe_next ) - )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_pkt__bindgen_ty_1 ) ) . tqe_prev - as * const _ as usize } , 8usize , concat ! ( - "Alignment of field: " , stringify ! ( - ip_frag_pkt__bindgen_ty_1 ) , "::" , stringify ! ( tqe_prev ) - )); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(ip_frag_pkt__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(ip_frag_pkt__bindgen_ty_1)) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_pkt__bindgen_ty_1)).tqe_next as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_pkt__bindgen_ty_1), + "::", + stringify!(tqe_next) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_pkt__bindgen_ty_1)).tqe_prev as *const _ as usize }, + 8usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_pkt__bindgen_ty_1), + "::", + stringify!(tqe_prev) + ) + ); } impl Clone for ip_frag_pkt__bindgen_ty_1 { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl Default for ip_frag_pkt__bindgen_ty_1 { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } } #[test] fn bindgen_test_layout_ip_frag_pkt() { - assert_eq!(::std::mem::size_of::() , 192usize , concat ! ( - "Size of: " , stringify ! ( ip_frag_pkt ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_pkt ) ) . lru as * const _ as - usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag_pkt ) , "::" , - stringify ! ( lru ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_pkt ) ) . key as * const _ as - usize } , 16usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag_pkt ) , "::" , - stringify ! ( key ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_pkt ) ) . start as * const _ as - usize } , 56usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag_pkt ) , "::" , - stringify ! ( start ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_pkt ) ) . total_size as * const _ - as usize } , 64usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag_pkt ) , "::" , - stringify ! ( total_size ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_pkt ) ) . frag_size as * const _ - as usize } , 68usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag_pkt ) , "::" , - stringify ! ( frag_size ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_pkt ) ) . last_idx as * const _ - as usize } , 72usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag_pkt ) , "::" , - stringify ! ( last_idx ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ip_frag_pkt ) ) . frags as * const _ as - usize } , 80usize , concat ! ( - "Alignment of field: " , stringify ! ( ip_frag_pkt ) , "::" , - stringify ! ( frags ) )); + assert_eq!( + ::std::mem::size_of::(), + 192usize, + concat!("Size of: ", stringify!(ip_frag_pkt)) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_pkt)).lru as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_pkt), + "::", + stringify!(lru) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_pkt)).key as *const _ as usize }, + 16usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_pkt), + "::", + stringify!(key) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_pkt)).start as *const _ as usize }, + 56usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_pkt), + "::", + stringify!(start) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_pkt)).total_size as *const _ as usize }, + 64usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_pkt), + "::", + stringify!(total_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_pkt)).frag_size as *const _ as usize }, + 68usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_pkt), + "::", + stringify!(frag_size) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_pkt)).last_idx as *const _ as usize }, + 72usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_pkt), + "::", + stringify!(last_idx) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ip_frag_pkt)).frags as *const _ as usize }, + 80usize, + concat!( + "Alignment of field: ", + stringify!(ip_frag_pkt), + "::", + stringify!(frags) + ) + ); } impl Clone for ip_frag_pkt { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl Default for ip_frag_pkt { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +impl ::std::cmp::PartialEq for ip_frag_pkt { + fn eq(&self, other: &ip_frag_pkt) -> bool { + self.lru == other.lru && self.key == other.key && self.start == other.start && + self.total_size == other.total_size && self.frag_size == other.frag_size && + self.last_idx == other.last_idx && self.frags == other.frags + } } /// < fragment mbuf #[repr(C)] @@ -201,5 +313,7 @@ pub struct rte_mbuf { pub _address: u8, } impl Clone for rte_mbuf { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } diff --git a/tests/expectations/tests/opaque-template-inst-member.rs b/tests/expectations/tests/opaque-template-inst-member.rs index 0bef4c86b9..f686150c9f 100644 --- a/tests/expectations/tests/opaque-template-inst-member.rs +++ b/tests/expectations/tests/opaque-template-inst-member.rs @@ -6,10 +6,9 @@ #[repr(C)] #[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] -pub struct OpaqueTemplate { -} -/// This should not end up deriving Debug/Hash/PartialEq because its `mBlah` field cannot derive -/// Debug/Hash/PartialEq because the instantiation's definition cannot derive Debug/Hash/PartialEq. +pub struct OpaqueTemplate {} +/// This should not end up deriving Debug/Hash because its `mBlah` field cannot derive +/// Debug/Hash because the instantiation's definition cannot derive Debug/Hash. #[repr(C)] pub struct ContainsOpaqueTemplate { pub mBlah: [u32; 101usize], @@ -17,27 +16,48 @@ pub struct ContainsOpaqueTemplate { } #[test] fn bindgen_test_layout_ContainsOpaqueTemplate() { - assert_eq!(::std::mem::size_of::() , 408usize , - concat ! ( "Size of: " , stringify ! ( ContainsOpaqueTemplate ) - )); - assert_eq! (::std::mem::align_of::() , 4usize , - concat ! ( - "Alignment of " , stringify ! ( ContainsOpaqueTemplate ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ContainsOpaqueTemplate ) ) . mBlah as * - const _ as usize } , 0usize , concat ! ( - "Alignment of field: " , stringify ! ( ContainsOpaqueTemplate - ) , "::" , stringify ! ( mBlah ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const ContainsOpaqueTemplate ) ) . mBaz as * - const _ as usize } , 404usize , concat ! ( - "Alignment of field: " , stringify ! ( ContainsOpaqueTemplate - ) , "::" , stringify ! ( mBaz ) )); + assert_eq!( + ::std::mem::size_of::(), + 408usize, + concat!("Size of: ", stringify!(ContainsOpaqueTemplate)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(ContainsOpaqueTemplate)) + ); + assert_eq!( + unsafe { &(*(0 as *const ContainsOpaqueTemplate)).mBlah as *const _ as usize }, + 0usize, + concat!( + "Alignment of field: ", + stringify!(ContainsOpaqueTemplate), + "::", + stringify!(mBlah) + ) + ); + assert_eq!( + unsafe { &(*(0 as *const ContainsOpaqueTemplate)).mBaz as *const _ as usize }, + 404usize, + concat!( + "Alignment of field: ", + stringify!(ContainsOpaqueTemplate), + "::", + stringify!(mBaz) + ) + ); } impl Default for ContainsOpaqueTemplate { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +impl ::std::cmp::PartialEq for ContainsOpaqueTemplate { + fn eq(&self, other: &ContainsOpaqueTemplate) -> bool { + &self.mBlah[..] == &other.mBlah[..] && self.mBaz == other.mBaz + } } -/// This shold not end up deriving Debug/Hash/PartialEq either, for similar reasons, although +/// This should not end up deriving Debug/Hash either, for similar reasons, although /// we're exercising base member edges now. #[repr(C)] pub struct InheritsOpaqueTemplate { @@ -46,18 +66,34 @@ pub struct InheritsOpaqueTemplate { } #[test] fn bindgen_test_layout_InheritsOpaqueTemplate() { - assert_eq!(::std::mem::size_of::() , 416usize , - concat ! ( "Size of: " , stringify ! ( InheritsOpaqueTemplate ) - )); - assert_eq! (::std::mem::align_of::() , 8usize , - concat ! ( - "Alignment of " , stringify ! ( InheritsOpaqueTemplate ) )); - assert_eq! (unsafe { - & ( * ( 0 as * const InheritsOpaqueTemplate ) ) . wow as * - const _ as usize } , 408usize , concat ! ( - "Alignment of field: " , stringify ! ( InheritsOpaqueTemplate - ) , "::" , stringify ! ( wow ) )); + assert_eq!( + ::std::mem::size_of::(), + 416usize, + concat!("Size of: ", stringify!(InheritsOpaqueTemplate)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(InheritsOpaqueTemplate)) + ); + assert_eq!( + unsafe { &(*(0 as *const InheritsOpaqueTemplate)).wow as *const _ as usize }, + 408usize, + concat!( + "Alignment of field: ", + stringify!(InheritsOpaqueTemplate), + "::", + stringify!(wow) + ) + ); } impl Default for InheritsOpaqueTemplate { - fn default() -> Self { unsafe { ::std::mem::zeroed() } } + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +impl ::std::cmp::PartialEq for InheritsOpaqueTemplate { + fn eq(&self, other: &InheritsOpaqueTemplate) -> bool { + &self._base[..] == &other._base[..] && self.wow == other.wow + } } diff --git a/tests/headers/class_1_0.hpp b/tests/headers/class_1_0.hpp index ee00c2b7fd..6fa01e95f9 100644 --- a/tests/headers/class_1_0.hpp +++ b/tests/headers/class_1_0.hpp @@ -1,4 +1,4 @@ -// bindgen-flags: --rust-target 1.0 --with-derive-hash --with-derive-partialeq --with-derive-eq +// bindgen-flags: --rust-target 1.0 --with-derive-hash --with-derive-partialeq --impl-partialeq --with-derive-eq class C { int a; diff --git a/tests/headers/derive-partialeq-anonfield.h b/tests/headers/derive-partialeq-anonfield.h new file mode 100644 index 0000000000..3bbe2bc331 --- /dev/null +++ b/tests/headers/derive-partialeq-anonfield.h @@ -0,0 +1,5 @@ +// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --impl-partialeq + +struct rte_mbuf { + union {}; +} __attribute__((__aligned__(64))); diff --git a/tests/headers/derive-partialeq-base.hpp b/tests/headers/derive-partialeq-base.hpp new file mode 100644 index 0000000000..989cbe693a --- /dev/null +++ b/tests/headers/derive-partialeq-base.hpp @@ -0,0 +1,8 @@ +// bindgen-flags: --with-derive-partialeq --impl-partialeq + +class Base { + int large[33]; +}; + +class ShouldDerivePartialEq: Base { +}; diff --git a/tests/headers/derive-partialeq-bitfield.hpp b/tests/headers/derive-partialeq-bitfield.hpp new file mode 100644 index 0000000000..ac2cac632a --- /dev/null +++ b/tests/headers/derive-partialeq-bitfield.hpp @@ -0,0 +1,7 @@ +// bindgen-flags: --with-derive-partialeq --impl-partialeq + +class C { + bool a: 1; + bool b: 7; + int large_array[50]; +}; diff --git a/tests/headers/derive-partialeq-core.h b/tests/headers/derive-partialeq-core.h new file mode 100644 index 0000000000..6da5b786bc --- /dev/null +++ b/tests/headers/derive-partialeq-core.h @@ -0,0 +1,5 @@ +// bindgen-flags: --with-derive-partialeq --impl-partialeq --use-core --raw-line "extern crate core;" + +struct C { + int large_array[420]; +}; diff --git a/tests/headers/derive-partialeq-pointer.hpp b/tests/headers/derive-partialeq-pointer.hpp new file mode 100644 index 0000000000..ce971e075b --- /dev/null +++ b/tests/headers/derive-partialeq-pointer.hpp @@ -0,0 +1,12 @@ +// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq + +struct a; +class Bar { + a *b; +}; +struct c { + union {}; +}; +struct a { + c d; +}; diff --git a/tests/headers/derive-partialeq-union.hpp b/tests/headers/derive-partialeq-union.hpp new file mode 100644 index 0000000000..e2081a013a --- /dev/null +++ b/tests/headers/derive-partialeq-union.hpp @@ -0,0 +1,7 @@ +// bindgen-flags: --with-derive-partialeq --impl-partialeq + +/// Deriving PartialEq for rust unions is not supported. +union ShouldNotDerivePartialEq { + char a; + int b; +}; diff --git a/tests/headers/derive-partialeq-union_1_0.hpp b/tests/headers/derive-partialeq-union_1_0.hpp new file mode 100644 index 0000000000..d546d77b10 --- /dev/null +++ b/tests/headers/derive-partialeq-union_1_0.hpp @@ -0,0 +1,7 @@ +// bindgen-flags: --rust-target 1.0 --with-derive-partialeq --impl-partialeq + +/// This should manually derive PartialEq. +union ShouldDerivePartialEq { + char a[150]; + int b; +}; diff --git a/tests/headers/issue-648-derive-debug-with-padding.h b/tests/headers/issue-648-derive-debug-with-padding.h index c9ec021043..f528c10011 100644 --- a/tests/headers/issue-648-derive-debug-with-padding.h +++ b/tests/headers/issue-648-derive-debug-with-padding.h @@ -1,4 +1,4 @@ -// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq +// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --impl-partialeq /** * We emit a `[u8; 63usize]` padding field for this struct, which cannot derive * Debug/Hash because 63 is over the hard coded limit. (Yes, this struct doesn't end diff --git a/tests/headers/layout_array.h b/tests/headers/layout_array.h index 6a20f7c3c5..239e52b193 100644 --- a/tests/headers/layout_array.h +++ b/tests/headers/layout_array.h @@ -1,4 +1,4 @@ -// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq +// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --impl-partialeq typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; diff --git a/tests/headers/layout_array_too_long.h b/tests/headers/layout_array_too_long.h index a3ef3d2056..1d8b1b63e7 100644 --- a/tests/headers/layout_array_too_long.h +++ b/tests/headers/layout_array_too_long.h @@ -1,4 +1,4 @@ -// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --rustified-enum .* +// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --impl-partialeq --rustified-enum .* typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; diff --git a/tests/headers/opaque-template-inst-member.hpp b/tests/headers/opaque-template-inst-member.hpp index 4cb3dd72fd..6516aa564d 100644 --- a/tests/headers/opaque-template-inst-member.hpp +++ b/tests/headers/opaque-template-inst-member.hpp @@ -1,4 +1,4 @@ -// bindgen-flags: --opaque-type 'OpaqueTemplate' --with-derive-hash --with-derive-partialeq --with-derive-eq +// bindgen-flags: --opaque-type 'OpaqueTemplate' --with-derive-hash --with-derive-partialeq --impl-partialeq --with-derive-eq template class OpaqueTemplate { @@ -6,14 +6,14 @@ class OpaqueTemplate { bool mCannotDebug[400]; }; -/// This should not end up deriving Debug/Hash/PartialEq because its `mBlah` field cannot derive -/// Debug/Hash/PartialEq because the instantiation's definition cannot derive Debug/Hash/PartialEq. +/// This should not end up deriving Debug/Hash because its `mBlah` field cannot derive +/// Debug/Hash because the instantiation's definition cannot derive Debug/Hash. class ContainsOpaqueTemplate { OpaqueTemplate mBlah; int mBaz; }; -/// This shold not end up deriving Debug/Hash/PartialEq either, for similar reasons, although +/// This should not end up deriving Debug/Hash either, for similar reasons, although /// we're exercising base member edges now. class InheritsOpaqueTemplate : public OpaqueTemplate { char* wow;