Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
732
third-party/vendor/bindgen/ir/analysis/derive.rs
vendored
Normal file
732
third-party/vendor/bindgen/ir/analysis/derive.rs
vendored
Normal file
|
|
@ -0,0 +1,732 @@
|
|||
//! Determining which types for which we cannot emit `#[derive(Trait)]`.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
|
||||
use crate::ir::analysis::has_vtable::HasVtable;
|
||||
use crate::ir::comp::CompKind;
|
||||
use crate::ir::context::{BindgenContext, ItemId};
|
||||
use crate::ir::derive::CanDerive;
|
||||
use crate::ir::function::FunctionSig;
|
||||
use crate::ir::item::{IsOpaque, Item};
|
||||
use crate::ir::layout::Layout;
|
||||
use crate::ir::template::TemplateParameters;
|
||||
use crate::ir::traversal::{EdgeKind, Trace};
|
||||
use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
|
||||
use crate::ir::ty::{Type, TypeKind};
|
||||
use crate::{Entry, HashMap, HashSet};
|
||||
|
||||
/// Which trait to consider when doing the `CannotDerive` analysis.
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub enum DeriveTrait {
|
||||
/// The `Copy` trait.
|
||||
Copy,
|
||||
/// The `Debug` trait.
|
||||
Debug,
|
||||
/// The `Default` trait.
|
||||
Default,
|
||||
/// The `Hash` trait.
|
||||
Hash,
|
||||
/// The `PartialEq` and `PartialOrd` traits.
|
||||
PartialEqOrPartialOrd,
|
||||
}
|
||||
|
||||
/// An analysis that finds for each IR item whether a trait cannot be derived.
|
||||
///
|
||||
/// We use the monotone constraint function `cannot_derive`, defined as follows
|
||||
/// for type T:
|
||||
///
|
||||
/// * If T is Opaque and the layout of the type is known, get this layout as an
|
||||
/// opaquetype and check whether it can derive using trivial checks.
|
||||
///
|
||||
/// * If T is Array, a trait cannot be derived if the array is incomplete,
|
||||
/// if the length of the array is larger than the limit (unless the trait
|
||||
/// allows it), or the trait cannot be derived for the type of data the array
|
||||
/// contains.
|
||||
///
|
||||
/// * If T is Vector, a trait cannot be derived if the trait cannot be derived
|
||||
/// for the type of data the vector contains.
|
||||
///
|
||||
/// * If T is a type alias, a templated alias or an indirection to another type,
|
||||
/// the trait cannot be derived if the trait cannot be derived for type T
|
||||
/// refers to.
|
||||
///
|
||||
/// * If T is a compound type, the trait cannot be derived if the trait cannot
|
||||
/// be derived for any of its base members or fields.
|
||||
///
|
||||
/// * If T is an instantiation of an abstract template definition, the trait
|
||||
/// cannot be derived if any of the template arguments or template definition
|
||||
/// cannot derive the trait.
|
||||
///
|
||||
/// * For all other (simple) types, compiler and standard library limitations
|
||||
/// dictate whether the trait is implemented.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CannotDerive<'ctx> {
|
||||
ctx: &'ctx BindgenContext,
|
||||
|
||||
derive_trait: DeriveTrait,
|
||||
|
||||
// The incremental result of this analysis's computation.
|
||||
// Contains information whether particular item can derive `derive_trait`
|
||||
can_derive: HashMap<ItemId, CanDerive>,
|
||||
|
||||
// Dependencies saying that if a key ItemId has been inserted into the
|
||||
// `cannot_derive_partialeq_or_partialord` set, then each of the ids
|
||||
// in Vec<ItemId> need to be considered again.
|
||||
//
|
||||
// This is a subset of the natural IR graph with reversed edges, where we
|
||||
// only include the edges from the IR graph that can affect whether a type
|
||||
// can derive `derive_trait`.
|
||||
dependencies: HashMap<ItemId, Vec<ItemId>>,
|
||||
}
|
||||
|
||||
type EdgePredicate = fn(EdgeKind) -> bool;
|
||||
|
||||
fn consider_edge_default(kind: EdgeKind) -> bool {
|
||||
match kind {
|
||||
// These are the only edges that can affect whether a type can derive
|
||||
EdgeKind::BaseMember |
|
||||
EdgeKind::Field |
|
||||
EdgeKind::TypeReference |
|
||||
EdgeKind::VarType |
|
||||
EdgeKind::TemplateArgument |
|
||||
EdgeKind::TemplateDeclaration |
|
||||
EdgeKind::TemplateParameterDefinition => true,
|
||||
|
||||
EdgeKind::Constructor |
|
||||
EdgeKind::Destructor |
|
||||
EdgeKind::FunctionReturn |
|
||||
EdgeKind::FunctionParameter |
|
||||
EdgeKind::InnerType |
|
||||
EdgeKind::InnerVar |
|
||||
EdgeKind::Method |
|
||||
EdgeKind::Generic => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> CannotDerive<'ctx> {
|
||||
fn insert<Id: Into<ItemId>>(
|
||||
&mut self,
|
||||
id: Id,
|
||||
can_derive: CanDerive,
|
||||
) -> ConstrainResult {
|
||||
let id = id.into();
|
||||
trace!(
|
||||
"inserting {:?} can_derive<{}>={:?}",
|
||||
id,
|
||||
self.derive_trait,
|
||||
can_derive
|
||||
);
|
||||
|
||||
if let CanDerive::Yes = can_derive {
|
||||
return ConstrainResult::Same;
|
||||
}
|
||||
|
||||
match self.can_derive.entry(id) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
if *entry.get() < can_derive {
|
||||
entry.insert(can_derive);
|
||||
ConstrainResult::Changed
|
||||
} else {
|
||||
ConstrainResult::Same
|
||||
}
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(can_derive);
|
||||
ConstrainResult::Changed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn constrain_type(&mut self, item: &Item, ty: &Type) -> CanDerive {
|
||||
if !self.ctx.allowlisted_items().contains(&item.id()) {
|
||||
let can_derive = self
|
||||
.ctx
|
||||
.blocklisted_type_implements_trait(item, self.derive_trait);
|
||||
match can_derive {
|
||||
CanDerive::Yes => trace!(
|
||||
" blocklisted type explicitly implements {}",
|
||||
self.derive_trait
|
||||
),
|
||||
CanDerive::Manually => trace!(
|
||||
" blocklisted type requires manual implementation of {}",
|
||||
self.derive_trait
|
||||
),
|
||||
CanDerive::No => trace!(
|
||||
" cannot derive {} for blocklisted type",
|
||||
self.derive_trait
|
||||
),
|
||||
}
|
||||
return can_derive;
|
||||
}
|
||||
|
||||
if self.derive_trait.not_by_name(self.ctx, item) {
|
||||
trace!(
|
||||
" cannot derive {} for explicitly excluded type",
|
||||
self.derive_trait
|
||||
);
|
||||
return CanDerive::No;
|
||||
}
|
||||
|
||||
trace!("ty: {:?}", ty);
|
||||
if item.is_opaque(self.ctx, &()) {
|
||||
if !self.derive_trait.can_derive_union() &&
|
||||
ty.is_union() &&
|
||||
self.ctx.options().rust_features().untagged_union
|
||||
{
|
||||
trace!(
|
||||
" cannot derive {} for Rust unions",
|
||||
self.derive_trait
|
||||
);
|
||||
return CanDerive::No;
|
||||
}
|
||||
|
||||
let layout_can_derive =
|
||||
ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
|
||||
l.opaque().array_size_within_derive_limit(self.ctx)
|
||||
});
|
||||
|
||||
match layout_can_derive {
|
||||
CanDerive::Yes => {
|
||||
trace!(
|
||||
" we can trivially derive {} for the layout",
|
||||
self.derive_trait
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
trace!(
|
||||
" we cannot derive {} for the layout",
|
||||
self.derive_trait
|
||||
);
|
||||
}
|
||||
};
|
||||
return layout_can_derive;
|
||||
}
|
||||
|
||||
match *ty.kind() {
|
||||
// Handle the simple cases. These can derive traits without further
|
||||
// information.
|
||||
TypeKind::Void |
|
||||
TypeKind::NullPtr |
|
||||
TypeKind::Int(..) |
|
||||
TypeKind::Complex(..) |
|
||||
TypeKind::Float(..) |
|
||||
TypeKind::Enum(..) |
|
||||
TypeKind::TypeParam |
|
||||
TypeKind::UnresolvedTypeRef(..) |
|
||||
TypeKind::Reference(..) |
|
||||
TypeKind::ObjCInterface(..) |
|
||||
TypeKind::ObjCId |
|
||||
TypeKind::ObjCSel => {
|
||||
return self.derive_trait.can_derive_simple(ty.kind());
|
||||
}
|
||||
TypeKind::Pointer(inner) => {
|
||||
let inner_type =
|
||||
self.ctx.resolve_type(inner).canonical_type(self.ctx);
|
||||
if let TypeKind::Function(ref sig) = *inner_type.kind() {
|
||||
self.derive_trait.can_derive_fnptr(sig)
|
||||
} else {
|
||||
self.derive_trait.can_derive_pointer()
|
||||
}
|
||||
}
|
||||
TypeKind::Function(ref sig) => {
|
||||
self.derive_trait.can_derive_fnptr(sig)
|
||||
}
|
||||
|
||||
// Complex cases need more information
|
||||
TypeKind::Array(t, len) => {
|
||||
let inner_type =
|
||||
self.can_derive.get(&t.into()).cloned().unwrap_or_default();
|
||||
if inner_type != CanDerive::Yes {
|
||||
trace!(
|
||||
" arrays of T for which we cannot derive {} \
|
||||
also cannot derive {}",
|
||||
self.derive_trait,
|
||||
self.derive_trait
|
||||
);
|
||||
return CanDerive::No;
|
||||
}
|
||||
|
||||
if len == 0 && !self.derive_trait.can_derive_incomplete_array()
|
||||
{
|
||||
trace!(
|
||||
" cannot derive {} for incomplete arrays",
|
||||
self.derive_trait
|
||||
);
|
||||
return CanDerive::No;
|
||||
}
|
||||
|
||||
if self.derive_trait.can_derive_large_array(self.ctx) {
|
||||
trace!(" array can derive {}", self.derive_trait);
|
||||
return CanDerive::Yes;
|
||||
}
|
||||
|
||||
if len > RUST_DERIVE_IN_ARRAY_LIMIT {
|
||||
trace!(
|
||||
" array is too large to derive {}, but it may be implemented", self.derive_trait
|
||||
);
|
||||
return CanDerive::Manually;
|
||||
}
|
||||
trace!(
|
||||
" array is small enough to derive {}",
|
||||
self.derive_trait
|
||||
);
|
||||
CanDerive::Yes
|
||||
}
|
||||
TypeKind::Vector(t, len) => {
|
||||
let inner_type =
|
||||
self.can_derive.get(&t.into()).cloned().unwrap_or_default();
|
||||
if inner_type != CanDerive::Yes {
|
||||
trace!(
|
||||
" vectors of T for which we cannot derive {} \
|
||||
also cannot derive {}",
|
||||
self.derive_trait,
|
||||
self.derive_trait
|
||||
);
|
||||
return CanDerive::No;
|
||||
}
|
||||
assert_ne!(len, 0, "vectors cannot have zero length");
|
||||
self.derive_trait.can_derive_vector()
|
||||
}
|
||||
|
||||
TypeKind::Comp(ref info) => {
|
||||
assert!(
|
||||
!info.has_non_type_template_params(),
|
||||
"The early ty.is_opaque check should have handled this case"
|
||||
);
|
||||
|
||||
if !self.derive_trait.can_derive_compound_forward_decl() &&
|
||||
info.is_forward_declaration()
|
||||
{
|
||||
trace!(
|
||||
" cannot derive {} for forward decls",
|
||||
self.derive_trait
|
||||
);
|
||||
return CanDerive::No;
|
||||
}
|
||||
|
||||
// NOTE: Take into account that while unions in C and C++ are copied by
|
||||
// default, the may have an explicit destructor in C++, so we can't
|
||||
// defer this check just for the union case.
|
||||
if !self.derive_trait.can_derive_compound_with_destructor() &&
|
||||
self.ctx.lookup_has_destructor(
|
||||
item.id().expect_type_id(self.ctx),
|
||||
)
|
||||
{
|
||||
trace!(
|
||||
" comp has destructor which cannot derive {}",
|
||||
self.derive_trait
|
||||
);
|
||||
return CanDerive::No;
|
||||
}
|
||||
|
||||
if info.kind() == CompKind::Union {
|
||||
if self.derive_trait.can_derive_union() {
|
||||
if self.ctx.options().rust_features().untagged_union &&
|
||||
// https://github.com/rust-lang/rust/issues/36640
|
||||
(!info.self_template_params(self.ctx).is_empty() ||
|
||||
!item.all_template_params(self.ctx).is_empty())
|
||||
{
|
||||
trace!(
|
||||
" cannot derive {} for Rust union because issue 36640", self.derive_trait
|
||||
);
|
||||
return CanDerive::No;
|
||||
}
|
||||
// fall through to be same as non-union handling
|
||||
} else {
|
||||
if self.ctx.options().rust_features().untagged_union {
|
||||
trace!(
|
||||
" cannot derive {} for Rust unions",
|
||||
self.derive_trait
|
||||
);
|
||||
return CanDerive::No;
|
||||
}
|
||||
|
||||
let layout_can_derive =
|
||||
ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
|
||||
l.opaque()
|
||||
.array_size_within_derive_limit(self.ctx)
|
||||
});
|
||||
match layout_can_derive {
|
||||
CanDerive::Yes => {
|
||||
trace!(
|
||||
" union layout can trivially derive {}",
|
||||
self.derive_trait
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
trace!(
|
||||
" union layout cannot derive {}",
|
||||
self.derive_trait
|
||||
);
|
||||
}
|
||||
};
|
||||
return layout_can_derive;
|
||||
}
|
||||
}
|
||||
|
||||
if !self.derive_trait.can_derive_compound_with_vtable() &&
|
||||
item.has_vtable(self.ctx)
|
||||
{
|
||||
trace!(
|
||||
" cannot derive {} for comp with vtable",
|
||||
self.derive_trait
|
||||
);
|
||||
return CanDerive::No;
|
||||
}
|
||||
|
||||
// Bitfield units are always represented as arrays of u8, but
|
||||
// they're not traced as arrays, so we need to check here
|
||||
// instead.
|
||||
if !self.derive_trait.can_derive_large_array(self.ctx) &&
|
||||
info.has_too_large_bitfield_unit() &&
|
||||
!item.is_opaque(self.ctx, &())
|
||||
{
|
||||
trace!(
|
||||
" cannot derive {} for comp with too large bitfield unit",
|
||||
self.derive_trait
|
||||
);
|
||||
return CanDerive::No;
|
||||
}
|
||||
|
||||
let pred = self.derive_trait.consider_edge_comp();
|
||||
self.constrain_join(item, pred)
|
||||
}
|
||||
|
||||
TypeKind::ResolvedTypeRef(..) |
|
||||
TypeKind::TemplateAlias(..) |
|
||||
TypeKind::Alias(..) |
|
||||
TypeKind::BlockPointer(..) => {
|
||||
let pred = self.derive_trait.consider_edge_typeref();
|
||||
self.constrain_join(item, pred)
|
||||
}
|
||||
|
||||
TypeKind::TemplateInstantiation(..) => {
|
||||
let pred = self.derive_trait.consider_edge_tmpl_inst();
|
||||
self.constrain_join(item, pred)
|
||||
}
|
||||
|
||||
TypeKind::Opaque => unreachable!(
|
||||
"The early ty.is_opaque check should have handled this case"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn constrain_join(
|
||||
&mut self,
|
||||
item: &Item,
|
||||
consider_edge: EdgePredicate,
|
||||
) -> CanDerive {
|
||||
let mut candidate = None;
|
||||
|
||||
item.trace(
|
||||
self.ctx,
|
||||
&mut |sub_id, edge_kind| {
|
||||
// Ignore ourselves, since union with ourself is a
|
||||
// no-op. Ignore edges that aren't relevant to the
|
||||
// analysis.
|
||||
if sub_id == item.id() || !consider_edge(edge_kind) {
|
||||
return;
|
||||
}
|
||||
|
||||
let can_derive = self.can_derive
|
||||
.get(&sub_id)
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
|
||||
match can_derive {
|
||||
CanDerive::Yes => trace!(" member {:?} can derive {}", sub_id, self.derive_trait),
|
||||
CanDerive::Manually => trace!(" member {:?} cannot derive {}, but it may be implemented", sub_id, self.derive_trait),
|
||||
CanDerive::No => trace!(" member {:?} cannot derive {}", sub_id, self.derive_trait),
|
||||
}
|
||||
|
||||
*candidate.get_or_insert(CanDerive::Yes) |= can_derive;
|
||||
},
|
||||
&(),
|
||||
);
|
||||
|
||||
if candidate.is_none() {
|
||||
trace!(
|
||||
" can derive {} because there are no members",
|
||||
self.derive_trait
|
||||
);
|
||||
}
|
||||
candidate.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl DeriveTrait {
|
||||
fn not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool {
|
||||
match self {
|
||||
DeriveTrait::Copy => ctx.no_copy_by_name(item),
|
||||
DeriveTrait::Debug => ctx.no_debug_by_name(item),
|
||||
DeriveTrait::Default => ctx.no_default_by_name(item),
|
||||
DeriveTrait::Hash => ctx.no_hash_by_name(item),
|
||||
DeriveTrait::PartialEqOrPartialOrd => {
|
||||
ctx.no_partialeq_by_name(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn consider_edge_comp(&self) -> EdgePredicate {
|
||||
match self {
|
||||
DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
|
||||
_ => |kind| matches!(kind, EdgeKind::BaseMember | EdgeKind::Field),
|
||||
}
|
||||
}
|
||||
|
||||
fn consider_edge_typeref(&self) -> EdgePredicate {
|
||||
match self {
|
||||
DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
|
||||
_ => |kind| kind == EdgeKind::TypeReference,
|
||||
}
|
||||
}
|
||||
|
||||
fn consider_edge_tmpl_inst(&self) -> EdgePredicate {
|
||||
match self {
|
||||
DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
|
||||
_ => |kind| {
|
||||
matches!(
|
||||
kind,
|
||||
EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn can_derive_large_array(&self, ctx: &BindgenContext) -> bool {
|
||||
if ctx.options().rust_features().larger_arrays {
|
||||
!matches!(self, DeriveTrait::Default)
|
||||
} else {
|
||||
matches!(self, DeriveTrait::Copy)
|
||||
}
|
||||
}
|
||||
|
||||
fn can_derive_union(&self) -> bool {
|
||||
matches!(self, DeriveTrait::Copy)
|
||||
}
|
||||
|
||||
fn can_derive_compound_with_destructor(&self) -> bool {
|
||||
!matches!(self, DeriveTrait::Copy)
|
||||
}
|
||||
|
||||
fn can_derive_compound_with_vtable(&self) -> bool {
|
||||
!matches!(self, DeriveTrait::Default)
|
||||
}
|
||||
|
||||
fn can_derive_compound_forward_decl(&self) -> bool {
|
||||
matches!(self, DeriveTrait::Copy | DeriveTrait::Debug)
|
||||
}
|
||||
|
||||
fn can_derive_incomplete_array(&self) -> bool {
|
||||
!matches!(
|
||||
self,
|
||||
DeriveTrait::Copy |
|
||||
DeriveTrait::Hash |
|
||||
DeriveTrait::PartialEqOrPartialOrd
|
||||
)
|
||||
}
|
||||
|
||||
fn can_derive_fnptr(&self, f: &FunctionSig) -> CanDerive {
|
||||
match (self, f.function_pointers_can_derive()) {
|
||||
(DeriveTrait::Copy, _) | (DeriveTrait::Default, _) | (_, true) => {
|
||||
trace!(" function pointer can derive {}", self);
|
||||
CanDerive::Yes
|
||||
}
|
||||
(DeriveTrait::Debug, false) => {
|
||||
trace!(" function pointer cannot derive {}, but it may be implemented", self);
|
||||
CanDerive::Manually
|
||||
}
|
||||
(_, false) => {
|
||||
trace!(" function pointer cannot derive {}", self);
|
||||
CanDerive::No
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn can_derive_vector(&self) -> CanDerive {
|
||||
match self {
|
||||
DeriveTrait::PartialEqOrPartialOrd => {
|
||||
// FIXME: vectors always can derive PartialEq, but they should
|
||||
// not derive PartialOrd:
|
||||
// https://github.com/rust-lang-nursery/packed_simd/issues/48
|
||||
trace!(" vectors cannot derive PartialOrd");
|
||||
CanDerive::No
|
||||
}
|
||||
_ => {
|
||||
trace!(" vector can derive {}", self);
|
||||
CanDerive::Yes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn can_derive_pointer(&self) -> CanDerive {
|
||||
match self {
|
||||
DeriveTrait::Default => {
|
||||
trace!(" pointer cannot derive Default");
|
||||
CanDerive::No
|
||||
}
|
||||
_ => {
|
||||
trace!(" pointer can derive {}", self);
|
||||
CanDerive::Yes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn can_derive_simple(&self, kind: &TypeKind) -> CanDerive {
|
||||
match (self, kind) {
|
||||
// === Default ===
|
||||
(DeriveTrait::Default, TypeKind::Void) |
|
||||
(DeriveTrait::Default, TypeKind::NullPtr) |
|
||||
(DeriveTrait::Default, TypeKind::Enum(..)) |
|
||||
(DeriveTrait::Default, TypeKind::Reference(..)) |
|
||||
(DeriveTrait::Default, TypeKind::TypeParam) |
|
||||
(DeriveTrait::Default, TypeKind::ObjCInterface(..)) |
|
||||
(DeriveTrait::Default, TypeKind::ObjCId) |
|
||||
(DeriveTrait::Default, TypeKind::ObjCSel) => {
|
||||
trace!(" types that always cannot derive Default");
|
||||
CanDerive::No
|
||||
}
|
||||
(DeriveTrait::Default, TypeKind::UnresolvedTypeRef(..)) => {
|
||||
unreachable!(
|
||||
"Type with unresolved type ref can't reach derive default"
|
||||
)
|
||||
}
|
||||
// === Hash ===
|
||||
(DeriveTrait::Hash, TypeKind::Float(..)) |
|
||||
(DeriveTrait::Hash, TypeKind::Complex(..)) => {
|
||||
trace!(" float cannot derive Hash");
|
||||
CanDerive::No
|
||||
}
|
||||
// === others ===
|
||||
_ => {
|
||||
trace!(" simple type that can always derive {}", self);
|
||||
CanDerive::Yes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DeriveTrait {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let s = match self {
|
||||
DeriveTrait::Copy => "Copy",
|
||||
DeriveTrait::Debug => "Debug",
|
||||
DeriveTrait::Default => "Default",
|
||||
DeriveTrait::Hash => "Hash",
|
||||
DeriveTrait::PartialEqOrPartialOrd => "PartialEq/PartialOrd",
|
||||
};
|
||||
s.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> MonotoneFramework for CannotDerive<'ctx> {
|
||||
type Node = ItemId;
|
||||
type Extra = (&'ctx BindgenContext, DeriveTrait);
|
||||
type Output = HashMap<ItemId, CanDerive>;
|
||||
|
||||
fn new(
|
||||
(ctx, derive_trait): (&'ctx BindgenContext, DeriveTrait),
|
||||
) -> CannotDerive<'ctx> {
|
||||
let can_derive = HashMap::default();
|
||||
let dependencies = generate_dependencies(ctx, consider_edge_default);
|
||||
|
||||
CannotDerive {
|
||||
ctx,
|
||||
derive_trait,
|
||||
can_derive,
|
||||
dependencies,
|
||||
}
|
||||
}
|
||||
|
||||
fn initial_worklist(&self) -> Vec<ItemId> {
|
||||
// The transitive closure of all allowlisted items, including explicitly
|
||||
// blocklisted items.
|
||||
self.ctx
|
||||
.allowlisted_items()
|
||||
.iter()
|
||||
.cloned()
|
||||
.flat_map(|i| {
|
||||
let mut reachable = vec![i];
|
||||
i.trace(
|
||||
self.ctx,
|
||||
&mut |s, _| {
|
||||
reachable.push(s);
|
||||
},
|
||||
&(),
|
||||
);
|
||||
reachable
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn constrain(&mut self, id: ItemId) -> ConstrainResult {
|
||||
trace!("constrain: {:?}", id);
|
||||
|
||||
if let Some(CanDerive::No) = self.can_derive.get(&id).cloned() {
|
||||
trace!(" already know it cannot derive {}", self.derive_trait);
|
||||
return ConstrainResult::Same;
|
||||
}
|
||||
|
||||
let item = self.ctx.resolve_item(id);
|
||||
let can_derive = match item.as_type() {
|
||||
Some(ty) => {
|
||||
let mut can_derive = self.constrain_type(item, ty);
|
||||
if let CanDerive::Yes = can_derive {
|
||||
let is_reached_limit =
|
||||
|l: Layout| l.align > RUST_DERIVE_IN_ARRAY_LIMIT;
|
||||
if !self.derive_trait.can_derive_large_array(self.ctx) &&
|
||||
ty.layout(self.ctx).map_or(false, is_reached_limit)
|
||||
{
|
||||
// We have to be conservative: the struct *could* have enough
|
||||
// padding that we emit an array that is longer than
|
||||
// `RUST_DERIVE_IN_ARRAY_LIMIT`. If we moved padding calculations
|
||||
// into the IR and computed them before this analysis, then we could
|
||||
// be precise rather than conservative here.
|
||||
can_derive = CanDerive::Manually;
|
||||
}
|
||||
}
|
||||
can_derive
|
||||
}
|
||||
None => self.constrain_join(item, consider_edge_default),
|
||||
};
|
||||
|
||||
self.insert(id, can_derive)
|
||||
}
|
||||
|
||||
fn each_depending_on<F>(&self, id: ItemId, mut f: F)
|
||||
where
|
||||
F: FnMut(ItemId),
|
||||
{
|
||||
if let Some(edges) = self.dependencies.get(&id) {
|
||||
for item in edges {
|
||||
trace!("enqueue {:?} into worklist", item);
|
||||
f(*item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> From<CannotDerive<'ctx>> for HashMap<ItemId, CanDerive> {
|
||||
fn from(analysis: CannotDerive<'ctx>) -> Self {
|
||||
extra_assert!(analysis
|
||||
.can_derive
|
||||
.values()
|
||||
.all(|v| *v != CanDerive::Yes));
|
||||
|
||||
analysis.can_derive
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a `HashMap<ItemId, CanDerive>` into a `HashSet<ItemId>`.
|
||||
///
|
||||
/// Elements that are not `CanDerive::Yes` are kept in the set, so that it
|
||||
/// represents all items that cannot derive.
|
||||
pub fn as_cannot_derive_set(
|
||||
can_derive: HashMap<ItemId, CanDerive>,
|
||||
) -> HashSet<ItemId> {
|
||||
can_derive
|
||||
.into_iter()
|
||||
.filter_map(|(k, v)| if v != CanDerive::Yes { Some(k) } else { None })
|
||||
.collect()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue