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 let layout_can_derive =
183 ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
184 l.opaque().array_size_within_derive_limit()
185 });
186
187 match layout_can_derive {
188 CanDerive::Yes => {
189 trace!(
190 " we can trivially derive {} for the layout",
191 self.derive_trait
192 );
193 }
194 _ => {
195 trace!(
196 " we cannot derive {} for the layout",
197 self.derive_trait
198 );
199 }
200 };
201 return layout_can_derive;
202 }
203
204 match *ty.kind() {
205 TypeKind::Void |
208 TypeKind::NullPtr |
209 TypeKind::Int(..) |
210 TypeKind::Complex(..) |
211 TypeKind::Float(..) |
212 TypeKind::Enum(..) |
213 TypeKind::TypeParam |
214 TypeKind::UnresolvedTypeRef(..) |
215 TypeKind::Reference(..) |
216 TypeKind::ObjCInterface(..) |
217 TypeKind::ObjCId |
218 TypeKind::ObjCSel => self.derive_trait.can_derive_simple(ty.kind()),
219 TypeKind::Pointer(inner) => {
220 let inner_type =
221 self.ctx.resolve_type(inner).canonical_type(self.ctx);
222 if let TypeKind::Function(ref sig) = *inner_type.kind() {
223 self.derive_trait.can_derive_fnptr(sig)
224 } else {
225 self.derive_trait.can_derive_pointer()
226 }
227 }
228 TypeKind::Function(ref sig) => {
229 self.derive_trait.can_derive_fnptr(sig)
230 }
231
232 TypeKind::Array(t, len) => {
234 let inner_type =
235 self.can_derive.get(&t.into()).copied().unwrap_or_default();
236 if inner_type != CanDerive::Yes {
237 trace!(
238 " arrays of T for which we cannot derive {} \
239 also cannot derive {}",
240 self.derive_trait,
241 self.derive_trait
242 );
243 return CanDerive::No;
244 }
245
246 if len == 0 && !self.derive_trait.can_derive_incomplete_array()
247 {
248 trace!(
249 " cannot derive {} for incomplete arrays",
250 self.derive_trait
251 );
252 return CanDerive::No;
253 }
254
255 if self.derive_trait.can_derive_large_array(self.ctx) {
256 trace!(" array can derive {}", self.derive_trait);
257 return CanDerive::Yes;
258 }
259
260 if len > RUST_DERIVE_IN_ARRAY_LIMIT {
261 trace!(
262 " array is too large to derive {}, but it may be implemented", self.derive_trait
263 );
264 return CanDerive::Manually;
265 }
266 trace!(
267 " array is small enough to derive {}",
268 self.derive_trait
269 );
270 CanDerive::Yes
271 }
272 TypeKind::Vector(t, len) => {
273 let inner_type =
274 self.can_derive.get(&t.into()).copied().unwrap_or_default();
275 if inner_type != CanDerive::Yes {
276 trace!(
277 " vectors of T for which we cannot derive {} \
278 also cannot derive {}",
279 self.derive_trait,
280 self.derive_trait
281 );
282 return CanDerive::No;
283 }
284 assert_ne!(len, 0, "vectors cannot have zero length");
285 self.derive_trait.can_derive_vector()
286 }
287
288 TypeKind::Comp(ref info) => {
289 assert!(
290 !info.has_non_type_template_params(),
291 "The early ty.is_opaque check should have handled this case"
292 );
293
294 if !self.derive_trait.can_derive_compound_forward_decl() &&
295 info.is_forward_declaration()
296 {
297 trace!(
298 " cannot derive {} for forward decls",
299 self.derive_trait
300 );
301 return CanDerive::No;
302 }
303
304 if !self.derive_trait.can_derive_compound_with_destructor() &&
308 self.ctx.lookup_has_destructor(
309 item.id().expect_type_id(self.ctx),
310 )
311 {
312 trace!(
313 " comp has destructor which cannot derive {}",
314 self.derive_trait
315 );
316 return CanDerive::No;
317 }
318
319 if info.kind() == CompKind::Union {
320 if self.derive_trait.can_derive_union() {
321 if self.ctx.options().untagged_union &&
322 (!info.self_template_params(self.ctx).is_empty() ||
324 !item.all_template_params(self.ctx).is_empty())
325 {
326 trace!(
327 " cannot derive {} for Rust union because issue 36640", self.derive_trait
328 );
329 return CanDerive::No;
330 }
331 } else {
333 if self.ctx.options().untagged_union {
334 trace!(
335 " cannot derive {} for Rust unions",
336 self.derive_trait
337 );
338 return CanDerive::No;
339 }
340
341 let layout_can_derive =
342 ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
343 l.opaque().array_size_within_derive_limit()
344 });
345 match layout_can_derive {
346 CanDerive::Yes => {
347 trace!(
348 " union layout can trivially derive {}",
349 self.derive_trait
350 );
351 }
352 _ => {
353 trace!(
354 " union layout cannot derive {}",
355 self.derive_trait
356 );
357 }
358 };
359 return layout_can_derive;
360 }
361 }
362
363 if !self.derive_trait.can_derive_compound_with_vtable() &&
364 item.has_vtable(self.ctx)
365 {
366 trace!(
367 " cannot derive {} for comp with vtable",
368 self.derive_trait
369 );
370 return CanDerive::No;
371 }
372
373 if !self.derive_trait.can_derive_large_array(self.ctx) &&
377 info.has_too_large_bitfield_unit() &&
378 !item.is_opaque(self.ctx, &())
379 {
380 trace!(
381 " cannot derive {} for comp with too large bitfield unit",
382 self.derive_trait
383 );
384 return CanDerive::No;
385 }
386
387 let pred = self.derive_trait.consider_edge_comp();
388 self.constrain_join(item, pred)
389 }
390
391 TypeKind::ResolvedTypeRef(..) |
392 TypeKind::TemplateAlias(..) |
393 TypeKind::Alias(..) |
394 TypeKind::BlockPointer(..) => {
395 let pred = self.derive_trait.consider_edge_typeref();
396 self.constrain_join(item, pred)
397 }
398
399 TypeKind::TemplateInstantiation(..) => {
400 let pred = self.derive_trait.consider_edge_tmpl_inst();
401 self.constrain_join(item, pred)
402 }
403
404 TypeKind::Opaque => unreachable!(
405 "The early ty.is_opaque check should have handled this case"
406 ),
407 }
408 }
409
410 fn constrain_join(
411 &mut self,
412 item: &Item,
413 consider_edge: EdgePredicate,
414 ) -> CanDerive {
415 let mut candidate = None;
416
417 item.trace(
418 self.ctx,
419 &mut |sub_id, edge_kind| {
420 if sub_id == item.id() || !consider_edge(edge_kind) {
424 return;
425 }
426
427 let can_derive = self.can_derive
428 .get(&sub_id)
429 .copied()
430 .unwrap_or_default();
431
432 match can_derive {
433 CanDerive::Yes => trace!(" member {sub_id:?} can derive {}", self.derive_trait),
434 CanDerive::Manually => trace!(" member {sub_id:?} cannot derive {}, but it may be implemented", self.derive_trait),
435 CanDerive::No => trace!(" member {sub_id:?} cannot derive {}", self.derive_trait),
436 }
437
438 *candidate.get_or_insert(CanDerive::Yes) |= can_derive;
439 },
440 &(),
441 );
442
443 if candidate.is_none() {
444 trace!(
445 " can derive {} because there are no members",
446 self.derive_trait
447 );
448 }
449 candidate.unwrap_or_default()
450 }
451}
452
453impl DeriveTrait {
454 fn not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool {
455 match self {
456 DeriveTrait::Copy => ctx.no_copy_by_name(item),
457 DeriveTrait::Debug => ctx.no_debug_by_name(item),
458 DeriveTrait::Default => ctx.no_default_by_name(item),
459 DeriveTrait::Hash => ctx.no_hash_by_name(item),
460 DeriveTrait::PartialEqOrPartialOrd => {
461 ctx.no_partialeq_by_name(item)
462 }
463 }
464 }
465
466 fn consider_edge_comp(&self) -> EdgePredicate {
467 match self {
468 DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
469 _ => |kind| matches!(kind, EdgeKind::BaseMember | EdgeKind::Field),
470 }
471 }
472
473 fn consider_edge_typeref(&self) -> EdgePredicate {
474 match self {
475 DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
476 _ => |kind| kind == EdgeKind::TypeReference,
477 }
478 }
479
480 fn consider_edge_tmpl_inst(&self) -> EdgePredicate {
481 match self {
482 DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
483 _ => |kind| {
484 matches!(
485 kind,
486 EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration
487 )
488 },
489 }
490 }
491
492 fn can_derive_large_array(&self, ctx: &BindgenContext) -> bool {
493 if ctx.options().rust_features().larger_arrays {
494 !matches!(self, DeriveTrait::Default)
495 } else {
496 matches!(self, DeriveTrait::Copy)
497 }
498 }
499
500 fn can_derive_union(&self) -> bool {
501 matches!(self, DeriveTrait::Copy)
502 }
503
504 fn can_derive_compound_with_destructor(&self) -> bool {
505 !matches!(self, DeriveTrait::Copy)
506 }
507
508 fn can_derive_compound_with_vtable(&self) -> bool {
509 !matches!(self, DeriveTrait::Default)
510 }
511
512 fn can_derive_compound_forward_decl(&self) -> bool {
513 matches!(self, DeriveTrait::Copy | DeriveTrait::Debug)
514 }
515
516 fn can_derive_incomplete_array(&self) -> bool {
517 !matches!(
518 self,
519 DeriveTrait::Copy |
520 DeriveTrait::Hash |
521 DeriveTrait::PartialEqOrPartialOrd
522 )
523 }
524
525 fn can_derive_fnptr(&self, f: &FunctionSig) -> CanDerive {
526 match (self, f.function_pointers_can_derive()) {
527 (DeriveTrait::Copy, _) | (DeriveTrait::Default, _) | (_, true) => {
528 trace!(" function pointer can derive {self}");
529 CanDerive::Yes
530 }
531 (DeriveTrait::Debug, false) => {
532 trace!(" function pointer cannot derive {self}, but it may be implemented");
533 CanDerive::Manually
534 }
535 (_, false) => {
536 trace!(" function pointer cannot derive {self}");
537 CanDerive::No
538 }
539 }
540 }
541
542 fn can_derive_vector(&self) -> CanDerive {
543 if *self == DeriveTrait::PartialEqOrPartialOrd {
544 trace!(" vectors cannot derive PartialOrd");
548 CanDerive::No
549 } else {
550 trace!(" vector can derive {self}");
551 CanDerive::Yes
552 }
553 }
554
555 fn can_derive_pointer(&self) -> CanDerive {
556 if *self == DeriveTrait::Default {
557 trace!(" pointer cannot derive Default");
558 CanDerive::No
559 } else {
560 trace!(" pointer can derive {self}");
561 CanDerive::Yes
562 }
563 }
564
565 fn can_derive_simple(&self, kind: &TypeKind) -> CanDerive {
566 match (self, kind) {
567 (DeriveTrait::Default, TypeKind::Void) |
569 (DeriveTrait::Default, TypeKind::NullPtr) |
570 (DeriveTrait::Default, TypeKind::Enum(..)) |
571 (DeriveTrait::Default, TypeKind::Reference(..)) |
572 (DeriveTrait::Default, TypeKind::TypeParam) |
573 (DeriveTrait::Default, TypeKind::ObjCInterface(..)) |
574 (DeriveTrait::Default, TypeKind::ObjCId) |
575 (DeriveTrait::Default, TypeKind::ObjCSel) => {
576 trace!(" types that always cannot derive Default");
577 CanDerive::No
578 }
579 (DeriveTrait::Default, TypeKind::UnresolvedTypeRef(..)) => {
580 unreachable!(
581 "Type with unresolved type ref can't reach derive default"
582 )
583 }
584 (DeriveTrait::Hash, TypeKind::Float(..)) |
586 (DeriveTrait::Hash, TypeKind::Complex(..)) => {
587 trace!(" float cannot derive Hash");
588 CanDerive::No
589 }
590 _ => {
592 trace!(" simple type that can always derive {self}");
593 CanDerive::Yes
594 }
595 }
596 }
597}
598
599impl fmt::Display for DeriveTrait {
600 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
601 let s = match self {
602 DeriveTrait::Copy => "Copy",
603 DeriveTrait::Debug => "Debug",
604 DeriveTrait::Default => "Default",
605 DeriveTrait::Hash => "Hash",
606 DeriveTrait::PartialEqOrPartialOrd => "PartialEq/PartialOrd",
607 };
608 s.fmt(f)
609 }
610}
611
612impl<'ctx> MonotoneFramework for CannotDerive<'ctx> {
613 type Node = ItemId;
614 type Extra = (&'ctx BindgenContext, DeriveTrait);
615 type Output = HashMap<ItemId, CanDerive>;
616
617 fn new(
618 (ctx, derive_trait): (&'ctx BindgenContext, DeriveTrait),
619 ) -> CannotDerive<'ctx> {
620 let can_derive = HashMap::default();
621 let dependencies = generate_dependencies(ctx, consider_edge_default);
622
623 CannotDerive {
624 ctx,
625 derive_trait,
626 can_derive,
627 dependencies,
628 }
629 }
630
631 fn initial_worklist(&self) -> Vec<ItemId> {
632 self.ctx
635 .allowlisted_items()
636 .iter()
637 .copied()
638 .flat_map(|i| {
639 let mut reachable = vec![i];
640 i.trace(
641 self.ctx,
642 &mut |s, _| {
643 reachable.push(s);
644 },
645 &(),
646 );
647 reachable
648 })
649 .collect()
650 }
651
652 fn constrain(&mut self, id: ItemId) -> ConstrainResult {
653 trace!("constrain: {id:?}");
654
655 if let Some(CanDerive::No) = self.can_derive.get(&id) {
656 trace!(" already know it cannot derive {}", self.derive_trait);
657 return ConstrainResult::Same;
658 }
659
660 let item = self.ctx.resolve_item(id);
661 let can_derive = match item.as_type() {
662 Some(ty) => {
663 let mut can_derive = self.constrain_type(item, ty);
664 if let CanDerive::Yes = can_derive {
665 let is_reached_limit =
666 |l: Layout| l.align > RUST_DERIVE_IN_ARRAY_LIMIT;
667 if !self.derive_trait.can_derive_large_array(self.ctx) &&
668 ty.layout(self.ctx).is_some_and(is_reached_limit)
669 {
670 can_derive = CanDerive::Manually;
676 }
677 }
678 can_derive
679 }
680 None => self.constrain_join(item, consider_edge_default),
681 };
682
683 self.insert(id, can_derive)
684 }
685
686 fn each_depending_on<F>(&self, id: ItemId, mut f: F)
687 where
688 F: FnMut(ItemId),
689 {
690 if let Some(edges) = self.dependencies.get(&id) {
691 for item in edges {
692 trace!("enqueue {item:?} into worklist");
693 f(*item);
694 }
695 }
696 }
697}
698
699impl<'ctx> From<CannotDerive<'ctx>> for HashMap<ItemId, CanDerive> {
700 fn from(analysis: CannotDerive<'ctx>) -> Self {
701 extra_assert!(analysis
702 .can_derive
703 .values()
704 .all(|v| *v != CanDerive::Yes));
705
706 analysis.can_derive
707 }
708}
709
710pub(crate) fn as_cannot_derive_set(
715 can_derive: HashMap<ItemId, CanDerive>,
716) -> HashSet<ItemId> {
717 can_derive
718 .into_iter()
719 .filter_map(|(k, v)| if v == CanDerive::Yes { None } else { Some(k) })
720 .collect()
721}