1use std::fmt;
4
5use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
6use crate::ir::analysis::has_vtable::HasVtable;
7use crate::ir::comp::CompKind;
8use crate::ir::context::{BindgenContext, ItemId};
9use crate::ir::derive::CanDerive;
10use crate::ir::function::FunctionSig;
11use crate::ir::item::{IsOpaque, Item};
12use crate::ir::layout::Layout;
13use crate::ir::template::TemplateParameters;
14use crate::ir::traversal::{EdgeKind, Trace};
15use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
16use crate::ir::ty::{Type, TypeKind};
17use crate::{Entry, HashMap, HashSet};
18
19#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
21pub enum DeriveTrait {
22 Copy,
24 Debug,
26 Default,
28 Hash,
30 PartialEqOrPartialOrd,
32}
33
34#[derive(Debug, Clone)]
64pub(crate) struct CannotDerive<'ctx> {
65 ctx: &'ctx BindgenContext,
66
67 derive_trait: DeriveTrait,
68
69 can_derive: HashMap<ItemId, CanDerive>,
72
73 dependencies: HashMap<ItemId, Vec<ItemId>>,
81}
82
83type EdgePredicate = fn(EdgeKind) -> bool;
84
85fn consider_edge_default(kind: EdgeKind) -> bool {
86 match kind {
87 EdgeKind::BaseMember |
89 EdgeKind::Field |
90 EdgeKind::TypeReference |
91 EdgeKind::VarType |
92 EdgeKind::TemplateArgument |
93 EdgeKind::TemplateDeclaration |
94 EdgeKind::TemplateParameterDefinition => true,
95
96 EdgeKind::Constructor |
97 EdgeKind::Destructor |
98 EdgeKind::FunctionReturn |
99 EdgeKind::FunctionParameter |
100 EdgeKind::InnerType |
101 EdgeKind::InnerVar |
102 EdgeKind::Method |
103 EdgeKind::Generic => false,
104 }
105}
106
107impl CannotDerive<'_> {
108 fn insert<Id: Into<ItemId>>(
109 &mut self,
110 id: Id,
111 can_derive: CanDerive,
112 ) -> ConstrainResult {
113 let id = id.into();
114 trace!(
115 "inserting {id:?} can_derive<{}>={can_derive:?}",
116 self.derive_trait,
117 );
118
119 if let CanDerive::Yes = can_derive {
120 return ConstrainResult::Same;
121 }
122
123 match self.can_derive.entry(id) {
124 Entry::Occupied(mut entry) => {
125 if *entry.get() < can_derive {
126 entry.insert(can_derive);
127 ConstrainResult::Changed
128 } else {
129 ConstrainResult::Same
130 }
131 }
132 Entry::Vacant(entry) => {
133 entry.insert(can_derive);
134 ConstrainResult::Changed
135 }
136 }
137 }
138
139 fn constrain_type(&mut self, item: &Item, ty: &Type) -> CanDerive {
140 if !self.ctx.allowlisted_items().contains(&item.id()) {
141 let can_derive = self
142 .ctx
143 .blocklisted_type_implements_trait(item, self.derive_trait);
144 match can_derive {
145 CanDerive::Yes => trace!(
146 " blocklisted type explicitly implements {}",
147 self.derive_trait
148 ),
149 CanDerive::Manually => trace!(
150 " blocklisted type requires manual implementation of {}",
151 self.derive_trait
152 ),
153 CanDerive::No => trace!(
154 " cannot derive {} for blocklisted type",
155 self.derive_trait
156 ),
157 }
158 return can_derive;
159 }
160
161 if self.derive_trait.not_by_name(self.ctx, item) {
162 trace!(
163 " cannot derive {} for explicitly excluded type",
164 self.derive_trait
165 );
166 return CanDerive::No;
167 }
168
169 trace!("ty: {ty:?}");
170 if item.is_opaque(self.ctx, &()) {
171 if !self.derive_trait.can_derive_union() &&
172 ty.is_union() &&
173 self.ctx.options().untagged_union
174 {
175 trace!(
176 " cannot derive {} for Rust unions",
177 self.derive_trait
178 );
179 return CanDerive::No;
180 }
181
182 trace!(
183 " we can trivially derive {} for the layout",
184 self.derive_trait
185 );
186 return CanDerive::Yes;
187 }
188
189 match *ty.kind() {
190 TypeKind::Void |
193 TypeKind::NullPtr |
194 TypeKind::Int(..) |
195 TypeKind::Complex(..) |
196 TypeKind::Float(..) |
197 TypeKind::Enum(..) |
198 TypeKind::TypeParam |
199 TypeKind::UnresolvedTypeRef(..) |
200 TypeKind::Reference(..) |
201 TypeKind::ObjCInterface(..) |
202 TypeKind::ObjCId |
203 TypeKind::ObjCSel => self.derive_trait.can_derive_simple(ty.kind()),
204 TypeKind::Pointer(inner) => {
205 let inner_type =
206 self.ctx.resolve_type(inner).canonical_type(self.ctx);
207 if let TypeKind::Function(ref sig) = *inner_type.kind() {
208 self.derive_trait.can_derive_fnptr(sig)
209 } else {
210 self.derive_trait.can_derive_pointer()
211 }
212 }
213 TypeKind::Function(ref sig) => {
214 self.derive_trait.can_derive_fnptr(sig)
215 }
216
217 TypeKind::Array(t, len) => {
219 let inner_type =
220 self.can_derive.get(&t.into()).copied().unwrap_or_default();
221 if inner_type != CanDerive::Yes {
222 trace!(
223 " arrays of T for which we cannot derive {} \
224 also cannot derive {}",
225 self.derive_trait,
226 self.derive_trait
227 );
228 return CanDerive::No;
229 }
230
231 if len == 0 && !self.derive_trait.can_derive_incomplete_array()
232 {
233 trace!(
234 " cannot derive {} for incomplete arrays",
235 self.derive_trait
236 );
237 return CanDerive::No;
238 }
239
240 if self.derive_trait.can_derive_large_array(self.ctx) {
241 trace!(" array can derive {}", self.derive_trait);
242 return CanDerive::Yes;
243 }
244
245 if len > RUST_DERIVE_IN_ARRAY_LIMIT {
246 trace!(
247 " array is too large to derive {}, but it may be implemented", self.derive_trait
248 );
249 return CanDerive::Manually;
250 }
251 trace!(
252 " array is small enough to derive {}",
253 self.derive_trait
254 );
255 CanDerive::Yes
256 }
257 TypeKind::Vector(t, len) => {
258 let inner_type =
259 self.can_derive.get(&t.into()).copied().unwrap_or_default();
260 if inner_type != CanDerive::Yes {
261 trace!(
262 " vectors of T for which we cannot derive {} \
263 also cannot derive {}",
264 self.derive_trait,
265 self.derive_trait
266 );
267 return CanDerive::No;
268 }
269 assert_ne!(len, 0, "vectors cannot have zero length");
270 self.derive_trait.can_derive_vector()
271 }
272
273 TypeKind::Comp(ref info) => {
274 assert!(
275 !info.has_non_type_template_params(),
276 "The early ty.is_opaque check should have handled this case"
277 );
278
279 if !self.derive_trait.can_derive_compound_forward_decl() &&
280 info.is_forward_declaration()
281 {
282 trace!(
283 " cannot derive {} for forward decls",
284 self.derive_trait
285 );
286 return CanDerive::No;
287 }
288
289 if !self.derive_trait.can_derive_compound_with_destructor() &&
293 self.ctx.lookup_has_destructor(
294 item.id().expect_type_id(self.ctx),
295 )
296 {
297 trace!(
298 " comp has destructor which cannot derive {}",
299 self.derive_trait
300 );
301 return CanDerive::No;
302 }
303
304 if info.kind() == CompKind::Union {
305 if self.derive_trait.can_derive_union() {
306 if self.ctx.options().untagged_union &&
307 (!info.self_template_params(self.ctx).is_empty() ||
309 !item.all_template_params(self.ctx).is_empty())
310 {
311 trace!(
312 " cannot derive {} for Rust union because issue 36640", self.derive_trait
313 );
314 return CanDerive::No;
315 }
316 } else {
318 if self.ctx.options().untagged_union {
319 trace!(
320 " cannot derive {} for Rust unions",
321 self.derive_trait
322 );
323 return CanDerive::No;
324 }
325
326 trace!(
327 " union layout can trivially derive {}",
328 self.derive_trait
329 );
330 return CanDerive::Yes;
331 }
332 }
333
334 if !self.derive_trait.can_derive_compound_with_vtable() &&
335 item.has_vtable(self.ctx)
336 {
337 trace!(
338 " cannot derive {} for comp with vtable",
339 self.derive_trait
340 );
341 return CanDerive::No;
342 }
343
344 if !self.derive_trait.can_derive_large_array(self.ctx) &&
348 info.has_too_large_bitfield_unit() &&
349 !item.is_opaque(self.ctx, &())
350 {
351 trace!(
352 " cannot derive {} for comp with too large bitfield unit",
353 self.derive_trait
354 );
355 return CanDerive::No;
356 }
357
358 let pred = self.derive_trait.consider_edge_comp();
359 self.constrain_join(item, pred)
360 }
361
362 TypeKind::ResolvedTypeRef(..) |
363 TypeKind::TemplateAlias(..) |
364 TypeKind::Alias(..) |
365 TypeKind::BlockPointer(..) => {
366 let pred = self.derive_trait.consider_edge_typeref();
367 self.constrain_join(item, pred)
368 }
369
370 TypeKind::TemplateInstantiation(..) => {
371 let pred = self.derive_trait.consider_edge_tmpl_inst();
372 self.constrain_join(item, pred)
373 }
374
375 TypeKind::Opaque => unreachable!(
376 "The early ty.is_opaque check should have handled this case"
377 ),
378 }
379 }
380
381 fn constrain_join(
382 &mut self,
383 item: &Item,
384 consider_edge: EdgePredicate,
385 ) -> CanDerive {
386 let mut candidate = None;
387
388 item.trace(
389 self.ctx,
390 &mut |sub_id, edge_kind| {
391 if sub_id == item.id() || !consider_edge(edge_kind) {
395 return;
396 }
397
398 let can_derive = self.can_derive
399 .get(&sub_id)
400 .copied()
401 .unwrap_or_default();
402
403 match can_derive {
404 CanDerive::Yes => trace!(" member {sub_id:?} can derive {}", self.derive_trait),
405 CanDerive::Manually => trace!(" member {sub_id:?} cannot derive {}, but it may be implemented", self.derive_trait),
406 CanDerive::No => trace!(" member {sub_id:?} cannot derive {}", self.derive_trait),
407 }
408
409 *candidate.get_or_insert(CanDerive::Yes) |= can_derive;
410 },
411 &(),
412 );
413
414 if candidate.is_none() {
415 trace!(
416 " can derive {} because there are no members",
417 self.derive_trait
418 );
419 }
420 candidate.unwrap_or_default()
421 }
422}
423
424impl DeriveTrait {
425 fn not_by_name(self, ctx: &BindgenContext, item: &Item) -> bool {
426 match self {
427 DeriveTrait::Copy => ctx.no_copy_by_name(item),
428 DeriveTrait::Debug => ctx.no_debug_by_name(item),
429 DeriveTrait::Default => ctx.no_default_by_name(item),
430 DeriveTrait::Hash => ctx.no_hash_by_name(item),
431 DeriveTrait::PartialEqOrPartialOrd => {
432 ctx.no_partialeq_by_name(item)
433 }
434 }
435 }
436
437 fn consider_edge_comp(self) -> EdgePredicate {
438 match self {
439 DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
440 _ => |kind| matches!(kind, EdgeKind::BaseMember | EdgeKind::Field),
441 }
442 }
443
444 fn consider_edge_typeref(self) -> EdgePredicate {
445 match self {
446 DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
447 _ => |kind| kind == EdgeKind::TypeReference,
448 }
449 }
450
451 fn consider_edge_tmpl_inst(self) -> EdgePredicate {
452 match self {
453 DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
454 _ => |kind| {
455 matches!(
456 kind,
457 EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration
458 )
459 },
460 }
461 }
462
463 fn can_derive_large_array(self, _: &BindgenContext) -> bool {
464 !matches!(self, DeriveTrait::Default)
465 }
466
467 fn can_derive_union(self) -> bool {
468 matches!(self, DeriveTrait::Copy)
469 }
470
471 fn can_derive_compound_with_destructor(self) -> bool {
472 !matches!(self, DeriveTrait::Copy)
473 }
474
475 fn can_derive_compound_with_vtable(self) -> bool {
476 !matches!(self, DeriveTrait::Default)
477 }
478
479 fn can_derive_compound_forward_decl(self) -> bool {
480 matches!(self, DeriveTrait::Debug)
481 }
482
483 fn can_derive_incomplete_array(self) -> bool {
484 !matches!(
485 self,
486 DeriveTrait::Copy |
487 DeriveTrait::Hash |
488 DeriveTrait::PartialEqOrPartialOrd
489 )
490 }
491
492 fn can_derive_fnptr(self, f: &FunctionSig) -> CanDerive {
493 match (self, f.function_pointers_can_derive()) {
494 (DeriveTrait::Copy | DeriveTrait::Default, _) | (_, true) => {
495 trace!(" function pointer can derive {self}");
496 CanDerive::Yes
497 }
498 (DeriveTrait::Debug, false) => {
499 trace!(" function pointer cannot derive {self}, but it may be implemented");
500 CanDerive::Manually
501 }
502 (_, false) => {
503 trace!(" function pointer cannot derive {self}");
504 CanDerive::No
505 }
506 }
507 }
508
509 fn can_derive_vector(self) -> CanDerive {
510 if self == DeriveTrait::PartialEqOrPartialOrd {
511 trace!(" vectors cannot derive PartialOrd");
515 CanDerive::No
516 } else {
517 trace!(" vector can derive {self}");
518 CanDerive::Yes
519 }
520 }
521
522 fn can_derive_pointer(self) -> CanDerive {
523 if self == DeriveTrait::Default {
524 trace!(" pointer cannot derive Default");
525 CanDerive::No
526 } else {
527 trace!(" pointer can derive {self}");
528 CanDerive::Yes
529 }
530 }
531
532 fn can_derive_simple(self, kind: &TypeKind) -> CanDerive {
533 match (self, kind) {
534 (
536 DeriveTrait::Default,
537 TypeKind::Void |
538 TypeKind::NullPtr |
539 TypeKind::Enum(..) |
540 TypeKind::Reference(..) |
541 TypeKind::TypeParam |
542 TypeKind::ObjCInterface(..) |
543 TypeKind::ObjCId |
544 TypeKind::ObjCSel,
545 ) => {
546 trace!(" types that always cannot derive Default");
547 CanDerive::No
548 }
549 (DeriveTrait::Default, TypeKind::UnresolvedTypeRef(..)) => {
550 unreachable!(
551 "Type with unresolved type ref can't reach derive default"
552 )
553 }
554 (
556 DeriveTrait::Hash,
557 TypeKind::Float(..) | TypeKind::Complex(..),
558 ) => {
559 trace!(" float cannot derive Hash");
560 CanDerive::No
561 }
562 _ => {
564 trace!(" simple type that can always derive {self}");
565 CanDerive::Yes
566 }
567 }
568 }
569}
570
571impl fmt::Display for DeriveTrait {
572 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
573 let s = match self {
574 DeriveTrait::Copy => "Copy",
575 DeriveTrait::Debug => "Debug",
576 DeriveTrait::Default => "Default",
577 DeriveTrait::Hash => "Hash",
578 DeriveTrait::PartialEqOrPartialOrd => "PartialEq/PartialOrd",
579 };
580 s.fmt(f)
581 }
582}
583
584impl<'ctx> MonotoneFramework for CannotDerive<'ctx> {
585 type Node = ItemId;
586 type Extra = (&'ctx BindgenContext, DeriveTrait);
587 type Output = HashMap<ItemId, CanDerive>;
588
589 fn new(
590 (ctx, derive_trait): (&'ctx BindgenContext, DeriveTrait),
591 ) -> CannotDerive<'ctx> {
592 let can_derive = HashMap::default();
593 let dependencies = generate_dependencies(ctx, consider_edge_default);
594
595 CannotDerive {
596 ctx,
597 derive_trait,
598 can_derive,
599 dependencies,
600 }
601 }
602
603 fn initial_worklist(&self) -> Vec<ItemId> {
604 self.ctx
607 .allowlisted_items()
608 .iter()
609 .copied()
610 .flat_map(|i| {
611 let mut reachable = vec![i];
612 i.trace(
613 self.ctx,
614 &mut |s, _| {
615 reachable.push(s);
616 },
617 &(),
618 );
619 reachable
620 })
621 .collect()
622 }
623
624 fn constrain(&mut self, id: ItemId) -> ConstrainResult {
625 trace!("constrain: {id:?}");
626
627 if let Some(CanDerive::No) = self.can_derive.get(&id) {
628 trace!(" already know it cannot derive {}", self.derive_trait);
629 return ConstrainResult::Same;
630 }
631
632 let item = self.ctx.resolve_item(id);
633 let can_derive = match item.as_type() {
634 Some(ty) => {
635 let mut can_derive = self.constrain_type(item, ty);
636 if let CanDerive::Yes = can_derive {
637 let is_reached_limit =
638 |l: Layout| l.align > RUST_DERIVE_IN_ARRAY_LIMIT;
639 if !self.derive_trait.can_derive_large_array(self.ctx) &&
640 ty.layout(self.ctx).is_some_and(is_reached_limit)
641 {
642 can_derive = CanDerive::Manually;
648 }
649 }
650 can_derive
651 }
652 None => self.constrain_join(item, consider_edge_default),
653 };
654
655 self.insert(id, can_derive)
656 }
657
658 fn each_depending_on<F>(&self, id: ItemId, mut f: F)
659 where
660 F: FnMut(ItemId),
661 {
662 if let Some(edges) = self.dependencies.get(&id) {
663 for item in edges {
664 trace!("enqueue {item:?} into worklist");
665 f(*item);
666 }
667 }
668 }
669}
670
671impl<'ctx> From<CannotDerive<'ctx>> for HashMap<ItemId, CanDerive> {
672 fn from(analysis: CannotDerive<'ctx>) -> Self {
673 extra_assert!(analysis
674 .can_derive
675 .values()
676 .all(|v| *v != CanDerive::Yes));
677
678 analysis.can_derive
679 }
680}
681
682pub(crate) fn as_cannot_derive_set(
687 can_derive: HashMap<ItemId, CanDerive>,
688) -> HashSet<ItemId> {
689 can_derive
690 .into_iter()
691 .filter_map(|(k, v)| if v == CanDerive::Yes { None } else { Some(k) })
692 .collect()
693}