• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Determining which types for which we cannot emit `#[derive(Trait)]`.
2 
3 use std::fmt;
4 
5 use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
6 use crate::ir::analysis::has_vtable::HasVtable;
7 use crate::ir::comp::CompKind;
8 use crate::ir::context::{BindgenContext, ItemId};
9 use crate::ir::derive::CanDerive;
10 use crate::ir::function::FunctionSig;
11 use crate::ir::item::{IsOpaque, Item};
12 use crate::ir::template::TemplateParameters;
13 use crate::ir::traversal::{EdgeKind, Trace};
14 use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
15 use crate::ir::ty::{Type, TypeKind};
16 use crate::{Entry, HashMap, HashSet};
17 
18 /// Which trait to consider when doing the `CannotDerive` analysis.
19 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
20 pub enum DeriveTrait {
21     /// The `Copy` trait.
22     Copy,
23     /// The `Debug` trait.
24     Debug,
25     /// The `Default` trait.
26     Default,
27     /// The `Hash` trait.
28     Hash,
29     /// The `PartialEq` and `PartialOrd` traits.
30     PartialEqOrPartialOrd,
31 }
32 
33 /// An analysis that finds for each IR item whether a trait cannot be derived.
34 ///
35 /// We use the monotone constraint function `cannot_derive`, defined as follows
36 /// for type T:
37 ///
38 /// * If T is Opaque and the layout of the type is known, get this layout as an
39 ///   opaquetype and check whether it can derive using trivial checks.
40 ///
41 /// * If T is Array, a trait cannot be derived if the array is incomplete,
42 ///   if the length of the array is larger than the limit (unless the trait
43 ///   allows it), or the trait cannot be derived for the type of data the array
44 ///   contains.
45 ///
46 /// * If T is Vector, a trait cannot be derived if the trait cannot be derived
47 ///   for the type of data the vector contains.
48 ///
49 /// * If T is a type alias, a templated alias or an indirection to another type,
50 ///   the trait cannot be derived if the trait cannot be derived for type T
51 ///   refers to.
52 ///
53 /// * If T is a compound type, the trait cannot be derived if the trait cannot
54 ///   be derived for any of its base members or fields.
55 ///
56 /// * If T is an instantiation of an abstract template definition, the trait
57 ///   cannot be derived if any of the template arguments or template definition
58 ///   cannot derive the trait.
59 ///
60 /// * For all other (simple) types, compiler and standard library limitations
61 ///   dictate whether the trait is implemented.
62 #[derive(Debug, Clone)]
63 pub struct CannotDerive<'ctx> {
64     ctx: &'ctx BindgenContext,
65 
66     derive_trait: DeriveTrait,
67 
68     // The incremental result of this analysis's computation.
69     // Contains information whether particular item can derive `derive_trait`
70     can_derive: HashMap<ItemId, CanDerive>,
71 
72     // Dependencies saying that if a key ItemId has been inserted into the
73     // `cannot_derive_partialeq_or_partialord` set, then each of the ids
74     // in Vec<ItemId> need to be considered again.
75     //
76     // This is a subset of the natural IR graph with reversed edges, where we
77     // only include the edges from the IR graph that can affect whether a type
78     // can derive `derive_trait`.
79     dependencies: HashMap<ItemId, Vec<ItemId>>,
80 }
81 
82 type EdgePredicate = fn(EdgeKind) -> bool;
83 
consider_edge_default(kind: EdgeKind) -> bool84 fn consider_edge_default(kind: EdgeKind) -> bool {
85     match kind {
86         // These are the only edges that can affect whether a type can derive
87         EdgeKind::BaseMember |
88         EdgeKind::Field |
89         EdgeKind::TypeReference |
90         EdgeKind::VarType |
91         EdgeKind::TemplateArgument |
92         EdgeKind::TemplateDeclaration |
93         EdgeKind::TemplateParameterDefinition => true,
94 
95         EdgeKind::Constructor |
96         EdgeKind::Destructor |
97         EdgeKind::FunctionReturn |
98         EdgeKind::FunctionParameter |
99         EdgeKind::InnerType |
100         EdgeKind::InnerVar |
101         EdgeKind::Method |
102         EdgeKind::Generic => false,
103     }
104 }
105 
106 impl<'ctx> CannotDerive<'ctx> {
insert<Id: Into<ItemId>>( &mut self, id: Id, can_derive: CanDerive, ) -> ConstrainResult107     fn insert<Id: Into<ItemId>>(
108         &mut self,
109         id: Id,
110         can_derive: CanDerive,
111     ) -> ConstrainResult {
112         let id = id.into();
113         trace!(
114             "inserting {:?} can_derive<{}>={:?}",
115             id,
116             self.derive_trait,
117             can_derive
118         );
119 
120         if let CanDerive::Yes = can_derive {
121             return ConstrainResult::Same;
122         }
123 
124         match self.can_derive.entry(id) {
125             Entry::Occupied(mut entry) => {
126                 if *entry.get() < can_derive {
127                     entry.insert(can_derive);
128                     ConstrainResult::Changed
129                 } else {
130                     ConstrainResult::Same
131                 }
132             }
133             Entry::Vacant(entry) => {
134                 entry.insert(can_derive);
135                 ConstrainResult::Changed
136             }
137         }
138     }
139 
constrain_type(&mut self, item: &Item, ty: &Type) -> CanDerive140     fn constrain_type(&mut self, item: &Item, ty: &Type) -> CanDerive {
141         if !self.ctx.allowlisted_items().contains(&item.id()) {
142             let can_derive = self
143                 .ctx
144                 .blocklisted_type_implements_trait(item, self.derive_trait);
145             match can_derive {
146                 CanDerive::Yes => trace!(
147                     "    blocklisted type explicitly implements {}",
148                     self.derive_trait
149                 ),
150                 CanDerive::Manually => trace!(
151                     "    blocklisted type requires manual implementation of {}",
152                     self.derive_trait
153                 ),
154                 CanDerive::No => trace!(
155                     "    cannot derive {} for blocklisted type",
156                     self.derive_trait
157                 ),
158             }
159             return can_derive;
160         }
161 
162         if self.derive_trait.not_by_name(self.ctx, &item) {
163             trace!(
164                 "    cannot derive {} for explicitly excluded type",
165                 self.derive_trait
166             );
167             return CanDerive::No;
168         }
169 
170         trace!("ty: {:?}", ty);
171         if item.is_opaque(self.ctx, &()) {
172             if !self.derive_trait.can_derive_union() &&
173                 ty.is_union() &&
174                 self.ctx.options().rust_features().untagged_union
175             {
176                 trace!(
177                     "    cannot derive {} for Rust unions",
178                     self.derive_trait
179                 );
180                 return CanDerive::No;
181             }
182 
183             let layout_can_derive =
184                 ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
185                     l.opaque().array_size_within_derive_limit(self.ctx)
186                 });
187 
188             match layout_can_derive {
189                 CanDerive::Yes => {
190                     trace!(
191                         "    we can trivially derive {} for the layout",
192                         self.derive_trait
193                     );
194                 }
195                 _ => {
196                     trace!(
197                         "    we cannot derive {} for the layout",
198                         self.derive_trait
199                     );
200                 }
201             };
202             return layout_can_derive;
203         }
204 
205         match *ty.kind() {
206             // Handle the simple cases. These can derive traits without further
207             // information.
208             TypeKind::Void |
209             TypeKind::NullPtr |
210             TypeKind::Int(..) |
211             TypeKind::Complex(..) |
212             TypeKind::Float(..) |
213             TypeKind::Enum(..) |
214             TypeKind::TypeParam |
215             TypeKind::UnresolvedTypeRef(..) |
216             TypeKind::Reference(..) |
217             TypeKind::ObjCInterface(..) |
218             TypeKind::ObjCId |
219             TypeKind::ObjCSel => {
220                 return self.derive_trait.can_derive_simple(ty.kind());
221             }
222             TypeKind::Pointer(inner) => {
223                 let inner_type =
224                     self.ctx.resolve_type(inner).canonical_type(self.ctx);
225                 if let TypeKind::Function(ref sig) = *inner_type.kind() {
226                     return self.derive_trait.can_derive_fnptr(sig);
227                 } else {
228                     return self.derive_trait.can_derive_pointer();
229                 }
230             }
231             TypeKind::Function(ref sig) => {
232                 return self.derive_trait.can_derive_fnptr(sig)
233             }
234 
235             // Complex cases need more information
236             TypeKind::Array(t, len) => {
237                 let inner_type =
238                     self.can_derive.get(&t.into()).cloned().unwrap_or_default();
239                 if inner_type != CanDerive::Yes {
240                     trace!(
241                         "    arrays of T for which we cannot derive {} \
242                          also cannot derive {}",
243                         self.derive_trait,
244                         self.derive_trait
245                     );
246                     return CanDerive::No;
247                 }
248 
249                 if len == 0 && !self.derive_trait.can_derive_incomplete_array()
250                 {
251                     trace!(
252                         "    cannot derive {} for incomplete arrays",
253                         self.derive_trait
254                     );
255                     return CanDerive::No;
256                 }
257 
258                 if self.derive_trait.can_derive_large_array() {
259                     trace!("    array can derive {}", self.derive_trait);
260                     return CanDerive::Yes;
261                 }
262 
263                 if len > RUST_DERIVE_IN_ARRAY_LIMIT {
264                     trace!(
265                         "    array is too large to derive {}, but it may be implemented", self.derive_trait
266                     );
267                     return CanDerive::Manually;
268                 }
269                 trace!(
270                     "    array is small enough to derive {}",
271                     self.derive_trait
272                 );
273                 return CanDerive::Yes;
274             }
275             TypeKind::Vector(t, len) => {
276                 let inner_type =
277                     self.can_derive.get(&t.into()).cloned().unwrap_or_default();
278                 if inner_type != CanDerive::Yes {
279                     trace!(
280                         "    vectors of T for which we cannot derive {} \
281                          also cannot derive {}",
282                         self.derive_trait,
283                         self.derive_trait
284                     );
285                     return CanDerive::No;
286                 }
287                 assert_ne!(len, 0, "vectors cannot have zero length");
288                 return self.derive_trait.can_derive_vector();
289             }
290 
291             TypeKind::Comp(ref info) => {
292                 assert!(
293                     !info.has_non_type_template_params(),
294                     "The early ty.is_opaque check should have handled this case"
295                 );
296 
297                 if !self.derive_trait.can_derive_compound_forward_decl() &&
298                     info.is_forward_declaration()
299                 {
300                     trace!(
301                         "    cannot derive {} for forward decls",
302                         self.derive_trait
303                     );
304                     return CanDerive::No;
305                 }
306 
307                 // NOTE: Take into account that while unions in C and C++ are copied by
308                 // default, the may have an explicit destructor in C++, so we can't
309                 // defer this check just for the union case.
310                 if !self.derive_trait.can_derive_compound_with_destructor() &&
311                     self.ctx.lookup_has_destructor(
312                         item.id().expect_type_id(self.ctx),
313                     )
314                 {
315                     trace!(
316                         "    comp has destructor which cannot derive {}",
317                         self.derive_trait
318                     );
319                     return CanDerive::No;
320                 }
321 
322                 if info.kind() == CompKind::Union {
323                     if self.derive_trait.can_derive_union() {
324                         if self.ctx.options().rust_features().untagged_union &&
325                            // https://github.com/rust-lang/rust/issues/36640
326                            (!info.self_template_params(self.ctx).is_empty() ||
327                             !item.all_template_params(self.ctx).is_empty())
328                         {
329                             trace!(
330                                 "    cannot derive {} for Rust union because issue 36640", self.derive_trait
331                             );
332                             return CanDerive::No;
333                         }
334                     // fall through to be same as non-union handling
335                     } else {
336                         if self.ctx.options().rust_features().untagged_union {
337                             trace!(
338                                 "    cannot derive {} for Rust unions",
339                                 self.derive_trait
340                             );
341                             return CanDerive::No;
342                         }
343 
344                         let layout_can_derive =
345                             ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
346                                 l.opaque()
347                                     .array_size_within_derive_limit(self.ctx)
348                             });
349                         match layout_can_derive {
350                             CanDerive::Yes => {
351                                 trace!(
352                                     "    union layout can trivially derive {}",
353                                     self.derive_trait
354                                 );
355                             }
356                             _ => {
357                                 trace!(
358                                     "    union layout cannot derive {}",
359                                     self.derive_trait
360                                 );
361                             }
362                         };
363                         return layout_can_derive;
364                     }
365                 }
366 
367                 if !self.derive_trait.can_derive_compound_with_vtable() &&
368                     item.has_vtable(self.ctx)
369                 {
370                     trace!(
371                         "    cannot derive {} for comp with vtable",
372                         self.derive_trait
373                     );
374                     return CanDerive::No;
375                 }
376 
377                 // Bitfield units are always represented as arrays of u8, but
378                 // they're not traced as arrays, so we need to check here
379                 // instead.
380                 if !self.derive_trait.can_derive_large_array() &&
381                     info.has_too_large_bitfield_unit() &&
382                     !item.is_opaque(self.ctx, &())
383                 {
384                     trace!(
385                         "    cannot derive {} for comp with too large bitfield unit",
386                         self.derive_trait
387                     );
388                     return CanDerive::No;
389                 }
390 
391                 let pred = self.derive_trait.consider_edge_comp();
392                 return self.constrain_join(item, pred);
393             }
394 
395             TypeKind::ResolvedTypeRef(..) |
396             TypeKind::TemplateAlias(..) |
397             TypeKind::Alias(..) |
398             TypeKind::BlockPointer(..) => {
399                 let pred = self.derive_trait.consider_edge_typeref();
400                 return self.constrain_join(item, pred);
401             }
402 
403             TypeKind::TemplateInstantiation(..) => {
404                 let pred = self.derive_trait.consider_edge_tmpl_inst();
405                 return self.constrain_join(item, pred);
406             }
407 
408             TypeKind::Opaque => unreachable!(
409                 "The early ty.is_opaque check should have handled this case"
410             ),
411         }
412     }
413 
constrain_join( &mut self, item: &Item, consider_edge: EdgePredicate, ) -> CanDerive414     fn constrain_join(
415         &mut self,
416         item: &Item,
417         consider_edge: EdgePredicate,
418     ) -> CanDerive {
419         let mut candidate = None;
420 
421         item.trace(
422             self.ctx,
423             &mut |sub_id, edge_kind| {
424                 // Ignore ourselves, since union with ourself is a
425                 // no-op. Ignore edges that aren't relevant to the
426                 // analysis.
427                 if sub_id == item.id() || !consider_edge(edge_kind) {
428                     return;
429                 }
430 
431                 let can_derive = self.can_derive
432                     .get(&sub_id)
433                     .cloned()
434                     .unwrap_or_default();
435 
436                 match can_derive {
437                     CanDerive::Yes => trace!("    member {:?} can derive {}", sub_id, self.derive_trait),
438                     CanDerive::Manually => trace!("    member {:?} cannot derive {}, but it may be implemented", sub_id, self.derive_trait),
439                     CanDerive::No => trace!("    member {:?} cannot derive {}", sub_id, self.derive_trait),
440                 }
441 
442                 *candidate.get_or_insert(CanDerive::Yes) |= can_derive;
443             },
444             &(),
445         );
446 
447         if candidate.is_none() {
448             trace!(
449                 "    can derive {} because there are no members",
450                 self.derive_trait
451             );
452         }
453         candidate.unwrap_or_default()
454     }
455 }
456 
457 impl DeriveTrait {
not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool458     fn not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool {
459         match self {
460             DeriveTrait::Copy => ctx.no_copy_by_name(item),
461             DeriveTrait::Debug => ctx.no_debug_by_name(item),
462             DeriveTrait::Default => ctx.no_default_by_name(item),
463             DeriveTrait::Hash => ctx.no_hash_by_name(item),
464             DeriveTrait::PartialEqOrPartialOrd => {
465                 ctx.no_partialeq_by_name(item)
466             }
467         }
468     }
469 
consider_edge_comp(&self) -> EdgePredicate470     fn consider_edge_comp(&self) -> EdgePredicate {
471         match self {
472             DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
473             _ => |kind| match kind {
474                 EdgeKind::BaseMember | EdgeKind::Field => true,
475                 _ => false,
476             },
477         }
478     }
479 
consider_edge_typeref(&self) -> EdgePredicate480     fn consider_edge_typeref(&self) -> EdgePredicate {
481         match self {
482             DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
483             _ => |kind| kind == EdgeKind::TypeReference,
484         }
485     }
486 
consider_edge_tmpl_inst(&self) -> EdgePredicate487     fn consider_edge_tmpl_inst(&self) -> EdgePredicate {
488         match self {
489             DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
490             _ => |kind| match kind {
491                 EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration => {
492                     true
493                 }
494                 _ => false,
495             },
496         }
497     }
498 
can_derive_large_array(&self) -> bool499     fn can_derive_large_array(&self) -> bool {
500         match self {
501             DeriveTrait::Copy => true,
502             _ => false,
503         }
504     }
505 
can_derive_union(&self) -> bool506     fn can_derive_union(&self) -> bool {
507         match self {
508             DeriveTrait::Copy => true,
509             _ => false,
510         }
511     }
512 
can_derive_compound_with_destructor(&self) -> bool513     fn can_derive_compound_with_destructor(&self) -> bool {
514         match self {
515             DeriveTrait::Copy => false,
516             _ => true,
517         }
518     }
519 
can_derive_compound_with_vtable(&self) -> bool520     fn can_derive_compound_with_vtable(&self) -> bool {
521         match self {
522             DeriveTrait::Default => false,
523             _ => true,
524         }
525     }
526 
can_derive_compound_forward_decl(&self) -> bool527     fn can_derive_compound_forward_decl(&self) -> bool {
528         match self {
529             DeriveTrait::Copy | DeriveTrait::Debug => true,
530             _ => false,
531         }
532     }
533 
can_derive_incomplete_array(&self) -> bool534     fn can_derive_incomplete_array(&self) -> bool {
535         match self {
536             DeriveTrait::Copy |
537             DeriveTrait::Hash |
538             DeriveTrait::PartialEqOrPartialOrd => false,
539             _ => true,
540         }
541     }
542 
can_derive_fnptr(&self, f: &FunctionSig) -> CanDerive543     fn can_derive_fnptr(&self, f: &FunctionSig) -> CanDerive {
544         match (self, f.function_pointers_can_derive()) {
545             (DeriveTrait::Copy, _) | (DeriveTrait::Default, _) | (_, true) => {
546                 trace!("    function pointer can derive {}", self);
547                 CanDerive::Yes
548             }
549             (DeriveTrait::Debug, false) => {
550                 trace!("    function pointer cannot derive {}, but it may be implemented", self);
551                 CanDerive::Manually
552             }
553             (_, false) => {
554                 trace!("    function pointer cannot derive {}", self);
555                 CanDerive::No
556             }
557         }
558     }
559 
can_derive_vector(&self) -> CanDerive560     fn can_derive_vector(&self) -> CanDerive {
561         match self {
562             DeriveTrait::PartialEqOrPartialOrd => {
563                 // FIXME: vectors always can derive PartialEq, but they should
564                 // not derive PartialOrd:
565                 // https://github.com/rust-lang-nursery/packed_simd/issues/48
566                 trace!("    vectors cannot derive PartialOrd");
567                 CanDerive::No
568             }
569             _ => {
570                 trace!("    vector can derive {}", self);
571                 CanDerive::Yes
572             }
573         }
574     }
575 
can_derive_pointer(&self) -> CanDerive576     fn can_derive_pointer(&self) -> CanDerive {
577         match self {
578             DeriveTrait::Default => {
579                 trace!("    pointer cannot derive Default");
580                 CanDerive::No
581             }
582             _ => {
583                 trace!("    pointer can derive {}", self);
584                 CanDerive::Yes
585             }
586         }
587     }
588 
can_derive_simple(&self, kind: &TypeKind) -> CanDerive589     fn can_derive_simple(&self, kind: &TypeKind) -> CanDerive {
590         match (self, kind) {
591             // === Default ===
592             (DeriveTrait::Default, TypeKind::Void) |
593             (DeriveTrait::Default, TypeKind::NullPtr) |
594             (DeriveTrait::Default, TypeKind::Enum(..)) |
595             (DeriveTrait::Default, TypeKind::Reference(..)) |
596             (DeriveTrait::Default, TypeKind::TypeParam) |
597             (DeriveTrait::Default, TypeKind::ObjCInterface(..)) |
598             (DeriveTrait::Default, TypeKind::ObjCId) |
599             (DeriveTrait::Default, TypeKind::ObjCSel) => {
600                 trace!("    types that always cannot derive Default");
601                 CanDerive::No
602             }
603             (DeriveTrait::Default, TypeKind::UnresolvedTypeRef(..)) => {
604                 unreachable!(
605                     "Type with unresolved type ref can't reach derive default"
606                 )
607             }
608             // === Hash ===
609             (DeriveTrait::Hash, TypeKind::Float(..)) |
610             (DeriveTrait::Hash, TypeKind::Complex(..)) => {
611                 trace!("    float cannot derive Hash");
612                 CanDerive::No
613             }
614             // === others ===
615             _ => {
616                 trace!("    simple type that can always derive {}", self);
617                 CanDerive::Yes
618             }
619         }
620     }
621 }
622 
623 impl fmt::Display for DeriveTrait {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result624     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
625         let s = match self {
626             DeriveTrait::Copy => "Copy",
627             DeriveTrait::Debug => "Debug",
628             DeriveTrait::Default => "Default",
629             DeriveTrait::Hash => "Hash",
630             DeriveTrait::PartialEqOrPartialOrd => "PartialEq/PartialOrd",
631         };
632         s.fmt(f)
633     }
634 }
635 
636 impl<'ctx> MonotoneFramework for CannotDerive<'ctx> {
637     type Node = ItemId;
638     type Extra = (&'ctx BindgenContext, DeriveTrait);
639     type Output = HashMap<ItemId, CanDerive>;
640 
new( (ctx, derive_trait): (&'ctx BindgenContext, DeriveTrait), ) -> CannotDerive<'ctx>641     fn new(
642         (ctx, derive_trait): (&'ctx BindgenContext, DeriveTrait),
643     ) -> CannotDerive<'ctx> {
644         let can_derive = HashMap::default();
645         let dependencies = generate_dependencies(ctx, consider_edge_default);
646 
647         CannotDerive {
648             ctx,
649             derive_trait,
650             can_derive,
651             dependencies,
652         }
653     }
654 
initial_worklist(&self) -> Vec<ItemId>655     fn initial_worklist(&self) -> Vec<ItemId> {
656         // The transitive closure of all allowlisted items, including explicitly
657         // blocklisted items.
658         self.ctx
659             .allowlisted_items()
660             .iter()
661             .cloned()
662             .flat_map(|i| {
663                 let mut reachable = vec![i];
664                 i.trace(
665                     self.ctx,
666                     &mut |s, _| {
667                         reachable.push(s);
668                     },
669                     &(),
670                 );
671                 reachable
672             })
673             .collect()
674     }
675 
constrain(&mut self, id: ItemId) -> ConstrainResult676     fn constrain(&mut self, id: ItemId) -> ConstrainResult {
677         trace!("constrain: {:?}", id);
678 
679         if let Some(CanDerive::No) = self.can_derive.get(&id).cloned() {
680             trace!("    already know it cannot derive {}", self.derive_trait);
681             return ConstrainResult::Same;
682         }
683 
684         let item = self.ctx.resolve_item(id);
685         let can_derive = match item.as_type() {
686             Some(ty) => {
687                 let mut can_derive = self.constrain_type(item, ty);
688                 if let CanDerive::Yes = can_derive {
689                     if !self.derive_trait.can_derive_large_array() &&
690                         ty.layout(self.ctx).map_or(false, |l| {
691                             l.align > RUST_DERIVE_IN_ARRAY_LIMIT
692                         })
693                     {
694                         // We have to be conservative: the struct *could* have enough
695                         // padding that we emit an array that is longer than
696                         // `RUST_DERIVE_IN_ARRAY_LIMIT`. If we moved padding calculations
697                         // into the IR and computed them before this analysis, then we could
698                         // be precise rather than conservative here.
699                         can_derive = CanDerive::Manually;
700                     }
701                 }
702                 can_derive
703             }
704             None => self.constrain_join(item, consider_edge_default),
705         };
706 
707         self.insert(id, can_derive)
708     }
709 
each_depending_on<F>(&self, id: ItemId, mut f: F) where F: FnMut(ItemId),710     fn each_depending_on<F>(&self, id: ItemId, mut f: F)
711     where
712         F: FnMut(ItemId),
713     {
714         if let Some(edges) = self.dependencies.get(&id) {
715             for item in edges {
716                 trace!("enqueue {:?} into worklist", item);
717                 f(*item);
718             }
719         }
720     }
721 }
722 
723 impl<'ctx> From<CannotDerive<'ctx>> for HashMap<ItemId, CanDerive> {
from(analysis: CannotDerive<'ctx>) -> Self724     fn from(analysis: CannotDerive<'ctx>) -> Self {
725         extra_assert!(analysis
726             .can_derive
727             .values()
728             .all(|v| *v != CanDerive::Yes));
729 
730         analysis.can_derive
731     }
732 }
733 
734 /// Convert a `HashMap<ItemId, CanDerive>` into a `HashSet<ItemId>`.
735 ///
736 /// Elements that are not `CanDerive::Yes` are kept in the set, so that it
737 /// represents all items that cannot derive.
as_cannot_derive_set( can_derive: HashMap<ItemId, CanDerive>, ) -> HashSet<ItemId>738 pub fn as_cannot_derive_set(
739     can_derive: HashMap<ItemId, CanDerive>,
740 ) -> HashSet<ItemId> {
741     can_derive
742         .into_iter()
743         .filter_map(|(k, v)| if v != CanDerive::Yes { Some(k) } else { None })
744         .collect()
745 }
746