summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/callbacks.rs19
-rw-r--r--src/ir/analysis/derive.rs25
-rw-r--r--src/ir/context.rs38
3 files changed, 75 insertions, 7 deletions
diff --git a/src/callbacks.rs b/src/callbacks.rs
index 1cd7f37b..e288af43 100644
--- a/src/callbacks.rs
+++ b/src/callbacks.rs
@@ -1,5 +1,7 @@
//! A public API for more fine-grained customization of bindgen behavior.
+pub use crate::ir::analysis::DeriveTrait;
+pub use crate::ir::derive::CanDerive as ImplementsTrait;
pub use crate::ir::enum_ty::{EnumVariantCustomBehavior, EnumVariantValue};
pub use crate::ir::int::IntKind;
use std::fmt;
@@ -76,4 +78,21 @@ pub trait ParseCallbacks: fmt::Debug + UnwindSafe {
/// This will be called on every file inclusion, with the full path of the included file.
fn include_file(&self, _filename: &str) {}
+
+ /// This will be called to determine whether a particular blocklisted type
+ /// implements a trait or not. This will be used to implement traits on
+ /// other types containing the blocklisted type.
+ ///
+ /// * `None`: use the default behavior
+ /// * `Some(ImplementsTrait::Yes)`: `_name` implements `_derive_trait`
+ /// * `Some(ImplementsTrait::Manually)`: any type including `_name` can't
+ /// derive `_derive_trait` but can implemented it manually
+ /// * `Some(ImplementsTrait::No)`: `_name` doesn't implement `_derive_trait`
+ fn blocklisted_type_implements_trait(
+ &self,
+ _name: &str,
+ _derive_trait: DeriveTrait,
+ ) -> Option<ImplementsTrait> {
+ None
+ }
}
diff --git a/src/ir/analysis/derive.rs b/src/ir/analysis/derive.rs
index fa4ce795..be626661 100644
--- a/src/ir/analysis/derive.rs
+++ b/src/ir/analysis/derive.rs
@@ -16,7 +16,7 @@ use crate::ir::ty::{Type, TypeKind};
use crate::{Entry, HashMap, HashSet};
/// Which trait to consider when doing the `CannotDerive` analysis.
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum DeriveTrait {
/// The `Copy` trait.
Copy,
@@ -139,11 +139,24 @@ impl<'ctx> CannotDerive<'ctx> {
fn constrain_type(&mut self, item: &Item, ty: &Type) -> CanDerive {
if !self.ctx.allowlisted_items().contains(&item.id()) {
- trace!(
- " cannot derive {} for blocklisted type",
- self.derive_trait
- );
- return CanDerive::No;
+ 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) {
diff --git a/src/ir/context.rs b/src/ir/context.rs
index a0d4de1e..ccb05e75 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -28,7 +28,7 @@ use cexpr;
use clang_sys;
use proc_macro2::{Ident, Span};
use std::borrow::Cow;
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
use std::collections::HashMap as StdHashMap;
use std::iter::IntoIterator;
use std::mem;
@@ -380,6 +380,10 @@ pub struct BindgenContext {
/// computed after parsing our IR, and before running any of our analyses.
allowlisted: Option<ItemSet>,
+ /// Cache for calls to `ParseCallbacks::blocklisted_type_implements_trait`
+ blocklisted_types_implement_traits:
+ RefCell<HashMap<DeriveTrait, HashMap<ItemId, CanDerive>>>,
+
/// The set of `ItemId`s that are allowlisted for code generation _and_ that
/// we should generate accounting for the codegen options.
///
@@ -560,6 +564,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
options,
generated_bindgen_complex: Cell::new(false),
allowlisted: None,
+ blocklisted_types_implement_traits: Default::default(),
codegen_items: None,
used_template_parameters: None,
need_bitfield_allocation: Default::default(),
@@ -2205,6 +2210,37 @@ If you encounter an error missing from this list, please file an issue or a PR!"
self.allowlisted.as_ref().unwrap()
}
+ /// Check whether a particular blocklisted type implements a trait or not.
+ /// Results may be cached.
+ pub fn blocklisted_type_implements_trait(
+ &self,
+ item: &Item,
+ derive_trait: DeriveTrait,
+ ) -> CanDerive {
+ assert!(self.in_codegen_phase());
+ assert!(self.current_module == self.root_module);
+
+ let cb = match self.options.parse_callbacks {
+ Some(ref cb) => cb,
+ None => return CanDerive::No,
+ };
+
+ *self
+ .blocklisted_types_implement_traits
+ .borrow_mut()
+ .entry(derive_trait)
+ .or_default()
+ .entry(item.id())
+ .or_insert_with(|| {
+ item.expect_type()
+ .name()
+ .and_then(|name| {
+ cb.blocklisted_type_implements_trait(name, derive_trait)
+ })
+ .unwrap_or(CanDerive::No)
+ })
+ }
+
/// Get a reference to the set of items we should generate.
pub fn codegen_items(&self) -> &ItemSet {
assert!(self.in_codegen_phase());