summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/callbacks.rs106
-rw-r--r--src/clang.rs2216
-rw-r--r--src/codegen/bitfield_unit.rs102
-rw-r--r--src/codegen/bitfield_unit_tests.rs260
-rw-r--r--src/codegen/dyngen.rs181
-rw-r--r--src/codegen/error.rs33
-rw-r--r--src/codegen/helpers.rs309
-rw-r--r--src/codegen/impl_debug.rs245
-rw-r--r--src/codegen/impl_partialeq.rs142
-rw-r--r--src/codegen/mod.rs5050
-rw-r--r--src/codegen/postprocessing/merge_extern_blocks.rs46
-rw-r--r--src/codegen/postprocessing/mod.rs66
-rw-r--r--src/codegen/postprocessing/sort_semantically.rs24
-rw-r--r--src/codegen/struct_layout.rs444
-rw-r--r--src/deps.rs20
-rw-r--r--src/extra_assertions.rs34
-rw-r--r--src/features.rs313
-rw-r--r--src/ir/analysis/derive.rs732
-rw-r--r--src/ir/analysis/has_destructor.rs176
-rw-r--r--src/ir/analysis/has_float.rs252
-rw-r--r--src/ir/analysis/has_type_param_in_array.rs252
-rw-r--r--src/ir/analysis/has_vtable.rs240
-rw-r--r--src/ir/analysis/mod.rs402
-rw-r--r--src/ir/analysis/sizedness.rs361
-rw-r--r--src/ir/analysis/template_params.rs608
-rw-r--r--src/ir/annotations.rs211
-rw-r--r--src/ir/comment.rs119
-rw-r--r--src/ir/comp.rs1891
-rw-r--r--src/ir/context.rs2855
-rw-r--r--src/ir/derive.rs135
-rw-r--r--src/ir/dot.rs86
-rw-r--r--src/ir/enum_ty.rs320
-rw-r--r--src/ir/function.rs690
-rw-r--r--src/ir/int.rs127
-rw-r--r--src/ir/item.rs2018
-rw-r--r--src/ir/item_kind.rs147
-rw-r--r--src/ir/layout.rs143
-rw-r--r--src/ir/mod.rs24
-rw-r--r--src/ir/module.rs95
-rw-r--r--src/ir/objc.rs329
-rw-r--r--src/ir/template.rs343
-rw-r--r--src/ir/traversal.rs478
-rw-r--r--src/ir/ty.rs1266
-rw-r--r--src/ir/var.rs413
-rw-r--r--src/lib.rs2928
-rw-r--r--src/log_stubs.rs32
-rw-r--r--src/main.rs109
-rw-r--r--src/options.rs1092
-rw-r--r--src/parse.rs102
-rw-r--r--src/regex_set.rs92
-rw-r--r--src/time.rs52
51 files changed, 0 insertions, 28711 deletions
diff --git a/src/callbacks.rs b/src/callbacks.rs
deleted file mode 100644
index 9b345449..00000000
--- a/src/callbacks.rs
+++ /dev/null
@@ -1,106 +0,0 @@
-//! 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;
-use std::panic::UnwindSafe;
-
-/// An enum to allow ignoring parsing of macros.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum MacroParsingBehavior {
- /// Ignore the macro, generating no code for it, or anything that depends on
- /// it.
- Ignore,
- /// The default behavior bindgen would have otherwise.
- Default,
-}
-
-impl Default for MacroParsingBehavior {
- fn default() -> Self {
- MacroParsingBehavior::Default
- }
-}
-
-/// A trait to allow configuring different kinds of types in different
-/// situations.
-pub trait ParseCallbacks: fmt::Debug + UnwindSafe {
- /// This function will be run on every macro that is identified.
- fn will_parse_macro(&self, _name: &str) -> MacroParsingBehavior {
- MacroParsingBehavior::Default
- }
-
- /// The integer kind an integer macro should have, given a name and the
- /// value of that macro, or `None` if you want the default to be chosen.
- fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> {
- None
- }
-
- /// This will be run on every string macro. The callback cannot influence the further
- /// treatment of the macro, but may use the value to generate additional code or configuration.
- fn str_macro(&self, _name: &str, _value: &[u8]) {}
-
- /// This will be run on every function-like macro. The callback cannot
- /// influence the further treatment of the macro, but may use the value to
- /// generate additional code or configuration.
- ///
- /// The first parameter represents the name and argument list (including the
- /// parentheses) of the function-like macro. The second parameter represents
- /// the expansion of the macro as a sequence of tokens.
- fn func_macro(&self, _name: &str, _value: &[&[u8]]) {}
-
- /// This function should return whether, given an enum variant
- /// name, and value, this enum variant will forcibly be a constant.
- fn enum_variant_behavior(
- &self,
- _enum_name: Option<&str>,
- _original_variant_name: &str,
- _variant_value: EnumVariantValue,
- ) -> Option<EnumVariantCustomBehavior> {
- None
- }
-
- /// Allows to rename an enum variant, replacing `_original_variant_name`.
- fn enum_variant_name(
- &self,
- _enum_name: Option<&str>,
- _original_variant_name: &str,
- _variant_value: EnumVariantValue,
- ) -> Option<String> {
- None
- }
-
- /// Allows to rename an item, replacing `_original_item_name`.
- fn item_name(&self, _original_item_name: &str) -> Option<String> {
- None
- }
-
- /// 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
- }
-
- /// Provide a list of custom derive attributes.
- ///
- /// If no additional attributes are wanted, this function should return an
- /// empty `Vec`.
- fn add_derives(&self, _name: &str) -> Vec<String> {
- vec![]
- }
-}
diff --git a/src/clang.rs b/src/clang.rs
deleted file mode 100644
index ea505c87..00000000
--- a/src/clang.rs
+++ /dev/null
@@ -1,2216 +0,0 @@
-//! A higher level Clang API built on top of the generated bindings in the
-//! `clang_sys` module.
-
-#![allow(non_upper_case_globals, dead_code)]
-
-use crate::ir::context::BindgenContext;
-use clang_sys::*;
-use std::ffi::{CStr, CString};
-use std::fmt;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::os::raw::{c_char, c_int, c_longlong, c_uint, c_ulong, c_ulonglong};
-use std::{mem, ptr, slice};
-
-/// Type representing a clang attribute.
-///
-/// Values of this type can be used to check for different attributes using the `has_attrs`
-/// function.
-pub struct Attribute {
- name: &'static [u8],
- kind: Option<CXCursorKind>,
- token_kind: CXTokenKind,
-}
-
-impl Attribute {
- /// A `warn_unused_result` attribute.
- pub const MUST_USE: Self = Self {
- name: b"warn_unused_result",
- // FIXME(emilio): clang-sys doesn't expose `CXCursor_WarnUnusedResultAttr` (from clang 9).
- kind: Some(440),
- token_kind: CXToken_Identifier,
- };
-
- /// A `_Noreturn` attribute.
- pub const NO_RETURN: Self = Self {
- name: b"_Noreturn",
- kind: None,
- token_kind: CXToken_Keyword,
- };
-
- /// A `[[noreturn]]` attribute.
- pub const NO_RETURN_CPP: Self = Self {
- name: b"noreturn",
- kind: None,
- token_kind: CXToken_Identifier,
- };
-}
-
-/// A cursor into the Clang AST, pointing to an AST node.
-///
-/// We call the AST node pointed to by the cursor the cursor's "referent".
-#[derive(Copy, Clone)]
-pub struct Cursor {
- x: CXCursor,
-}
-
-impl fmt::Debug for Cursor {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(
- fmt,
- "Cursor({} kind: {}, loc: {}, usr: {:?})",
- self.spelling(),
- kind_to_str(self.kind()),
- self.location(),
- self.usr()
- )
- }
-}
-
-impl Cursor {
- /// Get the Unified Symbol Resolution for this cursor's referent, if
- /// available.
- ///
- /// The USR can be used to compare entities across translation units.
- pub fn usr(&self) -> Option<String> {
- let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) };
- if s.is_empty() {
- None
- } else {
- Some(s)
- }
- }
-
- /// Is this cursor's referent a declaration?
- pub fn is_declaration(&self) -> bool {
- unsafe { clang_isDeclaration(self.kind()) != 0 }
- }
-
- /// Get this cursor's referent's spelling.
- pub fn spelling(&self) -> String {
- unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) }
- }
-
- /// Get this cursor's referent's display name.
- ///
- /// This is not necessarily a valid identifier. It includes extra
- /// information, such as parameters for a function, etc.
- pub fn display_name(&self) -> String {
- unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) }
- }
-
- /// Get the mangled name of this cursor's referent.
- pub fn mangling(&self) -> String {
- unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) }
- }
-
- /// Gets the C++ manglings for this cursor, or an error if the manglings
- /// are not available.
- pub fn cxx_manglings(&self) -> Result<Vec<String>, ()> {
- use clang_sys::*;
- unsafe {
- let manglings = clang_Cursor_getCXXManglings(self.x);
- if manglings.is_null() {
- return Err(());
- }
- let count = (*manglings).Count as usize;
-
- let mut result = Vec::with_capacity(count);
- for i in 0..count {
- let string_ptr = (*manglings).Strings.add(i);
- result.push(cxstring_to_string_leaky(*string_ptr));
- }
- clang_disposeStringSet(manglings);
- Ok(result)
- }
- }
-
- /// Returns whether the cursor refers to a built-in definition.
- pub fn is_builtin(&self) -> bool {
- let (file, _, _, _) = self.location().location();
- file.name().is_none()
- }
-
- /// Get the `Cursor` for this cursor's referent's lexical parent.
- ///
- /// The lexical parent is the parent of the definition. The semantic parent
- /// is the parent of the declaration. Generally, the lexical parent doesn't
- /// have any effect on semantics, while the semantic parent does.
- ///
- /// In the following snippet, the `Foo` class would be the semantic parent
- /// of the out-of-line `method` definition, while the lexical parent is the
- /// translation unit.
- ///
- /// ```c++
- /// class Foo {
- /// void method();
- /// };
- ///
- /// void Foo::method() { /* ... */ }
- /// ```
- pub fn lexical_parent(&self) -> Cursor {
- unsafe {
- Cursor {
- x: clang_getCursorLexicalParent(self.x),
- }
- }
- }
-
- /// Get the referent's semantic parent, if one is available.
- ///
- /// See documentation for `lexical_parent` for details on semantic vs
- /// lexical parents.
- pub fn fallible_semantic_parent(&self) -> Option<Cursor> {
- let sp = unsafe {
- Cursor {
- x: clang_getCursorSemanticParent(self.x),
- }
- };
- if sp == *self || !sp.is_valid() {
- return None;
- }
- Some(sp)
- }
-
- /// Get the referent's semantic parent.
- ///
- /// See documentation for `lexical_parent` for details on semantic vs
- /// lexical parents.
- pub fn semantic_parent(&self) -> Cursor {
- self.fallible_semantic_parent().unwrap()
- }
-
- /// Return the number of template arguments used by this cursor's referent,
- /// if the referent is either a template instantiation. Returns `None`
- /// otherwise.
- ///
- /// NOTE: This may not return `Some` for partial template specializations,
- /// see #193 and #194.
- pub fn num_template_args(&self) -> Option<u32> {
- // XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while
- // `clang_Cursor_getNumTemplateArguments` is totally unreliable.
- // Therefore, try former first, and only fallback to the latter if we
- // have to.
- self.cur_type()
- .num_template_args()
- .or_else(|| {
- let n: c_int =
- unsafe { clang_Cursor_getNumTemplateArguments(self.x) };
-
- if n >= 0 {
- Some(n as u32)
- } else {
- debug_assert_eq!(n, -1);
- None
- }
- })
- .or_else(|| {
- let canonical = self.canonical();
- if canonical != *self {
- canonical.num_template_args()
- } else {
- None
- }
- })
- }
-
- /// Get a cursor pointing to this referent's containing translation unit.
- ///
- /// Note that we shouldn't create a `TranslationUnit` struct here, because
- /// bindgen assumes there will only be one of them alive at a time, and
- /// disposes it on drop. That can change if this would be required, but I
- /// think we can survive fine without it.
- pub fn translation_unit(&self) -> Cursor {
- assert!(self.is_valid());
- unsafe {
- let tu = clang_Cursor_getTranslationUnit(self.x);
- let cursor = Cursor {
- x: clang_getTranslationUnitCursor(tu),
- };
- assert!(cursor.is_valid());
- cursor
- }
- }
-
- /// Is the referent a top level construct?
- pub fn is_toplevel(&self) -> bool {
- let mut semantic_parent = self.fallible_semantic_parent();
-
- while semantic_parent.is_some() &&
- (semantic_parent.unwrap().kind() == CXCursor_Namespace ||
- semantic_parent.unwrap().kind() ==
- CXCursor_NamespaceAlias ||
- semantic_parent.unwrap().kind() == CXCursor_NamespaceRef)
- {
- semantic_parent =
- semantic_parent.unwrap().fallible_semantic_parent();
- }
-
- let tu = self.translation_unit();
- // Yes, this can happen with, e.g., macro definitions.
- semantic_parent == tu.fallible_semantic_parent()
- }
-
- /// There are a few kinds of types that we need to treat specially, mainly
- /// not tracking the type declaration but the location of the cursor, given
- /// clang doesn't expose a proper declaration for these types.
- pub fn is_template_like(&self) -> bool {
- matches!(
- self.kind(),
- CXCursor_ClassTemplate |
- CXCursor_ClassTemplatePartialSpecialization |
- CXCursor_TypeAliasTemplateDecl
- )
- }
-
- /// Is this Cursor pointing to a function-like macro definition?
- pub fn is_macro_function_like(&self) -> bool {
- unsafe { clang_Cursor_isMacroFunctionLike(self.x) != 0 }
- }
-
- /// Get the kind of referent this cursor is pointing to.
- pub fn kind(&self) -> CXCursorKind {
- self.x.kind
- }
-
- /// Returns true if the cursor is a definition
- pub fn is_definition(&self) -> bool {
- unsafe { clang_isCursorDefinition(self.x) != 0 }
- }
-
- /// Is the referent a template specialization?
- pub fn is_template_specialization(&self) -> bool {
- self.specialized().is_some()
- }
-
- /// Is the referent a fully specialized template specialization without any
- /// remaining free template arguments?
- pub fn is_fully_specialized_template(&self) -> bool {
- self.is_template_specialization() &&
- self.kind() != CXCursor_ClassTemplatePartialSpecialization &&
- self.num_template_args().unwrap_or(0) > 0
- }
-
- /// Is the referent a template specialization that still has remaining free
- /// template arguments?
- pub fn is_in_non_fully_specialized_template(&self) -> bool {
- if self.is_toplevel() {
- return false;
- }
-
- let parent = self.semantic_parent();
- if parent.is_fully_specialized_template() {
- return false;
- }
-
- if !parent.is_template_like() {
- return parent.is_in_non_fully_specialized_template();
- }
-
- true
- }
-
- /// Is the referent any kind of template parameter?
- pub fn is_template_parameter(&self) -> bool {
- matches!(
- self.kind(),
- CXCursor_TemplateTemplateParameter |
- CXCursor_TemplateTypeParameter |
- CXCursor_NonTypeTemplateParameter
- )
- }
-
- /// Does the referent's type or value depend on a template parameter?
- pub fn is_dependent_on_template_parameter(&self) -> bool {
- fn visitor(
- found_template_parameter: &mut bool,
- cur: Cursor,
- ) -> CXChildVisitResult {
- // If we found a template parameter, it is dependent.
- if cur.is_template_parameter() {
- *found_template_parameter = true;
- return CXChildVisit_Break;
- }
-
- // Get the referent and traverse it as well.
- if let Some(referenced) = cur.referenced() {
- if referenced.is_template_parameter() {
- *found_template_parameter = true;
- return CXChildVisit_Break;
- }
-
- referenced
- .visit(|next| visitor(found_template_parameter, next));
- if *found_template_parameter {
- return CXChildVisit_Break;
- }
- }
-
- // Continue traversing the AST at the original cursor.
- CXChildVisit_Recurse
- }
-
- if self.is_template_parameter() {
- return true;
- }
-
- let mut found_template_parameter = false;
- self.visit(|next| visitor(&mut found_template_parameter, next));
-
- found_template_parameter
- }
-
- /// Is this cursor pointing a valid referent?
- pub fn is_valid(&self) -> bool {
- unsafe { clang_isInvalid(self.kind()) == 0 }
- }
-
- /// Get the source location for the referent.
- pub fn location(&self) -> SourceLocation {
- unsafe {
- SourceLocation {
- x: clang_getCursorLocation(self.x),
- }
- }
- }
-
- /// Get the source location range for the referent.
- pub fn extent(&self) -> CXSourceRange {
- unsafe { clang_getCursorExtent(self.x) }
- }
-
- /// Get the raw declaration comment for this referent, if one exists.
- pub fn raw_comment(&self) -> Option<String> {
- let s = unsafe {
- cxstring_into_string(clang_Cursor_getRawCommentText(self.x))
- };
- if s.is_empty() {
- None
- } else {
- Some(s)
- }
- }
-
- /// Get the referent's parsed comment.
- pub fn comment(&self) -> Comment {
- unsafe {
- Comment {
- x: clang_Cursor_getParsedComment(self.x),
- }
- }
- }
-
- /// Get the referent's type.
- pub fn cur_type(&self) -> Type {
- unsafe {
- Type {
- x: clang_getCursorType(self.x),
- }
- }
- }
-
- /// Given that this cursor's referent is a reference to another type, or is
- /// a declaration, get the cursor pointing to the referenced type or type of
- /// the declared thing.
- pub fn definition(&self) -> Option<Cursor> {
- unsafe {
- let ret = Cursor {
- x: clang_getCursorDefinition(self.x),
- };
-
- if ret.is_valid() && ret.kind() != CXCursor_NoDeclFound {
- Some(ret)
- } else {
- None
- }
- }
- }
-
- /// Given that this cursor's referent is reference type, get the cursor
- /// pointing to the referenced type.
- pub fn referenced(&self) -> Option<Cursor> {
- unsafe {
- let ret = Cursor {
- x: clang_getCursorReferenced(self.x),
- };
-
- if ret.is_valid() {
- Some(ret)
- } else {
- None
- }
- }
- }
-
- /// Get the canonical cursor for this referent.
- ///
- /// Many types can be declared multiple times before finally being properly
- /// defined. This method allows us to get the canonical cursor for the
- /// referent type.
- pub fn canonical(&self) -> Cursor {
- unsafe {
- Cursor {
- x: clang_getCanonicalCursor(self.x),
- }
- }
- }
-
- /// Given that this cursor points to either a template specialization or a
- /// template instantiation, get a cursor pointing to the template definition
- /// that is being specialized.
- pub fn specialized(&self) -> Option<Cursor> {
- unsafe {
- let ret = Cursor {
- x: clang_getSpecializedCursorTemplate(self.x),
- };
- if ret.is_valid() {
- Some(ret)
- } else {
- None
- }
- }
- }
-
- /// Assuming that this cursor's referent is a template declaration, get the
- /// kind of cursor that would be generated for its specializations.
- pub fn template_kind(&self) -> CXCursorKind {
- unsafe { clang_getTemplateCursorKind(self.x) }
- }
-
- /// Traverse this cursor's referent and its children.
- ///
- /// Call the given function on each AST node traversed.
- pub fn visit<Visitor>(&self, mut visitor: Visitor)
- where
- Visitor: FnMut(Cursor) -> CXChildVisitResult,
- {
- let data = &mut visitor as *mut Visitor;
- unsafe {
- clang_visitChildren(self.x, visit_children::<Visitor>, data.cast());
- }
- }
-
- /// Collect all of this cursor's children into a vec and return them.
- pub fn collect_children(&self) -> Vec<Cursor> {
- let mut children = vec![];
- self.visit(|c| {
- children.push(c);
- CXChildVisit_Continue
- });
- children
- }
-
- /// Does this cursor have any children?
- pub fn has_children(&self) -> bool {
- let mut has_children = false;
- self.visit(|_| {
- has_children = true;
- CXChildVisit_Break
- });
- has_children
- }
-
- /// Does this cursor have at least `n` children?
- pub fn has_at_least_num_children(&self, n: usize) -> bool {
- assert!(n > 0);
- let mut num_left = n;
- self.visit(|_| {
- num_left -= 1;
- if num_left == 0 {
- CXChildVisit_Break
- } else {
- CXChildVisit_Continue
- }
- });
- num_left == 0
- }
-
- /// Returns whether the given location contains a cursor with the given
- /// kind in the first level of nesting underneath (doesn't look
- /// recursively).
- pub fn contains_cursor(&self, kind: CXCursorKind) -> bool {
- let mut found = false;
-
- self.visit(|c| {
- if c.kind() == kind {
- found = true;
- CXChildVisit_Break
- } else {
- CXChildVisit_Continue
- }
- });
-
- found
- }
-
- /// Is the referent an inlined function?
- pub fn is_inlined_function(&self) -> bool {
- unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 }
- }
-
- /// Is the referent a defaulted function?
- pub fn is_defaulted_function(&self) -> bool {
- unsafe { clang_CXXMethod_isDefaulted(self.x) != 0 }
- }
-
- /// Is the referent a deleted function?
- pub fn is_deleted_function(&self) -> bool {
- // Unfortunately, libclang doesn't yet have an API for checking if a
- // member function is deleted, but the following should be a good
- // enough approximation.
- // Deleted functions are implicitly inline according to paragraph 4 of
- // [dcl.fct.def.delete] in the C++ standard. Normal inline functions
- // have a definition in the same translation unit, so if this is an
- // inline function without a definition, and it's not a defaulted
- // function, we can reasonably safely conclude that it's a deleted
- // function.
- self.is_inlined_function() &&
- self.definition().is_none() &&
- !self.is_defaulted_function()
- }
-
- /// Is the referent a bit field declaration?
- pub fn is_bit_field(&self) -> bool {
- unsafe { clang_Cursor_isBitField(self.x) != 0 }
- }
-
- /// Get a cursor to the bit field's width expression, or `None` if it's not
- /// a bit field.
- pub fn bit_width_expr(&self) -> Option<Cursor> {
- if !self.is_bit_field() {
- return None;
- }
-
- let mut result = None;
- self.visit(|cur| {
- // The first child may or may not be a TypeRef, depending on whether
- // the field's type is builtin. Skip it.
- if cur.kind() == CXCursor_TypeRef {
- return CXChildVisit_Continue;
- }
-
- // The next expression or literal is the bit width.
- result = Some(cur);
-
- CXChildVisit_Break
- });
-
- result
- }
-
- /// Get the width of this cursor's referent bit field, or `None` if the
- /// referent is not a bit field or if the width could not be evaluated.
- pub fn bit_width(&self) -> Option<u32> {
- // It is not safe to check the bit width without ensuring it doesn't
- // depend on a template parameter. See
- // https://github.com/rust-lang/rust-bindgen/issues/2239
- if self.bit_width_expr()?.is_dependent_on_template_parameter() {
- return None;
- }
-
- unsafe {
- let w = clang_getFieldDeclBitWidth(self.x);
- if w == -1 {
- None
- } else {
- Some(w as u32)
- }
- }
- }
-
- /// Get the integer representation type used to hold this cursor's referent
- /// enum type.
- pub fn enum_type(&self) -> Option<Type> {
- unsafe {
- let t = Type {
- x: clang_getEnumDeclIntegerType(self.x),
- };
- if t.is_valid() {
- Some(t)
- } else {
- None
- }
- }
- }
-
- /// Get the boolean constant value for this cursor's enum variant referent.
- ///
- /// Returns None if the cursor's referent is not an enum variant.
- pub fn enum_val_boolean(&self) -> Option<bool> {
- unsafe {
- if self.kind() == CXCursor_EnumConstantDecl {
- Some(clang_getEnumConstantDeclValue(self.x) != 0)
- } else {
- None
- }
- }
- }
-
- /// Get the signed constant value for this cursor's enum variant referent.
- ///
- /// Returns None if the cursor's referent is not an enum variant.
- pub fn enum_val_signed(&self) -> Option<i64> {
- unsafe {
- if self.kind() == CXCursor_EnumConstantDecl {
- Some(clang_getEnumConstantDeclValue(self.x) as i64)
- } else {
- None
- }
- }
- }
-
- /// Get the unsigned constant value for this cursor's enum variant referent.
- ///
- /// Returns None if the cursor's referent is not an enum variant.
- pub fn enum_val_unsigned(&self) -> Option<u64> {
- unsafe {
- if self.kind() == CXCursor_EnumConstantDecl {
- Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64)
- } else {
- None
- }
- }
- }
-
- /// Does this cursor have the given attributes?
- pub fn has_attrs<const N: usize>(
- &self,
- attrs: &[Attribute; N],
- ) -> [bool; N] {
- let mut found_attrs = [false; N];
- let mut found_count = 0;
-
- self.visit(|cur| {
- let kind = cur.kind();
- for (idx, attr) in attrs.iter().enumerate() {
- let found_attr = &mut found_attrs[idx];
- if !*found_attr {
- // `attr.name` and` attr.token_kind` are checked against unexposed attributes only.
- if attr.kind.map_or(false, |k| k == kind) ||
- (kind == CXCursor_UnexposedAttr &&
- cur.tokens().iter().any(|t| {
- t.kind == attr.token_kind &&
- t.spelling() == attr.name
- }))
- {
- *found_attr = true;
- found_count += 1;
-
- if found_count == N {
- return CXChildVisit_Break;
- }
- }
- }
- }
-
- CXChildVisit_Continue
- });
-
- found_attrs
- }
-
- /// Given that this cursor's referent is a `typedef`, get the `Type` that is
- /// being aliased.
- pub fn typedef_type(&self) -> Option<Type> {
- let inner = Type {
- x: unsafe { clang_getTypedefDeclUnderlyingType(self.x) },
- };
-
- if inner.is_valid() {
- Some(inner)
- } else {
- None
- }
- }
-
- /// Get the linkage kind for this cursor's referent.
- ///
- /// This only applies to functions and variables.
- pub fn linkage(&self) -> CXLinkageKind {
- unsafe { clang_getCursorLinkage(self.x) }
- }
-
- /// Get the visibility of this cursor's referent.
- pub fn visibility(&self) -> CXVisibilityKind {
- unsafe { clang_getCursorVisibility(self.x) }
- }
-
- /// Given that this cursor's referent is a function, return cursors to its
- /// parameters.
- ///
- /// Returns None if the cursor's referent is not a function/method call or
- /// declaration.
- pub fn args(&self) -> Option<Vec<Cursor>> {
- // match self.kind() {
- // CXCursor_FunctionDecl |
- // CXCursor_CXXMethod => {
- self.num_args().ok().map(|num| {
- (0..num)
- .map(|i| Cursor {
- x: unsafe { clang_Cursor_getArgument(self.x, i as c_uint) },
- })
- .collect()
- })
- }
-
- /// Given that this cursor's referent is a function/method call or
- /// declaration, return the number of arguments it takes.
- ///
- /// Returns Err if the cursor's referent is not a function/method call or
- /// declaration.
- pub fn num_args(&self) -> Result<u32, ()> {
- unsafe {
- let w = clang_Cursor_getNumArguments(self.x);
- if w == -1 {
- Err(())
- } else {
- Ok(w as u32)
- }
- }
- }
-
- /// Get the access specifier for this cursor's referent.
- pub fn access_specifier(&self) -> CX_CXXAccessSpecifier {
- unsafe { clang_getCXXAccessSpecifier(self.x) }
- }
-
- /// Is the cursor's referrent publically accessible in C++?
- ///
- /// Returns true if self.access_specifier() is `CX_CXXPublic` or
- /// `CX_CXXInvalidAccessSpecifier`.
- pub fn public_accessible(&self) -> bool {
- let access = self.access_specifier();
- access == CX_CXXPublic || access == CX_CXXInvalidAccessSpecifier
- }
-
- /// Is this cursor's referent a field declaration that is marked as
- /// `mutable`?
- pub fn is_mutable_field(&self) -> bool {
- unsafe { clang_CXXField_isMutable(self.x) != 0 }
- }
-
- /// Get the offset of the field represented by the Cursor.
- pub fn offset_of_field(&self) -> Result<usize, LayoutError> {
- let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) };
-
- if offset < 0 {
- Err(LayoutError::from(offset as i32))
- } else {
- Ok(offset as usize)
- }
- }
-
- /// Is this cursor's referent a member function that is declared `static`?
- pub fn method_is_static(&self) -> bool {
- unsafe { clang_CXXMethod_isStatic(self.x) != 0 }
- }
-
- /// Is this cursor's referent a member function that is declared `const`?
- pub fn method_is_const(&self) -> bool {
- unsafe { clang_CXXMethod_isConst(self.x) != 0 }
- }
-
- /// Is this cursor's referent a member function that is virtual?
- pub fn method_is_virtual(&self) -> bool {
- unsafe { clang_CXXMethod_isVirtual(self.x) != 0 }
- }
-
- /// Is this cursor's referent a member function that is pure virtual?
- pub fn method_is_pure_virtual(&self) -> bool {
- unsafe { clang_CXXMethod_isPureVirtual(self.x) != 0 }
- }
-
- /// Is this cursor's referent a struct or class with virtual members?
- pub fn is_virtual_base(&self) -> bool {
- unsafe { clang_isVirtualBase(self.x) != 0 }
- }
-
- /// Try to evaluate this cursor.
- pub fn evaluate(&self) -> Option<EvalResult> {
- EvalResult::new(*self)
- }
-
- /// Return the result type for this cursor
- pub fn ret_type(&self) -> Option<Type> {
- let rt = Type {
- x: unsafe { clang_getCursorResultType(self.x) },
- };
- if rt.is_valid() {
- Some(rt)
- } else {
- None
- }
- }
-
- /// Gets the tokens that correspond to that cursor.
- pub fn tokens(&self) -> RawTokens {
- RawTokens::new(self)
- }
-
- /// Gets the tokens that correspond to that cursor as `cexpr` tokens.
- pub fn cexpr_tokens(self) -> Vec<cexpr::token::Token> {
- self.tokens()
- .iter()
- .filter_map(|token| token.as_cexpr_token())
- .collect()
- }
-
- /// Obtain the real path name of a cursor of InclusionDirective kind.
- ///
- /// Returns None if the cursor does not include a file, otherwise the file's full name
- pub fn get_included_file_name(&self) -> Option<String> {
- let file = unsafe { clang_sys::clang_getIncludedFile(self.x) };
- if file.is_null() {
- None
- } else {
- Some(unsafe {
- cxstring_into_string(clang_sys::clang_getFileName(file))
- })
- }
- }
-}
-
-/// A struct that owns the tokenizer result from a given cursor.
-pub struct RawTokens<'a> {
- cursor: &'a Cursor,
- tu: CXTranslationUnit,
- tokens: *mut CXToken,
- token_count: c_uint,
-}
-
-impl<'a> RawTokens<'a> {
- fn new(cursor: &'a Cursor) -> Self {
- let mut tokens = ptr::null_mut();
- let mut token_count = 0;
- let range = cursor.extent();
- let tu = unsafe { clang_Cursor_getTranslationUnit(cursor.x) };
- unsafe { clang_tokenize(tu, range, &mut tokens, &mut token_count) };
- Self {
- cursor,
- tu,
- tokens,
- token_count,
- }
- }
-
- fn as_slice(&self) -> &[CXToken] {
- if self.tokens.is_null() {
- return &[];
- }
- unsafe { slice::from_raw_parts(self.tokens, self.token_count as usize) }
- }
-
- /// Get an iterator over these tokens.
- pub fn iter(&self) -> ClangTokenIterator {
- ClangTokenIterator {
- tu: self.tu,
- raw: self.as_slice().iter(),
- }
- }
-}
-
-impl<'a> Drop for RawTokens<'a> {
- fn drop(&mut self) {
- if !self.tokens.is_null() {
- unsafe {
- clang_disposeTokens(
- self.tu,
- self.tokens,
- self.token_count as c_uint,
- );
- }
- }
- }
-}
-
-/// A raw clang token, that exposes only kind, spelling, and extent. This is a
-/// slightly more convenient version of `CXToken` which owns the spelling
-/// string and extent.
-#[derive(Debug)]
-pub struct ClangToken {
- spelling: CXString,
- /// The extent of the token. This is the same as the relevant member from
- /// `CXToken`.
- pub extent: CXSourceRange,
- /// The kind of the token. This is the same as the relevant member from
- /// `CXToken`.
- pub kind: CXTokenKind,
-}
-
-impl ClangToken {
- /// Get the token spelling, without being converted to utf-8.
- pub fn spelling(&self) -> &[u8] {
- let c_str = unsafe {
- CStr::from_ptr(clang_getCString(self.spelling) as *const _)
- };
- c_str.to_bytes()
- }
-
- /// Converts a ClangToken to a `cexpr` token if possible.
- pub fn as_cexpr_token(&self) -> Option<cexpr::token::Token> {
- use cexpr::token;
-
- let kind = match self.kind {
- CXToken_Punctuation => token::Kind::Punctuation,
- CXToken_Literal => token::Kind::Literal,
- CXToken_Identifier => token::Kind::Identifier,
- CXToken_Keyword => token::Kind::Keyword,
- // NB: cexpr is not too happy about comments inside
- // expressions, so we strip them down here.
- CXToken_Comment => return None,
- _ => {
- warn!("Found unexpected token kind: {:?}", self);
- return None;
- }
- };
-
- Some(token::Token {
- kind,
- raw: self.spelling().to_vec().into_boxed_slice(),
- })
- }
-}
-
-impl Drop for ClangToken {
- fn drop(&mut self) {
- unsafe { clang_disposeString(self.spelling) }
- }
-}
-
-/// An iterator over a set of Tokens.
-pub struct ClangTokenIterator<'a> {
- tu: CXTranslationUnit,
- raw: slice::Iter<'a, CXToken>,
-}
-
-impl<'a> Iterator for ClangTokenIterator<'a> {
- type Item = ClangToken;
-
- fn next(&mut self) -> Option<Self::Item> {
- let raw = self.raw.next()?;
- unsafe {
- let kind = clang_getTokenKind(*raw);
- let spelling = clang_getTokenSpelling(self.tu, *raw);
- let extent = clang_getTokenExtent(self.tu, *raw);
- Some(ClangToken {
- kind,
- extent,
- spelling,
- })
- }
- }
-}
-
-/// Checks whether the name looks like an identifier, i.e. is alphanumeric
-/// (including '_') and does not start with a digit.
-pub fn is_valid_identifier(name: &str) -> bool {
- let mut chars = name.chars();
- let first_valid = chars
- .next()
- .map(|c| c.is_alphabetic() || c == '_')
- .unwrap_or(false);
-
- first_valid && chars.all(|c| c.is_alphanumeric() || c == '_')
-}
-
-extern "C" fn visit_children<Visitor>(
- cur: CXCursor,
- _parent: CXCursor,
- data: CXClientData,
-) -> CXChildVisitResult
-where
- Visitor: FnMut(Cursor) -> CXChildVisitResult,
-{
- let func: &mut Visitor = unsafe { &mut *(data as *mut Visitor) };
- let child = Cursor { x: cur };
-
- (*func)(child)
-}
-
-impl PartialEq for Cursor {
- fn eq(&self, other: &Cursor) -> bool {
- unsafe { clang_equalCursors(self.x, other.x) == 1 }
- }
-}
-
-impl Eq for Cursor {}
-
-impl Hash for Cursor {
- fn hash<H: Hasher>(&self, state: &mut H) {
- unsafe { clang_hashCursor(self.x) }.hash(state)
- }
-}
-
-/// The type of a node in clang's AST.
-#[derive(Clone, Copy)]
-pub struct Type {
- x: CXType,
-}
-
-impl PartialEq for Type {
- fn eq(&self, other: &Self) -> bool {
- unsafe { clang_equalTypes(self.x, other.x) != 0 }
- }
-}
-
-impl Eq for Type {}
-
-impl fmt::Debug for Type {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(
- fmt,
- "Type({}, kind: {}, cconv: {}, decl: {:?}, canon: {:?})",
- self.spelling(),
- type_to_str(self.kind()),
- self.call_conv(),
- self.declaration(),
- self.declaration().canonical()
- )
- }
-}
-
-/// An error about the layout of a struct, class, or type.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum LayoutError {
- /// Asked for the layout of an invalid type.
- Invalid,
- /// Asked for the layout of an incomplete type.
- Incomplete,
- /// Asked for the layout of a dependent type.
- Dependent,
- /// Asked for the layout of a type that does not have constant size.
- NotConstantSize,
- /// Asked for the layout of a field in a type that does not have such a
- /// field.
- InvalidFieldName,
- /// An unknown layout error.
- Unknown,
-}
-
-impl ::std::convert::From<i32> for LayoutError {
- fn from(val: i32) -> Self {
- use self::LayoutError::*;
-
- match val {
- CXTypeLayoutError_Invalid => Invalid,
- CXTypeLayoutError_Incomplete => Incomplete,
- CXTypeLayoutError_Dependent => Dependent,
- CXTypeLayoutError_NotConstantSize => NotConstantSize,
- CXTypeLayoutError_InvalidFieldName => InvalidFieldName,
- _ => Unknown,
- }
- }
-}
-
-impl Type {
- /// Get this type's kind.
- pub fn kind(&self) -> CXTypeKind {
- self.x.kind
- }
-
- /// Get a cursor pointing to this type's declaration.
- pub fn declaration(&self) -> Cursor {
- unsafe {
- Cursor {
- x: clang_getTypeDeclaration(self.x),
- }
- }
- }
-
- /// Get the canonical declaration of this type, if it is available.
- pub fn canonical_declaration(
- &self,
- location: Option<&Cursor>,
- ) -> Option<CanonicalTypeDeclaration> {
- let mut declaration = self.declaration();
- if !declaration.is_valid() {
- if let Some(location) = location {
- let mut location = *location;
- if let Some(referenced) = location.referenced() {
- location = referenced;
- }
- if location.is_template_like() {
- declaration = location;
- }
- }
- }
-
- let canonical = declaration.canonical();
- if canonical.is_valid() && canonical.kind() != CXCursor_NoDeclFound {
- Some(CanonicalTypeDeclaration(*self, canonical))
- } else {
- None
- }
- }
-
- /// Get a raw display name for this type.
- pub fn spelling(&self) -> String {
- let s = unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) };
- // Clang 5.0 introduced changes in the spelling API so it returned the
- // full qualified name. Let's undo that here.
- if s.split("::").all(is_valid_identifier) {
- if let Some(s) = s.split("::").last() {
- return s.to_owned();
- }
- }
-
- s
- }
-
- /// Is this type const qualified?
- pub fn is_const(&self) -> bool {
- unsafe { clang_isConstQualifiedType(self.x) != 0 }
- }
-
- #[inline]
- fn is_non_deductible_auto_type(&self) -> bool {
- debug_assert_eq!(self.kind(), CXType_Auto);
- self.canonical_type() == *self
- }
-
- #[inline]
- fn clang_size_of(&self, ctx: &BindgenContext) -> c_longlong {
- match self.kind() {
- // Work-around https://bugs.llvm.org/show_bug.cgi?id=40975
- CXType_RValueReference | CXType_LValueReference => {
- ctx.target_pointer_size() as c_longlong
- }
- // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
- CXType_Auto if self.is_non_deductible_auto_type() => -6,
- _ => unsafe { clang_Type_getSizeOf(self.x) },
- }
- }
-
- #[inline]
- fn clang_align_of(&self, ctx: &BindgenContext) -> c_longlong {
- match self.kind() {
- // Work-around https://bugs.llvm.org/show_bug.cgi?id=40975
- CXType_RValueReference | CXType_LValueReference => {
- ctx.target_pointer_size() as c_longlong
- }
- // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
- CXType_Auto if self.is_non_deductible_auto_type() => -6,
- _ => unsafe { clang_Type_getAlignOf(self.x) },
- }
- }
-
- /// What is the size of this type? Paper over invalid types by returning `0`
- /// for them.
- pub fn size(&self, ctx: &BindgenContext) -> usize {
- let val = self.clang_size_of(ctx);
- if val < 0 {
- 0
- } else {
- val as usize
- }
- }
-
- /// What is the size of this type?
- pub fn fallible_size(
- &self,
- ctx: &BindgenContext,
- ) -> Result<usize, LayoutError> {
- let val = self.clang_size_of(ctx);
- if val < 0 {
- Err(LayoutError::from(val as i32))
- } else {
- Ok(val as usize)
- }
- }
-
- /// What is the alignment of this type? Paper over invalid types by
- /// returning `0`.
- pub fn align(&self, ctx: &BindgenContext) -> usize {
- let val = self.clang_align_of(ctx);
- if val < 0 {
- 0
- } else {
- val as usize
- }
- }
-
- /// What is the alignment of this type?
- pub fn fallible_align(
- &self,
- ctx: &BindgenContext,
- ) -> Result<usize, LayoutError> {
- let val = self.clang_align_of(ctx);
- if val < 0 {
- Err(LayoutError::from(val as i32))
- } else {
- Ok(val as usize)
- }
- }
-
- /// Get the layout for this type, or an error describing why it does not
- /// have a valid layout.
- pub fn fallible_layout(
- &self,
- ctx: &BindgenContext,
- ) -> Result<crate::ir::layout::Layout, LayoutError> {
- use crate::ir::layout::Layout;
- let size = self.fallible_size(ctx)?;
- let align = self.fallible_align(ctx)?;
- Ok(Layout::new(size, align))
- }
-
- /// Get the number of template arguments this type has, or `None` if it is
- /// not some kind of template.
- pub fn num_template_args(&self) -> Option<u32> {
- let n = unsafe { clang_Type_getNumTemplateArguments(self.x) };
- if n >= 0 {
- Some(n as u32)
- } else {
- debug_assert_eq!(n, -1);
- None
- }
- }
-
- /// If this type is a class template specialization, return its
- /// template arguments. Otherwise, return None.
- pub fn template_args(&self) -> Option<TypeTemplateArgIterator> {
- self.num_template_args().map(|n| TypeTemplateArgIterator {
- x: self.x,
- length: n,
- index: 0,
- })
- }
-
- /// Given that this type is a function prototype, return the types of its parameters.
- ///
- /// Returns None if the type is not a function prototype.
- pub fn args(&self) -> Option<Vec<Type>> {
- self.num_args().ok().map(|num| {
- (0..num)
- .map(|i| Type {
- x: unsafe { clang_getArgType(self.x, i as c_uint) },
- })
- .collect()
- })
- }
-
- /// Given that this type is a function prototype, return the number of arguments it takes.
- ///
- /// Returns Err if the type is not a function prototype.
- pub fn num_args(&self) -> Result<u32, ()> {
- unsafe {
- let w = clang_getNumArgTypes(self.x);
- if w == -1 {
- Err(())
- } else {
- Ok(w as u32)
- }
- }
- }
-
- /// Given that this type is a pointer type, return the type that it points
- /// to.
- pub fn pointee_type(&self) -> Option<Type> {
- match self.kind() {
- CXType_Pointer |
- CXType_RValueReference |
- CXType_LValueReference |
- CXType_MemberPointer |
- CXType_BlockPointer |
- CXType_ObjCObjectPointer => {
- let ret = Type {
- x: unsafe { clang_getPointeeType(self.x) },
- };
- debug_assert!(ret.is_valid());
- Some(ret)
- }
- _ => None,
- }
- }
-
- /// Given that this type is an array, vector, or complex type, return the
- /// type of its elements.
- pub fn elem_type(&self) -> Option<Type> {
- let current_type = Type {
- x: unsafe { clang_getElementType(self.x) },
- };
- if current_type.is_valid() {
- Some(current_type)
- } else {
- None
- }
- }
-
- /// Given that this type is an array or vector type, return its number of
- /// elements.
- pub fn num_elements(&self) -> Option<usize> {
- let num_elements_returned = unsafe { clang_getNumElements(self.x) };
- if num_elements_returned != -1 {
- Some(num_elements_returned as usize)
- } else {
- None
- }
- }
-
- /// Get the canonical version of this type. This sees through `typedef`s and
- /// aliases to get the underlying, canonical type.
- pub fn canonical_type(&self) -> Type {
- unsafe {
- Type {
- x: clang_getCanonicalType(self.x),
- }
- }
- }
-
- /// Is this type a variadic function type?
- pub fn is_variadic(&self) -> bool {
- unsafe { clang_isFunctionTypeVariadic(self.x) != 0 }
- }
-
- /// Given that this type is a function type, get the type of its return
- /// value.
- pub fn ret_type(&self) -> Option<Type> {
- let rt = Type {
- x: unsafe { clang_getResultType(self.x) },
- };
- if rt.is_valid() {
- Some(rt)
- } else {
- None
- }
- }
-
- /// Given that this type is a function type, get its calling convention. If
- /// this is not a function type, `CXCallingConv_Invalid` is returned.
- pub fn call_conv(&self) -> CXCallingConv {
- unsafe { clang_getFunctionTypeCallingConv(self.x) }
- }
-
- /// For elaborated types (types which use `class`, `struct`, or `union` to
- /// disambiguate types from local bindings), get the underlying type.
- pub fn named(&self) -> Type {
- unsafe {
- Type {
- x: clang_Type_getNamedType(self.x),
- }
- }
- }
-
- /// Is this a valid type?
- pub fn is_valid(&self) -> bool {
- self.kind() != CXType_Invalid
- }
-
- /// Is this a valid and exposed type?
- pub fn is_valid_and_exposed(&self) -> bool {
- self.is_valid() && self.kind() != CXType_Unexposed
- }
-
- /// Is this type a fully instantiated template?
- pub fn is_fully_instantiated_template(&self) -> bool {
- // Yep, the spelling of this containing type-parameter is extremely
- // nasty... But can happen in <type_traits>. Unfortunately I couldn't
- // reduce it enough :(
- self.template_args().map_or(false, |args| args.len() > 0) &&
- !matches!(
- self.declaration().kind(),
- CXCursor_ClassTemplatePartialSpecialization |
- CXCursor_TypeAliasTemplateDecl |
- CXCursor_TemplateTemplateParameter
- )
- }
-
- /// Is this type an associated template type? Eg `T::Associated` in
- /// this example:
- ///
- /// ```c++
- /// template <typename T>
- /// class Foo {
- /// typename T::Associated member;
- /// };
- /// ```
- pub fn is_associated_type(&self) -> bool {
- // This is terrible :(
- fn hacky_parse_associated_type<S: AsRef<str>>(spelling: S) -> bool {
- lazy_static! {
- static ref ASSOC_TYPE_RE: regex::Regex = regex::Regex::new(
- r"typename type\-parameter\-\d+\-\d+::.+"
- )
- .unwrap();
- }
- ASSOC_TYPE_RE.is_match(spelling.as_ref())
- }
-
- self.kind() == CXType_Unexposed &&
- (hacky_parse_associated_type(self.spelling()) ||
- hacky_parse_associated_type(
- self.canonical_type().spelling(),
- ))
- }
-}
-
-/// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its
-/// cursor is the canonical declaration for its type. If you have a
-/// `CanonicalTypeDeclaration` instance, you know for sure that the type and
-/// cursor match up in a canonical declaration relationship, and it simply
-/// cannot be otherwise.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct CanonicalTypeDeclaration(Type, Cursor);
-
-impl CanonicalTypeDeclaration {
- /// Get the type.
- pub fn ty(&self) -> &Type {
- &self.0
- }
-
- /// Get the type's canonical declaration cursor.
- pub fn cursor(&self) -> &Cursor {
- &self.1
- }
-}
-
-/// An iterator for a type's template arguments.
-pub struct TypeTemplateArgIterator {
- x: CXType,
- length: u32,
- index: u32,
-}
-
-impl Iterator for TypeTemplateArgIterator {
- type Item = Type;
- fn next(&mut self) -> Option<Type> {
- if self.index < self.length {
- let idx = self.index as c_uint;
- self.index += 1;
- Some(Type {
- x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) },
- })
- } else {
- None
- }
- }
-}
-
-impl ExactSizeIterator for TypeTemplateArgIterator {
- fn len(&self) -> usize {
- assert!(self.index <= self.length);
- (self.length - self.index) as usize
- }
-}
-
-/// A `SourceLocation` is a file, line, column, and byte offset location for
-/// some source text.
-pub struct SourceLocation {
- x: CXSourceLocation,
-}
-
-impl SourceLocation {
- /// Get the (file, line, column, byte offset) tuple for this source
- /// location.
- pub fn location(&self) -> (File, usize, usize, usize) {
- unsafe {
- let mut file = mem::zeroed();
- let mut line = 0;
- let mut col = 0;
- let mut off = 0;
- clang_getSpellingLocation(
- self.x, &mut file, &mut line, &mut col, &mut off,
- );
- (File { x: file }, line as usize, col as usize, off as usize)
- }
- }
-}
-
-impl fmt::Display for SourceLocation {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let (file, line, col, _) = self.location();
- if let Some(name) = file.name() {
- write!(f, "{}:{}:{}", name, line, col)
- } else {
- "builtin definitions".fmt(f)
- }
- }
-}
-
-impl fmt::Debug for SourceLocation {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self)
- }
-}
-
-/// A comment in the source text.
-///
-/// Comments are sort of parsed by Clang, and have a tree structure.
-pub struct Comment {
- x: CXComment,
-}
-
-impl Comment {
- /// What kind of comment is this?
- pub fn kind(&self) -> CXCommentKind {
- unsafe { clang_Comment_getKind(self.x) }
- }
-
- /// Get this comment's children comment
- pub fn get_children(&self) -> CommentChildrenIterator {
- CommentChildrenIterator {
- parent: self.x,
- length: unsafe { clang_Comment_getNumChildren(self.x) },
- index: 0,
- }
- }
-
- /// Given that this comment is the start or end of an HTML tag, get its tag
- /// name.
- pub fn get_tag_name(&self) -> String {
- unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) }
- }
-
- /// Given that this comment is an HTML start tag, get its attributes.
- pub fn get_tag_attrs(&self) -> CommentAttributesIterator {
- CommentAttributesIterator {
- x: self.x,
- length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) },
- index: 0,
- }
- }
-}
-
-/// An iterator for a comment's children
-pub struct CommentChildrenIterator {
- parent: CXComment,
- length: c_uint,
- index: c_uint,
-}
-
-impl Iterator for CommentChildrenIterator {
- type Item = Comment;
- fn next(&mut self) -> Option<Comment> {
- if self.index < self.length {
- let idx = self.index;
- self.index += 1;
- Some(Comment {
- x: unsafe { clang_Comment_getChild(self.parent, idx) },
- })
- } else {
- None
- }
- }
-}
-
-/// An HTML start tag comment attribute
-pub struct CommentAttribute {
- /// HTML start tag attribute name
- pub name: String,
- /// HTML start tag attribute value
- pub value: String,
-}
-
-/// An iterator for a comment's attributes
-pub struct CommentAttributesIterator {
- x: CXComment,
- length: c_uint,
- index: c_uint,
-}
-
-impl Iterator for CommentAttributesIterator {
- type Item = CommentAttribute;
- fn next(&mut self) -> Option<CommentAttribute> {
- if self.index < self.length {
- let idx = self.index;
- self.index += 1;
- Some(CommentAttribute {
- name: unsafe {
- cxstring_into_string(clang_HTMLStartTag_getAttrName(
- self.x, idx,
- ))
- },
- value: unsafe {
- cxstring_into_string(clang_HTMLStartTag_getAttrValue(
- self.x, idx,
- ))
- },
- })
- } else {
- None
- }
- }
-}
-
-/// A source file.
-pub struct File {
- x: CXFile,
-}
-
-impl File {
- /// Get the name of this source file.
- pub fn name(&self) -> Option<String> {
- if self.x.is_null() {
- return None;
- }
- Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) })
- }
-}
-
-fn cxstring_to_string_leaky(s: CXString) -> String {
- if s.data.is_null() {
- return "".to_owned();
- }
- let c_str = unsafe { CStr::from_ptr(clang_getCString(s) as *const _) };
- c_str.to_string_lossy().into_owned()
-}
-
-fn cxstring_into_string(s: CXString) -> String {
- let ret = cxstring_to_string_leaky(s);
- unsafe { clang_disposeString(s) };
- ret
-}
-
-/// An `Index` is an environment for a set of translation units that will
-/// typically end up linked together in one final binary.
-pub struct Index {
- x: CXIndex,
-}
-
-impl Index {
- /// Construct a new `Index`.
- ///
- /// The `pch` parameter controls whether declarations in pre-compiled
- /// headers are included when enumerating a translation unit's "locals".
- ///
- /// The `diag` parameter controls whether debugging diagnostics are enabled.
- pub fn new(pch: bool, diag: bool) -> Index {
- unsafe {
- Index {
- x: clang_createIndex(pch as c_int, diag as c_int),
- }
- }
- }
-}
-
-impl fmt::Debug for Index {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt, "Index {{ }}")
- }
-}
-
-impl Drop for Index {
- fn drop(&mut self) {
- unsafe {
- clang_disposeIndex(self.x);
- }
- }
-}
-
-/// A translation unit (or "compilation unit").
-pub struct TranslationUnit {
- x: CXTranslationUnit,
-}
-
-impl fmt::Debug for TranslationUnit {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt, "TranslationUnit {{ }}")
- }
-}
-
-impl TranslationUnit {
- /// Parse a source file into a translation unit.
- pub fn parse(
- ix: &Index,
- file: &str,
- cmd_args: &[String],
- unsaved: &[UnsavedFile],
- opts: CXTranslationUnit_Flags,
- ) -> Option<TranslationUnit> {
- let fname = CString::new(file).unwrap();
- let _c_args: Vec<CString> = cmd_args
- .iter()
- .map(|s| CString::new(s.clone()).unwrap())
- .collect();
- let c_args: Vec<*const c_char> =
- _c_args.iter().map(|s| s.as_ptr()).collect();
- let mut c_unsaved: Vec<CXUnsavedFile> =
- unsaved.iter().map(|f| f.x).collect();
- let tu = unsafe {
- clang_parseTranslationUnit(
- ix.x,
- fname.as_ptr(),
- c_args.as_ptr(),
- c_args.len() as c_int,
- c_unsaved.as_mut_ptr(),
- c_unsaved.len() as c_uint,
- opts,
- )
- };
- if tu.is_null() {
- None
- } else {
- Some(TranslationUnit { x: tu })
- }
- }
-
- /// Get the Clang diagnostic information associated with this translation
- /// unit.
- pub fn diags(&self) -> Vec<Diagnostic> {
- unsafe {
- let num = clang_getNumDiagnostics(self.x) as usize;
- let mut diags = vec![];
- for i in 0..num {
- diags.push(Diagnostic {
- x: clang_getDiagnostic(self.x, i as c_uint),
- });
- }
- diags
- }
- }
-
- /// Get a cursor pointing to the root of this translation unit's AST.
- pub fn cursor(&self) -> Cursor {
- unsafe {
- Cursor {
- x: clang_getTranslationUnitCursor(self.x),
- }
- }
- }
-
- /// Is this the null translation unit?
- pub fn is_null(&self) -> bool {
- self.x.is_null()
- }
-}
-
-impl Drop for TranslationUnit {
- fn drop(&mut self) {
- unsafe {
- clang_disposeTranslationUnit(self.x);
- }
- }
-}
-
-/// A diagnostic message generated while parsing a translation unit.
-pub struct Diagnostic {
- x: CXDiagnostic,
-}
-
-impl Diagnostic {
- /// Format this diagnostic message as a string, using the given option bit
- /// flags.
- pub fn format(&self) -> String {
- unsafe {
- let opts = clang_defaultDiagnosticDisplayOptions();
- cxstring_into_string(clang_formatDiagnostic(self.x, opts))
- }
- }
-
- /// What is the severity of this diagnostic message?
- pub fn severity(&self) -> CXDiagnosticSeverity {
- unsafe { clang_getDiagnosticSeverity(self.x) }
- }
-}
-
-impl Drop for Diagnostic {
- /// Destroy this diagnostic message.
- fn drop(&mut self) {
- unsafe {
- clang_disposeDiagnostic(self.x);
- }
- }
-}
-
-/// A file which has not been saved to disk.
-pub struct UnsavedFile {
- x: CXUnsavedFile,
- /// The name of the unsaved file. Kept here to avoid leaving dangling pointers in
- /// `CXUnsavedFile`.
- pub name: CString,
- contents: CString,
-}
-
-impl UnsavedFile {
- /// Construct a new unsaved file with the given `name` and `contents`.
- pub fn new(name: &str, contents: &str) -> UnsavedFile {
- let name = CString::new(name).unwrap();
- let contents = CString::new(contents).unwrap();
- let x = CXUnsavedFile {
- Filename: name.as_ptr(),
- Contents: contents.as_ptr(),
- Length: contents.as_bytes().len() as c_ulong,
- };
- UnsavedFile { x, name, contents }
- }
-}
-
-impl fmt::Debug for UnsavedFile {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(
- fmt,
- "UnsavedFile(name: {:?}, contents: {:?})",
- self.name, self.contents
- )
- }
-}
-
-/// Convert a cursor kind into a static string.
-pub fn kind_to_str(x: CXCursorKind) -> String {
- unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) }
-}
-
-/// Convert a type kind to a static string.
-pub fn type_to_str(x: CXTypeKind) -> String {
- unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) }
-}
-
-/// Dump the Clang AST to stdout for debugging purposes.
-pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
- fn print_indent<S: AsRef<str>>(depth: isize, s: S) {
- for _ in 0..depth {
- print!(" ");
- }
- println!("{}", s.as_ref());
- }
-
- fn print_cursor<S: AsRef<str>>(depth: isize, prefix: S, c: &Cursor) {
- let prefix = prefix.as_ref();
- print_indent(
- depth,
- format!(" {}kind = {}", prefix, kind_to_str(c.kind())),
- );
- print_indent(
- depth,
- format!(" {}spelling = \"{}\"", prefix, c.spelling()),
- );
- print_indent(depth, format!(" {}location = {}", prefix, c.location()));
- print_indent(
- depth,
- format!(" {}is-definition? {}", prefix, c.is_definition()),
- );
- print_indent(
- depth,
- format!(" {}is-declaration? {}", prefix, c.is_declaration()),
- );
- print_indent(
- depth,
- format!(
- " {}is-inlined-function? {}",
- prefix,
- c.is_inlined_function()
- ),
- );
-
- let templ_kind = c.template_kind();
- if templ_kind != CXCursor_NoDeclFound {
- print_indent(
- depth,
- format!(
- " {}template-kind = {}",
- prefix,
- kind_to_str(templ_kind)
- ),
- );
- }
- if let Some(usr) = c.usr() {
- print_indent(depth, format!(" {}usr = \"{}\"", prefix, usr));
- }
- if let Ok(num) = c.num_args() {
- print_indent(depth, format!(" {}number-of-args = {}", prefix, num));
- }
- if let Some(num) = c.num_template_args() {
- print_indent(
- depth,
- format!(" {}number-of-template-args = {}", prefix, num),
- );
- }
-
- if c.is_bit_field() {
- let width = match c.bit_width() {
- Some(w) => w.to_string(),
- None => "<unevaluable>".to_string(),
- };
- print_indent(depth, format!(" {}bit-width = {}", prefix, width));
- }
-
- if let Some(ty) = c.enum_type() {
- print_indent(
- depth,
- format!(" {}enum-type = {}", prefix, type_to_str(ty.kind())),
- );
- }
- if let Some(val) = c.enum_val_signed() {
- print_indent(depth, format!(" {}enum-val = {}", prefix, val));
- }
- if let Some(ty) = c.typedef_type() {
- print_indent(
- depth,
- format!(" {}typedef-type = {}", prefix, type_to_str(ty.kind())),
- );
- }
- if let Some(ty) = c.ret_type() {
- print_indent(
- depth,
- format!(" {}ret-type = {}", prefix, type_to_str(ty.kind())),
- );
- }
-
- if let Some(refd) = c.referenced() {
- if refd != *c {
- println!();
- print_cursor(
- depth,
- String::from(prefix) + "referenced.",
- &refd,
- );
- }
- }
-
- let canonical = c.canonical();
- if canonical != *c {
- println!();
- print_cursor(
- depth,
- String::from(prefix) + "canonical.",
- &canonical,
- );
- }
-
- if let Some(specialized) = c.specialized() {
- if specialized != *c {
- println!();
- print_cursor(
- depth,
- String::from(prefix) + "specialized.",
- &specialized,
- );
- }
- }
-
- if let Some(parent) = c.fallible_semantic_parent() {
- println!();
- print_cursor(
- depth,
- String::from(prefix) + "semantic-parent.",
- &parent,
- );
- }
- }
-
- fn print_type<S: AsRef<str>>(depth: isize, prefix: S, ty: &Type) {
- let prefix = prefix.as_ref();
-
- let kind = ty.kind();
- print_indent(depth, format!(" {}kind = {}", prefix, type_to_str(kind)));
- if kind == CXType_Invalid {
- return;
- }
-
- print_indent(depth, format!(" {}cconv = {}", prefix, ty.call_conv()));
-
- print_indent(
- depth,
- format!(" {}spelling = \"{}\"", prefix, ty.spelling()),
- );
- let num_template_args =
- unsafe { clang_Type_getNumTemplateArguments(ty.x) };
- if num_template_args >= 0 {
- print_indent(
- depth,
- format!(
- " {}number-of-template-args = {}",
- prefix, num_template_args
- ),
- );
- }
- if let Some(num) = ty.num_elements() {
- print_indent(
- depth,
- format!(" {}number-of-elements = {}", prefix, num),
- );
- }
- print_indent(
- depth,
- format!(" {}is-variadic? {}", prefix, ty.is_variadic()),
- );
-
- let canonical = ty.canonical_type();
- if canonical != *ty {
- println!();
- print_type(depth, String::from(prefix) + "canonical.", &canonical);
- }
-
- if let Some(pointee) = ty.pointee_type() {
- if pointee != *ty {
- println!();
- print_type(depth, String::from(prefix) + "pointee.", &pointee);
- }
- }
-
- if let Some(elem) = ty.elem_type() {
- if elem != *ty {
- println!();
- print_type(depth, String::from(prefix) + "elements.", &elem);
- }
- }
-
- if let Some(ret) = ty.ret_type() {
- if ret != *ty {
- println!();
- print_type(depth, String::from(prefix) + "return.", &ret);
- }
- }
-
- let named = ty.named();
- if named != *ty && named.is_valid() {
- println!();
- print_type(depth, String::from(prefix) + "named.", &named);
- }
- }
-
- print_indent(depth, "(");
- print_cursor(depth, "", c);
-
- println!();
- let ty = c.cur_type();
- print_type(depth, "type.", &ty);
-
- let declaration = ty.declaration();
- if declaration != *c && declaration.kind() != CXCursor_NoDeclFound {
- println!();
- print_cursor(depth, "type.declaration.", &declaration);
- }
-
- // Recurse.
- let mut found_children = false;
- c.visit(|s| {
- if !found_children {
- println!();
- found_children = true;
- }
- ast_dump(&s, depth + 1)
- });
-
- print_indent(depth, ")");
-
- CXChildVisit_Continue
-}
-
-/// Try to extract the clang version to a string
-pub fn extract_clang_version() -> String {
- unsafe { cxstring_into_string(clang_getClangVersion()) }
-}
-
-/// A wrapper for the result of evaluating an expression.
-#[derive(Debug)]
-pub struct EvalResult {
- x: CXEvalResult,
-}
-
-impl EvalResult {
- /// Evaluate `cursor` and return the result.
- pub fn new(cursor: Cursor) -> Option<Self> {
- // Work around https://bugs.llvm.org/show_bug.cgi?id=42532, see:
- // * https://github.com/rust-lang/rust-bindgen/issues/283
- // * https://github.com/rust-lang/rust-bindgen/issues/1590
- {
- let mut found_cant_eval = false;
- cursor.visit(|c| {
- if c.kind() == CXCursor_TypeRef &&
- c.cur_type().canonical_type().kind() == CXType_Unexposed
- {
- found_cant_eval = true;
- return CXChildVisit_Break;
- }
-
- CXChildVisit_Recurse
- });
-
- if found_cant_eval {
- return None;
- }
- }
- Some(EvalResult {
- x: unsafe { clang_Cursor_Evaluate(cursor.x) },
- })
- }
-
- fn kind(&self) -> CXEvalResultKind {
- unsafe { clang_EvalResult_getKind(self.x) }
- }
-
- /// Try to get back the result as a double.
- pub fn as_double(&self) -> Option<f64> {
- match self.kind() {
- CXEval_Float => {
- Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64)
- }
- _ => None,
- }
- }
-
- /// Try to get back the result as an integer.
- pub fn as_int(&self) -> Option<i64> {
- if self.kind() != CXEval_Int {
- return None;
- }
-
- if unsafe { clang_EvalResult_isUnsignedInt(self.x) } != 0 {
- let value = unsafe { clang_EvalResult_getAsUnsigned(self.x) };
- if value > i64::max_value() as c_ulonglong {
- return None;
- }
-
- return Some(value as i64);
- }
-
- let value = unsafe { clang_EvalResult_getAsLongLong(self.x) };
- if value > i64::max_value() as c_longlong {
- return None;
- }
- if value < i64::min_value() as c_longlong {
- return None;
- }
- Some(value as i64)
- }
-
- /// Evaluates the expression as a literal string, that may or may not be
- /// valid utf-8.
- pub fn as_literal_string(&self) -> Option<Vec<u8>> {
- match self.kind() {
- CXEval_StrLiteral => {
- let ret = unsafe {
- CStr::from_ptr(clang_EvalResult_getAsStr(self.x))
- };
- Some(ret.to_bytes().to_vec())
- }
- _ => None,
- }
- }
-}
-
-impl Drop for EvalResult {
- fn drop(&mut self) {
- unsafe { clang_EvalResult_dispose(self.x) };
- }
-}
-
-/// Target information obtained from libclang.
-#[derive(Debug)]
-pub struct TargetInfo {
- /// The target triple.
- pub triple: String,
- /// The width of the pointer _in bits_.
- pub pointer_width: usize,
-}
-
-impl TargetInfo {
- /// Tries to obtain target information from libclang.
- pub fn new(tu: &TranslationUnit) -> Self {
- let triple;
- let pointer_width;
- unsafe {
- let ti = clang_getTranslationUnitTargetInfo(tu.x);
- triple = cxstring_into_string(clang_TargetInfo_getTriple(ti));
- pointer_width = clang_TargetInfo_getPointerWidth(ti);
- clang_TargetInfo_dispose(ti);
- }
- assert!(pointer_width > 0);
- assert_eq!(pointer_width % 8, 0);
- TargetInfo {
- triple,
- pointer_width: pointer_width as usize,
- }
- }
-}
diff --git a/src/codegen/bitfield_unit.rs b/src/codegen/bitfield_unit.rs
deleted file mode 100644
index 73ec2bd6..00000000
--- a/src/codegen/bitfield_unit.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-#[repr(C)]
-#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
-pub struct __BindgenBitfieldUnit<Storage> {
- storage: Storage,
-}
-
-impl<Storage> __BindgenBitfieldUnit<Storage> {
- #[inline]
- pub const fn new(storage: Storage) -> Self {
- Self { storage }
- }
-}
-
-impl<Storage> __BindgenBitfieldUnit<Storage>
-where
- Storage: AsRef<[u8]> + AsMut<[u8]>,
-{
- #[inline]
- pub fn get_bit(&self, index: usize) -> bool {
- debug_assert!(index / 8 < self.storage.as_ref().len());
-
- let byte_index = index / 8;
- let byte = self.storage.as_ref()[byte_index];
-
- let bit_index = if cfg!(target_endian = "big") {
- 7 - (index % 8)
- } else {
- index % 8
- };
-
- let mask = 1 << bit_index;
-
- byte & mask == mask
- }
-
- #[inline]
- pub fn set_bit(&mut self, index: usize, val: bool) {
- debug_assert!(index / 8 < self.storage.as_ref().len());
-
- let byte_index = index / 8;
- let byte = &mut self.storage.as_mut()[byte_index];
-
- let bit_index = if cfg!(target_endian = "big") {
- 7 - (index % 8)
- } else {
- index % 8
- };
-
- let mask = 1 << bit_index;
- if val {
- *byte |= mask;
- } else {
- *byte &= !mask;
- }
- }
-
- #[inline]
- pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
- debug_assert!(bit_width <= 64);
- debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
- debug_assert!(
- (bit_offset + (bit_width as usize)) / 8 <=
- self.storage.as_ref().len()
- );
-
- let mut val = 0;
-
- for i in 0..(bit_width as usize) {
- if self.get_bit(i + bit_offset) {
- let index = if cfg!(target_endian = "big") {
- bit_width as usize - 1 - i
- } else {
- i
- };
- val |= 1 << index;
- }
- }
-
- val
- }
-
- #[inline]
- pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
- debug_assert!(bit_width <= 64);
- debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
- debug_assert!(
- (bit_offset + (bit_width as usize)) / 8 <=
- self.storage.as_ref().len()
- );
-
- for i in 0..(bit_width as usize) {
- let mask = 1 << i;
- let val_bit_is_set = val & mask == mask;
- let index = if cfg!(target_endian = "big") {
- bit_width as usize - 1 - i
- } else {
- i
- };
- self.set_bit(index + bit_offset, val_bit_is_set);
- }
- }
-}
diff --git a/src/codegen/bitfield_unit_tests.rs b/src/codegen/bitfield_unit_tests.rs
deleted file mode 100644
index e143e4ea..00000000
--- a/src/codegen/bitfield_unit_tests.rs
+++ /dev/null
@@ -1,260 +0,0 @@
-//! Tests for `__BindgenBitfieldUnit`.
-//!
-//! Note that bit-fields are allocated right to left (least to most significant
-//! bits).
-//!
-//! From the x86 PS ABI:
-//!
-//! ```c
-//! struct {
-//! int j : 5;
-//! int k : 6;
-//! int m : 7;
-//! };
-//! ```
-//!
-//! ```ignore
-//! +------------------------------------------------------------+
-//! | | | | |
-//! | padding | m | k | j |
-//! |31 18|17 11|10 5|4 0|
-//! +------------------------------------------------------------+
-//! ```
-
-use super::bitfield_unit::__BindgenBitfieldUnit;
-
-#[test]
-fn bitfield_unit_get_bit() {
- let unit = __BindgenBitfieldUnit::<[u8; 2]>::new([0b10011101, 0b00011101]);
-
- let mut bits = vec![];
- for i in 0..16 {
- bits.push(unit.get_bit(i));
- }
-
- println!();
- println!("bits = {:?}", bits);
- assert_eq!(
- bits,
- &[
- // 0b10011101
- true, false, true, true, true, false, false, true,
- // 0b00011101
- true, false, true, true, true, false, false, false
- ]
- );
-}
-
-#[test]
-fn bitfield_unit_set_bit() {
- let mut unit =
- __BindgenBitfieldUnit::<[u8; 2]>::new([0b00000000, 0b00000000]);
-
- for i in 0..16 {
- if i % 3 == 0 {
- unit.set_bit(i, true);
- }
- }
-
- for i in 0..16 {
- assert_eq!(unit.get_bit(i), i % 3 == 0);
- }
-
- let mut unit =
- __BindgenBitfieldUnit::<[u8; 2]>::new([0b11111111, 0b11111111]);
-
- for i in 0..16 {
- if i % 3 == 0 {
- unit.set_bit(i, false);
- }
- }
-
- for i in 0..16 {
- assert_eq!(unit.get_bit(i), i % 3 != 0);
- }
-}
-
-macro_rules! bitfield_unit_get {
- (
- $(
- With $storage:expr , then get($start:expr, $len:expr) is $expected:expr;
- )*
- ) => {
- #[test]
- fn bitfield_unit_get() {
- $({
- let expected = $expected;
- let unit = __BindgenBitfieldUnit::<_>::new($storage);
- let actual = unit.get($start, $len);
-
- println!();
- println!("expected = {:064b}", expected);
- println!("actual = {:064b}", actual);
-
- assert_eq!(expected, actual);
- })*
- }
- }
-}
-
-bitfield_unit_get! {
- // Let's just exhaustively test getting the bits from a single byte, since
- // there are few enough combinations...
-
- With [0b11100010], then get(0, 1) is 0;
- With [0b11100010], then get(1, 1) is 1;
- With [0b11100010], then get(2, 1) is 0;
- With [0b11100010], then get(3, 1) is 0;
- With [0b11100010], then get(4, 1) is 0;
- With [0b11100010], then get(5, 1) is 1;
- With [0b11100010], then get(6, 1) is 1;
- With [0b11100010], then get(7, 1) is 1;
-
- With [0b11100010], then get(0, 2) is 0b10;
- With [0b11100010], then get(1, 2) is 0b01;
- With [0b11100010], then get(2, 2) is 0b00;
- With [0b11100010], then get(3, 2) is 0b00;
- With [0b11100010], then get(4, 2) is 0b10;
- With [0b11100010], then get(5, 2) is 0b11;
- With [0b11100010], then get(6, 2) is 0b11;
-
- With [0b11100010], then get(0, 3) is 0b010;
- With [0b11100010], then get(1, 3) is 0b001;
- With [0b11100010], then get(2, 3) is 0b000;
- With [0b11100010], then get(3, 3) is 0b100;
- With [0b11100010], then get(4, 3) is 0b110;
- With [0b11100010], then get(5, 3) is 0b111;
-
- With [0b11100010], then get(0, 4) is 0b0010;
- With [0b11100010], then get(1, 4) is 0b0001;
- With [0b11100010], then get(2, 4) is 0b1000;
- With [0b11100010], then get(3, 4) is 0b1100;
- With [0b11100010], then get(4, 4) is 0b1110;
-
- With [0b11100010], then get(0, 5) is 0b00010;
- With [0b11100010], then get(1, 5) is 0b10001;
- With [0b11100010], then get(2, 5) is 0b11000;
- With [0b11100010], then get(3, 5) is 0b11100;
-
- With [0b11100010], then get(0, 6) is 0b100010;
- With [0b11100010], then get(1, 6) is 0b110001;
- With [0b11100010], then get(2, 6) is 0b111000;
-
- With [0b11100010], then get(0, 7) is 0b1100010;
- With [0b11100010], then get(1, 7) is 0b1110001;
-
- With [0b11100010], then get(0, 8) is 0b11100010;
-
- // OK. Now let's test getting bits from across byte boundaries.
-
- With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
- then get(0, 16) is 0b1111111101010101;
-
- With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
- then get(1, 16) is 0b0111111110101010;
-
- With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
- then get(2, 16) is 0b0011111111010101;
-
- With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
- then get(3, 16) is 0b0001111111101010;
-
- With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
- then get(4, 16) is 0b0000111111110101;
-
- With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
- then get(5, 16) is 0b0000011111111010;
-
- With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
- then get(6, 16) is 0b0000001111111101;
-
- With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
- then get(7, 16) is 0b0000000111111110;
-
- With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
- then get(8, 16) is 0b0000000011111111;
-}
-
-macro_rules! bitfield_unit_set {
- (
- $(
- set($start:expr, $len:expr, $val:expr) is $expected:expr;
- )*
- ) => {
- #[test]
- fn bitfield_unit_set() {
- $(
- let mut unit = __BindgenBitfieldUnit::<[u8; 4]>::new([0, 0, 0, 0]);
- unit.set($start, $len, $val);
- let actual = unit.get(0, 32);
-
- println!();
- println!("set({}, {}, {:032b}", $start, $len, $val);
- println!("expected = {:064b}", $expected);
- println!("actual = {:064b}", actual);
-
- assert_eq!($expected, actual);
- )*
- }
- }
-}
-
-bitfield_unit_set! {
- // Once again, let's exhaustively test single byte combinations.
-
- set(0, 1, 0b11111111) is 0b00000001;
- set(1, 1, 0b11111111) is 0b00000010;
- set(2, 1, 0b11111111) is 0b00000100;
- set(3, 1, 0b11111111) is 0b00001000;
- set(4, 1, 0b11111111) is 0b00010000;
- set(5, 1, 0b11111111) is 0b00100000;
- set(6, 1, 0b11111111) is 0b01000000;
- set(7, 1, 0b11111111) is 0b10000000;
-
- set(0, 2, 0b11111111) is 0b00000011;
- set(1, 2, 0b11111111) is 0b00000110;
- set(2, 2, 0b11111111) is 0b00001100;
- set(3, 2, 0b11111111) is 0b00011000;
- set(4, 2, 0b11111111) is 0b00110000;
- set(5, 2, 0b11111111) is 0b01100000;
- set(6, 2, 0b11111111) is 0b11000000;
-
- set(0, 3, 0b11111111) is 0b00000111;
- set(1, 3, 0b11111111) is 0b00001110;
- set(2, 3, 0b11111111) is 0b00011100;
- set(3, 3, 0b11111111) is 0b00111000;
- set(4, 3, 0b11111111) is 0b01110000;
- set(5, 3, 0b11111111) is 0b11100000;
-
- set(0, 4, 0b11111111) is 0b00001111;
- set(1, 4, 0b11111111) is 0b00011110;
- set(2, 4, 0b11111111) is 0b00111100;
- set(3, 4, 0b11111111) is 0b01111000;
- set(4, 4, 0b11111111) is 0b11110000;
-
- set(0, 5, 0b11111111) is 0b00011111;
- set(1, 5, 0b11111111) is 0b00111110;
- set(2, 5, 0b11111111) is 0b01111100;
- set(3, 5, 0b11111111) is 0b11111000;
-
- set(0, 6, 0b11111111) is 0b00111111;
- set(1, 6, 0b11111111) is 0b01111110;
- set(2, 6, 0b11111111) is 0b11111100;
-
- set(0, 7, 0b11111111) is 0b01111111;
- set(1, 7, 0b11111111) is 0b11111110;
-
- set(0, 8, 0b11111111) is 0b11111111;
-
- // And, now let's cross byte boundaries.
-
- set(0, 16, 0b1111111111111111) is 0b00000000000000001111111111111111;
- set(1, 16, 0b1111111111111111) is 0b00000000000000011111111111111110;
- set(2, 16, 0b1111111111111111) is 0b00000000000000111111111111111100;
- set(3, 16, 0b1111111111111111) is 0b00000000000001111111111111111000;
- set(4, 16, 0b1111111111111111) is 0b00000000000011111111111111110000;
- set(5, 16, 0b1111111111111111) is 0b00000000000111111111111111100000;
- set(6, 16, 0b1111111111111111) is 0b00000000001111111111111111000000;
- set(7, 16, 0b1111111111111111) is 0b00000000011111111111111110000000;
- set(8, 16, 0b1111111111111111) is 0b00000000111111111111111100000000;
-}
diff --git a/src/codegen/dyngen.rs b/src/codegen/dyngen.rs
deleted file mode 100644
index 26cfe5cc..00000000
--- a/src/codegen/dyngen.rs
+++ /dev/null
@@ -1,181 +0,0 @@
-use crate::codegen;
-use crate::ir::function::Abi;
-use proc_macro2::Ident;
-
-/// Used to build the output tokens for dynamic bindings.
-#[derive(Default)]
-pub struct DynamicItems {
- /// Tracks the tokens that will appears inside the library struct -- e.g.:
- /// ```ignore
- /// struct Lib {
- /// __library: ::libloading::Library,
- /// pub x: Result<unsafe extern ..., ::libloading::Error>, // <- tracks these
- /// ...
- /// }
- /// ```
- struct_members: Vec<proc_macro2::TokenStream>,
-
- /// Tracks the tokens that will appear inside the library struct's implementation, e.g.:
- ///
- /// ```ignore
- /// impl Lib {
- /// ...
- /// pub unsafe fn foo(&self, ...) { // <- tracks these
- /// ...
- /// }
- /// }
- /// ```
- struct_implementation: Vec<proc_macro2::TokenStream>,
-
- /// Tracks the initialization of the fields inside the `::new` constructor of the library
- /// struct, e.g.:
- /// ```ignore
- /// impl Lib {
- ///
- /// pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
- /// where
- /// P: AsRef<::std::ffi::OsStr>,
- /// {
- /// ...
- /// let foo = __library.get(...) ...; // <- tracks these
- /// ...
- /// }
- ///
- /// ...
- /// }
- /// ```
- constructor_inits: Vec<proc_macro2::TokenStream>,
-
- /// Tracks the information that is passed to the library struct at the end of the `::new`
- /// constructor, e.g.:
- /// ```ignore
- /// impl LibFoo {
- /// pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
- /// where
- /// P: AsRef<::std::ffi::OsStr>,
- /// {
- /// ...
- /// Ok(LibFoo {
- /// __library: __library,
- /// foo,
- /// bar, // <- tracks these
- /// ...
- /// })
- /// }
- /// }
- /// ```
- init_fields: Vec<proc_macro2::TokenStream>,
-}
-
-impl DynamicItems {
- pub fn new() -> Self {
- Self::default()
- }
-
- pub fn get_tokens(&self, lib_ident: Ident) -> proc_macro2::TokenStream {
- let struct_members = &self.struct_members;
- let constructor_inits = &self.constructor_inits;
- let init_fields = &self.init_fields;
- let struct_implementation = &self.struct_implementation;
-
- quote! {
- extern crate libloading;
-
- pub struct #lib_ident {
- __library: ::libloading::Library,
- #(#struct_members)*
- }
-
- impl #lib_ident {
- pub unsafe fn new<P>(
- path: P
- ) -> Result<Self, ::libloading::Error>
- where P: AsRef<::std::ffi::OsStr> {
- let library = ::libloading::Library::new(path)?;
- Self::from_library(library)
- }
-
- pub unsafe fn from_library<L>(
- library: L
- ) -> Result<Self, ::libloading::Error>
- where L: Into<::libloading::Library> {
- let __library = library.into();
- #( #constructor_inits )*
- Ok(#lib_ident {
- __library,
- #( #init_fields ),*
- })
- }
-
- #( #struct_implementation )*
- }
- }
- }
-
- #[allow(clippy::too_many_arguments)]
- pub fn push(
- &mut self,
- ident: Ident,
- abi: Abi,
- is_variadic: bool,
- is_required: bool,
- args: Vec<proc_macro2::TokenStream>,
- args_identifiers: Vec<proc_macro2::TokenStream>,
- ret: proc_macro2::TokenStream,
- ret_ty: proc_macro2::TokenStream,
- attributes: Vec<proc_macro2::TokenStream>,
- ) {
- if !is_variadic {
- assert_eq!(args.len(), args_identifiers.len());
- }
-
- let signature = quote! { unsafe extern #abi fn ( #( #args),* ) #ret };
- let member = if is_required {
- signature
- } else {
- quote! { Result<#signature, ::libloading::Error> }
- };
-
- self.struct_members.push(quote! {
- pub #ident: #member,
- });
-
- // N.B: If the signature was required, it won't be wrapped in a Result<...>
- // and we can simply call it directly.
- let fn_ = if is_required {
- quote! { self.#ident }
- } else {
- quote! { self.#ident.as_ref().expect("Expected function, got error.") }
- };
- let call_body = quote! {
- (#fn_)(#( #args_identifiers ),*)
- };
-
- // We can't implement variadic functions from C easily, so we allow to
- // access the function pointer so that the user can call it just fine.
- if !is_variadic {
- self.struct_implementation.push(quote! {
- #(#attributes)*
- pub unsafe fn #ident ( &self, #( #args ),* ) -> #ret_ty {
- #call_body
- }
- });
- }
-
- // N.B: Unwrap the signature upon construction if it is required to be resolved.
- let ident_str = codegen::helpers::ast_ty::cstr_expr(ident.to_string());
- self.constructor_inits.push(if is_required {
- quote! {
- let #ident = __library.get(#ident_str).map(|sym| *sym)?;
- }
- } else {
- quote! {
- let #ident = __library.get(#ident_str).map(|sym| *sym);
- }
- });
-
- self.init_fields.push(quote! {
- #ident
- });
- }
-}
diff --git a/src/codegen/error.rs b/src/codegen/error.rs
deleted file mode 100644
index c1bcf4e1..00000000
--- a/src/codegen/error.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-use std::error;
-use std::fmt;
-
-/// Errors that can occur during code generation.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum Error {
- /// Tried to generate an opaque blob for a type that did not have a layout.
- NoLayoutForOpaqueBlob,
-
- /// Tried to instantiate an opaque template definition, or a template
- /// definition that is too difficult for us to understand (like a partial
- /// template specialization).
- InstantiationOfOpaqueType,
-}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.write_str(match *self {
- Error::NoLayoutForOpaqueBlob => {
- "Tried to generate an opaque blob, but had no layout"
- }
- Error::InstantiationOfOpaqueType => {
- "Instantiation of opaque template type or partial template \
- specialization"
- }
- })
- }
-}
-
-impl error::Error for Error {}
-
-/// A `Result` of `T` or an error of `bindgen::codegen::error::Error`.
-pub type Result<T> = ::std::result::Result<T, Error>;
diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs
deleted file mode 100644
index 5bf36acb..00000000
--- a/src/codegen/helpers.rs
+++ /dev/null
@@ -1,309 +0,0 @@
-//! Helpers for code generation that don't need macro expansion.
-
-use crate::ir::context::BindgenContext;
-use crate::ir::layout::Layout;
-use proc_macro2::{Ident, Span, TokenStream};
-use quote::TokenStreamExt;
-
-pub mod attributes {
- use proc_macro2::{Ident, Span, TokenStream};
- use std::str::FromStr;
-
- pub fn repr(which: &str) -> TokenStream {
- let which = Ident::new(which, Span::call_site());
- quote! {
- #[repr( #which )]
- }
- }
-
- pub fn repr_list(which_ones: &[&str]) -> TokenStream {
- let which_ones = which_ones
- .iter()
- .cloned()
- .map(|one| TokenStream::from_str(one).expect("repr to be valid"));
- quote! {
- #[repr( #( #which_ones ),* )]
- }
- }
-
- pub fn derives(which_ones: &[&str]) -> TokenStream {
- let which_ones = which_ones
- .iter()
- .cloned()
- .map(|one| TokenStream::from_str(one).expect("derive to be valid"));
- quote! {
- #[derive( #( #which_ones ),* )]
- }
- }
-
- pub fn inline() -> TokenStream {
- quote! {
- #[inline]
- }
- }
-
- pub fn must_use() -> TokenStream {
- quote! {
- #[must_use]
- }
- }
-
- pub fn non_exhaustive() -> TokenStream {
- quote! {
- #[non_exhaustive]
- }
- }
-
- pub fn doc(comment: String) -> TokenStream {
- // NOTE(emilio): By this point comments are already preprocessed and in
- // `///` form. Quote turns them into `#[doc]` comments, but oh well.
- TokenStream::from_str(&comment).unwrap()
- }
-
- pub fn link_name(name: &str) -> TokenStream {
- // LLVM mangles the name by default but it's already mangled.
- // Prefixing the name with \u{1} should tell LLVM to not mangle it.
- let name = format!("\u{1}{}", name);
- quote! {
- #[link_name = #name]
- }
- }
-}
-
-/// Generates a proper type for a field or type with a given `Layout`, that is,
-/// a type with the correct size and alignment restrictions.
-pub fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream {
- let opaque = layout.opaque();
-
- // FIXME(emilio, #412): We fall back to byte alignment, but there are
- // some things that legitimately are more than 8-byte aligned.
- //
- // Eventually we should be able to `unwrap` here, but...
- let ty_name = match opaque.known_rust_type_for_array(ctx) {
- Some(ty) => ty,
- None => {
- warn!("Found unknown alignment on code generation!");
- "u8"
- }
- };
-
- let ty_name = Ident::new(ty_name, Span::call_site());
-
- let data_len = opaque.array_size(ctx).unwrap_or(layout.size);
-
- if data_len == 1 {
- quote! {
- #ty_name
- }
- } else {
- quote! {
- [ #ty_name ; #data_len ]
- }
- }
-}
-
-/// Integer type of the same size as the given `Layout`.
-pub fn integer_type(
- ctx: &BindgenContext,
- layout: Layout,
-) -> Option<TokenStream> {
- let name = Layout::known_type_for_size(ctx, layout.size)?;
- let name = Ident::new(name, Span::call_site());
- Some(quote! { #name })
-}
-
-/// Generates a bitfield allocation unit type for a type with the given `Layout`.
-pub fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> TokenStream {
- let mut tokens = quote! {};
-
- if ctx.options().enable_cxx_namespaces {
- tokens.append_all(quote! { root:: });
- }
-
- let size = layout.size;
- tokens.append_all(quote! {
- __BindgenBitfieldUnit<[u8; #size]>
- });
-
- tokens
-}
-
-pub mod ast_ty {
- use crate::ir::context::BindgenContext;
- use crate::ir::function::FunctionSig;
- use crate::ir::layout::Layout;
- use crate::ir::ty::FloatKind;
- use proc_macro2::{self, TokenStream};
- use std::str::FromStr;
-
- pub fn c_void(ctx: &BindgenContext) -> TokenStream {
- // ctypes_prefix takes precedence
- match ctx.options().ctypes_prefix {
- Some(ref prefix) => {
- let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
- quote! {
- #prefix::c_void
- }
- }
- None => {
- if ctx.options().use_core &&
- ctx.options().rust_features.core_ffi_c_void
- {
- quote! { ::core::ffi::c_void }
- } else {
- quote! { ::std::os::raw::c_void }
- }
- }
- }
- }
-
- pub fn raw_type(ctx: &BindgenContext, name: &str) -> TokenStream {
- let ident = ctx.rust_ident_raw(name);
- match ctx.options().ctypes_prefix {
- Some(ref prefix) => {
- let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
- quote! {
- #prefix::#ident
- }
- }
- None => {
- if ctx.options().use_core &&
- ctx.options().rust_features().core_ffi_c
- {
- quote! {
- ::core::ffi::#ident
- }
- } else {
- quote! {
- ::std::os::raw::#ident
- }
- }
- }
- }
- }
-
- pub fn float_kind_rust_type(
- ctx: &BindgenContext,
- fk: FloatKind,
- layout: Option<Layout>,
- ) -> TokenStream {
- // TODO: we probably should take the type layout into account more
- // often?
- //
- // Also, maybe this one shouldn't be the default?
- match (fk, ctx.options().convert_floats) {
- (FloatKind::Float, true) => quote! { f32 },
- (FloatKind::Double, true) => quote! { f64 },
- (FloatKind::Float, false) => raw_type(ctx, "c_float"),
- (FloatKind::Double, false) => raw_type(ctx, "c_double"),
- (FloatKind::LongDouble, _) => {
- match layout {
- Some(layout) => {
- match layout.size {
- 4 => quote! { f32 },
- 8 => quote! { f64 },
- // TODO(emilio): If rust ever gains f128 we should
- // use it here and below.
- _ => super::integer_type(ctx, layout)
- .unwrap_or(quote! { f64 }),
- }
- }
- None => {
- debug_assert!(
- false,
- "How didn't we know the layout for a primitive type?"
- );
- quote! { f64 }
- }
- }
- }
- (FloatKind::Float128, _) => {
- if ctx.options().rust_features.i128_and_u128 {
- quote! { u128 }
- } else {
- quote! { [u64; 2] }
- }
- }
- }
- }
-
- pub fn int_expr(val: i64) -> TokenStream {
- // Don't use quote! { #val } because that adds the type suffix.
- let val = proc_macro2::Literal::i64_unsuffixed(val);
- quote!(#val)
- }
-
- pub fn uint_expr(val: u64) -> TokenStream {
- // Don't use quote! { #val } because that adds the type suffix.
- let val = proc_macro2::Literal::u64_unsuffixed(val);
- quote!(#val)
- }
-
- pub fn byte_array_expr(bytes: &[u8]) -> TokenStream {
- let mut bytes: Vec<_> = bytes.to_vec();
- bytes.push(0);
- quote! { [ #(#bytes),* ] }
- }
-
- pub fn cstr_expr(mut string: String) -> TokenStream {
- string.push('\0');
- let b = proc_macro2::Literal::byte_string(string.as_bytes());
- quote! {
- #b
- }
- }
-
- pub fn float_expr(ctx: &BindgenContext, f: f64) -> Result<TokenStream, ()> {
- if f.is_finite() {
- let val = proc_macro2::Literal::f64_unsuffixed(f);
-
- return Ok(quote!(#val));
- }
-
- let prefix = ctx.trait_prefix();
-
- if f.is_nan() {
- return Ok(quote! {
- ::#prefix::f64::NAN
- });
- }
-
- if f.is_infinite() {
- return Ok(if f.is_sign_positive() {
- quote! {
- ::#prefix::f64::INFINITY
- }
- } else {
- quote! {
- ::#prefix::f64::NEG_INFINITY
- }
- });
- }
-
- warn!("Unknown non-finite float number: {:?}", f);
- Err(())
- }
-
- pub fn arguments_from_signature(
- signature: &FunctionSig,
- ctx: &BindgenContext,
- ) -> Vec<TokenStream> {
- let mut unnamed_arguments = 0;
- signature
- .argument_types()
- .iter()
- .map(|&(ref name, _ty)| match *name {
- Some(ref name) => {
- let name = ctx.rust_ident(name);
- quote! { #name }
- }
- None => {
- unnamed_arguments += 1;
- let name =
- ctx.rust_ident(format!("arg{}", unnamed_arguments));
- quote! { #name }
- }
- })
- .collect()
- }
-}
diff --git a/src/codegen/impl_debug.rs b/src/codegen/impl_debug.rs
deleted file mode 100644
index 0e2cd33a..00000000
--- a/src/codegen/impl_debug.rs
+++ /dev/null
@@ -1,245 +0,0 @@
-use crate::ir::comp::{BitfieldUnit, CompKind, Field, FieldData, FieldMethods};
-use crate::ir::context::BindgenContext;
-use crate::ir::item::{HasTypeParamInArray, IsOpaque, Item, ItemCanonicalName};
-use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
-
-pub fn gen_debug_impl(
- ctx: &BindgenContext,
- fields: &[Field],
- item: &Item,
- kind: CompKind,
-) -> proc_macro2::TokenStream {
- let struct_name = item.canonical_name(ctx);
- let mut format_string = format!("{} {{{{ ", struct_name);
- let mut tokens = vec![];
-
- if item.is_opaque(ctx, &()) {
- format_string.push_str("opaque");
- } else {
- match kind {
- CompKind::Union => {
- format_string.push_str("union");
- }
- CompKind::Struct => {
- let processed_fields = fields.iter().filter_map(|f| match f {
- Field::DataMember(ref fd) => fd.impl_debug(ctx, ()),
- Field::Bitfields(ref bu) => bu.impl_debug(ctx, ()),
- });
-
- for (i, (fstring, toks)) in processed_fields.enumerate() {
- if i > 0 {
- format_string.push_str(", ");
- }
- tokens.extend(toks);
- format_string.push_str(&fstring);
- }
- }
- }
- }
-
- format_string.push_str(" }}");
- tokens.insert(0, quote! { #format_string });
-
- let prefix = ctx.trait_prefix();
-
- quote! {
- fn fmt(&self, f: &mut ::#prefix::fmt::Formatter<'_>) -> ::#prefix ::fmt::Result {
- write!(f, #( #tokens ),*)
- }
- }
-}
-
-/// A trait for the things which we can codegen tokens that contribute towards a
-/// generated `impl Debug`.
-pub trait ImplDebug<'a> {
- /// Any extra parameter required by this a particular `ImplDebug` implementation.
- type Extra;
-
- /// Generate a format string snippet to be included in the larger `impl Debug`
- /// format string, and the code to get the format string's interpolation values.
- fn impl_debug(
- &self,
- ctx: &BindgenContext,
- extra: Self::Extra,
- ) -> Option<(String, Vec<proc_macro2::TokenStream>)>;
-}
-
-impl<'a> ImplDebug<'a> for FieldData {
- type Extra = ();
-
- fn impl_debug(
- &self,
- ctx: &BindgenContext,
- _: Self::Extra,
- ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
- if let Some(name) = self.name() {
- ctx.resolve_item(self.ty()).impl_debug(ctx, name)
- } else {
- None
- }
- }
-}
-
-impl<'a> ImplDebug<'a> for BitfieldUnit {
- type Extra = ();
-
- fn impl_debug(
- &self,
- ctx: &BindgenContext,
- _: Self::Extra,
- ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
- let mut format_string = String::new();
- let mut tokens = vec![];
- for (i, bitfield) in self.bitfields().iter().enumerate() {
- if i > 0 {
- format_string.push_str(", ");
- }
-
- if let Some(bitfield_name) = bitfield.name() {
- format_string.push_str(&format!("{} : {{:?}}", bitfield_name));
- let getter_name = bitfield.getter_name();
- let name_ident = ctx.rust_ident_raw(getter_name);
- tokens.push(quote! {
- self.#name_ident ()
- });
- }
- }
-
- Some((format_string, tokens))
- }
-}
-
-impl<'a> ImplDebug<'a> for Item {
- type Extra = &'a str;
-
- fn impl_debug(
- &self,
- ctx: &BindgenContext,
- name: &str,
- ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
- let name_ident = ctx.rust_ident(name);
-
- // We don't know if blocklisted items `impl Debug` or not, so we can't
- // add them to the format string we're building up.
- if !ctx.allowlisted_items().contains(&self.id()) {
- return None;
- }
-
- let ty = match self.as_type() {
- Some(ty) => ty,
- None => {
- return None;
- }
- };
-
- fn debug_print(
- name: &str,
- name_ident: proc_macro2::TokenStream,
- ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
- Some((
- format!("{}: {{:?}}", name),
- vec![quote! {
- self.#name_ident
- }],
- ))
- }
-
- match *ty.kind() {
- // Handle the simple cases.
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Int(..) |
- TypeKind::Float(..) |
- TypeKind::Complex(..) |
- TypeKind::Function(..) |
- TypeKind::Enum(..) |
- TypeKind::Reference(..) |
- TypeKind::UnresolvedTypeRef(..) |
- TypeKind::ObjCInterface(..) |
- TypeKind::ObjCId |
- TypeKind::Comp(..) |
- TypeKind::ObjCSel => debug_print(name, quote! { #name_ident }),
-
- TypeKind::TemplateInstantiation(ref inst) => {
- if inst.is_opaque(ctx, self) {
- Some((format!("{}: opaque", name), vec![]))
- } else {
- debug_print(name, quote! { #name_ident })
- }
- }
-
- // The generic is not required to implement Debug, so we can not debug print that type
- TypeKind::TypeParam => {
- Some((format!("{}: Non-debuggable generic", name), vec![]))
- }
-
- TypeKind::Array(_, len) => {
- // Generics are not required to implement Debug
- if self.has_type_param_in_array(ctx) {
- Some((
- format!("{}: Array with length {}", name, len),
- vec![],
- ))
- } else if len < RUST_DERIVE_IN_ARRAY_LIMIT ||
- ctx.options().rust_features().larger_arrays
- {
- // The simple case
- debug_print(name, quote! { #name_ident })
- } else if ctx.options().use_core {
- // There is no String in core; reducing field visibility to avoid breaking
- // no_std setups.
- Some((format!("{}: [...]", name), vec![]))
- } else {
- // Let's implement our own print function
- Some((
- format!("{}: [{{}}]", name),
- vec![quote! {
- self.#name_ident
- .iter()
- .enumerate()
- .map(|(i, v)| format!("{}{:?}", if i > 0 { ", " } else { "" }, v))
- .collect::<String>()
- }],
- ))
- }
- }
- TypeKind::Vector(_, len) => {
- if ctx.options().use_core {
- // There is no format! in core; reducing field visibility to avoid breaking
- // no_std setups.
- Some((format!("{}(...)", name), vec![]))
- } else {
- let self_ids = 0..len;
- Some((
- format!("{}({{}})", name),
- vec![quote! {
- #(format!("{:?}", self.#self_ids)),*
- }],
- ))
- }
- }
-
- TypeKind::ResolvedTypeRef(t) |
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::BlockPointer(t) => {
- // We follow the aliases
- ctx.resolve_item(t).impl_debug(ctx, name)
- }
-
- TypeKind::Pointer(inner) => {
- let inner_type = ctx.resolve_type(inner).canonical_type(ctx);
- match *inner_type.kind() {
- TypeKind::Function(ref sig)
- if !sig.function_pointers_can_derive() =>
- {
- Some((format!("{}: FunctionPointer", name), vec![]))
- }
- _ => debug_print(name, quote! { #name_ident }),
- }
- }
-
- TypeKind::Opaque => None,
- }
- }
-}
diff --git a/src/codegen/impl_partialeq.rs b/src/codegen/impl_partialeq.rs
deleted file mode 100644
index 960306ff..00000000
--- a/src/codegen/impl_partialeq.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-use crate::ir::comp::{CompInfo, CompKind, Field, FieldMethods};
-use crate::ir::context::BindgenContext;
-use crate::ir::item::{IsOpaque, Item};
-use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
-
-/// Generate a manual implementation of `PartialEq` trait for the
-/// specified compound type.
-pub fn gen_partialeq_impl(
- ctx: &BindgenContext,
- comp_info: &CompInfo,
- item: &Item,
- ty_for_impl: &proc_macro2::TokenStream,
-) -> Option<proc_macro2::TokenStream> {
- let mut tokens = vec![];
-
- if item.is_opaque(ctx, &()) {
- tokens.push(quote! {
- &self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..]
- });
- } else if comp_info.kind() == CompKind::Union {
- assert!(!ctx.options().rust_features().untagged_union);
- tokens.push(quote! {
- &self.bindgen_union_field[..] == &other.bindgen_union_field[..]
- });
- } else {
- for base in comp_info.base_members().iter() {
- if !base.requires_storage(ctx) {
- continue;
- }
-
- let ty_item = ctx.resolve_item(base.ty);
- let field_name = &base.field_name;
-
- if ty_item.is_opaque(ctx, &()) {
- let field_name = ctx.rust_ident(field_name);
- tokens.push(quote! {
- &self. #field_name [..] == &other. #field_name [..]
- });
- } else {
- tokens.push(gen_field(ctx, ty_item, field_name));
- }
- }
-
- for field in comp_info.fields() {
- match *field {
- Field::DataMember(ref fd) => {
- let ty_item = ctx.resolve_item(fd.ty());
- let name = fd.name().unwrap();
- tokens.push(gen_field(ctx, ty_item, name));
- }
- Field::Bitfields(ref bu) => {
- for bitfield in bu.bitfields() {
- if bitfield.name().is_some() {
- let getter_name = bitfield.getter_name();
- let name_ident = ctx.rust_ident_raw(getter_name);
- tokens.push(quote! {
- self.#name_ident () == other.#name_ident ()
- });
- }
- }
- }
- }
- }
- }
-
- Some(quote! {
- fn eq(&self, other: & #ty_for_impl) -> bool {
- #( #tokens )&&*
- }
- })
-}
-
-fn gen_field(
- ctx: &BindgenContext,
- ty_item: &Item,
- name: &str,
-) -> proc_macro2::TokenStream {
- fn quote_equals(
- name_ident: proc_macro2::Ident,
- ) -> proc_macro2::TokenStream {
- quote! { self.#name_ident == other.#name_ident }
- }
-
- let name_ident = ctx.rust_ident(name);
- let ty = ty_item.expect_type();
-
- match *ty.kind() {
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Int(..) |
- TypeKind::Complex(..) |
- TypeKind::Float(..) |
- TypeKind::Enum(..) |
- TypeKind::TypeParam |
- TypeKind::UnresolvedTypeRef(..) |
- TypeKind::Reference(..) |
- TypeKind::ObjCInterface(..) |
- TypeKind::ObjCId |
- TypeKind::ObjCSel |
- TypeKind::Comp(..) |
- TypeKind::Pointer(_) |
- TypeKind::Function(..) |
- TypeKind::Opaque => quote_equals(name_ident),
-
- TypeKind::TemplateInstantiation(ref inst) => {
- if inst.is_opaque(ctx, ty_item) {
- quote! {
- &self. #name_ident [..] == &other. #name_ident [..]
- }
- } else {
- quote_equals(name_ident)
- }
- }
-
- TypeKind::Array(_, len) => {
- if len <= RUST_DERIVE_IN_ARRAY_LIMIT ||
- ctx.options().rust_features().larger_arrays
- {
- quote_equals(name_ident)
- } else {
- quote! {
- &self. #name_ident [..] == &other. #name_ident [..]
- }
- }
- }
- TypeKind::Vector(_, len) => {
- let self_ids = 0..len;
- let other_ids = 0..len;
- quote! {
- #(self.#self_ids == other.#other_ids &&)* true
- }
- }
-
- TypeKind::ResolvedTypeRef(t) |
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::BlockPointer(t) => {
- let inner_item = ctx.resolve_item(t);
- gen_field(ctx, inner_item, name)
- }
- }
-}
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
deleted file mode 100644
index 7e0d7aa0..00000000
--- a/src/codegen/mod.rs
+++ /dev/null
@@ -1,5050 +0,0 @@
-mod dyngen;
-mod error;
-mod helpers;
-mod impl_debug;
-mod impl_partialeq;
-mod postprocessing;
-pub mod struct_layout;
-
-#[cfg(test)]
-#[allow(warnings)]
-pub(crate) mod bitfield_unit;
-#[cfg(all(test, target_endian = "little"))]
-mod bitfield_unit_tests;
-
-use self::dyngen::DynamicItems;
-use self::helpers::attributes;
-use self::struct_layout::StructLayoutTracker;
-
-use super::BindgenOptions;
-
-use crate::ir::analysis::{HasVtable, Sizedness};
-use crate::ir::annotations::FieldAccessorKind;
-use crate::ir::comment;
-use crate::ir::comp::{
- Bitfield, BitfieldUnit, CompInfo, CompKind, Field, FieldData, FieldMethods,
- Method, MethodKind,
-};
-use crate::ir::context::{BindgenContext, ItemId};
-use crate::ir::derive::{
- CanDerive, CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq,
- CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd,
-};
-use crate::ir::dot;
-use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
-use crate::ir::function::{Abi, Function, FunctionKind, FunctionSig, Linkage};
-use crate::ir::int::IntKind;
-use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath};
-use crate::ir::item_kind::ItemKind;
-use crate::ir::layout::Layout;
-use crate::ir::module::Module;
-use crate::ir::objc::{ObjCInterface, ObjCMethod};
-use crate::ir::template::{
- AsTemplateParam, TemplateInstantiation, TemplateParameters,
-};
-use crate::ir::ty::{Type, TypeKind};
-use crate::ir::var::Var;
-
-use proc_macro2::{self, Ident, Span};
-use quote::TokenStreamExt;
-
-use crate::{Entry, HashMap, HashSet};
-use std::borrow::Cow;
-use std::cell::Cell;
-use std::collections::VecDeque;
-use std::fmt::Write;
-use std::iter;
-use std::ops;
-use std::str::FromStr;
-
-// Name of type defined in constified enum module
-pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &str = "Type";
-
-fn top_level_path(
- ctx: &BindgenContext,
- item: &Item,
-) -> Vec<proc_macro2::TokenStream> {
- let mut path = vec![quote! { self }];
-
- if ctx.options().enable_cxx_namespaces {
- for _ in 0..item.codegen_depth(ctx) {
- path.push(quote! { super });
- }
- }
-
- path
-}
-
-fn root_import(
- ctx: &BindgenContext,
- module: &Item,
-) -> proc_macro2::TokenStream {
- assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up");
- assert!(module.is_module());
-
- let mut path = top_level_path(ctx, module);
-
- let root = ctx.root_module().canonical_name(ctx);
- let root_ident = ctx.rust_ident(&root);
- path.push(quote! { #root_ident });
-
- let mut tokens = quote! {};
- tokens.append_separated(path, quote!(::));
-
- quote! {
- #[allow(unused_imports)]
- use #tokens ;
- }
-}
-
-bitflags! {
- struct DerivableTraits: u16 {
- const DEBUG = 1 << 0;
- const DEFAULT = 1 << 1;
- const COPY = 1 << 2;
- const CLONE = 1 << 3;
- const HASH = 1 << 4;
- const PARTIAL_ORD = 1 << 5;
- const ORD = 1 << 6;
- const PARTIAL_EQ = 1 << 7;
- const EQ = 1 << 8;
- }
-}
-
-fn derives_of_item(
- item: &Item,
- ctx: &BindgenContext,
- packed: bool,
-) -> DerivableTraits {
- let mut derivable_traits = DerivableTraits::empty();
-
- let all_template_params = item.all_template_params(ctx);
-
- if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
- derivable_traits |= DerivableTraits::COPY;
-
- if ctx.options().rust_features().builtin_clone_impls ||
- !all_template_params.is_empty()
- {
- // FIXME: This requires extra logic if you have a big array in a
- // templated struct. The reason for this is that the magic:
- // fn clone(&self) -> Self { *self }
- // doesn't work for templates.
- //
- // It's not hard to fix though.
- derivable_traits |= DerivableTraits::CLONE;
- }
- } else if packed {
- // If the struct or union is packed, deriving from Copy is required for
- // deriving from any other trait.
- return derivable_traits;
- }
-
- if item.can_derive_debug(ctx) && !item.annotations().disallow_debug() {
- derivable_traits |= DerivableTraits::DEBUG;
- }
-
- if item.can_derive_default(ctx) && !item.annotations().disallow_default() {
- derivable_traits |= DerivableTraits::DEFAULT;
- }
-
- if item.can_derive_hash(ctx) {
- derivable_traits |= DerivableTraits::HASH;
- }
-
- if item.can_derive_partialord(ctx) {
- derivable_traits |= DerivableTraits::PARTIAL_ORD;
- }
-
- if item.can_derive_ord(ctx) {
- derivable_traits |= DerivableTraits::ORD;
- }
-
- if item.can_derive_partialeq(ctx) {
- derivable_traits |= DerivableTraits::PARTIAL_EQ;
- }
-
- if item.can_derive_eq(ctx) {
- derivable_traits |= DerivableTraits::EQ;
- }
-
- derivable_traits
-}
-
-impl From<DerivableTraits> for Vec<&'static str> {
- fn from(derivable_traits: DerivableTraits) -> Vec<&'static str> {
- [
- (DerivableTraits::DEBUG, "Debug"),
- (DerivableTraits::DEFAULT, "Default"),
- (DerivableTraits::COPY, "Copy"),
- (DerivableTraits::CLONE, "Clone"),
- (DerivableTraits::HASH, "Hash"),
- (DerivableTraits::PARTIAL_ORD, "PartialOrd"),
- (DerivableTraits::ORD, "Ord"),
- (DerivableTraits::PARTIAL_EQ, "PartialEq"),
- (DerivableTraits::EQ, "Eq"),
- ]
- .iter()
- .filter_map(|&(flag, derive)| {
- Some(derive).filter(|_| derivable_traits.contains(flag))
- })
- .collect()
- }
-}
-
-struct CodegenResult<'a> {
- items: Vec<proc_macro2::TokenStream>,
- dynamic_items: DynamicItems,
-
- /// A monotonic counter used to add stable unique id's to stuff that doesn't
- /// need to be referenced by anything.
- codegen_id: &'a Cell<usize>,
-
- /// Whether a bindgen union has been generated at least once.
- saw_bindgen_union: bool,
-
- /// Whether an incomplete array has been generated at least once.
- saw_incomplete_array: bool,
-
- /// Whether Objective C types have been seen at least once.
- saw_objc: bool,
-
- /// Whether Apple block types have been seen at least once.
- saw_block: bool,
-
- /// Whether a bitfield allocation unit has been seen at least once.
- saw_bitfield_unit: bool,
-
- items_seen: HashSet<ItemId>,
- /// The set of generated function/var names, needed because in C/C++ is
- /// legal to do something like:
- ///
- /// ```c++
- /// extern "C" {
- /// void foo();
- /// extern int bar;
- /// }
- ///
- /// extern "C" {
- /// void foo();
- /// extern int bar;
- /// }
- /// ```
- ///
- /// Being these two different declarations.
- functions_seen: HashSet<String>,
- vars_seen: HashSet<String>,
-
- /// Used for making bindings to overloaded functions. Maps from a canonical
- /// function name to the number of overloads we have already codegen'd for
- /// that name. This lets us give each overload a unique suffix.
- overload_counters: HashMap<String, u32>,
-}
-
-impl<'a> CodegenResult<'a> {
- fn new(codegen_id: &'a Cell<usize>) -> Self {
- CodegenResult {
- items: vec![],
- dynamic_items: DynamicItems::new(),
- saw_bindgen_union: false,
- saw_incomplete_array: false,
- saw_objc: false,
- saw_block: false,
- saw_bitfield_unit: false,
- codegen_id,
- items_seen: Default::default(),
- functions_seen: Default::default(),
- vars_seen: Default::default(),
- overload_counters: Default::default(),
- }
- }
-
- fn dynamic_items(&mut self) -> &mut DynamicItems {
- &mut self.dynamic_items
- }
-
- fn saw_bindgen_union(&mut self) {
- self.saw_bindgen_union = true;
- }
-
- fn saw_incomplete_array(&mut self) {
- self.saw_incomplete_array = true;
- }
-
- fn saw_objc(&mut self) {
- self.saw_objc = true;
- }
-
- fn saw_block(&mut self) {
- self.saw_block = true;
- }
-
- fn saw_bitfield_unit(&mut self) {
- self.saw_bitfield_unit = true;
- }
-
- fn seen<Id: Into<ItemId>>(&self, item: Id) -> bool {
- self.items_seen.contains(&item.into())
- }
-
- fn set_seen<Id: Into<ItemId>>(&mut self, item: Id) {
- self.items_seen.insert(item.into());
- }
-
- fn seen_function(&self, name: &str) -> bool {
- self.functions_seen.contains(name)
- }
-
- fn saw_function(&mut self, name: &str) {
- self.functions_seen.insert(name.into());
- }
-
- /// Get the overload number for the given function name. Increments the
- /// counter internally so the next time we ask for the overload for this
- /// name, we get the incremented value, and so on.
- fn overload_number(&mut self, name: &str) -> u32 {
- let counter = self.overload_counters.entry(name.into()).or_insert(0);
- let number = *counter;
- *counter += 1;
- number
- }
-
- fn seen_var(&self, name: &str) -> bool {
- self.vars_seen.contains(name)
- }
-
- fn saw_var(&mut self, name: &str) {
- self.vars_seen.insert(name.into());
- }
-
- fn inner<F>(&mut self, cb: F) -> Vec<proc_macro2::TokenStream>
- where
- F: FnOnce(&mut Self),
- {
- let mut new = Self::new(self.codegen_id);
-
- cb(&mut new);
-
- self.saw_incomplete_array |= new.saw_incomplete_array;
- self.saw_objc |= new.saw_objc;
- self.saw_block |= new.saw_block;
- self.saw_bitfield_unit |= new.saw_bitfield_unit;
- self.saw_bindgen_union |= new.saw_bindgen_union;
-
- new.items
- }
-}
-
-impl<'a> ops::Deref for CodegenResult<'a> {
- type Target = Vec<proc_macro2::TokenStream>;
-
- fn deref(&self) -> &Self::Target {
- &self.items
- }
-}
-
-impl<'a> ops::DerefMut for CodegenResult<'a> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.items
- }
-}
-
-/// A trait to convert a rust type into a pointer, optionally const, to the same
-/// type.
-trait ToPtr {
- fn to_ptr(self, is_const: bool) -> proc_macro2::TokenStream;
-}
-
-impl ToPtr for proc_macro2::TokenStream {
- fn to_ptr(self, is_const: bool) -> proc_macro2::TokenStream {
- if is_const {
- quote! { *const #self }
- } else {
- quote! { *mut #self }
- }
- }
-}
-
-/// An extension trait for `proc_macro2::TokenStream` that lets us append any implicit
-/// template parameters that exist for some type, if necessary.
-trait AppendImplicitTemplateParams {
- fn append_implicit_template_params(
- &mut self,
- ctx: &BindgenContext,
- item: &Item,
- );
-}
-
-impl AppendImplicitTemplateParams for proc_macro2::TokenStream {
- fn append_implicit_template_params(
- &mut self,
- ctx: &BindgenContext,
- item: &Item,
- ) {
- let item = item.id().into_resolver().through_type_refs().resolve(ctx);
-
- match *item.expect_type().kind() {
- TypeKind::UnresolvedTypeRef(..) => {
- unreachable!("already resolved unresolved type refs")
- }
- TypeKind::ResolvedTypeRef(..) => {
- unreachable!("we resolved item through type refs")
- }
-
- // None of these types ever have implicit template parameters.
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Pointer(..) |
- TypeKind::Reference(..) |
- TypeKind::Int(..) |
- TypeKind::Float(..) |
- TypeKind::Complex(..) |
- TypeKind::Array(..) |
- TypeKind::TypeParam |
- TypeKind::Opaque |
- TypeKind::Function(..) |
- TypeKind::Enum(..) |
- TypeKind::ObjCId |
- TypeKind::ObjCSel |
- TypeKind::TemplateInstantiation(..) => return,
- _ => {}
- }
-
- let params: Vec<_> = item
- .used_template_params(ctx)
- .iter()
- .map(|p| {
- p.try_to_rust_ty(ctx, &())
- .expect("template params cannot fail to be a rust type")
- })
- .collect();
- if !params.is_empty() {
- self.append_all(quote! {
- < #( #params ),* >
- });
- }
- }
-}
-
-trait CodeGenerator {
- /// Extra information from the caller.
- type Extra;
-
- /// Extra information returned to the caller.
- type Return;
-
- fn codegen<'a>(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
- extra: &Self::Extra,
- ) -> Self::Return;
-}
-
-impl Item {
- fn process_before_codegen(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult,
- ) -> bool {
- if !self.is_enabled_for_codegen(ctx) {
- return false;
- }
-
- if self.is_blocklisted(ctx) || result.seen(self.id()) {
- debug!(
- "<Item as CodeGenerator>::process_before_codegen: Ignoring hidden or seen: \
- self = {:?}",
- self
- );
- return false;
- }
-
- if !ctx.codegen_items().contains(&self.id()) {
- // TODO(emilio, #453): Figure out what to do when this happens
- // legitimately, we could track the opaque stuff and disable the
- // assertion there I guess.
- warn!("Found non-allowlisted item in code generation: {:?}", self);
- }
-
- result.set_seen(self.id());
- true
- }
-}
-
-impl CodeGenerator for Item {
- type Extra = ();
- type Return = ();
-
- fn codegen<'a>(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
- _extra: &(),
- ) {
- debug!("<Item as CodeGenerator>::codegen: self = {:?}", self);
- if !self.process_before_codegen(ctx, result) {
- return;
- }
-
- match *self.kind() {
- ItemKind::Module(ref module) => {
- module.codegen(ctx, result, self);
- }
- ItemKind::Function(ref fun) => {
- fun.codegen(ctx, result, self);
- }
- ItemKind::Var(ref var) => {
- var.codegen(ctx, result, self);
- }
- ItemKind::Type(ref ty) => {
- ty.codegen(ctx, result, self);
- }
- }
- }
-}
-
-impl CodeGenerator for Module {
- type Extra = Item;
- type Return = ();
-
- fn codegen<'a>(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
- item: &Item,
- ) {
- debug!("<Module as CodeGenerator>::codegen: item = {:?}", item);
-
- let codegen_self = |result: &mut CodegenResult,
- found_any: &mut bool| {
- for child in self.children() {
- if ctx.codegen_items().contains(child) {
- *found_any = true;
- ctx.resolve_item(*child).codegen(ctx, result, &());
- }
- }
-
- if item.id() == ctx.root_module() {
- if result.saw_block {
- utils::prepend_block_header(ctx, &mut *result);
- }
- if result.saw_bindgen_union {
- utils::prepend_union_types(ctx, &mut *result);
- }
- if result.saw_incomplete_array {
- utils::prepend_incomplete_array_types(ctx, &mut *result);
- }
- if ctx.need_bindgen_complex_type() {
- utils::prepend_complex_type(&mut *result);
- }
- if result.saw_objc {
- utils::prepend_objc_header(ctx, &mut *result);
- }
- if result.saw_bitfield_unit {
- utils::prepend_bitfield_unit_type(ctx, &mut *result);
- }
- }
- };
-
- if !ctx.options().enable_cxx_namespaces ||
- (self.is_inline() &&
- !ctx.options().conservative_inline_namespaces)
- {
- codegen_self(result, &mut false);
- return;
- }
-
- let mut found_any = false;
- let inner_items = result.inner(|result| {
- result.push(root_import(ctx, item));
-
- let path = item.namespace_aware_canonical_path(ctx).join("::");
- if let Some(raw_lines) = ctx.options().module_lines.get(&path) {
- for raw_line in raw_lines {
- found_any = true;
- result.push(
- proc_macro2::TokenStream::from_str(raw_line).unwrap(),
- );
- }
- }
-
- codegen_self(result, &mut found_any);
- });
-
- // Don't bother creating an empty module.
- if !found_any {
- return;
- }
-
- let name = item.canonical_name(ctx);
- let ident = ctx.rust_ident(name);
- result.push(if item.id() == ctx.root_module() {
- quote! {
- #[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
- pub mod #ident {
- #( #inner_items )*
- }
- }
- } else {
- quote! {
- pub mod #ident {
- #( #inner_items )*
- }
- }
- });
- }
-}
-
-impl CodeGenerator for Var {
- type Extra = Item;
- type Return = ();
-
- fn codegen<'a>(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
- item: &Item,
- ) {
- use crate::ir::var::VarType;
- debug!("<Var as CodeGenerator>::codegen: item = {:?}", item);
- debug_assert!(item.is_enabled_for_codegen(ctx));
-
- let canonical_name = item.canonical_name(ctx);
-
- if result.seen_var(&canonical_name) {
- return;
- }
- result.saw_var(&canonical_name);
-
- let canonical_ident = ctx.rust_ident(&canonical_name);
-
- // We can't generate bindings to static variables of templates. The
- // number of actual variables for a single declaration are open ended
- // and we don't know what instantiations do or don't exist.
- if !item.all_template_params(ctx).is_empty() {
- return;
- }
-
- let mut attrs = vec![];
- if let Some(comment) = item.comment(ctx) {
- attrs.push(attributes::doc(comment));
- }
-
- let ty = self.ty().to_rust_ty_or_opaque(ctx, &());
-
- if let Some(val) = self.val() {
- match *val {
- VarType::Bool(val) => {
- result.push(quote! {
- #(#attrs)*
- pub const #canonical_ident : #ty = #val ;
- });
- }
- VarType::Int(val) => {
- let int_kind = self
- .ty()
- .into_resolver()
- .through_type_aliases()
- .through_type_refs()
- .resolve(ctx)
- .expect_type()
- .as_integer()
- .unwrap();
- let val = if int_kind.is_signed() {
- helpers::ast_ty::int_expr(val)
- } else {
- helpers::ast_ty::uint_expr(val as _)
- };
- result.push(quote! {
- #(#attrs)*
- pub const #canonical_ident : #ty = #val ;
- });
- }
- VarType::String(ref bytes) => {
- // Account the trailing zero.
- //
- // TODO: Here we ignore the type we just made up, probably
- // we should refactor how the variable type and ty id work.
- let len = bytes.len() + 1;
- let ty = quote! {
- [u8; #len]
- };
-
- match String::from_utf8(bytes.clone()) {
- Ok(string) => {
- let cstr = helpers::ast_ty::cstr_expr(string);
- if ctx
- .options()
- .rust_features
- .static_lifetime_elision
- {
- result.push(quote! {
- #(#attrs)*
- pub const #canonical_ident : &#ty = #cstr ;
- });
- } else {
- result.push(quote! {
- #(#attrs)*
- pub const #canonical_ident : &'static #ty = #cstr ;
- });
- }
- }
- Err(..) => {
- let bytes = helpers::ast_ty::byte_array_expr(bytes);
- result.push(quote! {
- #(#attrs)*
- pub const #canonical_ident : #ty = #bytes ;
- });
- }
- }
- }
- VarType::Float(f) => {
- if let Ok(expr) = helpers::ast_ty::float_expr(ctx, f) {
- result.push(quote! {
- #(#attrs)*
- pub const #canonical_ident : #ty = #expr ;
- });
- }
- }
- VarType::Char(c) => {
- result.push(quote! {
- #(#attrs)*
- pub const #canonical_ident : #ty = #c ;
- });
- }
- }
- } else {
- // If necessary, apply a `#[link_name]` attribute
- let link_name = self.mangled_name().unwrap_or_else(|| self.name());
- if !utils::names_will_be_identical_after_mangling(
- &canonical_name,
- link_name,
- None,
- ) {
- attrs.push(attributes::link_name(link_name));
- }
-
- let maybe_mut = if self.is_const() {
- quote! {}
- } else {
- quote! { mut }
- };
-
- let tokens = quote!(
- extern "C" {
- #(#attrs)*
- pub static #maybe_mut #canonical_ident: #ty;
- }
- );
-
- result.push(tokens);
- }
- }
-}
-
-impl CodeGenerator for Type {
- type Extra = Item;
- type Return = ();
-
- fn codegen<'a>(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
- item: &Item,
- ) {
- debug!("<Type as CodeGenerator>::codegen: item = {:?}", item);
- debug_assert!(item.is_enabled_for_codegen(ctx));
-
- match *self.kind() {
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Int(..) |
- TypeKind::Float(..) |
- TypeKind::Complex(..) |
- TypeKind::Array(..) |
- TypeKind::Vector(..) |
- TypeKind::Pointer(..) |
- TypeKind::Reference(..) |
- TypeKind::Function(..) |
- TypeKind::ResolvedTypeRef(..) |
- TypeKind::Opaque |
- TypeKind::TypeParam => {
- // These items don't need code generation, they only need to be
- // converted to rust types in fields, arguments, and such.
- // NOTE(emilio): If you add to this list, make sure to also add
- // it to BindgenContext::compute_allowlisted_and_codegen_items.
- }
- TypeKind::TemplateInstantiation(ref inst) => {
- inst.codegen(ctx, result, item)
- }
- TypeKind::BlockPointer(inner) => {
- if !ctx.options().generate_block {
- return;
- }
-
- let inner_item =
- inner.into_resolver().through_type_refs().resolve(ctx);
- let name = item.canonical_name(ctx);
-
- let inner_rust_type = {
- if let TypeKind::Function(fnsig) =
- inner_item.kind().expect_type().kind()
- {
- utils::fnsig_block(ctx, fnsig)
- } else {
- panic!("invalid block typedef: {:?}", inner_item)
- }
- };
-
- let rust_name = ctx.rust_ident(&name);
-
- let mut tokens = if let Some(comment) = item.comment(ctx) {
- attributes::doc(comment)
- } else {
- quote! {}
- };
-
- tokens.append_all(quote! {
- pub type #rust_name = #inner_rust_type ;
- });
-
- result.push(tokens);
- result.saw_block();
- }
- TypeKind::Comp(ref ci) => ci.codegen(ctx, result, item),
- TypeKind::TemplateAlias(inner, _) | TypeKind::Alias(inner) => {
- let inner_item =
- inner.into_resolver().through_type_refs().resolve(ctx);
- let name = item.canonical_name(ctx);
- let path = item.canonical_path(ctx);
-
- {
- let through_type_aliases = inner
- .into_resolver()
- .through_type_refs()
- .through_type_aliases()
- .resolve(ctx);
-
- // Try to catch the common pattern:
- //
- // typedef struct foo { ... } foo;
- //
- // here, and also other more complex cases like #946.
- if through_type_aliases.canonical_path(ctx) == path {
- return;
- }
- }
-
- // If this is a known named type, disallow generating anything
- // for it too. If size_t -> usize conversions are enabled, we
- // need to check that these conversions are permissible, but
- // nothing needs to be generated, still.
- let spelling = self.name().expect("Unnamed alias?");
- if utils::type_from_named(ctx, spelling).is_some() {
- if let "size_t" | "ssize_t" = spelling {
- let layout = inner_item
- .kind()
- .expect_type()
- .layout(ctx)
- .expect("No layout?");
- assert_eq!(
- layout.size,
- ctx.target_pointer_size(),
- "Target platform requires `--no-size_t-is-usize`. The size of `{}` ({}) does not match the target pointer size ({})",
- spelling,
- layout.size,
- ctx.target_pointer_size(),
- );
- assert_eq!(
- layout.align,
- ctx.target_pointer_size(),
- "Target platform requires `--no-size_t-is-usize`. The alignment of `{}` ({}) does not match the target pointer size ({})",
- spelling,
- layout.align,
- ctx.target_pointer_size(),
- );
- }
- return;
- }
-
- let mut outer_params = item.used_template_params(ctx);
-
- let is_opaque = item.is_opaque(ctx, &());
- let inner_rust_type = if is_opaque {
- outer_params = vec![];
- self.to_opaque(ctx, item)
- } else {
- // Its possible that we have better layout information than
- // the inner type does, so fall back to an opaque blob based
- // on our layout if converting the inner item fails.
- let mut inner_ty = inner_item
- .try_to_rust_ty_or_opaque(ctx, &())
- .unwrap_or_else(|_| self.to_opaque(ctx, item));
- inner_ty.append_implicit_template_params(ctx, inner_item);
- inner_ty
- };
-
- {
- // FIXME(emilio): This is a workaround to avoid generating
- // incorrect type aliases because of types that we haven't
- // been able to resolve (because, eg, they depend on a
- // template parameter).
- //
- // It's kind of a shame not generating them even when they
- // could be referenced, but we already do the same for items
- // with invalid template parameters, and at least this way
- // they can be replaced, instead of generating plain invalid
- // code.
- let inner_canon_type =
- inner_item.expect_type().canonical_type(ctx);
- if inner_canon_type.is_invalid_type_param() {
- warn!(
- "Item contained invalid named type, skipping: \
- {:?}, {:?}",
- item, inner_item
- );
- return;
- }
- }
-
- let rust_name = ctx.rust_ident(&name);
-
- let mut tokens = if let Some(comment) = item.comment(ctx) {
- attributes::doc(comment)
- } else {
- quote! {}
- };
-
- let alias_style = if ctx.options().type_alias.matches(&name) {
- AliasVariation::TypeAlias
- } else if ctx.options().new_type_alias.matches(&name) {
- AliasVariation::NewType
- } else if ctx.options().new_type_alias_deref.matches(&name) {
- AliasVariation::NewTypeDeref
- } else {
- ctx.options().default_alias_style
- };
-
- // We prefer using `pub use` over `pub type` because of:
- // https://github.com/rust-lang/rust/issues/26264
- // These are the only characters allowed in simple
- // paths, eg `good::dogs::Bront`.
- if inner_rust_type.to_string().chars().all(|c| matches!(c, 'A'..='Z' | 'a'..='z' | '0'..='9' | ':' | '_' | ' ')) && outer_params.is_empty() &&
- !is_opaque &&
- alias_style == AliasVariation::TypeAlias &&
- inner_item.expect_type().canonical_type(ctx).is_enum()
- {
- tokens.append_all(quote! {
- pub use
- });
- let path = top_level_path(ctx, item);
- tokens.append_separated(path, quote!(::));
- tokens.append_all(quote! {
- :: #inner_rust_type as #rust_name ;
- });
- result.push(tokens);
- return;
- }
-
- tokens.append_all(match alias_style {
- AliasVariation::TypeAlias => quote! {
- pub type #rust_name
- },
- AliasVariation::NewType | AliasVariation::NewTypeDeref => {
- assert!(
- ctx.options().rust_features().repr_transparent,
- "repr_transparent feature is required to use {:?}",
- alias_style
- );
-
- let mut attributes =
- vec![attributes::repr("transparent")];
- let packed = false; // Types can't be packed in Rust.
- let derivable_traits =
- derives_of_item(item, ctx, packed);
- if !derivable_traits.is_empty() {
- let derives: Vec<_> = derivable_traits.into();
- attributes.push(attributes::derives(&derives))
- }
-
- quote! {
- #( #attributes )*
- pub struct #rust_name
- }
- }
- });
-
- let params: Vec<_> = outer_params
- .into_iter()
- .filter_map(|p| p.as_template_param(ctx, &()))
- .collect();
- if params
- .iter()
- .any(|p| ctx.resolve_type(*p).is_invalid_type_param())
- {
- warn!(
- "Item contained invalid template \
- parameter: {:?}",
- item
- );
- return;
- }
- let params: Vec<_> = params
- .iter()
- .map(|p| {
- p.try_to_rust_ty(ctx, &()).expect(
- "type parameters can always convert to rust ty OK",
- )
- })
- .collect();
-
- if !params.is_empty() {
- tokens.append_all(quote! {
- < #( #params ),* >
- });
- }
-
- tokens.append_all(match alias_style {
- AliasVariation::TypeAlias => quote! {
- = #inner_rust_type ;
- },
- AliasVariation::NewType | AliasVariation::NewTypeDeref => {
- quote! {
- (pub #inner_rust_type) ;
- }
- }
- });
-
- if alias_style == AliasVariation::NewTypeDeref {
- let prefix = ctx.trait_prefix();
- tokens.append_all(quote! {
- impl ::#prefix::ops::Deref for #rust_name {
- type Target = #inner_rust_type;
- #[inline]
- fn deref(&self) -> &Self::Target {
- &self.0
- }
- }
- impl ::#prefix::ops::DerefMut for #rust_name {
- #[inline]
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.0
- }
- }
- });
- }
-
- result.push(tokens);
- }
- TypeKind::Enum(ref ei) => ei.codegen(ctx, result, item),
- TypeKind::ObjCId | TypeKind::ObjCSel => {
- result.saw_objc();
- }
- TypeKind::ObjCInterface(ref interface) => {
- interface.codegen(ctx, result, item)
- }
- ref u @ TypeKind::UnresolvedTypeRef(..) => {
- unreachable!("Should have been resolved after parsing {:?}!", u)
- }
- }
- }
-}
-
-struct Vtable<'a> {
- item_id: ItemId,
- /// A reference to the originating compound object.
- #[allow(dead_code)]
- comp_info: &'a CompInfo,
-}
-
-impl<'a> Vtable<'a> {
- fn new(item_id: ItemId, comp_info: &'a CompInfo) -> Self {
- Vtable { item_id, comp_info }
- }
-}
-
-impl<'a> CodeGenerator for Vtable<'a> {
- type Extra = Item;
- type Return = ();
-
- fn codegen<'b>(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult<'b>,
- item: &Item,
- ) {
- assert_eq!(item.id(), self.item_id);
- debug_assert!(item.is_enabled_for_codegen(ctx));
- let name = ctx.rust_ident(&self.canonical_name(ctx));
-
- // For now, we will only generate vtables for classes that:
- // - do not inherit from others (compilers merge VTable from primary parent class).
- // - do not contain a virtual destructor (requires ordering; platforms generate different vtables).
- if ctx.options().vtable_generation &&
- self.comp_info.base_members().is_empty() &&
- self.comp_info.destructor().is_none()
- {
- let class_ident = ctx.rust_ident(self.item_id.canonical_name(ctx));
-
- let methods = self
- .comp_info
- .methods()
- .iter()
- .filter_map(|m| {
- if !m.is_virtual() {
- return None;
- }
-
- let function_item = ctx.resolve_item(m.signature());
- let function = function_item.expect_function();
- let signature_item = ctx.resolve_item(function.signature());
- let signature = match signature_item.expect_type().kind() {
- TypeKind::Function(ref sig) => sig,
- _ => panic!("Function signature type mismatch"),
- };
-
- // FIXME: Is there a canonical name without the class prepended?
- let function_name = function_item.canonical_name(ctx);
-
- // FIXME: Need to account for overloading with times_seen (separately from regular function path).
- let function_name = ctx.rust_ident(function_name);
- let mut args = utils::fnsig_arguments(ctx, signature);
- let ret = utils::fnsig_return_ty(ctx, signature);
-
- args[0] = if m.is_const() {
- quote! { this: *const #class_ident }
- } else {
- quote! { this: *mut #class_ident }
- };
-
- Some(quote! {
- pub #function_name : unsafe extern "C" fn( #( #args ),* ) #ret
- })
- })
- .collect::<Vec<_>>();
-
- result.push(quote! {
- #[repr(C)]
- pub struct #name {
- #( #methods ),*
- }
- })
- } else {
- // For the cases we don't support, simply generate an empty struct.
- let void = helpers::ast_ty::c_void(ctx);
-
- result.push(quote! {
- #[repr(C)]
- pub struct #name ( #void );
- });
- }
- }
-}
-
-impl<'a> ItemCanonicalName for Vtable<'a> {
- fn canonical_name(&self, ctx: &BindgenContext) -> String {
- format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx))
- }
-}
-
-impl<'a> TryToRustTy for Vtable<'a> {
- type Extra = ();
-
- fn try_to_rust_ty(
- &self,
- ctx: &BindgenContext,
- _: &(),
- ) -> error::Result<proc_macro2::TokenStream> {
- let name = ctx.rust_ident(self.canonical_name(ctx));
- Ok(quote! {
- #name
- })
- }
-}
-
-impl CodeGenerator for TemplateInstantiation {
- type Extra = Item;
- type Return = ();
-
- fn codegen<'a>(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
- item: &Item,
- ) {
- debug_assert!(item.is_enabled_for_codegen(ctx));
-
- // Although uses of instantiations don't need code generation, and are
- // just converted to rust types in fields, vars, etc, we take this
- // opportunity to generate tests for their layout here. If the
- // instantiation is opaque, then its presumably because we don't
- // properly understand it (maybe because of specializations), and so we
- // shouldn't emit layout tests either.
- if !ctx.options().layout_tests || self.is_opaque(ctx, item) {
- return;
- }
-
- // If there are any unbound type parameters, then we can't generate a
- // layout test because we aren't dealing with a concrete type with a
- // concrete size and alignment.
- if ctx.uses_any_template_parameters(item.id()) {
- return;
- }
-
- let layout = item.kind().expect_type().layout(ctx);
-
- if let Some(layout) = layout {
- let size = layout.size;
- let align = layout.align;
-
- let name = item.full_disambiguated_name(ctx);
- let mut fn_name =
- format!("__bindgen_test_layout_{}_instantiation", name);
- let times_seen = result.overload_number(&fn_name);
- if times_seen > 0 {
- write!(&mut fn_name, "_{}", times_seen).unwrap();
- }
-
- let fn_name = ctx.rust_ident_raw(fn_name);
-
- let prefix = ctx.trait_prefix();
- let ident = item.to_rust_ty_or_opaque(ctx, &());
- let size_of_expr = quote! {
- ::#prefix::mem::size_of::<#ident>()
- };
- let align_of_expr = quote! {
- ::#prefix::mem::align_of::<#ident>()
- };
-
- let item = quote! {
- #[test]
- fn #fn_name() {
- assert_eq!(#size_of_expr, #size,
- concat!("Size of template specialization: ",
- stringify!(#ident)));
- assert_eq!(#align_of_expr, #align,
- concat!("Alignment of template specialization: ",
- stringify!(#ident)));
- }
- };
-
- result.push(item);
- }
- }
-}
-
-/// Trait for implementing the code generation of a struct or union field.
-trait FieldCodegen<'a> {
- type Extra;
-
- #[allow(clippy::too_many_arguments)]
- fn codegen<F, M>(
- &self,
- ctx: &BindgenContext,
- fields_should_be_private: bool,
- codegen_depth: usize,
- accessor_kind: FieldAccessorKind,
- parent: &CompInfo,
- result: &mut CodegenResult,
- struct_layout: &mut StructLayoutTracker,
- fields: &mut F,
- methods: &mut M,
- extra: Self::Extra,
- ) where
- F: Extend<proc_macro2::TokenStream>,
- M: Extend<proc_macro2::TokenStream>;
-}
-
-impl<'a> FieldCodegen<'a> for Field {
- type Extra = ();
-
- fn codegen<F, M>(
- &self,
- ctx: &BindgenContext,
- fields_should_be_private: bool,
- codegen_depth: usize,
- accessor_kind: FieldAccessorKind,
- parent: &CompInfo,
- result: &mut CodegenResult,
- struct_layout: &mut StructLayoutTracker,
- fields: &mut F,
- methods: &mut M,
- _: (),
- ) where
- F: Extend<proc_macro2::TokenStream>,
- M: Extend<proc_macro2::TokenStream>,
- {
- match *self {
- Field::DataMember(ref data) => {
- data.codegen(
- ctx,
- fields_should_be_private,
- codegen_depth,
- accessor_kind,
- parent,
- result,
- struct_layout,
- fields,
- methods,
- (),
- );
- }
- Field::Bitfields(ref unit) => {
- unit.codegen(
- ctx,
- fields_should_be_private,
- codegen_depth,
- accessor_kind,
- parent,
- result,
- struct_layout,
- fields,
- methods,
- (),
- );
- }
- }
- }
-}
-
-fn wrap_union_field_if_needed(
- ctx: &BindgenContext,
- struct_layout: &StructLayoutTracker,
- ty: proc_macro2::TokenStream,
- result: &mut CodegenResult,
-) -> proc_macro2::TokenStream {
- if struct_layout.is_rust_union() {
- if struct_layout.can_copy_union_fields() {
- ty
- } else {
- let prefix = ctx.trait_prefix();
- quote! {
- ::#prefix::mem::ManuallyDrop<#ty>
- }
- }
- } else {
- result.saw_bindgen_union();
- if ctx.options().enable_cxx_namespaces {
- quote! {
- root::__BindgenUnionField<#ty>
- }
- } else {
- quote! {
- __BindgenUnionField<#ty>
- }
- }
- }
-}
-
-impl<'a> FieldCodegen<'a> for FieldData {
- type Extra = ();
-
- fn codegen<F, M>(
- &self,
- ctx: &BindgenContext,
- fields_should_be_private: bool,
- codegen_depth: usize,
- accessor_kind: FieldAccessorKind,
- parent: &CompInfo,
- result: &mut CodegenResult,
- struct_layout: &mut StructLayoutTracker,
- fields: &mut F,
- methods: &mut M,
- _: (),
- ) where
- F: Extend<proc_macro2::TokenStream>,
- M: Extend<proc_macro2::TokenStream>,
- {
- // Bitfields are handled by `FieldCodegen` implementations for
- // `BitfieldUnit` and `Bitfield`.
- assert!(self.bitfield_width().is_none());
-
- let field_item =
- self.ty().into_resolver().through_type_refs().resolve(ctx);
- let field_ty = field_item.expect_type();
- let mut ty = self.ty().to_rust_ty_or_opaque(ctx, &());
- ty.append_implicit_template_params(ctx, field_item);
-
- // NB: If supported, we use proper `union` types.
- let ty = if parent.is_union() {
- wrap_union_field_if_needed(ctx, struct_layout, ty, result)
- } else if let Some(item) = field_ty.is_incomplete_array(ctx) {
- result.saw_incomplete_array();
-
- let inner = item.to_rust_ty_or_opaque(ctx, &());
-
- if ctx.options().enable_cxx_namespaces {
- quote! {
- root::__IncompleteArrayField<#inner>
- }
- } else {
- quote! {
- __IncompleteArrayField<#inner>
- }
- }
- } else {
- ty
- };
-
- let mut field = quote! {};
- if ctx.options().generate_comments {
- if let Some(raw_comment) = self.comment() {
- let comment =
- comment::preprocess(raw_comment, codegen_depth + 1);
- field = attributes::doc(comment);
- }
- }
-
- let field_name = self
- .name()
- .map(|name| ctx.rust_mangle(name).into_owned())
- .expect("Each field should have a name in codegen!");
- let field_ident = ctx.rust_ident_raw(field_name.as_str());
-
- if let Some(padding_field) =
- struct_layout.saw_field(&field_name, field_ty, self.offset())
- {
- fields.extend(Some(padding_field));
- }
-
- let is_private = (!self.is_public() &&
- ctx.options().respect_cxx_access_specs) ||
- self.annotations()
- .private_fields()
- .unwrap_or(fields_should_be_private);
-
- let accessor_kind =
- self.annotations().accessor_kind().unwrap_or(accessor_kind);
-
- if is_private {
- field.append_all(quote! {
- #field_ident : #ty ,
- });
- } else {
- field.append_all(quote! {
- pub #field_ident : #ty ,
- });
- }
-
- fields.extend(Some(field));
-
- // TODO: Factor the following code out, please!
- if accessor_kind == FieldAccessorKind::None {
- return;
- }
-
- let getter_name = ctx.rust_ident_raw(format!("get_{}", field_name));
- let mutable_getter_name =
- ctx.rust_ident_raw(format!("get_{}_mut", field_name));
- let field_name = ctx.rust_ident_raw(field_name);
-
- methods.extend(Some(match accessor_kind {
- FieldAccessorKind::None => unreachable!(),
- FieldAccessorKind::Regular => {
- quote! {
- #[inline]
- pub fn #getter_name(&self) -> & #ty {
- &self.#field_name
- }
-
- #[inline]
- pub fn #mutable_getter_name(&mut self) -> &mut #ty {
- &mut self.#field_name
- }
- }
- }
- FieldAccessorKind::Unsafe => {
- quote! {
- #[inline]
- pub unsafe fn #getter_name(&self) -> & #ty {
- &self.#field_name
- }
-
- #[inline]
- pub unsafe fn #mutable_getter_name(&mut self) -> &mut #ty {
- &mut self.#field_name
- }
- }
- }
- FieldAccessorKind::Immutable => {
- quote! {
- #[inline]
- pub fn #getter_name(&self) -> & #ty {
- &self.#field_name
- }
- }
- }
- }));
- }
-}
-
-impl BitfieldUnit {
- /// Get the constructor name for this bitfield unit.
- fn ctor_name(&self) -> proc_macro2::TokenStream {
- let ctor_name = Ident::new(
- &format!("new_bitfield_{}", self.nth()),
- Span::call_site(),
- );
- quote! {
- #ctor_name
- }
- }
-}
-
-impl Bitfield {
- /// Extend an under construction bitfield unit constructor with this
- /// bitfield. This sets the relevant bits on the `__bindgen_bitfield_unit`
- /// variable that's being constructed.
- fn extend_ctor_impl(
- &self,
- ctx: &BindgenContext,
- param_name: proc_macro2::TokenStream,
- mut ctor_impl: proc_macro2::TokenStream,
- ) -> proc_macro2::TokenStream {
- let bitfield_ty = ctx.resolve_type(self.ty());
- let bitfield_ty_layout = bitfield_ty
- .layout(ctx)
- .expect("Bitfield without layout? Gah!");
- let bitfield_int_ty = helpers::integer_type(ctx, bitfield_ty_layout)
- .expect(
- "Should already have verified that the bitfield is \
- representable as an int",
- );
-
- let offset = self.offset_into_unit();
- let width = self.width() as u8;
- let prefix = ctx.trait_prefix();
-
- ctor_impl.append_all(quote! {
- __bindgen_bitfield_unit.set(
- #offset,
- #width,
- {
- let #param_name: #bitfield_int_ty = unsafe {
- ::#prefix::mem::transmute(#param_name)
- };
- #param_name as u64
- }
- );
- });
-
- ctor_impl
- }
-}
-
-fn access_specifier(
- ctx: &BindgenContext,
- is_pub: bool,
-) -> proc_macro2::TokenStream {
- if is_pub || !ctx.options().respect_cxx_access_specs {
- quote! { pub }
- } else {
- quote! {}
- }
-}
-
-impl<'a> FieldCodegen<'a> for BitfieldUnit {
- type Extra = ();
-
- fn codegen<F, M>(
- &self,
- ctx: &BindgenContext,
- fields_should_be_private: bool,
- codegen_depth: usize,
- accessor_kind: FieldAccessorKind,
- parent: &CompInfo,
- result: &mut CodegenResult,
- struct_layout: &mut StructLayoutTracker,
- fields: &mut F,
- methods: &mut M,
- _: (),
- ) where
- F: Extend<proc_macro2::TokenStream>,
- M: Extend<proc_macro2::TokenStream>,
- {
- use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
-
- result.saw_bitfield_unit();
-
- let layout = self.layout();
- let unit_field_ty = helpers::bitfield_unit(ctx, layout);
- let field_ty = if parent.is_union() {
- wrap_union_field_if_needed(
- ctx,
- struct_layout,
- unit_field_ty.clone(),
- result,
- )
- } else {
- unit_field_ty.clone()
- };
-
- {
- let align_field_name = format!("_bitfield_align_{}", self.nth());
- let align_field_ident = ctx.rust_ident(&align_field_name);
- let align_ty = match self.layout().align {
- n if n >= 8 => quote! { u64 },
- 4 => quote! { u32 },
- 2 => quote! { u16 },
- _ => quote! { u8 },
- };
- let align_field = quote! {
- pub #align_field_ident: [#align_ty; 0],
- };
- fields.extend(Some(align_field));
- }
-
- let unit_field_name = format!("_bitfield_{}", self.nth());
- let unit_field_ident = ctx.rust_ident(&unit_field_name);
-
- let ctor_name = self.ctor_name();
- let mut ctor_params = vec![];
- let mut ctor_impl = quote! {};
-
- // We cannot generate any constructor if the underlying storage can't
- // implement AsRef<[u8]> / AsMut<[u8]> / etc, or can't derive Default.
- //
- // We don't check `larger_arrays` here because Default does still have
- // the 32 items limitation.
- let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT;
-
- let mut access_spec = !fields_should_be_private;
- for bf in self.bitfields() {
- // Codegen not allowed for anonymous bitfields
- if bf.name().is_none() {
- continue;
- }
-
- if layout.size > RUST_DERIVE_IN_ARRAY_LIMIT &&
- !ctx.options().rust_features().larger_arrays
- {
- continue;
- }
-
- access_spec &= bf.is_public();
- let mut bitfield_representable_as_int = true;
-
- bf.codegen(
- ctx,
- fields_should_be_private,
- codegen_depth,
- accessor_kind,
- parent,
- result,
- struct_layout,
- fields,
- methods,
- (&unit_field_name, &mut bitfield_representable_as_int),
- );
-
- // Generating a constructor requires the bitfield to be representable as an integer.
- if !bitfield_representable_as_int {
- generate_ctor = false;
- continue;
- }
-
- let param_name = bitfield_getter_name(ctx, bf);
- let bitfield_ty_item = ctx.resolve_item(bf.ty());
- let bitfield_ty = bitfield_ty_item.expect_type();
- let bitfield_ty =
- bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
-
- ctor_params.push(quote! {
- #param_name : #bitfield_ty
- });
- ctor_impl = bf.extend_ctor_impl(ctx, param_name, ctor_impl);
- }
-
- let access_spec = access_specifier(ctx, access_spec);
-
- let field = quote! {
- #access_spec #unit_field_ident : #field_ty ,
- };
- fields.extend(Some(field));
-
- if generate_ctor {
- methods.extend(Some(quote! {
- #[inline]
- #access_spec fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_ty {
- let mut __bindgen_bitfield_unit: #unit_field_ty = Default::default();
- #ctor_impl
- __bindgen_bitfield_unit
- }
- }));
- }
-
- struct_layout.saw_bitfield_unit(layout);
- }
-}
-
-fn bitfield_getter_name(
- ctx: &BindgenContext,
- bitfield: &Bitfield,
-) -> proc_macro2::TokenStream {
- let name = bitfield.getter_name();
- let name = ctx.rust_ident_raw(name);
- quote! { #name }
-}
-
-fn bitfield_setter_name(
- ctx: &BindgenContext,
- bitfield: &Bitfield,
-) -> proc_macro2::TokenStream {
- let setter = bitfield.setter_name();
- let setter = ctx.rust_ident_raw(setter);
- quote! { #setter }
-}
-
-impl<'a> FieldCodegen<'a> for Bitfield {
- type Extra = (&'a str, &'a mut bool);
-
- fn codegen<F, M>(
- &self,
- ctx: &BindgenContext,
- fields_should_be_private: bool,
- _codegen_depth: usize,
- _accessor_kind: FieldAccessorKind,
- parent: &CompInfo,
- _result: &mut CodegenResult,
- struct_layout: &mut StructLayoutTracker,
- _fields: &mut F,
- methods: &mut M,
- (unit_field_name, bitfield_representable_as_int): (&'a str, &mut bool),
- ) where
- F: Extend<proc_macro2::TokenStream>,
- M: Extend<proc_macro2::TokenStream>,
- {
- let prefix = ctx.trait_prefix();
- let getter_name = bitfield_getter_name(ctx, self);
- let setter_name = bitfield_setter_name(ctx, self);
- let unit_field_ident = Ident::new(unit_field_name, Span::call_site());
-
- let bitfield_ty_item = ctx.resolve_item(self.ty());
- let bitfield_ty = bitfield_ty_item.expect_type();
-
- let bitfield_ty_layout = bitfield_ty
- .layout(ctx)
- .expect("Bitfield without layout? Gah!");
- let bitfield_int_ty =
- match helpers::integer_type(ctx, bitfield_ty_layout) {
- Some(int_ty) => {
- *bitfield_representable_as_int = true;
- int_ty
- }
- None => {
- *bitfield_representable_as_int = false;
- return;
- }
- };
-
- let bitfield_ty =
- bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
-
- let offset = self.offset_into_unit();
- let width = self.width() as u8;
- let access_spec = access_specifier(
- ctx,
- self.is_public() && !fields_should_be_private,
- );
-
- if parent.is_union() && !struct_layout.is_rust_union() {
- methods.extend(Some(quote! {
- #[inline]
- #access_spec fn #getter_name(&self) -> #bitfield_ty {
- unsafe {
- ::#prefix::mem::transmute(
- self.#unit_field_ident.as_ref().get(#offset, #width)
- as #bitfield_int_ty
- )
- }
- }
-
- #[inline]
- #access_spec fn #setter_name(&mut self, val: #bitfield_ty) {
- unsafe {
- let val: #bitfield_int_ty = ::#prefix::mem::transmute(val);
- self.#unit_field_ident.as_mut().set(
- #offset,
- #width,
- val as u64
- )
- }
- }
- }));
- } else {
- methods.extend(Some(quote! {
- #[inline]
- #access_spec fn #getter_name(&self) -> #bitfield_ty {
- unsafe {
- ::#prefix::mem::transmute(
- self.#unit_field_ident.get(#offset, #width)
- as #bitfield_int_ty
- )
- }
- }
-
- #[inline]
- #access_spec fn #setter_name(&mut self, val: #bitfield_ty) {
- unsafe {
- let val: #bitfield_int_ty = ::#prefix::mem::transmute(val);
- self.#unit_field_ident.set(
- #offset,
- #width,
- val as u64
- )
- }
- }
- }));
- }
- }
-}
-
-impl CodeGenerator for CompInfo {
- type Extra = Item;
- type Return = ();
-
- fn codegen<'a>(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
- item: &Item,
- ) {
- debug!("<CompInfo as CodeGenerator>::codegen: item = {:?}", item);
- debug_assert!(item.is_enabled_for_codegen(ctx));
-
- // Don't output classes with template parameters that aren't types, and
- // also don't output template specializations, neither total or partial.
- if self.has_non_type_template_params() {
- return;
- }
-
- let ty = item.expect_type();
- let layout = ty.layout(ctx);
- let mut packed = self.is_packed(ctx, layout.as_ref());
-
- let canonical_name = item.canonical_name(ctx);
- let canonical_ident = ctx.rust_ident(&canonical_name);
-
- // Generate the vtable from the method list if appropriate.
- //
- // TODO: I don't know how this could play with virtual methods that are
- // not in the list of methods found by us, we'll see. Also, could the
- // order of the vtable pointers vary?
- //
- // FIXME: Once we generate proper vtables, we need to codegen the
- // vtable, but *not* generate a field for it in the case that
- // HasVtable::has_vtable_ptr is false but HasVtable::has_vtable is true.
- //
- // Also, we need to generate the vtable in such a way it "inherits" from
- // the parent too.
- let is_opaque = item.is_opaque(ctx, &());
- let mut fields = vec![];
- let mut struct_layout =
- StructLayoutTracker::new(ctx, self, ty, &canonical_name);
-
- if !is_opaque {
- if item.has_vtable_ptr(ctx) {
- let vtable = Vtable::new(item.id(), self);
- vtable.codegen(ctx, result, item);
-
- let vtable_type = vtable
- .try_to_rust_ty(ctx, &())
- .expect("vtable to Rust type conversion is infallible")
- .to_ptr(true);
-
- fields.push(quote! {
- pub vtable_: #vtable_type ,
- });
-
- struct_layout.saw_vtable();
- }
-
- for base in self.base_members() {
- if !base.requires_storage(ctx) {
- continue;
- }
-
- let inner_item = ctx.resolve_item(base.ty);
- let mut inner = inner_item.to_rust_ty_or_opaque(ctx, &());
- inner.append_implicit_template_params(ctx, inner_item);
- let field_name = ctx.rust_ident(&base.field_name);
-
- struct_layout.saw_base(inner_item.expect_type());
-
- let access_spec = access_specifier(ctx, base.is_public());
- fields.push(quote! {
- #access_spec #field_name: #inner,
- });
- }
- }
-
- let mut methods = vec![];
- if !is_opaque {
- let codegen_depth = item.codegen_depth(ctx);
- let fields_should_be_private =
- item.annotations().private_fields().unwrap_or(false);
- let struct_accessor_kind = item
- .annotations()
- .accessor_kind()
- .unwrap_or(FieldAccessorKind::None);
- for field in self.fields() {
- field.codegen(
- ctx,
- fields_should_be_private,
- codegen_depth,
- struct_accessor_kind,
- self,
- result,
- &mut struct_layout,
- &mut fields,
- &mut methods,
- (),
- );
- }
- // Check whether an explicit padding field is needed
- // at the end.
- if let Some(comp_layout) = layout {
- fields.extend(
- struct_layout
- .add_tail_padding(&canonical_name, comp_layout),
- );
- }
- }
-
- if is_opaque {
- // Opaque item should not have generated methods, fields.
- debug_assert!(fields.is_empty());
- debug_assert!(methods.is_empty());
- }
-
- let is_union = self.kind() == CompKind::Union;
- let layout = item.kind().expect_type().layout(ctx);
- let zero_sized = item.is_zero_sized(ctx);
- let forward_decl = self.is_forward_declaration();
-
- let mut explicit_align = None;
-
- // C++ requires every struct to be addressable, so what C++ compilers do
- // is making the struct 1-byte sized.
- //
- // This is apparently not the case for C, see:
- // https://github.com/rust-lang/rust-bindgen/issues/551
- //
- // Just get the layout, and assume C++ if not.
- //
- // NOTE: This check is conveniently here to avoid the dummy fields we
- // may add for unused template parameters.
- if !forward_decl && zero_sized {
- let has_address = if is_opaque {
- // Generate the address field if it's an opaque type and
- // couldn't determine the layout of the blob.
- layout.is_none()
- } else {
- layout.map_or(true, |l| l.size != 0)
- };
-
- if has_address {
- let layout = Layout::new(1, 1);
- let ty = helpers::blob(ctx, Layout::new(1, 1));
- struct_layout.saw_field_with_layout(
- "_address",
- layout,
- /* offset = */ Some(0),
- );
- fields.push(quote! {
- pub _address: #ty,
- });
- }
- }
-
- if is_opaque {
- match layout {
- Some(l) => {
- explicit_align = Some(l.align);
-
- let ty = helpers::blob(ctx, l);
- fields.push(quote! {
- pub _bindgen_opaque_blob: #ty ,
- });
- }
- None => {
- warn!("Opaque type without layout! Expect dragons!");
- }
- }
- } else if !is_union && !zero_sized {
- if let Some(padding_field) =
- layout.and_then(|layout| struct_layout.pad_struct(layout))
- {
- fields.push(padding_field);
- }
-
- if let Some(layout) = layout {
- if struct_layout.requires_explicit_align(layout) {
- if layout.align == 1 {
- packed = true;
- } else {
- explicit_align = Some(layout.align);
- if !ctx.options().rust_features.repr_align {
- let ty = helpers::blob(
- ctx,
- Layout::new(0, layout.align),
- );
- fields.push(quote! {
- pub __bindgen_align: #ty ,
- });
- }
- }
- }
- }
- } else if is_union && !forward_decl {
- // TODO(emilio): It'd be nice to unify this with the struct path
- // above somehow.
- let layout = layout.expect("Unable to get layout information?");
- if struct_layout.requires_explicit_align(layout) {
- explicit_align = Some(layout.align);
- }
-
- if !struct_layout.is_rust_union() {
- let ty = helpers::blob(ctx, layout);
- fields.push(quote! {
- pub bindgen_union_field: #ty ,
- })
- }
- }
-
- if forward_decl {
- fields.push(quote! {
- _unused: [u8; 0],
- });
- }
-
- let mut generic_param_names = vec![];
-
- for (idx, ty) in item.used_template_params(ctx).iter().enumerate() {
- let param = ctx.resolve_type(*ty);
- let name = param.name().unwrap();
- let ident = ctx.rust_ident(name);
- generic_param_names.push(ident.clone());
-
- let prefix = ctx.trait_prefix();
- let field_name = ctx.rust_ident(format!("_phantom_{}", idx));
- fields.push(quote! {
- pub #field_name : ::#prefix::marker::PhantomData<
- ::#prefix::cell::UnsafeCell<#ident>
- > ,
- });
- }
-
- let generics = if !generic_param_names.is_empty() {
- let generic_param_names = generic_param_names.clone();
- quote! {
- < #( #generic_param_names ),* >
- }
- } else {
- quote! {}
- };
-
- let mut attributes = vec![];
- let mut needs_clone_impl = false;
- let mut needs_default_impl = false;
- let mut needs_debug_impl = false;
- let mut needs_partialeq_impl = false;
- if let Some(comment) = item.comment(ctx) {
- attributes.push(attributes::doc(comment));
- }
- if packed && !is_opaque {
- let n = layout.map_or(1, |l| l.align);
- assert!(ctx.options().rust_features().repr_packed_n || n == 1);
- let packed_repr = if n == 1 {
- "packed".to_string()
- } else {
- format!("packed({})", n)
- };
- attributes.push(attributes::repr_list(&["C", &packed_repr]));
- } else {
- attributes.push(attributes::repr("C"));
- }
-
- if ctx.options().rust_features().repr_align {
- if let Some(explicit) = explicit_align {
- // Ensure that the struct has the correct alignment even in
- // presence of alignas.
- let explicit = helpers::ast_ty::int_expr(explicit as i64);
- attributes.push(quote! {
- #[repr(align(#explicit))]
- });
- }
- }
-
- let derivable_traits = derives_of_item(item, ctx, packed);
- if !derivable_traits.contains(DerivableTraits::DEBUG) {
- needs_debug_impl = ctx.options().derive_debug &&
- ctx.options().impl_debug &&
- !ctx.no_debug_by_name(item) &&
- !item.annotations().disallow_debug();
- }
-
- if !derivable_traits.contains(DerivableTraits::DEFAULT) {
- needs_default_impl = ctx.options().derive_default &&
- !self.is_forward_declaration() &&
- !ctx.no_default_by_name(item) &&
- !item.annotations().disallow_default();
- }
-
- let all_template_params = item.all_template_params(ctx);
-
- if derivable_traits.contains(DerivableTraits::COPY) &&
- !derivable_traits.contains(DerivableTraits::CLONE)
- {
- needs_clone_impl = true;
- }
-
- if !derivable_traits.contains(DerivableTraits::PARTIAL_EQ) {
- needs_partialeq_impl = ctx.options().derive_partialeq &&
- ctx.options().impl_partialeq &&
- ctx.lookup_can_derive_partialeq_or_partialord(item.id()) ==
- CanDerive::Manually;
- }
-
- let mut derives: Vec<_> = derivable_traits.into();
- derives.extend(item.annotations().derives().iter().map(String::as_str));
-
- // The custom derives callback may return a list of derive attributes;
- // add them to the end of the list.
- let custom_derives;
- if let Some(cb) = &ctx.options().parse_callbacks {
- custom_derives = cb.add_derives(&canonical_name);
- // In most cases this will be a no-op, since custom_derives will be empty.
- derives.extend(custom_derives.iter().map(|s| s.as_str()));
- };
-
- if !derives.is_empty() {
- attributes.push(attributes::derives(&derives))
- }
-
- if item.must_use(ctx) {
- attributes.push(attributes::must_use());
- }
-
- let mut tokens = if is_union && struct_layout.is_rust_union() {
- quote! {
- #( #attributes )*
- pub union #canonical_ident
- }
- } else {
- quote! {
- #( #attributes )*
- pub struct #canonical_ident
- }
- };
-
- tokens.append_all(quote! {
- #generics {
- #( #fields )*
- }
- });
- result.push(tokens);
-
- // Generate the inner types and all that stuff.
- //
- // TODO: In the future we might want to be smart, and use nested
- // modules, and whatnot.
- for ty in self.inner_types() {
- let child_item = ctx.resolve_item(*ty);
- // assert_eq!(child_item.parent_id(), item.id());
- child_item.codegen(ctx, result, &());
- }
-
- // NOTE: Some unexposed attributes (like alignment attributes) may
- // affect layout, so we're bad and pray to the gods for avoid sending
- // all the tests to shit when parsing things like max_align_t.
- if self.found_unknown_attr() {
- warn!(
- "Type {} has an unknown attribute that may affect layout",
- canonical_ident
- );
- }
-
- if all_template_params.is_empty() {
- if !is_opaque {
- for var in self.inner_vars() {
- ctx.resolve_item(*var).codegen(ctx, result, &());
- }
- }
-
- if ctx.options().layout_tests && !self.is_forward_declaration() {
- if let Some(layout) = layout {
- let fn_name =
- format!("bindgen_test_layout_{}", canonical_ident);
- let fn_name = ctx.rust_ident_raw(fn_name);
- let prefix = ctx.trait_prefix();
- let size_of_expr = quote! {
- ::#prefix::mem::size_of::<#canonical_ident>()
- };
- let align_of_expr = quote! {
- ::#prefix::mem::align_of::<#canonical_ident>()
- };
- let size = layout.size;
- let align = layout.align;
-
- let check_struct_align = if align >
- ctx.target_pointer_size() &&
- !ctx.options().rust_features().repr_align
- {
- None
- } else {
- Some(quote! {
- assert_eq!(#align_of_expr,
- #align,
- concat!("Alignment of ", stringify!(#canonical_ident)));
-
- })
- };
-
- // FIXME when [issue #465](https://github.com/rust-lang/rust-bindgen/issues/465) ready
- let too_many_base_vtables = self
- .base_members()
- .iter()
- .filter(|base| base.ty.has_vtable(ctx))
- .count() >
- 1;
-
- let should_skip_field_offset_checks =
- is_opaque || too_many_base_vtables;
-
- let check_field_offset = if should_skip_field_offset_checks
- {
- vec![]
- } else {
- self.fields()
- .iter()
- .filter_map(|field| match *field {
- Field::DataMember(ref f) if f.name().is_some() => Some(f),
- _ => None,
- })
- .flat_map(|field| {
- let name = field.name().unwrap();
- field.offset().map(|offset| {
- let field_offset = offset / 8;
- let field_name = ctx.rust_ident(name);
- quote! {
- assert_eq!(
- unsafe {
- ::#prefix::ptr::addr_of!((*ptr).#field_name) as usize - ptr as usize
- },
- #field_offset,
- concat!("Offset of field: ", stringify!(#canonical_ident), "::", stringify!(#field_name))
- );
- }
- })
- })
- .collect()
- };
-
- let uninit_decl = if !check_field_offset.is_empty() {
- // FIXME: When MSRV >= 1.59.0, we can use
- // > const PTR: *const #canonical_ident = ::#prefix::mem::MaybeUninit::uninit().as_ptr();
- Some(quote! {
- // Use a shared MaybeUninit so that rustc with
- // opt-level=0 doesn't take too much stack space,
- // see #2218.
- const UNINIT: ::#prefix::mem::MaybeUninit<#canonical_ident> = ::#prefix::mem::MaybeUninit::uninit();
- let ptr = UNINIT.as_ptr();
- })
- } else {
- None
- };
-
- let item = quote! {
- #[test]
- fn #fn_name() {
- #uninit_decl
- assert_eq!(#size_of_expr,
- #size,
- concat!("Size of: ", stringify!(#canonical_ident)));
- #check_struct_align
- #( #check_field_offset )*
- }
- };
- result.push(item);
- }
- }
-
- let mut method_names = Default::default();
- if ctx.options().codegen_config.methods() {
- for method in self.methods() {
- assert!(method.kind() != MethodKind::Constructor);
- method.codegen_method(
- ctx,
- &mut methods,
- &mut method_names,
- result,
- self,
- );
- }
- }
-
- if ctx.options().codegen_config.constructors() {
- for sig in self.constructors() {
- Method::new(
- MethodKind::Constructor,
- *sig,
- /* const */
- false,
- )
- .codegen_method(
- ctx,
- &mut methods,
- &mut method_names,
- result,
- self,
- );
- }
- }
-
- if ctx.options().codegen_config.destructors() {
- if let Some((kind, destructor)) = self.destructor() {
- debug_assert!(kind.is_destructor());
- Method::new(kind, destructor, false).codegen_method(
- ctx,
- &mut methods,
- &mut method_names,
- result,
- self,
- );
- }
- }
- }
-
- // NB: We can't use to_rust_ty here since for opaque types this tries to
- // use the specialization knowledge to generate a blob field.
- let ty_for_impl = quote! {
- #canonical_ident #generics
- };
-
- if needs_clone_impl {
- result.push(quote! {
- impl #generics Clone for #ty_for_impl {
- fn clone(&self) -> Self { *self }
- }
- });
- }
-
- if needs_default_impl {
- let prefix = ctx.trait_prefix();
- let body = if ctx.options().rust_features().maybe_uninit {
- quote! {
- let mut s = ::#prefix::mem::MaybeUninit::<Self>::uninit();
- unsafe {
- ::#prefix::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
- s.assume_init()
- }
- }
- } else {
- quote! {
- unsafe {
- let mut s: Self = ::#prefix::mem::uninitialized();
- ::#prefix::ptr::write_bytes(&mut s, 0, 1);
- s
- }
- }
- };
- // Note we use `ptr::write_bytes()` instead of `mem::zeroed()` because the latter does
- // not necessarily ensure padding bytes are zeroed. Some C libraries are sensitive to
- // non-zero padding bytes, especially when forwards/backwards compatability is
- // involved.
- result.push(quote! {
- impl #generics Default for #ty_for_impl {
- fn default() -> Self {
- #body
- }
- }
- });
- }
-
- if needs_debug_impl {
- let impl_ = impl_debug::gen_debug_impl(
- ctx,
- self.fields(),
- item,
- self.kind(),
- );
-
- let prefix = ctx.trait_prefix();
-
- result.push(quote! {
- impl #generics ::#prefix::fmt::Debug for #ty_for_impl {
- #impl_
- }
- });
- }
-
- if needs_partialeq_impl {
- if let Some(impl_) = impl_partialeq::gen_partialeq_impl(
- ctx,
- self,
- item,
- &ty_for_impl,
- ) {
- let partialeq_bounds = if !generic_param_names.is_empty() {
- let bounds = generic_param_names.iter().map(|t| {
- quote! { #t: PartialEq }
- });
- quote! { where #( #bounds ),* }
- } else {
- quote! {}
- };
-
- let prefix = ctx.trait_prefix();
- result.push(quote! {
- impl #generics ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds {
- #impl_
- }
- });
- }
- }
-
- if !methods.is_empty() {
- result.push(quote! {
- impl #generics #ty_for_impl {
- #( #methods )*
- }
- });
- }
- }
-}
-
-trait MethodCodegen {
- fn codegen_method<'a>(
- &self,
- ctx: &BindgenContext,
- methods: &mut Vec<proc_macro2::TokenStream>,
- method_names: &mut HashMap<String, usize>,
- result: &mut CodegenResult<'a>,
- parent: &CompInfo,
- );
-}
-
-impl MethodCodegen for Method {
- fn codegen_method<'a>(
- &self,
- ctx: &BindgenContext,
- methods: &mut Vec<proc_macro2::TokenStream>,
- method_names: &mut HashMap<String, usize>,
- result: &mut CodegenResult<'a>,
- _parent: &CompInfo,
- ) {
- assert!({
- let cc = &ctx.options().codegen_config;
- match self.kind() {
- MethodKind::Constructor => cc.constructors(),
- MethodKind::Destructor => cc.destructors(),
- MethodKind::VirtualDestructor { .. } => cc.destructors(),
- MethodKind::Static |
- MethodKind::Normal |
- MethodKind::Virtual { .. } => cc.methods(),
- }
- });
-
- // TODO(emilio): We could generate final stuff at least.
- if self.is_virtual() {
- return; // FIXME
- }
-
- // First of all, output the actual function.
- let function_item = ctx.resolve_item(self.signature());
- if !function_item.process_before_codegen(ctx, result) {
- return;
- }
- let function = function_item.expect_function();
- let times_seen = function.codegen(ctx, result, function_item);
- let times_seen = match times_seen {
- Some(seen) => seen,
- None => return,
- };
- let signature_item = ctx.resolve_item(function.signature());
- let mut name = match self.kind() {
- MethodKind::Constructor => "new".into(),
- MethodKind::Destructor => "destruct".into(),
- _ => function.name().to_owned(),
- };
-
- let signature = match *signature_item.expect_type().kind() {
- TypeKind::Function(ref sig) => sig,
- _ => panic!("How in the world?"),
- };
-
- let supported_abi = match signature.abi() {
- Abi::ThisCall => ctx.options().rust_features().thiscall_abi,
- Abi::Vectorcall => ctx.options().rust_features().vectorcall_abi,
- _ => true,
- };
-
- if !supported_abi {
- return;
- }
-
- // Do not generate variadic methods, since rust does not allow
- // implementing them, and we don't do a good job at it anyway.
- if signature.is_variadic() {
- return;
- }
-
- let count = {
- let count = method_names.entry(name.clone()).or_insert(0);
- *count += 1;
- *count - 1
- };
-
- if count != 0 {
- name.push_str(&count.to_string());
- }
-
- let mut function_name = function_item.canonical_name(ctx);
- if times_seen > 0 {
- write!(&mut function_name, "{}", times_seen).unwrap();
- }
- let function_name = ctx.rust_ident(function_name);
- let mut args = utils::fnsig_arguments(ctx, signature);
- let mut ret = utils::fnsig_return_ty(ctx, signature);
-
- if !self.is_static() && !self.is_constructor() {
- args[0] = if self.is_const() {
- quote! { &self }
- } else {
- quote! { &mut self }
- };
- }
-
- // If it's a constructor, we always return `Self`, and we inject the
- // "this" parameter, so there's no need to ask the user for it.
- //
- // Note that constructors in Clang are represented as functions with
- // return-type = void.
- if self.is_constructor() {
- args.remove(0);
- ret = quote! { -> Self };
- }
-
- let mut exprs =
- helpers::ast_ty::arguments_from_signature(signature, ctx);
-
- let mut stmts = vec![];
-
- // If it's a constructor, we need to insert an extra parameter with a
- // variable called `__bindgen_tmp` we're going to create.
- if self.is_constructor() {
- let prefix = ctx.trait_prefix();
- let tmp_variable_decl = if ctx
- .options()
- .rust_features()
- .maybe_uninit
- {
- exprs[0] = quote! {
- __bindgen_tmp.as_mut_ptr()
- };
- quote! {
- let mut __bindgen_tmp = ::#prefix::mem::MaybeUninit::uninit()
- }
- } else {
- exprs[0] = quote! {
- &mut __bindgen_tmp
- };
- quote! {
- let mut __bindgen_tmp = ::#prefix::mem::uninitialized()
- }
- };
- stmts.push(tmp_variable_decl);
- } else if !self.is_static() {
- assert!(!exprs.is_empty());
- exprs[0] = quote! {
- self
- };
- };
-
- let call = quote! {
- #function_name (#( #exprs ),* )
- };
-
- stmts.push(call);
-
- if self.is_constructor() {
- stmts.push(if ctx.options().rust_features().maybe_uninit {
- quote! {
- __bindgen_tmp.assume_init()
- }
- } else {
- quote! {
- __bindgen_tmp
- }
- })
- }
-
- let block = quote! {
- #( #stmts );*
- };
-
- let mut attrs = vec![attributes::inline()];
-
- if signature.must_use() &&
- ctx.options().rust_features().must_use_function
- {
- attrs.push(attributes::must_use());
- }
-
- let name = ctx.rust_ident(&name);
- methods.push(quote! {
- #(#attrs)*
- pub unsafe fn #name ( #( #args ),* ) #ret {
- #block
- }
- });
- }
-}
-
-/// A helper type that represents different enum variations.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum EnumVariation {
- /// The code for this enum will use a Rust enum. Note that creating this in unsafe code
- /// (including FFI) with an invalid value will invoke undefined behaviour, whether or not
- /// its marked as non_exhaustive.
- Rust {
- /// Indicates whether the generated struct should be `#[non_exhaustive]`
- non_exhaustive: bool,
- },
- /// The code for this enum will use a newtype
- NewType {
- /// Indicates whether the newtype will have bitwise operators
- is_bitfield: bool,
- /// Indicates whether the variants will be represented as global constants
- is_global: bool,
- },
- /// The code for this enum will use consts
- Consts,
- /// The code for this enum will use a module containing consts
- ModuleConsts,
-}
-
-impl EnumVariation {
- fn is_rust(&self) -> bool {
- matches!(*self, EnumVariation::Rust { .. })
- }
-
- /// Both the `Const` and `ModuleConsts` variants will cause this to return
- /// true.
- fn is_const(&self) -> bool {
- matches!(*self, EnumVariation::Consts | EnumVariation::ModuleConsts)
- }
-}
-
-impl Default for EnumVariation {
- fn default() -> EnumVariation {
- EnumVariation::Consts
- }
-}
-
-impl std::str::FromStr for EnumVariation {
- type Err = std::io::Error;
-
- /// Create a `EnumVariation` from a string.
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "rust" => Ok(EnumVariation::Rust {
- non_exhaustive: false,
- }),
- "rust_non_exhaustive" => Ok(EnumVariation::Rust {
- non_exhaustive: true,
- }),
- "bitfield" => Ok(EnumVariation::NewType {
- is_bitfield: true,
- is_global: false,
- }),
- "consts" => Ok(EnumVariation::Consts),
- "moduleconsts" => Ok(EnumVariation::ModuleConsts),
- "newtype" => Ok(EnumVariation::NewType {
- is_bitfield: false,
- is_global: false,
- }),
- "newtype_global" => Ok(EnumVariation::NewType {
- is_bitfield: false,
- is_global: true,
- }),
- _ => Err(std::io::Error::new(
- std::io::ErrorKind::InvalidInput,
- concat!(
- "Got an invalid EnumVariation. Accepted values ",
- "are 'rust', 'rust_non_exhaustive', 'bitfield', 'consts',",
- "'moduleconsts', 'newtype' and 'newtype_global'."
- ),
- )),
- }
- }
-}
-
-/// A helper type to construct different enum variations.
-enum EnumBuilder<'a> {
- Rust {
- codegen_depth: usize,
- attrs: Vec<proc_macro2::TokenStream>,
- ident: Ident,
- tokens: proc_macro2::TokenStream,
- emitted_any_variants: bool,
- },
- NewType {
- codegen_depth: usize,
- canonical_name: &'a str,
- tokens: proc_macro2::TokenStream,
- is_bitfield: bool,
- is_global: bool,
- },
- Consts {
- variants: Vec<proc_macro2::TokenStream>,
- codegen_depth: usize,
- },
- ModuleConsts {
- codegen_depth: usize,
- module_name: &'a str,
- module_items: Vec<proc_macro2::TokenStream>,
- },
-}
-
-impl<'a> EnumBuilder<'a> {
- /// Returns the depth of the code generation for a variant of this enum.
- fn codegen_depth(&self) -> usize {
- match *self {
- EnumBuilder::Rust { codegen_depth, .. } |
- EnumBuilder::NewType { codegen_depth, .. } |
- EnumBuilder::ModuleConsts { codegen_depth, .. } |
- EnumBuilder::Consts { codegen_depth, .. } => codegen_depth,
- }
- }
-
- /// Returns true if the builder is for a rustified enum.
- fn is_rust_enum(&self) -> bool {
- matches!(*self, EnumBuilder::Rust { .. })
- }
-
- /// Create a new enum given an item builder, a canonical name, a name for
- /// the representation, and which variation it should be generated as.
- fn new(
- name: &'a str,
- mut attrs: Vec<proc_macro2::TokenStream>,
- repr: proc_macro2::TokenStream,
- enum_variation: EnumVariation,
- enum_codegen_depth: usize,
- ) -> Self {
- let ident = Ident::new(name, Span::call_site());
-
- match enum_variation {
- EnumVariation::NewType {
- is_bitfield,
- is_global,
- } => EnumBuilder::NewType {
- codegen_depth: enum_codegen_depth,
- canonical_name: name,
- tokens: quote! {
- #( #attrs )*
- pub struct #ident (pub #repr);
- },
- is_bitfield,
- is_global,
- },
-
- EnumVariation::Rust { .. } => {
- // `repr` is guaranteed to be Rustified in Enum::codegen
- attrs.insert(0, quote! { #[repr( #repr )] });
- let tokens = quote!();
- EnumBuilder::Rust {
- codegen_depth: enum_codegen_depth + 1,
- attrs,
- ident,
- tokens,
- emitted_any_variants: false,
- }
- }
-
- EnumVariation::Consts => {
- let mut variants = Vec::new();
-
- variants.push(quote! {
- #( #attrs )*
- pub type #ident = #repr;
- });
-
- EnumBuilder::Consts {
- variants,
- codegen_depth: enum_codegen_depth,
- }
- }
-
- EnumVariation::ModuleConsts => {
- let ident = Ident::new(
- CONSTIFIED_ENUM_MODULE_REPR_NAME,
- Span::call_site(),
- );
- let type_definition = quote! {
- #( #attrs )*
- pub type #ident = #repr;
- };
-
- EnumBuilder::ModuleConsts {
- codegen_depth: enum_codegen_depth + 1,
- module_name: name,
- module_items: vec![type_definition],
- }
- }
- }
- }
-
- /// Add a variant to this enum.
- fn with_variant<'b>(
- self,
- ctx: &BindgenContext,
- variant: &EnumVariant,
- mangling_prefix: Option<&str>,
- rust_ty: proc_macro2::TokenStream,
- result: &mut CodegenResult<'b>,
- is_ty_named: bool,
- ) -> Self {
- let variant_name = ctx.rust_mangle(variant.name());
- let is_rust_enum = self.is_rust_enum();
- let expr = match variant.val() {
- EnumVariantValue::Boolean(v) if is_rust_enum => {
- helpers::ast_ty::uint_expr(v as u64)
- }
- EnumVariantValue::Boolean(v) => quote!(#v),
- EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v),
- EnumVariantValue::Unsigned(v) => helpers::ast_ty::uint_expr(v),
- };
-
- let mut doc = quote! {};
- if ctx.options().generate_comments {
- if let Some(raw_comment) = variant.comment() {
- let comment =
- comment::preprocess(raw_comment, self.codegen_depth());
- doc = attributes::doc(comment);
- }
- }
-
- match self {
- EnumBuilder::Rust {
- attrs,
- ident,
- tokens,
- emitted_any_variants: _,
- codegen_depth,
- } => {
- let name = ctx.rust_ident(variant_name);
- EnumBuilder::Rust {
- attrs,
- ident,
- codegen_depth,
- tokens: quote! {
- #tokens
- #doc
- #name = #expr,
- },
- emitted_any_variants: true,
- }
- }
-
- EnumBuilder::NewType {
- canonical_name,
- is_global,
- ..
- } => {
- if ctx.options().rust_features().associated_const &&
- is_ty_named &&
- !is_global
- {
- let enum_ident = ctx.rust_ident(canonical_name);
- let variant_ident = ctx.rust_ident(variant_name);
-
- result.push(quote! {
- impl #enum_ident {
- #doc
- pub const #variant_ident : #rust_ty = #rust_ty ( #expr );
- }
- });
- } else {
- let ident = ctx.rust_ident(match mangling_prefix {
- Some(prefix) => {
- Cow::Owned(format!("{}_{}", prefix, variant_name))
- }
- None => variant_name,
- });
- result.push(quote! {
- #doc
- pub const #ident : #rust_ty = #rust_ty ( #expr );
- });
- }
-
- self
- }
-
- EnumBuilder::Consts { .. } => {
- let constant_name = match mangling_prefix {
- Some(prefix) => {
- Cow::Owned(format!("{}_{}", prefix, variant_name))
- }
- None => variant_name,
- };
-
- let ident = ctx.rust_ident(constant_name);
- result.push(quote! {
- #doc
- pub const #ident : #rust_ty = #expr ;
- });
-
- self
- }
- EnumBuilder::ModuleConsts {
- codegen_depth,
- module_name,
- mut module_items,
- } => {
- let name = ctx.rust_ident(variant_name);
- let ty = ctx.rust_ident(CONSTIFIED_ENUM_MODULE_REPR_NAME);
- module_items.push(quote! {
- #doc
- pub const #name : #ty = #expr ;
- });
-
- EnumBuilder::ModuleConsts {
- module_name,
- module_items,
- codegen_depth,
- }
- }
- }
- }
-
- fn build<'b>(
- self,
- ctx: &BindgenContext,
- rust_ty: proc_macro2::TokenStream,
- result: &mut CodegenResult<'b>,
- ) -> proc_macro2::TokenStream {
- match self {
- EnumBuilder::Rust {
- attrs,
- ident,
- tokens,
- emitted_any_variants,
- ..
- } => {
- let variants = if !emitted_any_variants {
- quote!(__bindgen_cannot_repr_c_on_empty_enum = 0)
- } else {
- tokens
- };
-
- quote! {
- #( #attrs )*
- pub enum #ident {
- #variants
- }
- }
- }
- EnumBuilder::NewType {
- canonical_name,
- tokens,
- is_bitfield,
- ..
- } => {
- if !is_bitfield {
- return tokens;
- }
-
- let rust_ty_name = ctx.rust_ident_raw(canonical_name);
- let prefix = ctx.trait_prefix();
-
- result.push(quote! {
- impl ::#prefix::ops::BitOr<#rust_ty> for #rust_ty {
- type Output = Self;
-
- #[inline]
- fn bitor(self, other: Self) -> Self {
- #rust_ty_name(self.0 | other.0)
- }
- }
- });
-
- result.push(quote! {
- impl ::#prefix::ops::BitOrAssign for #rust_ty {
- #[inline]
- fn bitor_assign(&mut self, rhs: #rust_ty) {
- self.0 |= rhs.0;
- }
- }
- });
-
- result.push(quote! {
- impl ::#prefix::ops::BitAnd<#rust_ty> for #rust_ty {
- type Output = Self;
-
- #[inline]
- fn bitand(self, other: Self) -> Self {
- #rust_ty_name(self.0 & other.0)
- }
- }
- });
-
- result.push(quote! {
- impl ::#prefix::ops::BitAndAssign for #rust_ty {
- #[inline]
- fn bitand_assign(&mut self, rhs: #rust_ty) {
- self.0 &= rhs.0;
- }
- }
- });
-
- tokens
- }
- EnumBuilder::Consts { variants, .. } => quote! { #( #variants )* },
- EnumBuilder::ModuleConsts {
- module_items,
- module_name,
- ..
- } => {
- let ident = ctx.rust_ident(module_name);
- quote! {
- pub mod #ident {
- #( #module_items )*
- }
- }
- }
- }
- }
-}
-
-impl CodeGenerator for Enum {
- type Extra = Item;
- type Return = ();
-
- fn codegen<'a>(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
- item: &Item,
- ) {
- debug!("<Enum as CodeGenerator>::codegen: item = {:?}", item);
- debug_assert!(item.is_enabled_for_codegen(ctx));
-
- let name = item.canonical_name(ctx);
- let ident = ctx.rust_ident(&name);
- let enum_ty = item.expect_type();
- let layout = enum_ty.layout(ctx);
- let variation = self.computed_enum_variation(ctx, item);
-
- let repr_translated;
- let repr = match self.repr().map(|repr| ctx.resolve_type(repr)) {
- Some(repr)
- if !ctx.options().translate_enum_integer_types &&
- !variation.is_rust() =>
- {
- repr
- }
- repr => {
- // An enum's integer type is translated to a native Rust
- // integer type in 3 cases:
- // * the enum is Rustified and we need a translated type for
- // the repr attribute
- // * the representation couldn't be determined from the C source
- // * it was explicitly requested as a bindgen option
-
- let kind = match repr {
- Some(repr) => match *repr.canonical_type(ctx).kind() {
- TypeKind::Int(int_kind) => int_kind,
- _ => panic!("Unexpected type as enum repr"),
- },
- None => {
- warn!(
- "Guessing type of enum! Forward declarations of enums \
- shouldn't be legal!"
- );
- IntKind::Int
- }
- };
-
- let signed = kind.is_signed();
- let size = layout
- .map(|l| l.size)
- .or_else(|| kind.known_size())
- .unwrap_or(0);
-
- let translated = match (signed, size) {
- (true, 1) => IntKind::I8,
- (false, 1) => IntKind::U8,
- (true, 2) => IntKind::I16,
- (false, 2) => IntKind::U16,
- (true, 4) => IntKind::I32,
- (false, 4) => IntKind::U32,
- (true, 8) => IntKind::I64,
- (false, 8) => IntKind::U64,
- _ => {
- warn!(
- "invalid enum decl: signed: {}, size: {}",
- signed, size
- );
- IntKind::I32
- }
- };
-
- repr_translated =
- Type::new(None, None, TypeKind::Int(translated), false);
- &repr_translated
- }
- };
-
- let mut attrs = vec![];
-
- // TODO(emilio): Delegate this to the builders?
- match variation {
- EnumVariation::Rust { non_exhaustive } => {
- if non_exhaustive &&
- ctx.options().rust_features().non_exhaustive
- {
- attrs.push(attributes::non_exhaustive());
- } else if non_exhaustive &&
- !ctx.options().rust_features().non_exhaustive
- {
- panic!("The rust target you're using doesn't seem to support non_exhaustive enums");
- }
- }
- EnumVariation::NewType { .. } => {
- if ctx.options().rust_features.repr_transparent {
- attrs.push(attributes::repr("transparent"));
- } else {
- attrs.push(attributes::repr("C"));
- }
- }
- _ => {}
- };
-
- if let Some(comment) = item.comment(ctx) {
- attrs.push(attributes::doc(comment));
- }
-
- if item.must_use(ctx) {
- attrs.push(attributes::must_use());
- }
-
- if !variation.is_const() {
- let packed = false; // Enums can't be packed in Rust.
- let mut derives = derives_of_item(item, ctx, packed);
- // For backwards compat, enums always derive
- // Clone/Eq/PartialEq/Hash, even if we don't generate those by
- // default.
- derives.insert(
- DerivableTraits::CLONE |
- DerivableTraits::HASH |
- DerivableTraits::PARTIAL_EQ |
- DerivableTraits::EQ,
- );
- let mut derives: Vec<_> = derives.into();
- for derive in item.annotations().derives().iter() {
- if !derives.contains(&derive.as_str()) {
- derives.push(derive);
- }
- }
-
- // The custom derives callback may return a list of derive attributes;
- // add them to the end of the list.
- let custom_derives;
- if let Some(cb) = &ctx.options().parse_callbacks {
- custom_derives = cb.add_derives(&name);
- // In most cases this will be a no-op, since custom_derives will be empty.
- derives.extend(custom_derives.iter().map(|s| s.as_str()));
- };
-
- attrs.push(attributes::derives(&derives));
- }
-
- fn add_constant<'a>(
- ctx: &BindgenContext,
- enum_: &Type,
- // Only to avoid recomputing every time.
- enum_canonical_name: &Ident,
- // May be the same as "variant" if it's because the
- // enum is unnamed and we still haven't seen the
- // value.
- variant_name: &Ident,
- referenced_name: &Ident,
- enum_rust_ty: proc_macro2::TokenStream,
- result: &mut CodegenResult<'a>,
- ) {
- let constant_name = if enum_.name().is_some() {
- if ctx.options().prepend_enum_name {
- format!("{}_{}", enum_canonical_name, variant_name)
- } else {
- format!("{}", variant_name)
- }
- } else {
- format!("{}", variant_name)
- };
- let constant_name = ctx.rust_ident(constant_name);
-
- result.push(quote! {
- pub const #constant_name : #enum_rust_ty =
- #enum_canonical_name :: #referenced_name ;
- });
- }
-
- let repr = repr.to_rust_ty_or_opaque(ctx, item);
-
- let mut builder = EnumBuilder::new(
- &name,
- attrs,
- repr,
- variation,
- item.codegen_depth(ctx),
- );
-
- // A map where we keep a value -> variant relation.
- let mut seen_values = HashMap::<_, Ident>::default();
- let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &());
- let is_toplevel = item.is_toplevel(ctx);
-
- // Used to mangle the constants we generate in the unnamed-enum case.
- let parent_canonical_name = if is_toplevel {
- None
- } else {
- Some(item.parent_id().canonical_name(ctx))
- };
-
- let constant_mangling_prefix = if ctx.options().prepend_enum_name {
- if enum_ty.name().is_none() {
- parent_canonical_name.as_deref()
- } else {
- Some(&*name)
- }
- } else {
- None
- };
-
- // NB: We defer the creation of constified variants, in case we find
- // another variant with the same value (which is the common thing to
- // do).
- let mut constified_variants = VecDeque::new();
-
- let mut iter = self.variants().iter().peekable();
- while let Some(variant) =
- iter.next().or_else(|| constified_variants.pop_front())
- {
- if variant.hidden() {
- continue;
- }
-
- if variant.force_constification() && iter.peek().is_some() {
- constified_variants.push_back(variant);
- continue;
- }
-
- match seen_values.entry(variant.val()) {
- Entry::Occupied(ref entry) => {
- if variation.is_rust() {
- let variant_name = ctx.rust_mangle(variant.name());
- let mangled_name =
- if is_toplevel || enum_ty.name().is_some() {
- variant_name
- } else {
- let parent_name =
- parent_canonical_name.as_ref().unwrap();
-
- Cow::Owned(format!(
- "{}_{}",
- parent_name, variant_name
- ))
- };
-
- let existing_variant_name = entry.get();
- // Use associated constants for named enums.
- if enum_ty.name().is_some() &&
- ctx.options().rust_features().associated_const
- {
- let enum_canonical_name = &ident;
- let variant_name =
- ctx.rust_ident_raw(&*mangled_name);
- result.push(quote! {
- impl #enum_rust_ty {
- pub const #variant_name : #enum_rust_ty =
- #enum_canonical_name :: #existing_variant_name ;
- }
- });
- } else {
- add_constant(
- ctx,
- enum_ty,
- &ident,
- &Ident::new(&mangled_name, Span::call_site()),
- existing_variant_name,
- enum_rust_ty.clone(),
- result,
- );
- }
- } else {
- builder = builder.with_variant(
- ctx,
- variant,
- constant_mangling_prefix,
- enum_rust_ty.clone(),
- result,
- enum_ty.name().is_some(),
- );
- }
- }
- Entry::Vacant(entry) => {
- builder = builder.with_variant(
- ctx,
- variant,
- constant_mangling_prefix,
- enum_rust_ty.clone(),
- result,
- enum_ty.name().is_some(),
- );
-
- let variant_name = ctx.rust_ident(variant.name());
-
- // If it's an unnamed enum, or constification is enforced,
- // we also generate a constant so it can be properly
- // accessed.
- if (variation.is_rust() && enum_ty.name().is_none()) ||
- variant.force_constification()
- {
- let mangled_name = if is_toplevel {
- variant_name.clone()
- } else {
- let parent_name =
- parent_canonical_name.as_ref().unwrap();
-
- Ident::new(
- &format!("{}_{}", parent_name, variant_name),
- Span::call_site(),
- )
- };
-
- add_constant(
- ctx,
- enum_ty,
- &ident,
- &mangled_name,
- &variant_name,
- enum_rust_ty.clone(),
- result,
- );
- }
-
- entry.insert(variant_name);
- }
- }
- }
-
- let item = builder.build(ctx, enum_rust_ty, result);
- result.push(item);
- }
-}
-
-/// Enum for the default type of macro constants.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum MacroTypeVariation {
- /// Use i32 or i64
- Signed,
- /// Use u32 or u64
- Unsigned,
-}
-
-impl MacroTypeVariation {
- /// Convert a `MacroTypeVariation` to its str representation.
- pub fn as_str(&self) -> &str {
- match self {
- MacroTypeVariation::Signed => "signed",
- MacroTypeVariation::Unsigned => "unsigned",
- }
- }
-}
-
-impl Default for MacroTypeVariation {
- fn default() -> MacroTypeVariation {
- MacroTypeVariation::Unsigned
- }
-}
-
-impl std::str::FromStr for MacroTypeVariation {
- type Err = std::io::Error;
-
- /// Create a `MacroTypeVariation` from a string.
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "signed" => Ok(MacroTypeVariation::Signed),
- "unsigned" => Ok(MacroTypeVariation::Unsigned),
- _ => Err(std::io::Error::new(
- std::io::ErrorKind::InvalidInput,
- concat!(
- "Got an invalid MacroTypeVariation. Accepted values ",
- "are 'signed' and 'unsigned'"
- ),
- )),
- }
- }
-}
-
-/// Enum for how aliases should be translated.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum AliasVariation {
- /// Convert to regular Rust alias
- TypeAlias,
- /// Create a new type by wrapping the old type in a struct and using #[repr(transparent)]
- NewType,
- /// Same as NewStruct but also impl Deref to be able to use the methods of the wrapped type
- NewTypeDeref,
-}
-
-impl AliasVariation {
- /// Convert an `AliasVariation` to its str representation.
- pub fn as_str(&self) -> &str {
- match self {
- AliasVariation::TypeAlias => "type_alias",
- AliasVariation::NewType => "new_type",
- AliasVariation::NewTypeDeref => "new_type_deref",
- }
- }
-}
-
-impl Default for AliasVariation {
- fn default() -> AliasVariation {
- AliasVariation::TypeAlias
- }
-}
-
-impl std::str::FromStr for AliasVariation {
- type Err = std::io::Error;
-
- /// Create an `AliasVariation` from a string.
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "type_alias" => Ok(AliasVariation::TypeAlias),
- "new_type" => Ok(AliasVariation::NewType),
- "new_type_deref" => Ok(AliasVariation::NewTypeDeref),
- _ => Err(std::io::Error::new(
- std::io::ErrorKind::InvalidInput,
- concat!(
- "Got an invalid AliasVariation. Accepted values ",
- "are 'type_alias', 'new_type', and 'new_type_deref'"
- ),
- )),
- }
- }
-}
-
-/// Enum for how non-Copy unions should be translated.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum NonCopyUnionStyle {
- /// Wrap members in a type generated by bindgen.
- BindgenWrapper,
- /// Wrap members in [`::core::mem::ManuallyDrop`].
- ///
- /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your
- /// MSRV is lower.
- ManuallyDrop,
-}
-
-impl NonCopyUnionStyle {
- /// Convert an `NonCopyUnionStyle` to its str representation.
- pub fn as_str(&self) -> &'static str {
- match self {
- Self::BindgenWrapper => "bindgen_wrapper",
- Self::ManuallyDrop => "manually_drop",
- }
- }
-}
-
-impl Default for NonCopyUnionStyle {
- fn default() -> Self {
- Self::BindgenWrapper
- }
-}
-
-impl std::str::FromStr for NonCopyUnionStyle {
- type Err = std::io::Error;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "bindgen_wrapper" => Ok(Self::BindgenWrapper),
- "manually_drop" => Ok(Self::ManuallyDrop),
- _ => Err(std::io::Error::new(
- std::io::ErrorKind::InvalidInput,
- concat!(
- "Got an invalid NonCopyUnionStyle. Accepted values ",
- "are 'bindgen_wrapper' and 'manually_drop'"
- ),
- )),
- }
- }
-}
-
-/// Fallible conversion to an opaque blob.
-///
-/// Implementors of this trait should provide the `try_get_layout` method to
-/// fallibly get this thing's layout, which the provided `try_to_opaque` trait
-/// method will use to convert the `Layout` into an opaque blob Rust type.
-trait TryToOpaque {
- type Extra;
-
- /// Get the layout for this thing, if one is available.
- fn try_get_layout(
- &self,
- ctx: &BindgenContext,
- extra: &Self::Extra,
- ) -> error::Result<Layout>;
-
- /// Do not override this provided trait method.
- fn try_to_opaque(
- &self,
- ctx: &BindgenContext,
- extra: &Self::Extra,
- ) -> error::Result<proc_macro2::TokenStream> {
- self.try_get_layout(ctx, extra)
- .map(|layout| helpers::blob(ctx, layout))
- }
-}
-
-/// Infallible conversion of an IR thing to an opaque blob.
-///
-/// The resulting layout is best effort, and is unfortunately not guaranteed to
-/// be correct. When all else fails, we fall back to a single byte layout as a
-/// last resort, because C++ does not permit zero-sized types. See the note in
-/// the `ToRustTyOrOpaque` doc comment about fallible versus infallible traits
-/// and when each is appropriate.
-///
-/// Don't implement this directly. Instead implement `TryToOpaque`, and then
-/// leverage the blanket impl for this trait.
-trait ToOpaque: TryToOpaque {
- fn get_layout(&self, ctx: &BindgenContext, extra: &Self::Extra) -> Layout {
- self.try_get_layout(ctx, extra)
- .unwrap_or_else(|_| Layout::for_size(ctx, 1))
- }
-
- fn to_opaque(
- &self,
- ctx: &BindgenContext,
- extra: &Self::Extra,
- ) -> proc_macro2::TokenStream {
- let layout = self.get_layout(ctx, extra);
- helpers::blob(ctx, layout)
- }
-}
-
-impl<T> ToOpaque for T where T: TryToOpaque {}
-
-/// Fallible conversion from an IR thing to an *equivalent* Rust type.
-///
-/// If the C/C++ construct represented by the IR thing cannot (currently) be
-/// represented in Rust (for example, instantiations of templates with
-/// const-value generic parameters) then the impl should return an `Err`. It
-/// should *not* attempt to return an opaque blob with the correct size and
-/// alignment. That is the responsibility of the `TryToOpaque` trait.
-trait TryToRustTy {
- type Extra;
-
- fn try_to_rust_ty(
- &self,
- ctx: &BindgenContext,
- extra: &Self::Extra,
- ) -> error::Result<proc_macro2::TokenStream>;
-}
-
-/// Fallible conversion to a Rust type or an opaque blob with the correct size
-/// and alignment.
-///
-/// Don't implement this directly. Instead implement `TryToRustTy` and
-/// `TryToOpaque`, and then leverage the blanket impl for this trait below.
-trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque {
- type Extra;
-
- fn try_to_rust_ty_or_opaque(
- &self,
- ctx: &BindgenContext,
- extra: &<Self as TryToRustTyOrOpaque>::Extra,
- ) -> error::Result<proc_macro2::TokenStream>;
-}
-
-impl<E, T> TryToRustTyOrOpaque for T
-where
- T: TryToRustTy<Extra = E> + TryToOpaque<Extra = E>,
-{
- type Extra = E;
-
- fn try_to_rust_ty_or_opaque(
- &self,
- ctx: &BindgenContext,
- extra: &E,
- ) -> error::Result<proc_macro2::TokenStream> {
- self.try_to_rust_ty(ctx, extra).or_else(|_| {
- if let Ok(layout) = self.try_get_layout(ctx, extra) {
- Ok(helpers::blob(ctx, layout))
- } else {
- Err(error::Error::NoLayoutForOpaqueBlob)
- }
- })
- }
-}
-
-/// Infallible conversion to a Rust type, or an opaque blob with a best effort
-/// of correct size and alignment.
-///
-/// Don't implement this directly. Instead implement `TryToRustTy` and
-/// `TryToOpaque`, and then leverage the blanket impl for this trait below.
-///
-/// ### Fallible vs. Infallible Conversions to Rust Types
-///
-/// When should one use this infallible `ToRustTyOrOpaque` trait versus the
-/// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` triats? All fallible trait
-/// implementations that need to convert another thing into a Rust type or
-/// opaque blob in a nested manner should also use fallible trait methods and
-/// propagate failure up the stack. Only infallible functions and methods like
-/// CodeGenerator implementations should use the infallible
-/// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely
-/// we are to get a usable `Layout` even if we can't generate an equivalent Rust
-/// type for a C++ construct.
-trait ToRustTyOrOpaque: TryToRustTy + ToOpaque {
- type Extra;
-
- fn to_rust_ty_or_opaque(
- &self,
- ctx: &BindgenContext,
- extra: &<Self as ToRustTyOrOpaque>::Extra,
- ) -> proc_macro2::TokenStream;
-}
-
-impl<E, T> ToRustTyOrOpaque for T
-where
- T: TryToRustTy<Extra = E> + ToOpaque<Extra = E>,
-{
- type Extra = E;
-
- fn to_rust_ty_or_opaque(
- &self,
- ctx: &BindgenContext,
- extra: &E,
- ) -> proc_macro2::TokenStream {
- self.try_to_rust_ty(ctx, extra)
- .unwrap_or_else(|_| self.to_opaque(ctx, extra))
- }
-}
-
-impl<T> TryToOpaque for T
-where
- T: Copy + Into<ItemId>,
-{
- type Extra = ();
-
- fn try_get_layout(
- &self,
- ctx: &BindgenContext,
- _: &(),
- ) -> error::Result<Layout> {
- ctx.resolve_item((*self).into()).try_get_layout(ctx, &())
- }
-}
-
-impl<T> TryToRustTy for T
-where
- T: Copy + Into<ItemId>,
-{
- type Extra = ();
-
- fn try_to_rust_ty(
- &self,
- ctx: &BindgenContext,
- _: &(),
- ) -> error::Result<proc_macro2::TokenStream> {
- ctx.resolve_item((*self).into()).try_to_rust_ty(ctx, &())
- }
-}
-
-impl TryToOpaque for Item {
- type Extra = ();
-
- fn try_get_layout(
- &self,
- ctx: &BindgenContext,
- _: &(),
- ) -> error::Result<Layout> {
- self.kind().expect_type().try_get_layout(ctx, self)
- }
-}
-
-impl TryToRustTy for Item {
- type Extra = ();
-
- fn try_to_rust_ty(
- &self,
- ctx: &BindgenContext,
- _: &(),
- ) -> error::Result<proc_macro2::TokenStream> {
- self.kind().expect_type().try_to_rust_ty(ctx, self)
- }
-}
-
-impl TryToOpaque for Type {
- type Extra = Item;
-
- fn try_get_layout(
- &self,
- ctx: &BindgenContext,
- _: &Item,
- ) -> error::Result<Layout> {
- self.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob)
- }
-}
-
-impl TryToRustTy for Type {
- type Extra = Item;
-
- fn try_to_rust_ty(
- &self,
- ctx: &BindgenContext,
- item: &Item,
- ) -> error::Result<proc_macro2::TokenStream> {
- use self::helpers::ast_ty::*;
-
- match *self.kind() {
- TypeKind::Void => Ok(c_void(ctx)),
- // TODO: we should do something smart with nullptr, or maybe *const
- // c_void is enough?
- TypeKind::NullPtr => Ok(c_void(ctx).to_ptr(true)),
- TypeKind::Int(ik) => {
- match ik {
- IntKind::Bool => Ok(quote! { bool }),
- IntKind::Char { .. } => Ok(raw_type(ctx, "c_char")),
- IntKind::SChar => Ok(raw_type(ctx, "c_schar")),
- IntKind::UChar => Ok(raw_type(ctx, "c_uchar")),
- IntKind::Short => Ok(raw_type(ctx, "c_short")),
- IntKind::UShort => Ok(raw_type(ctx, "c_ushort")),
- IntKind::Int => Ok(raw_type(ctx, "c_int")),
- IntKind::UInt => Ok(raw_type(ctx, "c_uint")),
- IntKind::Long => Ok(raw_type(ctx, "c_long")),
- IntKind::ULong => Ok(raw_type(ctx, "c_ulong")),
- IntKind::LongLong => Ok(raw_type(ctx, "c_longlong")),
- IntKind::ULongLong => Ok(raw_type(ctx, "c_ulonglong")),
- IntKind::WChar => {
- let layout = self
- .layout(ctx)
- .expect("Couldn't compute wchar_t's layout?");
- let ty = Layout::known_type_for_size(ctx, layout.size)
- .expect("Non-representable wchar_t?");
- let ident = ctx.rust_ident_raw(ty);
- Ok(quote! { #ident })
- }
-
- IntKind::I8 => Ok(quote! { i8 }),
- IntKind::U8 => Ok(quote! { u8 }),
- IntKind::I16 => Ok(quote! { i16 }),
- IntKind::U16 => Ok(quote! { u16 }),
- IntKind::I32 => Ok(quote! { i32 }),
- IntKind::U32 => Ok(quote! { u32 }),
- IntKind::I64 => Ok(quote! { i64 }),
- IntKind::U64 => Ok(quote! { u64 }),
- IntKind::Custom { name, .. } => {
- Ok(proc_macro2::TokenStream::from_str(name).unwrap())
- }
- IntKind::U128 => {
- Ok(if ctx.options().rust_features.i128_and_u128 {
- quote! { u128 }
- } else {
- // Best effort thing, but wrong alignment
- // unfortunately.
- quote! { [u64; 2] }
- })
- }
- IntKind::I128 => {
- Ok(if ctx.options().rust_features.i128_and_u128 {
- quote! { i128 }
- } else {
- quote! { [u64; 2] }
- })
- }
- }
- }
- TypeKind::Float(fk) => {
- Ok(float_kind_rust_type(ctx, fk, self.layout(ctx)))
- }
- TypeKind::Complex(fk) => {
- let float_path =
- float_kind_rust_type(ctx, fk, self.layout(ctx));
-
- ctx.generated_bindgen_complex();
- Ok(if ctx.options().enable_cxx_namespaces {
- quote! {
- root::__BindgenComplex<#float_path>
- }
- } else {
- quote! {
- __BindgenComplex<#float_path>
- }
- })
- }
- TypeKind::Function(ref fs) => {
- // We can't rely on the sizeof(Option<NonZero<_>>) ==
- // sizeof(NonZero<_>) optimization with opaque blobs (because
- // they aren't NonZero), so don't *ever* use an or_opaque
- // variant here.
- let ty = fs.try_to_rust_ty(ctx, &())?;
-
- let prefix = ctx.trait_prefix();
- Ok(quote! {
- ::#prefix::option::Option<#ty>
- })
- }
- TypeKind::Array(item, len) | TypeKind::Vector(item, len) => {
- let ty = item.try_to_rust_ty(ctx, &())?;
- Ok(quote! {
- [ #ty ; #len ]
- })
- }
- TypeKind::Enum(..) => {
- let path = item.namespace_aware_canonical_path(ctx);
- let path = proc_macro2::TokenStream::from_str(&path.join("::"))
- .unwrap();
- Ok(quote!(#path))
- }
- TypeKind::TemplateInstantiation(ref inst) => {
- inst.try_to_rust_ty(ctx, item)
- }
- TypeKind::ResolvedTypeRef(inner) => inner.try_to_rust_ty(ctx, &()),
- TypeKind::TemplateAlias(..) |
- TypeKind::Alias(..) |
- TypeKind::BlockPointer(..) => {
- if self.is_block_pointer() && !ctx.options().generate_block {
- let void = c_void(ctx);
- return Ok(void.to_ptr(/* is_const = */ false));
- }
-
- if item.is_opaque(ctx, &()) &&
- item.used_template_params(ctx)
- .into_iter()
- .any(|param| param.is_template_param(ctx, &()))
- {
- self.try_to_opaque(ctx, item)
- } else if let Some(ty) = self
- .name()
- .and_then(|name| utils::type_from_named(ctx, name))
- {
- Ok(ty)
- } else {
- utils::build_path(item, ctx)
- }
- }
- TypeKind::Comp(ref info) => {
- let template_params = item.all_template_params(ctx);
- if info.has_non_type_template_params() ||
- (item.is_opaque(ctx, &()) && !template_params.is_empty())
- {
- return self.try_to_opaque(ctx, item);
- }
-
- utils::build_path(item, ctx)
- }
- TypeKind::Opaque => self.try_to_opaque(ctx, item),
- TypeKind::Pointer(inner) | TypeKind::Reference(inner) => {
- let is_const = ctx.resolve_type(inner).is_const();
-
- let inner =
- inner.into_resolver().through_type_refs().resolve(ctx);
- let inner_ty = inner.expect_type();
-
- let is_objc_pointer =
- matches!(inner_ty.kind(), TypeKind::ObjCInterface(..));
-
- // Regardless if we can properly represent the inner type, we
- // should always generate a proper pointer here, so use
- // infallible conversion of the inner type.
- let mut ty = inner.to_rust_ty_or_opaque(ctx, &());
- ty.append_implicit_template_params(ctx, inner);
-
- // Avoid the first function pointer level, since it's already
- // represented in Rust.
- if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer
- {
- Ok(ty)
- } else {
- Ok(ty.to_ptr(is_const))
- }
- }
- TypeKind::TypeParam => {
- let name = item.canonical_name(ctx);
- let ident = ctx.rust_ident(&name);
- Ok(quote! {
- #ident
- })
- }
- TypeKind::ObjCSel => Ok(quote! {
- objc::runtime::Sel
- }),
- TypeKind::ObjCId => Ok(quote! {
- id
- }),
- TypeKind::ObjCInterface(ref interface) => {
- let name = ctx.rust_ident(interface.name());
- Ok(quote! {
- #name
- })
- }
- ref u @ TypeKind::UnresolvedTypeRef(..) => {
- unreachable!("Should have been resolved after parsing {:?}!", u)
- }
- }
- }
-}
-
-impl TryToOpaque for TemplateInstantiation {
- type Extra = Item;
-
- fn try_get_layout(
- &self,
- ctx: &BindgenContext,
- item: &Item,
- ) -> error::Result<Layout> {
- item.expect_type()
- .layout(ctx)
- .ok_or(error::Error::NoLayoutForOpaqueBlob)
- }
-}
-
-impl TryToRustTy for TemplateInstantiation {
- type Extra = Item;
-
- fn try_to_rust_ty(
- &self,
- ctx: &BindgenContext,
- item: &Item,
- ) -> error::Result<proc_macro2::TokenStream> {
- if self.is_opaque(ctx, item) {
- return Err(error::Error::InstantiationOfOpaqueType);
- }
-
- let def = self
- .template_definition()
- .into_resolver()
- .through_type_refs()
- .resolve(ctx);
-
- let mut ty = quote! {};
- let def_path = def.namespace_aware_canonical_path(ctx);
- ty.append_separated(
- def_path.into_iter().map(|p| ctx.rust_ident(p)),
- quote!(::),
- );
-
- let def_params = def.self_template_params(ctx);
- if def_params.is_empty() {
- // This can happen if we generated an opaque type for a partial
- // template specialization, and we've hit an instantiation of
- // that partial specialization.
- extra_assert!(def.is_opaque(ctx, &()));
- return Err(error::Error::InstantiationOfOpaqueType);
- }
-
- // TODO: If the definition type is a template class/struct
- // definition's member template definition, it could rely on
- // generic template parameters from its outer template
- // class/struct. When we emit bindings for it, it could require
- // *more* type arguments than we have here, and we will need to
- // reconstruct them somehow. We don't have any means of doing
- // that reconstruction at this time.
-
- let template_args = self
- .template_arguments()
- .iter()
- .zip(def_params.iter())
- // Only pass type arguments for the type parameters that
- // the def uses.
- .filter(|&(_, param)| ctx.uses_template_parameter(def.id(), *param))
- .map(|(arg, _)| {
- let arg = arg.into_resolver().through_type_refs().resolve(ctx);
- let mut ty = arg.try_to_rust_ty(ctx, &())?;
- ty.append_implicit_template_params(ctx, arg);
- Ok(ty)
- })
- .collect::<error::Result<Vec<_>>>()?;
-
- if template_args.is_empty() {
- return Ok(ty);
- }
-
- Ok(quote! {
- #ty < #( #template_args ),* >
- })
- }
-}
-
-impl TryToRustTy for FunctionSig {
- type Extra = ();
-
- fn try_to_rust_ty(
- &self,
- ctx: &BindgenContext,
- _: &(),
- ) -> error::Result<proc_macro2::TokenStream> {
- // TODO: we might want to consider ignoring the reference return value.
- let ret = utils::fnsig_return_ty(ctx, self);
- let arguments = utils::fnsig_arguments(ctx, self);
- let abi = self.abi();
-
- match abi {
- Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
- warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
- Ok(proc_macro2::TokenStream::new())
- }
- Abi::Vectorcall
- if !ctx.options().rust_features().vectorcall_abi =>
- {
- warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
- Ok(proc_macro2::TokenStream::new())
- }
- _ => Ok(quote! {
- unsafe extern #abi fn ( #( #arguments ),* ) #ret
- }),
- }
- }
-}
-
-impl CodeGenerator for Function {
- type Extra = Item;
-
- /// If we've actually generated the symbol, the number of times we've seen
- /// it.
- type Return = Option<u32>;
-
- fn codegen<'a>(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
- item: &Item,
- ) -> Self::Return {
- debug!("<Function as CodeGenerator>::codegen: item = {:?}", item);
- debug_assert!(item.is_enabled_for_codegen(ctx));
-
- // We can't currently do anything with Internal functions so just
- // avoid generating anything for them.
- match self.linkage() {
- Linkage::Internal => return None,
- Linkage::External => {}
- }
-
- // Pure virtual methods have no actual symbol, so we can't generate
- // something meaningful for them.
- let is_dynamic_function = match self.kind() {
- FunctionKind::Method(ref method_kind)
- if method_kind.is_pure_virtual() =>
- {
- return None;
- }
- FunctionKind::Function => {
- ctx.options().dynamic_library_name.is_some()
- }
- _ => false,
- };
-
- // Similar to static member variables in a class template, we can't
- // generate bindings to template functions, because the set of
- // instantiations is open ended and we have no way of knowing which
- // monomorphizations actually exist.
- if !item.all_template_params(ctx).is_empty() {
- return None;
- }
-
- let name = self.name();
- let mut canonical_name = item.canonical_name(ctx);
- let mangled_name = self.mangled_name();
-
- {
- let seen_symbol_name = mangled_name.unwrap_or(&canonical_name);
-
- // TODO: Maybe warn here if there's a type/argument mismatch, or
- // something?
- if result.seen_function(seen_symbol_name) {
- return None;
- }
- result.saw_function(seen_symbol_name);
- }
-
- let signature_item = ctx.resolve_item(self.signature());
- let signature = signature_item.kind().expect_type().canonical_type(ctx);
- let signature = match *signature.kind() {
- TypeKind::Function(ref sig) => sig,
- _ => panic!("Signature kind is not a Function: {:?}", signature),
- };
-
- let args = utils::fnsig_arguments(ctx, signature);
- let ret = utils::fnsig_return_ty(ctx, signature);
-
- let mut attributes = vec![];
-
- if ctx.options().rust_features().must_use_function {
- let must_use = signature.must_use() || {
- let ret_ty = signature
- .return_type()
- .into_resolver()
- .through_type_refs()
- .resolve(ctx);
- ret_ty.must_use(ctx)
- };
-
- if must_use {
- attributes.push(attributes::must_use());
- }
- }
-
- if let Some(comment) = item.comment(ctx) {
- attributes.push(attributes::doc(comment));
- }
-
- let abi = match signature.abi() {
- Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
- warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
- return None;
- }
- Abi::Vectorcall
- if !ctx.options().rust_features().vectorcall_abi =>
- {
- warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
- return None;
- }
- Abi::Win64 if signature.is_variadic() => {
- warn!("Skipping variadic function with Win64 ABI that isn't supported");
- return None;
- }
- Abi::Unknown(unknown_abi) => {
- panic!(
- "Invalid or unknown abi {:?} for function {:?} ({:?})",
- unknown_abi, canonical_name, self
- );
- }
- abi => abi,
- };
-
- // Handle overloaded functions by giving each overload its own unique
- // suffix.
- let times_seen = result.overload_number(&canonical_name);
- if times_seen > 0 {
- write!(&mut canonical_name, "{}", times_seen).unwrap();
- }
-
- let link_name = mangled_name.unwrap_or(name);
- if !is_dynamic_function &&
- !utils::names_will_be_identical_after_mangling(
- &canonical_name,
- link_name,
- Some(abi),
- )
- {
- attributes.push(attributes::link_name(link_name));
- }
-
- // Unfortunately this can't piggyback on the `attributes` list because
- // the #[link(wasm_import_module)] needs to happen before the `extern
- // "C"` block. It doesn't get picked up properly otherwise
- let wasm_link_attribute =
- ctx.options().wasm_import_module_name.as_ref().map(|name| {
- quote! { #[link(wasm_import_module = #name)] }
- });
-
- let ident = ctx.rust_ident(canonical_name);
- let tokens = quote! {
- #wasm_link_attribute
- extern #abi {
- #(#attributes)*
- pub fn #ident ( #( #args ),* ) #ret;
- }
- };
-
- // If we're doing dynamic binding generation, add to the dynamic items.
- if is_dynamic_function {
- let args_identifiers =
- utils::fnsig_argument_identifiers(ctx, signature);
- let return_item = ctx.resolve_item(signature.return_type());
- let ret_ty = match *return_item.kind().expect_type().kind() {
- TypeKind::Void => quote! {()},
- _ => return_item.to_rust_ty_or_opaque(ctx, &()),
- };
- result.dynamic_items().push(
- ident,
- abi,
- signature.is_variadic(),
- ctx.options().dynamic_link_require_all,
- args,
- args_identifiers,
- ret,
- ret_ty,
- attributes,
- );
- } else {
- result.push(tokens);
- }
- Some(times_seen)
- }
-}
-
-fn objc_method_codegen(
- ctx: &BindgenContext,
- method: &ObjCMethod,
- methods: &mut Vec<proc_macro2::TokenStream>,
- class_name: Option<&str>,
- rust_class_name: &str,
- prefix: &str,
-) {
- // This would ideally resolve the method into an Item, and use
- // Item::process_before_codegen; however, ObjC methods are not currently
- // made into function items.
- let name = format!("{}::{}{}", rust_class_name, prefix, method.rust_name());
- if ctx.options().blocklisted_items.matches(name) {
- return;
- }
-
- let signature = method.signature();
- let fn_args = utils::fnsig_arguments(ctx, signature);
- let fn_ret = utils::fnsig_return_ty(ctx, signature);
-
- let sig = if method.is_class_method() {
- let fn_args = fn_args.clone();
- quote! {
- ( #( #fn_args ),* ) #fn_ret
- }
- } else {
- let fn_args = fn_args.clone();
- let args = iter::once(quote! { &self }).chain(fn_args.into_iter());
- quote! {
- ( #( #args ),* ) #fn_ret
- }
- };
-
- let methods_and_args = method.format_method_call(&fn_args);
-
- let body = if method.is_class_method() {
- let class_name = ctx.rust_ident(
- class_name.expect("Generating a class method without class name?"),
- );
- quote! {
- msg_send!(class!(#class_name), #methods_and_args)
- }
- } else {
- quote! {
- msg_send!(*self, #methods_and_args)
- }
- };
-
- let method_name =
- ctx.rust_ident(format!("{}{}", prefix, method.rust_name()));
-
- methods.push(quote! {
- unsafe fn #method_name #sig where <Self as std::ops::Deref>::Target: objc::Message + Sized {
- #body
- }
- });
-}
-
-impl CodeGenerator for ObjCInterface {
- type Extra = Item;
- type Return = ();
-
- fn codegen<'a>(
- &self,
- ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
- item: &Item,
- ) {
- debug_assert!(item.is_enabled_for_codegen(ctx));
-
- let mut impl_items = vec![];
- let rust_class_name = item.path_for_allowlisting(ctx)[1..].join("::");
-
- for method in self.methods() {
- objc_method_codegen(
- ctx,
- method,
- &mut impl_items,
- None,
- &rust_class_name,
- "",
- );
- }
-
- for class_method in self.class_methods() {
- let ambiquity = self
- .methods()
- .iter()
- .map(|m| m.rust_name())
- .any(|x| x == class_method.rust_name());
- let prefix = if ambiquity { "class_" } else { "" };
- objc_method_codegen(
- ctx,
- class_method,
- &mut impl_items,
- Some(self.name()),
- &rust_class_name,
- prefix,
- );
- }
-
- let trait_name = ctx.rust_ident(self.rust_name());
- let trait_constraints = quote! {
- Sized + std::ops::Deref
- };
- let trait_block = if self.is_template() {
- let template_names: Vec<Ident> = self
- .template_names
- .iter()
- .map(|g| ctx.rust_ident(g))
- .collect();
-
- quote! {
- pub trait #trait_name <#(#template_names:'static),*> : #trait_constraints {
- #( #impl_items )*
- }
- }
- } else {
- quote! {
- pub trait #trait_name : #trait_constraints {
- #( #impl_items )*
- }
- }
- };
-
- let class_name = ctx.rust_ident(self.name());
- if !self.is_category() && !self.is_protocol() {
- let struct_block = quote! {
- #[repr(transparent)]
- #[derive(Debug, Copy, Clone)]
- pub struct #class_name(pub id);
- impl std::ops::Deref for #class_name {
- type Target = objc::runtime::Object;
- fn deref(&self) -> &Self::Target {
- unsafe {
- &*self.0
- }
- }
- }
- unsafe impl objc::Message for #class_name { }
- impl #class_name {
- pub fn alloc() -> Self {
- Self(unsafe {
- msg_send!(class!(#class_name), alloc)
- })
- }
- }
- };
- result.push(struct_block);
- let mut protocol_set: HashSet<ItemId> = Default::default();
- for protocol_id in self.conforms_to.iter() {
- protocol_set.insert(*protocol_id);
- let protocol_name = ctx.rust_ident(
- ctx.resolve_type(protocol_id.expect_type_id(ctx))
- .name()
- .unwrap(),
- );
- let impl_trait = quote! {
- impl #protocol_name for #class_name { }
- };
- result.push(impl_trait);
- }
- let mut parent_class = self.parent_class;
- while let Some(parent_id) = parent_class {
- let parent = parent_id
- .expect_type_id(ctx)
- .into_resolver()
- .through_type_refs()
- .resolve(ctx)
- .expect_type()
- .kind();
-
- let parent = match parent {
- TypeKind::ObjCInterface(ref parent) => parent,
- _ => break,
- };
- parent_class = parent.parent_class;
-
- let parent_name = ctx.rust_ident(parent.rust_name());
- let impl_trait = if parent.is_template() {
- let template_names: Vec<Ident> = parent
- .template_names
- .iter()
- .map(|g| ctx.rust_ident(g))
- .collect();
- quote! {
- impl <#(#template_names :'static),*> #parent_name <#(#template_names),*> for #class_name {
- }
- }
- } else {
- quote! {
- impl #parent_name for #class_name { }
- }
- };
- result.push(impl_trait);
- for protocol_id in parent.conforms_to.iter() {
- if protocol_set.insert(*protocol_id) {
- let protocol_name = ctx.rust_ident(
- ctx.resolve_type(protocol_id.expect_type_id(ctx))
- .name()
- .unwrap(),
- );
- let impl_trait = quote! {
- impl #protocol_name for #class_name { }
- };
- result.push(impl_trait);
- }
- }
- if !parent.is_template() {
- let parent_struct_name = parent.name();
- let child_struct_name = self.name();
- let parent_struct = ctx.rust_ident(parent_struct_name);
- let from_block = quote! {
- impl From<#class_name> for #parent_struct {
- fn from(child: #class_name) -> #parent_struct {
- #parent_struct(child.0)
- }
- }
- };
- result.push(from_block);
-
- let error_msg = format!(
- "This {} cannot be downcasted to {}",
- parent_struct_name, child_struct_name
- );
- let try_into_block = quote! {
- impl std::convert::TryFrom<#parent_struct> for #class_name {
- type Error = &'static str;
- fn try_from(parent: #parent_struct) -> Result<#class_name, Self::Error> {
- let is_kind_of : bool = unsafe { msg_send!(parent, isKindOfClass:class!(#class_name))};
- if is_kind_of {
- Ok(#class_name(parent.0))
- } else {
- Err(#error_msg)
- }
- }
- }
- };
- result.push(try_into_block);
- }
- }
- }
-
- if !self.is_protocol() {
- let impl_block = if self.is_template() {
- let template_names: Vec<Ident> = self
- .template_names
- .iter()
- .map(|g| ctx.rust_ident(g))
- .collect();
- quote! {
- impl <#(#template_names :'static),*> #trait_name <#(#template_names),*> for #class_name {
- }
- }
- } else {
- quote! {
- impl #trait_name for #class_name {
- }
- }
- };
- result.push(impl_block);
- }
-
- result.push(trait_block);
- result.saw_objc();
- }
-}
-
-pub(crate) fn codegen(
- context: BindgenContext,
-) -> (proc_macro2::TokenStream, BindgenOptions, Vec<String>) {
- context.gen(|context| {
- let _t = context.timer("codegen");
- let counter = Cell::new(0);
- let mut result = CodegenResult::new(&counter);
-
- debug!("codegen: {:?}", context.options());
-
- if context.options().emit_ir {
- let codegen_items = context.codegen_items();
- for (id, item) in context.items() {
- if codegen_items.contains(&id) {
- println!("ir: {:?} = {:#?}", id, item);
- }
- }
- }
-
- if let Some(path) = context.options().emit_ir_graphviz.as_ref() {
- match dot::write_dot_file(context, path) {
- Ok(()) => info!(
- "Your dot file was generated successfully into: {}",
- path
- ),
- Err(e) => warn!("{}", e),
- }
- }
-
- if let Some(spec) = context.options().depfile.as_ref() {
- match spec.write(context.deps()) {
- Ok(()) => info!(
- "Your depfile was generated successfully into: {}",
- spec.depfile_path.display()
- ),
- Err(e) => warn!("{}", e),
- }
- }
-
- context.resolve_item(context.root_module()).codegen(
- context,
- &mut result,
- &(),
- );
-
- if let Some(ref lib_name) = context.options().dynamic_library_name {
- let lib_ident = context.rust_ident(lib_name);
- let dynamic_items_tokens =
- result.dynamic_items().get_tokens(lib_ident);
- result.push(dynamic_items_tokens);
- }
-
- postprocessing::postprocessing(result.items, context.options())
- })
-}
-
-pub mod utils {
- use super::{error, ToRustTyOrOpaque};
- use crate::ir::context::BindgenContext;
- use crate::ir::function::{Abi, FunctionSig};
- use crate::ir::item::{Item, ItemCanonicalPath};
- use crate::ir::ty::TypeKind;
- use proc_macro2;
- use std::borrow::Cow;
- use std::mem;
- use std::str::FromStr;
-
- pub fn prepend_bitfield_unit_type(
- ctx: &BindgenContext,
- result: &mut Vec<proc_macro2::TokenStream>,
- ) {
- let bitfield_unit_src = include_str!("./bitfield_unit.rs");
- let bitfield_unit_src = if ctx.options().rust_features().min_const_fn {
- Cow::Borrowed(bitfield_unit_src)
- } else {
- Cow::Owned(bitfield_unit_src.replace("const fn ", "fn "))
- };
- let bitfield_unit_type =
- proc_macro2::TokenStream::from_str(&bitfield_unit_src).unwrap();
- let bitfield_unit_type = quote!(#bitfield_unit_type);
-
- let items = vec![bitfield_unit_type];
- let old_items = mem::replace(result, items);
- result.extend(old_items);
- }
-
- pub fn prepend_objc_header(
- ctx: &BindgenContext,
- result: &mut Vec<proc_macro2::TokenStream>,
- ) {
- let use_objc = if ctx.options().objc_extern_crate {
- quote! {
- #[macro_use]
- extern crate objc;
- }
- } else {
- quote! {
- use objc::{self, msg_send, sel, sel_impl, class};
- }
- };
-
- let id_type = quote! {
- #[allow(non_camel_case_types)]
- pub type id = *mut objc::runtime::Object;
- };
-
- let items = vec![use_objc, id_type];
- let old_items = mem::replace(result, items);
- result.extend(old_items.into_iter());
- }
-
- pub fn prepend_block_header(
- ctx: &BindgenContext,
- result: &mut Vec<proc_macro2::TokenStream>,
- ) {
- let use_block = if ctx.options().block_extern_crate {
- quote! {
- extern crate block;
- }
- } else {
- quote! {
- use block;
- }
- };
-
- let items = vec![use_block];
- let old_items = mem::replace(result, items);
- result.extend(old_items.into_iter());
- }
-
- pub fn prepend_union_types(
- ctx: &BindgenContext,
- result: &mut Vec<proc_macro2::TokenStream>,
- ) {
- let prefix = ctx.trait_prefix();
-
- // If the target supports `const fn`, declare eligible functions
- // as `const fn` else just `fn`.
- let const_fn = if ctx.options().rust_features().min_const_fn {
- quote! { const fn }
- } else {
- quote! { fn }
- };
-
- // TODO(emilio): The fmt::Debug impl could be way nicer with
- // std::intrinsics::type_name, but...
- let union_field_decl = quote! {
- #[repr(C)]
- pub struct __BindgenUnionField<T>(::#prefix::marker::PhantomData<T>);
- };
-
- let union_field_impl = quote! {
- impl<T> __BindgenUnionField<T> {
- #[inline]
- pub #const_fn new() -> Self {
- __BindgenUnionField(::#prefix::marker::PhantomData)
- }
-
- #[inline]
- pub unsafe fn as_ref(&self) -> &T {
- ::#prefix::mem::transmute(self)
- }
-
- #[inline]
- pub unsafe fn as_mut(&mut self) -> &mut T {
- ::#prefix::mem::transmute(self)
- }
- }
- };
-
- let union_field_default_impl = quote! {
- impl<T> ::#prefix::default::Default for __BindgenUnionField<T> {
- #[inline]
- fn default() -> Self {
- Self::new()
- }
- }
- };
-
- let union_field_clone_impl = quote! {
- impl<T> ::#prefix::clone::Clone for __BindgenUnionField<T> {
- #[inline]
- fn clone(&self) -> Self {
- Self::new()
- }
- }
- };
-
- let union_field_copy_impl = quote! {
- impl<T> ::#prefix::marker::Copy for __BindgenUnionField<T> {}
- };
-
- let union_field_debug_impl = quote! {
- impl<T> ::#prefix::fmt::Debug for __BindgenUnionField<T> {
- fn fmt(&self, fmt: &mut ::#prefix::fmt::Formatter<'_>)
- -> ::#prefix::fmt::Result {
- fmt.write_str("__BindgenUnionField")
- }
- }
- };
-
- // The actual memory of the filed will be hashed, so that's why these
- // field doesn't do anything with the hash.
- let union_field_hash_impl = quote! {
- impl<T> ::#prefix::hash::Hash for __BindgenUnionField<T> {
- fn hash<H: ::#prefix::hash::Hasher>(&self, _state: &mut H) {
- }
- }
- };
-
- let union_field_partialeq_impl = quote! {
- impl<T> ::#prefix::cmp::PartialEq for __BindgenUnionField<T> {
- fn eq(&self, _other: &__BindgenUnionField<T>) -> bool {
- true
- }
- }
- };
-
- let union_field_eq_impl = quote! {
- impl<T> ::#prefix::cmp::Eq for __BindgenUnionField<T> {
- }
- };
-
- let items = vec![
- union_field_decl,
- union_field_impl,
- union_field_default_impl,
- union_field_clone_impl,
- union_field_copy_impl,
- union_field_debug_impl,
- union_field_hash_impl,
- union_field_partialeq_impl,
- union_field_eq_impl,
- ];
-
- let old_items = mem::replace(result, items);
- result.extend(old_items.into_iter());
- }
-
- pub fn prepend_incomplete_array_types(
- ctx: &BindgenContext,
- result: &mut Vec<proc_macro2::TokenStream>,
- ) {
- let prefix = ctx.trait_prefix();
-
- // If the target supports `const fn`, declare eligible functions
- // as `const fn` else just `fn`.
- let const_fn = if ctx.options().rust_features().min_const_fn {
- quote! { const fn }
- } else {
- quote! { fn }
- };
-
- let incomplete_array_decl = quote! {
- #[repr(C)]
- #[derive(Default)]
- pub struct __IncompleteArrayField<T>(
- ::#prefix::marker::PhantomData<T>, [T; 0]);
- };
-
- let incomplete_array_impl = quote! {
- impl<T> __IncompleteArrayField<T> {
- #[inline]
- pub #const_fn new() -> Self {
- __IncompleteArrayField(::#prefix::marker::PhantomData, [])
- }
-
- #[inline]
- pub fn as_ptr(&self) -> *const T {
- self as *const _ as *const T
- }
-
- #[inline]
- pub fn as_mut_ptr(&mut self) -> *mut T {
- self as *mut _ as *mut T
- }
-
- #[inline]
- pub unsafe fn as_slice(&self, len: usize) -> &[T] {
- ::#prefix::slice::from_raw_parts(self.as_ptr(), len)
- }
-
- #[inline]
- pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
- ::#prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
- }
- }
- };
-
- let incomplete_array_debug_impl = quote! {
- impl<T> ::#prefix::fmt::Debug for __IncompleteArrayField<T> {
- fn fmt(&self, fmt: &mut ::#prefix::fmt::Formatter<'_>)
- -> ::#prefix::fmt::Result {
- fmt.write_str("__IncompleteArrayField")
- }
- }
- };
-
- let items = vec![
- incomplete_array_decl,
- incomplete_array_impl,
- incomplete_array_debug_impl,
- ];
-
- let old_items = mem::replace(result, items);
- result.extend(old_items.into_iter());
- }
-
- pub fn prepend_complex_type(result: &mut Vec<proc_macro2::TokenStream>) {
- let complex_type = quote! {
- #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)]
- #[repr(C)]
- pub struct __BindgenComplex<T> {
- pub re: T,
- pub im: T
- }
- };
-
- let items = vec![complex_type];
- let old_items = mem::replace(result, items);
- result.extend(old_items.into_iter());
- }
-
- pub fn build_path(
- item: &Item,
- ctx: &BindgenContext,
- ) -> error::Result<proc_macro2::TokenStream> {
- let path = item.namespace_aware_canonical_path(ctx);
- let tokens =
- proc_macro2::TokenStream::from_str(&path.join("::")).unwrap();
-
- Ok(tokens)
- }
-
- fn primitive_ty(
- ctx: &BindgenContext,
- name: &str,
- ) -> proc_macro2::TokenStream {
- let ident = ctx.rust_ident_raw(name);
- quote! {
- #ident
- }
- }
-
- pub fn type_from_named(
- ctx: &BindgenContext,
- name: &str,
- ) -> Option<proc_macro2::TokenStream> {
- // FIXME: We could use the inner item to check this is really a
- // primitive type but, who the heck overrides these anyway?
- Some(match name {
- "int8_t" => primitive_ty(ctx, "i8"),
- "uint8_t" => primitive_ty(ctx, "u8"),
- "int16_t" => primitive_ty(ctx, "i16"),
- "uint16_t" => primitive_ty(ctx, "u16"),
- "int32_t" => primitive_ty(ctx, "i32"),
- "uint32_t" => primitive_ty(ctx, "u32"),
- "int64_t" => primitive_ty(ctx, "i64"),
- "uint64_t" => primitive_ty(ctx, "u64"),
-
- "size_t" if ctx.options().size_t_is_usize => {
- primitive_ty(ctx, "usize")
- }
- "uintptr_t" => primitive_ty(ctx, "usize"),
-
- "ssize_t" if ctx.options().size_t_is_usize => {
- primitive_ty(ctx, "isize")
- }
- "intptr_t" | "ptrdiff_t" => primitive_ty(ctx, "isize"),
- _ => return None,
- })
- }
-
- pub fn fnsig_return_ty(
- ctx: &BindgenContext,
- sig: &FunctionSig,
- ) -> proc_macro2::TokenStream {
- if sig.is_divergent() {
- return quote! { -> ! };
- }
-
- let return_item = ctx.resolve_item(sig.return_type());
- if let TypeKind::Void = *return_item.kind().expect_type().kind() {
- quote! {}
- } else {
- let ret_ty = return_item.to_rust_ty_or_opaque(ctx, &());
- quote! {
- -> #ret_ty
- }
- }
- }
-
- pub fn fnsig_arguments(
- ctx: &BindgenContext,
- sig: &FunctionSig,
- ) -> Vec<proc_macro2::TokenStream> {
- use super::ToPtr;
-
- let mut unnamed_arguments = 0;
- let mut args = sig
- .argument_types()
- .iter()
- .map(|&(ref name, ty)| {
- let arg_item = ctx.resolve_item(ty);
- let arg_ty = arg_item.kind().expect_type();
-
- // From the C90 standard[1]:
- //
- // A declaration of a parameter as "array of type" shall be
- // adjusted to "qualified pointer to type", where the type
- // qualifiers (if any) are those specified within the [ and ] of
- // the array type derivation.
- //
- // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
- let arg_ty = match *arg_ty.canonical_type(ctx).kind() {
- TypeKind::Array(t, _) => {
- let stream =
- if ctx.options().array_pointers_in_arguments {
- arg_ty.to_rust_ty_or_opaque(ctx, arg_item)
- } else {
- t.to_rust_ty_or_opaque(ctx, &())
- };
- stream.to_ptr(ctx.resolve_type(t).is_const())
- }
- TypeKind::Pointer(inner) => {
- let inner = ctx.resolve_item(inner);
- let inner_ty = inner.expect_type();
- if let TypeKind::ObjCInterface(ref interface) =
- *inner_ty.canonical_type(ctx).kind()
- {
- let name = ctx.rust_ident(interface.name());
- quote! {
- #name
- }
- } else {
- arg_item.to_rust_ty_or_opaque(ctx, &())
- }
- }
- _ => arg_item.to_rust_ty_or_opaque(ctx, &()),
- };
-
- let arg_name = match *name {
- Some(ref name) => ctx.rust_mangle(name).into_owned(),
- None => {
- unnamed_arguments += 1;
- format!("arg{}", unnamed_arguments)
- }
- };
-
- assert!(!arg_name.is_empty());
- let arg_name = ctx.rust_ident(arg_name);
-
- quote! {
- #arg_name : #arg_ty
- }
- })
- .collect::<Vec<_>>();
-
- if sig.is_variadic() {
- args.push(quote! { ... })
- }
-
- args
- }
-
- pub fn fnsig_argument_identifiers(
- ctx: &BindgenContext,
- sig: &FunctionSig,
- ) -> Vec<proc_macro2::TokenStream> {
- let mut unnamed_arguments = 0;
- let args = sig
- .argument_types()
- .iter()
- .map(|&(ref name, _ty)| {
- let arg_name = match *name {
- Some(ref name) => ctx.rust_mangle(name).into_owned(),
- None => {
- unnamed_arguments += 1;
- format!("arg{}", unnamed_arguments)
- }
- };
-
- assert!(!arg_name.is_empty());
- let arg_name = ctx.rust_ident(arg_name);
-
- quote! {
- #arg_name
- }
- })
- .collect::<Vec<_>>();
-
- args
- }
-
- pub fn fnsig_block(
- ctx: &BindgenContext,
- sig: &FunctionSig,
- ) -> proc_macro2::TokenStream {
- let args = sig.argument_types().iter().map(|&(_, ty)| {
- let arg_item = ctx.resolve_item(ty);
-
- arg_item.to_rust_ty_or_opaque(ctx, &())
- });
-
- let return_item = ctx.resolve_item(sig.return_type());
- let ret_ty =
- if let TypeKind::Void = *return_item.kind().expect_type().kind() {
- quote! { () }
- } else {
- return_item.to_rust_ty_or_opaque(ctx, &())
- };
-
- quote! {
- *const ::block::Block<(#(#args,)*), #ret_ty>
- }
- }
-
- // Returns true if `canonical_name` will end up as `mangled_name` at the
- // machine code level, i.e. after LLVM has applied any target specific
- // mangling.
- pub fn names_will_be_identical_after_mangling(
- canonical_name: &str,
- mangled_name: &str,
- call_conv: Option<Abi>,
- ) -> bool {
- // If the mangled name and the canonical name are the same then no
- // mangling can have happened between the two versions.
- if canonical_name == mangled_name {
- return true;
- }
-
- // Working with &[u8] makes indexing simpler than with &str
- let canonical_name = canonical_name.as_bytes();
- let mangled_name = mangled_name.as_bytes();
-
- let (mangling_prefix, expect_suffix) = match call_conv {
- Some(Abi::C) |
- // None is the case for global variables
- None => {
- (b'_', false)
- }
- Some(Abi::Stdcall) => (b'_', true),
- Some(Abi::Fastcall) => (b'@', true),
-
- // This is something we don't recognize, stay on the safe side
- // by emitting the `#[link_name]` attribute
- Some(_) => return false,
- };
-
- // Check that the mangled name is long enough to at least contain the
- // canonical name plus the expected prefix.
- if mangled_name.len() < canonical_name.len() + 1 {
- return false;
- }
-
- // Return if the mangled name does not start with the prefix expected
- // for the given calling convention.
- if mangled_name[0] != mangling_prefix {
- return false;
- }
-
- // Check that the mangled name contains the canonical name after the
- // prefix
- if &mangled_name[1..canonical_name.len() + 1] != canonical_name {
- return false;
- }
-
- // If the given calling convention also prescribes a suffix, check that
- // it exists too
- if expect_suffix {
- let suffix = &mangled_name[canonical_name.len() + 1..];
-
- // The shortest suffix is "@0"
- if suffix.len() < 2 {
- return false;
- }
-
- // Check that the suffix starts with '@' and is all ASCII decimals
- // after that.
- if suffix[0] != b'@' || !suffix[1..].iter().all(u8::is_ascii_digit)
- {
- return false;
- }
- } else if mangled_name.len() != canonical_name.len() + 1 {
- // If we don't expect a prefix but there is one, we need the
- // #[link_name] attribute
- return false;
- }
-
- true
- }
-}
diff --git a/src/codegen/postprocessing/merge_extern_blocks.rs b/src/codegen/postprocessing/merge_extern_blocks.rs
deleted file mode 100644
index 2b761494..00000000
--- a/src/codegen/postprocessing/merge_extern_blocks.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-use syn::{Item, ItemForeignMod};
-
-pub(super) fn merge_extern_blocks(items: &mut Vec<Item>) {
- // Keep all the extern blocks in a different `Vec` for faster search.
- let mut foreign_mods = Vec::<ItemForeignMod>::new();
-
- for item in std::mem::take(items) {
- match item {
- Item::ForeignMod(ItemForeignMod {
- attrs,
- abi,
- brace_token,
- items: foreign_items,
- }) => {
- let mut exists = false;
- for foreign_mod in &mut foreign_mods {
- // Check if there is a extern block with the same ABI and
- // attributes.
- if foreign_mod.attrs == attrs && foreign_mod.abi == abi {
- // Merge the items of the two blocks.
- foreign_mod.items.extend_from_slice(&foreign_items);
- exists = true;
- break;
- }
- }
- // If no existing extern block had the same ABI and attributes, store
- // it.
- if !exists {
- foreign_mods.push(ItemForeignMod {
- attrs,
- abi,
- brace_token,
- items: foreign_items,
- });
- }
- }
- // If the item is not an extern block, we don't have to do anything.
- _ => items.push(item),
- }
- }
-
- // Move all the extern blocks alongside the rest of the items.
- for foreign_mod in foreign_mods {
- items.push(Item::ForeignMod(foreign_mod));
- }
-}
diff --git a/src/codegen/postprocessing/mod.rs b/src/codegen/postprocessing/mod.rs
deleted file mode 100644
index c6612f2b..00000000
--- a/src/codegen/postprocessing/mod.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use proc_macro2::TokenStream;
-use quote::ToTokens;
-use syn::Item;
-
-use crate::BindgenOptions;
-
-mod merge_extern_blocks;
-mod sort_semantically;
-
-use merge_extern_blocks::merge_extern_blocks;
-use sort_semantically::sort_semantically;
-
-struct PostProcessingPass {
- should_run: fn(&BindgenOptions) -> bool,
- run: fn(&mut Vec<Item>),
-}
-
-// TODO: This can be a const fn when mutable references are allowed in const
-// context.
-macro_rules! pass {
- ($pass:ident) => {
- PostProcessingPass {
- should_run: |options| options.$pass,
- run: |items| $pass(items),
- }
- };
-}
-
-const PASSES: &[PostProcessingPass] =
- &[pass!(merge_extern_blocks), pass!(sort_semantically)];
-
-pub(crate) fn postprocessing(
- items: Vec<TokenStream>,
- options: &BindgenOptions,
-) -> TokenStream {
- let require_syn = PASSES.iter().any(|pass| (pass.should_run)(options));
- if !require_syn {
- return items.into_iter().collect();
- }
- let module_wrapped_tokens =
- quote!(mod wrapper_for_sorting_hack { #( #items )* });
-
- // This syn business is a hack, for now. This means that we are re-parsing already
- // generated code using `syn` (as opposed to `quote`) because `syn` provides us more
- // control over the elements.
- // One caveat is that some of the items coming from `quote`d output might have
- // multiple items within them. Hence, we have to wrap the incoming in a `mod`.
- // The two `unwrap`s here are deliberate because
- // The first one won't panic because we build the `mod` and know it is there
- // The second one won't panic because we know original output has something in
- // it already.
- let (_, mut items) = syn::parse2::<syn::ItemMod>(module_wrapped_tokens)
- .unwrap()
- .content
- .unwrap();
-
- for pass in PASSES {
- if (pass.should_run)(options) {
- (pass.run)(&mut items);
- }
- }
-
- let synful_items = items.into_iter().map(|item| item.into_token_stream());
-
- quote! { #( #synful_items )* }
-}
diff --git a/src/codegen/postprocessing/sort_semantically.rs b/src/codegen/postprocessing/sort_semantically.rs
deleted file mode 100644
index 96596cb0..00000000
--- a/src/codegen/postprocessing/sort_semantically.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-use syn::Item;
-
-pub(super) fn sort_semantically(items: &mut [Item]) {
- items.sort_by_key(|item| match item {
- Item::Type(_) => 0,
- Item::Struct(_) => 1,
- Item::Const(_) => 2,
- Item::Fn(_) => 3,
- Item::Enum(_) => 4,
- Item::Union(_) => 5,
- Item::Static(_) => 6,
- Item::Trait(_) => 7,
- Item::TraitAlias(_) => 8,
- Item::Impl(_) => 9,
- Item::Mod(_) => 10,
- Item::Use(_) => 11,
- Item::Verbatim(_) => 12,
- Item::ExternCrate(_) => 13,
- Item::ForeignMod(_) => 14,
- Item::Macro(_) => 15,
- Item::Macro2(_) => 16,
- _ => 18,
- });
-}
diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs
deleted file mode 100644
index ddac1b0a..00000000
--- a/src/codegen/struct_layout.rs
+++ /dev/null
@@ -1,444 +0,0 @@
-//! Helpers for code generation that need struct layout
-
-use super::helpers;
-
-use crate::ir::comp::CompInfo;
-use crate::ir::context::BindgenContext;
-use crate::ir::layout::Layout;
-use crate::ir::ty::{Type, TypeKind};
-use proc_macro2::{self, Ident, Span};
-use std::cmp;
-
-const MAX_GUARANTEED_ALIGN: usize = 8;
-
-/// Trace the layout of struct.
-#[derive(Debug)]
-pub struct StructLayoutTracker<'a> {
- name: &'a str,
- ctx: &'a BindgenContext,
- comp: &'a CompInfo,
- is_packed: bool,
- known_type_layout: Option<Layout>,
- is_rust_union: bool,
- can_copy_union_fields: bool,
- latest_offset: usize,
- padding_count: usize,
- latest_field_layout: Option<Layout>,
- max_field_align: usize,
- last_field_was_bitfield: bool,
-}
-
-/// Returns a size aligned to a given value.
-pub fn align_to(size: usize, align: usize) -> usize {
- if align == 0 {
- return size;
- }
-
- let rem = size % align;
- if rem == 0 {
- return size;
- }
-
- size + align - rem
-}
-
-/// Returns the lower power of two byte count that can hold at most n bits.
-pub fn bytes_from_bits_pow2(mut n: usize) -> usize {
- if n == 0 {
- return 0;
- }
-
- if n <= 8 {
- return 1;
- }
-
- if !n.is_power_of_two() {
- n = n.next_power_of_two();
- }
-
- n / 8
-}
-
-#[test]
-fn test_align_to() {
- assert_eq!(align_to(1, 1), 1);
- assert_eq!(align_to(1, 2), 2);
- assert_eq!(align_to(1, 4), 4);
- assert_eq!(align_to(5, 1), 5);
- assert_eq!(align_to(17, 4), 20);
-}
-
-#[test]
-fn test_bytes_from_bits_pow2() {
- assert_eq!(bytes_from_bits_pow2(0), 0);
- for i in 1..9 {
- assert_eq!(bytes_from_bits_pow2(i), 1);
- }
- for i in 9..17 {
- assert_eq!(bytes_from_bits_pow2(i), 2);
- }
- for i in 17..33 {
- assert_eq!(bytes_from_bits_pow2(i), 4);
- }
-}
-
-impl<'a> StructLayoutTracker<'a> {
- pub fn new(
- ctx: &'a BindgenContext,
- comp: &'a CompInfo,
- ty: &'a Type,
- name: &'a str,
- ) -> Self {
- let known_type_layout = ty.layout(ctx);
- let is_packed = comp.is_packed(ctx, known_type_layout.as_ref());
- let (is_rust_union, can_copy_union_fields) =
- comp.is_rust_union(ctx, known_type_layout.as_ref(), name);
- StructLayoutTracker {
- name,
- ctx,
- comp,
- is_packed,
- known_type_layout,
- is_rust_union,
- can_copy_union_fields,
- latest_offset: 0,
- padding_count: 0,
- latest_field_layout: None,
- max_field_align: 0,
- last_field_was_bitfield: false,
- }
- }
-
- pub fn can_copy_union_fields(&self) -> bool {
- self.can_copy_union_fields
- }
-
- pub fn is_rust_union(&self) -> bool {
- self.is_rust_union
- }
-
- pub fn saw_vtable(&mut self) {
- debug!("saw vtable for {}", self.name);
-
- let ptr_size = self.ctx.target_pointer_size();
- self.latest_offset += ptr_size;
- self.latest_field_layout = Some(Layout::new(ptr_size, ptr_size));
- self.max_field_align = ptr_size;
- }
-
- pub fn saw_base(&mut self, base_ty: &Type) {
- debug!("saw base for {}", self.name);
- if let Some(layout) = base_ty.layout(self.ctx) {
- self.align_to_latest_field(layout);
-
- self.latest_offset += self.padding_bytes(layout) + layout.size;
- self.latest_field_layout = Some(layout);
- self.max_field_align = cmp::max(self.max_field_align, layout.align);
- }
- }
-
- pub fn saw_bitfield_unit(&mut self, layout: Layout) {
- debug!("saw bitfield unit for {}: {:?}", self.name, layout);
-
- self.align_to_latest_field(layout);
-
- self.latest_offset += layout.size;
-
- debug!(
- "Offset: <bitfield>: {} -> {}",
- self.latest_offset - layout.size,
- self.latest_offset
- );
-
- self.latest_field_layout = Some(layout);
- self.last_field_was_bitfield = true;
- // NB: We intentionally don't update the max_field_align here, since our
- // bitfields code doesn't necessarily guarantee it, so we need to
- // actually generate the dummy alignment.
- }
-
- /// Returns a padding field if necessary for a given new field _before_
- /// adding that field.
- pub fn saw_field(
- &mut self,
- field_name: &str,
- field_ty: &Type,
- field_offset: Option<usize>,
- ) -> Option<proc_macro2::TokenStream> {
- let mut field_layout = field_ty.layout(self.ctx)?;
-
- if let TypeKind::Array(inner, len) =
- *field_ty.canonical_type(self.ctx).kind()
- {
- // FIXME(emilio): As an _ultra_ hack, we correct the layout returned
- // by arrays of structs that have a bigger alignment than what we
- // can support.
- //
- // This means that the structs in the array are super-unsafe to
- // access, since they won't be properly aligned, but there's not too
- // much we can do about it.
- if let Some(layout) = self.ctx.resolve_type(inner).layout(self.ctx)
- {
- if layout.align > MAX_GUARANTEED_ALIGN {
- field_layout.size =
- align_to(layout.size, layout.align) * len;
- field_layout.align = MAX_GUARANTEED_ALIGN;
- }
- }
- }
- self.saw_field_with_layout(field_name, field_layout, field_offset)
- }
-
- pub fn saw_field_with_layout(
- &mut self,
- field_name: &str,
- field_layout: Layout,
- field_offset: Option<usize>,
- ) -> Option<proc_macro2::TokenStream> {
- let will_merge_with_bitfield = self.align_to_latest_field(field_layout);
-
- let is_union = self.comp.is_union();
- let padding_bytes = match field_offset {
- Some(offset) if offset / 8 > self.latest_offset => {
- offset / 8 - self.latest_offset
- }
- _ => {
- if will_merge_with_bitfield ||
- field_layout.align == 0 ||
- is_union
- {
- 0
- } else if !self.is_packed {
- self.padding_bytes(field_layout)
- } else if let Some(l) = self.known_type_layout {
- self.padding_bytes(l)
- } else {
- 0
- }
- }
- };
-
- self.latest_offset += padding_bytes;
-
- let padding_layout = if self.is_packed || is_union {
- None
- } else {
- let force_padding = self.ctx.options().force_explicit_padding;
-
- // Otherwise the padding is useless.
- let need_padding = force_padding ||
- padding_bytes >= field_layout.align ||
- field_layout.align > MAX_GUARANTEED_ALIGN;
-
- debug!(
- "Offset: <padding>: {} -> {}",
- self.latest_offset - padding_bytes,
- self.latest_offset
- );
-
- debug!(
- "align field {} to {}/{} with {} padding bytes {:?}",
- field_name,
- self.latest_offset,
- field_offset.unwrap_or(0) / 8,
- padding_bytes,
- field_layout
- );
-
- let padding_align = if force_padding {
- 1
- } else {
- cmp::min(field_layout.align, MAX_GUARANTEED_ALIGN)
- };
-
- if need_padding && padding_bytes != 0 {
- Some(Layout::new(padding_bytes, padding_align))
- } else {
- None
- }
- };
-
- self.latest_offset += field_layout.size;
- self.latest_field_layout = Some(field_layout);
- self.max_field_align =
- cmp::max(self.max_field_align, field_layout.align);
- self.last_field_was_bitfield = false;
-
- debug!(
- "Offset: {}: {} -> {}",
- field_name,
- self.latest_offset - field_layout.size,
- self.latest_offset
- );
-
- padding_layout.map(|layout| self.padding_field(layout))
- }
-
- pub fn add_tail_padding(
- &mut self,
- comp_name: &str,
- comp_layout: Layout,
- ) -> Option<proc_macro2::TokenStream> {
- // Only emit an padding field at the end of a struct if the
- // user configures explicit padding.
- if !self.ctx.options().force_explicit_padding {
- return None;
- }
-
- // Padding doesn't make sense for rust unions.
- if self.is_rust_union {
- return None;
- }
-
- if self.latest_offset == comp_layout.size {
- // This struct does not contain tail padding.
- return None;
- }
-
- trace!(
- "need a tail padding field for {}: offset {} -> size {}",
- comp_name,
- self.latest_offset,
- comp_layout.size
- );
- let size = comp_layout.size - self.latest_offset;
- Some(self.padding_field(Layout::new(size, 0)))
- }
-
- pub fn pad_struct(
- &mut self,
- layout: Layout,
- ) -> Option<proc_macro2::TokenStream> {
- debug!(
- "pad_struct:\n\tself = {:#?}\n\tlayout = {:#?}",
- self, layout
- );
-
- if layout.size < self.latest_offset {
- warn!(
- "Calculated wrong layout for {}, too more {} bytes",
- self.name,
- self.latest_offset - layout.size
- );
- return None;
- }
-
- let padding_bytes = layout.size - self.latest_offset;
- if padding_bytes == 0 {
- return None;
- }
-
- let repr_align = self.ctx.options().rust_features().repr_align;
-
- // We always pad to get to the correct size if the struct is one of
- // those we can't align properly.
- //
- // Note that if the last field we saw was a bitfield, we may need to pad
- // regardless, because bitfields don't respect alignment as strictly as
- // other fields.
- if padding_bytes >= layout.align ||
- (self.last_field_was_bitfield &&
- padding_bytes >= self.latest_field_layout.unwrap().align) ||
- (!repr_align && layout.align > MAX_GUARANTEED_ALIGN)
- {
- let layout = if self.is_packed {
- Layout::new(padding_bytes, 1)
- } else if self.last_field_was_bitfield ||
- layout.align > MAX_GUARANTEED_ALIGN
- {
- // We've already given up on alignment here.
- Layout::for_size(self.ctx, padding_bytes)
- } else {
- Layout::new(padding_bytes, layout.align)
- };
-
- debug!("pad bytes to struct {}, {:?}", self.name, layout);
-
- Some(self.padding_field(layout))
- } else {
- None
- }
- }
-
- pub fn requires_explicit_align(&self, layout: Layout) -> bool {
- let repr_align = self.ctx.options().rust_features().repr_align;
-
- // Always force explicit repr(align) for stuff more than 16-byte aligned
- // to work-around https://github.com/rust-lang/rust/issues/54341.
- //
- // Worst-case this just generates redundant alignment attributes.
- if repr_align && self.max_field_align >= 16 {
- return true;
- }
-
- if self.max_field_align >= layout.align {
- return false;
- }
-
- // We can only generate up-to a 8-bytes of alignment unless we support
- // repr(align).
- repr_align || layout.align <= MAX_GUARANTEED_ALIGN
- }
-
- fn padding_bytes(&self, layout: Layout) -> usize {
- align_to(self.latest_offset, layout.align) - self.latest_offset
- }
-
- fn padding_field(&mut self, layout: Layout) -> proc_macro2::TokenStream {
- let ty = helpers::blob(self.ctx, layout);
- let padding_count = self.padding_count;
-
- self.padding_count += 1;
-
- let padding_field_name = Ident::new(
- &format!("__bindgen_padding_{}", padding_count),
- Span::call_site(),
- );
-
- self.max_field_align = cmp::max(self.max_field_align, layout.align);
-
- quote! {
- pub #padding_field_name : #ty ,
- }
- }
-
- /// Returns whether the new field is known to merge with a bitfield.
- ///
- /// This is just to avoid doing the same check also in pad_field.
- fn align_to_latest_field(&mut self, new_field_layout: Layout) -> bool {
- if self.is_packed {
- // Skip to align fields when packed.
- return false;
- }
-
- let layout = match self.latest_field_layout {
- Some(l) => l,
- None => return false,
- };
-
- // If it was, we may or may not need to align, depending on what the
- // current field alignment and the bitfield size and alignment are.
- debug!(
- "align_to_bitfield? {}: {:?} {:?}",
- self.last_field_was_bitfield, layout, new_field_layout
- );
-
- // Avoid divide-by-zero errors if align is 0.
- let align = cmp::max(1, layout.align);
-
- if self.last_field_was_bitfield &&
- new_field_layout.align <= layout.size % align &&
- new_field_layout.size <= layout.size % align
- {
- // The new field will be coalesced into some of the remaining bits.
- //
- // FIXME(emilio): I think this may not catch everything?
- debug!("Will merge with bitfield");
- return true;
- }
-
- // Else, just align the obvious way.
- self.latest_offset += self.padding_bytes(layout);
- false
- }
-}
diff --git a/src/deps.rs b/src/deps.rs
deleted file mode 100644
index 987225b2..00000000
--- a/src/deps.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-/// Generating build depfiles from parsed bindings.
-use std::{collections::BTreeSet, path::PathBuf};
-
-#[derive(Clone, Debug)]
-pub(crate) struct DepfileSpec {
- pub output_module: String,
- pub depfile_path: PathBuf,
-}
-
-impl DepfileSpec {
- pub fn write(&self, deps: &BTreeSet<String>) -> std::io::Result<()> {
- let mut buf = format!("{}:", self.output_module);
-
- for file in deps {
- buf = format!("{} {}", buf, file);
- }
-
- std::fs::write(&self.depfile_path, &buf)
- }
-}
diff --git a/src/extra_assertions.rs b/src/extra_assertions.rs
deleted file mode 100644
index 0888bf39..00000000
--- a/src/extra_assertions.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-//! Macros for defining extra assertions that should only be checked in testing
-//! and/or CI when the `testing_only_extra_assertions` feature is enabled.
-
-/// Simple macro that forwards to assert! when using
-/// testing_only_extra_assertions.
-#[macro_export]
-macro_rules! extra_assert {
- ( $cond:expr ) => {
- if cfg!(feature = "testing_only_extra_assertions") {
- assert!($cond);
- }
- };
- ( $cond:expr , $( $arg:tt )+ ) => {
- if cfg!(feature = "testing_only_extra_assertions") {
- assert!($cond, $( $arg )* )
- }
- };
-}
-
-/// Simple macro that forwards to assert_eq! when using
-/// testing_only_extra_assertions.
-#[macro_export]
-macro_rules! extra_assert_eq {
- ( $lhs:expr , $rhs:expr ) => {
- if cfg!(feature = "testing_only_extra_assertions") {
- assert_eq!($lhs, $rhs);
- }
- };
- ( $lhs:expr , $rhs:expr , $( $arg:tt )+ ) => {
- if cfg!(feature = "testing_only_extra_assertions") {
- assert!($lhs, $rhs, $( $arg )* );
- }
- };
-}
diff --git a/src/features.rs b/src/features.rs
deleted file mode 100644
index 4f05b9eb..00000000
--- a/src/features.rs
+++ /dev/null
@@ -1,313 +0,0 @@
-//! Contains code for selecting features
-
-#![deny(missing_docs)]
-#![deny(unused_extern_crates)]
-
-use std::io;
-use std::str::FromStr;
-
-/// Define RustTarget struct definition, Default impl, and conversions
-/// between RustTarget and String.
-macro_rules! rust_target_def {
- ( $( $( #[$attr:meta] )* => $release:ident => $value:expr; )* ) => {
- /// Represents the version of the Rust language to target.
- ///
- /// To support a beta release, use the corresponding stable release.
- ///
- /// This enum will have more variants added as necessary.
- #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Hash)]
- #[allow(non_camel_case_types)]
- pub enum RustTarget {
- $(
- $(
- #[$attr]
- )*
- $release,
- )*
- }
-
- impl Default for RustTarget {
- /// Gives the latest stable Rust version
- fn default() -> RustTarget {
- LATEST_STABLE_RUST
- }
- }
-
- impl FromStr for RustTarget {
- type Err = io::Error;
-
- /// Create a `RustTarget` from a string.
- ///
- /// * The stable/beta versions of Rust are of the form "1.0",
- /// "1.19", etc.
- /// * The nightly version should be specified with "nightly".
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s.as_ref() {
- $(
- stringify!($value) => Ok(RustTarget::$release),
- )*
- _ => Err(
- io::Error::new(
- io::ErrorKind::InvalidInput,
- concat!(
- "Got an invalid rust target. Accepted values ",
- "are of the form ",
- "\"1.0\" or \"nightly\"."))),
- }
- }
- }
-
- impl From<RustTarget> for String {
- fn from(target: RustTarget) -> Self {
- match target {
- $(
- RustTarget::$release => stringify!($value),
- )*
- }.into()
- }
- }
- }
-}
-
-/// Defines an array slice with all RustTarget values
-macro_rules! rust_target_values_def {
- ( $( $( #[$attr:meta] )* => $release:ident => $value:expr; )* ) => {
- /// Strings of allowed `RustTarget` values
- pub static RUST_TARGET_STRINGS: &'static [&str] = &[
- $(
- stringify!($value),
- )*
- ];
- }
-}
-
-/// Defines macro which takes a macro
-macro_rules! rust_target_base {
- ( $x_macro:ident ) => {
- $x_macro!(
- /// Rust stable 1.0
- => Stable_1_0 => 1.0;
- /// Rust stable 1.17
- /// * Static lifetime elision ([RFC 1623](https://github.com/rust-lang/rfcs/blob/master/text/1623-static.md))
- => Stable_1_17 => 1.17;
- /// Rust stable 1.19
- /// * Untagged unions ([RFC 1444](https://github.com/rust-lang/rfcs/blob/master/text/1444-union.md))
- => Stable_1_19 => 1.19;
- /// Rust stable 1.20
- /// * Associated constants ([PR](https://github.com/rust-lang/rust/pull/42809))
- => Stable_1_20 => 1.20;
- /// Rust stable 1.21
- /// * Builtin impls for `Clone` ([PR](https://github.com/rust-lang/rust/pull/43690))
- => Stable_1_21 => 1.21;
- /// Rust stable 1.25
- /// * `repr(align)` ([PR](https://github.com/rust-lang/rust/pull/47006))
- => Stable_1_25 => 1.25;
- /// Rust stable 1.26
- /// * [i128 / u128 support](https://doc.rust-lang.org/std/primitive.i128.html)
- => Stable_1_26 => 1.26;
- /// Rust stable 1.27
- /// * `must_use` attribute on functions ([PR](https://github.com/rust-lang/rust/pull/48925))
- => Stable_1_27 => 1.27;
- /// Rust stable 1.28
- /// * `repr(transparent)` ([PR](https://github.com/rust-lang/rust/pull/51562))
- => Stable_1_28 => 1.28;
- /// Rust stable 1.30
- /// * `const fn` support for limited cases ([PR](https://github.com/rust-lang/rust/pull/54835/)
- /// * [c_void available in core](https://doc.rust-lang.org/core/ffi/enum.c_void.html)
- => Stable_1_30 => 1.30;
- /// Rust stable 1.33
- /// * repr(packed(N)) ([PR](https://github.com/rust-lang/rust/pull/57049))
- => Stable_1_33 => 1.33;
- /// Rust stable 1.36
- /// * `MaybeUninit` instead of `mem::uninitialized()` ([PR](https://github.com/rust-lang/rust/pull/60445))
- => Stable_1_36 => 1.36;
- /// Rust stable 1.40
- /// * `non_exhaustive` enums/structs ([Tracking issue](https://github.com/rust-lang/rust/issues/44109))
- => Stable_1_40 => 1.40;
- /// Rust stable 1.47
- /// * `larger_arrays` ([Tracking issue](https://github.com/rust-lang/rust/pull/74060))
- => Stable_1_47 => 1.47;
- /// Rust stable 1.64
- /// * `core_ffi_c` ([Tracking issue](https://github.com/rust-lang/rust/issues/94501))
- => Stable_1_64 => 1.64;
- /// Nightly rust
- /// * `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202))
- /// * `vectorcall` calling convention (no tracking issue)
- => Nightly => nightly;
- );
- }
-}
-
-rust_target_base!(rust_target_def);
-rust_target_base!(rust_target_values_def);
-
-/// Latest stable release of Rust
-pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_64;
-
-/// Create RustFeatures struct definition, new(), and a getter for each field
-macro_rules! rust_feature_def {
- (
- $( $rust_target:ident {
- $( $( #[$attr:meta] )* => $feature:ident; )*
- } )*
- ) => {
- /// Features supported by a rust target
- #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
- #[allow(missing_docs)] // Documentation should go into the relevant variants.
- pub(crate) struct RustFeatures {
- $( $(
- $(
- #[$attr]
- )*
- pub $feature: bool,
- )* )*
- }
-
- impl RustFeatures {
- /// Gives a RustFeatures struct with all features disabled
- fn new() -> Self {
- RustFeatures {
- $( $(
- $feature: false,
- )* )*
- }
- }
- }
-
- impl From<RustTarget> for RustFeatures {
- fn from(rust_target: RustTarget) -> Self {
- let mut features = RustFeatures::new();
-
- $(
- if rust_target >= RustTarget::$rust_target {
- $(
- features.$feature = true;
- )*
- }
- )*
-
- features
- }
- }
- }
-}
-
-// NOTE(emilio): When adding or removing features here, make sure to update the
-// documentation for the relevant variant in the rust_target_base macro
-// definition.
-rust_feature_def!(
- Stable_1_17 {
- => static_lifetime_elision;
- }
- Stable_1_19 {
- => untagged_union;
- }
- Stable_1_20 {
- => associated_const;
- }
- Stable_1_21 {
- => builtin_clone_impls;
- }
- Stable_1_25 {
- => repr_align;
- }
- Stable_1_26 {
- => i128_and_u128;
- }
- Stable_1_27 {
- => must_use_function;
- }
- Stable_1_28 {
- => repr_transparent;
- }
- Stable_1_30 {
- => min_const_fn;
- => core_ffi_c_void;
- }
- Stable_1_33 {
- => repr_packed_n;
- }
- Stable_1_36 {
- => maybe_uninit;
- }
- Stable_1_40 {
- => non_exhaustive;
- }
- Stable_1_47 {
- => larger_arrays;
- }
- Stable_1_64 {
- => core_ffi_c;
- }
- Nightly {
- => thiscall_abi;
- => vectorcall_abi;
- }
-);
-
-impl Default for RustFeatures {
- fn default() -> Self {
- let default_rust_target: RustTarget = Default::default();
- Self::from(default_rust_target)
- }
-}
-
-#[cfg(test)]
-mod test {
- #![allow(unused_imports)]
- use super::*;
-
- #[test]
- fn target_features() {
- let f_1_0 = RustFeatures::from(RustTarget::Stable_1_0);
- assert!(
- !f_1_0.static_lifetime_elision &&
- !f_1_0.core_ffi_c_void &&
- !f_1_0.untagged_union &&
- !f_1_0.associated_const &&
- !f_1_0.builtin_clone_impls &&
- !f_1_0.repr_align &&
- !f_1_0.thiscall_abi &&
- !f_1_0.vectorcall_abi
- );
- let f_1_21 = RustFeatures::from(RustTarget::Stable_1_21);
- assert!(
- f_1_21.static_lifetime_elision &&
- !f_1_21.core_ffi_c_void &&
- f_1_21.untagged_union &&
- f_1_21.associated_const &&
- f_1_21.builtin_clone_impls &&
- !f_1_21.repr_align &&
- !f_1_21.thiscall_abi &&
- !f_1_21.vectorcall_abi
- );
- let f_nightly = RustFeatures::from(RustTarget::Nightly);
- assert!(
- f_nightly.static_lifetime_elision &&
- f_nightly.core_ffi_c_void &&
- f_nightly.untagged_union &&
- f_nightly.associated_const &&
- f_nightly.builtin_clone_impls &&
- f_nightly.maybe_uninit &&
- f_nightly.repr_align &&
- f_nightly.thiscall_abi &&
- f_nightly.vectorcall_abi
- );
- }
-
- fn test_target(target_str: &str, target: RustTarget) {
- let target_string: String = target.into();
- assert_eq!(target_str, target_string);
- assert_eq!(target, RustTarget::from_str(target_str).unwrap());
- }
-
- #[test]
- fn str_to_target() {
- test_target("1.0", RustTarget::Stable_1_0);
- test_target("1.17", RustTarget::Stable_1_17);
- test_target("1.19", RustTarget::Stable_1_19);
- test_target("1.21", RustTarget::Stable_1_21);
- test_target("1.25", RustTarget::Stable_1_25);
- test_target("nightly", RustTarget::Nightly);
- }
-}
diff --git a/src/ir/analysis/derive.rs b/src/ir/analysis/derive.rs
deleted file mode 100644
index d888cd55..00000000
--- a/src/ir/analysis/derive.rs
+++ /dev/null
@@ -1,732 +0,0 @@
-//! 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()
-}
diff --git a/src/ir/analysis/has_destructor.rs b/src/ir/analysis/has_destructor.rs
deleted file mode 100644
index 74fd73d1..00000000
--- a/src/ir/analysis/has_destructor.rs
+++ /dev/null
@@ -1,176 +0,0 @@
-//! Determining which types have destructors
-
-use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
-use crate::ir::comp::{CompKind, Field, FieldMethods};
-use crate::ir::context::{BindgenContext, ItemId};
-use crate::ir::traversal::EdgeKind;
-use crate::ir::ty::TypeKind;
-use crate::{HashMap, HashSet};
-
-/// An analysis that finds for each IR item whether it has a destructor or not
-///
-/// We use the monotone function `has destructor`, defined as follows:
-///
-/// * If T is a type alias, a templated alias, or an indirection to another type,
-/// T has a destructor if the type T refers to has a destructor.
-/// * If T is a compound type, T has a destructor if we saw a destructor when parsing it,
-/// or if it's a struct, T has a destructor if any of its base members has a destructor,
-/// or if any of its fields have a destructor.
-/// * If T is an instantiation of an abstract template definition, T has
-/// a destructor if its template definition has a destructor,
-/// or if any of the template arguments has a destructor.
-/// * If T is the type of a field, that field has a destructor if it's not a bitfield,
-/// and if T has a destructor.
-#[derive(Debug, Clone)]
-pub struct HasDestructorAnalysis<'ctx> {
- ctx: &'ctx BindgenContext,
-
- // The incremental result of this analysis's computation. Everything in this
- // set definitely has a destructor.
- have_destructor: HashSet<ItemId>,
-
- // Dependencies saying that if a key ItemId has been inserted into the
- // `have_destructor` 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
- // has a destructor or not.
- dependencies: HashMap<ItemId, Vec<ItemId>>,
-}
-
-impl<'ctx> HasDestructorAnalysis<'ctx> {
- fn consider_edge(kind: EdgeKind) -> bool {
- // These are the only edges that can affect whether a type has a
- // destructor or not.
- matches!(
- kind,
- EdgeKind::TypeReference |
- EdgeKind::BaseMember |
- EdgeKind::Field |
- EdgeKind::TemplateArgument |
- EdgeKind::TemplateDeclaration
- )
- }
-
- fn insert<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
- let id = id.into();
- let was_not_already_in_set = self.have_destructor.insert(id);
- assert!(
- was_not_already_in_set,
- "We shouldn't try and insert {:?} twice because if it was \
- already in the set, `constrain` should have exited early.",
- id
- );
- ConstrainResult::Changed
- }
-}
-
-impl<'ctx> MonotoneFramework for HasDestructorAnalysis<'ctx> {
- type Node = ItemId;
- type Extra = &'ctx BindgenContext;
- type Output = HashSet<ItemId>;
-
- fn new(ctx: &'ctx BindgenContext) -> Self {
- let have_destructor = HashSet::default();
- let dependencies = generate_dependencies(ctx, Self::consider_edge);
-
- HasDestructorAnalysis {
- ctx,
- have_destructor,
- dependencies,
- }
- }
-
- fn initial_worklist(&self) -> Vec<ItemId> {
- self.ctx.allowlisted_items().iter().cloned().collect()
- }
-
- fn constrain(&mut self, id: ItemId) -> ConstrainResult {
- if self.have_destructor.contains(&id) {
- // We've already computed that this type has a destructor and that can't
- // change.
- return ConstrainResult::Same;
- }
-
- let item = self.ctx.resolve_item(id);
- let ty = match item.as_type() {
- None => return ConstrainResult::Same,
- Some(ty) => ty,
- };
-
- match *ty.kind() {
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::ResolvedTypeRef(t) => {
- if self.have_destructor.contains(&t.into()) {
- self.insert(id)
- } else {
- ConstrainResult::Same
- }
- }
-
- TypeKind::Comp(ref info) => {
- if info.has_own_destructor() {
- return self.insert(id);
- }
-
- match info.kind() {
- CompKind::Union => ConstrainResult::Same,
- CompKind::Struct => {
- let base_or_field_destructor =
- info.base_members().iter().any(|base| {
- self.have_destructor.contains(&base.ty.into())
- }) || info.fields().iter().any(
- |field| match *field {
- Field::DataMember(ref data) => self
- .have_destructor
- .contains(&data.ty().into()),
- Field::Bitfields(_) => false,
- },
- );
- if base_or_field_destructor {
- self.insert(id)
- } else {
- ConstrainResult::Same
- }
- }
- }
- }
-
- TypeKind::TemplateInstantiation(ref inst) => {
- let definition_or_arg_destructor = self
- .have_destructor
- .contains(&inst.template_definition().into()) ||
- inst.template_arguments().iter().any(|arg| {
- self.have_destructor.contains(&arg.into())
- });
- if definition_or_arg_destructor {
- self.insert(id)
- } else {
- ConstrainResult::Same
- }
- }
-
- _ => ConstrainResult::Same,
- }
- }
-
- 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<HasDestructorAnalysis<'ctx>> for HashSet<ItemId> {
- fn from(analysis: HasDestructorAnalysis<'ctx>) -> Self {
- analysis.have_destructor
- }
-}
diff --git a/src/ir/analysis/has_float.rs b/src/ir/analysis/has_float.rs
deleted file mode 100644
index bbf2126f..00000000
--- a/src/ir/analysis/has_float.rs
+++ /dev/null
@@ -1,252 +0,0 @@
-//! Determining which types has float.
-
-use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
-use crate::ir::comp::Field;
-use crate::ir::comp::FieldMethods;
-use crate::ir::context::{BindgenContext, ItemId};
-use crate::ir::traversal::EdgeKind;
-use crate::ir::ty::TypeKind;
-use crate::{HashMap, HashSet};
-
-/// An analysis that finds for each IR item whether it has float or not.
-///
-/// We use the monotone constraint function `has_float`,
-/// defined as follows:
-///
-/// * If T is float or complex float, T trivially has.
-/// * If T is a type alias, a templated alias or an indirection to another type,
-/// it has float if the type T refers to has.
-/// * If T is a compound type, it has float if any of base memter or field
-/// has.
-/// * If T is an instantiation of an abstract template definition, T has
-/// float if any of the template arguments or template definition
-/// has.
-#[derive(Debug, Clone)]
-pub struct HasFloat<'ctx> {
- ctx: &'ctx BindgenContext,
-
- // The incremental result of this analysis's computation. Everything in this
- // set has float.
- has_float: HashSet<ItemId>,
-
- // Dependencies saying that if a key ItemId has been inserted into the
- // `has_float` 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
- // has float or not.
- dependencies: HashMap<ItemId, Vec<ItemId>>,
-}
-
-impl<'ctx> HasFloat<'ctx> {
- fn consider_edge(kind: EdgeKind) -> bool {
- match kind {
- 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 => false,
- EdgeKind::Generic => false,
- }
- }
-
- fn insert<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
- let id = id.into();
- trace!("inserting {:?} into the has_float set", id);
-
- let was_not_already_in_set = self.has_float.insert(id);
- assert!(
- was_not_already_in_set,
- "We shouldn't try and insert {:?} twice because if it was \
- already in the set, `constrain` should have exited early.",
- id
- );
-
- ConstrainResult::Changed
- }
-}
-
-impl<'ctx> MonotoneFramework for HasFloat<'ctx> {
- type Node = ItemId;
- type Extra = &'ctx BindgenContext;
- type Output = HashSet<ItemId>;
-
- fn new(ctx: &'ctx BindgenContext) -> HasFloat<'ctx> {
- let has_float = HashSet::default();
- let dependencies = generate_dependencies(ctx, Self::consider_edge);
-
- HasFloat {
- ctx,
- has_float,
- dependencies,
- }
- }
-
- fn initial_worklist(&self) -> Vec<ItemId> {
- self.ctx.allowlisted_items().iter().cloned().collect()
- }
-
- fn constrain(&mut self, id: ItemId) -> ConstrainResult {
- trace!("constrain: {:?}", id);
-
- if self.has_float.contains(&id) {
- trace!(" already know it do not have float");
- return ConstrainResult::Same;
- }
-
- let item = self.ctx.resolve_item(id);
- let ty = match item.as_type() {
- Some(ty) => ty,
- None => {
- trace!(" not a type; ignoring");
- return ConstrainResult::Same;
- }
- };
-
- match *ty.kind() {
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Int(..) |
- TypeKind::Function(..) |
- TypeKind::Enum(..) |
- TypeKind::Reference(..) |
- TypeKind::TypeParam |
- TypeKind::Opaque |
- TypeKind::Pointer(..) |
- TypeKind::UnresolvedTypeRef(..) |
- TypeKind::ObjCInterface(..) |
- TypeKind::ObjCId |
- TypeKind::ObjCSel => {
- trace!(" simple type that do not have float");
- ConstrainResult::Same
- }
-
- TypeKind::Float(..) | TypeKind::Complex(..) => {
- trace!(" float type has float");
- self.insert(id)
- }
-
- TypeKind::Array(t, _) => {
- if self.has_float.contains(&t.into()) {
- trace!(
- " Array with type T that has float also has float"
- );
- return self.insert(id);
- }
- trace!(" Array with type T that do not have float also do not have float");
- ConstrainResult::Same
- }
- TypeKind::Vector(t, _) => {
- if self.has_float.contains(&t.into()) {
- trace!(
- " Vector with type T that has float also has float"
- );
- return self.insert(id);
- }
- trace!(" Vector with type T that do not have float also do not have float");
- ConstrainResult::Same
- }
-
- TypeKind::ResolvedTypeRef(t) |
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::BlockPointer(t) => {
- if self.has_float.contains(&t.into()) {
- trace!(
- " aliases and type refs to T which have float \
- also have float"
- );
- self.insert(id)
- } else {
- trace!(" aliases and type refs to T which do not have float \
- also do not have floaarrayt");
- ConstrainResult::Same
- }
- }
-
- TypeKind::Comp(ref info) => {
- let bases_have = info
- .base_members()
- .iter()
- .any(|base| self.has_float.contains(&base.ty.into()));
- if bases_have {
- trace!(" bases have float, so we also have");
- return self.insert(id);
- }
- let fields_have = info.fields().iter().any(|f| match *f {
- Field::DataMember(ref data) => {
- self.has_float.contains(&data.ty().into())
- }
- Field::Bitfields(ref bfu) => bfu
- .bitfields()
- .iter()
- .any(|b| self.has_float.contains(&b.ty().into())),
- });
- if fields_have {
- trace!(" fields have float, so we also have");
- return self.insert(id);
- }
-
- trace!(" comp doesn't have float");
- ConstrainResult::Same
- }
-
- TypeKind::TemplateInstantiation(ref template) => {
- let args_have = template
- .template_arguments()
- .iter()
- .any(|arg| self.has_float.contains(&arg.into()));
- if args_have {
- trace!(
- " template args have float, so \
- insantiation also has float"
- );
- return self.insert(id);
- }
-
- let def_has = self
- .has_float
- .contains(&template.template_definition().into());
- if def_has {
- trace!(
- " template definition has float, so \
- insantiation also has"
- );
- return self.insert(id);
- }
-
- trace!(" template instantiation do not have float");
- ConstrainResult::Same
- }
- }
- }
-
- 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<HasFloat<'ctx>> for HashSet<ItemId> {
- fn from(analysis: HasFloat<'ctx>) -> Self {
- analysis.has_float
- }
-}
diff --git a/src/ir/analysis/has_type_param_in_array.rs b/src/ir/analysis/has_type_param_in_array.rs
deleted file mode 100644
index aa523047..00000000
--- a/src/ir/analysis/has_type_param_in_array.rs
+++ /dev/null
@@ -1,252 +0,0 @@
-//! Determining which types has typed parameters in array.
-
-use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
-use crate::ir::comp::Field;
-use crate::ir::comp::FieldMethods;
-use crate::ir::context::{BindgenContext, ItemId};
-use crate::ir::traversal::EdgeKind;
-use crate::ir::ty::TypeKind;
-use crate::{HashMap, HashSet};
-
-/// An analysis that finds for each IR item whether it has array or not.
-///
-/// We use the monotone constraint function `has_type_parameter_in_array`,
-/// defined as follows:
-///
-/// * If T is Array type with type parameter, T trivially has.
-/// * If T is a type alias, a templated alias or an indirection to another type,
-/// it has type parameter in array if the type T refers to has.
-/// * If T is a compound type, it has array if any of base memter or field
-/// has type paramter in array.
-/// * If T is an instantiation of an abstract template definition, T has
-/// type parameter in array if any of the template arguments or template definition
-/// has.
-#[derive(Debug, Clone)]
-pub struct HasTypeParameterInArray<'ctx> {
- ctx: &'ctx BindgenContext,
-
- // The incremental result of this analysis's computation. Everything in this
- // set has array.
- has_type_parameter_in_array: HashSet<ItemId>,
-
- // Dependencies saying that if a key ItemId has been inserted into the
- // `has_type_parameter_in_array` 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
- // has array or not.
- dependencies: HashMap<ItemId, Vec<ItemId>>,
-}
-
-impl<'ctx> HasTypeParameterInArray<'ctx> {
- fn consider_edge(kind: EdgeKind) -> bool {
- match kind {
- // These are the only edges that can affect whether a type has type parameter
- // in array or not.
- 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 => false,
- EdgeKind::Generic => false,
- }
- }
-
- fn insert<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
- let id = id.into();
- trace!(
- "inserting {:?} into the has_type_parameter_in_array set",
- id
- );
-
- let was_not_already_in_set =
- self.has_type_parameter_in_array.insert(id);
- assert!(
- was_not_already_in_set,
- "We shouldn't try and insert {:?} twice because if it was \
- already in the set, `constrain` should have exited early.",
- id
- );
-
- ConstrainResult::Changed
- }
-}
-
-impl<'ctx> MonotoneFramework for HasTypeParameterInArray<'ctx> {
- type Node = ItemId;
- type Extra = &'ctx BindgenContext;
- type Output = HashSet<ItemId>;
-
- fn new(ctx: &'ctx BindgenContext) -> HasTypeParameterInArray<'ctx> {
- let has_type_parameter_in_array = HashSet::default();
- let dependencies = generate_dependencies(ctx, Self::consider_edge);
-
- HasTypeParameterInArray {
- ctx,
- has_type_parameter_in_array,
- dependencies,
- }
- }
-
- fn initial_worklist(&self) -> Vec<ItemId> {
- self.ctx.allowlisted_items().iter().cloned().collect()
- }
-
- fn constrain(&mut self, id: ItemId) -> ConstrainResult {
- trace!("constrain: {:?}", id);
-
- if self.has_type_parameter_in_array.contains(&id) {
- trace!(" already know it do not have array");
- return ConstrainResult::Same;
- }
-
- let item = self.ctx.resolve_item(id);
- let ty = match item.as_type() {
- Some(ty) => ty,
- None => {
- trace!(" not a type; ignoring");
- return ConstrainResult::Same;
- }
- };
-
- match *ty.kind() {
- // Handle the simple cases. These cannot have array in type parameter
- // without further information.
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Int(..) |
- TypeKind::Float(..) |
- TypeKind::Vector(..) |
- TypeKind::Complex(..) |
- TypeKind::Function(..) |
- TypeKind::Enum(..) |
- TypeKind::Reference(..) |
- TypeKind::TypeParam |
- TypeKind::Opaque |
- TypeKind::Pointer(..) |
- TypeKind::UnresolvedTypeRef(..) |
- TypeKind::ObjCInterface(..) |
- TypeKind::ObjCId |
- TypeKind::ObjCSel => {
- trace!(" simple type that do not have array");
- ConstrainResult::Same
- }
-
- TypeKind::Array(t, _) => {
- let inner_ty =
- self.ctx.resolve_type(t).canonical_type(self.ctx);
- match *inner_ty.kind() {
- TypeKind::TypeParam => {
- trace!(" Array with Named type has type parameter");
- self.insert(id)
- }
- _ => {
- trace!(
- " Array without Named type does have type parameter"
- );
- ConstrainResult::Same
- }
- }
- }
-
- TypeKind::ResolvedTypeRef(t) |
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::BlockPointer(t) => {
- if self.has_type_parameter_in_array.contains(&t.into()) {
- trace!(
- " aliases and type refs to T which have array \
- also have array"
- );
- self.insert(id)
- } else {
- trace!(
- " aliases and type refs to T which do not have array \
- also do not have array"
- );
- ConstrainResult::Same
- }
- }
-
- TypeKind::Comp(ref info) => {
- let bases_have = info.base_members().iter().any(|base| {
- self.has_type_parameter_in_array.contains(&base.ty.into())
- });
- if bases_have {
- trace!(" bases have array, so we also have");
- return self.insert(id);
- }
- let fields_have = info.fields().iter().any(|f| match *f {
- Field::DataMember(ref data) => self
- .has_type_parameter_in_array
- .contains(&data.ty().into()),
- Field::Bitfields(..) => false,
- });
- if fields_have {
- trace!(" fields have array, so we also have");
- return self.insert(id);
- }
-
- trace!(" comp doesn't have array");
- ConstrainResult::Same
- }
-
- TypeKind::TemplateInstantiation(ref template) => {
- let args_have =
- template.template_arguments().iter().any(|arg| {
- self.has_type_parameter_in_array.contains(&arg.into())
- });
- if args_have {
- trace!(
- " template args have array, so \
- insantiation also has array"
- );
- return self.insert(id);
- }
-
- let def_has = self
- .has_type_parameter_in_array
- .contains(&template.template_definition().into());
- if def_has {
- trace!(
- " template definition has array, so \
- insantiation also has"
- );
- return self.insert(id);
- }
-
- trace!(" template instantiation do not have array");
- ConstrainResult::Same
- }
- }
- }
-
- 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<HasTypeParameterInArray<'ctx>> for HashSet<ItemId> {
- fn from(analysis: HasTypeParameterInArray<'ctx>) -> Self {
- analysis.has_type_parameter_in_array
- }
-}
diff --git a/src/ir/analysis/has_vtable.rs b/src/ir/analysis/has_vtable.rs
deleted file mode 100644
index 8ac47a65..00000000
--- a/src/ir/analysis/has_vtable.rs
+++ /dev/null
@@ -1,240 +0,0 @@
-//! Determining which types has vtable
-
-use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
-use crate::ir::context::{BindgenContext, ItemId};
-use crate::ir::traversal::EdgeKind;
-use crate::ir::ty::TypeKind;
-use crate::{Entry, HashMap};
-use std::cmp;
-use std::ops;
-
-/// The result of the `HasVtableAnalysis` for an individual item.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-pub enum HasVtableResult {
- /// The item does not have a vtable pointer.
- No,
-
- /// The item has a vtable and the actual vtable pointer is within this item.
- SelfHasVtable,
-
- /// The item has a vtable, but the actual vtable pointer is in a base
- /// member.
- BaseHasVtable,
-}
-
-impl Default for HasVtableResult {
- fn default() -> Self {
- HasVtableResult::No
- }
-}
-
-impl HasVtableResult {
- /// Take the least upper bound of `self` and `rhs`.
- pub fn join(self, rhs: Self) -> Self {
- cmp::max(self, rhs)
- }
-}
-
-impl ops::BitOr for HasVtableResult {
- type Output = Self;
-
- fn bitor(self, rhs: HasVtableResult) -> Self::Output {
- self.join(rhs)
- }
-}
-
-impl ops::BitOrAssign for HasVtableResult {
- fn bitor_assign(&mut self, rhs: HasVtableResult) {
- *self = self.join(rhs)
- }
-}
-
-/// An analysis that finds for each IR item whether it has vtable or not
-///
-/// We use the monotone function `has vtable`, defined as follows:
-///
-/// * If T is a type alias, a templated alias, an indirection to another type,
-/// or a reference of a type, T has vtable if the type T refers to has vtable.
-/// * If T is a compound type, T has vtable if we saw a virtual function when
-/// parsing it or any of its base member has vtable.
-/// * If T is an instantiation of an abstract template definition, T has
-/// vtable if template definition has vtable
-#[derive(Debug, Clone)]
-pub struct HasVtableAnalysis<'ctx> {
- ctx: &'ctx BindgenContext,
-
- // The incremental result of this analysis's computation. Everything in this
- // set definitely has a vtable.
- have_vtable: HashMap<ItemId, HasVtableResult>,
-
- // Dependencies saying that if a key ItemId has been inserted into the
- // `have_vtable` 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
- // has a vtable or not.
- dependencies: HashMap<ItemId, Vec<ItemId>>,
-}
-
-impl<'ctx> HasVtableAnalysis<'ctx> {
- fn consider_edge(kind: EdgeKind) -> bool {
- // These are the only edges that can affect whether a type has a
- // vtable or not.
- matches!(
- kind,
- EdgeKind::TypeReference |
- EdgeKind::BaseMember |
- EdgeKind::TemplateDeclaration
- )
- }
-
- fn insert<Id: Into<ItemId>>(
- &mut self,
- id: Id,
- result: HasVtableResult,
- ) -> ConstrainResult {
- if let HasVtableResult::No = result {
- return ConstrainResult::Same;
- }
-
- let id = id.into();
- match self.have_vtable.entry(id) {
- Entry::Occupied(mut entry) => {
- if *entry.get() < result {
- entry.insert(result);
- ConstrainResult::Changed
- } else {
- ConstrainResult::Same
- }
- }
- Entry::Vacant(entry) => {
- entry.insert(result);
- ConstrainResult::Changed
- }
- }
- }
-
- fn forward<Id1, Id2>(&mut self, from: Id1, to: Id2) -> ConstrainResult
- where
- Id1: Into<ItemId>,
- Id2: Into<ItemId>,
- {
- let from = from.into();
- let to = to.into();
-
- match self.have_vtable.get(&from).cloned() {
- None => ConstrainResult::Same,
- Some(r) => self.insert(to, r),
- }
- }
-}
-
-impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> {
- type Node = ItemId;
- type Extra = &'ctx BindgenContext;
- type Output = HashMap<ItemId, HasVtableResult>;
-
- fn new(ctx: &'ctx BindgenContext) -> HasVtableAnalysis<'ctx> {
- let have_vtable = HashMap::default();
- let dependencies = generate_dependencies(ctx, Self::consider_edge);
-
- HasVtableAnalysis {
- ctx,
- have_vtable,
- dependencies,
- }
- }
-
- fn initial_worklist(&self) -> Vec<ItemId> {
- self.ctx.allowlisted_items().iter().cloned().collect()
- }
-
- fn constrain(&mut self, id: ItemId) -> ConstrainResult {
- trace!("constrain {:?}", id);
-
- let item = self.ctx.resolve_item(id);
- let ty = match item.as_type() {
- None => return ConstrainResult::Same,
- Some(ty) => ty,
- };
-
- // TODO #851: figure out a way to handle deriving from template type parameters.
- match *ty.kind() {
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::ResolvedTypeRef(t) |
- TypeKind::Reference(t) => {
- trace!(
- " aliases and references forward to their inner type"
- );
- self.forward(t, id)
- }
-
- TypeKind::Comp(ref info) => {
- trace!(" comp considers its own methods and bases");
- let mut result = HasVtableResult::No;
-
- if info.has_own_virtual_method() {
- trace!(" comp has its own virtual method");
- result |= HasVtableResult::SelfHasVtable;
- }
-
- let bases_has_vtable = info.base_members().iter().any(|base| {
- trace!(" comp has a base with a vtable: {:?}", base);
- self.have_vtable.contains_key(&base.ty.into())
- });
- if bases_has_vtable {
- result |= HasVtableResult::BaseHasVtable;
- }
-
- self.insert(id, result)
- }
-
- TypeKind::TemplateInstantiation(ref inst) => {
- self.forward(inst.template_definition(), id)
- }
-
- _ => ConstrainResult::Same,
- }
- }
-
- 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<HasVtableAnalysis<'ctx>> for HashMap<ItemId, HasVtableResult> {
- fn from(analysis: HasVtableAnalysis<'ctx>) -> Self {
- // We let the lack of an entry mean "No" to save space.
- extra_assert!(analysis
- .have_vtable
- .values()
- .all(|v| { *v != HasVtableResult::No }));
-
- analysis.have_vtable
- }
-}
-
-/// A convenience trait for the things for which we might wonder if they have a
-/// vtable during codegen.
-///
-/// This is not for _computing_ whether the thing has a vtable, it is for
-/// looking up the results of the HasVtableAnalysis's computations for a
-/// specific thing.
-pub trait HasVtable {
- /// Return `true` if this thing has vtable, `false` otherwise.
- fn has_vtable(&self, ctx: &BindgenContext) -> bool;
-
- /// Return `true` if this thing has an actual vtable pointer in itself, as
- /// opposed to transitively in a base member.
- fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool;
-}
diff --git a/src/ir/analysis/mod.rs b/src/ir/analysis/mod.rs
deleted file mode 100644
index 40dfc6d6..00000000
--- a/src/ir/analysis/mod.rs
+++ /dev/null
@@ -1,402 +0,0 @@
-//! Fix-point analyses on the IR using the "monotone framework".
-//!
-//! A lattice is a set with a partial ordering between elements, where there is
-//! a single least upper bound and a single greatest least bound for every
-//! subset. We are dealing with finite lattices, which means that it has a
-//! finite number of elements, and it follows that there exists a single top and
-//! a single bottom member of the lattice. For example, the power set of a
-//! finite set forms a finite lattice where partial ordering is defined by set
-//! inclusion, that is `a <= b` if `a` is a subset of `b`. Here is the finite
-//! lattice constructed from the set {0,1,2}:
-//!
-//! ```text
-//! .----- Top = {0,1,2} -----.
-//! / | \
-//! / | \
-//! / | \
-//! {0,1} -------. {0,2} .--------- {1,2}
-//! | \ / \ / |
-//! | / \ |
-//! | / \ / \ |
-//! {0} --------' {1} `---------- {2}
-//! \ | /
-//! \ | /
-//! \ | /
-//! `------ Bottom = {} ------'
-//! ```
-//!
-//! A monotone function `f` is a function where if `x <= y`, then it holds that
-//! `f(x) <= f(y)`. It should be clear that running a monotone function to a
-//! fix-point on a finite lattice will always terminate: `f` can only "move"
-//! along the lattice in a single direction, and therefore can only either find
-//! a fix-point in the middle of the lattice or continue to the top or bottom
-//! depending if it is ascending or descending the lattice respectively.
-//!
-//! For a deeper introduction to the general form of this kind of analysis, see
-//! [Static Program Analysis by Anders Møller and Michael I. Schwartzbach][spa].
-//!
-//! [spa]: https://cs.au.dk/~amoeller/spa/spa.pdf
-
-// Re-export individual analyses.
-mod template_params;
-pub use self::template_params::UsedTemplateParameters;
-mod derive;
-pub use self::derive::{as_cannot_derive_set, CannotDerive, DeriveTrait};
-mod has_vtable;
-pub use self::has_vtable::{HasVtable, HasVtableAnalysis, HasVtableResult};
-mod has_destructor;
-pub use self::has_destructor::HasDestructorAnalysis;
-mod has_type_param_in_array;
-pub use self::has_type_param_in_array::HasTypeParameterInArray;
-mod has_float;
-pub use self::has_float::HasFloat;
-mod sizedness;
-pub use self::sizedness::{Sizedness, SizednessAnalysis, SizednessResult};
-
-use crate::ir::context::{BindgenContext, ItemId};
-
-use crate::ir::traversal::{EdgeKind, Trace};
-use crate::HashMap;
-use std::fmt;
-use std::ops;
-
-/// An analysis in the monotone framework.
-///
-/// Implementors of this trait must maintain the following two invariants:
-///
-/// 1. The concrete data must be a member of a finite-height lattice.
-/// 2. The concrete `constrain` method must be monotone: that is,
-/// if `x <= y`, then `constrain(x) <= constrain(y)`.
-///
-/// If these invariants do not hold, iteration to a fix-point might never
-/// complete.
-///
-/// For a simple example analysis, see the `ReachableFrom` type in the `tests`
-/// module below.
-pub trait MonotoneFramework: Sized + fmt::Debug {
- /// The type of node in our dependency graph.
- ///
- /// This is just generic (and not `ItemId`) so that we can easily unit test
- /// without constructing real `Item`s and their `ItemId`s.
- type Node: Copy;
-
- /// Any extra data that is needed during computation.
- ///
- /// Again, this is just generic (and not `&BindgenContext`) so that we can
- /// easily unit test without constructing real `BindgenContext`s full of
- /// real `Item`s and real `ItemId`s.
- type Extra: Sized;
-
- /// The final output of this analysis. Once we have reached a fix-point, we
- /// convert `self` into this type, and return it as the final result of the
- /// analysis.
- type Output: From<Self> + fmt::Debug;
-
- /// Construct a new instance of this analysis.
- fn new(extra: Self::Extra) -> Self;
-
- /// Get the initial set of nodes from which to start the analysis. Unless
- /// you are sure of some domain-specific knowledge, this should be the
- /// complete set of nodes.
- fn initial_worklist(&self) -> Vec<Self::Node>;
-
- /// Update the analysis for the given node.
- ///
- /// If this results in changing our internal state (ie, we discovered that
- /// we have not reached a fix-point and iteration should continue), return
- /// `ConstrainResult::Changed`. Otherwise, return `ConstrainResult::Same`.
- /// When `constrain` returns `ConstrainResult::Same` for all nodes in the
- /// set, we have reached a fix-point and the analysis is complete.
- fn constrain(&mut self, node: Self::Node) -> ConstrainResult;
-
- /// For each node `d` that depends on the given `node`'s current answer when
- /// running `constrain(d)`, call `f(d)`. This informs us which new nodes to
- /// queue up in the worklist when `constrain(node)` reports updated
- /// information.
- fn each_depending_on<F>(&self, node: Self::Node, f: F)
- where
- F: FnMut(Self::Node);
-}
-
-/// Whether an analysis's `constrain` function modified the incremental results
-/// or not.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum ConstrainResult {
- /// The incremental results were updated, and the fix-point computation
- /// should continue.
- Changed,
-
- /// The incremental results were not updated.
- Same,
-}
-
-impl Default for ConstrainResult {
- fn default() -> Self {
- ConstrainResult::Same
- }
-}
-
-impl ops::BitOr for ConstrainResult {
- type Output = Self;
-
- fn bitor(self, rhs: ConstrainResult) -> Self::Output {
- if self == ConstrainResult::Changed || rhs == ConstrainResult::Changed {
- ConstrainResult::Changed
- } else {
- ConstrainResult::Same
- }
- }
-}
-
-impl ops::BitOrAssign for ConstrainResult {
- fn bitor_assign(&mut self, rhs: ConstrainResult) {
- *self = *self | rhs;
- }
-}
-
-/// Run an analysis in the monotone framework.
-pub fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output
-where
- Analysis: MonotoneFramework,
-{
- let mut analysis = Analysis::new(extra);
- let mut worklist = analysis.initial_worklist();
-
- while let Some(node) = worklist.pop() {
- if let ConstrainResult::Changed = analysis.constrain(node) {
- analysis.each_depending_on(node, |needs_work| {
- worklist.push(needs_work);
- });
- }
- }
-
- analysis.into()
-}
-
-/// Generate the dependency map for analysis
-pub fn generate_dependencies<F>(
- ctx: &BindgenContext,
- consider_edge: F,
-) -> HashMap<ItemId, Vec<ItemId>>
-where
- F: Fn(EdgeKind) -> bool,
-{
- let mut dependencies = HashMap::default();
-
- for &item in ctx.allowlisted_items() {
- dependencies.entry(item).or_insert_with(Vec::new);
-
- {
- // We reverse our natural IR graph edges to find dependencies
- // between nodes.
- item.trace(
- ctx,
- &mut |sub_item: ItemId, edge_kind| {
- if ctx.allowlisted_items().contains(&sub_item) &&
- consider_edge(edge_kind)
- {
- dependencies
- .entry(sub_item)
- .or_insert_with(Vec::new)
- .push(item);
- }
- },
- &(),
- );
- }
- }
- dependencies
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::{HashMap, HashSet};
-
- // Here we find the set of nodes that are reachable from any given
- // node. This is a lattice mapping nodes to subsets of all nodes. Our join
- // function is set union.
- //
- // This is our test graph:
- //
- // +---+ +---+
- // | | | |
- // | 1 | .----| 2 |
- // | | | | |
- // +---+ | +---+
- // | | ^
- // | | |
- // | +---+ '------'
- // '----->| |
- // | 3 |
- // .------| |------.
- // | +---+ |
- // | ^ |
- // v | v
- // +---+ | +---+ +---+
- // | | | | | | |
- // | 4 | | | 5 |--->| 6 |
- // | | | | | | |
- // +---+ | +---+ +---+
- // | | | |
- // | | | v
- // | +---+ | +---+
- // | | | | | |
- // '----->| 7 |<-----' | 8 |
- // | | | |
- // +---+ +---+
- //
- // And here is the mapping from a node to the set of nodes that are
- // reachable from it within the test graph:
- //
- // 1: {3,4,5,6,7,8}
- // 2: {2}
- // 3: {3,4,5,6,7,8}
- // 4: {3,4,5,6,7,8}
- // 5: {3,4,5,6,7,8}
- // 6: {8}
- // 7: {3,4,5,6,7,8}
- // 8: {}
-
- #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
- struct Node(usize);
-
- #[derive(Clone, Debug, Default, PartialEq, Eq)]
- struct Graph(HashMap<Node, Vec<Node>>);
-
- impl Graph {
- fn make_test_graph() -> Graph {
- let mut g = Graph::default();
- g.0.insert(Node(1), vec![Node(3)]);
- g.0.insert(Node(2), vec![Node(2)]);
- g.0.insert(Node(3), vec![Node(4), Node(5)]);
- g.0.insert(Node(4), vec![Node(7)]);
- g.0.insert(Node(5), vec![Node(6), Node(7)]);
- g.0.insert(Node(6), vec![Node(8)]);
- g.0.insert(Node(7), vec![Node(3)]);
- g.0.insert(Node(8), vec![]);
- g
- }
-
- fn reverse(&self) -> Graph {
- let mut reversed = Graph::default();
- for (node, edges) in self.0.iter() {
- reversed.0.entry(*node).or_insert_with(Vec::new);
- for referent in edges.iter() {
- reversed
- .0
- .entry(*referent)
- .or_insert_with(Vec::new)
- .push(*node);
- }
- }
- reversed
- }
- }
-
- #[derive(Clone, Debug, PartialEq, Eq)]
- struct ReachableFrom<'a> {
- reachable: HashMap<Node, HashSet<Node>>,
- graph: &'a Graph,
- reversed: Graph,
- }
-
- impl<'a> MonotoneFramework for ReachableFrom<'a> {
- type Node = Node;
- type Extra = &'a Graph;
- type Output = HashMap<Node, HashSet<Node>>;
-
- fn new(graph: &'a Graph) -> ReachableFrom {
- let reversed = graph.reverse();
- ReachableFrom {
- reachable: Default::default(),
- graph,
- reversed,
- }
- }
-
- fn initial_worklist(&self) -> Vec<Node> {
- self.graph.0.keys().cloned().collect()
- }
-
- fn constrain(&mut self, node: Node) -> ConstrainResult {
- // The set of nodes reachable from a node `x` is
- //
- // reachable(x) = s_0 U s_1 U ... U reachable(s_0) U reachable(s_1) U ...
- //
- // where there exist edges from `x` to each of `s_0, s_1, ...`.
- //
- // Yes, what follows is a **terribly** inefficient set union
- // implementation. Don't copy this code outside of this test!
-
- let original_size = self
- .reachable
- .entry(node)
- .or_insert_with(HashSet::default)
- .len();
-
- for sub_node in self.graph.0[&node].iter() {
- self.reachable.get_mut(&node).unwrap().insert(*sub_node);
-
- let sub_reachable = self
- .reachable
- .entry(*sub_node)
- .or_insert_with(HashSet::default)
- .clone();
-
- for transitive in sub_reachable {
- self.reachable.get_mut(&node).unwrap().insert(transitive);
- }
- }
-
- let new_size = self.reachable[&node].len();
- if original_size != new_size {
- ConstrainResult::Changed
- } else {
- ConstrainResult::Same
- }
- }
-
- fn each_depending_on<F>(&self, node: Node, mut f: F)
- where
- F: FnMut(Node),
- {
- for dep in self.reversed.0[&node].iter() {
- f(*dep);
- }
- }
- }
-
- impl<'a> From<ReachableFrom<'a>> for HashMap<Node, HashSet<Node>> {
- fn from(reachable: ReachableFrom<'a>) -> Self {
- reachable.reachable
- }
- }
-
- #[test]
- fn monotone() {
- let g = Graph::make_test_graph();
- let reachable = analyze::<ReachableFrom>(&g);
- println!("reachable = {:#?}", reachable);
-
- fn nodes<A>(nodes: A) -> HashSet<Node>
- where
- A: AsRef<[usize]>,
- {
- nodes.as_ref().iter().cloned().map(Node).collect()
- }
-
- let mut expected = HashMap::default();
- expected.insert(Node(1), nodes([3, 4, 5, 6, 7, 8]));
- expected.insert(Node(2), nodes([2]));
- expected.insert(Node(3), nodes([3, 4, 5, 6, 7, 8]));
- expected.insert(Node(4), nodes([3, 4, 5, 6, 7, 8]));
- expected.insert(Node(5), nodes([3, 4, 5, 6, 7, 8]));
- expected.insert(Node(6), nodes([8]));
- expected.insert(Node(7), nodes([3, 4, 5, 6, 7, 8]));
- expected.insert(Node(8), nodes([]));
- println!("expected = {:#?}", expected);
-
- assert_eq!(reachable, expected);
- }
-}
diff --git a/src/ir/analysis/sizedness.rs b/src/ir/analysis/sizedness.rs
deleted file mode 100644
index 251c3747..00000000
--- a/src/ir/analysis/sizedness.rs
+++ /dev/null
@@ -1,361 +0,0 @@
-//! Determining the sizedness of types (as base classes and otherwise).
-
-use super::{
- generate_dependencies, ConstrainResult, HasVtable, MonotoneFramework,
-};
-use crate::ir::context::{BindgenContext, TypeId};
-use crate::ir::item::IsOpaque;
-use crate::ir::traversal::EdgeKind;
-use crate::ir::ty::TypeKind;
-use crate::{Entry, HashMap};
-use std::{cmp, ops};
-
-/// The result of the `Sizedness` analysis for an individual item.
-///
-/// This is a chain lattice of the form:
-///
-/// ```ignore
-/// NonZeroSized
-/// |
-/// DependsOnTypeParam
-/// |
-/// ZeroSized
-/// ```
-///
-/// We initially assume that all types are `ZeroSized` and then update our
-/// understanding as we learn more about each type.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-pub enum SizednessResult {
- /// The type is zero-sized.
- ///
- /// This means that if it is a C++ type, and is not being used as a base
- /// member, then we must add an `_address` byte to enforce the
- /// unique-address-per-distinct-object-instance rule.
- ZeroSized,
-
- /// Whether this type is zero-sized or not depends on whether a type
- /// parameter is zero-sized or not.
- ///
- /// For example, given these definitions:
- ///
- /// ```c++
- /// template<class T>
- /// class Flongo : public T {};
- ///
- /// class Empty {};
- ///
- /// class NonEmpty { int x; };
- /// ```
- ///
- /// Then `Flongo<Empty>` is zero-sized, and needs an `_address` byte
- /// inserted, while `Flongo<NonEmpty>` is *not* zero-sized, and should *not*
- /// have an `_address` byte inserted.
- ///
- /// We don't properly handle this situation correctly right now:
- /// https://github.com/rust-lang/rust-bindgen/issues/586
- DependsOnTypeParam,
-
- /// Has some size that is known to be greater than zero. That doesn't mean
- /// it has a static size, but it is not zero sized for sure. In other words,
- /// it might contain an incomplete array or some other dynamically sized
- /// type.
- NonZeroSized,
-}
-
-impl Default for SizednessResult {
- fn default() -> Self {
- SizednessResult::ZeroSized
- }
-}
-
-impl SizednessResult {
- /// Take the least upper bound of `self` and `rhs`.
- pub fn join(self, rhs: Self) -> Self {
- cmp::max(self, rhs)
- }
-}
-
-impl ops::BitOr for SizednessResult {
- type Output = Self;
-
- fn bitor(self, rhs: SizednessResult) -> Self::Output {
- self.join(rhs)
- }
-}
-
-impl ops::BitOrAssign for SizednessResult {
- fn bitor_assign(&mut self, rhs: SizednessResult) {
- *self = self.join(rhs)
- }
-}
-
-/// An analysis that computes the sizedness of all types.
-///
-/// * For types with known sizes -- for example pointers, scalars, etc... --
-/// they are assigned `NonZeroSized`.
-///
-/// * For compound structure types with one or more fields, they are assigned
-/// `NonZeroSized`.
-///
-/// * For compound structure types without any fields, the results of the bases
-/// are `join`ed.
-///
-/// * For type parameters, `DependsOnTypeParam` is assigned.
-#[derive(Debug)]
-pub struct SizednessAnalysis<'ctx> {
- ctx: &'ctx BindgenContext,
- dependencies: HashMap<TypeId, Vec<TypeId>>,
- // Incremental results of the analysis. Missing entries are implicitly
- // considered `ZeroSized`.
- sized: HashMap<TypeId, SizednessResult>,
-}
-
-impl<'ctx> SizednessAnalysis<'ctx> {
- fn consider_edge(kind: EdgeKind) -> bool {
- // These are the only edges that can affect whether a type is
- // zero-sized or not.
- matches!(
- kind,
- EdgeKind::TemplateArgument |
- EdgeKind::TemplateParameterDefinition |
- EdgeKind::TemplateDeclaration |
- EdgeKind::TypeReference |
- EdgeKind::BaseMember |
- EdgeKind::Field
- )
- }
-
- /// Insert an incremental result, and return whether this updated our
- /// knowledge of types and we should continue the analysis.
- fn insert(
- &mut self,
- id: TypeId,
- result: SizednessResult,
- ) -> ConstrainResult {
- trace!("inserting {:?} for {:?}", result, id);
-
- if let SizednessResult::ZeroSized = result {
- return ConstrainResult::Same;
- }
-
- match self.sized.entry(id) {
- Entry::Occupied(mut entry) => {
- if *entry.get() < result {
- entry.insert(result);
- ConstrainResult::Changed
- } else {
- ConstrainResult::Same
- }
- }
- Entry::Vacant(entry) => {
- entry.insert(result);
- ConstrainResult::Changed
- }
- }
- }
-
- fn forward(&mut self, from: TypeId, to: TypeId) -> ConstrainResult {
- match self.sized.get(&from).cloned() {
- None => ConstrainResult::Same,
- Some(r) => self.insert(to, r),
- }
- }
-}
-
-impl<'ctx> MonotoneFramework for SizednessAnalysis<'ctx> {
- type Node = TypeId;
- type Extra = &'ctx BindgenContext;
- type Output = HashMap<TypeId, SizednessResult>;
-
- fn new(ctx: &'ctx BindgenContext) -> SizednessAnalysis<'ctx> {
- let dependencies = generate_dependencies(ctx, Self::consider_edge)
- .into_iter()
- .filter_map(|(id, sub_ids)| {
- id.as_type_id(ctx).map(|id| {
- (
- id,
- sub_ids
- .into_iter()
- .filter_map(|s| s.as_type_id(ctx))
- .collect::<Vec<_>>(),
- )
- })
- })
- .collect();
-
- let sized = HashMap::default();
-
- SizednessAnalysis {
- ctx,
- dependencies,
- sized,
- }
- }
-
- fn initial_worklist(&self) -> Vec<TypeId> {
- self.ctx
- .allowlisted_items()
- .iter()
- .cloned()
- .filter_map(|id| id.as_type_id(self.ctx))
- .collect()
- }
-
- fn constrain(&mut self, id: TypeId) -> ConstrainResult {
- trace!("constrain {:?}", id);
-
- if let Some(SizednessResult::NonZeroSized) =
- self.sized.get(&id).cloned()
- {
- trace!(" already know it is not zero-sized");
- return ConstrainResult::Same;
- }
-
- if id.has_vtable_ptr(self.ctx) {
- trace!(" has an explicit vtable pointer, therefore is not zero-sized");
- return self.insert(id, SizednessResult::NonZeroSized);
- }
-
- let ty = self.ctx.resolve_type(id);
-
- if id.is_opaque(self.ctx, &()) {
- trace!(" type is opaque; checking layout...");
- let result =
- ty.layout(self.ctx).map_or(SizednessResult::ZeroSized, |l| {
- if l.size == 0 {
- trace!(" ...layout has size == 0");
- SizednessResult::ZeroSized
- } else {
- trace!(" ...layout has size > 0");
- SizednessResult::NonZeroSized
- }
- });
- return self.insert(id, result);
- }
-
- match *ty.kind() {
- TypeKind::Void => {
- trace!(" void is zero-sized");
- self.insert(id, SizednessResult::ZeroSized)
- }
-
- TypeKind::TypeParam => {
- trace!(
- " type params sizedness depends on what they're \
- instantiated as"
- );
- self.insert(id, SizednessResult::DependsOnTypeParam)
- }
-
- TypeKind::Int(..) |
- TypeKind::Float(..) |
- TypeKind::Complex(..) |
- TypeKind::Function(..) |
- TypeKind::Enum(..) |
- TypeKind::Reference(..) |
- TypeKind::NullPtr |
- TypeKind::ObjCId |
- TypeKind::ObjCSel |
- TypeKind::Pointer(..) => {
- trace!(" {:?} is known not to be zero-sized", ty.kind());
- self.insert(id, SizednessResult::NonZeroSized)
- }
-
- TypeKind::ObjCInterface(..) => {
- trace!(" obj-c interfaces always have at least the `isa` pointer");
- self.insert(id, SizednessResult::NonZeroSized)
- }
-
- TypeKind::TemplateAlias(t, _) |
- TypeKind::Alias(t) |
- TypeKind::BlockPointer(t) |
- TypeKind::ResolvedTypeRef(t) => {
- trace!(" aliases and type refs forward to their inner type");
- self.forward(t, id)
- }
-
- TypeKind::TemplateInstantiation(ref inst) => {
- trace!(
- " template instantiations are zero-sized if their \
- definition is zero-sized"
- );
- self.forward(inst.template_definition(), id)
- }
-
- TypeKind::Array(_, 0) => {
- trace!(" arrays of zero elements are zero-sized");
- self.insert(id, SizednessResult::ZeroSized)
- }
- TypeKind::Array(..) => {
- trace!(" arrays of > 0 elements are not zero-sized");
- self.insert(id, SizednessResult::NonZeroSized)
- }
- TypeKind::Vector(..) => {
- trace!(" vectors are not zero-sized");
- self.insert(id, SizednessResult::NonZeroSized)
- }
-
- TypeKind::Comp(ref info) => {
- trace!(" comp considers its own fields and bases");
-
- if !info.fields().is_empty() {
- return self.insert(id, SizednessResult::NonZeroSized);
- }
-
- let result = info
- .base_members()
- .iter()
- .filter_map(|base| self.sized.get(&base.ty))
- .fold(SizednessResult::ZeroSized, |a, b| a.join(*b));
-
- self.insert(id, result)
- }
-
- TypeKind::Opaque => {
- unreachable!("covered by the .is_opaque() check above")
- }
-
- TypeKind::UnresolvedTypeRef(..) => {
- unreachable!("Should have been resolved after parsing!");
- }
- }
- }
-
- fn each_depending_on<F>(&self, id: TypeId, mut f: F)
- where
- F: FnMut(TypeId),
- {
- if let Some(edges) = self.dependencies.get(&id) {
- for ty in edges {
- trace!("enqueue {:?} into worklist", ty);
- f(*ty);
- }
- }
- }
-}
-
-impl<'ctx> From<SizednessAnalysis<'ctx>> for HashMap<TypeId, SizednessResult> {
- fn from(analysis: SizednessAnalysis<'ctx>) -> Self {
- // We let the lack of an entry mean "ZeroSized" to save space.
- extra_assert!(analysis
- .sized
- .values()
- .all(|v| { *v != SizednessResult::ZeroSized }));
-
- analysis.sized
- }
-}
-
-/// A convenience trait for querying whether some type or id is sized.
-///
-/// This is not for _computing_ whether the thing is sized, it is for looking up
-/// the results of the `Sizedness` analysis's computations for a specific thing.
-pub trait Sizedness {
- /// Get the sizedness of this type.
- fn sizedness(&self, ctx: &BindgenContext) -> SizednessResult;
-
- /// Is the sizedness for this type `SizednessResult::ZeroSized`?
- fn is_zero_sized(&self, ctx: &BindgenContext) -> bool {
- self.sizedness(ctx) == SizednessResult::ZeroSized
- }
-}
diff --git a/src/ir/analysis/template_params.rs b/src/ir/analysis/template_params.rs
deleted file mode 100644
index e88b774d..00000000
--- a/src/ir/analysis/template_params.rs
+++ /dev/null
@@ -1,608 +0,0 @@
-//! Discover which template type parameters are actually used.
-//!
-//! ### Why do we care?
-//!
-//! C++ allows ignoring template parameters, while Rust does not. Usually we can
-//! blindly stick a `PhantomData<T>` inside a generic Rust struct to make up for
-//! this. That doesn't work for templated type aliases, however:
-//!
-//! ```C++
-//! template <typename T>
-//! using Fml = int;
-//! ```
-//!
-//! If we generate the naive Rust code for this alias, we get:
-//!
-//! ```ignore
-//! pub type Fml<T> = ::std::os::raw::int;
-//! ```
-//!
-//! And this is rejected by `rustc` due to the unused type parameter.
-//!
-//! (Aside: in these simple cases, `libclang` will often just give us the
-//! aliased type directly, and we will never even know we were dealing with
-//! aliases, let alone templated aliases. It's the more convoluted scenarios
-//! where we get to have some fun...)
-//!
-//! For such problematic template aliases, we could generate a tuple whose
-//! second member is a `PhantomData<T>`. Or, if we wanted to go the extra mile,
-//! we could even generate some smarter wrapper that implements `Deref`,
-//! `DerefMut`, `From`, `Into`, `AsRef`, and `AsMut` to the actually aliased
-//! type. However, this is still lackluster:
-//!
-//! 1. Even with a billion conversion-trait implementations, using the generated
-//! bindings is rather un-ergonomic.
-//! 2. With either of these solutions, we need to keep track of which aliases
-//! we've transformed like this in order to generate correct uses of the
-//! wrapped type.
-//!
-//! Given that we have to properly track which template parameters ended up used
-//! for (2), we might as well leverage that information to make ergonomic
-//! bindings that don't contain any unused type parameters at all, and
-//! completely avoid the pain of (1).
-//!
-//! ### How do we determine which template parameters are used?
-//!
-//! Determining which template parameters are actually used is a trickier
-//! problem than it might seem at a glance. On the one hand, trivial uses are
-//! easy to detect:
-//!
-//! ```C++
-//! template <typename T>
-//! class Foo {
-//! T trivial_use_of_t;
-//! };
-//! ```
-//!
-//! It gets harder when determining if one template parameter is used depends on
-//! determining if another template parameter is used. In this example, whether
-//! `U` is used depends on whether `T` is used.
-//!
-//! ```C++
-//! template <typename T>
-//! class DoesntUseT {
-//! int x;
-//! };
-//!
-//! template <typename U>
-//! class Fml {
-//! DoesntUseT<U> lololol;
-//! };
-//! ```
-//!
-//! We can express the set of used template parameters as a constraint solving
-//! problem (where the set of template parameters used by a given IR item is the
-//! union of its sub-item's used template parameters) and iterate to a
-//! fixed-point.
-//!
-//! We use the `ir::analysis::MonotoneFramework` infrastructure for this
-//! fix-point analysis, where our lattice is the mapping from each IR item to
-//! the powerset of the template parameters that appear in the input C++ header,
-//! our join function is set union. The set of template parameters appearing in
-//! the program is finite, as is the number of IR items. We start at our
-//! lattice's bottom element: every item mapping to an empty set of template
-//! parameters. Our analysis only adds members to each item's set of used
-//! template parameters, never removes them, so it is monotone. Because our
-//! lattice is finite and our constraint function is monotone, iteration to a
-//! fix-point will terminate.
-//!
-//! See `src/ir/analysis.rs` for more.
-
-use super::{ConstrainResult, MonotoneFramework};
-use crate::ir::context::{BindgenContext, ItemId};
-use crate::ir::item::{Item, ItemSet};
-use crate::ir::template::{TemplateInstantiation, TemplateParameters};
-use crate::ir::traversal::{EdgeKind, Trace};
-use crate::ir::ty::TypeKind;
-use crate::{HashMap, HashSet};
-
-/// An analysis that finds for each IR item its set of template parameters that
-/// it uses.
-///
-/// We use the monotone constraint function `template_param_usage`, defined as
-/// follows:
-///
-/// * If `T` is a named template type parameter, it trivially uses itself:
-///
-/// ```ignore
-/// template_param_usage(T) = { T }
-/// ```
-///
-/// * If `inst` is a template instantiation, `inst.args` are the template
-/// instantiation's template arguments, `inst.def` is the template definition
-/// being instantiated, and `inst.def.params` is the template definition's
-/// template parameters, then the instantiation's usage is the union of each
-/// of its arguments' usages *if* the corresponding template parameter is in
-/// turn used by the template definition:
-///
-/// ```ignore
-/// template_param_usage(inst) = union(
-/// template_param_usage(inst.args[i])
-/// for i in 0..length(inst.args.length)
-/// if inst.def.params[i] in template_param_usage(inst.def)
-/// )
-/// ```
-///
-/// * Finally, for all other IR item kinds, we use our lattice's `join`
-/// operation: set union with each successor of the given item's template
-/// parameter usage:
-///
-/// ```ignore
-/// template_param_usage(v) =
-/// union(template_param_usage(w) for w in successors(v))
-/// ```
-///
-/// Note that we ignore certain edges in the graph, such as edges from a
-/// template declaration to its template parameters' definitions for this
-/// analysis. If we didn't, then we would mistakenly determine that ever
-/// template parameter is always used.
-///
-/// The final wrinkle is handling of blocklisted types. Normally, we say that
-/// the set of allowlisted items is the transitive closure of items explicitly
-/// called out for allowlisting, *without* any items explicitly called out as
-/// blocklisted. However, for the purposes of this analysis's correctness, we
-/// simplify and consider run the analysis on the full transitive closure of
-/// allowlisted items. We do, however, treat instantiations of blocklisted items
-/// specially; see `constrain_instantiation_of_blocklisted_template` and its
-/// documentation for details.
-#[derive(Debug, Clone)]
-pub struct UsedTemplateParameters<'ctx> {
- ctx: &'ctx BindgenContext,
-
- // The Option is only there for temporary moves out of the hash map. See the
- // comments in `UsedTemplateParameters::constrain` below.
- used: HashMap<ItemId, Option<ItemSet>>,
-
- dependencies: HashMap<ItemId, Vec<ItemId>>,
-
- // The set of allowlisted items, without any blocklisted items reachable
- // from the allowlisted items which would otherwise be considered
- // allowlisted as well.
- allowlisted_items: HashSet<ItemId>,
-}
-
-impl<'ctx> UsedTemplateParameters<'ctx> {
- fn consider_edge(kind: EdgeKind) -> bool {
- match kind {
- // For each of these kinds of edges, if the referent uses a template
- // parameter, then it should be considered that the origin of the
- // edge also uses the template parameter.
- EdgeKind::TemplateArgument |
- EdgeKind::BaseMember |
- EdgeKind::Field |
- EdgeKind::Constructor |
- EdgeKind::Destructor |
- EdgeKind::VarType |
- EdgeKind::FunctionReturn |
- EdgeKind::FunctionParameter |
- EdgeKind::TypeReference => true,
-
- // An inner var or type using a template parameter is orthogonal
- // from whether we use it. See template-param-usage-{6,11}.hpp.
- EdgeKind::InnerVar | EdgeKind::InnerType => false,
-
- // We can't emit machine code for new monomorphizations of class
- // templates' methods (and don't detect explicit instantiations) so
- // we must ignore template parameters that are only used by
- // methods. This doesn't apply to a function type's return or
- // parameter types, however, because of type aliases of function
- // pointers that use template parameters, eg
- // tests/headers/struct_with_typedef_template_arg.hpp
- EdgeKind::Method => false,
-
- // If we considered these edges, we would end up mistakenly claiming
- // that every template parameter always used.
- EdgeKind::TemplateDeclaration |
- EdgeKind::TemplateParameterDefinition => false,
-
- // Since we have to be careful about which edges we consider for
- // this analysis to be correct, we ignore generic edges. We also
- // avoid a `_` wild card to force authors of new edge kinds to
- // determine whether they need to be considered by this analysis.
- EdgeKind::Generic => false,
- }
- }
-
- fn take_this_id_usage_set<Id: Into<ItemId>>(
- &mut self,
- this_id: Id,
- ) -> ItemSet {
- let this_id = this_id.into();
- self.used
- .get_mut(&this_id)
- .expect(
- "Should have a set of used template params for every item \
- id",
- )
- .take()
- .expect(
- "Should maintain the invariant that all used template param \
- sets are `Some` upon entry of `constrain`",
- )
- }
-
- /// We say that blocklisted items use all of their template parameters. The
- /// blocklisted type is most likely implemented explicitly by the user,
- /// since it won't be in the generated bindings, and we don't know exactly
- /// what they'll to with template parameters, but we can push the issue down
- /// the line to them.
- fn constrain_instantiation_of_blocklisted_template(
- &self,
- this_id: ItemId,
- used_by_this_id: &mut ItemSet,
- instantiation: &TemplateInstantiation,
- ) {
- trace!(
- " instantiation of blocklisted template, uses all template \
- arguments"
- );
-
- let args = instantiation
- .template_arguments()
- .iter()
- .map(|a| {
- a.into_resolver()
- .through_type_refs()
- .through_type_aliases()
- .resolve(self.ctx)
- .id()
- })
- .filter(|a| *a != this_id)
- .flat_map(|a| {
- self.used
- .get(&a)
- .expect("Should have a used entry for the template arg")
- .as_ref()
- .expect(
- "Because a != this_id, and all used template \
- param sets other than this_id's are `Some`, \
- a's used template param set should be `Some`",
- )
- .iter()
- .cloned()
- });
-
- used_by_this_id.extend(args);
- }
-
- /// A template instantiation's concrete template argument is only used if
- /// the template definition uses the corresponding template parameter.
- fn constrain_instantiation(
- &self,
- this_id: ItemId,
- used_by_this_id: &mut ItemSet,
- instantiation: &TemplateInstantiation,
- ) {
- trace!(" template instantiation");
-
- let decl = self.ctx.resolve_type(instantiation.template_definition());
- let args = instantiation.template_arguments();
-
- let params = decl.self_template_params(self.ctx);
-
- debug_assert!(this_id != instantiation.template_definition());
- let used_by_def = self.used
- .get(&instantiation.template_definition().into())
- .expect("Should have a used entry for instantiation's template definition")
- .as_ref()
- .expect("And it should be Some because only this_id's set is None, and an \
- instantiation's template definition should never be the \
- instantiation itself");
-
- for (arg, param) in args.iter().zip(params.iter()) {
- trace!(
- " instantiation's argument {:?} is used if definition's \
- parameter {:?} is used",
- arg,
- param
- );
-
- if used_by_def.contains(&param.into()) {
- trace!(" param is used by template definition");
-
- let arg = arg
- .into_resolver()
- .through_type_refs()
- .through_type_aliases()
- .resolve(self.ctx)
- .id();
-
- if arg == this_id {
- continue;
- }
-
- let used_by_arg = self
- .used
- .get(&arg)
- .expect("Should have a used entry for the template arg")
- .as_ref()
- .expect(
- "Because arg != this_id, and all used template \
- param sets other than this_id's are `Some`, \
- arg's used template param set should be \
- `Some`",
- )
- .iter()
- .cloned();
- used_by_this_id.extend(used_by_arg);
- }
- }
- }
-
- /// The join operation on our lattice: the set union of all of this id's
- /// successors.
- fn constrain_join(&self, used_by_this_id: &mut ItemSet, item: &Item) {
- trace!(" other item: join with successors' usage");
-
- 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() || !Self::consider_edge(edge_kind) {
- return;
- }
-
- let used_by_sub_id = self
- .used
- .get(&sub_id)
- .expect("Should have a used set for the sub_id successor")
- .as_ref()
- .expect(
- "Because sub_id != id, and all used template \
- param sets other than id's are `Some`, \
- sub_id's used template param set should be \
- `Some`",
- )
- .iter()
- .cloned();
-
- trace!(
- " union with {:?}'s usage: {:?}",
- sub_id,
- used_by_sub_id.clone().collect::<Vec<_>>()
- );
-
- used_by_this_id.extend(used_by_sub_id);
- },
- &(),
- );
- }
-}
-
-impl<'ctx> MonotoneFramework for UsedTemplateParameters<'ctx> {
- type Node = ItemId;
- type Extra = &'ctx BindgenContext;
- type Output = HashMap<ItemId, ItemSet>;
-
- fn new(ctx: &'ctx BindgenContext) -> UsedTemplateParameters<'ctx> {
- let mut used = HashMap::default();
- let mut dependencies = HashMap::default();
- let allowlisted_items: HashSet<_> =
- ctx.allowlisted_items().iter().cloned().collect();
-
- let allowlisted_and_blocklisted_items: ItemSet = allowlisted_items
- .iter()
- .cloned()
- .flat_map(|i| {
- let mut reachable = vec![i];
- i.trace(
- ctx,
- &mut |s, _| {
- reachable.push(s);
- },
- &(),
- );
- reachable
- })
- .collect();
-
- for item in allowlisted_and_blocklisted_items {
- dependencies.entry(item).or_insert_with(Vec::new);
- used.entry(item).or_insert_with(|| Some(ItemSet::new()));
-
- {
- // We reverse our natural IR graph edges to find dependencies
- // between nodes.
- item.trace(
- ctx,
- &mut |sub_item: ItemId, _| {
- used.entry(sub_item)
- .or_insert_with(|| Some(ItemSet::new()));
- dependencies
- .entry(sub_item)
- .or_insert_with(Vec::new)
- .push(item);
- },
- &(),
- );
- }
-
- // Additionally, whether a template instantiation's template
- // arguments are used depends on whether the template declaration's
- // generic template parameters are used.
- let item_kind =
- ctx.resolve_item(item).as_type().map(|ty| ty.kind());
- if let Some(&TypeKind::TemplateInstantiation(ref inst)) = item_kind
- {
- let decl = ctx.resolve_type(inst.template_definition());
- let args = inst.template_arguments();
-
- // Although template definitions should always have
- // template parameters, there is a single exception:
- // opaque templates. Hence the unwrap_or.
- let params = decl.self_template_params(ctx);
-
- for (arg, param) in args.iter().zip(params.iter()) {
- let arg = arg
- .into_resolver()
- .through_type_aliases()
- .through_type_refs()
- .resolve(ctx)
- .id();
-
- let param = param
- .into_resolver()
- .through_type_aliases()
- .through_type_refs()
- .resolve(ctx)
- .id();
-
- used.entry(arg).or_insert_with(|| Some(ItemSet::new()));
- used.entry(param).or_insert_with(|| Some(ItemSet::new()));
-
- dependencies
- .entry(arg)
- .or_insert_with(Vec::new)
- .push(param);
- }
- }
- }
-
- if cfg!(feature = "testing_only_extra_assertions") {
- // Invariant: The `used` map has an entry for every allowlisted
- // item, as well as all explicitly blocklisted items that are
- // reachable from allowlisted items.
- //
- // Invariant: the `dependencies` map has an entry for every
- // allowlisted item.
- //
- // (This is so that every item we call `constrain` on is guaranteed
- // to have a set of template parameters, and we can allow
- // blocklisted templates to use all of their parameters).
- for item in allowlisted_items.iter() {
- extra_assert!(used.contains_key(item));
- extra_assert!(dependencies.contains_key(item));
- item.trace(
- ctx,
- &mut |sub_item, _| {
- extra_assert!(used.contains_key(&sub_item));
- extra_assert!(dependencies.contains_key(&sub_item));
- },
- &(),
- )
- }
- }
-
- UsedTemplateParameters {
- ctx,
- used,
- dependencies,
- allowlisted_items,
- }
- }
-
- 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 {
- // Invariant: all hash map entries' values are `Some` upon entering and
- // exiting this method.
- extra_assert!(self.used.values().all(|v| v.is_some()));
-
- // Take the set for this id out of the hash map while we mutate it based
- // on other hash map entries. We *must* put it back into the hash map at
- // the end of this method. This allows us to side-step HashMap's lack of
- // an analog to slice::split_at_mut.
- let mut used_by_this_id = self.take_this_id_usage_set(id);
-
- trace!("constrain {:?}", id);
- trace!(" initially, used set is {:?}", used_by_this_id);
-
- let original_len = used_by_this_id.len();
-
- let item = self.ctx.resolve_item(id);
- let ty_kind = item.as_type().map(|ty| ty.kind());
- match ty_kind {
- // Named template type parameters trivially use themselves.
- Some(&TypeKind::TypeParam) => {
- trace!(" named type, trivially uses itself");
- used_by_this_id.insert(id);
- }
- // Template instantiations only use their template arguments if the
- // template definition uses the corresponding template parameter.
- Some(&TypeKind::TemplateInstantiation(ref inst)) => {
- if self
- .allowlisted_items
- .contains(&inst.template_definition().into())
- {
- self.constrain_instantiation(
- id,
- &mut used_by_this_id,
- inst,
- );
- } else {
- self.constrain_instantiation_of_blocklisted_template(
- id,
- &mut used_by_this_id,
- inst,
- );
- }
- }
- // Otherwise, add the union of each of its referent item's template
- // parameter usage.
- _ => self.constrain_join(&mut used_by_this_id, item),
- }
-
- trace!(" finally, used set is {:?}", used_by_this_id);
-
- let new_len = used_by_this_id.len();
- assert!(
- new_len >= original_len,
- "This is the property that ensures this function is monotone -- \
- if it doesn't hold, the analysis might never terminate!"
- );
-
- // Put the set back in the hash map and restore our invariant.
- debug_assert!(self.used[&id].is_none());
- self.used.insert(id, Some(used_by_this_id));
- extra_assert!(self.used.values().all(|v| v.is_some()));
-
- if new_len != original_len {
- ConstrainResult::Changed
- } else {
- ConstrainResult::Same
- }
- }
-
- fn each_depending_on<F>(&self, item: ItemId, mut f: F)
- where
- F: FnMut(ItemId),
- {
- if let Some(edges) = self.dependencies.get(&item) {
- for item in edges {
- trace!("enqueue {:?} into worklist", item);
- f(*item);
- }
- }
- }
-}
-
-impl<'ctx> From<UsedTemplateParameters<'ctx>> for HashMap<ItemId, ItemSet> {
- fn from(used_templ_params: UsedTemplateParameters<'ctx>) -> Self {
- used_templ_params
- .used
- .into_iter()
- .map(|(k, v)| (k, v.unwrap()))
- .collect()
- }
-}
diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs
deleted file mode 100644
index 288c11eb..00000000
--- a/src/ir/annotations.rs
+++ /dev/null
@@ -1,211 +0,0 @@
-//! Types and functions related to bindgen annotation comments.
-//!
-//! Users can add annotations in doc comments to types that they would like to
-//! replace other types with, mark as opaque, etc. This module deals with all of
-//! that stuff.
-
-use crate::clang;
-
-/// What kind of accessor should we provide for a field?
-#[derive(Copy, PartialEq, Eq, Clone, Debug)]
-pub enum FieldAccessorKind {
- /// No accessor.
- None,
- /// Plain accessor.
- Regular,
- /// Unsafe accessor.
- Unsafe,
- /// Immutable accessor.
- Immutable,
-}
-
-/// Annotations for a given item, or a field.
-///
-/// You can see the kind of comments that are accepted in the Doxygen
-/// documentation:
-///
-/// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html
-#[derive(Default, Clone, PartialEq, Eq, Debug)]
-pub struct Annotations {
- /// Whether this item is marked as opaque. Only applies to types.
- opaque: bool,
- /// Whether this item should be hidden from the output. Only applies to
- /// types, or enum variants.
- hide: bool,
- /// Whether this type should be replaced by another. The name is a
- /// namespace-aware path.
- use_instead_of: Option<Vec<String>>,
- /// Manually disable deriving copy/clone on this type. Only applies to
- /// struct or union types.
- disallow_copy: bool,
- /// Manually disable deriving debug on this type.
- disallow_debug: bool,
- /// Manually disable deriving/implement default on this type.
- disallow_default: bool,
- /// Whether to add a #[must_use] annotation to this type.
- must_use_type: bool,
- /// Whether fields should be marked as private or not. You can set this on
- /// structs (it will apply to all the fields), or individual fields.
- private_fields: Option<bool>,
- /// The kind of accessor this field will have. Also can be applied to
- /// structs so all the fields inside share it by default.
- accessor_kind: Option<FieldAccessorKind>,
- /// Whether this enum variant should be constified.
- ///
- /// This is controlled by the `constant` attribute, this way:
- ///
- /// ```cpp
- /// enum Foo {
- /// Bar = 0, /**< <div rustbindgen constant></div> */
- /// Baz = 0,
- /// };
- /// ```
- ///
- /// In that case, bindgen will generate a constant for `Bar` instead of
- /// `Baz`.
- constify_enum_variant: bool,
- /// List of explicit derives for this type.
- derives: Vec<String>,
-}
-
-fn parse_accessor(s: &str) -> FieldAccessorKind {
- match s {
- "false" => FieldAccessorKind::None,
- "unsafe" => FieldAccessorKind::Unsafe,
- "immutable" => FieldAccessorKind::Immutable,
- _ => FieldAccessorKind::Regular,
- }
-}
-
-impl Annotations {
- /// Construct new annotations for the given cursor and its bindgen comments
- /// (if any).
- pub fn new(cursor: &clang::Cursor) -> Option<Annotations> {
- let mut anno = Annotations::default();
- let mut matched_one = false;
- anno.parse(&cursor.comment(), &mut matched_one);
-
- if matched_one {
- Some(anno)
- } else {
- None
- }
- }
-
- /// Should this type be hidden?
- pub fn hide(&self) -> bool {
- self.hide
- }
-
- /// Should this type be opaque?
- pub fn opaque(&self) -> bool {
- self.opaque
- }
-
- /// For a given type, indicates the type it should replace.
- ///
- /// For example, in the following code:
- ///
- /// ```cpp
- ///
- /// /** <div rustbindgen replaces="Bar"></div> */
- /// struct Foo { int x; };
- ///
- /// struct Bar { char foo; };
- /// ```
- ///
- /// the generated code would look something like:
- ///
- /// ```
- /// /** <div rustbindgen replaces="Bar"></div> */
- /// struct Bar {
- /// x: ::std::os::raw::c_int,
- /// };
- /// ```
- ///
- /// That is, code for `Foo` is used to generate `Bar`.
- pub fn use_instead_of(&self) -> Option<&[String]> {
- self.use_instead_of.as_deref()
- }
-
- /// The list of derives that have been specified in this annotation.
- pub fn derives(&self) -> &[String] {
- &self.derives
- }
-
- /// Should we avoid implementing the `Copy` trait?
- pub fn disallow_copy(&self) -> bool {
- self.disallow_copy
- }
-
- /// Should we avoid implementing the `Debug` trait?
- pub fn disallow_debug(&self) -> bool {
- self.disallow_debug
- }
-
- /// Should we avoid implementing the `Default` trait?
- pub fn disallow_default(&self) -> bool {
- self.disallow_default
- }
-
- /// Should this type get a `#[must_use]` annotation?
- pub fn must_use_type(&self) -> bool {
- self.must_use_type
- }
-
- /// Should the fields be private?
- pub fn private_fields(&self) -> Option<bool> {
- self.private_fields
- }
-
- /// What kind of accessors should we provide for this type's fields?
- pub fn accessor_kind(&self) -> Option<FieldAccessorKind> {
- self.accessor_kind
- }
-
- fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) {
- use clang_sys::CXComment_HTMLStartTag;
- if comment.kind() == CXComment_HTMLStartTag &&
- comment.get_tag_name() == "div" &&
- comment
- .get_tag_attrs()
- .next()
- .map_or(false, |attr| attr.name == "rustbindgen")
- {
- *matched = true;
- for attr in comment.get_tag_attrs() {
- match attr.name.as_str() {
- "opaque" => self.opaque = true,
- "hide" => self.hide = true,
- "nocopy" => self.disallow_copy = true,
- "nodebug" => self.disallow_debug = true,
- "nodefault" => self.disallow_default = true,
- "mustusetype" => self.must_use_type = true,
- "replaces" => {
- self.use_instead_of = Some(
- attr.value.split("::").map(Into::into).collect(),
- )
- }
- "derive" => self.derives.push(attr.value),
- "private" => {
- self.private_fields = Some(attr.value != "false")
- }
- "accessor" => {
- self.accessor_kind = Some(parse_accessor(&attr.value))
- }
- "constant" => self.constify_enum_variant = true,
- _ => {}
- }
- }
- }
-
- for child in comment.get_children() {
- self.parse(&child, matched);
- }
- }
-
- /// Returns whether we've parsed a "constant" attribute.
- pub fn constify_enum_variant(&self) -> bool {
- self.constify_enum_variant
- }
-}
diff --git a/src/ir/comment.rs b/src/ir/comment.rs
deleted file mode 100644
index c96e3ebb..00000000
--- a/src/ir/comment.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-//! Utilities for manipulating C/C++ comments.
-
-/// The type of a comment.
-#[derive(Debug, PartialEq, Eq)]
-enum Kind {
- /// A `///` comment, or something of the like.
- /// All lines in a comment should start with the same symbol.
- SingleLines,
- /// A `/**` comment, where each other line can start with `*` and the
- /// entire block ends with `*/`.
- MultiLine,
-}
-
-/// Preprocesses a C/C++ comment so that it is a valid Rust comment.
-pub fn preprocess(comment: &str, indent: usize) -> String {
- match self::kind(comment) {
- Some(Kind::SingleLines) => preprocess_single_lines(comment, indent),
- Some(Kind::MultiLine) => preprocess_multi_line(comment, indent),
- None => comment.to_owned(),
- }
-}
-
-/// Gets the kind of the doc comment, if it is one.
-fn kind(comment: &str) -> Option<Kind> {
- if comment.starts_with("/*") {
- Some(Kind::MultiLine)
- } else if comment.starts_with("//") {
- Some(Kind::SingleLines)
- } else {
- None
- }
-}
-
-fn make_indent(indent: usize) -> String {
- const RUST_INDENTATION: usize = 4;
- " ".repeat(indent * RUST_INDENTATION)
-}
-
-/// Preprocesses multiple single line comments.
-///
-/// Handles lines starting with both `//` and `///`.
-fn preprocess_single_lines(comment: &str, indent: usize) -> String {
- debug_assert!(comment.starts_with("//"), "comment is not single line");
-
- let indent = make_indent(indent);
- let mut is_first = true;
- let lines: Vec<_> = comment
- .lines()
- .map(|l| l.trim().trim_start_matches('/'))
- .map(|l| {
- let indent = if is_first { "" } else { &*indent };
- is_first = false;
- format!("{}///{}", indent, l)
- })
- .collect();
- lines.join("\n")
-}
-
-fn preprocess_multi_line(comment: &str, indent: usize) -> String {
- let comment = comment
- .trim_start_matches('/')
- .trim_end_matches('/')
- .trim_end_matches('*');
-
- let indent = make_indent(indent);
- // Strip any potential `*` characters preceding each line.
- let mut is_first = true;
- let mut lines: Vec<_> = comment
- .lines()
- .map(|line| line.trim().trim_start_matches('*').trim_start_matches('!'))
- .skip_while(|line| line.trim().is_empty()) // Skip the first empty lines.
- .map(|line| {
- let indent = if is_first { "" } else { &*indent };
- is_first = false;
- format!("{}///{}", indent, line)
- })
- .collect();
-
- // Remove the trailing line corresponding to the `*/`.
- if lines
- .last()
- .map_or(false, |l| l.trim().is_empty() || l.trim() == "///")
- {
- lines.pop();
- }
-
- lines.join("\n")
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn picks_up_single_and_multi_line_doc_comments() {
- assert_eq!(kind("/// hello"), Some(Kind::SingleLines));
- assert_eq!(kind("/** world */"), Some(Kind::MultiLine));
- }
-
- #[test]
- fn processes_single_lines_correctly() {
- assert_eq!(preprocess("/// hello", 0), "/// hello");
- assert_eq!(preprocess("// hello", 0), "/// hello");
- assert_eq!(preprocess("// hello", 0), "/// hello");
- }
-
- #[test]
- fn processes_multi_lines_correctly() {
- assert_eq!(
- preprocess("/** hello \n * world \n * foo \n */", 0),
- "/// hello\n/// world\n/// foo"
- );
-
- assert_eq!(
- preprocess("/**\nhello\n*world\n*foo\n*/", 0),
- "///hello\n///world\n///foo"
- );
- }
-}
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
deleted file mode 100644
index f44c5d67..00000000
--- a/src/ir/comp.rs
+++ /dev/null
@@ -1,1891 +0,0 @@
-//! Compound types (unions and structs) in our intermediate representation.
-
-use super::analysis::Sizedness;
-use super::annotations::Annotations;
-use super::context::{BindgenContext, FunctionId, ItemId, TypeId, VarId};
-use super::dot::DotAttributes;
-use super::item::{IsOpaque, Item};
-use super::layout::Layout;
-use super::template::TemplateParameters;
-use super::traversal::{EdgeKind, Trace, Tracer};
-use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
-use crate::clang;
-use crate::codegen::struct_layout::{align_to, bytes_from_bits_pow2};
-use crate::ir::derive::CanDeriveCopy;
-use crate::parse::{ClangItemParser, ParseError};
-use crate::HashMap;
-use crate::NonCopyUnionStyle;
-use peeking_take_while::PeekableExt;
-use std::cmp;
-use std::io;
-use std::mem;
-
-/// The kind of compound type.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum CompKind {
- /// A struct.
- Struct,
- /// A union.
- Union,
-}
-
-/// The kind of C++ method.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum MethodKind {
- /// A constructor. We represent it as method for convenience, to avoid code
- /// duplication.
- Constructor,
- /// A destructor.
- Destructor,
- /// A virtual destructor.
- VirtualDestructor {
- /// Whether it's pure virtual.
- pure_virtual: bool,
- },
- /// A static method.
- Static,
- /// A normal method.
- Normal,
- /// A virtual method.
- Virtual {
- /// Whether it's pure virtual.
- pure_virtual: bool,
- },
-}
-
-impl MethodKind {
- /// Is this a destructor method?
- pub fn is_destructor(&self) -> bool {
- matches!(
- *self,
- MethodKind::Destructor | MethodKind::VirtualDestructor { .. }
- )
- }
-
- /// Is this a pure virtual method?
- pub fn is_pure_virtual(&self) -> bool {
- match *self {
- MethodKind::Virtual { pure_virtual } |
- MethodKind::VirtualDestructor { pure_virtual } => pure_virtual,
- _ => false,
- }
- }
-}
-
-/// A struct representing a C++ method, either static, normal, or virtual.
-#[derive(Debug)]
-pub struct Method {
- kind: MethodKind,
- /// The signature of the method. Take into account this is not a `Type`
- /// item, but a `Function` one.
- ///
- /// This is tricky and probably this field should be renamed.
- signature: FunctionId,
- is_const: bool,
-}
-
-impl Method {
- /// Construct a new `Method`.
- pub fn new(
- kind: MethodKind,
- signature: FunctionId,
- is_const: bool,
- ) -> Self {
- Method {
- kind,
- signature,
- is_const,
- }
- }
-
- /// What kind of method is this?
- pub fn kind(&self) -> MethodKind {
- self.kind
- }
-
- /// Is this a constructor?
- pub fn is_constructor(&self) -> bool {
- self.kind == MethodKind::Constructor
- }
-
- /// Is this a virtual method?
- pub fn is_virtual(&self) -> bool {
- matches!(
- self.kind,
- MethodKind::Virtual { .. } | MethodKind::VirtualDestructor { .. }
- )
- }
-
- /// Is this a static method?
- pub fn is_static(&self) -> bool {
- self.kind == MethodKind::Static
- }
-
- /// Get the id for the `Function` signature for this method.
- pub fn signature(&self) -> FunctionId {
- self.signature
- }
-
- /// Is this a const qualified method?
- pub fn is_const(&self) -> bool {
- self.is_const
- }
-}
-
-/// Methods common to the various field types.
-pub trait FieldMethods {
- /// Get the name of this field.
- fn name(&self) -> Option<&str>;
-
- /// Get the type of this field.
- fn ty(&self) -> TypeId;
-
- /// Get the comment for this field.
- fn comment(&self) -> Option<&str>;
-
- /// If this is a bitfield, how many bits does it need?
- fn bitfield_width(&self) -> Option<u32>;
-
- /// Is this feild declared public?
- fn is_public(&self) -> bool;
-
- /// Get the annotations for this field.
- fn annotations(&self) -> &Annotations;
-
- /// The offset of the field (in bits)
- fn offset(&self) -> Option<usize>;
-}
-
-/// A contiguous set of logical bitfields that live within the same physical
-/// allocation unit. See 9.2.4 [class.bit] in the C++ standard and [section
-/// 2.4.II.1 in the Itanium C++
-/// ABI](http://itanium-cxx-abi.github.io/cxx-abi/abi.html#class-types).
-#[derive(Debug)]
-pub struct BitfieldUnit {
- nth: usize,
- layout: Layout,
- bitfields: Vec<Bitfield>,
-}
-
-impl BitfieldUnit {
- /// Get the 1-based index of this bitfield unit within its containing
- /// struct. Useful for generating a Rust struct's field name for this unit
- /// of bitfields.
- pub fn nth(&self) -> usize {
- self.nth
- }
-
- /// Get the layout within which these bitfields reside.
- pub fn layout(&self) -> Layout {
- self.layout
- }
-
- /// Get the bitfields within this unit.
- pub fn bitfields(&self) -> &[Bitfield] {
- &self.bitfields
- }
-}
-
-/// A struct representing a C++ field.
-#[derive(Debug)]
-pub enum Field {
- /// A normal data member.
- DataMember(FieldData),
-
- /// A physical allocation unit containing many logical bitfields.
- Bitfields(BitfieldUnit),
-}
-
-impl Field {
- /// Get this field's layout.
- pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
- match *self {
- Field::Bitfields(BitfieldUnit { layout, .. }) => Some(layout),
- Field::DataMember(ref data) => {
- ctx.resolve_type(data.ty).layout(ctx)
- }
- }
- }
-}
-
-impl Trace for Field {
- type Extra = ();
-
- fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
- where
- T: Tracer,
- {
- match *self {
- Field::DataMember(ref data) => {
- tracer.visit_kind(data.ty.into(), EdgeKind::Field);
- }
- Field::Bitfields(BitfieldUnit { ref bitfields, .. }) => {
- for bf in bitfields {
- tracer.visit_kind(bf.ty().into(), EdgeKind::Field);
- }
- }
- }
- }
-}
-
-impl DotAttributes for Field {
- fn dot_attributes<W>(
- &self,
- ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write,
- {
- match *self {
- Field::DataMember(ref data) => data.dot_attributes(ctx, out),
- Field::Bitfields(BitfieldUnit {
- layout,
- ref bitfields,
- ..
- }) => {
- writeln!(
- out,
- r#"<tr>
- <td>bitfield unit</td>
- <td>
- <table border="0">
- <tr>
- <td>unit.size</td><td>{}</td>
- </tr>
- <tr>
- <td>unit.align</td><td>{}</td>
- </tr>
- "#,
- layout.size, layout.align
- )?;
- for bf in bitfields {
- bf.dot_attributes(ctx, out)?;
- }
- writeln!(out, "</table></td></tr>")
- }
- }
- }
-}
-
-impl DotAttributes for FieldData {
- fn dot_attributes<W>(
- &self,
- _ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write,
- {
- writeln!(
- out,
- "<tr><td>{}</td><td>{:?}</td></tr>",
- self.name().unwrap_or("(anonymous)"),
- self.ty()
- )
- }
-}
-
-impl DotAttributes for Bitfield {
- fn dot_attributes<W>(
- &self,
- _ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write,
- {
- writeln!(
- out,
- "<tr><td>{} : {}</td><td>{:?}</td></tr>",
- self.name().unwrap_or("(anonymous)"),
- self.width(),
- self.ty()
- )
- }
-}
-
-/// A logical bitfield within some physical bitfield allocation unit.
-#[derive(Debug)]
-pub struct Bitfield {
- /// Index of the bit within this bitfield's allocation unit where this
- /// bitfield's bits begin.
- offset_into_unit: usize,
-
- /// The field data for this bitfield.
- data: FieldData,
-
- /// Name of the generated Rust getter for this bitfield.
- ///
- /// Should be assigned before codegen.
- getter_name: Option<String>,
-
- /// Name of the generated Rust setter for this bitfield.
- ///
- /// Should be assigned before codegen.
- setter_name: Option<String>,
-}
-
-impl Bitfield {
- /// Construct a new bitfield.
- fn new(offset_into_unit: usize, raw: RawField) -> Bitfield {
- assert!(raw.bitfield_width().is_some());
-
- Bitfield {
- offset_into_unit,
- data: raw.0,
- getter_name: None,
- setter_name: None,
- }
- }
-
- /// Get the index of the bit within this bitfield's allocation unit where
- /// this bitfield begins.
- pub fn offset_into_unit(&self) -> usize {
- self.offset_into_unit
- }
-
- /// Get the mask value that when &'ed with this bitfield's allocation unit
- /// produces this bitfield's value.
- pub fn mask(&self) -> u64 {
- use std::u64;
-
- let unoffseted_mask =
- if self.width() as u64 == mem::size_of::<u64>() as u64 * 8 {
- u64::MAX
- } else {
- (1u64 << self.width()) - 1u64
- };
-
- unoffseted_mask << self.offset_into_unit()
- }
-
- /// Get the bit width of this bitfield.
- pub fn width(&self) -> u32 {
- self.data.bitfield_width().unwrap()
- }
-
- /// Name of the generated Rust getter for this bitfield.
- ///
- /// Panics if called before assigning bitfield accessor names or if
- /// this bitfield have no name.
- pub fn getter_name(&self) -> &str {
- assert!(
- self.name().is_some(),
- "`Bitfield::getter_name` called on anonymous field"
- );
- self.getter_name.as_ref().expect(
- "`Bitfield::getter_name` should only be called after\
- assigning bitfield accessor names",
- )
- }
-
- /// Name of the generated Rust setter for this bitfield.
- ///
- /// Panics if called before assigning bitfield accessor names or if
- /// this bitfield have no name.
- pub fn setter_name(&self) -> &str {
- assert!(
- self.name().is_some(),
- "`Bitfield::setter_name` called on anonymous field"
- );
- self.setter_name.as_ref().expect(
- "`Bitfield::setter_name` should only be called\
- after assigning bitfield accessor names",
- )
- }
-}
-
-impl FieldMethods for Bitfield {
- fn name(&self) -> Option<&str> {
- self.data.name()
- }
-
- fn ty(&self) -> TypeId {
- self.data.ty()
- }
-
- fn comment(&self) -> Option<&str> {
- self.data.comment()
- }
-
- fn bitfield_width(&self) -> Option<u32> {
- self.data.bitfield_width()
- }
-
- fn is_public(&self) -> bool {
- self.data.is_public()
- }
-
- fn annotations(&self) -> &Annotations {
- self.data.annotations()
- }
-
- fn offset(&self) -> Option<usize> {
- self.data.offset()
- }
-}
-
-/// A raw field might be either of a plain data member or a bitfield within a
-/// bitfield allocation unit, but we haven't processed it and determined which
-/// yet (which would involve allocating it into a bitfield unit if it is a
-/// bitfield).
-#[derive(Debug)]
-struct RawField(FieldData);
-
-impl RawField {
- /// Construct a new `RawField`.
- fn new(
- name: Option<String>,
- ty: TypeId,
- comment: Option<String>,
- annotations: Option<Annotations>,
- bitfield_width: Option<u32>,
- public: bool,
- offset: Option<usize>,
- ) -> RawField {
- RawField(FieldData {
- name,
- ty,
- comment,
- annotations: annotations.unwrap_or_default(),
- bitfield_width,
- public,
- offset,
- })
- }
-}
-
-impl FieldMethods for RawField {
- fn name(&self) -> Option<&str> {
- self.0.name()
- }
-
- fn ty(&self) -> TypeId {
- self.0.ty()
- }
-
- fn comment(&self) -> Option<&str> {
- self.0.comment()
- }
-
- fn bitfield_width(&self) -> Option<u32> {
- self.0.bitfield_width()
- }
-
- fn is_public(&self) -> bool {
- self.0.is_public()
- }
-
- fn annotations(&self) -> &Annotations {
- self.0.annotations()
- }
-
- fn offset(&self) -> Option<usize> {
- self.0.offset()
- }
-}
-
-/// Convert the given ordered set of raw fields into a list of either plain data
-/// members, and/or bitfield units containing multiple bitfields.
-///
-/// If we do not have the layout for a bitfield's type, then we can't reliably
-/// compute its allocation unit. In such cases, we return an error.
-fn raw_fields_to_fields_and_bitfield_units<I>(
- ctx: &BindgenContext,
- raw_fields: I,
- packed: bool,
-) -> Result<(Vec<Field>, bool), ()>
-where
- I: IntoIterator<Item = RawField>,
-{
- let mut raw_fields = raw_fields.into_iter().fuse().peekable();
- let mut fields = vec![];
- let mut bitfield_unit_count = 0;
-
- loop {
- // While we have plain old data members, just keep adding them to our
- // resulting fields. We introduce a scope here so that we can use
- // `raw_fields` again after the `by_ref` iterator adaptor is dropped.
- {
- let non_bitfields = raw_fields
- .by_ref()
- .peeking_take_while(|f| f.bitfield_width().is_none())
- .map(|f| Field::DataMember(f.0));
- fields.extend(non_bitfields);
- }
-
- // Now gather all the consecutive bitfields. Only consecutive bitfields
- // may potentially share a bitfield allocation unit with each other in
- // the Itanium C++ ABI.
- let mut bitfields = raw_fields
- .by_ref()
- .peeking_take_while(|f| f.bitfield_width().is_some())
- .peekable();
-
- if bitfields.peek().is_none() {
- break;
- }
-
- bitfields_to_allocation_units(
- ctx,
- &mut bitfield_unit_count,
- &mut fields,
- bitfields,
- packed,
- )?;
- }
-
- assert!(
- raw_fields.next().is_none(),
- "The above loop should consume all items in `raw_fields`"
- );
-
- Ok((fields, bitfield_unit_count != 0))
-}
-
-/// Given a set of contiguous raw bitfields, group and allocate them into
-/// (potentially multiple) bitfield units.
-fn bitfields_to_allocation_units<E, I>(
- ctx: &BindgenContext,
- bitfield_unit_count: &mut usize,
- fields: &mut E,
- raw_bitfields: I,
- packed: bool,
-) -> Result<(), ()>
-where
- E: Extend<Field>,
- I: IntoIterator<Item = RawField>,
-{
- assert!(ctx.collected_typerefs());
-
- // NOTE: What follows is reverse-engineered from LLVM's
- // lib/AST/RecordLayoutBuilder.cpp
- //
- // FIXME(emilio): There are some differences between Microsoft and the
- // Itanium ABI, but we'll ignore those and stick to Itanium for now.
- //
- // Also, we need to handle packed bitfields and stuff.
- //
- // TODO(emilio): Take into account C++'s wide bitfields, and
- // packing, sigh.
-
- fn flush_allocation_unit<E>(
- fields: &mut E,
- bitfield_unit_count: &mut usize,
- unit_size_in_bits: usize,
- unit_align_in_bits: usize,
- bitfields: Vec<Bitfield>,
- packed: bool,
- ) where
- E: Extend<Field>,
- {
- *bitfield_unit_count += 1;
- let align = if packed {
- 1
- } else {
- bytes_from_bits_pow2(unit_align_in_bits)
- };
- let size = align_to(unit_size_in_bits, 8) / 8;
- let layout = Layout::new(size, align);
- fields.extend(Some(Field::Bitfields(BitfieldUnit {
- nth: *bitfield_unit_count,
- layout,
- bitfields,
- })));
- }
-
- let mut max_align = 0;
- let mut unfilled_bits_in_unit = 0;
- let mut unit_size_in_bits = 0;
- let mut unit_align = 0;
- let mut bitfields_in_unit = vec![];
-
- // TODO(emilio): Determine this from attributes or pragma ms_struct
- // directives. Also, perhaps we should check if the target is MSVC?
- const is_ms_struct: bool = false;
-
- for bitfield in raw_bitfields {
- let bitfield_width = bitfield.bitfield_width().unwrap() as usize;
- let bitfield_layout =
- ctx.resolve_type(bitfield.ty()).layout(ctx).ok_or(())?;
- let bitfield_size = bitfield_layout.size;
- let bitfield_align = bitfield_layout.align;
-
- let mut offset = unit_size_in_bits;
- if !packed {
- if is_ms_struct {
- if unit_size_in_bits != 0 &&
- (bitfield_width == 0 ||
- bitfield_width > unfilled_bits_in_unit)
- {
- // We've reached the end of this allocation unit, so flush it
- // and its bitfields.
- unit_size_in_bits =
- align_to(unit_size_in_bits, unit_align * 8);
- flush_allocation_unit(
- fields,
- bitfield_unit_count,
- unit_size_in_bits,
- unit_align,
- mem::take(&mut bitfields_in_unit),
- packed,
- );
-
- // Now we're working on a fresh bitfield allocation unit, so reset
- // the current unit size and alignment.
- offset = 0;
- unit_align = 0;
- }
- } else if offset != 0 &&
- (bitfield_width == 0 ||
- (offset & (bitfield_align * 8 - 1)) + bitfield_width >
- bitfield_size * 8)
- {
- offset = align_to(offset, bitfield_align * 8);
- }
- }
-
- // According to the x86[-64] ABI spec: "Unnamed bit-fields’ types do not
- // affect the alignment of a structure or union". This makes sense: such
- // bit-fields are only used for padding, and we can't perform an
- // un-aligned read of something we can't read because we can't even name
- // it.
- if bitfield.name().is_some() {
- max_align = cmp::max(max_align, bitfield_align);
-
- // NB: The `bitfield_width` here is completely, absolutely
- // intentional. Alignment of the allocation unit is based on the
- // maximum bitfield width, not (directly) on the bitfields' types'
- // alignment.
- unit_align = cmp::max(unit_align, bitfield_width);
- }
-
- // Always keep all bitfields around. While unnamed bitifields are used
- // for padding (and usually not needed hereafter), large unnamed
- // bitfields over their types size cause weird allocation size behavior from clang.
- // Therefore, all bitfields needed to be kept around in order to check for this
- // and make the struct opaque in this case
- bitfields_in_unit.push(Bitfield::new(offset, bitfield));
-
- unit_size_in_bits = offset + bitfield_width;
-
- // Compute what the physical unit's final size would be given what we
- // have seen so far, and use that to compute how many bits are still
- // available in the unit.
- let data_size = align_to(unit_size_in_bits, bitfield_align * 8);
- unfilled_bits_in_unit = data_size - unit_size_in_bits;
- }
-
- if unit_size_in_bits != 0 {
- // Flush the last allocation unit and its bitfields.
- flush_allocation_unit(
- fields,
- bitfield_unit_count,
- unit_size_in_bits,
- unit_align,
- bitfields_in_unit,
- packed,
- );
- }
-
- Ok(())
-}
-
-/// A compound structure's fields are initially raw, and have bitfields that
-/// have not been grouped into allocation units. During this time, the fields
-/// are mutable and we build them up during parsing.
-///
-/// Then, once resolving typerefs is completed, we compute all structs' fields'
-/// bitfield allocation units, and they remain frozen and immutable forever
-/// after.
-#[derive(Debug)]
-enum CompFields {
- Before(Vec<RawField>),
- After {
- fields: Vec<Field>,
- has_bitfield_units: bool,
- },
- Error,
-}
-
-impl Default for CompFields {
- fn default() -> CompFields {
- CompFields::Before(vec![])
- }
-}
-
-impl CompFields {
- fn append_raw_field(&mut self, raw: RawField) {
- match *self {
- CompFields::Before(ref mut raws) => {
- raws.push(raw);
- }
- _ => {
- panic!(
- "Must not append new fields after computing bitfield allocation units"
- );
- }
- }
- }
-
- fn compute_bitfield_units(&mut self, ctx: &BindgenContext, packed: bool) {
- let raws = match *self {
- CompFields::Before(ref mut raws) => mem::take(raws),
- _ => {
- panic!("Already computed bitfield units");
- }
- };
-
- let result = raw_fields_to_fields_and_bitfield_units(ctx, raws, packed);
-
- match result {
- Ok((fields, has_bitfield_units)) => {
- *self = CompFields::After {
- fields,
- has_bitfield_units,
- };
- }
- Err(()) => {
- *self = CompFields::Error;
- }
- }
- }
-
- fn deanonymize_fields(&mut self, ctx: &BindgenContext, methods: &[Method]) {
- let fields = match *self {
- CompFields::After { ref mut fields, .. } => fields,
- // Nothing to do here.
- CompFields::Error => return,
- CompFields::Before(_) => {
- panic!("Not yet computed bitfield units.");
- }
- };
-
- fn has_method(
- methods: &[Method],
- ctx: &BindgenContext,
- name: &str,
- ) -> bool {
- methods.iter().any(|method| {
- let method_name = ctx.resolve_func(method.signature()).name();
- method_name == name || ctx.rust_mangle(method_name) == name
- })
- }
-
- struct AccessorNamesPair {
- getter: String,
- setter: String,
- }
-
- let mut accessor_names: HashMap<String, AccessorNamesPair> = fields
- .iter()
- .flat_map(|field| match *field {
- Field::Bitfields(ref bu) => &*bu.bitfields,
- Field::DataMember(_) => &[],
- })
- .filter_map(|bitfield| bitfield.name())
- .map(|bitfield_name| {
- let bitfield_name = bitfield_name.to_string();
- let getter = {
- let mut getter =
- ctx.rust_mangle(&bitfield_name).to_string();
- if has_method(methods, ctx, &getter) {
- getter.push_str("_bindgen_bitfield");
- }
- getter
- };
- let setter = {
- let setter = format!("set_{}", bitfield_name);
- let mut setter = ctx.rust_mangle(&setter).to_string();
- if has_method(methods, ctx, &setter) {
- setter.push_str("_bindgen_bitfield");
- }
- setter
- };
- (bitfield_name, AccessorNamesPair { getter, setter })
- })
- .collect();
-
- let mut anon_field_counter = 0;
- for field in fields.iter_mut() {
- match *field {
- Field::DataMember(FieldData { ref mut name, .. }) => {
- if name.is_some() {
- continue;
- }
-
- anon_field_counter += 1;
- *name = Some(format!(
- "{}{}",
- ctx.options().anon_fields_prefix,
- anon_field_counter
- ));
- }
- Field::Bitfields(ref mut bu) => {
- for bitfield in &mut bu.bitfields {
- if bitfield.name().is_none() {
- continue;
- }
-
- if let Some(AccessorNamesPair { getter, setter }) =
- accessor_names.remove(bitfield.name().unwrap())
- {
- bitfield.getter_name = Some(getter);
- bitfield.setter_name = Some(setter);
- }
- }
- }
- }
- }
- }
-}
-
-impl Trace for CompFields {
- type Extra = ();
-
- fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, _: &())
- where
- T: Tracer,
- {
- match *self {
- CompFields::Error => {}
- CompFields::Before(ref fields) => {
- for f in fields {
- tracer.visit_kind(f.ty().into(), EdgeKind::Field);
- }
- }
- CompFields::After { ref fields, .. } => {
- for f in fields {
- f.trace(context, tracer, &());
- }
- }
- }
- }
-}
-
-/// Common data shared across different field types.
-#[derive(Clone, Debug)]
-pub struct FieldData {
- /// The name of the field, empty if it's an unnamed bitfield width.
- name: Option<String>,
-
- /// The inner type.
- ty: TypeId,
-
- /// The doc comment on the field if any.
- comment: Option<String>,
-
- /// Annotations for this field, or the default.
- annotations: Annotations,
-
- /// If this field is a bitfield, and how many bits does it contain if it is.
- bitfield_width: Option<u32>,
-
- /// If the C++ field is declared `public`
- public: bool,
-
- /// The offset of the field (in bits)
- offset: Option<usize>,
-}
-
-impl FieldMethods for FieldData {
- fn name(&self) -> Option<&str> {
- self.name.as_deref()
- }
-
- fn ty(&self) -> TypeId {
- self.ty
- }
-
- fn comment(&self) -> Option<&str> {
- self.comment.as_deref()
- }
-
- fn bitfield_width(&self) -> Option<u32> {
- self.bitfield_width
- }
-
- fn is_public(&self) -> bool {
- self.public
- }
-
- fn annotations(&self) -> &Annotations {
- &self.annotations
- }
-
- fn offset(&self) -> Option<usize> {
- self.offset
- }
-}
-
-/// The kind of inheritance a base class is using.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum BaseKind {
- /// Normal inheritance, like:
- ///
- /// ```cpp
- /// class A : public B {};
- /// ```
- Normal,
- /// Virtual inheritance, like:
- ///
- /// ```cpp
- /// class A: public virtual B {};
- /// ```
- Virtual,
-}
-
-/// A base class.
-#[derive(Clone, Debug)]
-pub struct Base {
- /// The type of this base class.
- pub ty: TypeId,
- /// The kind of inheritance we're doing.
- pub kind: BaseKind,
- /// Name of the field in which this base should be stored.
- pub field_name: String,
- /// Whether this base is inherited from publically.
- pub is_pub: bool,
-}
-
-impl Base {
- /// Whether this base class is inheriting virtually.
- pub fn is_virtual(&self) -> bool {
- self.kind == BaseKind::Virtual
- }
-
- /// Whether this base class should have it's own field for storage.
- pub fn requires_storage(&self, ctx: &BindgenContext) -> bool {
- // Virtual bases are already taken into account by the vtable
- // pointer.
- //
- // FIXME(emilio): Is this always right?
- if self.is_virtual() {
- return false;
- }
-
- // NB: We won't include zero-sized types in our base chain because they
- // would contribute to our size given the dummy field we insert for
- // zero-sized types.
- if self.ty.is_zero_sized(ctx) {
- return false;
- }
-
- true
- }
-
- /// Whether this base is inherited from publically.
- pub fn is_public(&self) -> bool {
- self.is_pub
- }
-}
-
-/// A compound type.
-///
-/// Either a struct or union, a compound type is built up from the combination
-/// of fields which also are associated with their own (potentially compound)
-/// type.
-#[derive(Debug)]
-pub struct CompInfo {
- /// Whether this is a struct or a union.
- kind: CompKind,
-
- /// The members of this struct or union.
- fields: CompFields,
-
- /// The abstract template parameters of this class. Note that these are NOT
- /// concrete template arguments, and should always be a
- /// `Type(TypeKind::TypeParam(name))`. For concrete template arguments, see
- /// `TypeKind::TemplateInstantiation`.
- template_params: Vec<TypeId>,
-
- /// The method declarations inside this class, if in C++ mode.
- methods: Vec<Method>,
-
- /// The different constructors this struct or class contains.
- constructors: Vec<FunctionId>,
-
- /// The destructor of this type. The bool represents whether this destructor
- /// is virtual.
- destructor: Option<(MethodKind, FunctionId)>,
-
- /// Vector of classes this one inherits from.
- base_members: Vec<Base>,
-
- /// The inner types that were declared inside this class, in something like:
- ///
- /// class Foo {
- /// typedef int FooTy;
- /// struct Bar {
- /// int baz;
- /// };
- /// }
- ///
- /// static Foo::Bar const = {3};
- inner_types: Vec<TypeId>,
-
- /// Set of static constants declared inside this class.
- inner_vars: Vec<VarId>,
-
- /// Whether this type should generate an vtable (TODO: Should be able to
- /// look at the virtual methods and ditch this field).
- has_own_virtual_method: bool,
-
- /// Whether this type has destructor.
- has_destructor: bool,
-
- /// Whether this type has a base type with more than one member.
- ///
- /// TODO: We should be able to compute this.
- has_nonempty_base: bool,
-
- /// If this type has a template parameter which is not a type (e.g.: a
- /// size_t)
- has_non_type_template_params: bool,
-
- /// Whether this type has a bit field member whose width couldn't be
- /// evaluated (e.g. if it depends on a template parameter). We generate an
- /// opaque type in this case.
- has_unevaluable_bit_field_width: bool,
-
- /// Whether we saw `__attribute__((packed))` on or within this type.
- packed_attr: bool,
-
- /// Used to know if we've found an opaque attribute that could cause us to
- /// generate a type with invalid layout. This is explicitly used to avoid us
- /// generating bad alignments when parsing types like max_align_t.
- ///
- /// It's not clear what the behavior should be here, if generating the item
- /// and pray, or behave as an opaque type.
- found_unknown_attr: bool,
-
- /// Used to indicate when a struct has been forward declared. Usually used
- /// in headers so that APIs can't modify them directly.
- is_forward_declaration: bool,
-}
-
-impl CompInfo {
- /// Construct a new compound type.
- pub fn new(kind: CompKind) -> Self {
- CompInfo {
- kind,
- fields: CompFields::default(),
- template_params: vec![],
- methods: vec![],
- constructors: vec![],
- destructor: None,
- base_members: vec![],
- inner_types: vec![],
- inner_vars: vec![],
- has_own_virtual_method: false,
- has_destructor: false,
- has_nonempty_base: false,
- has_non_type_template_params: false,
- has_unevaluable_bit_field_width: false,
- packed_attr: false,
- found_unknown_attr: false,
- is_forward_declaration: false,
- }
- }
-
- /// Compute the layout of this type.
- ///
- /// This is called as a fallback under some circumstances where LLVM doesn't
- /// give us the correct layout.
- ///
- /// If we're a union without known layout, we try to compute it from our
- /// members. This is not ideal, but clang fails to report the size for these
- /// kind of unions, see test/headers/template_union.hpp
- pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
- // We can't do better than clang here, sorry.
- if self.kind == CompKind::Struct {
- return None;
- }
-
- // By definition, we don't have the right layout information here if
- // we're a forward declaration.
- if self.is_forward_declaration() {
- return None;
- }
-
- // empty union case
- if !self.has_fields() {
- return None;
- }
-
- let mut max_size = 0;
- // Don't allow align(0)
- let mut max_align = 1;
- self.each_known_field_layout(ctx, |layout| {
- max_size = cmp::max(max_size, layout.size);
- max_align = cmp::max(max_align, layout.align);
- });
-
- Some(Layout::new(max_size, max_align))
- }
-
- /// Get this type's set of fields.
- pub fn fields(&self) -> &[Field] {
- match self.fields {
- CompFields::Error => &[],
- CompFields::After { ref fields, .. } => fields,
- CompFields::Before(..) => {
- panic!("Should always have computed bitfield units first");
- }
- }
- }
-
- fn has_fields(&self) -> bool {
- match self.fields {
- CompFields::Error => false,
- CompFields::After { ref fields, .. } => !fields.is_empty(),
- CompFields::Before(ref raw_fields) => !raw_fields.is_empty(),
- }
- }
-
- fn each_known_field_layout(
- &self,
- ctx: &BindgenContext,
- mut callback: impl FnMut(Layout),
- ) {
- match self.fields {
- CompFields::Error => {}
- CompFields::After { ref fields, .. } => {
- for field in fields.iter() {
- if let Some(layout) = field.layout(ctx) {
- callback(layout);
- }
- }
- }
- CompFields::Before(ref raw_fields) => {
- for field in raw_fields.iter() {
- let field_ty = ctx.resolve_type(field.0.ty);
- if let Some(layout) = field_ty.layout(ctx) {
- callback(layout);
- }
- }
- }
- }
- }
-
- fn has_bitfields(&self) -> bool {
- match self.fields {
- CompFields::Error => false,
- CompFields::After {
- has_bitfield_units, ..
- } => has_bitfield_units,
- CompFields::Before(_) => {
- panic!("Should always have computed bitfield units first");
- }
- }
- }
-
- /// Returns whether we have a too large bitfield unit, in which case we may
- /// not be able to derive some of the things we should be able to normally
- /// derive.
- pub fn has_too_large_bitfield_unit(&self) -> bool {
- if !self.has_bitfields() {
- return false;
- }
- self.fields().iter().any(|field| match *field {
- Field::DataMember(..) => false,
- Field::Bitfields(ref unit) => {
- unit.layout.size > RUST_DERIVE_IN_ARRAY_LIMIT
- }
- })
- }
-
- /// Does this type have any template parameters that aren't types
- /// (e.g. int)?
- pub fn has_non_type_template_params(&self) -> bool {
- self.has_non_type_template_params
- }
-
- /// Do we see a virtual function during parsing?
- /// Get the has_own_virtual_method boolean.
- pub fn has_own_virtual_method(&self) -> bool {
- self.has_own_virtual_method
- }
-
- /// Did we see a destructor when parsing this type?
- pub fn has_own_destructor(&self) -> bool {
- self.has_destructor
- }
-
- /// Get this type's set of methods.
- pub fn methods(&self) -> &[Method] {
- &self.methods
- }
-
- /// Get this type's set of constructors.
- pub fn constructors(&self) -> &[FunctionId] {
- &self.constructors
- }
-
- /// Get this type's destructor.
- pub fn destructor(&self) -> Option<(MethodKind, FunctionId)> {
- self.destructor
- }
-
- /// What kind of compound type is this?
- pub fn kind(&self) -> CompKind {
- self.kind
- }
-
- /// Is this a union?
- pub fn is_union(&self) -> bool {
- self.kind() == CompKind::Union
- }
-
- /// The set of types that this one inherits from.
- pub fn base_members(&self) -> &[Base] {
- &self.base_members
- }
-
- /// Construct a new compound type from a Clang type.
- pub fn from_ty(
- potential_id: ItemId,
- ty: &clang::Type,
- location: Option<clang::Cursor>,
- ctx: &mut BindgenContext,
- ) -> Result<Self, ParseError> {
- use clang_sys::*;
- assert!(
- ty.template_args().is_none(),
- "We handle template instantiations elsewhere"
- );
-
- let mut cursor = ty.declaration();
- let mut kind = Self::kind_from_cursor(&cursor);
- if kind.is_err() {
- if let Some(location) = location {
- kind = Self::kind_from_cursor(&location);
- cursor = location;
- }
- }
-
- let kind = kind?;
-
- debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor);
-
- let mut ci = CompInfo::new(kind);
- ci.is_forward_declaration =
- location.map_or(true, |cur| match cur.kind() {
- CXCursor_ParmDecl => true,
- CXCursor_StructDecl | CXCursor_UnionDecl |
- CXCursor_ClassDecl => !cur.is_definition(),
- _ => false,
- });
-
- let mut maybe_anonymous_struct_field = None;
- cursor.visit(|cur| {
- if cur.kind() != CXCursor_FieldDecl {
- if let Some((ty, clang_ty, public, offset)) =
- maybe_anonymous_struct_field.take()
- {
- if cur.kind() == CXCursor_TypedefDecl &&
- cur.typedef_type().unwrap().canonical_type() ==
- clang_ty
- {
- // Typedefs of anonymous structs appear later in the ast
- // than the struct itself, that would otherwise be an
- // anonymous field. Detect that case here, and do
- // nothing.
- } else {
- let field = RawField::new(
- None, ty, None, None, None, public, offset,
- );
- ci.fields.append_raw_field(field);
- }
- }
- }
-
- match cur.kind() {
- CXCursor_FieldDecl => {
- if let Some((ty, clang_ty, public, offset)) =
- maybe_anonymous_struct_field.take()
- {
- let mut used = false;
- cur.visit(|child| {
- if child.cur_type() == clang_ty {
- used = true;
- }
- CXChildVisit_Continue
- });
-
- if !used {
- let field = RawField::new(
- None, ty, None, None, None, public, offset,
- );
- ci.fields.append_raw_field(field);
- }
- }
-
- let bit_width = if cur.is_bit_field() {
- let width = cur.bit_width();
-
- // Make opaque type if the bit width couldn't be
- // evaluated.
- if width.is_none() {
- ci.has_unevaluable_bit_field_width = true;
- return CXChildVisit_Break;
- }
-
- width
- } else {
- None
- };
-
- let field_type = Item::from_ty_or_ref(
- cur.cur_type(),
- cur,
- Some(potential_id),
- ctx,
- );
-
- let comment = cur.raw_comment();
- let annotations = Annotations::new(&cur);
- let name = cur.spelling();
- let is_public = cur.public_accessible();
- let offset = cur.offset_of_field().ok();
-
- // Name can be empty if there are bitfields, for example,
- // see tests/headers/struct_with_bitfields.h
- assert!(
- !name.is_empty() || bit_width.is_some(),
- "Empty field name?"
- );
-
- let name = if name.is_empty() { None } else { Some(name) };
-
- let field = RawField::new(
- name,
- field_type,
- comment,
- annotations,
- bit_width,
- is_public,
- offset,
- );
- ci.fields.append_raw_field(field);
-
- // No we look for things like attributes and stuff.
- cur.visit(|cur| {
- if cur.kind() == CXCursor_UnexposedAttr {
- ci.found_unknown_attr = true;
- }
- CXChildVisit_Continue
- });
- }
- CXCursor_UnexposedAttr => {
- ci.found_unknown_attr = true;
- }
- CXCursor_EnumDecl |
- CXCursor_TypeAliasDecl |
- CXCursor_TypeAliasTemplateDecl |
- CXCursor_TypedefDecl |
- CXCursor_StructDecl |
- CXCursor_UnionDecl |
- CXCursor_ClassTemplate |
- CXCursor_ClassDecl => {
- // We can find non-semantic children here, clang uses a
- // StructDecl to note incomplete structs that haven't been
- // forward-declared before, see [1].
- //
- // Also, clang seems to scope struct definitions inside
- // unions, and other named struct definitions inside other
- // structs to the whole translation unit.
- //
- // Let's just assume that if the cursor we've found is a
- // definition, it's a valid inner type.
- //
- // [1]: https://github.com/rust-lang/rust-bindgen/issues/482
- let is_inner_struct =
- cur.semantic_parent() == cursor || cur.is_definition();
- if !is_inner_struct {
- return CXChildVisit_Continue;
- }
-
- // Even if this is a definition, we may not be the semantic
- // parent, see #1281.
- let inner = Item::parse(cur, Some(potential_id), ctx)
- .expect("Inner ClassDecl");
-
- // If we avoided recursion parsing this type (in
- // `Item::from_ty_with_id()`), then this might not be a
- // valid type ID, so check and gracefully handle this.
- if ctx.resolve_item_fallible(inner).is_some() {
- let inner = inner.expect_type_id(ctx);
-
- ci.inner_types.push(inner);
-
- // A declaration of an union or a struct without name
- // could also be an unnamed field, unfortunately.
- if cur.spelling().is_empty() &&
- cur.kind() != CXCursor_EnumDecl
- {
- let ty = cur.cur_type();
- let public = cur.public_accessible();
- let offset = cur.offset_of_field().ok();
-
- maybe_anonymous_struct_field =
- Some((inner, ty, public, offset));
- }
- }
- }
- CXCursor_PackedAttr => {
- ci.packed_attr = true;
- }
- CXCursor_TemplateTypeParameter => {
- let param = Item::type_param(None, cur, ctx).expect(
- "Item::type_param should't fail when pointing \
- at a TemplateTypeParameter",
- );
- ci.template_params.push(param);
- }
- CXCursor_CXXBaseSpecifier => {
- let is_virtual_base = cur.is_virtual_base();
- ci.has_own_virtual_method |= is_virtual_base;
-
- let kind = if is_virtual_base {
- BaseKind::Virtual
- } else {
- BaseKind::Normal
- };
-
- let field_name = match ci.base_members.len() {
- 0 => "_base".into(),
- n => format!("_base_{}", n),
- };
- let type_id =
- Item::from_ty_or_ref(cur.cur_type(), cur, None, ctx);
- ci.base_members.push(Base {
- ty: type_id,
- kind,
- field_name,
- is_pub: cur.access_specifier() ==
- clang_sys::CX_CXXPublic,
- });
- }
- CXCursor_Constructor | CXCursor_Destructor |
- CXCursor_CXXMethod => {
- let is_virtual = cur.method_is_virtual();
- let is_static = cur.method_is_static();
- debug_assert!(!(is_static && is_virtual), "How?");
-
- ci.has_destructor |= cur.kind() == CXCursor_Destructor;
- ci.has_own_virtual_method |= is_virtual;
-
- // This used to not be here, but then I tried generating
- // stylo bindings with this (without path filters), and
- // cried a lot with a method in gfx/Point.h
- // (ToUnknownPoint), that somehow was causing the same type
- // to be inserted in the map two times.
- //
- // I couldn't make a reduced test case, but anyway...
- // Methods of template functions not only used to be inlined,
- // but also instantiated, and we wouldn't be able to call
- // them, so just bail out.
- if !ci.template_params.is_empty() {
- return CXChildVisit_Continue;
- }
-
- // NB: This gets us an owned `Function`, not a
- // `FunctionSig`.
- let signature =
- match Item::parse(cur, Some(potential_id), ctx) {
- Ok(item)
- if ctx
- .resolve_item(item)
- .kind()
- .is_function() =>
- {
- item
- }
- _ => return CXChildVisit_Continue,
- };
-
- let signature = signature.expect_function_id(ctx);
-
- match cur.kind() {
- CXCursor_Constructor => {
- ci.constructors.push(signature);
- }
- CXCursor_Destructor => {
- let kind = if is_virtual {
- MethodKind::VirtualDestructor {
- pure_virtual: cur.method_is_pure_virtual(),
- }
- } else {
- MethodKind::Destructor
- };
- ci.destructor = Some((kind, signature));
- }
- CXCursor_CXXMethod => {
- let is_const = cur.method_is_const();
- let method_kind = if is_static {
- MethodKind::Static
- } else if is_virtual {
- MethodKind::Virtual {
- pure_virtual: cur.method_is_pure_virtual(),
- }
- } else {
- MethodKind::Normal
- };
-
- let method =
- Method::new(method_kind, signature, is_const);
-
- ci.methods.push(method);
- }
- _ => unreachable!("How can we see this here?"),
- }
- }
- CXCursor_NonTypeTemplateParameter => {
- ci.has_non_type_template_params = true;
- }
- CXCursor_VarDecl => {
- let linkage = cur.linkage();
- if linkage != CXLinkage_External &&
- linkage != CXLinkage_UniqueExternal
- {
- return CXChildVisit_Continue;
- }
-
- let visibility = cur.visibility();
- if visibility != CXVisibility_Default {
- return CXChildVisit_Continue;
- }
-
- if let Ok(item) = Item::parse(cur, Some(potential_id), ctx)
- {
- ci.inner_vars.push(item.as_var_id_unchecked());
- }
- }
- // Intentionally not handled
- CXCursor_CXXAccessSpecifier |
- CXCursor_CXXFinalAttr |
- CXCursor_FunctionTemplate |
- CXCursor_ConversionFunction => {}
- _ => {
- warn!(
- "unhandled comp member `{}` (kind {:?}) in `{}` ({})",
- cur.spelling(),
- clang::kind_to_str(cur.kind()),
- cursor.spelling(),
- cur.location()
- );
- }
- }
- CXChildVisit_Continue
- });
-
- if let Some((ty, _, public, offset)) = maybe_anonymous_struct_field {
- let field =
- RawField::new(None, ty, None, None, None, public, offset);
- ci.fields.append_raw_field(field);
- }
-
- Ok(ci)
- }
-
- fn kind_from_cursor(
- cursor: &clang::Cursor,
- ) -> Result<CompKind, ParseError> {
- use clang_sys::*;
- Ok(match cursor.kind() {
- CXCursor_UnionDecl => CompKind::Union,
- CXCursor_ClassDecl | CXCursor_StructDecl => CompKind::Struct,
- CXCursor_CXXBaseSpecifier |
- CXCursor_ClassTemplatePartialSpecialization |
- CXCursor_ClassTemplate => match cursor.template_kind() {
- CXCursor_UnionDecl => CompKind::Union,
- _ => CompKind::Struct,
- },
- _ => {
- warn!("Unknown kind for comp type: {:?}", cursor);
- return Err(ParseError::Continue);
- }
- })
- }
-
- /// Get the set of types that were declared within this compound type
- /// (e.g. nested class definitions).
- pub fn inner_types(&self) -> &[TypeId] {
- &self.inner_types
- }
-
- /// Get the set of static variables declared within this compound type.
- pub fn inner_vars(&self) -> &[VarId] {
- &self.inner_vars
- }
-
- /// Have we found a field with an opaque type that could potentially mess up
- /// the layout of this compound type?
- pub fn found_unknown_attr(&self) -> bool {
- self.found_unknown_attr
- }
-
- /// Is this compound type packed?
- pub fn is_packed(
- &self,
- ctx: &BindgenContext,
- layout: Option<&Layout>,
- ) -> bool {
- if self.packed_attr {
- return true;
- }
-
- // Even though `libclang` doesn't expose `#pragma packed(...)`, we can
- // detect it through its effects.
- if let Some(parent_layout) = layout {
- let mut packed = false;
- self.each_known_field_layout(ctx, |layout| {
- packed = packed || layout.align > parent_layout.align;
- });
- if packed {
- info!("Found a struct that was defined within `#pragma packed(...)`");
- return true;
- }
-
- if self.has_own_virtual_method && parent_layout.align == 1 {
- return true;
- }
- }
-
- false
- }
-
- /// Returns true if compound type has been forward declared
- pub fn is_forward_declaration(&self) -> bool {
- self.is_forward_declaration
- }
-
- /// Compute this compound structure's bitfield allocation units.
- pub fn compute_bitfield_units(
- &mut self,
- ctx: &BindgenContext,
- layout: Option<&Layout>,
- ) {
- let packed = self.is_packed(ctx, layout);
- self.fields.compute_bitfield_units(ctx, packed)
- }
-
- /// Assign for each anonymous field a generated name.
- pub fn deanonymize_fields(&mut self, ctx: &BindgenContext) {
- self.fields.deanonymize_fields(ctx, &self.methods);
- }
-
- /// Returns whether the current union can be represented as a Rust `union`
- ///
- /// Requirements:
- /// 1. Current RustTarget allows for `untagged_union`
- /// 2. Each field can derive `Copy` or we use ManuallyDrop.
- /// 3. It's not zero-sized.
- ///
- /// Second boolean returns whether all fields can be copied (and thus
- /// ManuallyDrop is not needed).
- pub fn is_rust_union(
- &self,
- ctx: &BindgenContext,
- layout: Option<&Layout>,
- name: &str,
- ) -> (bool, bool) {
- if !self.is_union() {
- return (false, false);
- }
-
- if !ctx.options().rust_features().untagged_union {
- return (false, false);
- }
-
- if self.is_forward_declaration() {
- return (false, false);
- }
-
- let union_style = if ctx.options().bindgen_wrapper_union.matches(name) {
- NonCopyUnionStyle::BindgenWrapper
- } else if ctx.options().manually_drop_union.matches(name) {
- NonCopyUnionStyle::ManuallyDrop
- } else {
- ctx.options().default_non_copy_union_style
- };
-
- let all_can_copy = self.fields().iter().all(|f| match *f {
- Field::DataMember(ref field_data) => {
- field_data.ty().can_derive_copy(ctx)
- }
- Field::Bitfields(_) => true,
- });
-
- if !all_can_copy && union_style == NonCopyUnionStyle::BindgenWrapper {
- return (false, false);
- }
-
- if layout.map_or(false, |l| l.size == 0) {
- return (false, false);
- }
-
- (true, all_can_copy)
- }
-}
-
-impl DotAttributes for CompInfo {
- fn dot_attributes<W>(
- &self,
- ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write,
- {
- writeln!(out, "<tr><td>CompKind</td><td>{:?}</td></tr>", self.kind)?;
-
- if self.has_own_virtual_method {
- writeln!(out, "<tr><td>has_vtable</td><td>true</td></tr>")?;
- }
-
- if self.has_destructor {
- writeln!(out, "<tr><td>has_destructor</td><td>true</td></tr>")?;
- }
-
- if self.has_nonempty_base {
- writeln!(out, "<tr><td>has_nonempty_base</td><td>true</td></tr>")?;
- }
-
- if self.has_non_type_template_params {
- writeln!(
- out,
- "<tr><td>has_non_type_template_params</td><td>true</td></tr>"
- )?;
- }
-
- if self.packed_attr {
- writeln!(out, "<tr><td>packed_attr</td><td>true</td></tr>")?;
- }
-
- if self.is_forward_declaration {
- writeln!(
- out,
- "<tr><td>is_forward_declaration</td><td>true</td></tr>"
- )?;
- }
-
- if !self.fields().is_empty() {
- writeln!(out, r#"<tr><td>fields</td><td><table border="0">"#)?;
- for field in self.fields() {
- field.dot_attributes(ctx, out)?;
- }
- writeln!(out, "</table></td></tr>")?;
- }
-
- Ok(())
- }
-}
-
-impl IsOpaque for CompInfo {
- type Extra = Option<Layout>;
-
- fn is_opaque(&self, ctx: &BindgenContext, layout: &Option<Layout>) -> bool {
- if self.has_non_type_template_params ||
- self.has_unevaluable_bit_field_width
- {
- return true;
- }
-
- // When we do not have the layout for a bitfield's type (for example, it
- // is a type parameter), then we can't compute bitfield units. We are
- // left with no choice but to make the whole struct opaque, or else we
- // might generate structs with incorrect sizes and alignments.
- if let CompFields::Error = self.fields {
- return true;
- }
-
- // Bitfields with a width that is larger than their unit's width have
- // some strange things going on, and the best we can do is make the
- // whole struct opaque.
- if self.fields().iter().any(|f| match *f {
- Field::DataMember(_) => false,
- Field::Bitfields(ref unit) => unit.bitfields().iter().any(|bf| {
- let bitfield_layout = ctx
- .resolve_type(bf.ty())
- .layout(ctx)
- .expect("Bitfield without layout? Gah!");
- bf.width() / 8 > bitfield_layout.size as u32
- }),
- }) {
- return true;
- }
-
- if !ctx.options().rust_features().repr_packed_n {
- // If we don't have `#[repr(packed(N)]`, the best we can
- // do is make this struct opaque.
- //
- // See https://github.com/rust-lang/rust-bindgen/issues/537 and
- // https://github.com/rust-lang/rust/issues/33158
- if self.is_packed(ctx, layout.as_ref()) &&
- layout.map_or(false, |l| l.align > 1)
- {
- warn!("Found a type that is both packed and aligned to greater than \
- 1; Rust before version 1.33 doesn't have `#[repr(packed(N))]`, so we \
- are treating it as opaque. You may wish to set bindgen's rust target \
- version to 1.33 or later to enable `#[repr(packed(N))]` support.");
- return true;
- }
- }
-
- false
- }
-}
-
-impl TemplateParameters for CompInfo {
- fn self_template_params(&self, _ctx: &BindgenContext) -> Vec<TypeId> {
- self.template_params.clone()
- }
-}
-
-impl Trace for CompInfo {
- type Extra = Item;
-
- fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
- where
- T: Tracer,
- {
- for p in item.all_template_params(context) {
- tracer.visit_kind(p.into(), EdgeKind::TemplateParameterDefinition);
- }
-
- for ty in self.inner_types() {
- tracer.visit_kind(ty.into(), EdgeKind::InnerType);
- }
-
- for &var in self.inner_vars() {
- tracer.visit_kind(var.into(), EdgeKind::InnerVar);
- }
-
- for method in self.methods() {
- tracer.visit_kind(method.signature.into(), EdgeKind::Method);
- }
-
- if let Some((_kind, signature)) = self.destructor() {
- tracer.visit_kind(signature.into(), EdgeKind::Destructor);
- }
-
- for ctor in self.constructors() {
- tracer.visit_kind(ctor.into(), EdgeKind::Constructor);
- }
-
- // Base members and fields are not generated for opaque types (but all
- // of the above things are) so stop here.
- if item.is_opaque(context, &()) {
- return;
- }
-
- for base in self.base_members() {
- tracer.visit_kind(base.ty.into(), EdgeKind::BaseMember);
- }
-
- self.fields.trace(context, tracer, &());
- }
-}
diff --git a/src/ir/context.rs b/src/ir/context.rs
deleted file mode 100644
index 12373952..00000000
--- a/src/ir/context.rs
+++ /dev/null
@@ -1,2855 +0,0 @@
-//! Common context that is passed around during parsing and codegen.
-
-use super::super::time::Timer;
-use super::analysis::{
- analyze, as_cannot_derive_set, CannotDerive, DeriveTrait,
- HasDestructorAnalysis, HasFloat, HasTypeParameterInArray,
- HasVtableAnalysis, HasVtableResult, SizednessAnalysis, SizednessResult,
- UsedTemplateParameters,
-};
-use super::derive::{
- CanDerive, CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq,
- CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd,
-};
-use super::function::Function;
-use super::int::IntKind;
-use super::item::{IsOpaque, Item, ItemAncestors, ItemSet};
-use super::item_kind::ItemKind;
-use super::module::{Module, ModuleKind};
-use super::template::{TemplateInstantiation, TemplateParameters};
-use super::traversal::{self, Edge, ItemTraversal};
-use super::ty::{FloatKind, Type, TypeKind};
-use crate::callbacks::ParseCallbacks;
-use crate::clang::{self, Cursor};
-use crate::parse::ClangItemParser;
-use crate::BindgenOptions;
-use crate::{Entry, HashMap, HashSet};
-use cexpr;
-use clang_sys;
-use proc_macro2::{Ident, Span};
-use std::borrow::Cow;
-use std::cell::{Cell, RefCell};
-use std::collections::{BTreeSet, HashMap as StdHashMap};
-use std::iter::IntoIterator;
-use std::mem;
-
-/// An identifier for some kind of IR item.
-#[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)]
-pub struct ItemId(usize);
-
-macro_rules! item_id_newtype {
- (
- $( #[$attr:meta] )*
- pub struct $name:ident(ItemId)
- where
- $( #[$checked_attr:meta] )*
- checked = $checked:ident with $check_method:ident,
- $( #[$expected_attr:meta] )*
- expected = $expected:ident,
- $( #[$unchecked_attr:meta] )*
- unchecked = $unchecked:ident;
- ) => {
- $( #[$attr] )*
- #[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)]
- pub struct $name(ItemId);
-
- impl $name {
- /// Create an `ItemResolver` from this id.
- pub fn into_resolver(self) -> ItemResolver {
- let id: ItemId = self.into();
- id.into()
- }
- }
-
- impl<T> ::std::cmp::PartialEq<T> for $name
- where
- T: Copy + Into<ItemId>
- {
- fn eq(&self, rhs: &T) -> bool {
- let rhs: ItemId = (*rhs).into();
- self.0 == rhs
- }
- }
-
- impl From<$name> for ItemId {
- fn from(id: $name) -> ItemId {
- id.0
- }
- }
-
- impl<'a> From<&'a $name> for ItemId {
- fn from(id: &'a $name) -> ItemId {
- id.0
- }
- }
-
- impl ItemId {
- $( #[$checked_attr] )*
- pub fn $checked(&self, ctx: &BindgenContext) -> Option<$name> {
- if ctx.resolve_item(*self).kind().$check_method() {
- Some($name(*self))
- } else {
- None
- }
- }
-
- $( #[$expected_attr] )*
- pub fn $expected(&self, ctx: &BindgenContext) -> $name {
- self.$checked(ctx)
- .expect(concat!(
- stringify!($expected),
- " called with ItemId that points to the wrong ItemKind"
- ))
- }
-
- $( #[$unchecked_attr] )*
- pub fn $unchecked(&self) -> $name {
- $name(*self)
- }
- }
- }
-}
-
-item_id_newtype! {
- /// An identifier for an `Item` whose `ItemKind` is known to be
- /// `ItemKind::Type`.
- pub struct TypeId(ItemId)
- where
- /// Convert this `ItemId` into a `TypeId` if its associated item is a type,
- /// otherwise return `None`.
- checked = as_type_id with is_type,
-
- /// Convert this `ItemId` into a `TypeId`.
- ///
- /// If this `ItemId` does not point to a type, then panic.
- expected = expect_type_id,
-
- /// Convert this `ItemId` into a `TypeId` without actually checking whether
- /// this id actually points to a `Type`.
- unchecked = as_type_id_unchecked;
-}
-
-item_id_newtype! {
- /// An identifier for an `Item` whose `ItemKind` is known to be
- /// `ItemKind::Module`.
- pub struct ModuleId(ItemId)
- where
- /// Convert this `ItemId` into a `ModuleId` if its associated item is a
- /// module, otherwise return `None`.
- checked = as_module_id with is_module,
-
- /// Convert this `ItemId` into a `ModuleId`.
- ///
- /// If this `ItemId` does not point to a module, then panic.
- expected = expect_module_id,
-
- /// Convert this `ItemId` into a `ModuleId` without actually checking
- /// whether this id actually points to a `Module`.
- unchecked = as_module_id_unchecked;
-}
-
-item_id_newtype! {
- /// An identifier for an `Item` whose `ItemKind` is known to be
- /// `ItemKind::Var`.
- pub struct VarId(ItemId)
- where
- /// Convert this `ItemId` into a `VarId` if its associated item is a var,
- /// otherwise return `None`.
- checked = as_var_id with is_var,
-
- /// Convert this `ItemId` into a `VarId`.
- ///
- /// If this `ItemId` does not point to a var, then panic.
- expected = expect_var_id,
-
- /// Convert this `ItemId` into a `VarId` without actually checking whether
- /// this id actually points to a `Var`.
- unchecked = as_var_id_unchecked;
-}
-
-item_id_newtype! {
- /// An identifier for an `Item` whose `ItemKind` is known to be
- /// `ItemKind::Function`.
- pub struct FunctionId(ItemId)
- where
- /// Convert this `ItemId` into a `FunctionId` if its associated item is a function,
- /// otherwise return `None`.
- checked = as_function_id with is_function,
-
- /// Convert this `ItemId` into a `FunctionId`.
- ///
- /// If this `ItemId` does not point to a function, then panic.
- expected = expect_function_id,
-
- /// Convert this `ItemId` into a `FunctionId` without actually checking whether
- /// this id actually points to a `Function`.
- unchecked = as_function_id_unchecked;
-}
-
-impl From<ItemId> for usize {
- fn from(id: ItemId) -> usize {
- id.0
- }
-}
-
-impl ItemId {
- /// Get a numeric representation of this id.
- pub fn as_usize(&self) -> usize {
- (*self).into()
- }
-}
-
-impl<T> ::std::cmp::PartialEq<T> for ItemId
-where
- T: Copy + Into<ItemId>,
-{
- fn eq(&self, rhs: &T) -> bool {
- let rhs: ItemId = (*rhs).into();
- self.0 == rhs.0
- }
-}
-
-impl<T> CanDeriveDebug for T
-where
- T: Copy + Into<ItemId>,
-{
- fn can_derive_debug(&self, ctx: &BindgenContext) -> bool {
- ctx.options().derive_debug && ctx.lookup_can_derive_debug(*self)
- }
-}
-
-impl<T> CanDeriveDefault for T
-where
- T: Copy + Into<ItemId>,
-{
- fn can_derive_default(&self, ctx: &BindgenContext) -> bool {
- ctx.options().derive_default && ctx.lookup_can_derive_default(*self)
- }
-}
-
-impl<T> CanDeriveCopy for T
-where
- T: Copy + Into<ItemId>,
-{
- fn can_derive_copy(&self, ctx: &BindgenContext) -> bool {
- ctx.options().derive_copy && ctx.lookup_can_derive_copy(*self)
- }
-}
-
-impl<T> CanDeriveHash for T
-where
- T: Copy + Into<ItemId>,
-{
- fn can_derive_hash(&self, ctx: &BindgenContext) -> bool {
- ctx.options().derive_hash && ctx.lookup_can_derive_hash(*self)
- }
-}
-
-impl<T> CanDerivePartialOrd for T
-where
- T: Copy + Into<ItemId>,
-{
- fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool {
- ctx.options().derive_partialord &&
- ctx.lookup_can_derive_partialeq_or_partialord(*self) ==
- CanDerive::Yes
- }
-}
-
-impl<T> CanDerivePartialEq for T
-where
- T: Copy + Into<ItemId>,
-{
- fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool {
- ctx.options().derive_partialeq &&
- ctx.lookup_can_derive_partialeq_or_partialord(*self) ==
- CanDerive::Yes
- }
-}
-
-impl<T> CanDeriveEq for T
-where
- T: Copy + Into<ItemId>,
-{
- fn can_derive_eq(&self, ctx: &BindgenContext) -> bool {
- ctx.options().derive_eq &&
- ctx.lookup_can_derive_partialeq_or_partialord(*self) ==
- CanDerive::Yes &&
- !ctx.lookup_has_float(*self)
- }
-}
-
-impl<T> CanDeriveOrd for T
-where
- T: Copy + Into<ItemId>,
-{
- fn can_derive_ord(&self, ctx: &BindgenContext) -> bool {
- ctx.options().derive_ord &&
- ctx.lookup_can_derive_partialeq_or_partialord(*self) ==
- CanDerive::Yes &&
- !ctx.lookup_has_float(*self)
- }
-}
-
-/// A key used to index a resolved type, so we only process it once.
-///
-/// This is almost always a USR string (an unique identifier generated by
-/// clang), but it can also be the canonical declaration if the type is unnamed,
-/// in which case clang may generate the same USR for multiple nested unnamed
-/// types.
-#[derive(Eq, PartialEq, Hash, Debug)]
-enum TypeKey {
- Usr(String),
- Declaration(Cursor),
-}
-
-/// A context used during parsing and generation of structs.
-#[derive(Debug)]
-pub struct BindgenContext {
- /// The map of all the items parsed so far, keyed off ItemId.
- items: Vec<Option<Item>>,
-
- /// Clang USR to type map. This is needed to be able to associate types with
- /// item ids during parsing.
- types: HashMap<TypeKey, TypeId>,
-
- /// Maps from a cursor to the item id of the named template type parameter
- /// for that cursor.
- type_params: HashMap<clang::Cursor, TypeId>,
-
- /// A cursor to module map. Similar reason than above.
- modules: HashMap<Cursor, ModuleId>,
-
- /// The root module, this is guaranteed to be an item of kind Module.
- root_module: ModuleId,
-
- /// Current module being traversed.
- current_module: ModuleId,
-
- /// A HashMap keyed on a type definition, and whose value is the parent id
- /// of the declaration.
- ///
- /// This is used to handle the cases where the semantic and the lexical
- /// parents of the cursor differ, like when a nested class is defined
- /// outside of the parent class.
- semantic_parents: HashMap<clang::Cursor, ItemId>,
-
- /// A stack with the current type declarations and types we're parsing. This
- /// is needed to avoid infinite recursion when parsing a type like:
- ///
- /// struct c { struct c* next; };
- ///
- /// This means effectively, that a type has a potential ID before knowing if
- /// it's a correct type. But that's not important in practice.
- ///
- /// We could also use the `types` HashMap, but my intention with it is that
- /// only valid types and declarations end up there, and this could
- /// potentially break that assumption.
- currently_parsed_types: Vec<PartialType>,
-
- /// A map with all the already parsed macro names. This is done to avoid
- /// hard errors while parsing duplicated macros, as well to allow macro
- /// expression parsing.
- ///
- /// This needs to be an std::HashMap because the cexpr API requires it.
- parsed_macros: StdHashMap<Vec<u8>, cexpr::expr::EvalResult>,
-
- /// A set of all the included filenames.
- deps: BTreeSet<String>,
-
- /// The active replacements collected from replaces="xxx" annotations.
- replacements: HashMap<Vec<String>, ItemId>,
-
- collected_typerefs: bool,
-
- in_codegen: bool,
-
- /// The translation unit for parsing.
- translation_unit: clang::TranslationUnit,
-
- /// Target information that can be useful for some stuff.
- target_info: clang::TargetInfo,
-
- /// The options given by the user via cli or other medium.
- options: BindgenOptions,
-
- /// Whether a bindgen complex was generated
- generated_bindgen_complex: Cell<bool>,
-
- /// The set of `ItemId`s that are allowlisted. This the very first thing
- /// 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.
- ///
- /// It's computed right after computing the allowlisted items.
- codegen_items: Option<ItemSet>,
-
- /// Map from an item's id to the set of template parameter items that it
- /// uses. See `ir::named` for more details. Always `Some` during the codegen
- /// phase.
- used_template_parameters: Option<HashMap<ItemId, ItemSet>>,
-
- /// The set of `TypeKind::Comp` items found during parsing that need their
- /// bitfield allocation units computed. Drained in `compute_bitfield_units`.
- need_bitfield_allocation: Vec<ItemId>,
-
- /// The set of (`ItemId`s of) types that can't derive debug.
- ///
- /// This is populated when we enter codegen by `compute_cannot_derive_debug`
- /// and is always `None` before that and `Some` after.
- cannot_derive_debug: Option<HashSet<ItemId>>,
-
- /// The set of (`ItemId`s of) types that can't derive default.
- ///
- /// This is populated when we enter codegen by `compute_cannot_derive_default`
- /// and is always `None` before that and `Some` after.
- cannot_derive_default: Option<HashSet<ItemId>>,
-
- /// The set of (`ItemId`s of) types that can't derive copy.
- ///
- /// This is populated when we enter codegen by `compute_cannot_derive_copy`
- /// and is always `None` before that and `Some` after.
- cannot_derive_copy: Option<HashSet<ItemId>>,
-
- /// The set of (`ItemId`s of) types that can't derive hash.
- ///
- /// This is populated when we enter codegen by `compute_can_derive_hash`
- /// and is always `None` before that and `Some` after.
- cannot_derive_hash: Option<HashSet<ItemId>>,
-
- /// The map why specified `ItemId`s of) types that can't derive hash.
- ///
- /// This is populated when we enter codegen by
- /// `compute_cannot_derive_partialord_partialeq_or_eq` and is always `None`
- /// before that and `Some` after.
- cannot_derive_partialeq_or_partialord: Option<HashMap<ItemId, CanDerive>>,
-
- /// The sizedness of types.
- ///
- /// This is populated by `compute_sizedness` and is always `None` before
- /// that function is invoked and `Some` afterwards.
- sizedness: Option<HashMap<TypeId, SizednessResult>>,
-
- /// The set of (`ItemId's of`) types that has vtable.
- ///
- /// Populated when we enter codegen by `compute_has_vtable`; always `None`
- /// before that and `Some` after.
- have_vtable: Option<HashMap<ItemId, HasVtableResult>>,
-
- /// The set of (`ItemId's of`) types that has destructor.
- ///
- /// Populated when we enter codegen by `compute_has_destructor`; always `None`
- /// before that and `Some` after.
- have_destructor: Option<HashSet<ItemId>>,
-
- /// The set of (`ItemId's of`) types that has array.
- ///
- /// Populated when we enter codegen by `compute_has_type_param_in_array`; always `None`
- /// before that and `Some` after.
- has_type_param_in_array: Option<HashSet<ItemId>>,
-
- /// The set of (`ItemId's of`) types that has float.
- ///
- /// Populated when we enter codegen by `compute_has_float`; always `None`
- /// before that and `Some` after.
- has_float: Option<HashSet<ItemId>>,
-
- /// The set of warnings raised during binding generation.
- warnings: Vec<String>,
-}
-
-/// A traversal of allowlisted items.
-struct AllowlistedItemsTraversal<'ctx> {
- ctx: &'ctx BindgenContext,
- traversal: ItemTraversal<'ctx, ItemSet, Vec<ItemId>>,
-}
-
-impl<'ctx> Iterator for AllowlistedItemsTraversal<'ctx> {
- type Item = ItemId;
-
- fn next(&mut self) -> Option<ItemId> {
- loop {
- let id = self.traversal.next()?;
-
- if self.ctx.resolve_item(id).is_blocklisted(self.ctx) {
- continue;
- }
-
- return Some(id);
- }
- }
-}
-
-impl<'ctx> AllowlistedItemsTraversal<'ctx> {
- /// Construct a new allowlisted items traversal.
- pub fn new<R>(
- ctx: &'ctx BindgenContext,
- roots: R,
- predicate: for<'a> fn(&'a BindgenContext, Edge) -> bool,
- ) -> Self
- where
- R: IntoIterator<Item = ItemId>,
- {
- AllowlistedItemsTraversal {
- ctx,
- traversal: ItemTraversal::new(ctx, roots, predicate),
- }
- }
-}
-
-impl BindgenContext {
- /// Construct the context for the given `options`.
- pub(crate) fn new(
- options: BindgenOptions,
- input_unsaved_files: &[clang::UnsavedFile],
- ) -> Self {
- // TODO(emilio): Use the CXTargetInfo here when available.
- //
- // see: https://reviews.llvm.org/D32389
- let index = clang::Index::new(false, true);
-
- let parse_options =
- clang_sys::CXTranslationUnit_DetailedPreprocessingRecord;
-
- let translation_unit = {
- let _t =
- Timer::new("translation_unit").with_output(options.time_phases);
-
- clang::TranslationUnit::parse(
- &index,
- "",
- &options.clang_args,
- input_unsaved_files,
- parse_options,
- ).expect("libclang error; possible causes include:
-- Invalid flag syntax
-- Unrecognized flags
-- Invalid flag arguments
-- File I/O errors
-- Host vs. target architecture mismatch
-If you encounter an error missing from this list, please file an issue or a PR!")
- };
-
- let target_info = clang::TargetInfo::new(&translation_unit);
- let root_module = Self::build_root_module(ItemId(0));
- let root_module_id = root_module.id().as_module_id_unchecked();
-
- // depfiles need to include the explicitly listed headers too
- let mut deps = BTreeSet::default();
- if let Some(filename) = &options.input_header {
- deps.insert(filename.clone());
- }
- deps.extend(options.extra_input_headers.iter().cloned());
-
- BindgenContext {
- items: vec![Some(root_module)],
- deps,
- types: Default::default(),
- type_params: Default::default(),
- modules: Default::default(),
- root_module: root_module_id,
- current_module: root_module_id,
- semantic_parents: Default::default(),
- currently_parsed_types: vec![],
- parsed_macros: Default::default(),
- replacements: Default::default(),
- collected_typerefs: false,
- in_codegen: false,
- translation_unit,
- target_info,
- 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(),
- cannot_derive_debug: None,
- cannot_derive_default: None,
- cannot_derive_copy: None,
- cannot_derive_hash: None,
- cannot_derive_partialeq_or_partialord: None,
- sizedness: None,
- have_vtable: None,
- have_destructor: None,
- has_type_param_in_array: None,
- has_float: None,
- warnings: Vec::new(),
- }
- }
-
- /// Returns `true` if the target architecture is wasm32
- pub fn is_target_wasm32(&self) -> bool {
- self.target_info.triple.starts_with("wasm32-")
- }
-
- /// Creates a timer for the current bindgen phase. If time_phases is `true`,
- /// the timer will print to stderr when it is dropped, otherwise it will do
- /// nothing.
- pub fn timer<'a>(&self, name: &'a str) -> Timer<'a> {
- Timer::new(name).with_output(self.options.time_phases)
- }
-
- /// Returns the pointer width to use for the target for the current
- /// translation.
- pub fn target_pointer_size(&self) -> usize {
- self.target_info.pointer_width / 8
- }
-
- /// Get the stack of partially parsed types that we are in the middle of
- /// parsing.
- pub fn currently_parsed_types(&self) -> &[PartialType] {
- &self.currently_parsed_types[..]
- }
-
- /// Begin parsing the given partial type, and push it onto the
- /// `currently_parsed_types` stack so that we won't infinite recurse if we
- /// run into a reference to it while parsing it.
- pub fn begin_parsing(&mut self, partial_ty: PartialType) {
- self.currently_parsed_types.push(partial_ty);
- }
-
- /// Finish parsing the current partial type, pop it off the
- /// `currently_parsed_types` stack, and return it.
- pub fn finish_parsing(&mut self) -> PartialType {
- self.currently_parsed_types.pop().expect(
- "should have been parsing a type, if we finished parsing a type",
- )
- }
-
- /// Get the user-provided callbacks by reference, if any.
- pub fn parse_callbacks(&self) -> Option<&dyn ParseCallbacks> {
- self.options().parse_callbacks.as_deref()
- }
-
- /// Add another path to the set of included files.
- pub fn include_file(&mut self, filename: String) {
- if let Some(cbs) = self.parse_callbacks() {
- cbs.include_file(&filename);
- }
- self.deps.insert(filename);
- }
-
- /// Get any included files.
- pub fn deps(&self) -> &BTreeSet<String> {
- &self.deps
- }
-
- /// Define a new item.
- ///
- /// This inserts it into the internal items set, and its type into the
- /// internal types set.
- pub fn add_item(
- &mut self,
- item: Item,
- declaration: Option<Cursor>,
- location: Option<Cursor>,
- ) {
- debug!(
- "BindgenContext::add_item({:?}, declaration: {:?}, loc: {:?}",
- item, declaration, location
- );
- debug_assert!(
- declaration.is_some() ||
- !item.kind().is_type() ||
- item.kind().expect_type().is_builtin_or_type_param() ||
- item.kind().expect_type().is_opaque(self, &item) ||
- item.kind().expect_type().is_unresolved_ref(),
- "Adding a type without declaration?"
- );
-
- let id = item.id();
- let is_type = item.kind().is_type();
- let is_unnamed = is_type && item.expect_type().name().is_none();
- let is_template_instantiation =
- is_type && item.expect_type().is_template_instantiation();
-
- if item.id() != self.root_module {
- self.add_item_to_module(&item);
- }
-
- if is_type && item.expect_type().is_comp() {
- self.need_bitfield_allocation.push(id);
- }
-
- let old_item = mem::replace(&mut self.items[id.0], Some(item));
- assert!(
- old_item.is_none(),
- "should not have already associated an item with the given id"
- );
-
- // Unnamed items can have an USR, but they can't be referenced from
- // other sites explicitly and the USR can match if the unnamed items are
- // nested, so don't bother tracking them.
- if !is_type || is_template_instantiation {
- return;
- }
- if let Some(mut declaration) = declaration {
- if !declaration.is_valid() {
- if let Some(location) = location {
- if location.is_template_like() {
- declaration = location;
- }
- }
- }
- declaration = declaration.canonical();
- if !declaration.is_valid() {
- // This could happen, for example, with types like `int*` or
- // similar.
- //
- // Fortunately, we don't care about those types being
- // duplicated, so we can just ignore them.
- debug!(
- "Invalid declaration {:?} found for type {:?}",
- declaration,
- self.resolve_item_fallible(id)
- .unwrap()
- .kind()
- .expect_type()
- );
- return;
- }
-
- let key = if is_unnamed {
- TypeKey::Declaration(declaration)
- } else if let Some(usr) = declaration.usr() {
- TypeKey::Usr(usr)
- } else {
- warn!(
- "Valid declaration with no USR: {:?}, {:?}",
- declaration, location
- );
- TypeKey::Declaration(declaration)
- };
-
- let old = self.types.insert(key, id.as_type_id_unchecked());
- debug_assert_eq!(old, None);
- }
- }
-
- /// Ensure that every item (other than the root module) is in a module's
- /// children list. This is to make sure that every allowlisted item get's
- /// codegen'd, even if its parent is not allowlisted. See issue #769 for
- /// details.
- fn add_item_to_module(&mut self, item: &Item) {
- assert!(item.id() != self.root_module);
- assert!(self.resolve_item_fallible(item.id()).is_none());
-
- if let Some(ref mut parent) = self.items[item.parent_id().0] {
- if let Some(module) = parent.as_module_mut() {
- debug!(
- "add_item_to_module: adding {:?} as child of parent module {:?}",
- item.id(),
- item.parent_id()
- );
-
- module.children_mut().insert(item.id());
- return;
- }
- }
-
- debug!(
- "add_item_to_module: adding {:?} as child of current module {:?}",
- item.id(),
- self.current_module
- );
-
- self.items[(self.current_module.0).0]
- .as_mut()
- .expect("Should always have an item for self.current_module")
- .as_module_mut()
- .expect("self.current_module should always be a module")
- .children_mut()
- .insert(item.id());
- }
-
- /// Add a new named template type parameter to this context's item set.
- pub fn add_type_param(&mut self, item: Item, definition: clang::Cursor) {
- debug!(
- "BindgenContext::add_type_param: item = {:?}; definition = {:?}",
- item, definition
- );
-
- assert!(
- item.expect_type().is_type_param(),
- "Should directly be a named type, not a resolved reference or anything"
- );
- assert_eq!(
- definition.kind(),
- clang_sys::CXCursor_TemplateTypeParameter
- );
-
- self.add_item_to_module(&item);
-
- let id = item.id();
- let old_item = mem::replace(&mut self.items[id.0], Some(item));
- assert!(
- old_item.is_none(),
- "should not have already associated an item with the given id"
- );
-
- let old_named_ty = self
- .type_params
- .insert(definition, id.as_type_id_unchecked());
- assert!(
- old_named_ty.is_none(),
- "should not have already associated a named type with this id"
- );
- }
-
- /// Get the named type defined at the given cursor location, if we've
- /// already added one.
- pub fn get_type_param(&self, definition: &clang::Cursor) -> Option<TypeId> {
- assert_eq!(
- definition.kind(),
- clang_sys::CXCursor_TemplateTypeParameter
- );
- self.type_params.get(definition).cloned()
- }
-
- // TODO: Move all this syntax crap to other part of the code.
-
- /// Mangles a name so it doesn't conflict with any keyword.
- #[rustfmt::skip]
- pub fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> {
- if name.contains('@') ||
- name.contains('?') ||
- name.contains('$') ||
- matches!(
- name,
- "abstract" | "alignof" | "as" | "async" | "await" | "become" |
- "box" | "break" | "const" | "continue" | "crate" | "do" |
- "dyn" | "else" | "enum" | "extern" | "false" | "final" |
- "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" |
- "macro" | "match" | "mod" | "move" | "mut" | "offsetof" |
- "override" | "priv" | "proc" | "pub" | "pure" | "ref" |
- "return" | "Self" | "self" | "sizeof" | "static" |
- "struct" | "super" | "trait" | "true" | "try" | "type" | "typeof" |
- "unsafe" | "unsized" | "use" | "virtual" | "where" |
- "while" | "yield" | "str" | "bool" | "f32" | "f64" |
- "usize" | "isize" | "u128" | "i128" | "u64" | "i64" |
- "u32" | "i32" | "u16" | "i16" | "u8" | "i8" | "_"
- )
- {
- let mut s = name.to_owned();
- s = s.replace('@', "_");
- s = s.replace('?', "_");
- s = s.replace('$', "_");
- s.push('_');
- return Cow::Owned(s);
- }
- Cow::Borrowed(name)
- }
-
- /// Returns a mangled name as a rust identifier.
- pub fn rust_ident<S>(&self, name: S) -> Ident
- where
- S: AsRef<str>,
- {
- self.rust_ident_raw(self.rust_mangle(name.as_ref()))
- }
-
- /// Returns a mangled name as a rust identifier.
- pub fn rust_ident_raw<T>(&self, name: T) -> Ident
- where
- T: AsRef<str>,
- {
- Ident::new(name.as_ref(), Span::call_site())
- }
-
- /// Iterate over all items that have been defined.
- pub fn items(&self) -> impl Iterator<Item = (ItemId, &Item)> {
- self.items.iter().enumerate().filter_map(|(index, item)| {
- let item = item.as_ref()?;
- Some((ItemId(index), item))
- })
- }
-
- /// Have we collected all unresolved type references yet?
- pub fn collected_typerefs(&self) -> bool {
- self.collected_typerefs
- }
-
- /// Gather all the unresolved type references.
- fn collect_typerefs(
- &mut self,
- ) -> Vec<(ItemId, clang::Type, clang::Cursor, Option<ItemId>)> {
- debug_assert!(!self.collected_typerefs);
- self.collected_typerefs = true;
- let mut typerefs = vec![];
-
- for (id, item) in self.items() {
- let kind = item.kind();
- let ty = match kind.as_type() {
- Some(ty) => ty,
- None => continue,
- };
-
- if let TypeKind::UnresolvedTypeRef(ref ty, loc, parent_id) =
- *ty.kind()
- {
- typerefs.push((id, *ty, loc, parent_id));
- };
- }
- typerefs
- }
-
- /// Collect all of our unresolved type references and resolve them.
- fn resolve_typerefs(&mut self) {
- let _t = self.timer("resolve_typerefs");
-
- let typerefs = self.collect_typerefs();
-
- for (id, ty, loc, parent_id) in typerefs {
- let _resolved =
- {
- let resolved = Item::from_ty(&ty, loc, parent_id, self)
- .unwrap_or_else(|_| {
- warn!("Could not resolve type reference, falling back \
- to opaque blob");
- Item::new_opaque_type(self.next_item_id(), &ty, self)
- });
-
- let item = self.items[id.0].as_mut().unwrap();
- *item.kind_mut().as_type_mut().unwrap().kind_mut() =
- TypeKind::ResolvedTypeRef(resolved);
- resolved
- };
-
- // Something in the STL is trolling me. I don't need this assertion
- // right now, but worth investigating properly once this lands.
- //
- // debug_assert!(self.items.get(&resolved).is_some(), "How?");
- //
- // if let Some(parent_id) = parent_id {
- // assert_eq!(self.items[&resolved].parent_id(), parent_id);
- // }
- }
- }
-
- /// Temporarily loan `Item` with the given `ItemId`. This provides means to
- /// mutably borrow `Item` while having a reference to `BindgenContext`.
- ///
- /// `Item` with the given `ItemId` is removed from the context, given
- /// closure is executed and then `Item` is placed back.
- ///
- /// # Panics
- ///
- /// Panics if attempt to resolve given `ItemId` inside the given
- /// closure is made.
- fn with_loaned_item<F, T>(&mut self, id: ItemId, f: F) -> T
- where
- F: (FnOnce(&BindgenContext, &mut Item) -> T),
- {
- let mut item = self.items[id.0].take().unwrap();
-
- let result = f(self, &mut item);
-
- let existing = mem::replace(&mut self.items[id.0], Some(item));
- assert!(existing.is_none());
-
- result
- }
-
- /// Compute the bitfield allocation units for all `TypeKind::Comp` items we
- /// parsed.
- fn compute_bitfield_units(&mut self) {
- let _t = self.timer("compute_bitfield_units");
-
- assert!(self.collected_typerefs());
-
- let need_bitfield_allocation =
- mem::take(&mut self.need_bitfield_allocation);
- for id in need_bitfield_allocation {
- self.with_loaned_item(id, |ctx, item| {
- let ty = item.kind_mut().as_type_mut().unwrap();
- let layout = ty.layout(ctx);
- ty.as_comp_mut()
- .unwrap()
- .compute_bitfield_units(ctx, layout.as_ref());
- });
- }
- }
-
- /// Assign a new generated name for each anonymous field.
- fn deanonymize_fields(&mut self) {
- let _t = self.timer("deanonymize_fields");
-
- let comp_item_ids: Vec<ItemId> = self
- .items()
- .filter_map(|(id, item)| {
- if item.kind().as_type()?.is_comp() {
- return Some(id);
- }
- None
- })
- .collect();
-
- for id in comp_item_ids {
- self.with_loaned_item(id, |ctx, item| {
- item.kind_mut()
- .as_type_mut()
- .unwrap()
- .as_comp_mut()
- .unwrap()
- .deanonymize_fields(ctx);
- });
- }
- }
-
- /// Iterate over all items and replace any item that has been named in a
- /// `replaces="SomeType"` annotation with the replacement type.
- fn process_replacements(&mut self) {
- let _t = self.timer("process_replacements");
- if self.replacements.is_empty() {
- debug!("No replacements to process");
- return;
- }
-
- // FIXME: This is linear, but the replaces="xxx" annotation was already
- // there, and for better or worse it's useful, sigh...
- //
- // We leverage the ResolvedTypeRef thing, though, which is cool :P.
-
- let mut replacements = vec![];
-
- for (id, item) in self.items() {
- if item.annotations().use_instead_of().is_some() {
- continue;
- }
-
- // Calls to `canonical_name` are expensive, so eagerly filter out
- // items that cannot be replaced.
- let ty = match item.kind().as_type() {
- Some(ty) => ty,
- None => continue,
- };
-
- match *ty.kind() {
- TypeKind::Comp(..) |
- TypeKind::TemplateAlias(..) |
- TypeKind::Enum(..) |
- TypeKind::Alias(..) => {}
- _ => continue,
- }
-
- let path = item.path_for_allowlisting(self);
- let replacement = self.replacements.get(&path[1..]);
-
- if let Some(replacement) = replacement {
- if *replacement != id {
- // We set this just after parsing the annotation. It's
- // very unlikely, but this can happen.
- if self.resolve_item_fallible(*replacement).is_some() {
- replacements.push((
- id.expect_type_id(self),
- replacement.expect_type_id(self),
- ));
- }
- }
- }
- }
-
- for (id, replacement_id) in replacements {
- debug!("Replacing {:?} with {:?}", id, replacement_id);
- let new_parent = {
- let item_id: ItemId = id.into();
- let item = self.items[item_id.0].as_mut().unwrap();
- *item.kind_mut().as_type_mut().unwrap().kind_mut() =
- TypeKind::ResolvedTypeRef(replacement_id);
- item.parent_id()
- };
-
- // Relocate the replacement item from where it was declared, to
- // where the thing it is replacing was declared.
- //
- // First, we'll make sure that its parent id is correct.
-
- let old_parent = self.resolve_item(replacement_id).parent_id();
- if new_parent == old_parent {
- // Same parent and therefore also same containing
- // module. Nothing to do here.
- continue;
- }
-
- let replacement_item_id: ItemId = replacement_id.into();
- self.items[replacement_item_id.0]
- .as_mut()
- .unwrap()
- .set_parent_for_replacement(new_parent);
-
- // Second, make sure that it is in the correct module's children
- // set.
-
- let old_module = {
- let immut_self = &*self;
- old_parent
- .ancestors(immut_self)
- .chain(Some(immut_self.root_module.into()))
- .find(|id| {
- let item = immut_self.resolve_item(*id);
- item.as_module().map_or(false, |m| {
- m.children().contains(&replacement_id.into())
- })
- })
- };
- let old_module = old_module
- .expect("Every replacement item should be in a module");
-
- let new_module = {
- let immut_self = &*self;
- new_parent
- .ancestors(immut_self)
- .find(|id| immut_self.resolve_item(*id).is_module())
- };
- let new_module =
- new_module.unwrap_or_else(|| self.root_module.into());
-
- if new_module == old_module {
- // Already in the correct module.
- continue;
- }
-
- self.items[old_module.0]
- .as_mut()
- .unwrap()
- .as_module_mut()
- .unwrap()
- .children_mut()
- .remove(&replacement_id.into());
-
- self.items[new_module.0]
- .as_mut()
- .unwrap()
- .as_module_mut()
- .unwrap()
- .children_mut()
- .insert(replacement_id.into());
- }
- }
-
- /// Enter the code generation phase, invoke the given callback `cb`, and
- /// leave the code generation phase.
- pub(crate) fn gen<F, Out>(
- mut self,
- cb: F,
- ) -> (Out, BindgenOptions, Vec<String>)
- where
- F: FnOnce(&Self) -> Out,
- {
- self.in_codegen = true;
-
- self.resolve_typerefs();
- self.compute_bitfield_units();
- self.process_replacements();
-
- self.deanonymize_fields();
-
- self.assert_no_dangling_references();
-
- // Compute the allowlisted set after processing replacements and
- // resolving type refs, as those are the final mutations of the IR
- // graph, and their completion means that the IR graph is now frozen.
- self.compute_allowlisted_and_codegen_items();
-
- // Make sure to do this after processing replacements, since that messes
- // with the parentage and module children, and we want to assert that it
- // messes with them correctly.
- self.assert_every_item_in_a_module();
-
- self.compute_has_vtable();
- self.compute_sizedness();
- self.compute_has_destructor();
- self.find_used_template_parameters();
- self.compute_cannot_derive_debug();
- self.compute_cannot_derive_default();
- self.compute_cannot_derive_copy();
- self.compute_has_type_param_in_array();
- self.compute_has_float();
- self.compute_cannot_derive_hash();
- self.compute_cannot_derive_partialord_partialeq_or_eq();
-
- let ret = cb(&self);
- (ret, self.options, self.warnings)
- }
-
- /// When the `testing_only_extra_assertions` feature is enabled, this
- /// function walks the IR graph and asserts that we do not have any edges
- /// referencing an ItemId for which we do not have an associated IR item.
- fn assert_no_dangling_references(&self) {
- if cfg!(feature = "testing_only_extra_assertions") {
- for _ in self.assert_no_dangling_item_traversal() {
- // The iterator's next method does the asserting for us.
- }
- }
- }
-
- fn assert_no_dangling_item_traversal(
- &self,
- ) -> traversal::AssertNoDanglingItemsTraversal {
- assert!(self.in_codegen_phase());
- assert!(self.current_module == self.root_module);
-
- let roots = self.items().map(|(id, _)| id);
- traversal::AssertNoDanglingItemsTraversal::new(
- self,
- roots,
- traversal::all_edges,
- )
- }
-
- /// When the `testing_only_extra_assertions` feature is enabled, walk over
- /// every item and ensure that it is in the children set of one of its
- /// module ancestors.
- fn assert_every_item_in_a_module(&self) {
- if cfg!(feature = "testing_only_extra_assertions") {
- assert!(self.in_codegen_phase());
- assert!(self.current_module == self.root_module);
-
- for (id, _item) in self.items() {
- if id == self.root_module {
- continue;
- }
-
- assert!(
- {
- let id = id
- .into_resolver()
- .through_type_refs()
- .through_type_aliases()
- .resolve(self)
- .id();
- id.ancestors(self)
- .chain(Some(self.root_module.into()))
- .any(|ancestor| {
- debug!(
- "Checking if {:?} is a child of {:?}",
- id, ancestor
- );
- self.resolve_item(ancestor)
- .as_module()
- .map_or(false, |m| {
- m.children().contains(&id)
- })
- })
- },
- "{:?} should be in some ancestor module's children set",
- id
- );
- }
- }
- }
-
- /// Compute for every type whether it is sized or not, and whether it is
- /// sized or not as a base class.
- fn compute_sizedness(&mut self) {
- let _t = self.timer("compute_sizedness");
- assert!(self.sizedness.is_none());
- self.sizedness = Some(analyze::<SizednessAnalysis>(self));
- }
-
- /// Look up whether the type with the given id is sized or not.
- pub fn lookup_sizedness(&self, id: TypeId) -> SizednessResult {
- assert!(
- self.in_codegen_phase(),
- "We only compute sizedness after we've entered codegen"
- );
-
- self.sizedness
- .as_ref()
- .unwrap()
- .get(&id)
- .cloned()
- .unwrap_or(SizednessResult::ZeroSized)
- }
-
- /// Compute whether the type has vtable.
- fn compute_has_vtable(&mut self) {
- let _t = self.timer("compute_has_vtable");
- assert!(self.have_vtable.is_none());
- self.have_vtable = Some(analyze::<HasVtableAnalysis>(self));
- }
-
- /// Look up whether the item with `id` has vtable or not.
- pub fn lookup_has_vtable(&self, id: TypeId) -> HasVtableResult {
- assert!(
- self.in_codegen_phase(),
- "We only compute vtables when we enter codegen"
- );
-
- // Look up the computed value for whether the item with `id` has a
- // vtable or not.
- self.have_vtable
- .as_ref()
- .unwrap()
- .get(&id.into())
- .cloned()
- .unwrap_or(HasVtableResult::No)
- }
-
- /// Compute whether the type has a destructor.
- fn compute_has_destructor(&mut self) {
- let _t = self.timer("compute_has_destructor");
- assert!(self.have_destructor.is_none());
- self.have_destructor = Some(analyze::<HasDestructorAnalysis>(self));
- }
-
- /// Look up whether the item with `id` has a destructor.
- pub fn lookup_has_destructor(&self, id: TypeId) -> bool {
- assert!(
- self.in_codegen_phase(),
- "We only compute destructors when we enter codegen"
- );
-
- self.have_destructor.as_ref().unwrap().contains(&id.into())
- }
-
- fn find_used_template_parameters(&mut self) {
- let _t = self.timer("find_used_template_parameters");
- if self.options.allowlist_recursively {
- let used_params = analyze::<UsedTemplateParameters>(self);
- self.used_template_parameters = Some(used_params);
- } else {
- // If you aren't recursively allowlisting, then we can't really make
- // any sense of template parameter usage, and you're on your own.
- let mut used_params = HashMap::default();
- for &id in self.allowlisted_items() {
- used_params.entry(id).or_insert_with(|| {
- id.self_template_params(self)
- .into_iter()
- .map(|p| p.into())
- .collect()
- });
- }
- self.used_template_parameters = Some(used_params);
- }
- }
-
- /// Return `true` if `item` uses the given `template_param`, `false`
- /// otherwise.
- ///
- /// This method may only be called during the codegen phase, because the
- /// template usage information is only computed as we enter the codegen
- /// phase.
- ///
- /// If the item is blocklisted, then we say that it always uses the template
- /// parameter. This is a little subtle. The template parameter usage
- /// analysis only considers allowlisted items, and if any blocklisted item
- /// shows up in the generated bindings, it is the user's responsibility to
- /// manually provide a definition for them. To give them the most
- /// flexibility when doing that, we assume that they use every template
- /// parameter and always pass template arguments through in instantiations.
- pub fn uses_template_parameter(
- &self,
- item: ItemId,
- template_param: TypeId,
- ) -> bool {
- assert!(
- self.in_codegen_phase(),
- "We only compute template parameter usage as we enter codegen"
- );
-
- if self.resolve_item(item).is_blocklisted(self) {
- return true;
- }
-
- let template_param = template_param
- .into_resolver()
- .through_type_refs()
- .through_type_aliases()
- .resolve(self)
- .id();
-
- self.used_template_parameters
- .as_ref()
- .expect("should have found template parameter usage if we're in codegen")
- .get(&item)
- .map_or(false, |items_used_params| items_used_params.contains(&template_param))
- }
-
- /// Return `true` if `item` uses any unbound, generic template parameters,
- /// `false` otherwise.
- ///
- /// Has the same restrictions that `uses_template_parameter` has.
- pub fn uses_any_template_parameters(&self, item: ItemId) -> bool {
- assert!(
- self.in_codegen_phase(),
- "We only compute template parameter usage as we enter codegen"
- );
-
- self.used_template_parameters
- .as_ref()
- .expect(
- "should have template parameter usage info in codegen phase",
- )
- .get(&item)
- .map_or(false, |used| !used.is_empty())
- }
-
- // This deserves a comment. Builtin types don't get a valid declaration, so
- // we can't add it to the cursor->type map.
- //
- // That being said, they're not generated anyway, and are few, so the
- // duplication and special-casing is fine.
- //
- // If at some point we care about the memory here, probably a map TypeKind
- // -> builtin type ItemId would be the best to improve that.
- fn add_builtin_item(&mut self, item: Item) {
- debug!("add_builtin_item: item = {:?}", item);
- debug_assert!(item.kind().is_type());
- self.add_item_to_module(&item);
- let id = item.id();
- let old_item = mem::replace(&mut self.items[id.0], Some(item));
- assert!(old_item.is_none(), "Inserted type twice?");
- }
-
- fn build_root_module(id: ItemId) -> Item {
- let module = Module::new(Some("root".into()), ModuleKind::Normal);
- Item::new(id, None, None, id, ItemKind::Module(module), None)
- }
-
- /// Get the root module.
- pub fn root_module(&self) -> ModuleId {
- self.root_module
- }
-
- /// Resolve a type with the given id.
- ///
- /// Panics if there is no item for the given `TypeId` or if the resolved
- /// item is not a `Type`.
- pub fn resolve_type(&self, type_id: TypeId) -> &Type {
- self.resolve_item(type_id).kind().expect_type()
- }
-
- /// Resolve a function with the given id.
- ///
- /// Panics if there is no item for the given `FunctionId` or if the resolved
- /// item is not a `Function`.
- pub fn resolve_func(&self, func_id: FunctionId) -> &Function {
- self.resolve_item(func_id).kind().expect_function()
- }
-
- /// Resolve the given `ItemId` as a type, or `None` if there is no item with
- /// the given id.
- ///
- /// Panics if the id resolves to an item that is not a type.
- pub fn safe_resolve_type(&self, type_id: TypeId) -> Option<&Type> {
- self.resolve_item_fallible(type_id)
- .map(|t| t.kind().expect_type())
- }
-
- /// Resolve the given `ItemId` into an `Item`, or `None` if no such item
- /// exists.
- pub fn resolve_item_fallible<Id: Into<ItemId>>(
- &self,
- id: Id,
- ) -> Option<&Item> {
- self.items.get(id.into().0)?.as_ref()
- }
-
- /// Resolve the given `ItemId` into an `Item`.
- ///
- /// Panics if the given id does not resolve to any item.
- pub fn resolve_item<Id: Into<ItemId>>(&self, item_id: Id) -> &Item {
- let item_id = item_id.into();
- match self.resolve_item_fallible(item_id) {
- Some(item) => item,
- None => panic!("Not an item: {:?}", item_id),
- }
- }
-
- /// Get the current module.
- pub fn current_module(&self) -> ModuleId {
- self.current_module
- }
-
- /// Add a semantic parent for a given type definition.
- ///
- /// We do this from the type declaration, in order to be able to find the
- /// correct type definition afterwards.
- ///
- /// TODO(emilio): We could consider doing this only when
- /// declaration.lexical_parent() != definition.lexical_parent(), but it's
- /// not sure it's worth it.
- pub fn add_semantic_parent(
- &mut self,
- definition: clang::Cursor,
- parent_id: ItemId,
- ) {
- self.semantic_parents.insert(definition, parent_id);
- }
-
- /// Returns a known semantic parent for a given definition.
- pub fn known_semantic_parent(
- &self,
- definition: clang::Cursor,
- ) -> Option<ItemId> {
- self.semantic_parents.get(&definition).cloned()
- }
-
- /// Given a cursor pointing to the location of a template instantiation,
- /// return a tuple of the form `(declaration_cursor, declaration_id,
- /// num_expected_template_args)`.
- ///
- /// Note that `declaration_id` is not guaranteed to be in the context's item
- /// set! It is possible that it is a partial type that we are still in the
- /// middle of parsing.
- fn get_declaration_info_for_template_instantiation(
- &self,
- instantiation: &Cursor,
- ) -> Option<(Cursor, ItemId, usize)> {
- instantiation
- .cur_type()
- .canonical_declaration(Some(instantiation))
- .and_then(|canon_decl| {
- self.get_resolved_type(&canon_decl).and_then(
- |template_decl_id| {
- let num_params =
- template_decl_id.num_self_template_params(self);
- if num_params == 0 {
- None
- } else {
- Some((
- *canon_decl.cursor(),
- template_decl_id.into(),
- num_params,
- ))
- }
- },
- )
- })
- .or_else(|| {
- // If we haven't already parsed the declaration of
- // the template being instantiated, then it *must*
- // be on the stack of types we are currently
- // parsing. If it wasn't then clang would have
- // already errored out before we started
- // constructing our IR because you can't instantiate
- // a template until it is fully defined.
- instantiation
- .referenced()
- .and_then(|referenced| {
- self.currently_parsed_types()
- .iter()
- .find(|partial_ty| *partial_ty.decl() == referenced)
- .cloned()
- })
- .and_then(|template_decl| {
- let num_template_params =
- template_decl.num_self_template_params(self);
- if num_template_params == 0 {
- None
- } else {
- Some((
- *template_decl.decl(),
- template_decl.id(),
- num_template_params,
- ))
- }
- })
- })
- }
-
- /// Parse a template instantiation, eg `Foo<int>`.
- ///
- /// This is surprisingly difficult to do with libclang, due to the fact that
- /// it doesn't provide explicit template argument information, except for
- /// function template declarations(!?!??!).
- ///
- /// The only way to do this is manually inspecting the AST and looking for
- /// TypeRefs and TemplateRefs inside. This, unfortunately, doesn't work for
- /// more complex cases, see the comment on the assertion below.
- ///
- /// To add insult to injury, the AST itself has structure that doesn't make
- /// sense. Sometimes `Foo<Bar<int>>` has an AST with nesting like you might
- /// expect: `(Foo (Bar (int)))`. Other times, the AST we get is completely
- /// flat: `(Foo Bar int)`.
- ///
- /// To see an example of what this method handles:
- ///
- /// ```c++
- /// template<typename T>
- /// class Incomplete {
- /// T p;
- /// };
- ///
- /// template<typename U>
- /// class Foo {
- /// Incomplete<U> bar;
- /// };
- /// ```
- ///
- /// Finally, template instantiations are always children of the current
- /// module. They use their template's definition for their name, so the
- /// parent is only useful for ensuring that their layout tests get
- /// codegen'd.
- fn instantiate_template(
- &mut self,
- with_id: ItemId,
- template: TypeId,
- ty: &clang::Type,
- location: clang::Cursor,
- ) -> Option<TypeId> {
- let num_expected_args =
- self.resolve_type(template).num_self_template_params(self);
- if num_expected_args == 0 {
- warn!(
- "Tried to instantiate a template for which we could not \
- determine any template parameters"
- );
- return None;
- }
-
- let mut args = vec![];
- let mut found_const_arg = false;
- let mut children = location.collect_children();
-
- if children.iter().all(|c| !c.has_children()) {
- // This is insanity... If clang isn't giving us a properly nested
- // AST for which template arguments belong to which template we are
- // instantiating, we'll need to construct it ourselves. However,
- // there is an extra `NamespaceRef, NamespaceRef, ..., TemplateRef`
- // representing a reference to the outermost template declaration
- // that we need to filter out of the children. We need to do this
- // filtering because we already know which template declaration is
- // being specialized via the `location`'s type, and if we do not
- // filter it out, we'll add an extra layer of template instantiation
- // on accident.
- let idx = children
- .iter()
- .position(|c| c.kind() == clang_sys::CXCursor_TemplateRef);
- if let Some(idx) = idx {
- if children
- .iter()
- .take(idx)
- .all(|c| c.kind() == clang_sys::CXCursor_NamespaceRef)
- {
- children = children.into_iter().skip(idx + 1).collect();
- }
- }
- }
-
- for child in children.iter().rev() {
- match child.kind() {
- clang_sys::CXCursor_TypeRef |
- clang_sys::CXCursor_TypedefDecl |
- clang_sys::CXCursor_TypeAliasDecl => {
- // The `with_id` id will potentially end up unused if we give up
- // on this type (for example, because it has const value
- // template args), so if we pass `with_id` as the parent, it is
- // potentially a dangling reference. Instead, use the canonical
- // template declaration as the parent. It is already parsed and
- // has a known-resolvable `ItemId`.
- let ty = Item::from_ty_or_ref(
- child.cur_type(),
- *child,
- Some(template.into()),
- self,
- );
- args.push(ty);
- }
- clang_sys::CXCursor_TemplateRef => {
- let (
- template_decl_cursor,
- template_decl_id,
- num_expected_template_args,
- ) = self.get_declaration_info_for_template_instantiation(
- child,
- )?;
-
- if num_expected_template_args == 0 ||
- child.has_at_least_num_children(
- num_expected_template_args,
- )
- {
- // Do a happy little parse. See comment in the TypeRef
- // match arm about parent IDs.
- let ty = Item::from_ty_or_ref(
- child.cur_type(),
- *child,
- Some(template.into()),
- self,
- );
- args.push(ty);
- } else {
- // This is the case mentioned in the doc comment where
- // clang gives us a flattened AST and we have to
- // reconstruct which template arguments go to which
- // instantiation :(
- let args_len = args.len();
- if args_len < num_expected_template_args {
- warn!(
- "Found a template instantiation without \
- enough template arguments"
- );
- return None;
- }
-
- let mut sub_args: Vec<_> = args
- .drain(args_len - num_expected_template_args..)
- .collect();
- sub_args.reverse();
-
- let sub_name = Some(template_decl_cursor.spelling());
- let sub_inst = TemplateInstantiation::new(
- // This isn't guaranteed to be a type that we've
- // already finished parsing yet.
- template_decl_id.as_type_id_unchecked(),
- sub_args,
- );
- let sub_kind =
- TypeKind::TemplateInstantiation(sub_inst);
- let sub_ty = Type::new(
- sub_name,
- template_decl_cursor
- .cur_type()
- .fallible_layout(self)
- .ok(),
- sub_kind,
- false,
- );
- let sub_id = self.next_item_id();
- let sub_item = Item::new(
- sub_id,
- None,
- None,
- self.current_module.into(),
- ItemKind::Type(sub_ty),
- Some(child.location()),
- );
-
- // Bypass all the validations in add_item explicitly.
- debug!(
- "instantiate_template: inserting nested \
- instantiation item: {:?}",
- sub_item
- );
- self.add_item_to_module(&sub_item);
- debug_assert_eq!(sub_id, sub_item.id());
- self.items[sub_id.0] = Some(sub_item);
- args.push(sub_id.as_type_id_unchecked());
- }
- }
- _ => {
- warn!(
- "Found template arg cursor we can't handle: {:?}",
- child
- );
- found_const_arg = true;
- }
- }
- }
-
- if found_const_arg {
- // This is a dependently typed template instantiation. That is, an
- // instantiation of a template with one or more const values as
- // template arguments, rather than only types as template
- // arguments. For example, `Foo<true, 5>` versus `Bar<bool, int>`.
- // We can't handle these instantiations, so just punt in this
- // situation...
- warn!(
- "Found template instantiated with a const value; \
- bindgen can't handle this kind of template instantiation!"
- );
- return None;
- }
-
- if args.len() != num_expected_args {
- warn!(
- "Found a template with an unexpected number of template \
- arguments"
- );
- return None;
- }
-
- args.reverse();
- let type_kind = TypeKind::TemplateInstantiation(
- TemplateInstantiation::new(template, args),
- );
- let name = ty.spelling();
- let name = if name.is_empty() { None } else { Some(name) };
- let ty = Type::new(
- name,
- ty.fallible_layout(self).ok(),
- type_kind,
- ty.is_const(),
- );
- let item = Item::new(
- with_id,
- None,
- None,
- self.current_module.into(),
- ItemKind::Type(ty),
- Some(location.location()),
- );
-
- // Bypass all the validations in add_item explicitly.
- debug!("instantiate_template: inserting item: {:?}", item);
- self.add_item_to_module(&item);
- debug_assert_eq!(with_id, item.id());
- self.items[with_id.0] = Some(item);
- Some(with_id.as_type_id_unchecked())
- }
-
- /// If we have already resolved the type for the given type declaration,
- /// return its `ItemId`. Otherwise, return `None`.
- pub fn get_resolved_type(
- &self,
- decl: &clang::CanonicalTypeDeclaration,
- ) -> Option<TypeId> {
- self.types
- .get(&TypeKey::Declaration(*decl.cursor()))
- .or_else(|| {
- decl.cursor()
- .usr()
- .and_then(|usr| self.types.get(&TypeKey::Usr(usr)))
- })
- .cloned()
- }
-
- /// Looks up for an already resolved type, either because it's builtin, or
- /// because we already have it in the map.
- pub fn builtin_or_resolved_ty(
- &mut self,
- with_id: ItemId,
- parent_id: Option<ItemId>,
- ty: &clang::Type,
- location: Option<clang::Cursor>,
- ) -> Option<TypeId> {
- use clang_sys::{CXCursor_TypeAliasTemplateDecl, CXCursor_TypeRef};
- debug!(
- "builtin_or_resolved_ty: {:?}, {:?}, {:?}, {:?}",
- ty, location, with_id, parent_id
- );
-
- if let Some(decl) = ty.canonical_declaration(location.as_ref()) {
- if let Some(id) = self.get_resolved_type(&decl) {
- debug!(
- "Already resolved ty {:?}, {:?}, {:?} {:?}",
- id, decl, ty, location
- );
- // If the declaration already exists, then either:
- //
- // * the declaration is a template declaration of some sort,
- // and we are looking at an instantiation or specialization
- // of it, or
- // * we have already parsed and resolved this type, and
- // there's nothing left to do.
- if let Some(location) = location {
- if decl.cursor().is_template_like() &&
- *ty != decl.cursor().cur_type()
- {
- // For specialized type aliases, there's no way to get the
- // template parameters as of this writing (for a struct
- // specialization we wouldn't be in this branch anyway).
- //
- // Explicitly return `None` if there aren't any
- // unspecialized parameters (contains any `TypeRef`) so we
- // resolve the canonical type if there is one and it's
- // exposed.
- //
- // This is _tricky_, I know :(
- if decl.cursor().kind() ==
- CXCursor_TypeAliasTemplateDecl &&
- !location.contains_cursor(CXCursor_TypeRef) &&
- ty.canonical_type().is_valid_and_exposed()
- {
- return None;
- }
-
- return self
- .instantiate_template(with_id, id, ty, location)
- .or(Some(id));
- }
- }
-
- return Some(self.build_ty_wrapper(with_id, id, parent_id, ty));
- }
- }
-
- debug!("Not resolved, maybe builtin?");
- self.build_builtin_ty(ty)
- }
-
- /// Make a new item that is a resolved type reference to the `wrapped_id`.
- ///
- /// This is unfortunately a lot of bloat, but is needed to properly track
- /// constness et al.
- ///
- /// We should probably make the constness tracking separate, so it doesn't
- /// bloat that much, but hey, we already bloat the heck out of builtin
- /// types.
- pub fn build_ty_wrapper(
- &mut self,
- with_id: ItemId,
- wrapped_id: TypeId,
- parent_id: Option<ItemId>,
- ty: &clang::Type,
- ) -> TypeId {
- self.build_wrapper(with_id, wrapped_id, parent_id, ty, ty.is_const())
- }
-
- /// A wrapper over a type that adds a const qualifier explicitly.
- ///
- /// Needed to handle const methods in C++, wrapping the type .
- pub fn build_const_wrapper(
- &mut self,
- with_id: ItemId,
- wrapped_id: TypeId,
- parent_id: Option<ItemId>,
- ty: &clang::Type,
- ) -> TypeId {
- self.build_wrapper(
- with_id, wrapped_id, parent_id, ty, /* is_const = */ true,
- )
- }
-
- fn build_wrapper(
- &mut self,
- with_id: ItemId,
- wrapped_id: TypeId,
- parent_id: Option<ItemId>,
- ty: &clang::Type,
- is_const: bool,
- ) -> TypeId {
- let spelling = ty.spelling();
- let layout = ty.fallible_layout(self).ok();
- let location = ty.declaration().location();
- let type_kind = TypeKind::ResolvedTypeRef(wrapped_id);
- let ty = Type::new(Some(spelling), layout, type_kind, is_const);
- let item = Item::new(
- with_id,
- None,
- None,
- parent_id.unwrap_or_else(|| self.current_module.into()),
- ItemKind::Type(ty),
- Some(location),
- );
- self.add_builtin_item(item);
- with_id.as_type_id_unchecked()
- }
-
- /// Returns the next item id to be used for an item.
- pub fn next_item_id(&mut self) -> ItemId {
- let ret = ItemId(self.items.len());
- self.items.push(None);
- ret
- }
-
- fn build_builtin_ty(&mut self, ty: &clang::Type) -> Option<TypeId> {
- use clang_sys::*;
- let type_kind = match ty.kind() {
- CXType_NullPtr => TypeKind::NullPtr,
- CXType_Void => TypeKind::Void,
- CXType_Bool => TypeKind::Int(IntKind::Bool),
- CXType_Int => TypeKind::Int(IntKind::Int),
- CXType_UInt => TypeKind::Int(IntKind::UInt),
- CXType_Char_S => TypeKind::Int(IntKind::Char { is_signed: true }),
- CXType_Char_U => TypeKind::Int(IntKind::Char { is_signed: false }),
- CXType_SChar => TypeKind::Int(IntKind::SChar),
- CXType_UChar => TypeKind::Int(IntKind::UChar),
- CXType_Short => TypeKind::Int(IntKind::Short),
- CXType_UShort => TypeKind::Int(IntKind::UShort),
- CXType_WChar => TypeKind::Int(IntKind::WChar),
- CXType_Char16 => TypeKind::Int(IntKind::U16),
- CXType_Char32 => TypeKind::Int(IntKind::U32),
- CXType_Long => TypeKind::Int(IntKind::Long),
- CXType_ULong => TypeKind::Int(IntKind::ULong),
- CXType_LongLong => TypeKind::Int(IntKind::LongLong),
- CXType_ULongLong => TypeKind::Int(IntKind::ULongLong),
- CXType_Int128 => TypeKind::Int(IntKind::I128),
- CXType_UInt128 => TypeKind::Int(IntKind::U128),
- CXType_Float => TypeKind::Float(FloatKind::Float),
- CXType_Double => TypeKind::Float(FloatKind::Double),
- CXType_LongDouble => TypeKind::Float(FloatKind::LongDouble),
- CXType_Float128 => TypeKind::Float(FloatKind::Float128),
- CXType_Complex => {
- let float_type =
- ty.elem_type().expect("Not able to resolve complex type?");
- let float_kind = match float_type.kind() {
- CXType_Float => FloatKind::Float,
- CXType_Double => FloatKind::Double,
- CXType_LongDouble => FloatKind::LongDouble,
- CXType_Float128 => FloatKind::Float128,
- _ => panic!(
- "Non floating-type complex? {:?}, {:?}",
- ty, float_type,
- ),
- };
- TypeKind::Complex(float_kind)
- }
- _ => return None,
- };
-
- let spelling = ty.spelling();
- let is_const = ty.is_const();
- let layout = ty.fallible_layout(self).ok();
- let location = ty.declaration().location();
- let ty = Type::new(Some(spelling), layout, type_kind, is_const);
- let id = self.next_item_id();
- let item = Item::new(
- id,
- None,
- None,
- self.root_module.into(),
- ItemKind::Type(ty),
- Some(location),
- );
- self.add_builtin_item(item);
- Some(id.as_type_id_unchecked())
- }
-
- /// Get the current Clang translation unit that is being processed.
- pub fn translation_unit(&self) -> &clang::TranslationUnit {
- &self.translation_unit
- }
-
- /// Have we parsed the macro named `macro_name` already?
- pub fn parsed_macro(&self, macro_name: &[u8]) -> bool {
- self.parsed_macros.contains_key(macro_name)
- }
-
- /// Get the currently parsed macros.
- pub fn parsed_macros(
- &self,
- ) -> &StdHashMap<Vec<u8>, cexpr::expr::EvalResult> {
- debug_assert!(!self.in_codegen_phase());
- &self.parsed_macros
- }
-
- /// Mark the macro named `macro_name` as parsed.
- pub fn note_parsed_macro(
- &mut self,
- id: Vec<u8>,
- value: cexpr::expr::EvalResult,
- ) {
- self.parsed_macros.insert(id, value);
- }
-
- /// Are we in the codegen phase?
- pub fn in_codegen_phase(&self) -> bool {
- self.in_codegen
- }
-
- /// Mark the type with the given `name` as replaced by the type with id
- /// `potential_ty`.
- ///
- /// Replacement types are declared using the `replaces="xxx"` annotation,
- /// and implies that the original type is hidden.
- pub fn replace(&mut self, name: &[String], potential_ty: ItemId) {
- match self.replacements.entry(name.into()) {
- Entry::Vacant(entry) => {
- debug!(
- "Defining replacement for {:?} as {:?}",
- name, potential_ty
- );
- entry.insert(potential_ty);
- }
- Entry::Occupied(occupied) => {
- warn!(
- "Replacement for {:?} already defined as {:?}; \
- ignoring duplicate replacement definition as {:?}",
- name,
- occupied.get(),
- potential_ty
- );
- }
- }
- }
-
- /// Has the item with the given `name` and `id` been replaced by another
- /// type?
- pub fn is_replaced_type<Id: Into<ItemId>>(
- &self,
- path: &[String],
- id: Id,
- ) -> bool {
- let id = id.into();
- matches!(self.replacements.get(path), Some(replaced_by) if *replaced_by != id)
- }
-
- /// Is the type with the given `name` marked as opaque?
- pub fn opaque_by_name(&self, path: &[String]) -> bool {
- debug_assert!(
- self.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- self.options.opaque_types.matches(&path[1..].join("::"))
- }
-
- /// Get the options used to configure this bindgen context.
- pub(crate) fn options(&self) -> &BindgenOptions {
- &self.options
- }
-
- /// Tokenizes a namespace cursor in order to get the name and kind of the
- /// namespace.
- fn tokenize_namespace(
- &self,
- cursor: &clang::Cursor,
- ) -> (Option<String>, ModuleKind) {
- assert_eq!(
- cursor.kind(),
- ::clang_sys::CXCursor_Namespace,
- "Be a nice person"
- );
-
- let mut module_name = None;
- let spelling = cursor.spelling();
- if !spelling.is_empty() {
- module_name = Some(spelling)
- }
-
- let mut kind = ModuleKind::Normal;
- let mut found_namespace_keyword = false;
- for token in cursor.tokens().iter() {
- match token.spelling() {
- b"inline" => {
- assert!(!found_namespace_keyword);
- assert!(kind != ModuleKind::Inline);
- kind = ModuleKind::Inline;
- }
- // The double colon allows us to handle nested namespaces like
- // namespace foo::bar { }
- //
- // libclang still gives us two namespace cursors, which is cool,
- // but the tokenization of the second begins with the double
- // colon. That's ok, so we only need to handle the weird
- // tokenization here.
- //
- // Fortunately enough, inline nested namespace specifiers aren't
- // a thing, and are invalid C++ :)
- b"namespace" | b"::" => {
- found_namespace_keyword = true;
- }
- b"{" => {
- assert!(found_namespace_keyword);
- break;
- }
- name if found_namespace_keyword => {
- if module_name.is_none() {
- module_name =
- Some(String::from_utf8_lossy(name).into_owned());
- }
- break;
- }
- spelling if !found_namespace_keyword => {
- // This is _likely_, but not certainly, a macro that's been placed just before
- // the namespace keyword. Unfortunately, clang tokens don't let us easily see
- // through the ifdef tokens, so we don't know what this token should really be.
- // Instead of panicking though, we warn the user that we assumed the token was
- // blank, and then move on.
- //
- // See also https://github.com/rust-lang/rust-bindgen/issues/1676.
- warn!(
- "Ignored unknown namespace prefix '{}' at {:?} in {:?}",
- String::from_utf8_lossy(spelling),
- token,
- cursor
- );
- }
- spelling => {
- panic!(
- "Unknown token '{}' while processing namespace at {:?} in {:?}",
- String::from_utf8_lossy(spelling),
- token,
- cursor
- );
- }
- }
- }
-
- (module_name, kind)
- }
-
- /// Given a CXCursor_Namespace cursor, return the item id of the
- /// corresponding module, or create one on the fly.
- pub fn module(&mut self, cursor: clang::Cursor) -> ModuleId {
- use clang_sys::*;
- assert_eq!(cursor.kind(), CXCursor_Namespace, "Be a nice person");
- let cursor = cursor.canonical();
- if let Some(id) = self.modules.get(&cursor) {
- return *id;
- }
-
- let (module_name, kind) = self.tokenize_namespace(&cursor);
-
- let module_id = self.next_item_id();
- let module = Module::new(module_name, kind);
- let module = Item::new(
- module_id,
- None,
- None,
- self.current_module.into(),
- ItemKind::Module(module),
- Some(cursor.location()),
- );
-
- let module_id = module.id().as_module_id_unchecked();
- self.modules.insert(cursor, module_id);
-
- self.add_item(module, None, None);
-
- module_id
- }
-
- /// Start traversing the module with the given `module_id`, invoke the
- /// callback `cb`, and then return to traversing the original module.
- pub fn with_module<F>(&mut self, module_id: ModuleId, cb: F)
- where
- F: FnOnce(&mut Self),
- {
- debug_assert!(self.resolve_item(module_id).kind().is_module(), "Wat");
-
- let previous_id = self.current_module;
- self.current_module = module_id;
-
- cb(self);
-
- self.current_module = previous_id;
- }
-
- /// Iterate over all (explicitly or transitively) allowlisted items.
- ///
- /// If no items are explicitly allowlisted, then all items are considered
- /// allowlisted.
- pub fn allowlisted_items(&self) -> &ItemSet {
- assert!(self.in_codegen_phase());
- assert!(self.current_module == self.root_module);
-
- 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);
-
- *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| match self.options.parse_callbacks {
- Some(ref cb) => cb.blocklisted_type_implements_trait(
- name,
- derive_trait,
- ),
- // Sized integer types from <stdint.h> get mapped to Rust primitive
- // types regardless of whether they are blocklisted, so ensure that
- // standard traits are considered derivable for them too.
- None => Some(if self.is_stdint_type(name) {
- CanDerive::Yes
- } else {
- CanDerive::No
- }),
- })
- .unwrap_or(CanDerive::No)
- })
- }
-
- /// Is the given type a type from <stdint.h> that corresponds to a Rust primitive type?
- pub fn is_stdint_type(&self, name: &str) -> bool {
- match name {
- "int8_t" | "uint8_t" | "int16_t" | "uint16_t" | "int32_t" |
- "uint32_t" | "int64_t" | "uint64_t" | "uintptr_t" |
- "intptr_t" | "ptrdiff_t" => true,
- "size_t" | "ssize_t" => self.options.size_t_is_usize,
- _ => false,
- }
- }
-
- /// Get a reference to the set of items we should generate.
- pub fn codegen_items(&self) -> &ItemSet {
- assert!(self.in_codegen_phase());
- assert!(self.current_module == self.root_module);
- self.codegen_items.as_ref().unwrap()
- }
-
- /// Compute the allowlisted items set and populate `self.allowlisted`.
- fn compute_allowlisted_and_codegen_items(&mut self) {
- assert!(self.in_codegen_phase());
- assert!(self.current_module == self.root_module);
- assert!(self.allowlisted.is_none());
- let _t = self.timer("compute_allowlisted_and_codegen_items");
-
- let roots = {
- let mut roots = self
- .items()
- // Only consider roots that are enabled for codegen.
- .filter(|&(_, item)| item.is_enabled_for_codegen(self))
- .filter(|&(_, item)| {
- // If nothing is explicitly allowlisted, then everything is fair
- // game.
- if self.options().allowlisted_types.is_empty() &&
- self.options().allowlisted_functions.is_empty() &&
- self.options().allowlisted_vars.is_empty() &&
- self.options().allowlisted_files.is_empty()
- {
- return true;
- }
-
- // If this is a type that explicitly replaces another, we assume
- // you know what you're doing.
- if item.annotations().use_instead_of().is_some() {
- return true;
- }
-
- // Items with a source location in an explicitly allowlisted file
- // are always included.
- if !self.options().allowlisted_files.is_empty() {
- if let Some(location) = item.location() {
- let (file, _, _, _) = location.location();
- if let Some(filename) = file.name() {
- if self
- .options()
- .allowlisted_files
- .matches(&filename)
- {
- return true;
- }
- }
- }
- }
-
- let name = item.path_for_allowlisting(self)[1..].join("::");
- debug!("allowlisted_items: testing {:?}", name);
- match *item.kind() {
- ItemKind::Module(..) => true,
- ItemKind::Function(_) => {
- self.options().allowlisted_functions.matches(&name)
- }
- ItemKind::Var(_) => {
- self.options().allowlisted_vars.matches(&name)
- }
- ItemKind::Type(ref ty) => {
- if self.options().allowlisted_types.matches(&name) {
- return true;
- }
-
- // Auto-allowlist types that don't need code
- // generation if not allowlisting recursively, to
- // make the #[derive] analysis not be lame.
- if !self.options().allowlist_recursively {
- match *ty.kind() {
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Int(..) |
- TypeKind::Float(..) |
- TypeKind::Complex(..) |
- TypeKind::Array(..) |
- TypeKind::Vector(..) |
- TypeKind::Pointer(..) |
- TypeKind::Reference(..) |
- TypeKind::Function(..) |
- TypeKind::ResolvedTypeRef(..) |
- TypeKind::Opaque |
- TypeKind::TypeParam => return true,
- _ => {}
- }
- if self.is_stdint_type(&name) {
- return true;
- }
- }
-
- // Unnamed top-level enums are special and we
- // allowlist them via the `allowlisted_vars` filter,
- // since they're effectively top-level constants,
- // and there's no way for them to be referenced
- // consistently.
- let parent = self.resolve_item(item.parent_id());
- if !parent.is_module() {
- return false;
- }
-
- let enum_ = match *ty.kind() {
- TypeKind::Enum(ref e) => e,
- _ => return false,
- };
-
- if ty.name().is_some() {
- return false;
- }
-
- let mut prefix_path =
- parent.path_for_allowlisting(self).clone();
- enum_.variants().iter().any(|variant| {
- prefix_path.push(
- variant.name_for_allowlisting().into(),
- );
- let name = prefix_path[1..].join("::");
- prefix_path.pop().unwrap();
- self.options().allowlisted_vars.matches(&name)
- })
- }
- }
- })
- .map(|(id, _)| id)
- .collect::<Vec<_>>();
-
- // The reversal preserves the expected ordering of traversal,
- // resulting in more stable-ish bindgen-generated names for
- // anonymous types (like unions).
- roots.reverse();
- roots
- };
-
- let allowlisted_items_predicate =
- if self.options().allowlist_recursively {
- traversal::all_edges
- } else {
- // Only follow InnerType edges from the allowlisted roots.
- // Such inner types (e.g. anonymous structs/unions) are
- // always emitted by codegen, and they need to be allowlisted
- // to make sure they are processed by e.g. the derive analysis.
- traversal::only_inner_type_edges
- };
-
- let allowlisted = AllowlistedItemsTraversal::new(
- self,
- roots.clone(),
- allowlisted_items_predicate,
- )
- .collect::<ItemSet>();
-
- let codegen_items = if self.options().allowlist_recursively {
- AllowlistedItemsTraversal::new(
- self,
- roots,
- traversal::codegen_edges,
- )
- .collect::<ItemSet>()
- } else {
- allowlisted.clone()
- };
-
- self.allowlisted = Some(allowlisted);
- self.codegen_items = Some(codegen_items);
-
- let mut warnings = Vec::new();
-
- for item in self.options().allowlisted_functions.unmatched_items() {
- warnings
- .push(format!("unused option: --allowlist-function {}", item));
- }
-
- for item in self.options().allowlisted_vars.unmatched_items() {
- warnings.push(format!("unused option: --allowlist-var {}", item));
- }
-
- for item in self.options().allowlisted_types.unmatched_items() {
- warnings.push(format!("unused option: --allowlist-type {}", item));
- }
-
- for msg in warnings {
- warn!("{}", msg);
- self.warnings.push(msg);
- }
- }
-
- /// Convenient method for getting the prefix to use for most traits in
- /// codegen depending on the `use_core` option.
- pub fn trait_prefix(&self) -> Ident {
- if self.options().use_core {
- self.rust_ident_raw("core")
- } else {
- self.rust_ident_raw("std")
- }
- }
-
- /// Call if a bindgen complex is generated
- pub fn generated_bindgen_complex(&self) {
- self.generated_bindgen_complex.set(true)
- }
-
- /// Whether we need to generate the bindgen complex type
- pub fn need_bindgen_complex_type(&self) -> bool {
- self.generated_bindgen_complex.get()
- }
-
- /// Compute whether we can derive debug.
- fn compute_cannot_derive_debug(&mut self) {
- let _t = self.timer("compute_cannot_derive_debug");
- assert!(self.cannot_derive_debug.is_none());
- if self.options.derive_debug {
- self.cannot_derive_debug =
- Some(as_cannot_derive_set(analyze::<CannotDerive>((
- self,
- DeriveTrait::Debug,
- ))));
- }
- }
-
- /// Look up whether the item with `id` can
- /// derive debug or not.
- pub fn lookup_can_derive_debug<Id: Into<ItemId>>(&self, id: Id) -> bool {
- let id = id.into();
- assert!(
- self.in_codegen_phase(),
- "We only compute can_derive_debug when we enter codegen"
- );
-
- // Look up the computed value for whether the item with `id` can
- // derive debug or not.
- !self.cannot_derive_debug.as_ref().unwrap().contains(&id)
- }
-
- /// Compute whether we can derive default.
- fn compute_cannot_derive_default(&mut self) {
- let _t = self.timer("compute_cannot_derive_default");
- assert!(self.cannot_derive_default.is_none());
- if self.options.derive_default {
- self.cannot_derive_default =
- Some(as_cannot_derive_set(analyze::<CannotDerive>((
- self,
- DeriveTrait::Default,
- ))));
- }
- }
-
- /// Look up whether the item with `id` can
- /// derive default or not.
- pub fn lookup_can_derive_default<Id: Into<ItemId>>(&self, id: Id) -> bool {
- let id = id.into();
- assert!(
- self.in_codegen_phase(),
- "We only compute can_derive_default when we enter codegen"
- );
-
- // Look up the computed value for whether the item with `id` can
- // derive default or not.
- !self.cannot_derive_default.as_ref().unwrap().contains(&id)
- }
-
- /// Compute whether we can derive copy.
- fn compute_cannot_derive_copy(&mut self) {
- let _t = self.timer("compute_cannot_derive_copy");
- assert!(self.cannot_derive_copy.is_none());
- self.cannot_derive_copy =
- Some(as_cannot_derive_set(analyze::<CannotDerive>((
- self,
- DeriveTrait::Copy,
- ))));
- }
-
- /// Compute whether we can derive hash.
- fn compute_cannot_derive_hash(&mut self) {
- let _t = self.timer("compute_cannot_derive_hash");
- assert!(self.cannot_derive_hash.is_none());
- if self.options.derive_hash {
- self.cannot_derive_hash =
- Some(as_cannot_derive_set(analyze::<CannotDerive>((
- self,
- DeriveTrait::Hash,
- ))));
- }
- }
-
- /// Look up whether the item with `id` can
- /// derive hash or not.
- pub fn lookup_can_derive_hash<Id: Into<ItemId>>(&self, id: Id) -> bool {
- let id = id.into();
- assert!(
- self.in_codegen_phase(),
- "We only compute can_derive_debug when we enter codegen"
- );
-
- // Look up the computed value for whether the item with `id` can
- // derive hash or not.
- !self.cannot_derive_hash.as_ref().unwrap().contains(&id)
- }
-
- /// Compute whether we can derive PartialOrd, PartialEq or Eq.
- fn compute_cannot_derive_partialord_partialeq_or_eq(&mut self) {
- let _t = self.timer("compute_cannot_derive_partialord_partialeq_or_eq");
- assert!(self.cannot_derive_partialeq_or_partialord.is_none());
- if self.options.derive_partialord ||
- self.options.derive_partialeq ||
- self.options.derive_eq
- {
- self.cannot_derive_partialeq_or_partialord =
- Some(analyze::<CannotDerive>((
- self,
- DeriveTrait::PartialEqOrPartialOrd,
- )));
- }
- }
-
- /// Look up whether the item with `id` can derive `Partial{Eq,Ord}`.
- pub fn lookup_can_derive_partialeq_or_partialord<Id: Into<ItemId>>(
- &self,
- id: Id,
- ) -> CanDerive {
- let id = id.into();
- assert!(
- self.in_codegen_phase(),
- "We only compute can_derive_partialeq_or_partialord when we enter codegen"
- );
-
- // Look up the computed value for whether the item with `id` can
- // derive partialeq or not.
- self.cannot_derive_partialeq_or_partialord
- .as_ref()
- .unwrap()
- .get(&id)
- .cloned()
- .unwrap_or(CanDerive::Yes)
- }
-
- /// Look up whether the item with `id` can derive `Copy` or not.
- pub fn lookup_can_derive_copy<Id: Into<ItemId>>(&self, id: Id) -> bool {
- assert!(
- self.in_codegen_phase(),
- "We only compute can_derive_debug when we enter codegen"
- );
-
- // Look up the computed value for whether the item with `id` can
- // derive `Copy` or not.
- let id = id.into();
-
- !self.lookup_has_type_param_in_array(id) &&
- !self.cannot_derive_copy.as_ref().unwrap().contains(&id)
- }
-
- /// Compute whether the type has type parameter in array.
- fn compute_has_type_param_in_array(&mut self) {
- let _t = self.timer("compute_has_type_param_in_array");
- assert!(self.has_type_param_in_array.is_none());
- self.has_type_param_in_array =
- Some(analyze::<HasTypeParameterInArray>(self));
- }
-
- /// Look up whether the item with `id` has type parameter in array or not.
- pub fn lookup_has_type_param_in_array<Id: Into<ItemId>>(
- &self,
- id: Id,
- ) -> bool {
- assert!(
- self.in_codegen_phase(),
- "We only compute has array when we enter codegen"
- );
-
- // Look up the computed value for whether the item with `id` has
- // type parameter in array or not.
- self.has_type_param_in_array
- .as_ref()
- .unwrap()
- .contains(&id.into())
- }
-
- /// Compute whether the type has float.
- fn compute_has_float(&mut self) {
- let _t = self.timer("compute_has_float");
- assert!(self.has_float.is_none());
- if self.options.derive_eq || self.options.derive_ord {
- self.has_float = Some(analyze::<HasFloat>(self));
- }
- }
-
- /// Look up whether the item with `id` has array or not.
- pub fn lookup_has_float<Id: Into<ItemId>>(&self, id: Id) -> bool {
- assert!(
- self.in_codegen_phase(),
- "We only compute has float when we enter codegen"
- );
-
- // Look up the computed value for whether the item with `id` has
- // float or not.
- self.has_float.as_ref().unwrap().contains(&id.into())
- }
-
- /// Check if `--no-partialeq` flag is enabled for this item.
- pub fn no_partialeq_by_name(&self, item: &Item) -> bool {
- let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().no_partialeq_types.matches(&name)
- }
-
- /// Check if `--no-copy` flag is enabled for this item.
- pub fn no_copy_by_name(&self, item: &Item) -> bool {
- let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().no_copy_types.matches(&name)
- }
-
- /// Check if `--no-debug` flag is enabled for this item.
- pub fn no_debug_by_name(&self, item: &Item) -> bool {
- let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().no_debug_types.matches(&name)
- }
-
- /// Check if `--no-default` flag is enabled for this item.
- pub fn no_default_by_name(&self, item: &Item) -> bool {
- let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().no_default_types.matches(&name)
- }
-
- /// Check if `--no-hash` flag is enabled for this item.
- pub fn no_hash_by_name(&self, item: &Item) -> bool {
- let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().no_hash_types.matches(&name)
- }
-
- /// Check if `--must-use-type` flag is enabled for this item.
- pub fn must_use_type_by_name(&self, item: &Item) -> bool {
- let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().must_use_types.matches(&name)
- }
-}
-
-/// A builder struct for configuring item resolution options.
-#[derive(Debug, Copy, Clone)]
-pub struct ItemResolver {
- id: ItemId,
- through_type_refs: bool,
- through_type_aliases: bool,
-}
-
-impl ItemId {
- /// Create an `ItemResolver` from this item id.
- pub fn into_resolver(self) -> ItemResolver {
- self.into()
- }
-}
-
-impl<T> From<T> for ItemResolver
-where
- T: Into<ItemId>,
-{
- fn from(id: T) -> ItemResolver {
- ItemResolver::new(id)
- }
-}
-
-impl ItemResolver {
- /// Construct a new `ItemResolver` from the given id.
- pub fn new<Id: Into<ItemId>>(id: Id) -> ItemResolver {
- let id = id.into();
- ItemResolver {
- id,
- through_type_refs: false,
- through_type_aliases: false,
- }
- }
-
- /// Keep resolving through `Type::TypeRef` items.
- pub fn through_type_refs(mut self) -> ItemResolver {
- self.through_type_refs = true;
- self
- }
-
- /// Keep resolving through `Type::Alias` items.
- pub fn through_type_aliases(mut self) -> ItemResolver {
- self.through_type_aliases = true;
- self
- }
-
- /// Finish configuring and perform the actual item resolution.
- pub fn resolve(self, ctx: &BindgenContext) -> &Item {
- assert!(ctx.collected_typerefs());
-
- let mut id = self.id;
- let mut seen_ids = HashSet::default();
- loop {
- let item = ctx.resolve_item(id);
-
- // Detect cycles and bail out. These can happen in certain cases
- // involving incomplete qualified dependent types (#2085).
- if !seen_ids.insert(id) {
- return item;
- }
-
- let ty_kind = item.as_type().map(|t| t.kind());
- match ty_kind {
- Some(&TypeKind::ResolvedTypeRef(next_id))
- if self.through_type_refs =>
- {
- id = next_id.into();
- }
- // We intentionally ignore template aliases here, as they are
- // more complicated, and don't represent a simple renaming of
- // some type.
- Some(&TypeKind::Alias(next_id))
- if self.through_type_aliases =>
- {
- id = next_id.into();
- }
- _ => return item,
- }
- }
- }
-}
-
-/// A type that we are in the middle of parsing.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct PartialType {
- decl: Cursor,
- // Just an ItemId, and not a TypeId, because we haven't finished this type
- // yet, so there's still time for things to go wrong.
- id: ItemId,
-}
-
-impl PartialType {
- /// Construct a new `PartialType`.
- pub fn new(decl: Cursor, id: ItemId) -> PartialType {
- // assert!(decl == decl.canonical());
- PartialType { decl, id }
- }
-
- /// The cursor pointing to this partial type's declaration location.
- pub fn decl(&self) -> &Cursor {
- &self.decl
- }
-
- /// The item ID allocated for this type. This is *NOT* a key for an entry in
- /// the context's item set yet!
- pub fn id(&self) -> ItemId {
- self.id
- }
-}
-
-impl TemplateParameters for PartialType {
- fn self_template_params(&self, _ctx: &BindgenContext) -> Vec<TypeId> {
- // Maybe at some point we will eagerly parse named types, but for now we
- // don't and this information is unavailable.
- vec![]
- }
-
- fn num_self_template_params(&self, _ctx: &BindgenContext) -> usize {
- // Wouldn't it be nice if libclang would reliably give us this
- // information‽
- match self.decl().kind() {
- clang_sys::CXCursor_ClassTemplate |
- clang_sys::CXCursor_FunctionTemplate |
- clang_sys::CXCursor_TypeAliasTemplateDecl => {
- let mut num_params = 0;
- self.decl().visit(|c| {
- match c.kind() {
- clang_sys::CXCursor_TemplateTypeParameter |
- clang_sys::CXCursor_TemplateTemplateParameter |
- clang_sys::CXCursor_NonTypeTemplateParameter => {
- num_params += 1;
- }
- _ => {}
- };
- clang_sys::CXChildVisit_Continue
- });
- num_params
- }
- _ => 0,
- }
- }
-}
diff --git a/src/ir/derive.rs b/src/ir/derive.rs
deleted file mode 100644
index 594ce2ab..00000000
--- a/src/ir/derive.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-//! Traits for determining whether we can derive traits for a thing or not.
-//!
-//! These traits tend to come in pairs:
-//!
-//! 1. A "trivial" version, whose implementations aren't allowed to recursively
-//! look at other types or the results of fix point analyses.
-//!
-//! 2. A "normal" version, whose implementations simply query the results of a
-//! fix point analysis.
-//!
-//! The former is used by the analyses when creating the results queried by the
-//! second.
-
-use super::context::BindgenContext;
-
-use std::cmp;
-use std::ops;
-
-/// A trait that encapsulates the logic for whether or not we can derive `Debug`
-/// for a given thing.
-pub trait CanDeriveDebug {
- /// Return `true` if `Debug` can be derived for this thing, `false`
- /// otherwise.
- fn can_derive_debug(&self, ctx: &BindgenContext) -> bool;
-}
-
-/// A trait that encapsulates the logic for whether or not we can derive `Copy`
-/// for a given thing.
-pub trait CanDeriveCopy {
- /// Return `true` if `Copy` can be derived for this thing, `false`
- /// otherwise.
- fn can_derive_copy(&self, ctx: &BindgenContext) -> bool;
-}
-
-/// A trait that encapsulates the logic for whether or not we can derive
-/// `Default` for a given thing.
-pub trait CanDeriveDefault {
- /// Return `true` if `Default` can be derived for this thing, `false`
- /// otherwise.
- fn can_derive_default(&self, ctx: &BindgenContext) -> bool;
-}
-
-/// A trait that encapsulates the logic for whether or not we can derive `Hash`
-/// for a given thing.
-pub trait CanDeriveHash {
- /// Return `true` if `Hash` can be derived for this thing, `false`
- /// otherwise.
- fn can_derive_hash(&self, ctx: &BindgenContext) -> bool;
-}
-
-/// A trait that encapsulates the logic for whether or not we can derive
-/// `PartialEq` for a given thing.
-pub trait CanDerivePartialEq {
- /// Return `true` if `PartialEq` can be derived for this thing, `false`
- /// otherwise.
- fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool;
-}
-
-/// A trait that encapsulates the logic for whether or not we can derive
-/// `PartialOrd` for a given thing.
-pub trait CanDerivePartialOrd {
- /// Return `true` if `PartialOrd` can be derived for this thing, `false`
- /// otherwise.
- fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool;
-}
-
-/// A trait that encapsulates the logic for whether or not we can derive `Eq`
-/// for a given thing.
-pub trait CanDeriveEq {
- /// Return `true` if `Eq` can be derived for this thing, `false` otherwise.
- fn can_derive_eq(&self, ctx: &BindgenContext) -> bool;
-}
-
-/// A trait that encapsulates the logic for whether or not we can derive `Ord`
-/// for a given thing.
-pub trait CanDeriveOrd {
- /// Return `true` if `Ord` can be derived for this thing, `false` otherwise.
- fn can_derive_ord(&self, ctx: &BindgenContext) -> bool;
-}
-
-/// Whether it is possible or not to automatically derive trait for an item.
-///
-/// ```ignore
-/// No
-/// ^
-/// |
-/// Manually
-/// ^
-/// |
-/// Yes
-/// ```
-///
-/// Initially we assume that we can derive trait for all types and then
-/// update our understanding as we learn more about each type.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub enum CanDerive {
- /// Yes, we can derive automatically.
- Yes,
-
- /// The only thing that stops us from automatically deriving is that
- /// array with more than maximum number of elements is used.
- ///
- /// This means we probably can "manually" implement such trait.
- Manually,
-
- /// No, we cannot.
- No,
-}
-
-impl Default for CanDerive {
- fn default() -> CanDerive {
- CanDerive::Yes
- }
-}
-
-impl CanDerive {
- /// Take the least upper bound of `self` and `rhs`.
- pub fn join(self, rhs: Self) -> Self {
- cmp::max(self, rhs)
- }
-}
-
-impl ops::BitOr for CanDerive {
- type Output = Self;
-
- fn bitor(self, rhs: Self) -> Self::Output {
- self.join(rhs)
- }
-}
-
-impl ops::BitOrAssign for CanDerive {
- fn bitor_assign(&mut self, rhs: Self) {
- *self = self.join(rhs)
- }
-}
diff --git a/src/ir/dot.rs b/src/ir/dot.rs
deleted file mode 100644
index f7d07f19..00000000
--- a/src/ir/dot.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-//! Generating Graphviz `dot` files from our IR.
-
-use super::context::{BindgenContext, ItemId};
-use super::traversal::Trace;
-use std::fs::File;
-use std::io::{self, Write};
-use std::path::Path;
-
-/// A trait for anything that can write attributes as `<table>` rows to a dot
-/// file.
-pub trait DotAttributes {
- /// Write this thing's attributes to the given output. Each attribute must
- /// be its own `<tr>...</tr>`.
- fn dot_attributes<W>(
- &self,
- ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write;
-}
-
-/// Write a graphviz dot file containing our IR.
-pub fn write_dot_file<P>(ctx: &BindgenContext, path: P) -> io::Result<()>
-where
- P: AsRef<Path>,
-{
- let file = File::create(path)?;
- let mut dot_file = io::BufWriter::new(file);
- writeln!(&mut dot_file, "digraph {{")?;
-
- let mut err: Option<io::Result<_>> = None;
-
- for (id, item) in ctx.items() {
- let is_allowlisted = ctx.allowlisted_items().contains(&id);
-
- writeln!(
- &mut dot_file,
- r#"{} [fontname="courier", color={}, label=< <table border="0" align="left">"#,
- id.as_usize(),
- if is_allowlisted { "black" } else { "gray" }
- )?;
- item.dot_attributes(ctx, &mut dot_file)?;
- writeln!(&mut dot_file, r#"</table> >];"#)?;
-
- item.trace(
- ctx,
- &mut |sub_id: ItemId, edge_kind| {
- if err.is_some() {
- return;
- }
-
- match writeln!(
- &mut dot_file,
- "{} -> {} [label={:?}, color={}];",
- id.as_usize(),
- sub_id.as_usize(),
- edge_kind,
- if is_allowlisted { "black" } else { "gray" }
- ) {
- Ok(_) => {}
- Err(e) => err = Some(Err(e)),
- }
- },
- &(),
- );
-
- if let Some(err) = err {
- return err;
- }
-
- if let Some(module) = item.as_module() {
- for child in module.children() {
- writeln!(
- &mut dot_file,
- "{} -> {} [style=dotted, color=gray]",
- item.id().as_usize(),
- child.as_usize()
- )?;
- }
- }
- }
-
- writeln!(&mut dot_file, "}}")?;
- Ok(())
-}
diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs
deleted file mode 100644
index 123d1d79..00000000
--- a/src/ir/enum_ty.rs
+++ /dev/null
@@ -1,320 +0,0 @@
-//! Intermediate representation for C/C++ enumerations.
-
-use super::super::codegen::EnumVariation;
-use super::context::{BindgenContext, TypeId};
-use super::item::Item;
-use super::ty::{Type, TypeKind};
-use crate::clang;
-use crate::ir::annotations::Annotations;
-use crate::parse::{ClangItemParser, ParseError};
-use crate::regex_set::RegexSet;
-
-/// An enum representing custom handling that can be given to a variant.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum EnumVariantCustomBehavior {
- /// This variant will be a module containing constants.
- ModuleConstify,
- /// This variant will be constified, that is, forced to generate a constant.
- Constify,
- /// This variant will be hidden entirely from the resulting enum.
- Hide,
-}
-
-/// A C/C++ enumeration.
-#[derive(Debug)]
-pub struct Enum {
- /// The representation used for this enum; it should be an `IntKind` type or
- /// an alias to one.
- ///
- /// It's `None` if the enum is a forward declaration and isn't defined
- /// anywhere else, see `tests/headers/func_ptr_in_struct.h`.
- repr: Option<TypeId>,
-
- /// The different variants, with explicit values.
- variants: Vec<EnumVariant>,
-}
-
-impl Enum {
- /// Construct a new `Enum` with the given representation and variants.
- pub fn new(repr: Option<TypeId>, variants: Vec<EnumVariant>) -> Self {
- Enum { repr, variants }
- }
-
- /// Get this enumeration's representation.
- pub fn repr(&self) -> Option<TypeId> {
- self.repr
- }
-
- /// Get this enumeration's variants.
- pub fn variants(&self) -> &[EnumVariant] {
- &self.variants
- }
-
- /// Construct an enumeration from the given Clang type.
- pub fn from_ty(
- ty: &clang::Type,
- ctx: &mut BindgenContext,
- ) -> Result<Self, ParseError> {
- use clang_sys::*;
- debug!("Enum::from_ty {:?}", ty);
-
- if ty.kind() != CXType_Enum {
- return Err(ParseError::Continue);
- }
-
- let declaration = ty.declaration().canonical();
- let repr = declaration
- .enum_type()
- .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok());
- let mut variants = vec![];
-
- let variant_ty =
- repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx));
- let is_bool = variant_ty.map_or(false, Type::is_bool);
-
- // Assume signedness since the default type by the C standard is an int.
- let is_signed = variant_ty.map_or(true, |ty| match *ty.kind() {
- TypeKind::Int(ref int_kind) => int_kind.is_signed(),
- ref other => {
- panic!("Since when enums can be non-integers? {:?}", other)
- }
- });
-
- let type_name = ty.spelling();
- let type_name = if type_name.is_empty() {
- None
- } else {
- Some(type_name)
- };
- let type_name = type_name.as_deref();
-
- let definition = declaration.definition().unwrap_or(declaration);
- definition.visit(|cursor| {
- if cursor.kind() == CXCursor_EnumConstantDecl {
- let value = if is_bool {
- cursor.enum_val_boolean().map(EnumVariantValue::Boolean)
- } else if is_signed {
- cursor.enum_val_signed().map(EnumVariantValue::Signed)
- } else {
- cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned)
- };
- if let Some(val) = value {
- let name = cursor.spelling();
- let annotations = Annotations::new(&cursor);
- let custom_behavior = ctx
- .parse_callbacks()
- .and_then(|callbacks| {
- callbacks
- .enum_variant_behavior(type_name, &name, val)
- })
- .or_else(|| {
- let annotations = annotations.as_ref()?;
- if annotations.hide() {
- Some(EnumVariantCustomBehavior::Hide)
- } else if annotations.constify_enum_variant() {
- Some(EnumVariantCustomBehavior::Constify)
- } else {
- None
- }
- });
-
- let new_name = ctx
- .parse_callbacks()
- .and_then(|callbacks| {
- callbacks.enum_variant_name(type_name, &name, val)
- })
- .or_else(|| {
- annotations
- .as_ref()?
- .use_instead_of()?
- .last()
- .cloned()
- })
- .unwrap_or_else(|| name.clone());
-
- let comment = cursor.raw_comment();
- variants.push(EnumVariant::new(
- new_name,
- name,
- comment,
- val,
- custom_behavior,
- ));
- }
- }
- CXChildVisit_Continue
- });
- Ok(Enum::new(repr, variants))
- }
-
- fn is_matching_enum(
- &self,
- ctx: &BindgenContext,
- enums: &RegexSet,
- item: &Item,
- ) -> bool {
- let path = item.path_for_allowlisting(ctx);
- let enum_ty = item.expect_type();
-
- if enums.matches(&path[1..].join("::")) {
- return true;
- }
-
- // Test the variants if the enum is anonymous.
- if enum_ty.name().is_some() {
- return false;
- }
-
- self.variants().iter().any(|v| enums.matches(v.name()))
- }
-
- /// Returns the final representation of the enum.
- pub fn computed_enum_variation(
- &self,
- ctx: &BindgenContext,
- item: &Item,
- ) -> EnumVariation {
- // ModuleConsts has higher precedence before Rust in order to avoid
- // problems with overlapping match patterns.
- if self.is_matching_enum(
- ctx,
- &ctx.options().constified_enum_modules,
- item,
- ) {
- EnumVariation::ModuleConsts
- } else if self.is_matching_enum(
- ctx,
- &ctx.options().bitfield_enums,
- item,
- ) {
- EnumVariation::NewType {
- is_bitfield: true,
- is_global: false,
- }
- } else if self.is_matching_enum(ctx, &ctx.options().newtype_enums, item)
- {
- EnumVariation::NewType {
- is_bitfield: false,
- is_global: false,
- }
- } else if self.is_matching_enum(
- ctx,
- &ctx.options().newtype_global_enums,
- item,
- ) {
- EnumVariation::NewType {
- is_bitfield: false,
- is_global: true,
- }
- } else if self.is_matching_enum(
- ctx,
- &ctx.options().rustified_enums,
- item,
- ) {
- EnumVariation::Rust {
- non_exhaustive: false,
- }
- } else if self.is_matching_enum(
- ctx,
- &ctx.options().rustified_non_exhaustive_enums,
- item,
- ) {
- EnumVariation::Rust {
- non_exhaustive: true,
- }
- } else if self.is_matching_enum(
- ctx,
- &ctx.options().constified_enums,
- item,
- ) {
- EnumVariation::Consts
- } else {
- ctx.options().default_enum_style
- }
- }
-}
-
-/// A single enum variant, to be contained only in an enum.
-#[derive(Debug)]
-pub struct EnumVariant {
- /// The name of the variant.
- name: String,
-
- /// The original name of the variant (without user mangling)
- name_for_allowlisting: String,
-
- /// An optional doc comment.
- comment: Option<String>,
-
- /// The integer value of the variant.
- val: EnumVariantValue,
-
- /// The custom behavior this variant may have, if any.
- custom_behavior: Option<EnumVariantCustomBehavior>,
-}
-
-/// A constant value assigned to an enumeration variant.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum EnumVariantValue {
- /// A boolean constant.
- Boolean(bool),
-
- /// A signed constant.
- Signed(i64),
-
- /// An unsigned constant.
- Unsigned(u64),
-}
-
-impl EnumVariant {
- /// Construct a new enumeration variant from the given parts.
- pub fn new(
- name: String,
- name_for_allowlisting: String,
- comment: Option<String>,
- val: EnumVariantValue,
- custom_behavior: Option<EnumVariantCustomBehavior>,
- ) -> Self {
- EnumVariant {
- name,
- name_for_allowlisting,
- comment,
- val,
- custom_behavior,
- }
- }
-
- /// Get this variant's name.
- pub fn name(&self) -> &str {
- &self.name
- }
-
- /// Get this variant's name.
- pub fn name_for_allowlisting(&self) -> &str {
- &self.name_for_allowlisting
- }
-
- /// Get this variant's value.
- pub fn val(&self) -> EnumVariantValue {
- self.val
- }
-
- /// Get this variant's documentation.
- pub fn comment(&self) -> Option<&str> {
- self.comment.as_deref()
- }
-
- /// Returns whether this variant should be enforced to be a constant by code
- /// generation.
- pub fn force_constification(&self) -> bool {
- self.custom_behavior
- .map_or(false, |b| b == EnumVariantCustomBehavior::Constify)
- }
-
- /// Returns whether the current variant should be hidden completely from the
- /// resulting rust enum.
- pub fn hidden(&self) -> bool {
- self.custom_behavior
- .map_or(false, |b| b == EnumVariantCustomBehavior::Hide)
- }
-}
diff --git a/src/ir/function.rs b/src/ir/function.rs
deleted file mode 100644
index 928b5aad..00000000
--- a/src/ir/function.rs
+++ /dev/null
@@ -1,690 +0,0 @@
-//! Intermediate representation for C/C++ functions and methods.
-
-use super::comp::MethodKind;
-use super::context::{BindgenContext, TypeId};
-use super::dot::DotAttributes;
-use super::item::Item;
-use super::traversal::{EdgeKind, Trace, Tracer};
-use super::ty::TypeKind;
-use crate::clang::{self, Attribute};
-use crate::parse::{
- ClangItemParser, ClangSubItemParser, ParseError, ParseResult,
-};
-use clang_sys::{self, CXCallingConv};
-use proc_macro2;
-use quote;
-use quote::TokenStreamExt;
-use std::io;
-
-const RUST_DERIVE_FUNPTR_LIMIT: usize = 12;
-
-/// What kind of a function are we looking at?
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum FunctionKind {
- /// A plain, free function.
- Function,
- /// A method of some kind.
- Method(MethodKind),
-}
-
-impl FunctionKind {
- /// Given a clang cursor, return the kind of function it represents, or
- /// `None` otherwise.
- pub fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> {
- // FIXME(emilio): Deduplicate logic with `ir::comp`.
- Some(match cursor.kind() {
- clang_sys::CXCursor_FunctionDecl => FunctionKind::Function,
- clang_sys::CXCursor_Constructor => {
- FunctionKind::Method(MethodKind::Constructor)
- }
- clang_sys::CXCursor_Destructor => {
- FunctionKind::Method(if cursor.method_is_virtual() {
- MethodKind::VirtualDestructor {
- pure_virtual: cursor.method_is_pure_virtual(),
- }
- } else {
- MethodKind::Destructor
- })
- }
- clang_sys::CXCursor_CXXMethod => {
- if cursor.method_is_virtual() {
- FunctionKind::Method(MethodKind::Virtual {
- pure_virtual: cursor.method_is_pure_virtual(),
- })
- } else if cursor.method_is_static() {
- FunctionKind::Method(MethodKind::Static)
- } else {
- FunctionKind::Method(MethodKind::Normal)
- }
- }
- _ => return None,
- })
- }
-}
-
-/// The style of linkage
-#[derive(Debug, Clone, Copy)]
-pub enum Linkage {
- /// Externally visible and can be linked against
- External,
- /// Not exposed externally. 'static inline' functions will have this kind of linkage
- Internal,
-}
-
-/// A function declaration, with a signature, arguments, and argument names.
-///
-/// The argument names vector must be the same length as the ones in the
-/// signature.
-#[derive(Debug)]
-pub struct Function {
- /// The name of this function.
- name: String,
-
- /// The mangled name, that is, the symbol.
- mangled_name: Option<String>,
-
- /// The id pointing to the current function signature.
- signature: TypeId,
-
- /// The doc comment on the function, if any.
- comment: Option<String>,
-
- /// The kind of function this is.
- kind: FunctionKind,
-
- /// The linkage of the function.
- linkage: Linkage,
-}
-
-impl Function {
- /// Construct a new function.
- pub fn new(
- name: String,
- mangled_name: Option<String>,
- signature: TypeId,
- comment: Option<String>,
- kind: FunctionKind,
- linkage: Linkage,
- ) -> Self {
- Function {
- name,
- mangled_name,
- signature,
- comment,
- kind,
- linkage,
- }
- }
-
- /// Get this function's name.
- pub fn name(&self) -> &str {
- &self.name
- }
-
- /// Get this function's name.
- pub fn mangled_name(&self) -> Option<&str> {
- self.mangled_name.as_deref()
- }
-
- /// Get this function's signature type.
- pub fn signature(&self) -> TypeId {
- self.signature
- }
-
- /// Get this function's comment.
- pub fn comment(&self) -> Option<&str> {
- self.comment.as_deref()
- }
-
- /// Get this function's kind.
- pub fn kind(&self) -> FunctionKind {
- self.kind
- }
-
- /// Get this function's linkage.
- pub fn linkage(&self) -> Linkage {
- self.linkage
- }
-}
-
-impl DotAttributes for Function {
- fn dot_attributes<W>(
- &self,
- _ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write,
- {
- if let Some(ref mangled) = self.mangled_name {
- let mangled: String =
- mangled.chars().flat_map(|c| c.escape_default()).collect();
- writeln!(
- out,
- "<tr><td>mangled name</td><td>{}</td></tr>",
- mangled
- )?;
- }
-
- Ok(())
- }
-}
-
-/// An ABI extracted from a clang cursor.
-#[derive(Debug, Copy, Clone)]
-pub enum Abi {
- /// The default C ABI.
- C,
- /// The "stdcall" ABI.
- Stdcall,
- /// The "fastcall" ABI.
- Fastcall,
- /// The "thiscall" ABI.
- ThisCall,
- /// The "vectorcall" ABI.
- Vectorcall,
- /// The "aapcs" ABI.
- Aapcs,
- /// The "win64" ABI.
- Win64,
- /// An unknown or invalid ABI.
- Unknown(CXCallingConv),
-}
-
-impl Abi {
- /// Returns whether this Abi is known or not.
- fn is_unknown(&self) -> bool {
- matches!(*self, Abi::Unknown(..))
- }
-}
-
-impl quote::ToTokens for Abi {
- fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
- tokens.append_all(match *self {
- Abi::C => quote! { "C" },
- Abi::Stdcall => quote! { "stdcall" },
- Abi::Fastcall => quote! { "fastcall" },
- Abi::ThisCall => quote! { "thiscall" },
- Abi::Vectorcall => quote! { "vectorcall" },
- Abi::Aapcs => quote! { "aapcs" },
- Abi::Win64 => quote! { "win64" },
- Abi::Unknown(cc) => panic!(
- "Cannot turn unknown calling convention to tokens: {:?}",
- cc
- ),
- });
- }
-}
-
-/// A function signature.
-#[derive(Debug)]
-pub struct FunctionSig {
- /// The return type of the function.
- return_type: TypeId,
-
- /// The type of the arguments, optionally with the name of the argument when
- /// declared.
- argument_types: Vec<(Option<String>, TypeId)>,
-
- /// Whether this function is variadic.
- is_variadic: bool,
- is_divergent: bool,
-
- /// Whether this function's return value must be used.
- must_use: bool,
-
- /// The ABI of this function.
- abi: Abi,
-}
-
-fn get_abi(cc: CXCallingConv) -> Abi {
- use clang_sys::*;
- match cc {
- CXCallingConv_Default => Abi::C,
- CXCallingConv_C => Abi::C,
- CXCallingConv_X86StdCall => Abi::Stdcall,
- CXCallingConv_X86FastCall => Abi::Fastcall,
- CXCallingConv_X86ThisCall => Abi::ThisCall,
- CXCallingConv_X86VectorCall => Abi::Vectorcall,
- CXCallingConv_AAPCS => Abi::Aapcs,
- CXCallingConv_X86_64Win64 => Abi::Win64,
- other => Abi::Unknown(other),
- }
-}
-
-/// Get the mangled name for the cursor's referent.
-pub fn cursor_mangling(
- ctx: &BindgenContext,
- cursor: &clang::Cursor,
-) -> Option<String> {
- if !ctx.options().enable_mangling {
- return None;
- }
-
- // We early return here because libclang may crash in some case
- // if we pass in a variable inside a partial specialized template.
- // See rust-lang/rust-bindgen#67, and rust-lang/rust-bindgen#462.
- if cursor.is_in_non_fully_specialized_template() {
- return None;
- }
-
- let is_destructor = cursor.kind() == clang_sys::CXCursor_Destructor;
- if let Ok(mut manglings) = cursor.cxx_manglings() {
- while let Some(m) = manglings.pop() {
- // Only generate the destructor group 1, see below.
- if is_destructor && !m.ends_with("D1Ev") {
- continue;
- }
-
- return Some(m);
- }
- }
-
- let mut mangling = cursor.mangling();
- if mangling.is_empty() {
- return None;
- }
-
- if is_destructor {
- // With old (3.8-) libclang versions, and the Itanium ABI, clang returns
- // the "destructor group 0" symbol, which means that it'll try to free
- // memory, which definitely isn't what we want.
- //
- // Explicitly force the destructor group 1 symbol.
- //
- // See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special
- // for the reference, and http://stackoverflow.com/a/6614369/1091587 for
- // a more friendly explanation.
- //
- // We don't need to do this for constructors since clang seems to always
- // have returned the C1 constructor.
- //
- // FIXME(emilio): Can a legit symbol in other ABIs end with this string?
- // I don't think so, but if it can this would become a linker error
- // anyway, not an invalid free at runtime.
- //
- // TODO(emilio, #611): Use cpp_demangle if this becomes nastier with
- // time.
- if mangling.ends_with("D0Ev") {
- let new_len = mangling.len() - 4;
- mangling.truncate(new_len);
- mangling.push_str("D1Ev");
- }
- }
-
- Some(mangling)
-}
-
-fn args_from_ty_and_cursor(
- ty: &clang::Type,
- cursor: &clang::Cursor,
- ctx: &mut BindgenContext,
-) -> Vec<(Option<String>, TypeId)> {
- let cursor_args = cursor.args().unwrap_or_default().into_iter();
- let type_args = ty.args().unwrap_or_default().into_iter();
-
- // Argument types can be found in either the cursor or the type, but argument names may only be
- // found on the cursor. We often have access to both a type and a cursor for each argument, but
- // in some cases we may only have one.
- //
- // Prefer using the type as the source of truth for the argument's type, but fall back to
- // inspecting the cursor (this happens for Objective C interfaces).
- //
- // Prefer using the cursor for the argument's type, but fall back to using the parent's cursor
- // (this happens for function pointer return types).
- cursor_args
- .map(Some)
- .chain(std::iter::repeat(None))
- .zip(type_args.map(Some).chain(std::iter::repeat(None)))
- .take_while(|(cur, ty)| cur.is_some() || ty.is_some())
- .map(|(arg_cur, arg_ty)| {
- let name = arg_cur.map(|a| a.spelling()).and_then(|name| {
- if name.is_empty() {
- None
- } else {
- Some(name)
- }
- });
-
- let cursor = arg_cur.unwrap_or(*cursor);
- let ty = arg_ty.unwrap_or_else(|| cursor.cur_type());
- (name, Item::from_ty_or_ref(ty, cursor, None, ctx))
- })
- .collect()
-}
-
-impl FunctionSig {
- /// Construct a new function signature.
- pub fn new(
- return_type: TypeId,
- argument_types: Vec<(Option<String>, TypeId)>,
- is_variadic: bool,
- is_divergent: bool,
- must_use: bool,
- abi: Abi,
- ) -> Self {
- FunctionSig {
- return_type,
- argument_types,
- is_variadic,
- is_divergent,
- must_use,
- abi,
- }
- }
-
- /// Construct a new function signature from the given Clang type.
- pub fn from_ty(
- ty: &clang::Type,
- cursor: &clang::Cursor,
- ctx: &mut BindgenContext,
- ) -> Result<Self, ParseError> {
- use clang_sys::*;
- debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor);
-
- // Skip function templates
- let kind = cursor.kind();
- if kind == CXCursor_FunctionTemplate {
- return Err(ParseError::Continue);
- }
-
- let spelling = cursor.spelling();
-
- // Don't parse operatorxx functions in C++
- let is_operator = |spelling: &str| {
- spelling.starts_with("operator") &&
- !clang::is_valid_identifier(spelling)
- };
- if is_operator(&spelling) {
- return Err(ParseError::Continue);
- }
-
- // Constructors of non-type template parameter classes for some reason
- // include the template parameter in their name. Just skip them, since
- // we don't handle well non-type template parameters anyway.
- if (kind == CXCursor_Constructor || kind == CXCursor_Destructor) &&
- spelling.contains('<')
- {
- return Err(ParseError::Continue);
- }
-
- let cursor = if cursor.is_valid() {
- *cursor
- } else {
- ty.declaration()
- };
-
- let mut args = match kind {
- CXCursor_FunctionDecl |
- CXCursor_Constructor |
- CXCursor_CXXMethod |
- CXCursor_ObjCInstanceMethodDecl |
- CXCursor_ObjCClassMethodDecl => {
- args_from_ty_and_cursor(ty, &cursor, ctx)
- }
- _ => {
- // For non-CXCursor_FunctionDecl, visiting the cursor's children
- // is the only reliable way to get parameter names.
- let mut args = vec![];
- cursor.visit(|c| {
- if c.kind() == CXCursor_ParmDecl {
- let ty =
- Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
- let name = c.spelling();
- let name =
- if name.is_empty() { None } else { Some(name) };
- args.push((name, ty));
- }
- CXChildVisit_Continue
- });
-
- if args.is_empty() {
- // FIXME(emilio): Sometimes libclang doesn't expose the
- // right AST for functions tagged as stdcall and such...
- //
- // https://bugs.llvm.org/show_bug.cgi?id=45919
- args_from_ty_and_cursor(ty, &cursor, ctx)
- } else {
- args
- }
- }
- };
-
- let (must_use, mut is_divergent) =
- if ctx.options().enable_function_attribute_detection {
- let [must_use, no_return, no_return_cpp] = cursor.has_attrs(&[
- Attribute::MUST_USE,
- Attribute::NO_RETURN,
- Attribute::NO_RETURN_CPP,
- ]);
- (must_use, no_return || no_return_cpp)
- } else {
- Default::default()
- };
-
- // This looks easy to break but the clang parser keeps the type spelling clean even if
- // other attributes are added.
- is_divergent =
- is_divergent || ty.spelling().contains("__attribute__((noreturn))");
-
- let is_method = kind == CXCursor_CXXMethod;
- let is_constructor = kind == CXCursor_Constructor;
- let is_destructor = kind == CXCursor_Destructor;
- if (is_constructor || is_destructor || is_method) &&
- cursor.lexical_parent() != cursor.semantic_parent()
- {
- // Only parse constructors once.
- return Err(ParseError::Continue);
- }
-
- if is_method || is_constructor || is_destructor {
- let is_const = is_method && cursor.method_is_const();
- let is_virtual = is_method && cursor.method_is_virtual();
- let is_static = is_method && cursor.method_is_static();
- if !is_static && !is_virtual {
- let parent = cursor.semantic_parent();
- let class = Item::parse(parent, None, ctx)
- .expect("Expected to parse the class");
- // The `class` most likely is not finished parsing yet, so use
- // the unchecked variant.
- let class = class.as_type_id_unchecked();
-
- let class = if is_const {
- let const_class_id = ctx.next_item_id();
- ctx.build_const_wrapper(
- const_class_id,
- class,
- None,
- &parent.cur_type(),
- )
- } else {
- class
- };
-
- let ptr =
- Item::builtin_type(TypeKind::Pointer(class), false, ctx);
- args.insert(0, (Some("this".into()), ptr));
- } else if is_virtual {
- let void = Item::builtin_type(TypeKind::Void, false, ctx);
- let ptr =
- Item::builtin_type(TypeKind::Pointer(void), false, ctx);
- args.insert(0, (Some("this".into()), ptr));
- }
- }
-
- let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl ||
- kind == CXCursor_ObjCClassMethodDecl
- {
- ty.ret_type()
- .or_else(|| cursor.ret_type())
- .ok_or(ParseError::Continue)?
- } else {
- ty.ret_type().ok_or(ParseError::Continue)?
- };
-
- let ret = if is_constructor && ctx.is_target_wasm32() {
- // Constructors in Clang wasm32 target return a pointer to the object
- // being constructed.
- let void = Item::builtin_type(TypeKind::Void, false, ctx);
- Item::builtin_type(TypeKind::Pointer(void), false, ctx)
- } else {
- Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx)
- };
-
- // Clang plays with us at "find the calling convention", see #549 and
- // co. This seems to be a better fix than that commit.
- let mut call_conv = ty.call_conv();
- if let Some(ty) = cursor.cur_type().canonical_type().pointee_type() {
- let cursor_call_conv = ty.call_conv();
- if cursor_call_conv != CXCallingConv_Invalid {
- call_conv = cursor_call_conv;
- }
- }
- let abi = get_abi(call_conv);
-
- if abi.is_unknown() {
- warn!("Unknown calling convention: {:?}", call_conv);
- }
-
- Ok(Self::new(
- ret,
- args,
- ty.is_variadic(),
- is_divergent,
- must_use,
- abi,
- ))
- }
-
- /// Get this function signature's return type.
- pub fn return_type(&self) -> TypeId {
- self.return_type
- }
-
- /// Get this function signature's argument (name, type) pairs.
- pub fn argument_types(&self) -> &[(Option<String>, TypeId)] {
- &self.argument_types
- }
-
- /// Get this function signature's ABI.
- pub fn abi(&self) -> Abi {
- self.abi
- }
-
- /// Is this function signature variadic?
- pub fn is_variadic(&self) -> bool {
- // Clang reports some functions as variadic when they *might* be
- // variadic. We do the argument check because rust doesn't codegen well
- // variadic functions without an initial argument.
- self.is_variadic && !self.argument_types.is_empty()
- }
-
- /// Must this function's return value be used?
- pub fn must_use(&self) -> bool {
- self.must_use
- }
-
- /// Are function pointers with this signature able to derive Rust traits?
- /// Rust only supports deriving traits for function pointers with a limited
- /// number of parameters and a couple ABIs.
- ///
- /// For more details, see:
- ///
- /// * https://github.com/rust-lang/rust-bindgen/issues/547,
- /// * https://github.com/rust-lang/rust/issues/38848,
- /// * and https://github.com/rust-lang/rust/issues/40158
- pub fn function_pointers_can_derive(&self) -> bool {
- if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT {
- return false;
- }
-
- matches!(self.abi, Abi::C | Abi::Unknown(..))
- }
-
- pub(crate) fn is_divergent(&self) -> bool {
- self.is_divergent
- }
-}
-
-impl ClangSubItemParser for Function {
- fn parse(
- cursor: clang::Cursor,
- context: &mut BindgenContext,
- ) -> Result<ParseResult<Self>, ParseError> {
- use clang_sys::*;
-
- let kind = match FunctionKind::from_cursor(&cursor) {
- None => return Err(ParseError::Continue),
- Some(k) => k,
- };
-
- debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());
-
- let visibility = cursor.visibility();
- if visibility != CXVisibility_Default {
- return Err(ParseError::Continue);
- }
-
- if cursor.access_specifier() == CX_CXXPrivate {
- return Err(ParseError::Continue);
- }
-
- if cursor.is_inlined_function() {
- if !context.options().generate_inline_functions {
- return Err(ParseError::Continue);
- }
- if cursor.is_deleted_function() {
- return Err(ParseError::Continue);
- }
- }
-
- let linkage = cursor.linkage();
- let linkage = match linkage {
- CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External,
- CXLinkage_Internal => Linkage::Internal,
- _ => return Err(ParseError::Continue),
- };
-
- // Grab the signature using Item::from_ty.
- let sig = Item::from_ty(&cursor.cur_type(), cursor, None, context)?;
-
- let mut name = cursor.spelling();
- assert!(!name.is_empty(), "Empty function name?");
-
- if cursor.kind() == CXCursor_Destructor {
- // Remove the leading `~`. The alternative to this is special-casing
- // code-generation for destructor functions, which seems less than
- // ideal.
- if name.starts_with('~') {
- name.remove(0);
- }
-
- // Add a suffix to avoid colliding with constructors. This would be
- // technically fine (since we handle duplicated functions/methods),
- // but seems easy enough to handle it here.
- name.push_str("_destructor");
- }
-
- let mangled_name = cursor_mangling(context, &cursor);
- let comment = cursor.raw_comment();
-
- let function =
- Self::new(name, mangled_name, sig, comment, kind, linkage);
- Ok(ParseResult::New(function, Some(cursor)))
- }
-}
-
-impl Trace for FunctionSig {
- type Extra = ();
-
- fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
- where
- T: Tracer,
- {
- tracer.visit_kind(self.return_type().into(), EdgeKind::FunctionReturn);
-
- for &(_, ty) in self.argument_types() {
- tracer.visit_kind(ty.into(), EdgeKind::FunctionParameter);
- }
- }
-}
diff --git a/src/ir/int.rs b/src/ir/int.rs
deleted file mode 100644
index 22838e89..00000000
--- a/src/ir/int.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-//! Intermediate representation for integral types.
-
-/// Which integral type are we dealing with?
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub enum IntKind {
- /// A `bool`.
- Bool,
-
- /// A `signed char`.
- SChar,
-
- /// An `unsigned char`.
- UChar,
-
- /// An `wchar_t`.
- WChar,
-
- /// A platform-dependent `char` type, with the signedness support.
- Char {
- /// Whether the char is signed for the target platform.
- is_signed: bool,
- },
-
- /// A `short`.
- Short,
-
- /// An `unsigned short`.
- UShort,
-
- /// An `int`.
- Int,
-
- /// An `unsigned int`.
- UInt,
-
- /// A `long`.
- Long,
-
- /// An `unsigned long`.
- ULong,
-
- /// A `long long`.
- LongLong,
-
- /// An `unsigned long long`.
- ULongLong,
-
- /// A 8-bit signed integer.
- I8,
-
- /// A 8-bit unsigned integer.
- U8,
-
- /// A 16-bit signed integer.
- I16,
-
- /// Either a `char16_t` or a `wchar_t`.
- U16,
-
- /// A 32-bit signed integer.
- I32,
-
- /// A 32-bit unsigned integer.
- U32,
-
- /// A 64-bit signed integer.
- I64,
-
- /// A 64-bit unsigned integer.
- U64,
-
- /// An `int128_t`
- I128,
-
- /// A `uint128_t`.
- U128,
-
- /// A custom integer type, used to allow custom macro types depending on
- /// range.
- Custom {
- /// The name of the type, which would be used without modification.
- name: &'static str,
- /// Whether the type is signed or not.
- is_signed: bool,
- },
-}
-
-impl IntKind {
- /// Is this integral type signed?
- pub fn is_signed(&self) -> bool {
- use self::IntKind::*;
- match *self {
- // TODO(emilio): wchar_t can in theory be signed, but we have no way
- // to know whether it is or not right now (unlike char, there's no
- // WChar_S / WChar_U).
- Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 |
- WChar | U32 | U64 | U128 => false,
-
- SChar | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 |
- I128 => true,
-
- Char { is_signed } => is_signed,
-
- Custom { is_signed, .. } => is_signed,
- }
- }
-
- /// If this type has a known size, return it (in bytes). This is to
- /// alleviate libclang sometimes not giving us a layout (like in the case
- /// when an enum is defined inside a class with template parameters).
- pub fn known_size(&self) -> Option<usize> {
- use self::IntKind::*;
- Some(match *self {
- Bool | UChar | SChar | U8 | I8 | Char { .. } => 1,
- U16 | I16 => 2,
- U32 | I32 => 4,
- U64 | I64 => 8,
- I128 | U128 => 16,
- _ => return None,
- })
- }
-
- /// Whether this type's signedness matches the value.
- pub fn signedness_matches(&self, val: i64) -> bool {
- val >= 0 || self.is_signed()
- }
-}
diff --git a/src/ir/item.rs b/src/ir/item.rs
deleted file mode 100644
index 3b15cd6e..00000000
--- a/src/ir/item.rs
+++ /dev/null
@@ -1,2018 +0,0 @@
-//! Bindgen's core intermediate representation type.
-
-use super::super::codegen::{EnumVariation, CONSTIFIED_ENUM_MODULE_REPR_NAME};
-use super::analysis::{HasVtable, HasVtableResult, Sizedness, SizednessResult};
-use super::annotations::Annotations;
-use super::comment;
-use super::comp::{CompKind, MethodKind};
-use super::context::{BindgenContext, ItemId, PartialType, TypeId};
-use super::derive::{
- CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq,
- CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd,
-};
-use super::dot::DotAttributes;
-use super::function::{Function, FunctionKind};
-use super::item_kind::ItemKind;
-use super::layout::Opaque;
-use super::module::Module;
-use super::template::{AsTemplateParam, TemplateParameters};
-use super::traversal::{EdgeKind, Trace, Tracer};
-use super::ty::{Type, TypeKind};
-use crate::clang;
-use crate::parse::{
- ClangItemParser, ClangSubItemParser, ParseError, ParseResult,
-};
-use clang_sys;
-use lazycell::LazyCell;
-use regex;
-use std::cell::Cell;
-use std::collections::BTreeSet;
-use std::fmt::Write;
-use std::io;
-use std::iter;
-
-/// A trait to get the canonical name from an item.
-///
-/// This is the trait that will eventually isolate all the logic related to name
-/// mangling and that kind of stuff.
-///
-/// This assumes no nested paths, at some point I'll have to make it a more
-/// complex thing.
-///
-/// This name is required to be safe for Rust, that is, is not expected to
-/// return any rust keyword from here.
-pub trait ItemCanonicalName {
- /// Get the canonical name for this item.
- fn canonical_name(&self, ctx: &BindgenContext) -> String;
-}
-
-/// The same, but specifies the path that needs to be followed to reach an item.
-///
-/// To contrast with canonical_name, here's an example:
-///
-/// ```c++
-/// namespace foo {
-/// const BAR = 3;
-/// }
-/// ```
-///
-/// For bar, the canonical path is `vec!["foo", "BAR"]`, while the canonical
-/// name is just `"BAR"`.
-pub trait ItemCanonicalPath {
- /// Get the namespace-aware canonical path for this item. This means that if
- /// namespaces are disabled, you'll get a single item, and otherwise you get
- /// the whole path.
- fn namespace_aware_canonical_path(
- &self,
- ctx: &BindgenContext,
- ) -> Vec<String>;
-
- /// Get the canonical path for this item.
- fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String>;
-}
-
-/// A trait for determining if some IR thing is opaque or not.
-pub trait IsOpaque {
- /// Extra context the IR thing needs to determine if it is opaque or not.
- type Extra;
-
- /// Returns `true` if the thing is opaque, and `false` otherwise.
- ///
- /// May only be called when `ctx` is in the codegen phase.
- fn is_opaque(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool;
-}
-
-/// A trait for determining if some IR thing has type parameter in array or not.
-pub trait HasTypeParamInArray {
- /// Returns `true` if the thing has Array, and `false` otherwise.
- fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool;
-}
-
-/// A trait for determining if some IR thing has float or not.
-pub trait HasFloat {
- /// Returns `true` if the thing has float, and `false` otherwise.
- fn has_float(&self, ctx: &BindgenContext) -> bool;
-}
-
-/// A trait for iterating over an item and its parents and up its ancestor chain
-/// up to (but not including) the implicit root module.
-pub trait ItemAncestors {
- /// Get an iterable over this item's ancestors.
- fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a>;
-}
-
-#[cfg(testing_only_extra_assertions)]
-type DebugOnlyItemSet = ItemSet;
-
-#[cfg(not(testing_only_extra_assertions))]
-struct DebugOnlyItemSet;
-
-#[cfg(not(testing_only_extra_assertions))]
-impl DebugOnlyItemSet {
- fn new() -> Self {
- DebugOnlyItemSet
- }
-
- fn contains(&self, _id: &ItemId) -> bool {
- false
- }
-
- fn insert(&mut self, _id: ItemId) {}
-}
-
-/// An iterator over an item and its ancestors.
-pub struct ItemAncestorsIter<'a> {
- item: ItemId,
- ctx: &'a BindgenContext,
- seen: DebugOnlyItemSet,
-}
-
-impl<'a> ItemAncestorsIter<'a> {
- fn new<Id: Into<ItemId>>(ctx: &'a BindgenContext, id: Id) -> Self {
- ItemAncestorsIter {
- item: id.into(),
- ctx,
- seen: DebugOnlyItemSet::new(),
- }
- }
-}
-
-impl<'a> Iterator for ItemAncestorsIter<'a> {
- type Item = ItemId;
-
- fn next(&mut self) -> Option<Self::Item> {
- let item = self.ctx.resolve_item(self.item);
-
- if item.parent_id() == self.item {
- None
- } else {
- self.item = item.parent_id();
-
- extra_assert!(!self.seen.contains(&item.id()));
- self.seen.insert(item.id());
-
- Some(item.id())
- }
- }
-}
-
-impl<T> AsTemplateParam for T
-where
- T: Copy + Into<ItemId>,
-{
- type Extra = ();
-
- fn as_template_param(
- &self,
- ctx: &BindgenContext,
- _: &(),
- ) -> Option<TypeId> {
- ctx.resolve_item((*self).into()).as_template_param(ctx, &())
- }
-}
-
-impl AsTemplateParam for Item {
- type Extra = ();
-
- fn as_template_param(
- &self,
- ctx: &BindgenContext,
- _: &(),
- ) -> Option<TypeId> {
- self.kind.as_template_param(ctx, self)
- }
-}
-
-impl AsTemplateParam for ItemKind {
- type Extra = Item;
-
- fn as_template_param(
- &self,
- ctx: &BindgenContext,
- item: &Item,
- ) -> Option<TypeId> {
- match *self {
- ItemKind::Type(ref ty) => ty.as_template_param(ctx, item),
- ItemKind::Module(..) |
- ItemKind::Function(..) |
- ItemKind::Var(..) => None,
- }
- }
-}
-
-impl<T> ItemCanonicalName for T
-where
- T: Copy + Into<ItemId>,
-{
- fn canonical_name(&self, ctx: &BindgenContext) -> String {
- debug_assert!(
- ctx.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- ctx.resolve_item(*self).canonical_name(ctx)
- }
-}
-
-impl<T> ItemCanonicalPath for T
-where
- T: Copy + Into<ItemId>,
-{
- fn namespace_aware_canonical_path(
- &self,
- ctx: &BindgenContext,
- ) -> Vec<String> {
- debug_assert!(
- ctx.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- ctx.resolve_item(*self).namespace_aware_canonical_path(ctx)
- }
-
- fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
- debug_assert!(
- ctx.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- ctx.resolve_item(*self).canonical_path(ctx)
- }
-}
-
-impl<T> ItemAncestors for T
-where
- T: Copy + Into<ItemId>,
-{
- fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a> {
- ItemAncestorsIter::new(ctx, *self)
- }
-}
-
-impl ItemAncestors for Item {
- fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a> {
- self.id().ancestors(ctx)
- }
-}
-
-impl<Id> Trace for Id
-where
- Id: Copy + Into<ItemId>,
-{
- type Extra = ();
-
- fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, extra: &())
- where
- T: Tracer,
- {
- ctx.resolve_item(*self).trace(ctx, tracer, extra);
- }
-}
-
-impl Trace for Item {
- type Extra = ();
-
- fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, _extra: &())
- where
- T: Tracer,
- {
- // Even if this item is blocklisted/hidden, we want to trace it. It is
- // traversal iterators' consumers' responsibility to filter items as
- // needed. Generally, this filtering happens in the implementation of
- // `Iterator` for `allowlistedItems`. Fully tracing blocklisted items is
- // necessary for things like the template parameter usage analysis to
- // function correctly.
-
- match *self.kind() {
- ItemKind::Type(ref ty) => {
- // There are some types, like resolved type references, where we
- // don't want to stop collecting types even though they may be
- // opaque.
- if ty.should_be_traced_unconditionally() ||
- !self.is_opaque(ctx, &())
- {
- ty.trace(ctx, tracer, self);
- }
- }
- ItemKind::Function(ref fun) => {
- // Just the same way, it has not real meaning for a function to
- // be opaque, so we trace across it.
- tracer.visit(fun.signature().into());
- }
- ItemKind::Var(ref var) => {
- tracer.visit_kind(var.ty().into(), EdgeKind::VarType);
- }
- ItemKind::Module(_) => {
- // Module -> children edges are "weak", and we do not want to
- // trace them. If we did, then allowlisting wouldn't work as
- // expected: everything in every module would end up
- // allowlisted.
- //
- // TODO: make a new edge kind for module -> children edges and
- // filter them during allowlisting traversals.
- }
- }
- }
-}
-
-impl CanDeriveDebug for Item {
- fn can_derive_debug(&self, ctx: &BindgenContext) -> bool {
- self.id().can_derive_debug(ctx)
- }
-}
-
-impl CanDeriveDefault for Item {
- fn can_derive_default(&self, ctx: &BindgenContext) -> bool {
- self.id().can_derive_default(ctx)
- }
-}
-
-impl CanDeriveCopy for Item {
- fn can_derive_copy(&self, ctx: &BindgenContext) -> bool {
- self.id().can_derive_copy(ctx)
- }
-}
-
-impl CanDeriveHash for Item {
- fn can_derive_hash(&self, ctx: &BindgenContext) -> bool {
- self.id().can_derive_hash(ctx)
- }
-}
-
-impl CanDerivePartialOrd for Item {
- fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool {
- self.id().can_derive_partialord(ctx)
- }
-}
-
-impl CanDerivePartialEq for Item {
- fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool {
- self.id().can_derive_partialeq(ctx)
- }
-}
-
-impl CanDeriveEq for Item {
- fn can_derive_eq(&self, ctx: &BindgenContext) -> bool {
- self.id().can_derive_eq(ctx)
- }
-}
-
-impl CanDeriveOrd for Item {
- fn can_derive_ord(&self, ctx: &BindgenContext) -> bool {
- self.id().can_derive_ord(ctx)
- }
-}
-
-/// An item is the base of the bindgen representation, it can be either a
-/// module, a type, a function, or a variable (see `ItemKind` for more
-/// information).
-///
-/// Items refer to each other by `ItemId`. Every item has its parent's
-/// id. Depending on the kind of item this is, it may also refer to other items,
-/// such as a compound type item referring to other types. Collectively, these
-/// references form a graph.
-///
-/// The entry-point to this graph is the "root module": a meta-item used to hold
-/// all top-level items.
-///
-/// An item may have a comment, and annotations (see the `annotations` module).
-///
-/// Note that even though we parse all the types of annotations in comments, not
-/// all of them apply to every item. Those rules are described in the
-/// `annotations` module.
-#[derive(Debug)]
-pub struct Item {
- /// This item's id.
- id: ItemId,
-
- /// The item's local id, unique only amongst its siblings. Only used for
- /// anonymous items.
- ///
- /// Lazily initialized in local_id().
- ///
- /// Note that only structs, unions, and enums get a local type id. In any
- /// case this is an implementation detail.
- local_id: LazyCell<usize>,
-
- /// The next local id to use for a child or template instantiation.
- next_child_local_id: Cell<usize>,
-
- /// A cached copy of the canonical name, as returned by `canonical_name`.
- ///
- /// This is a fairly used operation during codegen so this makes bindgen
- /// considerably faster in those cases.
- canonical_name: LazyCell<String>,
-
- /// The path to use for allowlisting and other name-based checks, as
- /// returned by `path_for_allowlisting`, lazily constructed.
- path_for_allowlisting: LazyCell<Vec<String>>,
-
- /// A doc comment over the item, if any.
- comment: Option<String>,
- /// Annotations extracted from the doc comment, or the default ones
- /// otherwise.
- annotations: Annotations,
- /// An item's parent id. This will most likely be a class where this item
- /// was declared, or a module, etc.
- ///
- /// All the items have a parent, except the root module, in which case the
- /// parent id is its own id.
- parent_id: ItemId,
- /// The item kind.
- kind: ItemKind,
- /// The source location of the item.
- location: Option<clang::SourceLocation>,
-}
-
-impl AsRef<ItemId> for Item {
- fn as_ref(&self) -> &ItemId {
- &self.id
- }
-}
-
-impl Item {
- /// Construct a new `Item`.
- pub fn new(
- id: ItemId,
- comment: Option<String>,
- annotations: Option<Annotations>,
- parent_id: ItemId,
- kind: ItemKind,
- location: Option<clang::SourceLocation>,
- ) -> Self {
- debug_assert!(id != parent_id || kind.is_module());
- Item {
- id,
- local_id: LazyCell::new(),
- next_child_local_id: Cell::new(1),
- canonical_name: LazyCell::new(),
- path_for_allowlisting: LazyCell::new(),
- parent_id,
- comment,
- annotations: annotations.unwrap_or_default(),
- kind,
- location,
- }
- }
-
- /// Construct a new opaque item type.
- pub fn new_opaque_type(
- with_id: ItemId,
- ty: &clang::Type,
- ctx: &mut BindgenContext,
- ) -> TypeId {
- let location = ty.declaration().location();
- let ty = Opaque::from_clang_ty(ty, ctx);
- let kind = ItemKind::Type(ty);
- let parent = ctx.root_module().into();
- ctx.add_item(
- Item::new(with_id, None, None, parent, kind, Some(location)),
- None,
- None,
- );
- with_id.as_type_id_unchecked()
- }
-
- /// Get this `Item`'s identifier.
- pub fn id(&self) -> ItemId {
- self.id
- }
-
- /// Get this `Item`'s parent's identifier.
- ///
- /// For the root module, the parent's ID is its own ID.
- pub fn parent_id(&self) -> ItemId {
- self.parent_id
- }
-
- /// Set this item's parent id.
- ///
- /// This is only used so replacements get generated in the proper module.
- pub fn set_parent_for_replacement<Id: Into<ItemId>>(&mut self, id: Id) {
- self.parent_id = id.into();
- }
-
- /// Returns the depth this item is indented to.
- ///
- /// FIXME(emilio): This may need fixes for the enums within modules stuff.
- pub fn codegen_depth(&self, ctx: &BindgenContext) -> usize {
- if !ctx.options().enable_cxx_namespaces {
- return 0;
- }
-
- self.ancestors(ctx)
- .filter(|id| {
- ctx.resolve_item(*id).as_module().map_or(false, |module| {
- !module.is_inline() ||
- ctx.options().conservative_inline_namespaces
- })
- })
- .count() +
- 1
- }
-
- /// Get this `Item`'s comment, if it has any, already preprocessed and with
- /// the right indentation.
- pub fn comment(&self, ctx: &BindgenContext) -> Option<String> {
- if !ctx.options().generate_comments {
- return None;
- }
-
- self.comment.as_ref().map(|comment| {
- comment::preprocess(comment, self.codegen_depth(ctx))
- })
- }
-
- /// What kind of item is this?
- pub fn kind(&self) -> &ItemKind {
- &self.kind
- }
-
- /// Get a mutable reference to this item's kind.
- pub fn kind_mut(&mut self) -> &mut ItemKind {
- &mut self.kind
- }
-
- /// Where in the source is this item located?
- pub fn location(&self) -> Option<&clang::SourceLocation> {
- self.location.as_ref()
- }
-
- /// Get an identifier that differentiates this item from its siblings.
- ///
- /// This should stay relatively stable in the face of code motion outside or
- /// below this item's lexical scope, meaning that this can be useful for
- /// generating relatively stable identifiers within a scope.
- pub fn local_id(&self, ctx: &BindgenContext) -> usize {
- *self.local_id.borrow_with(|| {
- let parent = ctx.resolve_item(self.parent_id);
- parent.next_child_local_id()
- })
- }
-
- /// Get an identifier that differentiates a child of this item of other
- /// related items.
- ///
- /// This is currently used for anonymous items, and template instantiation
- /// tests, in both cases in order to reduce noise when system headers are at
- /// place.
- pub fn next_child_local_id(&self) -> usize {
- let local_id = self.next_child_local_id.get();
- self.next_child_local_id.set(local_id + 1);
- local_id
- }
-
- /// Returns whether this item is a top-level item, from the point of view of
- /// bindgen.
- ///
- /// This point of view changes depending on whether namespaces are enabled
- /// or not. That way, in the following example:
- ///
- /// ```c++
- /// namespace foo {
- /// static int var;
- /// }
- /// ```
- ///
- /// `var` would be a toplevel item if namespaces are disabled, but won't if
- /// they aren't.
- ///
- /// This function is used to determine when the codegen phase should call
- /// `codegen` on an item, since any item that is not top-level will be
- /// generated by its parent.
- pub fn is_toplevel(&self, ctx: &BindgenContext) -> bool {
- // FIXME: Workaround for some types falling behind when parsing weird
- // stl classes, for example.
- if ctx.options().enable_cxx_namespaces &&
- self.kind().is_module() &&
- self.id() != ctx.root_module()
- {
- return false;
- }
-
- let mut parent = self.parent_id;
- loop {
- let parent_item = match ctx.resolve_item_fallible(parent) {
- Some(item) => item,
- None => return false,
- };
-
- if parent_item.id() == ctx.root_module() {
- return true;
- } else if ctx.options().enable_cxx_namespaces ||
- !parent_item.kind().is_module()
- {
- return false;
- }
-
- parent = parent_item.parent_id();
- }
- }
-
- /// Get a reference to this item's underlying `Type`. Panic if this is some
- /// other kind of item.
- pub fn expect_type(&self) -> &Type {
- self.kind().expect_type()
- }
-
- /// Get a reference to this item's underlying `Type`, or `None` if this is
- /// some other kind of item.
- pub fn as_type(&self) -> Option<&Type> {
- self.kind().as_type()
- }
-
- /// Get a reference to this item's underlying `Function`. Panic if this is
- /// some other kind of item.
- pub fn expect_function(&self) -> &Function {
- self.kind().expect_function()
- }
-
- /// Is this item a module?
- pub fn is_module(&self) -> bool {
- matches!(self.kind, ItemKind::Module(..))
- }
-
- /// Get this item's annotations.
- pub fn annotations(&self) -> &Annotations {
- &self.annotations
- }
-
- /// Whether this item should be blocklisted.
- ///
- /// This may be due to either annotations or to other kind of configuration.
- pub fn is_blocklisted(&self, ctx: &BindgenContext) -> bool {
- debug_assert!(
- ctx.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- if self.annotations.hide() {
- return true;
- }
-
- if !ctx.options().blocklisted_files.is_empty() {
- if let Some(location) = &self.location {
- let (file, _, _, _) = location.location();
- if let Some(filename) = file.name() {
- if ctx.options().blocklisted_files.matches(&filename) {
- return true;
- }
- }
- }
- }
-
- let path = self.path_for_allowlisting(ctx);
- let name = path[1..].join("::");
- ctx.options().blocklisted_items.matches(&name) ||
- match self.kind {
- ItemKind::Type(..) => {
- ctx.options().blocklisted_types.matches(&name) ||
- ctx.is_replaced_type(path, self.id)
- }
- ItemKind::Function(..) => {
- ctx.options().blocklisted_functions.matches(&name)
- }
- // TODO: Add constant / namespace blocklisting?
- ItemKind::Var(..) | ItemKind::Module(..) => false,
- }
- }
-
- /// Is this a reference to another type?
- pub fn is_type_ref(&self) -> bool {
- self.as_type().map_or(false, |ty| ty.is_type_ref())
- }
-
- /// Is this item a var type?
- pub fn is_var(&self) -> bool {
- matches!(*self.kind(), ItemKind::Var(..))
- }
-
- /// Take out item NameOptions
- pub fn name<'a>(&'a self, ctx: &'a BindgenContext) -> NameOptions<'a> {
- NameOptions::new(self, ctx)
- }
-
- /// Get the target item id for name generation.
- fn name_target(&self, ctx: &BindgenContext) -> ItemId {
- let mut targets_seen = DebugOnlyItemSet::new();
- let mut item = self;
-
- loop {
- extra_assert!(!targets_seen.contains(&item.id()));
- targets_seen.insert(item.id());
-
- if self.annotations().use_instead_of().is_some() {
- return self.id();
- }
-
- match *item.kind() {
- ItemKind::Type(ref ty) => match *ty.kind() {
- TypeKind::ResolvedTypeRef(inner) => {
- item = ctx.resolve_item(inner);
- }
- TypeKind::TemplateInstantiation(ref inst) => {
- item = ctx.resolve_item(inst.template_definition());
- }
- _ => return item.id(),
- },
- _ => return item.id(),
- }
- }
- }
-
- /// Create a fully disambiguated name for an item, including template
- /// parameters if it is a type
- pub fn full_disambiguated_name(&self, ctx: &BindgenContext) -> String {
- let mut s = String::new();
- let level = 0;
- self.push_disambiguated_name(ctx, &mut s, level);
- s
- }
-
- /// Helper function for full_disambiguated_name
- fn push_disambiguated_name(
- &self,
- ctx: &BindgenContext,
- to: &mut String,
- level: u8,
- ) {
- to.push_str(&self.canonical_name(ctx));
- if let ItemKind::Type(ref ty) = *self.kind() {
- if let TypeKind::TemplateInstantiation(ref inst) = *ty.kind() {
- to.push_str(&format!("_open{}_", level));
- for arg in inst.template_arguments() {
- arg.into_resolver()
- .through_type_refs()
- .resolve(ctx)
- .push_disambiguated_name(ctx, to, level + 1);
- to.push('_');
- }
- to.push_str(&format!("close{}", level));
- }
- }
- }
-
- /// Get this function item's name, or `None` if this item is not a function.
- fn func_name(&self) -> Option<&str> {
- match *self.kind() {
- ItemKind::Function(ref func) => Some(func.name()),
- _ => None,
- }
- }
-
- /// Get the overload index for this method. If this is not a method, return
- /// `None`.
- fn overload_index(&self, ctx: &BindgenContext) -> Option<usize> {
- self.func_name().and_then(|func_name| {
- let parent = ctx.resolve_item(self.parent_id());
- if let ItemKind::Type(ref ty) = *parent.kind() {
- if let TypeKind::Comp(ref ci) = *ty.kind() {
- // All the constructors have the same name, so no need to
- // resolve and check.
- return ci
- .constructors()
- .iter()
- .position(|c| *c == self.id())
- .or_else(|| {
- ci.methods()
- .iter()
- .filter(|m| {
- let item = ctx.resolve_item(m.signature());
- let func = item.expect_function();
- func.name() == func_name
- })
- .position(|m| m.signature() == self.id())
- });
- }
- }
-
- None
- })
- }
-
- /// Get this item's base name (aka non-namespaced name).
- fn base_name(&self, ctx: &BindgenContext) -> String {
- if let Some(path) = self.annotations().use_instead_of() {
- return path.last().unwrap().clone();
- }
-
- match *self.kind() {
- ItemKind::Var(ref var) => var.name().to_owned(),
- ItemKind::Module(ref module) => {
- module.name().map(ToOwned::to_owned).unwrap_or_else(|| {
- format!("_bindgen_mod_{}", self.exposed_id(ctx))
- })
- }
- ItemKind::Type(ref ty) => {
- ty.sanitized_name(ctx).map(Into::into).unwrap_or_else(|| {
- format!("_bindgen_ty_{}", self.exposed_id(ctx))
- })
- }
- ItemKind::Function(ref fun) => {
- let mut name = fun.name().to_owned();
-
- if let Some(idx) = self.overload_index(ctx) {
- if idx > 0 {
- write!(&mut name, "{}", idx).unwrap();
- }
- }
-
- name
- }
- }
- }
-
- fn is_anon(&self) -> bool {
- match self.kind() {
- ItemKind::Module(module) => module.name().is_none(),
- ItemKind::Type(ty) => ty.name().is_none(),
- ItemKind::Function(_) => false,
- ItemKind::Var(_) => false,
- }
- }
-
- /// Get the canonical name without taking into account the replaces
- /// annotation.
- ///
- /// This is the base logic used to implement hiding and replacing via
- /// annotations, and also to implement proper name mangling.
- ///
- /// The idea is that each generated type in the same "level" (read: module
- /// or namespace) has a unique canonical name.
- ///
- /// This name should be derived from the immutable state contained in the
- /// type and the parent chain, since it should be consistent.
- ///
- /// If `BindgenOptions::disable_nested_struct_naming` is true then returned
- /// name is the inner most non-anonymous name plus all the anonymous base names
- /// that follows.
- pub fn real_canonical_name(
- &self,
- ctx: &BindgenContext,
- opt: &NameOptions,
- ) -> String {
- let target = ctx.resolve_item(self.name_target(ctx));
-
- // Short-circuit if the target has an override, and just use that.
- if let Some(path) = target.annotations.use_instead_of() {
- if ctx.options().enable_cxx_namespaces {
- return path.last().unwrap().clone();
- }
- return path.join("_");
- }
-
- let base_name = target.base_name(ctx);
-
- // Named template type arguments are never namespaced, and never
- // mangled.
- if target.is_template_param(ctx, &()) {
- return base_name;
- }
-
- // Ancestors' id iter
- let mut ids_iter = target
- .parent_id()
- .ancestors(ctx)
- .filter(|id| *id != ctx.root_module())
- .take_while(|id| {
- // Stop iterating ancestors once we reach a non-inline namespace
- // when opt.within_namespaces is set.
- !opt.within_namespaces || !ctx.resolve_item(*id).is_module()
- })
- .filter(|id| {
- if !ctx.options().conservative_inline_namespaces {
- if let ItemKind::Module(ref module) =
- *ctx.resolve_item(*id).kind()
- {
- return !module.is_inline();
- }
- }
-
- true
- });
-
- let ids: Vec<_> = if ctx.options().disable_nested_struct_naming {
- let mut ids = Vec::new();
-
- // If target is anonymous we need find its first named ancestor.
- if target.is_anon() {
- for id in ids_iter.by_ref() {
- ids.push(id);
-
- if !ctx.resolve_item(id).is_anon() {
- break;
- }
- }
- }
-
- ids
- } else {
- ids_iter.collect()
- };
-
- // Concatenate this item's ancestors' names together.
- let mut names: Vec<_> = ids
- .into_iter()
- .map(|id| {
- let item = ctx.resolve_item(id);
- let target = ctx.resolve_item(item.name_target(ctx));
- target.base_name(ctx)
- })
- .filter(|name| !name.is_empty())
- .collect();
-
- names.reverse();
-
- if !base_name.is_empty() {
- names.push(base_name);
- }
-
- if ctx.options().c_naming {
- if let Some(prefix) = self.c_naming_prefix() {
- names.insert(0, prefix.to_string());
- }
- }
-
- let name = names.join("_");
-
- let name = if opt.user_mangled == UserMangled::Yes {
- ctx.parse_callbacks()
- .and_then(|callbacks| callbacks.item_name(&name))
- .unwrap_or(name)
- } else {
- name
- };
-
- ctx.rust_mangle(&name).into_owned()
- }
-
- /// The exposed id that represents an unique id among the siblings of a
- /// given item.
- pub fn exposed_id(&self, ctx: &BindgenContext) -> String {
- // Only use local ids for enums, classes, structs and union types. All
- // other items use their global id.
- let ty_kind = self.kind().as_type().map(|t| t.kind());
- if let Some(ty_kind) = ty_kind {
- match *ty_kind {
- TypeKind::Comp(..) |
- TypeKind::TemplateInstantiation(..) |
- TypeKind::Enum(..) => return self.local_id(ctx).to_string(),
- _ => {}
- }
- }
-
- // Note that this `id_` prefix prevents (really unlikely) collisions
- // between the global id and the local id of an item with the same
- // parent.
- format!("id_{}", self.id().as_usize())
- }
-
- /// Get a reference to this item's `Module`, or `None` if this is not a
- /// `Module` item.
- pub fn as_module(&self) -> Option<&Module> {
- match self.kind {
- ItemKind::Module(ref module) => Some(module),
- _ => None,
- }
- }
-
- /// Get a mutable reference to this item's `Module`, or `None` if this is
- /// not a `Module` item.
- pub fn as_module_mut(&mut self) -> Option<&mut Module> {
- match self.kind {
- ItemKind::Module(ref mut module) => Some(module),
- _ => None,
- }
- }
-
- /// Returns whether the item is a constified module enum
- fn is_constified_enum_module(&self, ctx: &BindgenContext) -> bool {
- // Do not jump through aliases, except for aliases that point to a type
- // with the same name, since we dont generate coe for them.
- let item = self.id.into_resolver().through_type_refs().resolve(ctx);
- let type_ = match *item.kind() {
- ItemKind::Type(ref type_) => type_,
- _ => return false,
- };
-
- match *type_.kind() {
- TypeKind::Enum(ref enum_) => {
- enum_.computed_enum_variation(ctx, self) ==
- EnumVariation::ModuleConsts
- }
- TypeKind::Alias(inner_id) => {
- // TODO(emilio): Make this "hop through type aliases that aren't
- // really generated" an option in `ItemResolver`?
- let inner_item = ctx.resolve_item(inner_id);
- let name = item.canonical_name(ctx);
-
- if inner_item.canonical_name(ctx) == name {
- inner_item.is_constified_enum_module(ctx)
- } else {
- false
- }
- }
- _ => false,
- }
- }
-
- /// Is this item of a kind that is enabled for code generation?
- pub fn is_enabled_for_codegen(&self, ctx: &BindgenContext) -> bool {
- let cc = &ctx.options().codegen_config;
- match *self.kind() {
- ItemKind::Module(..) => true,
- ItemKind::Var(_) => cc.vars(),
- ItemKind::Type(_) => cc.types(),
- ItemKind::Function(ref f) => match f.kind() {
- FunctionKind::Function => cc.functions(),
- FunctionKind::Method(MethodKind::Constructor) => {
- cc.constructors()
- }
- FunctionKind::Method(MethodKind::Destructor) |
- FunctionKind::Method(MethodKind::VirtualDestructor {
- ..
- }) => cc.destructors(),
- FunctionKind::Method(MethodKind::Static) |
- FunctionKind::Method(MethodKind::Normal) |
- FunctionKind::Method(MethodKind::Virtual { .. }) => {
- cc.methods()
- }
- },
- }
- }
-
- /// Returns the path we should use for allowlisting / blocklisting, which
- /// doesn't include user-mangling.
- pub fn path_for_allowlisting(&self, ctx: &BindgenContext) -> &Vec<String> {
- self.path_for_allowlisting
- .borrow_with(|| self.compute_path(ctx, UserMangled::No))
- }
-
- fn compute_path(
- &self,
- ctx: &BindgenContext,
- mangled: UserMangled,
- ) -> Vec<String> {
- if let Some(path) = self.annotations().use_instead_of() {
- let mut ret =
- vec![ctx.resolve_item(ctx.root_module()).name(ctx).get()];
- ret.extend_from_slice(path);
- return ret;
- }
-
- let target = ctx.resolve_item(self.name_target(ctx));
- let mut path: Vec<_> = target
- .ancestors(ctx)
- .chain(iter::once(ctx.root_module().into()))
- .map(|id| ctx.resolve_item(id))
- .filter(|item| {
- item.id() == target.id() ||
- item.as_module().map_or(false, |module| {
- !module.is_inline() ||
- ctx.options().conservative_inline_namespaces
- })
- })
- .map(|item| {
- ctx.resolve_item(item.name_target(ctx))
- .name(ctx)
- .within_namespaces()
- .user_mangled(mangled)
- .get()
- })
- .collect();
- path.reverse();
- path
- }
-
- /// Returns a prefix for the canonical name when C naming is enabled.
- fn c_naming_prefix(&self) -> Option<&str> {
- let ty = match self.kind {
- ItemKind::Type(ref ty) => ty,
- _ => return None,
- };
-
- Some(match ty.kind() {
- TypeKind::Comp(ref ci) => match ci.kind() {
- CompKind::Struct => "struct",
- CompKind::Union => "union",
- },
- TypeKind::Enum(..) => "enum",
- _ => return None,
- })
- }
-
- /// Whether this is a #[must_use] type.
- pub fn must_use(&self, ctx: &BindgenContext) -> bool {
- self.annotations().must_use_type() || ctx.must_use_type_by_name(self)
- }
-}
-
-impl<T> IsOpaque for T
-where
- T: Copy + Into<ItemId>,
-{
- type Extra = ();
-
- fn is_opaque(&self, ctx: &BindgenContext, _: &()) -> bool {
- debug_assert!(
- ctx.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- ctx.resolve_item((*self).into()).is_opaque(ctx, &())
- }
-}
-
-impl IsOpaque for Item {
- type Extra = ();
-
- fn is_opaque(&self, ctx: &BindgenContext, _: &()) -> bool {
- debug_assert!(
- ctx.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- self.annotations.opaque() ||
- self.as_type().map_or(false, |ty| ty.is_opaque(ctx, self)) ||
- ctx.opaque_by_name(self.path_for_allowlisting(ctx))
- }
-}
-
-impl<T> HasVtable for T
-where
- T: Copy + Into<ItemId>,
-{
- fn has_vtable(&self, ctx: &BindgenContext) -> bool {
- let id: ItemId = (*self).into();
- id.as_type_id(ctx).map_or(false, |id| {
- !matches!(ctx.lookup_has_vtable(id), HasVtableResult::No)
- })
- }
-
- fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool {
- let id: ItemId = (*self).into();
- id.as_type_id(ctx).map_or(false, |id| {
- matches!(ctx.lookup_has_vtable(id), HasVtableResult::SelfHasVtable)
- })
- }
-}
-
-impl HasVtable for Item {
- fn has_vtable(&self, ctx: &BindgenContext) -> bool {
- self.id().has_vtable(ctx)
- }
-
- fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool {
- self.id().has_vtable_ptr(ctx)
- }
-}
-
-impl<T> Sizedness for T
-where
- T: Copy + Into<ItemId>,
-{
- fn sizedness(&self, ctx: &BindgenContext) -> SizednessResult {
- let id: ItemId = (*self).into();
- id.as_type_id(ctx)
- .map_or(SizednessResult::default(), |id| ctx.lookup_sizedness(id))
- }
-}
-
-impl Sizedness for Item {
- fn sizedness(&self, ctx: &BindgenContext) -> SizednessResult {
- self.id().sizedness(ctx)
- }
-}
-
-impl<T> HasTypeParamInArray for T
-where
- T: Copy + Into<ItemId>,
-{
- fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool {
- debug_assert!(
- ctx.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- ctx.lookup_has_type_param_in_array(*self)
- }
-}
-
-impl HasTypeParamInArray for Item {
- fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool {
- debug_assert!(
- ctx.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- ctx.lookup_has_type_param_in_array(self.id())
- }
-}
-
-impl<T> HasFloat for T
-where
- T: Copy + Into<ItemId>,
-{
- fn has_float(&self, ctx: &BindgenContext) -> bool {
- debug_assert!(
- ctx.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- ctx.lookup_has_float(*self)
- }
-}
-
-impl HasFloat for Item {
- fn has_float(&self, ctx: &BindgenContext) -> bool {
- debug_assert!(
- ctx.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- ctx.lookup_has_float(self.id())
- }
-}
-
-/// A set of items.
-pub type ItemSet = BTreeSet<ItemId>;
-
-impl DotAttributes for Item {
- fn dot_attributes<W>(
- &self,
- ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write,
- {
- writeln!(
- out,
- "<tr><td>{:?}</td></tr>
- <tr><td>name</td><td>{}</td></tr>",
- self.id,
- self.name(ctx).get()
- )?;
-
- if self.is_opaque(ctx, &()) {
- writeln!(out, "<tr><td>opaque</td><td>true</td></tr>")?;
- }
-
- self.kind.dot_attributes(ctx, out)
- }
-}
-
-impl<T> TemplateParameters for T
-where
- T: Copy + Into<ItemId>,
-{
- fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
- ctx.resolve_item_fallible(*self)
- .map_or(vec![], |item| item.self_template_params(ctx))
- }
-}
-
-impl TemplateParameters for Item {
- fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
- self.kind.self_template_params(ctx)
- }
-}
-
-impl TemplateParameters for ItemKind {
- fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
- match *self {
- ItemKind::Type(ref ty) => ty.self_template_params(ctx),
- // If we start emitting bindings to explicitly instantiated
- // functions, then we'll need to check ItemKind::Function for
- // template params.
- ItemKind::Function(_) | ItemKind::Module(_) | ItemKind::Var(_) => {
- vec![]
- }
- }
- }
-}
-
-// An utility function to handle recursing inside nested types.
-fn visit_child(
- cur: clang::Cursor,
- id: ItemId,
- ty: &clang::Type,
- parent_id: Option<ItemId>,
- ctx: &mut BindgenContext,
- result: &mut Result<TypeId, ParseError>,
-) -> clang_sys::CXChildVisitResult {
- use clang_sys::*;
- if result.is_ok() {
- return CXChildVisit_Break;
- }
-
- *result = Item::from_ty_with_id(id, ty, cur, parent_id, ctx);
-
- match *result {
- Ok(..) => CXChildVisit_Break,
- Err(ParseError::Recurse) => {
- cur.visit(|c| visit_child(c, id, ty, parent_id, ctx, result));
- CXChildVisit_Continue
- }
- Err(ParseError::Continue) => CXChildVisit_Continue,
- }
-}
-
-impl ClangItemParser for Item {
- fn builtin_type(
- kind: TypeKind,
- is_const: bool,
- ctx: &mut BindgenContext,
- ) -> TypeId {
- // Feel free to add more here, I'm just lazy.
- match kind {
- TypeKind::Void |
- TypeKind::Int(..) |
- TypeKind::Pointer(..) |
- TypeKind::Float(..) => {}
- _ => panic!("Unsupported builtin type"),
- }
-
- let ty = Type::new(None, None, kind, is_const);
- let id = ctx.next_item_id();
- let module = ctx.root_module().into();
- ctx.add_item(
- Item::new(id, None, None, module, ItemKind::Type(ty), None),
- None,
- None,
- );
- id.as_type_id_unchecked()
- }
-
- fn parse(
- cursor: clang::Cursor,
- parent_id: Option<ItemId>,
- ctx: &mut BindgenContext,
- ) -> Result<ItemId, ParseError> {
- use crate::ir::var::Var;
- use clang_sys::*;
-
- if !cursor.is_valid() {
- return Err(ParseError::Continue);
- }
-
- let comment = cursor.raw_comment();
- let annotations = Annotations::new(&cursor);
-
- let current_module = ctx.current_module().into();
- let relevant_parent_id = parent_id.unwrap_or(current_module);
-
- macro_rules! try_parse {
- ($what:ident) => {
- match $what::parse(cursor, ctx) {
- Ok(ParseResult::New(item, declaration)) => {
- let id = ctx.next_item_id();
-
- ctx.add_item(
- Item::new(
- id,
- comment,
- annotations,
- relevant_parent_id,
- ItemKind::$what(item),
- Some(cursor.location()),
- ),
- declaration,
- Some(cursor),
- );
- return Ok(id);
- }
- Ok(ParseResult::AlreadyResolved(id)) => {
- return Ok(id);
- }
- Err(ParseError::Recurse) => return Err(ParseError::Recurse),
- Err(ParseError::Continue) => {}
- }
- };
- }
-
- try_parse!(Module);
-
- // NOTE: Is extremely important to parse functions and vars **before**
- // types. Otherwise we can parse a function declaration as a type
- // (which is legal), and lose functions to generate.
- //
- // In general, I'm not totally confident this split between
- // ItemKind::Function and TypeKind::FunctionSig is totally worth it, but
- // I guess we can try.
- try_parse!(Function);
- try_parse!(Var);
-
- // Types are sort of special, so to avoid parsing template classes
- // twice, handle them separately.
- {
- let definition = cursor.definition();
- let applicable_cursor = definition.unwrap_or(cursor);
-
- let relevant_parent_id = match definition {
- Some(definition) => {
- if definition != cursor {
- ctx.add_semantic_parent(definition, relevant_parent_id);
- return Ok(Item::from_ty_or_ref(
- applicable_cursor.cur_type(),
- cursor,
- parent_id,
- ctx,
- )
- .into());
- }
- ctx.known_semantic_parent(definition)
- .or(parent_id)
- .unwrap_or_else(|| ctx.current_module().into())
- }
- None => relevant_parent_id,
- };
-
- match Item::from_ty(
- &applicable_cursor.cur_type(),
- applicable_cursor,
- Some(relevant_parent_id),
- ctx,
- ) {
- Ok(ty) => return Ok(ty.into()),
- Err(ParseError::Recurse) => return Err(ParseError::Recurse),
- Err(ParseError::Continue) => {}
- }
- }
-
- // Guess how does clang treat extern "C" blocks?
- if cursor.kind() == CXCursor_UnexposedDecl {
- Err(ParseError::Recurse)
- } else {
- // We allowlist cursors here known to be unhandled, to prevent being
- // too noisy about this.
- match cursor.kind() {
- CXCursor_MacroDefinition |
- CXCursor_MacroExpansion |
- CXCursor_UsingDeclaration |
- CXCursor_UsingDirective |
- CXCursor_StaticAssert |
- CXCursor_FunctionTemplate => {
- debug!(
- "Unhandled cursor kind {:?}: {:?}",
- cursor.kind(),
- cursor
- );
- }
- CXCursor_InclusionDirective => {
- let file = cursor.get_included_file_name();
- match file {
- None => {
- warn!(
- "Inclusion of a nameless file in {:?}",
- cursor
- );
- }
- Some(filename) => {
- ctx.include_file(filename);
- }
- }
- }
- _ => {
- // ignore toplevel operator overloads
- let spelling = cursor.spelling();
- if !spelling.starts_with("operator") {
- warn!(
- "Unhandled cursor kind {:?}: {:?}",
- cursor.kind(),
- cursor
- );
- }
- }
- }
-
- Err(ParseError::Continue)
- }
- }
-
- fn from_ty_or_ref(
- ty: clang::Type,
- location: clang::Cursor,
- parent_id: Option<ItemId>,
- ctx: &mut BindgenContext,
- ) -> TypeId {
- let id = ctx.next_item_id();
- Self::from_ty_or_ref_with_id(id, ty, location, parent_id, ctx)
- }
-
- /// Parse a C++ type. If we find a reference to a type that has not been
- /// defined yet, use `UnresolvedTypeRef` as a placeholder.
- ///
- /// This logic is needed to avoid parsing items with the incorrect parent
- /// and it's sort of complex to explain, so I'll just point to
- /// `tests/headers/typeref.hpp` to see the kind of constructs that forced
- /// this.
- ///
- /// Typerefs are resolved once parsing is completely done, see
- /// `BindgenContext::resolve_typerefs`.
- fn from_ty_or_ref_with_id(
- potential_id: ItemId,
- ty: clang::Type,
- location: clang::Cursor,
- parent_id: Option<ItemId>,
- ctx: &mut BindgenContext,
- ) -> TypeId {
- debug!(
- "from_ty_or_ref_with_id: {:?} {:?}, {:?}, {:?}",
- potential_id, ty, location, parent_id
- );
-
- if ctx.collected_typerefs() {
- debug!("refs already collected, resolving directly");
- return Item::from_ty_with_id(
- potential_id,
- &ty,
- location,
- parent_id,
- ctx,
- )
- .unwrap_or_else(|_| Item::new_opaque_type(potential_id, &ty, ctx));
- }
-
- if let Some(ty) = ctx.builtin_or_resolved_ty(
- potential_id,
- parent_id,
- &ty,
- Some(location),
- ) {
- debug!("{:?} already resolved: {:?}", ty, location);
- return ty;
- }
-
- debug!("New unresolved type reference: {:?}, {:?}", ty, location);
-
- let is_const = ty.is_const();
- let kind = TypeKind::UnresolvedTypeRef(ty, location, parent_id);
- let current_module = ctx.current_module();
-
- ctx.add_item(
- Item::new(
- potential_id,
- None,
- None,
- parent_id.unwrap_or_else(|| current_module.into()),
- ItemKind::Type(Type::new(None, None, kind, is_const)),
- Some(location.location()),
- ),
- None,
- None,
- );
- potential_id.as_type_id_unchecked()
- }
-
- fn from_ty(
- ty: &clang::Type,
- location: clang::Cursor,
- parent_id: Option<ItemId>,
- ctx: &mut BindgenContext,
- ) -> Result<TypeId, ParseError> {
- let id = ctx.next_item_id();
- Item::from_ty_with_id(id, ty, location, parent_id, ctx)
- }
-
- /// This is one of the trickiest methods you'll find (probably along with
- /// some of the ones that handle templates in `BindgenContext`).
- ///
- /// This method parses a type, given the potential id of that type (if
- /// parsing it was correct), an optional location we're scanning, which is
- /// critical some times to obtain information, an optional parent item id,
- /// that will, if it's `None`, become the current module id, and the
- /// context.
- fn from_ty_with_id(
- id: ItemId,
- ty: &clang::Type,
- location: clang::Cursor,
- parent_id: Option<ItemId>,
- ctx: &mut BindgenContext,
- ) -> Result<TypeId, ParseError> {
- use clang_sys::*;
-
- debug!(
- "Item::from_ty_with_id: {:?}\n\
- \tty = {:?},\n\
- \tlocation = {:?}",
- id, ty, location
- );
-
- if ty.kind() == clang_sys::CXType_Unexposed ||
- location.cur_type().kind() == clang_sys::CXType_Unexposed
- {
- if ty.is_associated_type() ||
- location.cur_type().is_associated_type()
- {
- return Ok(Item::new_opaque_type(id, ty, ctx));
- }
-
- if let Some(param_id) = Item::type_param(None, location, ctx) {
- return Ok(ctx.build_ty_wrapper(id, param_id, None, ty));
- }
- }
-
- // Treat all types that are declared inside functions as opaque. The Rust binding
- // won't be able to do anything with them anyway.
- //
- // (If we don't do this check here, we can have subtle logic bugs because we generally
- // ignore function bodies. See issue #2036.)
- if let Some(ref parent) = ty.declaration().fallible_semantic_parent() {
- if FunctionKind::from_cursor(parent).is_some() {
- debug!("Skipping type declared inside function: {:?}", ty);
- return Ok(Item::new_opaque_type(id, ty, ctx));
- }
- }
-
- let decl = {
- let canonical_def = ty.canonical_type().declaration().definition();
- canonical_def.unwrap_or_else(|| ty.declaration())
- };
-
- let comment = decl.raw_comment().or_else(|| location.raw_comment());
- let annotations =
- Annotations::new(&decl).or_else(|| Annotations::new(&location));
-
- if let Some(ref annotations) = annotations {
- if let Some(replaced) = annotations.use_instead_of() {
- ctx.replace(replaced, id);
- }
- }
-
- if let Some(ty) =
- ctx.builtin_or_resolved_ty(id, parent_id, ty, Some(location))
- {
- return Ok(ty);
- }
-
- // First, check we're not recursing.
- let mut valid_decl = decl.kind() != CXCursor_NoDeclFound;
- let declaration_to_look_for = if valid_decl {
- decl.canonical()
- } else if location.kind() == CXCursor_ClassTemplate {
- valid_decl = true;
- location
- } else {
- decl
- };
-
- if valid_decl {
- if let Some(partial) = ctx
- .currently_parsed_types()
- .iter()
- .find(|ty| *ty.decl() == declaration_to_look_for)
- {
- debug!("Avoiding recursion parsing type: {:?}", ty);
- // Unchecked because we haven't finished this type yet.
- return Ok(partial.id().as_type_id_unchecked());
- }
- }
-
- let current_module = ctx.current_module().into();
- let partial_ty = PartialType::new(declaration_to_look_for, id);
- if valid_decl {
- ctx.begin_parsing(partial_ty);
- }
-
- let result = Type::from_clang_ty(id, ty, location, parent_id, ctx);
- let relevant_parent_id = parent_id.unwrap_or(current_module);
- let ret = match result {
- Ok(ParseResult::AlreadyResolved(ty)) => {
- Ok(ty.as_type_id_unchecked())
- }
- Ok(ParseResult::New(item, declaration)) => {
- ctx.add_item(
- Item::new(
- id,
- comment,
- annotations,
- relevant_parent_id,
- ItemKind::Type(item),
- Some(location.location()),
- ),
- declaration,
- Some(location),
- );
- Ok(id.as_type_id_unchecked())
- }
- Err(ParseError::Continue) => Err(ParseError::Continue),
- Err(ParseError::Recurse) => {
- debug!("Item::from_ty recursing in the ast");
- let mut result = Err(ParseError::Recurse);
-
- // Need to pop here, otherwise we'll get stuck.
- //
- // TODO: Find a nicer interface, really. Also, the
- // declaration_to_look_for suspiciously shares a lot of
- // logic with ir::context, so we should refactor that.
- if valid_decl {
- let finished = ctx.finish_parsing();
- assert_eq!(*finished.decl(), declaration_to_look_for);
- }
-
- location.visit(|cur| {
- visit_child(cur, id, ty, parent_id, ctx, &mut result)
- });
-
- if valid_decl {
- let partial_ty =
- PartialType::new(declaration_to_look_for, id);
- ctx.begin_parsing(partial_ty);
- }
-
- // If we have recursed into the AST all we know, and we still
- // haven't found what we've got, let's just try and make a named
- // type.
- //
- // This is what happens with some template members, for example.
- if let Err(ParseError::Recurse) = result {
- warn!(
- "Unknown type, assuming named template type: \
- id = {:?}; spelling = {}",
- id,
- ty.spelling()
- );
- Item::type_param(Some(id), location, ctx)
- .map(Ok)
- .unwrap_or(Err(ParseError::Recurse))
- } else {
- result
- }
- }
- };
-
- if valid_decl {
- let partial_ty = ctx.finish_parsing();
- assert_eq!(*partial_ty.decl(), declaration_to_look_for);
- }
-
- ret
- }
-
- /// A named type is a template parameter, e.g., the "T" in Foo<T>. They're
- /// always local so it's the only exception when there's no declaration for
- /// a type.
- fn type_param(
- with_id: Option<ItemId>,
- location: clang::Cursor,
- ctx: &mut BindgenContext,
- ) -> Option<TypeId> {
- let ty = location.cur_type();
-
- debug!(
- "Item::type_param:\n\
- \twith_id = {:?},\n\
- \tty = {} {:?},\n\
- \tlocation: {:?}",
- with_id,
- ty.spelling(),
- ty,
- location
- );
-
- if ty.kind() != clang_sys::CXType_Unexposed {
- // If the given cursor's type's kind is not Unexposed, then we
- // aren't looking at a template parameter. This check may need to be
- // updated in the future if they start properly exposing template
- // type parameters.
- return None;
- }
-
- let ty_spelling = ty.spelling();
-
- // Clang does not expose any information about template type parameters
- // via their clang::Type, nor does it give us their canonical cursors
- // the straightforward way. However, there are three situations from
- // which we can find the definition of the template type parameter, if
- // the cursor is indeed looking at some kind of a template type
- // parameter or use of one:
- //
- // 1. The cursor is pointing at the template type parameter's
- // definition. This is the trivial case.
- //
- // (kind = TemplateTypeParameter, ...)
- //
- // 2. The cursor is pointing at a TypeRef whose referenced() cursor is
- // situation (1).
- //
- // (kind = TypeRef,
- // referenced = (kind = TemplateTypeParameter, ...),
- // ...)
- //
- // 3. The cursor is pointing at some use of a template type parameter
- // (for example, in a FieldDecl), and this cursor has a child cursor
- // whose spelling is the same as the parent's type's spelling, and whose
- // kind is a TypeRef of the situation (2) variety.
- //
- // (kind = FieldDecl,
- // type = (kind = Unexposed,
- // spelling = "T",
- // ...),
- // children =
- // (kind = TypeRef,
- // spelling = "T",
- // referenced = (kind = TemplateTypeParameter,
- // spelling = "T",
- // ...),
- // ...)
- // ...)
- //
- // TODO: The alternative to this hacky pattern matching would be to
- // maintain proper scopes of template parameters while parsing and use
- // de Brujin indices to access template parameters, which clang exposes
- // in the cursor's type's canonical type's spelling:
- // "type-parameter-x-y". That is probably a better approach long-term,
- // but maintaining these scopes properly would require more changes to
- // the whole libclang -> IR parsing code.
-
- fn is_template_with_spelling(
- refd: &clang::Cursor,
- spelling: &str,
- ) -> bool {
- lazy_static! {
- static ref ANON_TYPE_PARAM_RE: regex::Regex =
- regex::Regex::new(r"^type\-parameter\-\d+\-\d+$").unwrap();
- }
-
- if refd.kind() != clang_sys::CXCursor_TemplateTypeParameter {
- return false;
- }
-
- let refd_spelling = refd.spelling();
- refd_spelling == spelling ||
- // Allow for anonymous template parameters.
- (refd_spelling.is_empty() && ANON_TYPE_PARAM_RE.is_match(spelling.as_ref()))
- }
-
- let definition = if is_template_with_spelling(&location, &ty_spelling) {
- // Situation (1)
- location
- } else if location.kind() == clang_sys::CXCursor_TypeRef {
- // Situation (2)
- match location.referenced() {
- Some(refd)
- if is_template_with_spelling(&refd, &ty_spelling) =>
- {
- refd
- }
- _ => return None,
- }
- } else {
- // Situation (3)
- let mut definition = None;
-
- location.visit(|child| {
- let child_ty = child.cur_type();
- if child_ty.kind() == clang_sys::CXCursor_TypeRef &&
- child_ty.spelling() == ty_spelling
- {
- match child.referenced() {
- Some(refd)
- if is_template_with_spelling(
- &refd,
- &ty_spelling,
- ) =>
- {
- definition = Some(refd);
- return clang_sys::CXChildVisit_Break;
- }
- _ => {}
- }
- }
-
- clang_sys::CXChildVisit_Continue
- });
-
- definition?
- };
- assert!(is_template_with_spelling(&definition, &ty_spelling));
-
- // Named types are always parented to the root module. They are never
- // referenced with namespace prefixes, and they can't inherit anything
- // from their parent either, so it is simplest to just hang them off
- // something we know will always exist.
- let parent = ctx.root_module().into();
-
- if let Some(id) = ctx.get_type_param(&definition) {
- if let Some(with_id) = with_id {
- return Some(ctx.build_ty_wrapper(
- with_id,
- id,
- Some(parent),
- &ty,
- ));
- } else {
- return Some(id);
- }
- }
-
- // See tests/headers/const_tparam.hpp and
- // tests/headers/variadic_tname.hpp.
- let name = ty_spelling.replace("const ", "").replace('.', "");
-
- let id = with_id.unwrap_or_else(|| ctx.next_item_id());
- let item = Item::new(
- id,
- None,
- None,
- parent,
- ItemKind::Type(Type::named(name)),
- Some(location.location()),
- );
- ctx.add_type_param(item, definition);
- Some(id.as_type_id_unchecked())
- }
-}
-
-impl ItemCanonicalName for Item {
- fn canonical_name(&self, ctx: &BindgenContext) -> String {
- debug_assert!(
- ctx.in_codegen_phase(),
- "You're not supposed to call this yet"
- );
- self.canonical_name
- .borrow_with(|| {
- let in_namespace = ctx.options().enable_cxx_namespaces ||
- ctx.options().disable_name_namespacing;
-
- if in_namespace {
- self.name(ctx).within_namespaces().get()
- } else {
- self.name(ctx).get()
- }
- })
- .clone()
- }
-}
-
-impl ItemCanonicalPath for Item {
- fn namespace_aware_canonical_path(
- &self,
- ctx: &BindgenContext,
- ) -> Vec<String> {
- let mut path = self.canonical_path(ctx);
-
- // ASSUMPTION: (disable_name_namespacing && cxx_namespaces)
- // is equivalent to
- // disable_name_namespacing
- if ctx.options().disable_name_namespacing {
- // Only keep the last item in path
- let split_idx = path.len() - 1;
- path = path.split_off(split_idx);
- } else if !ctx.options().enable_cxx_namespaces {
- // Ignore first item "root"
- path = vec![path[1..].join("_")];
- }
-
- if self.is_constified_enum_module(ctx) {
- path.push(CONSTIFIED_ENUM_MODULE_REPR_NAME.into());
- }
-
- path
- }
-
- fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
- self.compute_path(ctx, UserMangled::Yes)
- }
-}
-
-/// Whether to use the user-mangled name (mangled by the `item_name` callback or
-/// not.
-///
-/// Most of the callers probably want just yes, but the ones dealing with
-/// allowlisting and blocklisting don't.
-#[derive(Copy, Clone, Debug, PartialEq)]
-enum UserMangled {
- No,
- Yes,
-}
-
-/// Builder struct for naming variations, which hold inside different
-/// flags for naming options.
-#[derive(Debug)]
-pub struct NameOptions<'a> {
- item: &'a Item,
- ctx: &'a BindgenContext,
- within_namespaces: bool,
- user_mangled: UserMangled,
-}
-
-impl<'a> NameOptions<'a> {
- /// Construct a new `NameOptions`
- pub fn new(item: &'a Item, ctx: &'a BindgenContext) -> Self {
- NameOptions {
- item,
- ctx,
- within_namespaces: false,
- user_mangled: UserMangled::Yes,
- }
- }
-
- /// Construct the name without the item's containing C++ namespaces mangled
- /// into it. In other words, the item's name within the item's namespace.
- pub fn within_namespaces(&mut self) -> &mut Self {
- self.within_namespaces = true;
- self
- }
-
- fn user_mangled(&mut self, user_mangled: UserMangled) -> &mut Self {
- self.user_mangled = user_mangled;
- self
- }
-
- /// Construct a name `String`
- pub fn get(&self) -> String {
- self.item.real_canonical_name(self.ctx, self)
- }
-}
diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs
deleted file mode 100644
index 4a12fef4..00000000
--- a/src/ir/item_kind.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-//! Different variants of an `Item` in our intermediate representation.
-
-use super::context::BindgenContext;
-use super::dot::DotAttributes;
-use super::function::Function;
-use super::module::Module;
-use super::ty::Type;
-use super::var::Var;
-use std::io;
-
-/// A item we parse and translate.
-#[derive(Debug)]
-pub enum ItemKind {
- /// A module, created implicitly once (the root module), or via C++
- /// namespaces.
- Module(Module),
-
- /// A type declared in any of the multiple ways it can be declared.
- Type(Type),
-
- /// A function or method declaration.
- Function(Function),
-
- /// A variable declaration, most likely a static.
- Var(Var),
-}
-
-impl ItemKind {
- /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it
- /// is some other kind.
- pub fn as_module(&self) -> Option<&Module> {
- match *self {
- ItemKind::Module(ref module) => Some(module),
- _ => None,
- }
- }
-
- /// Transform our `ItemKind` into a string.
- pub fn kind_name(&self) -> &'static str {
- match *self {
- ItemKind::Module(..) => "Module",
- ItemKind::Type(..) => "Type",
- ItemKind::Function(..) => "Function",
- ItemKind::Var(..) => "Var",
- }
- }
-
- /// Is this a module?
- pub fn is_module(&self) -> bool {
- self.as_module().is_some()
- }
-
- /// Get a reference to this `ItemKind`'s underying `Module`, or panic if it
- /// is some other kind.
- pub fn expect_module(&self) -> &Module {
- self.as_module().expect("Not a module")
- }
-
- /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if
- /// it is some other kind.
- pub fn as_function(&self) -> Option<&Function> {
- match *self {
- ItemKind::Function(ref func) => Some(func),
- _ => None,
- }
- }
-
- /// Is this a function?
- pub fn is_function(&self) -> bool {
- self.as_function().is_some()
- }
-
- /// Get a reference to this `ItemKind`'s underying `Function`, or panic if
- /// it is some other kind.
- pub fn expect_function(&self) -> &Function {
- self.as_function().expect("Not a function")
- }
-
- /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if
- /// it is some other kind.
- pub fn as_type(&self) -> Option<&Type> {
- match *self {
- ItemKind::Type(ref ty) => Some(ty),
- _ => None,
- }
- }
-
- /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None`
- /// if it is some other kind.
- pub fn as_type_mut(&mut self) -> Option<&mut Type> {
- match *self {
- ItemKind::Type(ref mut ty) => Some(ty),
- _ => None,
- }
- }
-
- /// Is this a type?
- pub fn is_type(&self) -> bool {
- self.as_type().is_some()
- }
-
- /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is
- /// some other kind.
- pub fn expect_type(&self) -> &Type {
- self.as_type().expect("Not a type")
- }
-
- /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is
- /// some other kind.
- pub fn as_var(&self) -> Option<&Var> {
- match *self {
- ItemKind::Var(ref v) => Some(v),
- _ => None,
- }
- }
-
- /// Is this a variable?
- pub fn is_var(&self) -> bool {
- self.as_var().is_some()
- }
-
- /// Get a reference to this `ItemKind`'s underying `Var`, or panic if it is
- /// some other kind.
- pub fn expect_var(&self) -> &Var {
- self.as_var().expect("Not a var")
- }
-}
-
-impl DotAttributes for ItemKind {
- fn dot_attributes<W>(
- &self,
- ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write,
- {
- writeln!(out, "<tr><td>kind</td><td>{}</td></tr>", self.kind_name())?;
-
- match *self {
- ItemKind::Module(ref module) => module.dot_attributes(ctx, out),
- ItemKind::Type(ref ty) => ty.dot_attributes(ctx, out),
- ItemKind::Function(ref func) => func.dot_attributes(ctx, out),
- ItemKind::Var(ref var) => var.dot_attributes(ctx, out),
- }
- }
-}
diff --git a/src/ir/layout.rs b/src/ir/layout.rs
deleted file mode 100644
index 6f450307..00000000
--- a/src/ir/layout.rs
+++ /dev/null
@@ -1,143 +0,0 @@
-//! Intermediate representation for the physical layout of some type.
-
-use super::derive::CanDerive;
-use super::ty::{Type, TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
-use crate::clang;
-use crate::ir::context::BindgenContext;
-use std::cmp;
-
-/// A type that represents the struct layout of a type.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct Layout {
- /// The size (in bytes) of this layout.
- pub size: usize,
- /// The alignment (in bytes) of this layout.
- pub align: usize,
- /// Whether this layout's members are packed or not.
- pub packed: bool,
-}
-
-#[test]
-fn test_layout_for_size() {
- use std::mem;
-
- let ptr_size = mem::size_of::<*mut ()>();
- assert_eq!(
- Layout::for_size_internal(ptr_size, ptr_size),
- Layout::new(ptr_size, ptr_size)
- );
- assert_eq!(
- Layout::for_size_internal(ptr_size, 3 * ptr_size),
- Layout::new(3 * ptr_size, ptr_size)
- );
-}
-
-impl Layout {
- /// Gets the integer type name for a given known size.
- pub fn known_type_for_size(
- ctx: &BindgenContext,
- size: usize,
- ) -> Option<&'static str> {
- Some(match size {
- 16 if ctx.options().rust_features.i128_and_u128 => "u128",
- 8 => "u64",
- 4 => "u32",
- 2 => "u16",
- 1 => "u8",
- _ => return None,
- })
- }
-
- /// Construct a new `Layout` with the given `size` and `align`. It is not
- /// packed.
- pub fn new(size: usize, align: usize) -> Self {
- Layout {
- size,
- align,
- packed: false,
- }
- }
-
- fn for_size_internal(ptr_size: usize, size: usize) -> Self {
- let mut next_align = 2;
- while size % next_align == 0 && next_align <= ptr_size {
- next_align *= 2;
- }
- Layout {
- size,
- align: next_align / 2,
- packed: false,
- }
- }
-
- /// Creates a non-packed layout for a given size, trying to use the maximum
- /// alignment possible.
- pub fn for_size(ctx: &BindgenContext, size: usize) -> Self {
- Self::for_size_internal(ctx.target_pointer_size(), size)
- }
-
- /// Is this a zero-sized layout?
- pub fn is_zero(&self) -> bool {
- self.size == 0 && self.align == 0
- }
-
- /// Construct a zero-sized layout.
- pub fn zero() -> Self {
- Self::new(0, 0)
- }
-
- /// Get this layout as an opaque type.
- pub fn opaque(&self) -> Opaque {
- Opaque(*self)
- }
-}
-
-/// When we are treating a type as opaque, it is just a blob with a `Layout`.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct Opaque(pub Layout);
-
-impl Opaque {
- /// Construct a new opaque type from the given clang type.
- pub fn from_clang_ty(ty: &clang::Type, ctx: &BindgenContext) -> Type {
- let layout = Layout::new(ty.size(ctx), ty.align(ctx));
- let ty_kind = TypeKind::Opaque;
- let is_const = ty.is_const();
- Type::new(None, Some(layout), ty_kind, is_const)
- }
-
- /// Return the known rust type we should use to create a correctly-aligned
- /// field with this layout.
- pub fn known_rust_type_for_array(
- &self,
- ctx: &BindgenContext,
- ) -> Option<&'static str> {
- Layout::known_type_for_size(ctx, self.0.align)
- }
-
- /// Return the array size that an opaque type for this layout should have if
- /// we know the correct type for it, or `None` otherwise.
- pub fn array_size(&self, ctx: &BindgenContext) -> Option<usize> {
- if self.known_rust_type_for_array(ctx).is_some() {
- Some(self.0.size / cmp::max(self.0.align, 1))
- } else {
- None
- }
- }
-
- /// Return `true` if this opaque layout's array size will fit within the
- /// maximum number of array elements that Rust allows deriving traits
- /// with. Return `false` otherwise.
- pub fn array_size_within_derive_limit(
- &self,
- ctx: &BindgenContext,
- ) -> CanDerive {
- if self
- .array_size(ctx)
- .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
- {
- CanDerive::Yes
- } else {
- CanDerive::Manually
- }
- }
-}
diff --git a/src/ir/mod.rs b/src/ir/mod.rs
deleted file mode 100644
index 8f6a2dac..00000000
--- a/src/ir/mod.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-//! The ir module defines bindgen's intermediate representation.
-//!
-//! Parsing C/C++ generates the IR, while code generation outputs Rust code from
-//! the IR.
-
-pub mod analysis;
-pub mod annotations;
-pub mod comment;
-pub mod comp;
-pub mod context;
-pub mod derive;
-pub mod dot;
-pub mod enum_ty;
-pub mod function;
-pub mod int;
-pub mod item;
-pub mod item_kind;
-pub mod layout;
-pub mod module;
-pub mod objc;
-pub mod template;
-pub mod traversal;
-pub mod ty;
-pub mod var;
diff --git a/src/ir/module.rs b/src/ir/module.rs
deleted file mode 100644
index d5aca94a..00000000
--- a/src/ir/module.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-//! Intermediate representation for modules (AKA C++ namespaces).
-
-use super::context::BindgenContext;
-use super::dot::DotAttributes;
-use super::item::ItemSet;
-use crate::clang;
-use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
-use crate::parse_one;
-use std::io;
-
-/// Whether this module is inline or not.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum ModuleKind {
- /// This module is not inline.
- Normal,
- /// This module is inline, as in `inline namespace foo {}`.
- Inline,
-}
-
-/// A module, as in, a C++ namespace.
-#[derive(Clone, Debug)]
-pub struct Module {
- /// The name of the module, or none if it's anonymous.
- name: Option<String>,
- /// The kind of module this is.
- kind: ModuleKind,
- /// The children of this module, just here for convenience.
- children: ItemSet,
-}
-
-impl Module {
- /// Construct a new `Module`.
- pub fn new(name: Option<String>, kind: ModuleKind) -> Self {
- Module {
- name,
- kind,
- children: ItemSet::new(),
- }
- }
-
- /// Get this module's name.
- pub fn name(&self) -> Option<&str> {
- self.name.as_deref()
- }
-
- /// Get a mutable reference to this module's children.
- pub fn children_mut(&mut self) -> &mut ItemSet {
- &mut self.children
- }
-
- /// Get this module's children.
- pub fn children(&self) -> &ItemSet {
- &self.children
- }
-
- /// Whether this namespace is inline.
- pub fn is_inline(&self) -> bool {
- self.kind == ModuleKind::Inline
- }
-}
-
-impl DotAttributes for Module {
- fn dot_attributes<W>(
- &self,
- _ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write,
- {
- writeln!(out, "<tr><td>ModuleKind</td><td>{:?}</td></tr>", self.kind)
- }
-}
-
-impl ClangSubItemParser for Module {
- fn parse(
- cursor: clang::Cursor,
- ctx: &mut BindgenContext,
- ) -> Result<ParseResult<Self>, ParseError> {
- use clang_sys::*;
- match cursor.kind() {
- CXCursor_Namespace => {
- let module_id = ctx.module(cursor);
- ctx.with_module(module_id, |ctx| {
- cursor.visit(|cursor| {
- parse_one(ctx, cursor, Some(module_id.into()))
- })
- });
-
- Ok(ParseResult::AlreadyResolved(module_id.into()))
- }
- _ => Err(ParseError::Continue),
- }
- }
-}
diff --git a/src/ir/objc.rs b/src/ir/objc.rs
deleted file mode 100644
index 0845ad0f..00000000
--- a/src/ir/objc.rs
+++ /dev/null
@@ -1,329 +0,0 @@
-//! Objective C types
-
-use super::context::{BindgenContext, ItemId};
-use super::function::FunctionSig;
-use super::item::Item;
-use super::traversal::{Trace, Tracer};
-use super::ty::TypeKind;
-use crate::clang;
-use crate::parse::ClangItemParser;
-use clang_sys::CXChildVisit_Continue;
-use clang_sys::CXCursor_ObjCCategoryDecl;
-use clang_sys::CXCursor_ObjCClassMethodDecl;
-use clang_sys::CXCursor_ObjCClassRef;
-use clang_sys::CXCursor_ObjCInstanceMethodDecl;
-use clang_sys::CXCursor_ObjCProtocolDecl;
-use clang_sys::CXCursor_ObjCProtocolRef;
-use clang_sys::CXCursor_ObjCSuperClassRef;
-use clang_sys::CXCursor_TemplateTypeParameter;
-use proc_macro2::{Ident, Span, TokenStream};
-
-/// Objective C interface as used in TypeKind
-///
-/// Also protocols and categories are parsed as this type
-#[derive(Debug)]
-pub struct ObjCInterface {
- /// The name
- /// like, NSObject
- name: String,
-
- category: Option<String>,
-
- is_protocol: bool,
-
- /// The list of template names almost always, ObjectType or KeyType
- pub template_names: Vec<String>,
-
- /// The list of protocols that this interface conforms to.
- pub conforms_to: Vec<ItemId>,
-
- /// The direct parent for this interface.
- pub parent_class: Option<ItemId>,
-
- /// List of the methods defined in this interfae
- methods: Vec<ObjCMethod>,
-
- class_methods: Vec<ObjCMethod>,
-}
-
-/// The objective c methods
-#[derive(Debug)]
-pub struct ObjCMethod {
- /// The original method selector name
- /// like, dataWithBytes:length:
- name: String,
-
- /// Method name as converted to rust
- /// like, dataWithBytes_length_
- rust_name: String,
-
- signature: FunctionSig,
-
- /// Is class method?
- is_class_method: bool,
-}
-
-impl ObjCInterface {
- fn new(name: &str) -> ObjCInterface {
- ObjCInterface {
- name: name.to_owned(),
- category: None,
- is_protocol: false,
- template_names: Vec::new(),
- parent_class: None,
- conforms_to: Vec::new(),
- methods: Vec::new(),
- class_methods: Vec::new(),
- }
- }
-
- /// The name
- /// like, NSObject
- pub fn name(&self) -> &str {
- self.name.as_ref()
- }
-
- /// Formats the name for rust
- /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods
- /// and protocols are like PNSObject
- pub fn rust_name(&self) -> String {
- if let Some(ref cat) = self.category {
- format!("{}_{}", self.name(), cat)
- } else if self.is_protocol {
- format!("P{}", self.name())
- } else {
- format!("I{}", self.name().to_owned())
- }
- }
-
- /// Is this a template interface?
- pub fn is_template(&self) -> bool {
- !self.template_names.is_empty()
- }
-
- /// List of the methods defined in this interface
- pub fn methods(&self) -> &Vec<ObjCMethod> {
- &self.methods
- }
-
- /// Is this a protocol?
- pub fn is_protocol(&self) -> bool {
- self.is_protocol
- }
-
- /// Is this a category?
- pub fn is_category(&self) -> bool {
- self.category.is_some()
- }
-
- /// List of the class methods defined in this interface
- pub fn class_methods(&self) -> &Vec<ObjCMethod> {
- &self.class_methods
- }
-
- /// Parses the Objective C interface from the cursor
- pub fn from_ty(
- cursor: &clang::Cursor,
- ctx: &mut BindgenContext,
- ) -> Option<Self> {
- let name = cursor.spelling();
- let mut interface = Self::new(&name);
-
- if cursor.kind() == CXCursor_ObjCProtocolDecl {
- interface.is_protocol = true;
- }
-
- cursor.visit(|c| {
- match c.kind() {
- CXCursor_ObjCClassRef => {
- if cursor.kind() == CXCursor_ObjCCategoryDecl {
- // We are actually a category extension, and we found the reference
- // to the original interface, so name this interface approriately
- interface.name = c.spelling();
- interface.category = Some(cursor.spelling());
- }
- }
- CXCursor_ObjCProtocolRef => {
- // Gather protocols this interface conforms to
- let needle = format!("P{}", c.spelling());
- let items_map = ctx.items();
- debug!(
- "Interface {} conforms to {}, find the item",
- interface.name, needle
- );
-
- for (id, item) in items_map {
- if let Some(ty) = item.as_type() {
- if let TypeKind::ObjCInterface(ref protocol) =
- *ty.kind()
- {
- if protocol.is_protocol {
- debug!(
- "Checking protocol {}, ty.name {:?}",
- protocol.name,
- ty.name()
- );
- if Some(needle.as_ref()) == ty.name() {
- debug!(
- "Found conforming protocol {:?}",
- item
- );
- interface.conforms_to.push(id);
- break;
- }
- }
- }
- }
- }
- }
- CXCursor_ObjCInstanceMethodDecl |
- CXCursor_ObjCClassMethodDecl => {
- let name = c.spelling();
- let signature =
- FunctionSig::from_ty(&c.cur_type(), &c, ctx)
- .expect("Invalid function sig");
- let is_class_method =
- c.kind() == CXCursor_ObjCClassMethodDecl;
- let method =
- ObjCMethod::new(&name, signature, is_class_method);
- interface.add_method(method);
- }
- CXCursor_TemplateTypeParameter => {
- let name = c.spelling();
- interface.template_names.push(name);
- }
- CXCursor_ObjCSuperClassRef => {
- let item = Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
- interface.parent_class = Some(item.into());
- }
- _ => {}
- }
- CXChildVisit_Continue
- });
- Some(interface)
- }
-
- fn add_method(&mut self, method: ObjCMethod) {
- if method.is_class_method {
- self.class_methods.push(method);
- } else {
- self.methods.push(method);
- }
- }
-}
-
-impl ObjCMethod {
- fn new(
- name: &str,
- signature: FunctionSig,
- is_class_method: bool,
- ) -> ObjCMethod {
- let split_name: Vec<&str> = name.split(':').collect();
-
- let rust_name = split_name.join("_");
-
- ObjCMethod {
- name: name.to_owned(),
- rust_name,
- signature,
- is_class_method,
- }
- }
-
- /// The original method selector name
- /// like, dataWithBytes:length:
- pub fn name(&self) -> &str {
- self.name.as_ref()
- }
-
- /// Method name as converted to rust
- /// like, dataWithBytes_length_
- pub fn rust_name(&self) -> &str {
- self.rust_name.as_ref()
- }
-
- /// Returns the methods signature as FunctionSig
- pub fn signature(&self) -> &FunctionSig {
- &self.signature
- }
-
- /// Is this a class method?
- pub fn is_class_method(&self) -> bool {
- self.is_class_method
- }
-
- /// Formats the method call
- pub fn format_method_call(&self, args: &[TokenStream]) -> TokenStream {
- let split_name: Vec<Option<Ident>> = self
- .name
- .split(':')
- .map(|name| {
- if name.is_empty() {
- None
- } else {
- Some(Ident::new(name, Span::call_site()))
- }
- })
- .collect();
-
- // No arguments
- if args.is_empty() && split_name.len() == 1 {
- let name = &split_name[0];
- return quote! {
- #name
- };
- }
-
- // Check right amount of arguments
- assert!(
- args.len() == split_name.len() - 1,
- "Incorrect method name or arguments for objc method, {:?} vs {:?}",
- args,
- split_name
- );
-
- // Get arguments without type signatures to pass to `msg_send!`
- let mut args_without_types = vec![];
- for arg in args.iter() {
- let arg = arg.to_string();
- let name_and_sig: Vec<&str> = arg.split(' ').collect();
- let name = name_and_sig[0];
- args_without_types.push(Ident::new(name, Span::call_site()))
- }
-
- let args = split_name.into_iter().zip(args_without_types).map(
- |(arg, arg_val)| {
- if let Some(arg) = arg {
- quote! { #arg: #arg_val }
- } else {
- quote! { #arg_val: #arg_val }
- }
- },
- );
-
- quote! {
- #( #args )*
- }
- }
-}
-
-impl Trace for ObjCInterface {
- type Extra = ();
-
- fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, _: &())
- where
- T: Tracer,
- {
- for method in &self.methods {
- method.signature.trace(context, tracer, &());
- }
-
- for class_method in &self.class_methods {
- class_method.signature.trace(context, tracer, &());
- }
-
- for protocol in &self.conforms_to {
- tracer.visit(*protocol);
- }
- }
-}
diff --git a/src/ir/template.rs b/src/ir/template.rs
deleted file mode 100644
index 8b06748e..00000000
--- a/src/ir/template.rs
+++ /dev/null
@@ -1,343 +0,0 @@
-//! Template declaration and instantiation related things.
-//!
-//! The nomenclature surrounding templates is often confusing, so here are a few
-//! brief definitions:
-//!
-//! * "Template definition": a class/struct/alias/function definition that takes
-//! generic template parameters. For example:
-//!
-//! ```c++
-//! template<typename T>
-//! class List<T> {
-//! // ...
-//! };
-//! ```
-//!
-//! * "Template instantiation": an instantiation is a use of a template with
-//! concrete template arguments. For example, `List<int>`.
-//!
-//! * "Template specialization": an alternative template definition providing a
-//! custom definition for instantiations with the matching template
-//! arguments. This C++ feature is unsupported by bindgen. For example:
-//!
-//! ```c++
-//! template<>
-//! class List<int> {
-//! // Special layout for int lists...
-//! };
-//! ```
-
-use super::context::{BindgenContext, ItemId, TypeId};
-use super::item::{IsOpaque, Item, ItemAncestors};
-use super::traversal::{EdgeKind, Trace, Tracer};
-use crate::clang;
-use crate::parse::ClangItemParser;
-
-/// Template declaration (and such declaration's template parameters) related
-/// methods.
-///
-/// This trait's methods distinguish between `None` and `Some([])` for
-/// declarations that are not templates and template declarations with zero
-/// parameters, in general.
-///
-/// Consider this example:
-///
-/// ```c++
-/// template <typename T, typename U>
-/// class Foo {
-/// T use_of_t;
-/// U use_of_u;
-///
-/// template <typename V>
-/// using Bar = V*;
-///
-/// class Inner {
-/// T x;
-/// U y;
-/// Bar<int> z;
-/// };
-///
-/// template <typename W>
-/// class Lol {
-/// // No use of W, but here's a use of T.
-/// T t;
-/// };
-///
-/// template <typename X>
-/// class Wtf {
-/// // X is not used because W is not used.
-/// Lol<X> lololol;
-/// };
-/// };
-///
-/// class Qux {
-/// int y;
-/// };
-/// ```
-///
-/// The following table depicts the results of each trait method when invoked on
-/// each of the declarations above:
-///
-/// +------+----------------------+--------------------------+------------------------+----
-/// |Decl. | self_template_params | num_self_template_params | all_template_parameters| ...
-/// +------+----------------------+--------------------------+------------------------+----
-/// |Foo | [T, U] | 2 | [T, U] | ...
-/// |Bar | [V] | 1 | [T, U, V] | ...
-/// |Inner | [] | 0 | [T, U] | ...
-/// |Lol | [W] | 1 | [T, U, W] | ...
-/// |Wtf | [X] | 1 | [T, U, X] | ...
-/// |Qux | [] | 0 | [] | ...
-/// +------+----------------------+--------------------------+------------------------+----
-///
-/// ----+------+-----+----------------------+
-/// ... |Decl. | ... | used_template_params |
-/// ----+------+-----+----------------------+
-/// ... |Foo | ... | [T, U] |
-/// ... |Bar | ... | [V] |
-/// ... |Inner | ... | [] |
-/// ... |Lol | ... | [T] |
-/// ... |Wtf | ... | [T] |
-/// ... |Qux | ... | [] |
-/// ----+------+-----+----------------------+
-pub trait TemplateParameters: Sized {
- /// Get the set of `ItemId`s that make up this template declaration's free
- /// template parameters.
- ///
- /// Note that these might *not* all be named types: C++ allows
- /// constant-value template parameters as well as template-template
- /// parameters. Of course, Rust does not allow generic parameters to be
- /// anything but types, so we must treat them as opaque, and avoid
- /// instantiating them.
- fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>;
-
- /// Get the number of free template parameters this template declaration
- /// has.
- fn num_self_template_params(&self, ctx: &BindgenContext) -> usize {
- self.self_template_params(ctx).len()
- }
-
- /// Get the complete set of template parameters that can affect this
- /// declaration.
- ///
- /// Note that this item doesn't need to be a template declaration itself for
- /// `Some` to be returned here (in contrast to `self_template_params`). If
- /// this item is a member of a template declaration, then the parent's
- /// template parameters are included here.
- ///
- /// In the example above, `Inner` depends on both of the `T` and `U` type
- /// parameters, even though it is not itself a template declaration and
- /// therefore has no type parameters itself. Perhaps it helps to think about
- /// how we would fully reference such a member type in C++:
- /// `Foo<int,char>::Inner`. `Foo` *must* be instantiated with template
- /// arguments before we can gain access to the `Inner` member type.
- fn all_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>
- where
- Self: ItemAncestors,
- {
- let mut ancestors: Vec<_> = self.ancestors(ctx).collect();
- ancestors.reverse();
- ancestors
- .into_iter()
- .flat_map(|id| id.self_template_params(ctx).into_iter())
- .collect()
- }
-
- /// Get only the set of template parameters that this item uses. This is a
- /// subset of `all_template_params` and does not necessarily contain any of
- /// `self_template_params`.
- fn used_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>
- where
- Self: AsRef<ItemId>,
- {
- assert!(
- ctx.in_codegen_phase(),
- "template parameter usage is not computed until codegen"
- );
-
- let id = *self.as_ref();
- ctx.resolve_item(id)
- .all_template_params(ctx)
- .into_iter()
- .filter(|p| ctx.uses_template_parameter(id, *p))
- .collect()
- }
-}
-
-/// A trait for things which may or may not be a named template type parameter.
-pub trait AsTemplateParam {
- /// Any extra information the implementor might need to make this decision.
- type Extra;
-
- /// Convert this thing to the item id of a named template type parameter.
- fn as_template_param(
- &self,
- ctx: &BindgenContext,
- extra: &Self::Extra,
- ) -> Option<TypeId>;
-
- /// Is this a named template type parameter?
- fn is_template_param(
- &self,
- ctx: &BindgenContext,
- extra: &Self::Extra,
- ) -> bool {
- self.as_template_param(ctx, extra).is_some()
- }
-}
-
-/// A concrete instantiation of a generic template.
-#[derive(Clone, Debug)]
-pub struct TemplateInstantiation {
- /// The template definition which this is instantiating.
- definition: TypeId,
- /// The concrete template arguments, which will be substituted in the
- /// definition for the generic template parameters.
- args: Vec<TypeId>,
-}
-
-impl TemplateInstantiation {
- /// Construct a new template instantiation from the given parts.
- pub fn new<I>(definition: TypeId, args: I) -> TemplateInstantiation
- where
- I: IntoIterator<Item = TypeId>,
- {
- TemplateInstantiation {
- definition,
- args: args.into_iter().collect(),
- }
- }
-
- /// Get the template definition for this instantiation.
- pub fn template_definition(&self) -> TypeId {
- self.definition
- }
-
- /// Get the concrete template arguments used in this instantiation.
- pub fn template_arguments(&self) -> &[TypeId] {
- &self.args[..]
- }
-
- /// Parse a `TemplateInstantiation` from a clang `Type`.
- pub fn from_ty(
- ty: &clang::Type,
- ctx: &mut BindgenContext,
- ) -> Option<TemplateInstantiation> {
- use clang_sys::*;
-
- let template_args = ty.template_args().map_or(vec![], |args| match ty
- .canonical_type()
- .template_args()
- {
- Some(canonical_args) => {
- let arg_count = args.len();
- args.chain(canonical_args.skip(arg_count))
- .filter(|t| t.kind() != CXType_Invalid)
- .map(|t| {
- Item::from_ty_or_ref(t, t.declaration(), None, ctx)
- })
- .collect()
- }
- None => args
- .filter(|t| t.kind() != CXType_Invalid)
- .map(|t| Item::from_ty_or_ref(t, t.declaration(), None, ctx))
- .collect(),
- });
-
- let declaration = ty.declaration();
- let definition = if declaration.kind() == CXCursor_TypeAliasTemplateDecl
- {
- Some(declaration)
- } else {
- declaration.specialized().or_else(|| {
- let mut template_ref = None;
- ty.declaration().visit(|child| {
- if child.kind() == CXCursor_TemplateRef {
- template_ref = Some(child);
- return CXVisit_Break;
- }
-
- // Instantiations of template aliases might have the
- // TemplateRef to the template alias definition arbitrarily
- // deep, so we need to recurse here and not only visit
- // direct children.
- CXChildVisit_Recurse
- });
-
- template_ref.and_then(|cur| cur.referenced())
- })
- };
-
- let definition = match definition {
- Some(def) => def,
- None => {
- if !ty.declaration().is_builtin() {
- warn!(
- "Could not find template definition for template \
- instantiation"
- );
- }
- return None;
- }
- };
-
- let template_definition =
- Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx);
-
- Some(TemplateInstantiation::new(
- template_definition,
- template_args,
- ))
- }
-}
-
-impl IsOpaque for TemplateInstantiation {
- type Extra = Item;
-
- /// Is this an opaque template instantiation?
- fn is_opaque(&self, ctx: &BindgenContext, item: &Item) -> bool {
- if self.template_definition().is_opaque(ctx, &()) {
- return true;
- }
-
- // TODO(#774): This doesn't properly handle opaque instantiations where
- // an argument is itself an instantiation because `canonical_name` does
- // not insert the template arguments into the name, ie it for nested
- // template arguments it creates "Foo" instead of "Foo<int>". The fully
- // correct fix is to make `canonical_{name,path}` include template
- // arguments properly.
-
- let mut path = item.path_for_allowlisting(ctx).clone();
- let args: Vec<_> = self
- .template_arguments()
- .iter()
- .map(|arg| {
- let arg_path =
- ctx.resolve_item(*arg).path_for_allowlisting(ctx);
- arg_path[1..].join("::")
- })
- .collect();
- {
- let last = path.last_mut().unwrap();
- last.push('<');
- last.push_str(&args.join(", "));
- last.push('>');
- }
-
- ctx.opaque_by_name(&path)
- }
-}
-
-impl Trace for TemplateInstantiation {
- type Extra = ();
-
- fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
- where
- T: Tracer,
- {
- tracer
- .visit_kind(self.definition.into(), EdgeKind::TemplateDeclaration);
- for arg in self.template_arguments() {
- tracer.visit_kind(arg.into(), EdgeKind::TemplateArgument);
- }
- }
-}
diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs
deleted file mode 100644
index f14483f2..00000000
--- a/src/ir/traversal.rs
+++ /dev/null
@@ -1,478 +0,0 @@
-//! Traversal of the graph of IR items and types.
-
-use super::context::{BindgenContext, ItemId};
-use super::item::ItemSet;
-use std::collections::{BTreeMap, VecDeque};
-
-/// An outgoing edge in the IR graph is a reference from some item to another
-/// item:
-///
-/// from --> to
-///
-/// The `from` is left implicit: it is the concrete `Trace` implementer which
-/// yielded this outgoing edge.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct Edge {
- to: ItemId,
- kind: EdgeKind,
-}
-
-impl Edge {
- /// Construct a new edge whose referent is `to` and is of the given `kind`.
- pub fn new(to: ItemId, kind: EdgeKind) -> Edge {
- Edge { to, kind }
- }
-}
-
-impl From<Edge> for ItemId {
- fn from(val: Edge) -> Self {
- val.to
- }
-}
-
-/// The kind of edge reference. This is useful when we wish to only consider
-/// certain kinds of edges for a particular traversal or analysis.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum EdgeKind {
- /// A generic, catch-all edge.
- Generic,
-
- /// An edge from a template declaration, to the definition of a named type
- /// parameter. For example, the edge from `Foo<T>` to `T` in the following
- /// snippet:
- ///
- /// ```C++
- /// template<typename T>
- /// class Foo { };
- /// ```
- TemplateParameterDefinition,
-
- /// An edge from a template instantiation to the template declaration that
- /// is being instantiated. For example, the edge from `Foo<int>` to
- /// to `Foo<T>`:
- ///
- /// ```C++
- /// template<typename T>
- /// class Foo { };
- ///
- /// using Bar = Foo<ant>;
- /// ```
- TemplateDeclaration,
-
- /// An edge from a template instantiation to its template argument. For
- /// example, `Foo<Bar>` to `Bar`:
- ///
- /// ```C++
- /// template<typename T>
- /// class Foo { };
- ///
- /// class Bar { };
- ///
- /// using FooBar = Foo<Bar>;
- /// ```
- TemplateArgument,
-
- /// An edge from a compound type to one of its base member types. For
- /// example, the edge from `Bar` to `Foo`:
- ///
- /// ```C++
- /// class Foo { };
- ///
- /// class Bar : public Foo { };
- /// ```
- BaseMember,
-
- /// An edge from a compound type to the types of one of its fields. For
- /// example, the edge from `Foo` to `int`:
- ///
- /// ```C++
- /// class Foo {
- /// int x;
- /// };
- /// ```
- Field,
-
- /// An edge from an class or struct type to an inner type member. For
- /// example, the edge from `Foo` to `Foo::Bar` here:
- ///
- /// ```C++
- /// class Foo {
- /// struct Bar { };
- /// };
- /// ```
- InnerType,
-
- /// An edge from an class or struct type to an inner static variable. For
- /// example, the edge from `Foo` to `Foo::BAR` here:
- ///
- /// ```C++
- /// class Foo {
- /// static const char* BAR;
- /// };
- /// ```
- InnerVar,
-
- /// An edge from a class or struct type to one of its method functions. For
- /// example, the edge from `Foo` to `Foo::bar`:
- ///
- /// ```C++
- /// class Foo {
- /// bool bar(int x, int y);
- /// };
- /// ```
- Method,
-
- /// An edge from a class or struct type to one of its constructor
- /// functions. For example, the edge from `Foo` to `Foo::Foo(int x, int y)`:
- ///
- /// ```C++
- /// class Foo {
- /// int my_x;
- /// int my_y;
- ///
- /// public:
- /// Foo(int x, int y);
- /// };
- /// ```
- Constructor,
-
- /// An edge from a class or struct type to its destructor function. For
- /// example, the edge from `Doggo` to `Doggo::~Doggo()`:
- ///
- /// ```C++
- /// struct Doggo {
- /// char* wow;
- ///
- /// public:
- /// ~Doggo();
- /// };
- /// ```
- Destructor,
-
- /// An edge from a function declaration to its return type. For example, the
- /// edge from `foo` to `int`:
- ///
- /// ```C++
- /// int foo(char* string);
- /// ```
- FunctionReturn,
-
- /// An edge from a function declaration to one of its parameter types. For
- /// example, the edge from `foo` to `char*`:
- ///
- /// ```C++
- /// int foo(char* string);
- /// ```
- FunctionParameter,
-
- /// An edge from a static variable to its type. For example, the edge from
- /// `FOO` to `const char*`:
- ///
- /// ```C++
- /// static const char* FOO;
- /// ```
- VarType,
-
- /// An edge from a non-templated alias or typedef to the referenced type.
- TypeReference,
-}
-
-/// A predicate to allow visiting only sub-sets of the whole IR graph by
-/// excluding certain edges from being followed by the traversal.
-///
-/// The predicate must return true if the traversal should follow this edge
-/// and visit everything that is reachable through it.
-pub type TraversalPredicate = for<'a> fn(&'a BindgenContext, Edge) -> bool;
-
-/// A `TraversalPredicate` implementation that follows all edges, and therefore
-/// traversals using this predicate will see the whole IR graph reachable from
-/// the traversal's roots.
-pub fn all_edges(_: &BindgenContext, _: Edge) -> bool {
- true
-}
-
-/// A `TraversalPredicate` implementation that only follows
-/// `EdgeKind::InnerType` edges, and therefore traversals using this predicate
-/// will only visit the traversal's roots and their inner types. This is used
-/// in no-recursive-allowlist mode, where inner types such as anonymous
-/// structs/unions still need to be processed.
-pub fn only_inner_type_edges(_: &BindgenContext, edge: Edge) -> bool {
- edge.kind == EdgeKind::InnerType
-}
-
-/// A `TraversalPredicate` implementation that only follows edges to items that
-/// are enabled for code generation. This lets us skip considering items for
-/// which are not reachable from code generation.
-pub fn codegen_edges(ctx: &BindgenContext, edge: Edge) -> bool {
- let cc = &ctx.options().codegen_config;
- match edge.kind {
- EdgeKind::Generic => {
- ctx.resolve_item(edge.to).is_enabled_for_codegen(ctx)
- }
-
- // We statically know the kind of item that non-generic edges can point
- // to, so we don't need to actually resolve the item and check
- // `Item::is_enabled_for_codegen`.
- EdgeKind::TemplateParameterDefinition |
- EdgeKind::TemplateArgument |
- EdgeKind::TemplateDeclaration |
- EdgeKind::BaseMember |
- EdgeKind::Field |
- EdgeKind::InnerType |
- EdgeKind::FunctionReturn |
- EdgeKind::FunctionParameter |
- EdgeKind::VarType |
- EdgeKind::TypeReference => cc.types(),
- EdgeKind::InnerVar => cc.vars(),
- EdgeKind::Method => cc.methods(),
- EdgeKind::Constructor => cc.constructors(),
- EdgeKind::Destructor => cc.destructors(),
- }
-}
-
-/// The storage for the set of items that have been seen (although their
-/// outgoing edges might not have been fully traversed yet) in an active
-/// traversal.
-pub trait TraversalStorage<'ctx> {
- /// Construct a new instance of this TraversalStorage, for a new traversal.
- fn new(ctx: &'ctx BindgenContext) -> Self;
-
- /// Add the given item to the storage. If the item has never been seen
- /// before, return `true`. Otherwise, return `false`.
- ///
- /// The `from` item is the item from which we discovered this item, or is
- /// `None` if this item is a root.
- fn add(&mut self, from: Option<ItemId>, item: ItemId) -> bool;
-}
-
-impl<'ctx> TraversalStorage<'ctx> for ItemSet {
- fn new(_: &'ctx BindgenContext) -> Self {
- ItemSet::new()
- }
-
- fn add(&mut self, _: Option<ItemId>, item: ItemId) -> bool {
- self.insert(item)
- }
-}
-
-/// A `TraversalStorage` implementation that keeps track of how we first reached
-/// each item. This is useful for providing debug assertions with meaningful
-/// diagnostic messages about dangling items.
-#[derive(Debug)]
-pub struct Paths<'ctx>(BTreeMap<ItemId, ItemId>, &'ctx BindgenContext);
-
-impl<'ctx> TraversalStorage<'ctx> for Paths<'ctx> {
- fn new(ctx: &'ctx BindgenContext) -> Self {
- Paths(BTreeMap::new(), ctx)
- }
-
- fn add(&mut self, from: Option<ItemId>, item: ItemId) -> bool {
- let newly_discovered =
- self.0.insert(item, from.unwrap_or(item)).is_none();
-
- if self.1.resolve_item_fallible(item).is_none() {
- let mut path = vec![];
- let mut current = item;
- loop {
- let predecessor = *self.0.get(&current).expect(
- "We know we found this item id, so it must have a \
- predecessor",
- );
- if predecessor == current {
- break;
- }
- path.push(predecessor);
- current = predecessor;
- }
- path.reverse();
- panic!(
- "Found reference to dangling id = {:?}\nvia path = {:?}",
- item, path
- );
- }
-
- newly_discovered
- }
-}
-
-/// The queue of seen-but-not-yet-traversed items.
-///
-/// Using a FIFO queue with a traversal will yield a breadth-first traversal,
-/// while using a LIFO queue will result in a depth-first traversal of the IR
-/// graph.
-pub trait TraversalQueue: Default {
- /// Add a newly discovered item to the queue.
- fn push(&mut self, item: ItemId);
-
- /// Pop the next item to traverse, if any.
- fn next(&mut self) -> Option<ItemId>;
-}
-
-impl TraversalQueue for Vec<ItemId> {
- fn push(&mut self, item: ItemId) {
- self.push(item);
- }
-
- fn next(&mut self) -> Option<ItemId> {
- self.pop()
- }
-}
-
-impl TraversalQueue for VecDeque<ItemId> {
- fn push(&mut self, item: ItemId) {
- self.push_back(item);
- }
-
- fn next(&mut self) -> Option<ItemId> {
- self.pop_front()
- }
-}
-
-/// Something that can receive edges from a `Trace` implementation.
-pub trait Tracer {
- /// Note an edge between items. Called from within a `Trace` implementation.
- fn visit_kind(&mut self, item: ItemId, kind: EdgeKind);
-
- /// A synonym for `tracer.visit_kind(item, EdgeKind::Generic)`.
- fn visit(&mut self, item: ItemId) {
- self.visit_kind(item, EdgeKind::Generic);
- }
-}
-
-impl<F> Tracer for F
-where
- F: FnMut(ItemId, EdgeKind),
-{
- fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) {
- (*self)(item, kind)
- }
-}
-
-/// Trace all of the outgoing edges to other items. Implementations should call
-/// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)`
-/// for each of their outgoing edges.
-pub trait Trace {
- /// If a particular type needs extra information beyond what it has in
- /// `self` and `context` to find its referenced items, its implementation
- /// can define this associated type, forcing callers to pass the needed
- /// information through.
- type Extra;
-
- /// Trace all of this item's outgoing edges to other items.
- fn trace<T>(
- &self,
- context: &BindgenContext,
- tracer: &mut T,
- extra: &Self::Extra,
- ) where
- T: Tracer;
-}
-
-/// An graph traversal of the transitive closure of references between items.
-///
-/// See `BindgenContext::allowlisted_items` for more information.
-pub struct ItemTraversal<'ctx, Storage, Queue>
-where
- Storage: TraversalStorage<'ctx>,
- Queue: TraversalQueue,
-{
- ctx: &'ctx BindgenContext,
-
- /// The set of items we have seen thus far in this traversal.
- seen: Storage,
-
- /// The set of items that we have seen, but have yet to traverse.
- queue: Queue,
-
- /// The predicate that determines which edges this traversal will follow.
- predicate: TraversalPredicate,
-
- /// The item we are currently traversing.
- currently_traversing: Option<ItemId>,
-}
-
-impl<'ctx, Storage, Queue> ItemTraversal<'ctx, Storage, Queue>
-where
- Storage: TraversalStorage<'ctx>,
- Queue: TraversalQueue,
-{
- /// Begin a new traversal, starting from the given roots.
- pub fn new<R>(
- ctx: &'ctx BindgenContext,
- roots: R,
- predicate: TraversalPredicate,
- ) -> ItemTraversal<'ctx, Storage, Queue>
- where
- R: IntoIterator<Item = ItemId>,
- {
- let mut seen = Storage::new(ctx);
- let mut queue = Queue::default();
-
- for id in roots {
- seen.add(None, id);
- queue.push(id);
- }
-
- ItemTraversal {
- ctx,
- seen,
- queue,
- predicate,
- currently_traversing: None,
- }
- }
-}
-
-impl<'ctx, Storage, Queue> Tracer for ItemTraversal<'ctx, Storage, Queue>
-where
- Storage: TraversalStorage<'ctx>,
- Queue: TraversalQueue,
-{
- fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) {
- let edge = Edge::new(item, kind);
- if !(self.predicate)(self.ctx, edge) {
- return;
- }
-
- let is_newly_discovered =
- self.seen.add(self.currently_traversing, item);
- if is_newly_discovered {
- self.queue.push(item)
- }
- }
-}
-
-impl<'ctx, Storage, Queue> Iterator for ItemTraversal<'ctx, Storage, Queue>
-where
- Storage: TraversalStorage<'ctx>,
- Queue: TraversalQueue,
-{
- type Item = ItemId;
-
- fn next(&mut self) -> Option<Self::Item> {
- let id = self.queue.next()?;
-
- let newly_discovered = self.seen.add(None, id);
- debug_assert!(
- !newly_discovered,
- "should have already seen anything we get out of our queue"
- );
- debug_assert!(
- self.ctx.resolve_item_fallible(id).is_some(),
- "should only get IDs of actual items in our context during traversal"
- );
-
- self.currently_traversing = Some(id);
- id.trace(self.ctx, self, &());
- self.currently_traversing = None;
-
- Some(id)
- }
-}
-
-/// An iterator to find any dangling items.
-///
-/// See `BindgenContext::assert_no_dangling_item_traversal` for more
-/// information.
-pub type AssertNoDanglingItemsTraversal<'ctx> =
- ItemTraversal<'ctx, Paths<'ctx>, VecDeque<ItemId>>;
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
deleted file mode 100644
index 6a3fd0e8..00000000
--- a/src/ir/ty.rs
+++ /dev/null
@@ -1,1266 +0,0 @@
-//! Everything related to types in our intermediate representation.
-
-use super::comp::CompInfo;
-use super::context::{BindgenContext, ItemId, TypeId};
-use super::dot::DotAttributes;
-use super::enum_ty::Enum;
-use super::function::FunctionSig;
-use super::int::IntKind;
-use super::item::{IsOpaque, Item};
-use super::layout::{Layout, Opaque};
-use super::objc::ObjCInterface;
-use super::template::{
- AsTemplateParam, TemplateInstantiation, TemplateParameters,
-};
-use super::traversal::{EdgeKind, Trace, Tracer};
-use crate::clang::{self, Cursor};
-use crate::parse::{ClangItemParser, ParseError, ParseResult};
-use std::borrow::Cow;
-use std::io;
-
-/// The base representation of a type in bindgen.
-///
-/// A type has an optional name, which if present cannot be empty, a `layout`
-/// (size, alignment and packedness) if known, a `Kind`, which determines which
-/// kind of type it is, and whether the type is const.
-#[derive(Debug)]
-pub struct Type {
- /// The name of the type, or None if it was an unnamed struct or union.
- name: Option<String>,
- /// The layout of the type, if known.
- layout: Option<Layout>,
- /// The inner kind of the type
- kind: TypeKind,
- /// Whether this type is const-qualified.
- is_const: bool,
-}
-
-/// The maximum number of items in an array for which Rust implements common
-/// traits, and so if we have a type containing an array with more than this
-/// many items, we won't be able to derive common traits on that type.
-///
-pub const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32;
-
-impl Type {
- /// Get the underlying `CompInfo` for this type, or `None` if this is some
- /// other kind of type.
- pub fn as_comp(&self) -> Option<&CompInfo> {
- match self.kind {
- TypeKind::Comp(ref ci) => Some(ci),
- _ => None,
- }
- }
-
- /// Get the underlying `CompInfo` for this type as a mutable reference, or
- /// `None` if this is some other kind of type.
- pub fn as_comp_mut(&mut self) -> Option<&mut CompInfo> {
- match self.kind {
- TypeKind::Comp(ref mut ci) => Some(ci),
- _ => None,
- }
- }
-
- /// Construct a new `Type`.
- pub fn new(
- name: Option<String>,
- layout: Option<Layout>,
- kind: TypeKind,
- is_const: bool,
- ) -> Self {
- Type {
- name,
- layout,
- kind,
- is_const,
- }
- }
-
- /// Which kind of type is this?
- pub fn kind(&self) -> &TypeKind {
- &self.kind
- }
-
- /// Get a mutable reference to this type's kind.
- pub fn kind_mut(&mut self) -> &mut TypeKind {
- &mut self.kind
- }
-
- /// Get this type's name.
- pub fn name(&self) -> Option<&str> {
- self.name.as_deref()
- }
-
- /// Whether this is a block pointer type.
- pub fn is_block_pointer(&self) -> bool {
- matches!(self.kind, TypeKind::BlockPointer(..))
- }
-
- /// Is this a compound type?
- pub fn is_comp(&self) -> bool {
- matches!(self.kind, TypeKind::Comp(..))
- }
-
- /// Is this a union?
- pub fn is_union(&self) -> bool {
- match self.kind {
- TypeKind::Comp(ref comp) => comp.is_union(),
- _ => false,
- }
- }
-
- /// Is this type of kind `TypeKind::TypeParam`?
- pub fn is_type_param(&self) -> bool {
- matches!(self.kind, TypeKind::TypeParam)
- }
-
- /// Is this a template instantiation type?
- pub fn is_template_instantiation(&self) -> bool {
- matches!(self.kind, TypeKind::TemplateInstantiation(..))
- }
-
- /// Is this a template alias type?
- pub fn is_template_alias(&self) -> bool {
- matches!(self.kind, TypeKind::TemplateAlias(..))
- }
-
- /// Is this a function type?
- pub fn is_function(&self) -> bool {
- matches!(self.kind, TypeKind::Function(..))
- }
-
- /// Is this an enum type?
- pub fn is_enum(&self) -> bool {
- matches!(self.kind, TypeKind::Enum(..))
- }
-
- /// Is this either a builtin or named type?
- pub fn is_builtin_or_type_param(&self) -> bool {
- matches!(
- self.kind,
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Function(..) |
- TypeKind::Array(..) |
- TypeKind::Reference(..) |
- TypeKind::Pointer(..) |
- TypeKind::Int(..) |
- TypeKind::Float(..) |
- TypeKind::TypeParam
- )
- }
-
- /// Creates a new named type, with name `name`.
- pub fn named(name: String) -> Self {
- let name = if name.is_empty() { None } else { Some(name) };
- Self::new(name, None, TypeKind::TypeParam, false)
- }
-
- /// Is this a floating point type?
- pub fn is_float(&self) -> bool {
- matches!(self.kind, TypeKind::Float(..))
- }
-
- /// Is this a boolean type?
- pub fn is_bool(&self) -> bool {
- matches!(self.kind, TypeKind::Int(IntKind::Bool))
- }
-
- /// Is this an integer type?
- pub fn is_integer(&self) -> bool {
- matches!(self.kind, TypeKind::Int(..))
- }
-
- /// Cast this type to an integer kind, or `None` if it is not an integer
- /// type.
- pub fn as_integer(&self) -> Option<IntKind> {
- match self.kind {
- TypeKind::Int(int_kind) => Some(int_kind),
- _ => None,
- }
- }
-
- /// Is this a `const` qualified type?
- pub fn is_const(&self) -> bool {
- self.is_const
- }
-
- /// Is this a reference to another type?
- pub fn is_type_ref(&self) -> bool {
- matches!(
- self.kind,
- TypeKind::ResolvedTypeRef(_) | TypeKind::UnresolvedTypeRef(_, _, _)
- )
- }
-
- /// Is this an unresolved reference?
- pub fn is_unresolved_ref(&self) -> bool {
- matches!(self.kind, TypeKind::UnresolvedTypeRef(_, _, _))
- }
-
- /// Is this a incomplete array type?
- pub fn is_incomplete_array(&self, ctx: &BindgenContext) -> Option<ItemId> {
- match self.kind {
- TypeKind::Array(item, len) => {
- if len == 0 {
- Some(item.into())
- } else {
- None
- }
- }
- TypeKind::ResolvedTypeRef(inner) => {
- ctx.resolve_type(inner).is_incomplete_array(ctx)
- }
- _ => None,
- }
- }
-
- /// What is the layout of this type?
- pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
- self.layout.or_else(|| {
- match self.kind {
- TypeKind::Comp(ref ci) => ci.layout(ctx),
- TypeKind::Array(inner, length) if length == 0 => Some(
- Layout::new(0, ctx.resolve_type(inner).layout(ctx)?.align),
- ),
- // FIXME(emilio): This is a hack for anonymous union templates.
- // Use the actual pointer size!
- TypeKind::Pointer(..) => Some(Layout::new(
- ctx.target_pointer_size(),
- ctx.target_pointer_size(),
- )),
- TypeKind::ResolvedTypeRef(inner) => {
- ctx.resolve_type(inner).layout(ctx)
- }
- _ => None,
- }
- })
- }
-
- /// Whether this named type is an invalid C++ identifier. This is done to
- /// avoid generating invalid code with some cases we can't handle, see:
- ///
- /// tests/headers/381-decltype-alias.hpp
- pub fn is_invalid_type_param(&self) -> bool {
- match self.kind {
- TypeKind::TypeParam => {
- let name = self.name().expect("Unnamed named type?");
- !clang::is_valid_identifier(name)
- }
- _ => false,
- }
- }
-
- /// Takes `name`, and returns a suitable identifier representation for it.
- fn sanitize_name(name: &str) -> Cow<str> {
- if clang::is_valid_identifier(name) {
- return Cow::Borrowed(name);
- }
-
- let name = name.replace(|c| c == ' ' || c == ':' || c == '.', "_");
- Cow::Owned(name)
- }
-
- /// Get this type's santizied name.
- pub fn sanitized_name<'a>(
- &'a self,
- ctx: &BindgenContext,
- ) -> Option<Cow<'a, str>> {
- let name_info = match *self.kind() {
- TypeKind::Pointer(inner) => Some((inner, Cow::Borrowed("ptr"))),
- TypeKind::Reference(inner) => Some((inner, Cow::Borrowed("ref"))),
- TypeKind::Array(inner, length) => {
- Some((inner, format!("array{}", length).into()))
- }
- _ => None,
- };
- if let Some((inner, prefix)) = name_info {
- ctx.resolve_item(inner)
- .expect_type()
- .sanitized_name(ctx)
- .map(|name| format!("{}_{}", prefix, name).into())
- } else {
- self.name().map(Self::sanitize_name)
- }
- }
-
- /// See safe_canonical_type.
- pub fn canonical_type<'tr>(
- &'tr self,
- ctx: &'tr BindgenContext,
- ) -> &'tr Type {
- self.safe_canonical_type(ctx)
- .expect("Should have been resolved after parsing!")
- }
-
- /// Returns the canonical type of this type, that is, the "inner type".
- ///
- /// For example, for a `typedef`, the canonical type would be the
- /// `typedef`ed type, for a template instantiation, would be the template
- /// its specializing, and so on. Return None if the type is unresolved.
- pub fn safe_canonical_type<'tr>(
- &'tr self,
- ctx: &'tr BindgenContext,
- ) -> Option<&'tr Type> {
- match self.kind {
- TypeKind::TypeParam |
- TypeKind::Array(..) |
- TypeKind::Vector(..) |
- TypeKind::Comp(..) |
- TypeKind::Opaque |
- TypeKind::Int(..) |
- TypeKind::Float(..) |
- TypeKind::Complex(..) |
- TypeKind::Function(..) |
- TypeKind::Enum(..) |
- TypeKind::Reference(..) |
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Pointer(..) |
- TypeKind::BlockPointer(..) |
- TypeKind::ObjCId |
- TypeKind::ObjCSel |
- TypeKind::ObjCInterface(..) => Some(self),
-
- TypeKind::ResolvedTypeRef(inner) |
- TypeKind::Alias(inner) |
- TypeKind::TemplateAlias(inner, _) => {
- ctx.resolve_type(inner).safe_canonical_type(ctx)
- }
- TypeKind::TemplateInstantiation(ref inst) => ctx
- .resolve_type(inst.template_definition())
- .safe_canonical_type(ctx),
-
- TypeKind::UnresolvedTypeRef(..) => None,
- }
- }
-
- /// There are some types we don't want to stop at when finding an opaque
- /// item, so we can arrive to the proper item that needs to be generated.
- pub fn should_be_traced_unconditionally(&self) -> bool {
- matches!(
- self.kind,
- TypeKind::Comp(..) |
- TypeKind::Function(..) |
- TypeKind::Pointer(..) |
- TypeKind::Array(..) |
- TypeKind::Reference(..) |
- TypeKind::TemplateInstantiation(..) |
- TypeKind::ResolvedTypeRef(..)
- )
- }
-}
-
-impl IsOpaque for Type {
- type Extra = Item;
-
- fn is_opaque(&self, ctx: &BindgenContext, item: &Item) -> bool {
- match self.kind {
- TypeKind::Opaque => true,
- TypeKind::TemplateInstantiation(ref inst) => {
- inst.is_opaque(ctx, item)
- }
- TypeKind::Comp(ref comp) => comp.is_opaque(ctx, &self.layout),
- TypeKind::ResolvedTypeRef(to) => to.is_opaque(ctx, &()),
- _ => false,
- }
- }
-}
-
-impl AsTemplateParam for Type {
- type Extra = Item;
-
- fn as_template_param(
- &self,
- ctx: &BindgenContext,
- item: &Item,
- ) -> Option<TypeId> {
- self.kind.as_template_param(ctx, item)
- }
-}
-
-impl AsTemplateParam for TypeKind {
- type Extra = Item;
-
- fn as_template_param(
- &self,
- ctx: &BindgenContext,
- item: &Item,
- ) -> Option<TypeId> {
- match *self {
- TypeKind::TypeParam => Some(item.id().expect_type_id(ctx)),
- TypeKind::ResolvedTypeRef(id) => id.as_template_param(ctx, &()),
- _ => None,
- }
- }
-}
-
-impl DotAttributes for Type {
- fn dot_attributes<W>(
- &self,
- ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write,
- {
- if let Some(ref layout) = self.layout {
- writeln!(
- out,
- "<tr><td>size</td><td>{}</td></tr>
- <tr><td>align</td><td>{}</td></tr>",
- layout.size, layout.align
- )?;
- if layout.packed {
- writeln!(out, "<tr><td>packed</td><td>true</td></tr>")?;
- }
- }
-
- if self.is_const {
- writeln!(out, "<tr><td>const</td><td>true</td></tr>")?;
- }
-
- self.kind.dot_attributes(ctx, out)
- }
-}
-
-impl DotAttributes for TypeKind {
- fn dot_attributes<W>(
- &self,
- ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write,
- {
- writeln!(
- out,
- "<tr><td>type kind</td><td>{}</td></tr>",
- self.kind_name()
- )?;
-
- if let TypeKind::Comp(ref comp) = *self {
- comp.dot_attributes(ctx, out)?;
- }
-
- Ok(())
- }
-}
-
-impl TypeKind {
- fn kind_name(&self) -> &'static str {
- match *self {
- TypeKind::Void => "Void",
- TypeKind::NullPtr => "NullPtr",
- TypeKind::Comp(..) => "Comp",
- TypeKind::Opaque => "Opaque",
- TypeKind::Int(..) => "Int",
- TypeKind::Float(..) => "Float",
- TypeKind::Complex(..) => "Complex",
- TypeKind::Alias(..) => "Alias",
- TypeKind::TemplateAlias(..) => "TemplateAlias",
- TypeKind::Array(..) => "Array",
- TypeKind::Vector(..) => "Vector",
- TypeKind::Function(..) => "Function",
- TypeKind::Enum(..) => "Enum",
- TypeKind::Pointer(..) => "Pointer",
- TypeKind::BlockPointer(..) => "BlockPointer",
- TypeKind::Reference(..) => "Reference",
- TypeKind::TemplateInstantiation(..) => "TemplateInstantiation",
- TypeKind::UnresolvedTypeRef(..) => "UnresolvedTypeRef",
- TypeKind::ResolvedTypeRef(..) => "ResolvedTypeRef",
- TypeKind::TypeParam => "TypeParam",
- TypeKind::ObjCInterface(..) => "ObjCInterface",
- TypeKind::ObjCId => "ObjCId",
- TypeKind::ObjCSel => "ObjCSel",
- }
- }
-}
-
-#[test]
-fn is_invalid_type_param_valid() {
- let ty = Type::new(Some("foo".into()), None, TypeKind::TypeParam, false);
- assert!(!ty.is_invalid_type_param())
-}
-
-#[test]
-fn is_invalid_type_param_valid_underscore_and_numbers() {
- let ty = Type::new(
- Some("_foo123456789_".into()),
- None,
- TypeKind::TypeParam,
- false,
- );
- assert!(!ty.is_invalid_type_param())
-}
-
-#[test]
-fn is_invalid_type_param_valid_unnamed_kind() {
- let ty = Type::new(Some("foo".into()), None, TypeKind::Void, false);
- assert!(!ty.is_invalid_type_param())
-}
-
-#[test]
-fn is_invalid_type_param_invalid_start() {
- let ty = Type::new(Some("1foo".into()), None, TypeKind::TypeParam, false);
- assert!(ty.is_invalid_type_param())
-}
-
-#[test]
-fn is_invalid_type_param_invalid_remaing() {
- let ty = Type::new(Some("foo-".into()), None, TypeKind::TypeParam, false);
- assert!(ty.is_invalid_type_param())
-}
-
-#[test]
-#[should_panic]
-fn is_invalid_type_param_unnamed() {
- let ty = Type::new(None, None, TypeKind::TypeParam, false);
- assert!(ty.is_invalid_type_param())
-}
-
-#[test]
-fn is_invalid_type_param_empty_name() {
- let ty = Type::new(Some("".into()), None, TypeKind::TypeParam, false);
- assert!(ty.is_invalid_type_param())
-}
-
-impl TemplateParameters for Type {
- fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
- self.kind.self_template_params(ctx)
- }
-}
-
-impl TemplateParameters for TypeKind {
- fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
- match *self {
- TypeKind::ResolvedTypeRef(id) => {
- ctx.resolve_type(id).self_template_params(ctx)
- }
- TypeKind::Comp(ref comp) => comp.self_template_params(ctx),
- TypeKind::TemplateAlias(_, ref args) => args.clone(),
-
- TypeKind::Opaque |
- TypeKind::TemplateInstantiation(..) |
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Int(_) |
- TypeKind::Float(_) |
- TypeKind::Complex(_) |
- TypeKind::Array(..) |
- TypeKind::Vector(..) |
- TypeKind::Function(_) |
- TypeKind::Enum(_) |
- TypeKind::Pointer(_) |
- TypeKind::BlockPointer(_) |
- TypeKind::Reference(_) |
- TypeKind::UnresolvedTypeRef(..) |
- TypeKind::TypeParam |
- TypeKind::Alias(_) |
- TypeKind::ObjCId |
- TypeKind::ObjCSel |
- TypeKind::ObjCInterface(_) => vec![],
- }
- }
-}
-
-/// The kind of float this type represents.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum FloatKind {
- /// A `float`.
- Float,
- /// A `double`.
- Double,
- /// A `long double`.
- LongDouble,
- /// A `__float128`.
- Float128,
-}
-
-/// The different kinds of types that we can parse.
-#[derive(Debug)]
-pub enum TypeKind {
- /// The void type.
- Void,
-
- /// The `nullptr_t` type.
- NullPtr,
-
- /// A compound type, that is, a class, struct, or union.
- Comp(CompInfo),
-
- /// An opaque type that we just don't understand. All usage of this shoulf
- /// result in an opaque blob of bytes generated from the containing type's
- /// layout.
- Opaque,
-
- /// An integer type, of a given kind. `bool` and `char` are also considered
- /// integers.
- Int(IntKind),
-
- /// A floating point type.
- Float(FloatKind),
-
- /// A complex floating point type.
- Complex(FloatKind),
-
- /// A type alias, with a name, that points to another type.
- Alias(TypeId),
-
- /// A templated alias, pointing to an inner type, just as `Alias`, but with
- /// template parameters.
- TemplateAlias(TypeId, Vec<TypeId>),
-
- /// A packed vector type: element type, number of elements
- Vector(TypeId, usize),
-
- /// An array of a type and a length.
- Array(TypeId, usize),
-
- /// A function type, with a given signature.
- Function(FunctionSig),
-
- /// An `enum` type.
- Enum(Enum),
-
- /// A pointer to a type. The bool field represents whether it's const or
- /// not.
- Pointer(TypeId),
-
- /// A pointer to an Apple block.
- BlockPointer(TypeId),
-
- /// A reference to a type, as in: int& foo().
- Reference(TypeId),
-
- /// An instantiation of an abstract template definition with a set of
- /// concrete template arguments.
- TemplateInstantiation(TemplateInstantiation),
-
- /// A reference to a yet-to-resolve type. This stores the clang cursor
- /// itself, and postpones its resolution.
- ///
- /// These are gone in a phase after parsing where these are mapped to
- /// already known types, and are converted to ResolvedTypeRef.
- ///
- /// see tests/headers/typeref.hpp to see somewhere where this is a problem.
- UnresolvedTypeRef(
- clang::Type,
- clang::Cursor,
- /* parent_id */
- Option<ItemId>,
- ),
-
- /// An indirection to another type.
- ///
- /// These are generated after we resolve a forward declaration, or when we
- /// replace one type with another.
- ResolvedTypeRef(TypeId),
-
- /// A named type, that is, a template parameter.
- TypeParam,
-
- /// Objective C interface. Always referenced through a pointer
- ObjCInterface(ObjCInterface),
-
- /// Objective C 'id' type, points to any object
- ObjCId,
-
- /// Objective C selector type
- ObjCSel,
-}
-
-impl Type {
- /// This is another of the nasty methods. This one is the one that takes
- /// care of the core logic of converting a clang type to a `Type`.
- ///
- /// It's sort of nasty and full of special-casing, but hopefully the
- /// comments in every special case justify why they're there.
- pub fn from_clang_ty(
- potential_id: ItemId,
- ty: &clang::Type,
- location: Cursor,
- parent_id: Option<ItemId>,
- ctx: &mut BindgenContext,
- ) -> Result<ParseResult<Self>, ParseError> {
- use clang_sys::*;
- {
- let already_resolved = ctx.builtin_or_resolved_ty(
- potential_id,
- parent_id,
- ty,
- Some(location),
- );
- if let Some(ty) = already_resolved {
- debug!("{:?} already resolved: {:?}", ty, location);
- return Ok(ParseResult::AlreadyResolved(ty.into()));
- }
- }
-
- let layout = ty.fallible_layout(ctx).ok();
- let cursor = ty.declaration();
- let mut name = cursor.spelling();
-
- debug!(
- "from_clang_ty: {:?}, ty: {:?}, loc: {:?}",
- potential_id, ty, location
- );
- debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types());
-
- let canonical_ty = ty.canonical_type();
-
- // Parse objc protocols as if they were interfaces
- let mut ty_kind = ty.kind();
- match location.kind() {
- CXCursor_ObjCProtocolDecl | CXCursor_ObjCCategoryDecl => {
- ty_kind = CXType_ObjCInterface
- }
- _ => {}
- }
-
- // Objective C template type parameter
- // FIXME: This is probably wrong, we are attempting to find the
- // objc template params, which seem to manifest as a typedef.
- // We are rewriting them as id to suppress multiple conflicting
- // typedefs at root level
- if ty_kind == CXType_Typedef {
- let is_template_type_param =
- ty.declaration().kind() == CXCursor_TemplateTypeParameter;
- let is_canonical_objcpointer =
- canonical_ty.kind() == CXType_ObjCObjectPointer;
-
- // We have found a template type for objc interface
- if is_canonical_objcpointer && is_template_type_param {
- // Objective-C generics are just ids with fancy name.
- // To keep it simple, just name them ids
- name = "id".to_owned();
- }
- }
-
- if location.kind() == CXCursor_ClassTemplatePartialSpecialization {
- // Sorry! (Not sorry)
- warn!(
- "Found a partial template specialization; bindgen does not \
- support partial template specialization! Constructing \
- opaque type instead."
- );
- return Ok(ParseResult::New(
- Opaque::from_clang_ty(&canonical_ty, ctx),
- None,
- ));
- }
-
- let kind = if location.kind() == CXCursor_TemplateRef ||
- (ty.template_args().is_some() && ty_kind != CXType_Typedef)
- {
- // This is a template instantiation.
- match TemplateInstantiation::from_ty(ty, ctx) {
- Some(inst) => TypeKind::TemplateInstantiation(inst),
- None => TypeKind::Opaque,
- }
- } else {
- match ty_kind {
- CXType_Unexposed
- if *ty != canonical_ty &&
- canonical_ty.kind() != CXType_Invalid &&
- ty.ret_type().is_none() &&
- // Sometime clang desugars some types more than
- // what we need, specially with function
- // pointers.
- //
- // We should also try the solution of inverting
- // those checks instead of doing this, that is,
- // something like:
- //
- // CXType_Unexposed if ty.ret_type().is_some()
- // => { ... }
- //
- // etc.
- !canonical_ty.spelling().contains("type-parameter") =>
- {
- debug!("Looking for canonical type: {:?}", canonical_ty);
- return Self::from_clang_ty(
- potential_id,
- &canonical_ty,
- location,
- parent_id,
- ctx,
- );
- }
- CXType_Unexposed | CXType_Invalid => {
- // For some reason Clang doesn't give us any hint in some
- // situations where we should generate a function pointer (see
- // tests/headers/func_ptr_in_struct.h), so we do a guess here
- // trying to see if it has a valid return type.
- if ty.ret_type().is_some() {
- let signature =
- FunctionSig::from_ty(ty, &location, ctx)?;
- TypeKind::Function(signature)
- // Same here, with template specialisations we can safely
- // assume this is a Comp(..)
- } else if ty.is_fully_instantiated_template() {
- debug!(
- "Template specialization: {:?}, {:?} {:?}",
- ty, location, canonical_ty
- );
- let complex = CompInfo::from_ty(
- potential_id,
- ty,
- Some(location),
- ctx,
- )
- .expect("C'mon");
- TypeKind::Comp(complex)
- } else {
- match location.kind() {
- CXCursor_CXXBaseSpecifier |
- CXCursor_ClassTemplate => {
- if location.kind() == CXCursor_CXXBaseSpecifier
- {
- // In the case we're parsing a base specifier
- // inside an unexposed or invalid type, it means
- // that we're parsing one of two things:
- //
- // * A template parameter.
- // * A complex class that isn't exposed.
- //
- // This means, unfortunately, that there's no
- // good way to differentiate between them.
- //
- // Probably we could try to look at the
- // declaration and complicate more this logic,
- // but we'll keep it simple... if it's a valid
- // C++ identifier, we'll consider it as a
- // template parameter.
- //
- // This is because:
- //
- // * We expect every other base that is a
- // proper identifier (that is, a simple
- // struct/union declaration), to be exposed,
- // so this path can't be reached in that
- // case.
- //
- // * Quite conveniently, complex base
- // specifiers preserve their full names (that
- // is: Foo<T> instead of Foo). We can take
- // advantage of this.
- //
- // If we find some edge case where this doesn't
- // work (which I guess is unlikely, see the
- // different test cases[1][2][3][4]), we'd need
- // to find more creative ways of differentiating
- // these two cases.
- //
- // [1]: inherit_named.hpp
- // [2]: forward-inherit-struct-with-fields.hpp
- // [3]: forward-inherit-struct.hpp
- // [4]: inherit-namespaced.hpp
- if location.spelling().chars().all(|c| {
- c.is_alphanumeric() || c == '_'
- }) {
- return Err(ParseError::Recurse);
- }
- } else {
- name = location.spelling();
- }
-
- let complex = CompInfo::from_ty(
- potential_id,
- ty,
- Some(location),
- ctx,
- );
- match complex {
- Ok(complex) => TypeKind::Comp(complex),
- Err(_) => {
- warn!(
- "Could not create complex type \
- from class template or base \
- specifier, using opaque blob"
- );
- let opaque =
- Opaque::from_clang_ty(ty, ctx);
- return Ok(ParseResult::New(
- opaque, None,
- ));
- }
- }
- }
- CXCursor_TypeAliasTemplateDecl => {
- debug!("TypeAliasTemplateDecl");
-
- // We need to manually unwind this one.
- let mut inner = Err(ParseError::Continue);
- let mut args = vec![];
-
- location.visit(|cur| {
- match cur.kind() {
- CXCursor_TypeAliasDecl => {
- let current = cur.cur_type();
-
- debug_assert_eq!(
- current.kind(),
- CXType_Typedef
- );
-
- name = current.spelling();
-
- let inner_ty = cur
- .typedef_type()
- .expect("Not valid Type?");
- inner = Ok(Item::from_ty_or_ref(
- inner_ty,
- cur,
- Some(potential_id),
- ctx,
- ));
- }
- CXCursor_TemplateTypeParameter => {
- let param = Item::type_param(
- None, cur, ctx,
- )
- .expect(
- "Item::type_param shouldn't \
- ever fail if we are looking \
- at a TemplateTypeParameter",
- );
- args.push(param);
- }
- _ => {}
- }
- CXChildVisit_Continue
- });
-
- let inner_type = match inner {
- Ok(inner) => inner,
- Err(..) => {
- warn!(
- "Failed to parse template alias \
- {:?}",
- location
- );
- return Err(ParseError::Continue);
- }
- };
-
- TypeKind::TemplateAlias(inner_type, args)
- }
- CXCursor_TemplateRef => {
- let referenced = location.referenced().unwrap();
- let referenced_ty = referenced.cur_type();
-
- debug!(
- "TemplateRef: location = {:?}; referenced = \
- {:?}; referenced_ty = {:?}",
- location,
- referenced,
- referenced_ty
- );
-
- return Self::from_clang_ty(
- potential_id,
- &referenced_ty,
- referenced,
- parent_id,
- ctx,
- );
- }
- CXCursor_TypeRef => {
- let referenced = location.referenced().unwrap();
- let referenced_ty = referenced.cur_type();
- let declaration = referenced_ty.declaration();
-
- debug!(
- "TypeRef: location = {:?}; referenced = \
- {:?}; referenced_ty = {:?}",
- location, referenced, referenced_ty
- );
-
- let id = Item::from_ty_or_ref_with_id(
- potential_id,
- referenced_ty,
- declaration,
- parent_id,
- ctx,
- );
- return Ok(ParseResult::AlreadyResolved(
- id.into(),
- ));
- }
- CXCursor_NamespaceRef => {
- return Err(ParseError::Continue);
- }
- _ => {
- if ty.kind() == CXType_Unexposed {
- warn!(
- "Unexposed type {:?}, recursing inside, \
- loc: {:?}",
- ty,
- location
- );
- return Err(ParseError::Recurse);
- }
-
- warn!("invalid type {:?}", ty);
- return Err(ParseError::Continue);
- }
- }
- }
- }
- CXType_Auto => {
- if canonical_ty == *ty {
- debug!("Couldn't find deduced type: {:?}", ty);
- return Err(ParseError::Continue);
- }
-
- return Self::from_clang_ty(
- potential_id,
- &canonical_ty,
- location,
- parent_id,
- ctx,
- );
- }
- // NOTE: We don't resolve pointers eagerly because the pointee type
- // might not have been parsed, and if it contains templates or
- // something else we might get confused, see the comment inside
- // TypeRef.
- //
- // We might need to, though, if the context is already in the
- // process of resolving them.
- CXType_ObjCObjectPointer |
- CXType_MemberPointer |
- CXType_Pointer => {
- let mut pointee = ty.pointee_type().unwrap();
- if *ty != canonical_ty {
- let canonical_pointee =
- canonical_ty.pointee_type().unwrap();
- // clang sometimes loses pointee constness here, see
- // #2244.
- if canonical_pointee.is_const() != pointee.is_const() {
- pointee = canonical_pointee;
- }
- }
- let inner =
- Item::from_ty_or_ref(pointee, location, None, ctx);
- TypeKind::Pointer(inner)
- }
- CXType_BlockPointer => {
- let pointee = ty.pointee_type().expect("Not valid Type?");
- let inner =
- Item::from_ty_or_ref(pointee, location, None, ctx);
- TypeKind::BlockPointer(inner)
- }
- // XXX: RValueReference is most likely wrong, but I don't think we
- // can even add bindings for that, so huh.
- CXType_RValueReference | CXType_LValueReference => {
- let inner = Item::from_ty_or_ref(
- ty.pointee_type().unwrap(),
- location,
- None,
- ctx,
- );
- TypeKind::Reference(inner)
- }
- // XXX DependentSizedArray is wrong
- CXType_VariableArray | CXType_DependentSizedArray => {
- let inner = Item::from_ty(
- ty.elem_type().as_ref().unwrap(),
- location,
- None,
- ctx,
- )
- .expect("Not able to resolve array element?");
- TypeKind::Pointer(inner)
- }
- CXType_IncompleteArray => {
- let inner = Item::from_ty(
- ty.elem_type().as_ref().unwrap(),
- location,
- None,
- ctx,
- )
- .expect("Not able to resolve array element?");
- TypeKind::Array(inner, 0)
- }
- CXType_FunctionNoProto | CXType_FunctionProto => {
- let signature = FunctionSig::from_ty(ty, &location, ctx)?;
- TypeKind::Function(signature)
- }
- CXType_Typedef => {
- let inner = cursor.typedef_type().expect("Not valid Type?");
- let inner =
- Item::from_ty_or_ref(inner, location, None, ctx);
- if inner == potential_id {
- warn!(
- "Generating oqaque type instead of self-referential \
- typedef");
- // This can happen if we bail out of recursive situations
- // within the clang parsing.
- TypeKind::Opaque
- } else {
- TypeKind::Alias(inner)
- }
- }
- CXType_Enum => {
- let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
-
- if name.is_empty() {
- let pretty_name = ty.spelling();
- if clang::is_valid_identifier(&pretty_name) {
- name = pretty_name;
- }
- }
-
- TypeKind::Enum(enum_)
- }
- CXType_Record => {
- let complex = CompInfo::from_ty(
- potential_id,
- ty,
- Some(location),
- ctx,
- )
- .expect("Not a complex type?");
-
- if name.is_empty() {
- // The pretty-printed name may contain typedefed name,
- // but may also be "struct (anonymous at .h:1)"
- let pretty_name = ty.spelling();
- if clang::is_valid_identifier(&pretty_name) {
- name = pretty_name;
- }
- }
-
- TypeKind::Comp(complex)
- }
- CXType_Vector => {
- let inner = Item::from_ty(
- ty.elem_type().as_ref().unwrap(),
- location,
- None,
- ctx,
- )
- .expect("Not able to resolve vector element?");
- TypeKind::Vector(inner, ty.num_elements().unwrap())
- }
- CXType_ConstantArray => {
- let inner = Item::from_ty(
- ty.elem_type().as_ref().unwrap(),
- location,
- None,
- ctx,
- )
- .expect("Not able to resolve array element?");
- TypeKind::Array(inner, ty.num_elements().unwrap())
- }
- CXType_Elaborated => {
- return Self::from_clang_ty(
- potential_id,
- &ty.named(),
- location,
- parent_id,
- ctx,
- );
- }
- CXType_ObjCId => TypeKind::ObjCId,
- CXType_ObjCSel => TypeKind::ObjCSel,
- CXType_ObjCClass | CXType_ObjCInterface => {
- let interface = ObjCInterface::from_ty(&location, ctx)
- .expect("Not a valid objc interface?");
- name = interface.rust_name();
- TypeKind::ObjCInterface(interface)
- }
- CXType_Dependent => {
- return Err(ParseError::Continue);
- }
- _ => {
- warn!(
- "unsupported type: kind = {:?}; ty = {:?}; at {:?}",
- ty.kind(),
- ty,
- location
- );
- return Err(ParseError::Continue);
- }
- }
- };
-
- let name = if name.is_empty() { None } else { Some(name) };
-
- let is_const = ty.is_const() ||
- (ty.kind() == CXType_ConstantArray &&
- ty.elem_type()
- .map_or(false, |element| element.is_const()));
-
- let ty = Type::new(name, layout, kind, is_const);
- // TODO: maybe declaration.canonical()?
- Ok(ParseResult::New(ty, Some(cursor.canonical())))
- }
-}
-
-impl Trace for Type {
- type Extra = Item;
-
- fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
- where
- T: Tracer,
- {
- if self
- .name()
- .map_or(false, |name| context.is_stdint_type(name))
- {
- // These types are special-cased in codegen and don't need to be traversed.
- return;
- }
- match *self.kind() {
- TypeKind::Pointer(inner) |
- TypeKind::Reference(inner) |
- TypeKind::Array(inner, _) |
- TypeKind::Vector(inner, _) |
- TypeKind::BlockPointer(inner) |
- TypeKind::Alias(inner) |
- TypeKind::ResolvedTypeRef(inner) => {
- tracer.visit_kind(inner.into(), EdgeKind::TypeReference);
- }
- TypeKind::TemplateAlias(inner, ref template_params) => {
- tracer.visit_kind(inner.into(), EdgeKind::TypeReference);
- for param in template_params {
- tracer.visit_kind(
- param.into(),
- EdgeKind::TemplateParameterDefinition,
- );
- }
- }
- TypeKind::TemplateInstantiation(ref inst) => {
- inst.trace(context, tracer, &());
- }
- TypeKind::Comp(ref ci) => ci.trace(context, tracer, item),
- TypeKind::Function(ref sig) => sig.trace(context, tracer, &()),
- TypeKind::Enum(ref en) => {
- if let Some(repr) = en.repr() {
- tracer.visit(repr.into());
- }
- }
- TypeKind::UnresolvedTypeRef(_, _, Some(id)) => {
- tracer.visit(id);
- }
-
- TypeKind::ObjCInterface(ref interface) => {
- interface.trace(context, tracer, &());
- }
-
- // None of these variants have edges to other items and types.
- TypeKind::Opaque |
- TypeKind::UnresolvedTypeRef(_, _, None) |
- TypeKind::TypeParam |
- TypeKind::Void |
- TypeKind::NullPtr |
- TypeKind::Int(_) |
- TypeKind::Float(_) |
- TypeKind::Complex(_) |
- TypeKind::ObjCId |
- TypeKind::ObjCSel => {}
- }
- }
-}
diff --git a/src/ir/var.rs b/src/ir/var.rs
deleted file mode 100644
index eecca4df..00000000
--- a/src/ir/var.rs
+++ /dev/null
@@ -1,413 +0,0 @@
-//! Intermediate representation of variables.
-
-use super::super::codegen::MacroTypeVariation;
-use super::context::{BindgenContext, TypeId};
-use super::dot::DotAttributes;
-use super::function::cursor_mangling;
-use super::int::IntKind;
-use super::item::Item;
-use super::ty::{FloatKind, TypeKind};
-use crate::callbacks::MacroParsingBehavior;
-use crate::clang;
-use crate::clang::ClangToken;
-use crate::parse::{
- ClangItemParser, ClangSubItemParser, ParseError, ParseResult,
-};
-use cexpr;
-use std::io;
-use std::num::Wrapping;
-
-/// The type for a constant variable.
-#[derive(Debug)]
-pub enum VarType {
- /// A boolean.
- Bool(bool),
- /// An integer.
- Int(i64),
- /// A floating point number.
- Float(f64),
- /// A character.
- Char(u8),
- /// A string, not necessarily well-formed utf-8.
- String(Vec<u8>),
-}
-
-/// A `Var` is our intermediate representation of a variable.
-#[derive(Debug)]
-pub struct Var {
- /// The name of the variable.
- name: String,
- /// The mangled name of the variable.
- mangled_name: Option<String>,
- /// The type of the variable.
- ty: TypeId,
- /// The value of the variable, that needs to be suitable for `ty`.
- val: Option<VarType>,
- /// Whether this variable is const.
- is_const: bool,
-}
-
-impl Var {
- /// Construct a new `Var`.
- pub fn new(
- name: String,
- mangled_name: Option<String>,
- ty: TypeId,
- val: Option<VarType>,
- is_const: bool,
- ) -> Var {
- assert!(!name.is_empty());
- Var {
- name,
- mangled_name,
- ty,
- val,
- is_const,
- }
- }
-
- /// Is this variable `const` qualified?
- pub fn is_const(&self) -> bool {
- self.is_const
- }
-
- /// The value of this constant variable, if any.
- pub fn val(&self) -> Option<&VarType> {
- self.val.as_ref()
- }
-
- /// Get this variable's type.
- pub fn ty(&self) -> TypeId {
- self.ty
- }
-
- /// Get this variable's name.
- pub fn name(&self) -> &str {
- &self.name
- }
-
- /// Get this variable's mangled name.
- pub fn mangled_name(&self) -> Option<&str> {
- self.mangled_name.as_deref()
- }
-}
-
-impl DotAttributes for Var {
- fn dot_attributes<W>(
- &self,
- _ctx: &BindgenContext,
- out: &mut W,
- ) -> io::Result<()>
- where
- W: io::Write,
- {
- if self.is_const {
- writeln!(out, "<tr><td>const</td><td>true</td></tr>")?;
- }
-
- if let Some(ref mangled) = self.mangled_name {
- writeln!(
- out,
- "<tr><td>mangled name</td><td>{}</td></tr>",
- mangled
- )?;
- }
-
- Ok(())
- }
-}
-
-fn default_macro_constant_type(ctx: &BindgenContext, value: i64) -> IntKind {
- if value < 0 ||
- ctx.options().default_macro_constant_type ==
- MacroTypeVariation::Signed
- {
- if value < i32::min_value() as i64 || value > i32::max_value() as i64 {
- IntKind::I64
- } else if !ctx.options().fit_macro_constants ||
- value < i16::min_value() as i64 ||
- value > i16::max_value() as i64
- {
- IntKind::I32
- } else if value < i8::min_value() as i64 ||
- value > i8::max_value() as i64
- {
- IntKind::I16
- } else {
- IntKind::I8
- }
- } else if value > u32::max_value() as i64 {
- IntKind::U64
- } else if !ctx.options().fit_macro_constants ||
- value > u16::max_value() as i64
- {
- IntKind::U32
- } else if value > u8::max_value() as i64 {
- IntKind::U16
- } else {
- IntKind::U8
- }
-}
-
-/// Parses tokens from a CXCursor_MacroDefinition pointing into a function-like
-/// macro, and calls the func_macro callback.
-fn handle_function_macro(
- cursor: &clang::Cursor,
- callbacks: &dyn crate::callbacks::ParseCallbacks,
-) {
- let is_closing_paren = |t: &ClangToken| {
- // Test cheap token kind before comparing exact spellings.
- t.kind == clang_sys::CXToken_Punctuation && t.spelling() == b")"
- };
- let tokens: Vec<_> = cursor.tokens().iter().collect();
- if let Some(boundary) = tokens.iter().position(is_closing_paren) {
- let mut spelled = tokens.iter().map(ClangToken::spelling);
- // Add 1, to convert index to length.
- let left = spelled.by_ref().take(boundary + 1);
- let left = left.collect::<Vec<_>>().concat();
- if let Ok(left) = String::from_utf8(left) {
- let right: Vec<_> = spelled.collect();
- callbacks.func_macro(&left, &right);
- }
- }
-}
-
-impl ClangSubItemParser for Var {
- fn parse(
- cursor: clang::Cursor,
- ctx: &mut BindgenContext,
- ) -> Result<ParseResult<Self>, ParseError> {
- use cexpr::expr::EvalResult;
- use cexpr::literal::CChar;
- use clang_sys::*;
- match cursor.kind() {
- CXCursor_MacroDefinition => {
- if let Some(callbacks) = ctx.parse_callbacks() {
- match callbacks.will_parse_macro(&cursor.spelling()) {
- MacroParsingBehavior::Ignore => {
- return Err(ParseError::Continue);
- }
- MacroParsingBehavior::Default => {}
- }
-
- if cursor.is_macro_function_like() {
- handle_function_macro(&cursor, callbacks);
- // We handled the macro, skip macro processing below.
- return Err(ParseError::Continue);
- }
- }
-
- let value = parse_macro(ctx, &cursor);
-
- let (id, value) = match value {
- Some(v) => v,
- None => return Err(ParseError::Continue),
- };
-
- assert!(!id.is_empty(), "Empty macro name?");
-
- let previously_defined = ctx.parsed_macro(&id);
-
- // NB: It's important to "note" the macro even if the result is
- // not an integer, otherwise we might loose other kind of
- // derived macros.
- ctx.note_parsed_macro(id.clone(), value.clone());
-
- if previously_defined {
- let name = String::from_utf8(id).unwrap();
- warn!("Duplicated macro definition: {}", name);
- return Err(ParseError::Continue);
- }
-
- // NOTE: Unwrapping, here and above, is safe, because the
- // identifier of a token comes straight from clang, and we
- // enforce utf8 there, so we should have already panicked at
- // this point.
- let name = String::from_utf8(id).unwrap();
- let (type_kind, val) = match value {
- EvalResult::Invalid => return Err(ParseError::Continue),
- EvalResult::Float(f) => {
- (TypeKind::Float(FloatKind::Double), VarType::Float(f))
- }
- EvalResult::Char(c) => {
- let c = match c {
- CChar::Char(c) => {
- assert_eq!(c.len_utf8(), 1);
- c as u8
- }
- CChar::Raw(c) => {
- assert!(c <= ::std::u8::MAX as u64);
- c as u8
- }
- };
-
- (TypeKind::Int(IntKind::U8), VarType::Char(c))
- }
- EvalResult::Str(val) => {
- let char_ty = Item::builtin_type(
- TypeKind::Int(IntKind::U8),
- true,
- ctx,
- );
- if let Some(callbacks) = ctx.parse_callbacks() {
- callbacks.str_macro(&name, &val);
- }
- (TypeKind::Pointer(char_ty), VarType::String(val))
- }
- EvalResult::Int(Wrapping(value)) => {
- let kind = ctx
- .parse_callbacks()
- .and_then(|c| c.int_macro(&name, value))
- .unwrap_or_else(|| {
- default_macro_constant_type(ctx, value)
- });
-
- (TypeKind::Int(kind), VarType::Int(value))
- }
- };
-
- let ty = Item::builtin_type(type_kind, true, ctx);
-
- Ok(ParseResult::New(
- Var::new(name, None, ty, Some(val), true),
- Some(cursor),
- ))
- }
- CXCursor_VarDecl => {
- let name = cursor.spelling();
- if name.is_empty() {
- warn!("Empty constant name?");
- return Err(ParseError::Continue);
- }
-
- let ty = cursor.cur_type();
-
- // TODO(emilio): do we have to special-case constant arrays in
- // some other places?
- let is_const = ty.is_const() ||
- (ty.kind() == CXType_ConstantArray &&
- ty.elem_type()
- .map_or(false, |element| element.is_const()));
-
- let ty = match Item::from_ty(&ty, cursor, None, ctx) {
- Ok(ty) => ty,
- Err(e) => {
- assert_eq!(
- ty.kind(),
- CXType_Auto,
- "Couldn't resolve constant type, and it \
- wasn't an nondeductible auto type!"
- );
- return Err(e);
- }
- };
-
- // Note: Ty might not be totally resolved yet, see
- // tests/headers/inner_const.hpp
- //
- // That's fine because in that case we know it's not a literal.
- let canonical_ty = ctx
- .safe_resolve_type(ty)
- .and_then(|t| t.safe_canonical_type(ctx));
-
- let is_integer = canonical_ty.map_or(false, |t| t.is_integer());
- let is_float = canonical_ty.map_or(false, |t| t.is_float());
-
- // TODO: We could handle `char` more gracefully.
- // TODO: Strings, though the lookup is a bit more hard (we need
- // to look at the canonical type of the pointee too, and check
- // is char, u8, or i8 I guess).
- let value = if is_integer {
- let kind = match *canonical_ty.unwrap().kind() {
- TypeKind::Int(kind) => kind,
- _ => unreachable!(),
- };
-
- let mut val = cursor.evaluate().and_then(|v| v.as_int());
- if val.is_none() || !kind.signedness_matches(val.unwrap()) {
- val = get_integer_literal_from_cursor(&cursor);
- }
-
- val.map(|val| {
- if kind == IntKind::Bool {
- VarType::Bool(val != 0)
- } else {
- VarType::Int(val)
- }
- })
- } else if is_float {
- cursor
- .evaluate()
- .and_then(|v| v.as_double())
- .map(VarType::Float)
- } else {
- cursor
- .evaluate()
- .and_then(|v| v.as_literal_string())
- .map(VarType::String)
- };
-
- let mangling = cursor_mangling(ctx, &cursor);
- let var = Var::new(name, mangling, ty, value, is_const);
-
- Ok(ParseResult::New(var, Some(cursor)))
- }
- _ => {
- /* TODO */
- Err(ParseError::Continue)
- }
- }
- }
-}
-
-/// Try and parse a macro using all the macros parsed until now.
-fn parse_macro(
- ctx: &BindgenContext,
- cursor: &clang::Cursor,
-) -> Option<(Vec<u8>, cexpr::expr::EvalResult)> {
- use cexpr::expr;
-
- let cexpr_tokens = cursor.cexpr_tokens();
-
- let parser = expr::IdentifierParser::new(ctx.parsed_macros());
-
- match parser.macro_definition(&cexpr_tokens) {
- Ok((_, (id, val))) => Some((id.into(), val)),
- _ => None,
- }
-}
-
-fn parse_int_literal_tokens(cursor: &clang::Cursor) -> Option<i64> {
- use cexpr::expr;
- use cexpr::expr::EvalResult;
-
- let cexpr_tokens = cursor.cexpr_tokens();
-
- // TODO(emilio): We can try to parse other kinds of literals.
- match expr::expr(&cexpr_tokens) {
- Ok((_, EvalResult::Int(Wrapping(val)))) => Some(val),
- _ => None,
- }
-}
-
-fn get_integer_literal_from_cursor(cursor: &clang::Cursor) -> Option<i64> {
- use clang_sys::*;
- let mut value = None;
- cursor.visit(|c| {
- match c.kind() {
- CXCursor_IntegerLiteral | CXCursor_UnaryOperator => {
- value = parse_int_literal_tokens(&c);
- }
- CXCursor_UnexposedExpr => {
- value = get_integer_literal_from_cursor(&c);
- }
- _ => (),
- }
- if value.is_some() {
- CXChildVisit_Break
- } else {
- CXChildVisit_Continue
- }
- });
- value
-}
diff --git a/src/lib.rs b/src/lib.rs
deleted file mode 100644
index 6e6fa225..00000000
--- a/src/lib.rs
+++ /dev/null
@@ -1,2928 +0,0 @@
-//! Generate Rust bindings for C and C++ libraries.
-//!
-//! Provide a C/C++ header file, receive Rust FFI code to call into C/C++
-//! functions and use types defined in the header.
-//!
-//! See the [`Builder`](./struct.Builder.html) struct for usage.
-//!
-//! See the [Users Guide](https://rust-lang.github.io/rust-bindgen/) for
-//! additional documentation.
-#![deny(missing_docs)]
-#![deny(unused_extern_crates)]
-// To avoid rather annoying warnings when matching with CXCursor_xxx as a
-// constant.
-#![allow(non_upper_case_globals)]
-// `quote!` nests quite deeply.
-#![recursion_limit = "128"]
-
-#[macro_use]
-extern crate bitflags;
-#[macro_use]
-extern crate lazy_static;
-#[macro_use]
-extern crate quote;
-
-#[cfg(feature = "logging")]
-#[macro_use]
-extern crate log;
-
-#[cfg(not(feature = "logging"))]
-#[macro_use]
-mod log_stubs;
-
-#[macro_use]
-mod extra_assertions;
-
-// A macro to declare an internal module for which we *must* provide
-// documentation for. If we are building with the "testing_only_docs" feature,
-// then the module is declared public, and our `#![deny(missing_docs)]` pragma
-// applies to it. This feature is used in CI, so we won't let anything slip by
-// undocumented. Normal builds, however, will leave the module private, so that
-// we don't expose internals to library consumers.
-macro_rules! doc_mod {
- ($m:ident, $doc_mod_name:ident) => {
- #[cfg(feature = "testing_only_docs")]
- pub mod $doc_mod_name {
- //! Autogenerated documentation module.
- pub use super::$m::*;
- }
- };
-}
-
-mod clang;
-mod codegen;
-mod deps;
-mod features;
-mod ir;
-mod parse;
-mod regex_set;
-mod time;
-
-pub mod callbacks;
-
-doc_mod!(clang, clang_docs);
-doc_mod!(features, features_docs);
-doc_mod!(ir, ir_docs);
-doc_mod!(parse, parse_docs);
-doc_mod!(regex_set, regex_set_docs);
-
-pub use crate::codegen::{
- AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle,
-};
-use crate::features::RustFeatures;
-pub use crate::features::{
- RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS,
-};
-use crate::ir::context::{BindgenContext, ItemId};
-use crate::ir::item::Item;
-use crate::parse::{ClangItemParser, ParseError};
-use crate::regex_set::RegexSet;
-
-use std::borrow::Cow;
-use std::fs::{File, OpenOptions};
-use std::io::{self, Write};
-use std::path::{Path, PathBuf};
-use std::process::{Command, Stdio};
-use std::rc::Rc;
-use std::{env, iter};
-
-// Some convenient typedefs for a fast hash map and hash set.
-type HashMap<K, V> = ::rustc_hash::FxHashMap<K, V>;
-type HashSet<K> = ::rustc_hash::FxHashSet<K>;
-pub(crate) use std::collections::hash_map::Entry;
-
-/// Default prefix for the anon fields.
-pub const DEFAULT_ANON_FIELDS_PREFIX: &str = "__bindgen_anon_";
-
-fn file_is_cpp(name_file: &str) -> bool {
- name_file.ends_with(".hpp") ||
- name_file.ends_with(".hxx") ||
- name_file.ends_with(".hh") ||
- name_file.ends_with(".h++")
-}
-
-fn args_are_cpp(clang_args: &[String]) -> bool {
- for w in clang_args.windows(2) {
- if w[0] == "-xc++" || w[1] == "-xc++" {
- return true;
- }
- if w[0] == "-x" && w[1] == "c++" {
- return true;
- }
- if w[0] == "-include" && file_is_cpp(&w[1]) {
- return true;
- }
- }
- false
-}
-
-bitflags! {
- /// A type used to indicate which kind of items we have to generate.
- pub struct CodegenConfig: u32 {
- /// Whether to generate functions.
- const FUNCTIONS = 1 << 0;
- /// Whether to generate types.
- const TYPES = 1 << 1;
- /// Whether to generate constants.
- const VARS = 1 << 2;
- /// Whether to generate methods.
- const METHODS = 1 << 3;
- /// Whether to generate constructors
- const CONSTRUCTORS = 1 << 4;
- /// Whether to generate destructors.
- const DESTRUCTORS = 1 << 5;
- }
-}
-
-impl CodegenConfig {
- /// Returns true if functions should be generated.
- pub fn functions(self) -> bool {
- self.contains(CodegenConfig::FUNCTIONS)
- }
-
- /// Returns true if types should be generated.
- pub fn types(self) -> bool {
- self.contains(CodegenConfig::TYPES)
- }
-
- /// Returns true if constants should be generated.
- pub fn vars(self) -> bool {
- self.contains(CodegenConfig::VARS)
- }
-
- /// Returns true if methds should be generated.
- pub fn methods(self) -> bool {
- self.contains(CodegenConfig::METHODS)
- }
-
- /// Returns true if constructors should be generated.
- pub fn constructors(self) -> bool {
- self.contains(CodegenConfig::CONSTRUCTORS)
- }
-
- /// Returns true if destructors should be generated.
- pub fn destructors(self) -> bool {
- self.contains(CodegenConfig::DESTRUCTORS)
- }
-}
-
-impl Default for CodegenConfig {
- fn default() -> Self {
- CodegenConfig::all()
- }
-}
-
-/// Configure and generate Rust bindings for a C/C++ header.
-///
-/// This is the main entry point to the library.
-///
-/// ```ignore
-/// use bindgen::builder;
-///
-/// // Configure and generate bindings.
-/// let bindings = builder().header("path/to/input/header")
-/// .allowlist_type("SomeCoolClass")
-/// .allowlist_function("do_some_cool_thing")
-/// .generate()?;
-///
-/// // Write the generated bindings to an output file.
-/// bindings.write_to_file("path/to/output.rs")?;
-/// ```
-///
-/// # Enums
-///
-/// Bindgen can map C/C++ enums into Rust in different ways. The way bindgen maps enums depends on
-/// the pattern passed to several methods:
-///
-/// 1. [`constified_enum_module()`](#method.constified_enum_module)
-/// 2. [`bitfield_enum()`](#method.bitfield_enum)
-/// 3. [`newtype_enum()`](#method.newtype_enum)
-/// 4. [`rustified_enum()`](#method.rustified_enum)
-///
-/// For each C enum, bindgen tries to match the pattern in the following order:
-///
-/// 1. Constified enum module
-/// 2. Bitfield enum
-/// 3. Newtype enum
-/// 4. Rustified enum
-///
-/// If none of the above patterns match, then bindgen will generate a set of Rust constants.
-///
-/// # Clang arguments
-///
-/// Extra arguments can be passed to with clang:
-/// 1. [`clang_arg()`](#method.clang_arg): takes a single argument
-/// 2. [`clang_args()`](#method.clang_args): takes an iterator of arguments
-/// 3. `BINDGEN_EXTRA_CLANG_ARGS` environment variable: whitespace separate
-/// environment variable of arguments
-///
-/// Clang arguments specific to your crate should be added via the
-/// `clang_arg()`/`clang_args()` methods.
-///
-/// End-users of the crate may need to set the `BINDGEN_EXTRA_CLANG_ARGS` environment variable to
-/// add additional arguments. For example, to build against a different sysroot a user could set
-/// `BINDGEN_EXTRA_CLANG_ARGS` to `--sysroot=/path/to/sysroot`.
-#[derive(Debug, Default)]
-pub struct Builder {
- options: BindgenOptions,
- input_headers: Vec<String>,
- // Tuples of unsaved file contents of the form (name, contents).
- input_header_contents: Vec<(String, String)>,
-}
-
-/// Construct a new [`Builder`](./struct.Builder.html).
-pub fn builder() -> Builder {
- Default::default()
-}
-
-fn get_extra_clang_args() -> Vec<String> {
- // Add any extra arguments from the environment to the clang command line.
- let extra_clang_args =
- match get_target_dependent_env_var("BINDGEN_EXTRA_CLANG_ARGS") {
- None => return vec![],
- Some(s) => s,
- };
- // Try to parse it with shell quoting. If we fail, make it one single big argument.
- if let Some(strings) = shlex::split(&extra_clang_args) {
- return strings;
- }
- vec![extra_clang_args]
-}
-
-impl Builder {
- /// Generates the command line flags use for creating `Builder`.
- pub fn command_line_flags(&self) -> Vec<String> {
- let mut output_vector: Vec<String> = Vec::new();
-
- if let Some(header) = self.input_headers.last().cloned() {
- // Positional argument 'header'
- output_vector.push(header);
- }
-
- output_vector.push("--rust-target".into());
- output_vector.push(self.options.rust_target.into());
-
- // FIXME(emilio): This is a bit hacky, maybe we should stop re-using the
- // RustFeatures to store the "disable_untagged_union" call, and make it
- // a different flag that we check elsewhere / in generate().
- if !self.options.rust_features.untagged_union &&
- RustFeatures::from(self.options.rust_target).untagged_union
- {
- output_vector.push("--disable-untagged-union".into());
- }
-
- if self.options.default_enum_style != Default::default() {
- output_vector.push("--default-enum-style".into());
- output_vector.push(
- match self.options.default_enum_style {
- codegen::EnumVariation::Rust {
- non_exhaustive: false,
- } => "rust",
- codegen::EnumVariation::Rust {
- non_exhaustive: true,
- } => "rust_non_exhaustive",
- codegen::EnumVariation::NewType {
- is_bitfield: true,
- ..
- } => "bitfield",
- codegen::EnumVariation::NewType {
- is_bitfield: false,
- is_global,
- } => {
- if is_global {
- "newtype_global"
- } else {
- "newtype"
- }
- }
- codegen::EnumVariation::Consts => "consts",
- codegen::EnumVariation::ModuleConsts => "moduleconsts",
- }
- .into(),
- )
- }
-
- if self.options.default_macro_constant_type != Default::default() {
- output_vector.push("--default-macro-constant-type".into());
- output_vector
- .push(self.options.default_macro_constant_type.as_str().into());
- }
-
- if self.options.default_alias_style != Default::default() {
- output_vector.push("--default-alias-style".into());
- output_vector
- .push(self.options.default_alias_style.as_str().into());
- }
-
- if self.options.default_non_copy_union_style != Default::default() {
- output_vector.push("--default-non-copy-union-style".into());
- output_vector.push(
- self.options.default_non_copy_union_style.as_str().into(),
- );
- }
-
- let regex_sets = &[
- (&self.options.bitfield_enums, "--bitfield-enum"),
- (&self.options.newtype_enums, "--newtype-enum"),
- (&self.options.newtype_global_enums, "--newtype-global-enum"),
- (&self.options.rustified_enums, "--rustified-enum"),
- (
- &self.options.rustified_non_exhaustive_enums,
- "--rustified-enum-non-exhaustive",
- ),
- (
- &self.options.constified_enum_modules,
- "--constified-enum-module",
- ),
- (&self.options.constified_enums, "--constified-enum"),
- (&self.options.type_alias, "--type-alias"),
- (&self.options.new_type_alias, "--new-type-alias"),
- (&self.options.new_type_alias_deref, "--new-type-alias-deref"),
- (
- &self.options.bindgen_wrapper_union,
- "--bindgen-wrapper-union",
- ),
- (&self.options.manually_drop_union, "--manually-drop-union"),
- (&self.options.blocklisted_types, "--blocklist-type"),
- (&self.options.blocklisted_functions, "--blocklist-function"),
- (&self.options.blocklisted_items, "--blocklist-item"),
- (&self.options.blocklisted_files, "--blocklist-file"),
- (&self.options.opaque_types, "--opaque-type"),
- (&self.options.allowlisted_functions, "--allowlist-function"),
- (&self.options.allowlisted_types, "--allowlist-type"),
- (&self.options.allowlisted_vars, "--allowlist-var"),
- (&self.options.allowlisted_files, "--allowlist-file"),
- (&self.options.no_partialeq_types, "--no-partialeq"),
- (&self.options.no_copy_types, "--no-copy"),
- (&self.options.no_debug_types, "--no-debug"),
- (&self.options.no_default_types, "--no-default"),
- (&self.options.no_hash_types, "--no-hash"),
- (&self.options.must_use_types, "--must-use-type"),
- ];
-
- for (set, flag) in regex_sets {
- for item in set.get_items() {
- output_vector.push((*flag).to_owned());
- output_vector.push(item.to_owned());
- }
- }
-
- if !self.options.layout_tests {
- output_vector.push("--no-layout-tests".into());
- }
-
- if self.options.impl_debug {
- output_vector.push("--impl-debug".into());
- }
-
- if self.options.impl_partialeq {
- output_vector.push("--impl-partialeq".into());
- }
-
- if !self.options.derive_copy {
- output_vector.push("--no-derive-copy".into());
- }
-
- if !self.options.derive_debug {
- output_vector.push("--no-derive-debug".into());
- }
-
- if !self.options.derive_default {
- output_vector.push("--no-derive-default".into());
- } else {
- output_vector.push("--with-derive-default".into());
- }
-
- if self.options.derive_hash {
- output_vector.push("--with-derive-hash".into());
- }
-
- if self.options.derive_partialord {
- output_vector.push("--with-derive-partialord".into());
- }
-
- if self.options.derive_ord {
- output_vector.push("--with-derive-ord".into());
- }
-
- if self.options.derive_partialeq {
- output_vector.push("--with-derive-partialeq".into());
- }
-
- if self.options.derive_eq {
- output_vector.push("--with-derive-eq".into());
- }
-
- if self.options.time_phases {
- output_vector.push("--time-phases".into());
- }
-
- if !self.options.generate_comments {
- output_vector.push("--no-doc-comments".into());
- }
-
- if !self.options.allowlist_recursively {
- output_vector.push("--no-recursive-allowlist".into());
- }
-
- if self.options.objc_extern_crate {
- output_vector.push("--objc-extern-crate".into());
- }
-
- if self.options.generate_block {
- output_vector.push("--generate-block".into());
- }
-
- if self.options.block_extern_crate {
- output_vector.push("--block-extern-crate".into());
- }
-
- if self.options.builtins {
- output_vector.push("--builtins".into());
- }
-
- if let Some(ref prefix) = self.options.ctypes_prefix {
- output_vector.push("--ctypes-prefix".into());
- output_vector.push(prefix.clone());
- }
-
- if self.options.anon_fields_prefix != DEFAULT_ANON_FIELDS_PREFIX {
- output_vector.push("--anon-fields-prefix".into());
- output_vector.push(self.options.anon_fields_prefix.clone());
- }
-
- if self.options.emit_ast {
- output_vector.push("--emit-clang-ast".into());
- }
-
- if self.options.emit_ir {
- output_vector.push("--emit-ir".into());
- }
- if let Some(ref graph) = self.options.emit_ir_graphviz {
- output_vector.push("--emit-ir-graphviz".into());
- output_vector.push(graph.clone())
- }
- if self.options.enable_cxx_namespaces {
- output_vector.push("--enable-cxx-namespaces".into());
- }
- if self.options.enable_function_attribute_detection {
- output_vector.push("--enable-function-attribute-detection".into());
- }
- if self.options.disable_name_namespacing {
- output_vector.push("--disable-name-namespacing".into());
- }
- if self.options.disable_nested_struct_naming {
- output_vector.push("--disable-nested-struct-naming".into());
- }
-
- if self.options.disable_header_comment {
- output_vector.push("--disable-header-comment".into());
- }
-
- if !self.options.codegen_config.functions() {
- output_vector.push("--ignore-functions".into());
- }
-
- output_vector.push("--generate".into());
-
- //Temporary placeholder for below 4 options
- let mut options: Vec<String> = Vec::new();
- if self.options.codegen_config.functions() {
- options.push("functions".into());
- }
- if self.options.codegen_config.types() {
- options.push("types".into());
- }
- if self.options.codegen_config.vars() {
- options.push("vars".into());
- }
- if self.options.codegen_config.methods() {
- options.push("methods".into());
- }
- if self.options.codegen_config.constructors() {
- options.push("constructors".into());
- }
- if self.options.codegen_config.destructors() {
- options.push("destructors".into());
- }
-
- output_vector.push(options.join(","));
-
- if !self.options.codegen_config.methods() {
- output_vector.push("--ignore-methods".into());
- }
-
- if !self.options.convert_floats {
- output_vector.push("--no-convert-floats".into());
- }
-
- if !self.options.prepend_enum_name {
- output_vector.push("--no-prepend-enum-name".into());
- }
-
- if self.options.fit_macro_constants {
- output_vector.push("--fit-macro-constant-types".into());
- }
-
- if self.options.array_pointers_in_arguments {
- output_vector.push("--use-array-pointers-in-arguments".into());
- }
-
- if let Some(ref wasm_import_module_name) =
- self.options.wasm_import_module_name
- {
- output_vector.push("--wasm-import-module-name".into());
- output_vector.push(wasm_import_module_name.clone());
- }
-
- for line in &self.options.raw_lines {
- output_vector.push("--raw-line".into());
- output_vector.push(line.clone());
- }
-
- for (module, lines) in &self.options.module_lines {
- for line in lines.iter() {
- output_vector.push("--module-raw-line".into());
- output_vector.push(module.clone());
- output_vector.push(line.clone());
- }
- }
-
- if self.options.use_core {
- output_vector.push("--use-core".into());
- }
-
- if self.options.conservative_inline_namespaces {
- output_vector.push("--conservative-inline-namespaces".into());
- }
-
- if self.options.generate_inline_functions {
- output_vector.push("--generate-inline-functions".into());
- }
-
- if !self.options.record_matches {
- output_vector.push("--no-record-matches".into());
- }
-
- if !self.options.size_t_is_usize {
- output_vector.push("--no-size_t-is-usize".into());
- }
-
- if !self.options.rustfmt_bindings {
- output_vector.push("--no-rustfmt-bindings".into());
- }
-
- if let Some(path) = self
- .options
- .rustfmt_configuration_file
- .as_ref()
- .and_then(|f| f.to_str())
- {
- output_vector.push("--rustfmt-configuration-file".into());
- output_vector.push(path.into());
- }
-
- if let Some(ref name) = self.options.dynamic_library_name {
- output_vector.push("--dynamic-loading".into());
- output_vector.push(name.clone());
- }
-
- if self.options.dynamic_link_require_all {
- output_vector.push("--dynamic-link-require-all".into());
- }
-
- if self.options.respect_cxx_access_specs {
- output_vector.push("--respect-cxx-access-specs".into());
- }
-
- if self.options.translate_enum_integer_types {
- output_vector.push("--translate-enum-integer-types".into());
- }
-
- if self.options.c_naming {
- output_vector.push("--c-naming".into());
- }
-
- if self.options.force_explicit_padding {
- output_vector.push("--explicit-padding".into());
- }
-
- if self.options.vtable_generation {
- output_vector.push("--vtable-generation".into());
- }
-
- if self.options.sort_semantically {
- output_vector.push("--sort-semantically".into());
- }
-
- if self.options.merge_extern_blocks {
- output_vector.push("--merge-extern-blocks".into());
- }
-
- // Add clang arguments
-
- output_vector.push("--".into());
-
- if !self.options.clang_args.is_empty() {
- output_vector.extend(self.options.clang_args.iter().cloned());
- }
-
- if self.input_headers.len() > 1 {
- // To pass more than one header, we need to pass all but the last
- // header via the `-include` clang arg
- for header in &self.input_headers[..self.input_headers.len() - 1] {
- output_vector.push("-include".to_string());
- output_vector.push(header.clone());
- }
- }
-
- output_vector
- }
-
- /// Add an input C/C++ header to generate bindings for.
- ///
- /// This can be used to generate bindings to a single header:
- ///
- /// ```ignore
- /// let bindings = bindgen::Builder::default()
- /// .header("input.h")
- /// .generate()
- /// .unwrap();
- /// ```
- ///
- /// Or you can invoke it multiple times to generate bindings to multiple
- /// headers:
- ///
- /// ```ignore
- /// let bindings = bindgen::Builder::default()
- /// .header("first.h")
- /// .header("second.h")
- /// .header("third.h")
- /// .generate()
- /// .unwrap();
- /// ```
- pub fn header<T: Into<String>>(mut self, header: T) -> Builder {
- self.input_headers.push(header.into());
- self
- }
-
- /// Add a depfile output which will be written alongside the generated bindings.
- pub fn depfile<H: Into<String>, D: Into<PathBuf>>(
- mut self,
- output_module: H,
- depfile: D,
- ) -> Builder {
- self.options.depfile = Some(deps::DepfileSpec {
- output_module: output_module.into(),
- depfile_path: depfile.into(),
- });
- self
- }
-
- /// Add `contents` as an input C/C++ header named `name`.
- ///
- /// The file `name` will be added to the clang arguments.
- pub fn header_contents(mut self, name: &str, contents: &str) -> Builder {
- // Apparently clang relies on having virtual FS correspondent to
- // the real one, so we need absolute paths here
- let absolute_path = env::current_dir()
- .expect("Cannot retrieve current directory")
- .join(name)
- .to_str()
- .expect("Cannot convert current directory name to string")
- .to_owned();
- self.input_header_contents
- .push((absolute_path, contents.into()));
- self
- }
-
- /// Specify the rust target
- ///
- /// The default is the latest stable Rust version
- pub fn rust_target(mut self, rust_target: RustTarget) -> Self {
- self.options.set_rust_target(rust_target);
- self
- }
-
- /// Disable support for native Rust unions, if supported.
- pub fn disable_untagged_union(mut self) -> Self {
- self.options.rust_features.untagged_union = false;
- self
- }
-
- /// Disable insertion of bindgen's version identifier into generated
- /// bindings.
- pub fn disable_header_comment(mut self) -> Self {
- self.options.disable_header_comment = true;
- self
- }
-
- /// Set the output graphviz file.
- pub fn emit_ir_graphviz<T: Into<String>>(mut self, path: T) -> Builder {
- let path = path.into();
- self.options.emit_ir_graphviz = Some(path);
- self
- }
-
- /// Whether the generated bindings should contain documentation comments
- /// (docstrings) or not. This is set to true by default.
- ///
- /// Note that clang by default excludes comments from system headers, pass
- /// `-fretain-comments-from-system-headers` as
- /// [`clang_arg`][Builder::clang_arg] to include them. It can also be told
- /// to process all comments (not just documentation ones) using the
- /// `-fparse-all-comments` flag. See [slides on clang comment parsing](
- /// https://llvm.org/devmtg/2012-11/Gribenko_CommentParsing.pdf) for
- /// background and examples.
- pub fn generate_comments(mut self, doit: bool) -> Self {
- self.options.generate_comments = doit;
- self
- }
-
- /// Whether to allowlist recursively or not. Defaults to true.
- ///
- /// Given that we have explicitly allowlisted the "initiate_dance_party"
- /// function in this C header:
- ///
- /// ```c
- /// typedef struct MoonBoots {
- /// int bouncy_level;
- /// } MoonBoots;
- ///
- /// void initiate_dance_party(MoonBoots* boots);
- /// ```
- ///
- /// We would normally generate bindings to both the `initiate_dance_party`
- /// function and the `MoonBoots` struct that it transitively references. By
- /// configuring with `allowlist_recursively(false)`, `bindgen` will not emit
- /// bindings for anything except the explicitly allowlisted items, and there
- /// would be no emitted struct definition for `MoonBoots`. However, the
- /// `initiate_dance_party` function would still reference `MoonBoots`!
- ///
- /// **Disabling this feature will almost certainly cause `bindgen` to emit
- /// bindings that will not compile!** If you disable this feature, then it
- /// is *your* responsibility to provide definitions for every type that is
- /// referenced from an explicitly allowlisted item. One way to provide the
- /// definitions is by using the [`Builder::raw_line`](#method.raw_line)
- /// method, another would be to define them in Rust and then `include!(...)`
- /// the bindings immediately afterwards.
- pub fn allowlist_recursively(mut self, doit: bool) -> Self {
- self.options.allowlist_recursively = doit;
- self
- }
-
- /// Deprecated alias for allowlist_recursively.
- #[deprecated(note = "Use allowlist_recursively instead")]
- pub fn whitelist_recursively(self, doit: bool) -> Self {
- self.allowlist_recursively(doit)
- }
-
- /// Generate `#[macro_use] extern crate objc;` instead of `use objc;`
- /// in the prologue of the files generated from objective-c files
- pub fn objc_extern_crate(mut self, doit: bool) -> Self {
- self.options.objc_extern_crate = doit;
- self
- }
-
- /// Generate proper block signatures instead of void pointers.
- pub fn generate_block(mut self, doit: bool) -> Self {
- self.options.generate_block = doit;
- self
- }
-
- /// Generate `#[macro_use] extern crate block;` instead of `use block;`
- /// in the prologue of the files generated from apple block files
- pub fn block_extern_crate(mut self, doit: bool) -> Self {
- self.options.block_extern_crate = doit;
- self
- }
-
- /// Whether to use the clang-provided name mangling. This is true by default
- /// and probably needed for C++ features.
- ///
- /// However, some old libclang versions seem to return incorrect results in
- /// some cases for non-mangled functions, see [1], so we allow disabling it.
- ///
- /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528
- pub fn trust_clang_mangling(mut self, doit: bool) -> Self {
- self.options.enable_mangling = doit;
- self
- }
-
- /// Hide the given type from the generated bindings. Regular expressions are
- /// supported.
- #[deprecated(note = "Use blocklist_type instead")]
- pub fn hide_type<T: AsRef<str>>(self, arg: T) -> Builder {
- self.blocklist_type(arg)
- }
-
- /// Hide the given type from the generated bindings. Regular expressions are
- /// supported.
- #[deprecated(note = "Use blocklist_type instead")]
- pub fn blacklist_type<T: AsRef<str>>(self, arg: T) -> Builder {
- self.blocklist_type(arg)
- }
-
- /// Hide the given type from the generated bindings. Regular expressions are
- /// supported.
- ///
- /// To blocklist types prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn blocklist_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.blocklisted_types.insert(arg);
- self
- }
-
- /// Hide the given function from the generated bindings. Regular expressions
- /// are supported.
- #[deprecated(note = "Use blocklist_function instead")]
- pub fn blacklist_function<T: AsRef<str>>(self, arg: T) -> Builder {
- self.blocklist_function(arg)
- }
-
- /// Hide the given function from the generated bindings. Regular expressions
- /// are supported.
- ///
- /// To blocklist functions prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn blocklist_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.blocklisted_functions.insert(arg);
- self
- }
-
- /// Hide the given item from the generated bindings, regardless of
- /// whether it's a type, function, module, etc. Regular
- /// expressions are supported.
- #[deprecated(note = "Use blocklist_item instead")]
- pub fn blacklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.blocklisted_items.insert(arg);
- self
- }
-
- /// Hide the given item from the generated bindings, regardless of
- /// whether it's a type, function, module, etc. Regular
- /// expressions are supported.
- ///
- /// To blocklist items prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn blocklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.blocklisted_items.insert(arg);
- self
- }
-
- /// Hide any contents of the given file from the generated bindings,
- /// regardless of whether it's a type, function, module etc.
- pub fn blocklist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.blocklisted_files.insert(arg);
- self
- }
-
- /// Treat the given type as opaque in the generated bindings. Regular
- /// expressions are supported.
- ///
- /// To change types prefixed with "mylib" into opaque, use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.opaque_types.insert(arg);
- self
- }
-
- /// Allowlist the given type so that it (and all types that it transitively
- /// refers to) appears in the generated bindings. Regular expressions are
- /// supported.
- #[deprecated(note = "use allowlist_type instead")]
- pub fn whitelisted_type<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_type(arg)
- }
-
- /// Allowlist the given type so that it (and all types that it transitively
- /// refers to) appears in the generated bindings. Regular expressions are
- /// supported.
- #[deprecated(note = "use allowlist_type instead")]
- pub fn whitelist_type<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_type(arg)
- }
-
- /// Allowlist the given type so that it (and all types that it transitively
- /// refers to) appears in the generated bindings. Regular expressions are
- /// supported.
- ///
- /// To allowlist types prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn allowlist_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.allowlisted_types.insert(arg);
- self
- }
-
- /// Allowlist the given function so that it (and all types that it
- /// transitively refers to) appears in the generated bindings. Regular
- /// expressions are supported.
- ///
- /// To allowlist functions prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn allowlist_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.allowlisted_functions.insert(arg);
- self
- }
-
- /// Allowlist the given function.
- ///
- /// Deprecated: use allowlist_function instead.
- #[deprecated(note = "use allowlist_function instead")]
- pub fn whitelist_function<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_function(arg)
- }
-
- /// Allowlist the given function.
- ///
- /// Deprecated: use allowlist_function instead.
- #[deprecated(note = "use allowlist_function instead")]
- pub fn whitelisted_function<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_function(arg)
- }
-
- /// Allowlist the given variable so that it (and all types that it
- /// transitively refers to) appears in the generated bindings. Regular
- /// expressions are supported.
- ///
- /// To allowlist variables prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn allowlist_var<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.allowlisted_vars.insert(arg);
- self
- }
-
- /// Allowlist the given file so that its contents appear in the generated bindings.
- pub fn allowlist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.allowlisted_files.insert(arg);
- self
- }
-
- /// Deprecated: use allowlist_var instead.
- #[deprecated(note = "use allowlist_var instead")]
- pub fn whitelist_var<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_var(arg)
- }
-
- /// Allowlist the given variable.
- ///
- /// Deprecated: use allowlist_var instead.
- #[deprecated(note = "use allowlist_var instead")]
- pub fn whitelisted_var<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_var(arg)
- }
-
- /// Set the default style of code to generate for enums
- pub fn default_enum_style(
- mut self,
- arg: codegen::EnumVariation,
- ) -> Builder {
- self.options.default_enum_style = arg;
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as being
- /// bitfield-like. Regular expressions are supported.
- ///
- /// This makes bindgen generate a type that isn't a rust `enum`. Regular
- /// expressions are supported.
- ///
- /// This is similar to the newtype enum style, but with the bitwise
- /// operators implemented.
- pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.bitfield_enums.insert(arg);
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as a newtype.
- /// Regular expressions are supported.
- ///
- /// This makes bindgen generate a type that isn't a Rust `enum`. Regular
- /// expressions are supported.
- pub fn newtype_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.newtype_enums.insert(arg);
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as a newtype
- /// whose variants are exposed as global constants.
- ///
- /// Regular expressions are supported.
- ///
- /// This makes bindgen generate a type that isn't a Rust `enum`. Regular
- /// expressions are supported.
- pub fn newtype_global_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.newtype_global_enums.insert(arg);
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as a Rust
- /// enum.
- ///
- /// This makes bindgen generate enums instead of constants. Regular
- /// expressions are supported.
- ///
- /// **Use this with caution**, creating this in unsafe code
- /// (including FFI) with an invalid value will invoke undefined behaviour.
- /// You may want to use the newtype enum style instead.
- pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.rustified_enums.insert(arg);
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as a Rust
- /// enum with the `#[non_exhaustive]` attribute.
- ///
- /// This makes bindgen generate enums instead of constants. Regular
- /// expressions are supported.
- ///
- /// **Use this with caution**, creating this in unsafe code
- /// (including FFI) with an invalid value will invoke undefined behaviour.
- /// You may want to use the newtype enum style instead.
- pub fn rustified_non_exhaustive_enum<T: AsRef<str>>(
- mut self,
- arg: T,
- ) -> Builder {
- self.options.rustified_non_exhaustive_enums.insert(arg);
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as a set of
- /// constants that are not to be put into a module.
- pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.constified_enums.insert(arg);
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as a set of
- /// constants that should be put into a module.
- ///
- /// This makes bindgen generate modules containing constants instead of
- /// just constants. Regular expressions are supported.
- pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.constified_enum_modules.insert(arg);
- self
- }
-
- /// Set the default type for macro constants
- pub fn default_macro_constant_type(
- mut self,
- arg: codegen::MacroTypeVariation,
- ) -> Builder {
- self.options.default_macro_constant_type = arg;
- self
- }
-
- /// Set the default style of code to generate for typedefs
- pub fn default_alias_style(
- mut self,
- arg: codegen::AliasVariation,
- ) -> Builder {
- self.options.default_alias_style = arg;
- self
- }
-
- /// Mark the given typedef alias (or set of aliases, if using a pattern) to
- /// use regular Rust type aliasing.
- ///
- /// This is the default behavior and should be used if `default_alias_style`
- /// was set to NewType or NewTypeDeref and you want to override it for a
- /// set of typedefs.
- pub fn type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.type_alias.insert(arg);
- self
- }
-
- /// Mark the given typedef alias (or set of aliases, if using a pattern) to
- /// be generated as a new type by having the aliased type be wrapped in a
- /// #[repr(transparent)] struct.
- ///
- /// Used to enforce stricter type checking.
- pub fn new_type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.new_type_alias.insert(arg);
- self
- }
-
- /// Mark the given typedef alias (or set of aliases, if using a pattern) to
- /// be generated as a new type by having the aliased type be wrapped in a
- /// #[repr(transparent)] struct and also have an automatically generated
- /// impl's of `Deref` and `DerefMut` to their aliased type.
- pub fn new_type_alias_deref<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.new_type_alias_deref.insert(arg);
- self
- }
-
- /// Set the default style of code to generate for unions with a non-Copy member.
- pub fn default_non_copy_union_style(
- mut self,
- arg: codegen::NonCopyUnionStyle,
- ) -> Self {
- self.options.default_non_copy_union_style = arg;
- self
- }
-
- /// Mark the given union (or set of union, if using a pattern) to use
- /// a bindgen-generated wrapper for its members if at least one is non-Copy.
- pub fn bindgen_wrapper_union<T: AsRef<str>>(mut self, arg: T) -> Self {
- self.options.bindgen_wrapper_union.insert(arg);
- self
- }
-
- /// Mark the given union (or set of union, if using a pattern) to use
- /// [`::core::mem::ManuallyDrop`] for its members if at least one is non-Copy.
- ///
- /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your
- /// MSRV is lower.
- pub fn manually_drop_union<T: AsRef<str>>(mut self, arg: T) -> Self {
- self.options.manually_drop_union.insert(arg);
- self
- }
-
- /// Add a string to prepend to the generated bindings. The string is passed
- /// through without any modification.
- pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self {
- self.options.raw_lines.push(arg.into());
- self
- }
-
- /// Add a given line to the beginning of module `mod`.
- pub fn module_raw_line<T, U>(mut self, mod_: T, line: U) -> Self
- where
- T: Into<String>,
- U: Into<String>,
- {
- self.options
- .module_lines
- .entry(mod_.into())
- .or_insert_with(Vec::new)
- .push(line.into());
- self
- }
-
- /// Add a given set of lines to the beginning of module `mod`.
- pub fn module_raw_lines<T, I>(mut self, mod_: T, lines: I) -> Self
- where
- T: Into<String>,
- I: IntoIterator,
- I::Item: Into<String>,
- {
- self.options
- .module_lines
- .entry(mod_.into())
- .or_insert_with(Vec::new)
- .extend(lines.into_iter().map(Into::into));
- self
- }
-
- /// Add an argument to be passed straight through to clang.
- pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder {
- self.options.clang_args.push(arg.into());
- self
- }
-
- /// Add arguments to be passed straight through to clang.
- pub fn clang_args<I>(mut self, iter: I) -> Builder
- where
- I: IntoIterator,
- I::Item: AsRef<str>,
- {
- for arg in iter {
- self = self.clang_arg(arg.as_ref())
- }
- self
- }
-
- /// Emit bindings for builtin definitions (for example `__builtin_va_list`)
- /// in the generated Rust.
- pub fn emit_builtins(mut self) -> Builder {
- self.options.builtins = true;
- self
- }
-
- /// Avoid converting floats to `f32`/`f64` by default.
- pub fn no_convert_floats(mut self) -> Self {
- self.options.convert_floats = false;
- self
- }
-
- /// Set whether layout tests should be generated.
- pub fn layout_tests(mut self, doit: bool) -> Self {
- self.options.layout_tests = doit;
- self
- }
-
- /// Set whether `Debug` should be implemented, if it can not be derived automatically.
- pub fn impl_debug(mut self, doit: bool) -> Self {
- self.options.impl_debug = doit;
- self
- }
-
- /// Set whether `PartialEq` should be implemented, if it can not be derived automatically.
- pub fn impl_partialeq(mut self, doit: bool) -> Self {
- self.options.impl_partialeq = doit;
- self
- }
-
- /// Set whether `Copy` should be derived by default.
- pub fn derive_copy(mut self, doit: bool) -> Self {
- self.options.derive_copy = doit;
- self
- }
-
- /// Set whether `Debug` should be derived by default.
- pub fn derive_debug(mut self, doit: bool) -> Self {
- self.options.derive_debug = doit;
- self
- }
-
- /// Set whether `Default` should be derived by default.
- pub fn derive_default(mut self, doit: bool) -> Self {
- self.options.derive_default = doit;
- self
- }
-
- /// Set whether `Hash` should be derived by default.
- pub fn derive_hash(mut self, doit: bool) -> Self {
- self.options.derive_hash = doit;
- self
- }
-
- /// Set whether `PartialOrd` should be derived by default.
- /// If we don't compute partialord, we also cannot compute
- /// ord. Set the derive_ord to `false` when doit is `false`.
- pub fn derive_partialord(mut self, doit: bool) -> Self {
- self.options.derive_partialord = doit;
- if !doit {
- self.options.derive_ord = false;
- }
- self
- }
-
- /// Set whether `Ord` should be derived by default.
- /// We can't compute `Ord` without computing `PartialOrd`,
- /// so we set the same option to derive_partialord.
- pub fn derive_ord(mut self, doit: bool) -> Self {
- self.options.derive_ord = doit;
- self.options.derive_partialord = doit;
- self
- }
-
- /// Set whether `PartialEq` should be derived by default.
- ///
- /// If we don't derive `PartialEq`, we also cannot derive `Eq`, so deriving
- /// `Eq` is also disabled when `doit` is `false`.
- pub fn derive_partialeq(mut self, doit: bool) -> Self {
- self.options.derive_partialeq = doit;
- if !doit {
- self.options.derive_eq = false;
- }
- self
- }
-
- /// Set whether `Eq` should be derived by default.
- ///
- /// We can't derive `Eq` without also deriving `PartialEq`, so we also
- /// enable deriving `PartialEq` when `doit` is `true`.
- pub fn derive_eq(mut self, doit: bool) -> Self {
- self.options.derive_eq = doit;
- if doit {
- self.options.derive_partialeq = doit;
- }
- self
- }
-
- /// Set whether or not to time bindgen phases, and print information to
- /// stderr.
- pub fn time_phases(mut self, doit: bool) -> Self {
- self.options.time_phases = doit;
- self
- }
-
- /// Emit Clang AST.
- pub fn emit_clang_ast(mut self) -> Builder {
- self.options.emit_ast = true;
- self
- }
-
- /// Emit IR.
- pub fn emit_ir(mut self) -> Builder {
- self.options.emit_ir = true;
- self
- }
-
- /// Enable C++ namespaces.
- pub fn enable_cxx_namespaces(mut self) -> Builder {
- self.options.enable_cxx_namespaces = true;
- self
- }
-
- /// Enable detecting must_use attributes on C functions.
- ///
- /// This is quite slow in some cases (see #1465), so it's disabled by
- /// default.
- ///
- /// Note that for this to do something meaningful for now at least, the rust
- /// target version has to have support for `#[must_use]`.
- pub fn enable_function_attribute_detection(mut self) -> Self {
- self.options.enable_function_attribute_detection = true;
- self
- }
-
- /// Disable name auto-namespacing.
- ///
- /// By default, bindgen mangles names like `foo::bar::Baz` to look like
- /// `foo_bar_Baz` instead of just `Baz`.
- ///
- /// This method disables that behavior.
- ///
- /// Note that this intentionally does not change the names used for
- /// allowlisting and blocklisting, which should still be mangled with the
- /// namespaces.
- ///
- /// Note, also, that this option may cause bindgen to generate duplicate
- /// names.
- pub fn disable_name_namespacing(mut self) -> Builder {
- self.options.disable_name_namespacing = true;
- self
- }
-
- /// Disable nested struct naming.
- ///
- /// The following structs have different names for C and C++. In case of C
- /// they are visible as `foo` and `bar`. In case of C++ they are visible as
- /// `foo` and `foo::bar`.
- ///
- /// ```c
- /// struct foo {
- /// struct bar {
- /// } b;
- /// };
- /// ```
- ///
- /// Bindgen wants to avoid duplicate names by default so it follows C++ naming
- /// and it generates `foo`/`foo_bar` instead of just `foo`/`bar`.
- ///
- /// This method disables this behavior and it is indented to be used only
- /// for headers that were written for C.
- pub fn disable_nested_struct_naming(mut self) -> Builder {
- self.options.disable_nested_struct_naming = true;
- self
- }
-
- /// Treat inline namespaces conservatively.
- ///
- /// This is tricky, because in C++ is technically legal to override an item
- /// defined in an inline namespace:
- ///
- /// ```cpp
- /// inline namespace foo {
- /// using Bar = int;
- /// }
- /// using Bar = long;
- /// ```
- ///
- /// Even though referencing `Bar` is a compiler error.
- ///
- /// We want to support this (arguably esoteric) use case, but we don't want
- /// to make the rest of bindgen users pay an usability penalty for that.
- ///
- /// To support this, we need to keep all the inline namespaces around, but
- /// then bindgen usage is a bit more difficult, because you cannot
- /// reference, e.g., `std::string` (you'd need to use the proper inline
- /// namespace).
- ///
- /// We could complicate a lot of the logic to detect name collisions, and if
- /// not detected generate a `pub use inline_ns::*` or something like that.
- ///
- /// That's probably something we can do if we see this option is needed in a
- /// lot of cases, to improve it's usability, but my guess is that this is
- /// not going to be too useful.
- pub fn conservative_inline_namespaces(mut self) -> Builder {
- self.options.conservative_inline_namespaces = true;
- self
- }
-
- /// Whether inline functions should be generated or not.
- ///
- /// Note that they will usually not work. However you can use
- /// `-fkeep-inline-functions` or `-fno-inline-functions` if you are
- /// responsible of compiling the library to make them callable.
- pub fn generate_inline_functions(mut self, doit: bool) -> Self {
- self.options.generate_inline_functions = doit;
- self
- }
-
- /// Ignore functions.
- pub fn ignore_functions(mut self) -> Builder {
- self.options.codegen_config.remove(CodegenConfig::FUNCTIONS);
- self
- }
-
- /// Ignore methods.
- pub fn ignore_methods(mut self) -> Builder {
- self.options.codegen_config.remove(CodegenConfig::METHODS);
- self
- }
-
- /// Avoid generating any unstable Rust, such as Rust unions, in the generated bindings.
- #[deprecated(note = "please use `rust_target` instead")]
- pub fn unstable_rust(self, doit: bool) -> Self {
- let rust_target = if doit {
- RustTarget::Nightly
- } else {
- LATEST_STABLE_RUST
- };
- self.rust_target(rust_target)
- }
-
- /// Use core instead of libstd in the generated bindings.
- pub fn use_core(mut self) -> Builder {
- self.options.use_core = true;
- self
- }
-
- /// Use the given prefix for the raw types instead of `::std::os::raw`.
- pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder {
- self.options.ctypes_prefix = Some(prefix.into());
- self
- }
-
- /// Use the given prefix for the anon fields.
- pub fn anon_fields_prefix<T: Into<String>>(mut self, prefix: T) -> Builder {
- self.options.anon_fields_prefix = prefix.into();
- self
- }
-
- /// Allows configuring types in different situations, see the
- /// [`ParseCallbacks`](./callbacks/trait.ParseCallbacks.html) documentation.
- pub fn parse_callbacks(
- mut self,
- cb: Box<dyn callbacks::ParseCallbacks>,
- ) -> Self {
- self.options.parse_callbacks = Some(Rc::from(cb));
- self
- }
-
- /// Choose what to generate using a
- /// [`CodegenConfig`](./struct.CodegenConfig.html).
- pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self {
- self.options.codegen_config = config;
- self
- }
-
- /// Whether to detect include paths using clang_sys.
- pub fn detect_include_paths(mut self, doit: bool) -> Self {
- self.options.detect_include_paths = doit;
- self
- }
-
- /// Whether to try to fit macro constants to types smaller than u32/i32
- pub fn fit_macro_constants(mut self, doit: bool) -> Self {
- self.options.fit_macro_constants = doit;
- self
- }
-
- /// Prepend the enum name to constant or newtype variants.
- pub fn prepend_enum_name(mut self, doit: bool) -> Self {
- self.options.prepend_enum_name = doit;
- self
- }
-
- /// Set whether `size_t` should be translated to `usize` automatically.
- pub fn size_t_is_usize(mut self, is: bool) -> Self {
- self.options.size_t_is_usize = is;
- self
- }
-
- /// Set whether rustfmt should format the generated bindings.
- pub fn rustfmt_bindings(mut self, doit: bool) -> Self {
- self.options.rustfmt_bindings = doit;
- self
- }
-
- /// Set whether we should record matched items in our regex sets.
- pub fn record_matches(mut self, doit: bool) -> Self {
- self.options.record_matches = doit;
- self
- }
-
- /// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt
- /// options are used.
- pub fn rustfmt_configuration_file(mut self, path: Option<PathBuf>) -> Self {
- self = self.rustfmt_bindings(true);
- self.options.rustfmt_configuration_file = path;
- self
- }
-
- /// Sets an explicit path to rustfmt, to be used when rustfmt is enabled.
- pub fn with_rustfmt<P: Into<PathBuf>>(mut self, path: P) -> Self {
- self.options.rustfmt_path = Some(path.into());
- self
- }
-
- /// If true, always emit explicit padding fields.
- ///
- /// If a struct needs to be serialized in its native format (padding bytes
- /// and all), for example writing it to a file or sending it on the network,
- /// then this should be enabled, as anything reading the padding bytes of
- /// a struct may lead to Undefined Behavior.
- pub fn explicit_padding(mut self, doit: bool) -> Self {
- self.options.force_explicit_padding = doit;
- self
- }
-
- /// If true, enables experimental support to generate vtable functions.
- ///
- /// Should mostly work, though some edge cases are likely to be broken.
- pub fn vtable_generation(mut self, doit: bool) -> Self {
- self.options.vtable_generation = doit;
- self
- }
-
- /// If true, enables the sorting of the output in a predefined manner.
- ///
- /// TODO: Perhaps move the sorting order out into a config
- pub fn sort_semantically(mut self, doit: bool) -> Self {
- self.options.sort_semantically = doit;
- self
- }
-
- /// If true, merges extern blocks.
- pub fn merge_extern_blocks(mut self, doit: bool) -> Self {
- self.options.merge_extern_blocks = doit;
- self
- }
-
- /// Generate the Rust bindings using the options built up thus far.
- pub fn generate(mut self) -> Result<Bindings, BindgenError> {
- // Add any extra arguments from the environment to the clang command line.
- self.options.clang_args.extend(get_extra_clang_args());
-
- // Transform input headers to arguments on the clang command line.
- self.options.input_header = self.input_headers.pop();
- self.options.extra_input_headers = self.input_headers;
- self.options.clang_args.extend(
- self.options.extra_input_headers.iter().flat_map(|header| {
- iter::once("-include".into())
- .chain(iter::once(header.to_string()))
- }),
- );
-
- let input_unsaved_files = self
- .input_header_contents
- .into_iter()
- .map(|(name, contents)| clang::UnsavedFile::new(&name, &contents))
- .collect::<Vec<_>>();
-
- Bindings::generate(self.options, input_unsaved_files)
- }
-
- /// Preprocess and dump the input header files to disk.
- ///
- /// This is useful when debugging bindgen, using C-Reduce, or when filing
- /// issues. The resulting file will be named something like `__bindgen.i` or
- /// `__bindgen.ii`
- pub fn dump_preprocessed_input(&self) -> io::Result<()> {
- let clang =
- clang_sys::support::Clang::find(None, &[]).ok_or_else(|| {
- io::Error::new(
- io::ErrorKind::Other,
- "Cannot find clang executable",
- )
- })?;
-
- // The contents of a wrapper file that includes all the input header
- // files.
- let mut wrapper_contents = String::new();
-
- // Whether we are working with C or C++ inputs.
- let mut is_cpp = args_are_cpp(&self.options.clang_args);
-
- // For each input header, add `#include "$header"`.
- for header in &self.input_headers {
- is_cpp |= file_is_cpp(header);
-
- wrapper_contents.push_str("#include \"");
- wrapper_contents.push_str(header);
- wrapper_contents.push_str("\"\n");
- }
-
- // For each input header content, add a prefix line of `#line 0 "$name"`
- // followed by the contents.
- for &(ref name, ref contents) in &self.input_header_contents {
- is_cpp |= file_is_cpp(name);
-
- wrapper_contents.push_str("#line 0 \"");
- wrapper_contents.push_str(name);
- wrapper_contents.push_str("\"\n");
- wrapper_contents.push_str(contents);
- }
-
- let wrapper_path = PathBuf::from(if is_cpp {
- "__bindgen.cpp"
- } else {
- "__bindgen.c"
- });
-
- {
- let mut wrapper_file = File::create(&wrapper_path)?;
- wrapper_file.write_all(wrapper_contents.as_bytes())?;
- }
-
- let mut cmd = Command::new(&clang.path);
- cmd.arg("-save-temps")
- .arg("-E")
- .arg("-C")
- .arg("-c")
- .arg(&wrapper_path)
- .stdout(Stdio::piped());
-
- for a in &self.options.clang_args {
- cmd.arg(a);
- }
-
- for a in get_extra_clang_args() {
- cmd.arg(a);
- }
-
- let mut child = cmd.spawn()?;
-
- let mut preprocessed = child.stdout.take().unwrap();
- let mut file = File::create(if is_cpp {
- "__bindgen.ii"
- } else {
- "__bindgen.i"
- })?;
- io::copy(&mut preprocessed, &mut file)?;
-
- if child.wait()?.success() {
- Ok(())
- } else {
- Err(io::Error::new(
- io::ErrorKind::Other,
- "clang exited with non-zero status",
- ))
- }
- }
-
- /// Don't derive `PartialEq` for a given type. Regular
- /// expressions are supported.
- pub fn no_partialeq<T: Into<String>>(mut self, arg: T) -> Builder {
- self.options.no_partialeq_types.insert(arg.into());
- self
- }
-
- /// Don't derive `Copy` for a given type. Regular
- /// expressions are supported.
- pub fn no_copy<T: Into<String>>(mut self, arg: T) -> Self {
- self.options.no_copy_types.insert(arg.into());
- self
- }
-
- /// Don't derive `Debug` for a given type. Regular
- /// expressions are supported.
- pub fn no_debug<T: Into<String>>(mut self, arg: T) -> Self {
- self.options.no_debug_types.insert(arg.into());
- self
- }
-
- /// Don't derive/impl `Default` for a given type. Regular
- /// expressions are supported.
- pub fn no_default<T: Into<String>>(mut self, arg: T) -> Self {
- self.options.no_default_types.insert(arg.into());
- self
- }
-
- /// Don't derive `Hash` for a given type. Regular
- /// expressions are supported.
- pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder {
- self.options.no_hash_types.insert(arg.into());
- self
- }
-
- /// Add `#[must_use]` for the given type. Regular
- /// expressions are supported.
- pub fn must_use_type<T: Into<String>>(mut self, arg: T) -> Builder {
- self.options.must_use_types.insert(arg.into());
- self
- }
-
- /// Set whether `arr[size]` should be treated as `*mut T` or `*mut [T; size]` (same for mut)
- pub fn array_pointers_in_arguments(mut self, doit: bool) -> Self {
- self.options.array_pointers_in_arguments = doit;
- self
- }
-
- /// Set the wasm import module name
- pub fn wasm_import_module_name<T: Into<String>>(
- mut self,
- import_name: T,
- ) -> Self {
- self.options.wasm_import_module_name = Some(import_name.into());
- self
- }
-
- /// Specify the dynamic library name if we are generating bindings for a shared library.
- pub fn dynamic_library_name<T: Into<String>>(
- mut self,
- dynamic_library_name: T,
- ) -> Self {
- self.options.dynamic_library_name = Some(dynamic_library_name.into());
- self
- }
-
- /// Require successful linkage for all routines in a shared library.
- /// This allows us to optimize function calls by being able to safely assume function pointers
- /// are valid.
- pub fn dynamic_link_require_all(mut self, req: bool) -> Self {
- self.options.dynamic_link_require_all = req;
- self
- }
-
- /// Generate bindings as `pub` only if the bound item is publically accessible by C++.
- pub fn respect_cxx_access_specs(mut self, doit: bool) -> Self {
- self.options.respect_cxx_access_specs = doit;
- self
- }
-
- /// Always translate enum integer types to native Rust integer types.
- ///
- /// This will result in enums having types such as `u32` and `i16` instead
- /// of `c_uint` and `c_short`. Types for Rustified enums are always
- /// translated.
- pub fn translate_enum_integer_types(mut self, doit: bool) -> Self {
- self.options.translate_enum_integer_types = doit;
- self
- }
-
- /// Generate types with C style naming.
- ///
- /// This will add prefixes to the generated type names. For example instead of a struct `A` we
- /// will generate struct `struct_A`. Currently applies to structs, unions, and enums.
- pub fn c_naming(mut self, doit: bool) -> Self {
- self.options.c_naming = doit;
- self
- }
-}
-
-/// Configuration options for generated bindings.
-#[derive(Clone, Debug)]
-struct BindgenOptions {
- /// The set of types that have been blocklisted and should not appear
- /// anywhere in the generated code.
- blocklisted_types: RegexSet,
-
- /// The set of functions that have been blocklisted and should not appear
- /// in the generated code.
- blocklisted_functions: RegexSet,
-
- /// The set of items, regardless of item-type, that have been
- /// blocklisted and should not appear in the generated code.
- blocklisted_items: RegexSet,
-
- /// The set of files whose contents should be blocklisted and should not
- /// appear in the generated code.
- blocklisted_files: RegexSet,
-
- /// The set of types that should be treated as opaque structures in the
- /// generated code.
- opaque_types: RegexSet,
-
- /// The explicit rustfmt path.
- rustfmt_path: Option<PathBuf>,
-
- /// The path to which we should write a Makefile-syntax depfile (if any).
- depfile: Option<deps::DepfileSpec>,
-
- /// The set of types that we should have bindings for in the generated
- /// code.
- ///
- /// This includes all types transitively reachable from any type in this
- /// set. One might think of allowlisted types/vars/functions as GC roots,
- /// and the generated Rust code as including everything that gets marked.
- allowlisted_types: RegexSet,
-
- /// Allowlisted functions. See docs for `allowlisted_types` for more.
- allowlisted_functions: RegexSet,
-
- /// Allowlisted variables. See docs for `allowlisted_types` for more.
- allowlisted_vars: RegexSet,
-
- /// The set of files whose contents should be allowlisted.
- allowlisted_files: RegexSet,
-
- /// The default style of code to generate for enums
- default_enum_style: codegen::EnumVariation,
-
- /// The enum patterns to mark an enum as a bitfield
- /// (newtype with bitwise operations).
- bitfield_enums: RegexSet,
-
- /// The enum patterns to mark an enum as a newtype.
- newtype_enums: RegexSet,
-
- /// The enum patterns to mark an enum as a global newtype.
- newtype_global_enums: RegexSet,
-
- /// The enum patterns to mark an enum as a Rust enum.
- rustified_enums: RegexSet,
-
- /// The enum patterns to mark an enum as a non-exhaustive Rust enum.
- rustified_non_exhaustive_enums: RegexSet,
-
- /// The enum patterns to mark an enum as a module of constants.
- constified_enum_modules: RegexSet,
-
- /// The enum patterns to mark an enum as a set of constants.
- constified_enums: RegexSet,
-
- /// The default type for C macro constants.
- default_macro_constant_type: codegen::MacroTypeVariation,
-
- /// The default style of code to generate for typedefs.
- default_alias_style: codegen::AliasVariation,
-
- /// Typedef patterns that will use regular type aliasing.
- type_alias: RegexSet,
-
- /// Typedef patterns that will be aliased by creating a new struct.
- new_type_alias: RegexSet,
-
- /// Typedef patterns that will be wrapped in a new struct and have
- /// Deref and Deref to their aliased type.
- new_type_alias_deref: RegexSet,
-
- /// The default style of code to generate for union containing non-Copy
- /// members.
- default_non_copy_union_style: codegen::NonCopyUnionStyle,
-
- /// The union patterns to mark an non-Copy union as using the bindgen
- /// generated wrapper.
- bindgen_wrapper_union: RegexSet,
-
- /// The union patterns to mark an non-Copy union as using the
- /// `::core::mem::ManuallyDrop` wrapper.
- manually_drop_union: RegexSet,
-
- /// Whether we should generate builtins or not.
- builtins: bool,
-
- /// True if we should dump the Clang AST for debugging purposes.
- emit_ast: bool,
-
- /// True if we should dump our internal IR for debugging purposes.
- emit_ir: bool,
-
- /// Output graphviz dot file.
- emit_ir_graphviz: Option<String>,
-
- /// True if we should emulate C++ namespaces with Rust modules in the
- /// generated bindings.
- enable_cxx_namespaces: bool,
-
- /// True if we should try to find unexposed attributes in functions, in
- /// order to be able to generate #[must_use] attributes in Rust.
- enable_function_attribute_detection: bool,
-
- /// True if we should avoid mangling names with namespaces.
- disable_name_namespacing: bool,
-
- /// True if we should avoid generating nested struct names.
- disable_nested_struct_naming: bool,
-
- /// True if we should avoid embedding version identifiers into source code.
- disable_header_comment: bool,
-
- /// True if we should generate layout tests for generated structures.
- layout_tests: bool,
-
- /// True if we should implement the Debug trait for C/C++ structures and types
- /// that do not support automatically deriving Debug.
- impl_debug: bool,
-
- /// True if we should implement the PartialEq trait for C/C++ structures and types
- /// that do not support automatically deriving PartialEq.
- impl_partialeq: bool,
-
- /// True if we should derive Copy trait implementations for C/C++ structures
- /// and types.
- derive_copy: bool,
-
- /// True if we should derive Debug trait implementations for C/C++ structures
- /// and types.
- derive_debug: bool,
-
- /// True if we should derive Default trait implementations for C/C++ structures
- /// and types.
- derive_default: bool,
-
- /// True if we should derive Hash trait implementations for C/C++ structures
- /// and types.
- derive_hash: bool,
-
- /// True if we should derive PartialOrd trait implementations for C/C++ structures
- /// and types.
- derive_partialord: bool,
-
- /// True if we should derive Ord trait implementations for C/C++ structures
- /// and types.
- derive_ord: bool,
-
- /// True if we should derive PartialEq trait implementations for C/C++ structures
- /// and types.
- derive_partialeq: bool,
-
- /// True if we should derive Eq trait implementations for C/C++ structures
- /// and types.
- derive_eq: bool,
-
- /// True if we should avoid using libstd to use libcore instead.
- use_core: bool,
-
- /// An optional prefix for the "raw" types, like `c_int`, `c_void`...
- ctypes_prefix: Option<String>,
-
- /// The prefix for the anon fields.
- anon_fields_prefix: String,
-
- /// Whether to time the bindgen phases.
- time_phases: bool,
-
- /// Whether we should convert float types to f32/f64 types.
- convert_floats: bool,
-
- /// The set of raw lines to prepend to the top-level module of generated
- /// Rust code.
- raw_lines: Vec<String>,
-
- /// The set of raw lines to prepend to each of the modules.
- ///
- /// This only makes sense if the `enable_cxx_namespaces` option is set.
- module_lines: HashMap<String, Vec<String>>,
-
- /// The set of arguments to pass straight through to Clang.
- clang_args: Vec<String>,
-
- /// The input header file.
- input_header: Option<String>,
-
- /// Any additional input header files.
- extra_input_headers: Vec<String>,
-
- /// A user-provided visitor to allow customizing different kinds of
- /// situations.
- parse_callbacks: Option<Rc<dyn callbacks::ParseCallbacks>>,
-
- /// Which kind of items should we generate? By default, we'll generate all
- /// of them.
- codegen_config: CodegenConfig,
-
- /// Whether to treat inline namespaces conservatively.
- ///
- /// See the builder method description for more details.
- conservative_inline_namespaces: bool,
-
- /// Whether to keep documentation comments in the generated output. See the
- /// documentation for more details. Defaults to true.
- generate_comments: bool,
-
- /// Whether to generate inline functions. Defaults to false.
- generate_inline_functions: bool,
-
- /// Whether to allowlist types recursively. Defaults to true.
- allowlist_recursively: bool,
-
- /// Instead of emitting 'use objc;' to files generated from objective c files,
- /// generate '#[macro_use] extern crate objc;'
- objc_extern_crate: bool,
-
- /// Instead of emitting 'use block;' to files generated from objective c files,
- /// generate '#[macro_use] extern crate block;'
- generate_block: bool,
-
- /// Instead of emitting 'use block;' to files generated from objective c files,
- /// generate '#[macro_use] extern crate block;'
- block_extern_crate: bool,
-
- /// Whether to use the clang-provided name mangling. This is true and
- /// probably needed for C++ features.
- ///
- /// However, some old libclang versions seem to return incorrect results in
- /// some cases for non-mangled functions, see [1], so we allow disabling it.
- ///
- /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528
- enable_mangling: bool,
-
- /// Whether to detect include paths using clang_sys.
- detect_include_paths: bool,
-
- /// Whether to try to fit macro constants into types smaller than u32/i32
- fit_macro_constants: bool,
-
- /// Whether to prepend the enum name to constant or newtype variants.
- prepend_enum_name: bool,
-
- /// Version of the Rust compiler to target
- rust_target: RustTarget,
-
- /// Features to enable, derived from `rust_target`
- rust_features: RustFeatures,
-
- /// Whether we should record which items in the regex sets ever matched.
- ///
- /// This may be a bit slower, but will enable reporting of unused allowlist
- /// items via the `error!` log.
- record_matches: bool,
-
- /// Whether `size_t` should be translated to `usize` automatically.
- size_t_is_usize: bool,
-
- /// Whether rustfmt should format the generated bindings.
- rustfmt_bindings: bool,
-
- /// The absolute path to the rustfmt configuration file, if None, the standard rustfmt
- /// options are used.
- rustfmt_configuration_file: Option<PathBuf>,
-
- /// The set of types that we should not derive `PartialEq` for.
- no_partialeq_types: RegexSet,
-
- /// The set of types that we should not derive `Copy` for.
- no_copy_types: RegexSet,
-
- /// The set of types that we should not derive `Debug` for.
- no_debug_types: RegexSet,
-
- /// The set of types that we should not derive/impl `Default` for.
- no_default_types: RegexSet,
-
- /// The set of types that we should not derive `Hash` for.
- no_hash_types: RegexSet,
-
- /// The set of types that we should be annotated with `#[must_use]`.
- must_use_types: RegexSet,
-
- /// Decide if C arrays should be regular pointers in rust or array pointers
- array_pointers_in_arguments: bool,
-
- /// Wasm import module name.
- wasm_import_module_name: Option<String>,
-
- /// The name of the dynamic library (if we are generating bindings for a shared library). If
- /// this is None, no dynamic bindings are created.
- dynamic_library_name: Option<String>,
-
- /// Require successful linkage for all routines in a shared library.
- /// This allows us to optimize function calls by being able to safely assume function pointers
- /// are valid. No effect if `dynamic_library_name` is None.
- dynamic_link_require_all: bool,
-
- /// Only make generated bindings `pub` if the items would be publically accessible
- /// by C++.
- respect_cxx_access_specs: bool,
-
- /// Always translate enum integer types to native Rust integer types.
- translate_enum_integer_types: bool,
-
- /// Generate types with C style naming.
- c_naming: bool,
-
- /// Always output explicit padding fields
- force_explicit_padding: bool,
-
- /// Emit vtable functions.
- vtable_generation: bool,
-
- /// Sort the code generation.
- sort_semantically: bool,
-
- /// Deduplicate `extern` blocks.
- merge_extern_blocks: bool,
-}
-
-/// TODO(emilio): This is sort of a lie (see the error message that results from
-/// removing this), but since we don't share references across panic boundaries
-/// it's ok.
-impl ::std::panic::UnwindSafe for BindgenOptions {}
-
-impl BindgenOptions {
- fn build(&mut self) {
- let mut regex_sets = [
- &mut self.allowlisted_vars,
- &mut self.allowlisted_types,
- &mut self.allowlisted_functions,
- &mut self.allowlisted_files,
- &mut self.blocklisted_types,
- &mut self.blocklisted_functions,
- &mut self.blocklisted_items,
- &mut self.blocklisted_files,
- &mut self.opaque_types,
- &mut self.bitfield_enums,
- &mut self.constified_enums,
- &mut self.constified_enum_modules,
- &mut self.newtype_enums,
- &mut self.newtype_global_enums,
- &mut self.rustified_enums,
- &mut self.rustified_non_exhaustive_enums,
- &mut self.type_alias,
- &mut self.new_type_alias,
- &mut self.new_type_alias_deref,
- &mut self.bindgen_wrapper_union,
- &mut self.manually_drop_union,
- &mut self.no_partialeq_types,
- &mut self.no_copy_types,
- &mut self.no_debug_types,
- &mut self.no_default_types,
- &mut self.no_hash_types,
- &mut self.must_use_types,
- ];
- let record_matches = self.record_matches;
- for regex_set in &mut regex_sets {
- regex_set.build(record_matches);
- }
- }
-
- /// Update rust target version
- pub fn set_rust_target(&mut self, rust_target: RustTarget) {
- self.rust_target = rust_target;
-
- // Keep rust_features synced with rust_target
- self.rust_features = rust_target.into();
- }
-
- /// Get features supported by target Rust version
- pub fn rust_features(&self) -> RustFeatures {
- self.rust_features
- }
-}
-
-impl Default for BindgenOptions {
- fn default() -> BindgenOptions {
- let rust_target = RustTarget::default();
-
- BindgenOptions {
- rust_target,
- rust_features: rust_target.into(),
- blocklisted_types: Default::default(),
- blocklisted_functions: Default::default(),
- blocklisted_items: Default::default(),
- blocklisted_files: Default::default(),
- opaque_types: Default::default(),
- rustfmt_path: Default::default(),
- depfile: Default::default(),
- allowlisted_types: Default::default(),
- allowlisted_functions: Default::default(),
- allowlisted_vars: Default::default(),
- allowlisted_files: Default::default(),
- default_enum_style: Default::default(),
- bitfield_enums: Default::default(),
- newtype_enums: Default::default(),
- newtype_global_enums: Default::default(),
- rustified_enums: Default::default(),
- rustified_non_exhaustive_enums: Default::default(),
- constified_enums: Default::default(),
- constified_enum_modules: Default::default(),
- default_macro_constant_type: Default::default(),
- default_alias_style: Default::default(),
- type_alias: Default::default(),
- new_type_alias: Default::default(),
- new_type_alias_deref: Default::default(),
- default_non_copy_union_style: Default::default(),
- bindgen_wrapper_union: Default::default(),
- manually_drop_union: Default::default(),
- builtins: false,
- emit_ast: false,
- emit_ir: false,
- emit_ir_graphviz: None,
- layout_tests: true,
- impl_debug: false,
- impl_partialeq: false,
- derive_copy: true,
- derive_debug: true,
- derive_default: false,
- derive_hash: false,
- derive_partialord: false,
- derive_ord: false,
- derive_partialeq: false,
- derive_eq: false,
- enable_cxx_namespaces: false,
- enable_function_attribute_detection: false,
- disable_name_namespacing: false,
- disable_nested_struct_naming: false,
- disable_header_comment: false,
- use_core: false,
- ctypes_prefix: None,
- anon_fields_prefix: DEFAULT_ANON_FIELDS_PREFIX.into(),
- convert_floats: true,
- raw_lines: vec![],
- module_lines: HashMap::default(),
- clang_args: vec![],
- input_header: None,
- extra_input_headers: vec![],
- parse_callbacks: None,
- codegen_config: CodegenConfig::all(),
- conservative_inline_namespaces: false,
- generate_comments: true,
- generate_inline_functions: false,
- allowlist_recursively: true,
- generate_block: false,
- objc_extern_crate: false,
- block_extern_crate: false,
- enable_mangling: true,
- detect_include_paths: true,
- fit_macro_constants: false,
- prepend_enum_name: true,
- time_phases: false,
- record_matches: true,
- rustfmt_bindings: true,
- size_t_is_usize: true,
- rustfmt_configuration_file: None,
- no_partialeq_types: Default::default(),
- no_copy_types: Default::default(),
- no_debug_types: Default::default(),
- no_default_types: Default::default(),
- no_hash_types: Default::default(),
- must_use_types: Default::default(),
- array_pointers_in_arguments: false,
- wasm_import_module_name: None,
- dynamic_library_name: None,
- dynamic_link_require_all: false,
- respect_cxx_access_specs: false,
- translate_enum_integer_types: false,
- c_naming: false,
- force_explicit_padding: false,
- vtable_generation: false,
- sort_semantically: false,
- merge_extern_blocks: false,
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-fn ensure_libclang_is_loaded() {
- if clang_sys::is_loaded() {
- return;
- }
-
- // XXX (issue #350): Ensure that our dynamically loaded `libclang`
- // doesn't get dropped prematurely, nor is loaded multiple times
- // across different threads.
-
- lazy_static! {
- static ref LIBCLANG: std::sync::Arc<clang_sys::SharedLibrary> = {
- clang_sys::load().expect("Unable to find libclang");
- clang_sys::get_library().expect(
- "We just loaded libclang and it had better still be \
- here!",
- )
- };
- }
-
- clang_sys::set_library(Some(LIBCLANG.clone()));
-}
-
-#[cfg(not(feature = "runtime"))]
-fn ensure_libclang_is_loaded() {}
-
-/// Error type for rust-bindgen.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-#[non_exhaustive]
-pub enum BindgenError {
- /// The header was a folder.
- FolderAsHeader(PathBuf),
- /// Permissions to read the header is insufficient.
- InsufficientPermissions(PathBuf),
- /// The header does not exist.
- NotExist(PathBuf),
- /// Clang diagnosed an error.
- ClangDiagnostic(String),
-}
-
-impl std::fmt::Display for BindgenError {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- BindgenError::FolderAsHeader(h) => {
- write!(f, "'{}' is a folder", h.display())
- }
- BindgenError::InsufficientPermissions(h) => {
- write!(f, "insufficient permissions to read '{}'", h.display())
- }
- BindgenError::NotExist(h) => {
- write!(f, "header '{}' does not exist.", h.display())
- }
- BindgenError::ClangDiagnostic(message) => {
- write!(f, "clang diagnosed error: {}", message)
- }
- }
- }
-}
-
-impl std::error::Error for BindgenError {}
-
-/// Generated Rust bindings.
-#[derive(Debug)]
-pub struct Bindings {
- options: BindgenOptions,
- warnings: Vec<String>,
- module: proc_macro2::TokenStream,
-}
-
-pub(crate) const HOST_TARGET: &str =
- include_str!(concat!(env!("OUT_DIR"), "/host-target.txt"));
-
-// Some architecture triplets are different between rust and libclang, see #1211
-// and duplicates.
-fn rust_to_clang_target(rust_target: &str) -> String {
- if rust_target.starts_with("aarch64-apple-") {
- let mut clang_target = "arm64-apple-".to_owned();
- clang_target
- .push_str(rust_target.strip_prefix("aarch64-apple-").unwrap());
- return clang_target;
- } else if rust_target.starts_with("riscv64gc-") {
- let mut clang_target = "riscv64-".to_owned();
- clang_target.push_str(rust_target.strip_prefix("riscv64gc-").unwrap());
- return clang_target;
- }
- rust_target.to_owned()
-}
-
-/// Returns the effective target, and whether it was explicitly specified on the
-/// clang flags.
-fn find_effective_target(clang_args: &[String]) -> (String, bool) {
- let mut args = clang_args.iter();
- while let Some(opt) = args.next() {
- if opt.starts_with("--target=") {
- let mut split = opt.split('=');
- split.next();
- return (split.next().unwrap().to_owned(), true);
- }
-
- if opt == "-target" {
- if let Some(target) = args.next() {
- return (target.clone(), true);
- }
- }
- }
-
- // If we're running from a build script, try to find the cargo target.
- if let Ok(t) = env::var("TARGET") {
- return (rust_to_clang_target(&t), false);
- }
-
- (rust_to_clang_target(HOST_TARGET), false)
-}
-
-impl Bindings {
- /// Generate bindings for the given options.
- pub(crate) fn generate(
- mut options: BindgenOptions,
- input_unsaved_files: Vec<clang::UnsavedFile>,
- ) -> Result<Bindings, BindgenError> {
- ensure_libclang_is_loaded();
-
- #[cfg(feature = "runtime")]
- debug!(
- "Generating bindings, libclang at {}",
- clang_sys::get_library().unwrap().path().display()
- );
- #[cfg(not(feature = "runtime"))]
- debug!("Generating bindings, libclang linked");
-
- options.build();
-
- let (effective_target, explicit_target) =
- find_effective_target(&options.clang_args);
-
- let is_host_build =
- rust_to_clang_target(HOST_TARGET) == effective_target;
-
- // NOTE: The is_host_build check wouldn't be sound normally in some
- // cases if we were to call a binary (if you have a 32-bit clang and are
- // building on a 64-bit system for example). But since we rely on
- // opening libclang.so, it has to be the same architecture and thus the
- // check is fine.
- if !explicit_target && !is_host_build {
- options
- .clang_args
- .insert(0, format!("--target={}", effective_target));
- };
-
- fn detect_include_paths(options: &mut BindgenOptions) {
- if !options.detect_include_paths {
- return;
- }
-
- // Filter out include paths and similar stuff, so we don't incorrectly
- // promote them to `-isystem`.
- let clang_args_for_clang_sys = {
- let mut last_was_include_prefix = false;
- options
- .clang_args
- .iter()
- .filter(|arg| {
- if last_was_include_prefix {
- last_was_include_prefix = false;
- return false;
- }
-
- let arg = &**arg;
-
- // https://clang.llvm.org/docs/ClangCommandLineReference.html
- // -isystem and -isystem-after are harmless.
- if arg == "-I" || arg == "--include-directory" {
- last_was_include_prefix = true;
- return false;
- }
-
- if arg.starts_with("-I") ||
- arg.starts_with("--include-directory=")
- {
- return false;
- }
-
- true
- })
- .cloned()
- .collect::<Vec<_>>()
- };
-
- debug!(
- "Trying to find clang with flags: {:?}",
- clang_args_for_clang_sys
- );
-
- let clang = match clang_sys::support::Clang::find(
- None,
- &clang_args_for_clang_sys,
- ) {
- None => return,
- Some(clang) => clang,
- };
-
- debug!("Found clang: {:?}", clang);
-
- // Whether we are working with C or C++ inputs.
- let is_cpp = args_are_cpp(&options.clang_args) ||
- options.input_header.as_deref().map_or(false, file_is_cpp);
-
- let search_paths = if is_cpp {
- clang.cpp_search_paths
- } else {
- clang.c_search_paths
- };
-
- if let Some(search_paths) = search_paths {
- for path in search_paths.into_iter() {
- if let Ok(path) = path.into_os_string().into_string() {
- options.clang_args.push("-isystem".to_owned());
- options.clang_args.push(path);
- }
- }
- }
- }
-
- detect_include_paths(&mut options);
-
- #[cfg(unix)]
- fn can_read(perms: &std::fs::Permissions) -> bool {
- use std::os::unix::fs::PermissionsExt;
- perms.mode() & 0o444 > 0
- }
-
- #[cfg(not(unix))]
- fn can_read(_: &std::fs::Permissions) -> bool {
- true
- }
-
- if let Some(h) = options.input_header.as_ref() {
- let path = Path::new(h);
- if let Ok(md) = std::fs::metadata(path) {
- if md.is_dir() {
- return Err(BindgenError::FolderAsHeader(path.into()));
- }
- if !can_read(&md.permissions()) {
- return Err(BindgenError::InsufficientPermissions(
- path.into(),
- ));
- }
- options.clang_args.push(h.clone())
- } else {
- return Err(BindgenError::NotExist(path.into()));
- }
- }
-
- for (idx, f) in input_unsaved_files.iter().enumerate() {
- if idx != 0 || options.input_header.is_some() {
- options.clang_args.push("-include".to_owned());
- }
- options.clang_args.push(f.name.to_str().unwrap().to_owned())
- }
-
- debug!("Fixed-up options: {:?}", options);
-
- let time_phases = options.time_phases;
- let mut context = BindgenContext::new(options, &input_unsaved_files);
-
- if is_host_build {
- debug_assert_eq!(
- context.target_pointer_size(),
- std::mem::size_of::<*mut ()>(),
- "{:?} {:?}",
- effective_target,
- HOST_TARGET
- );
- }
-
- {
- let _t = time::Timer::new("parse").with_output(time_phases);
- parse(&mut context)?;
- }
-
- let (module, options, warnings) = codegen::codegen(context);
-
- Ok(Bindings {
- options,
- warnings,
- module,
- })
- }
-
- /// Write these bindings as source text to a file.
- pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
- let file = OpenOptions::new()
- .write(true)
- .truncate(true)
- .create(true)
- .open(path.as_ref())?;
- self.write(Box::new(file))?;
- Ok(())
- }
-
- /// Write these bindings as source text to the given `Write`able.
- pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> io::Result<()> {
- if !self.options.disable_header_comment {
- let version = option_env!("CARGO_PKG_VERSION");
- let header = format!(
- "/* automatically generated by rust-bindgen {} */\n\n",
- version.unwrap_or("(unknown version)")
- );
- writer.write_all(header.as_bytes())?;
- }
-
- for line in self.options.raw_lines.iter() {
- writer.write_all(line.as_bytes())?;
- writer.write_all("\n".as_bytes())?;
- }
-
- if !self.options.raw_lines.is_empty() {
- writer.write_all("\n".as_bytes())?;
- }
-
- let bindings = self.module.to_string();
-
- match self.rustfmt_generated_string(&bindings) {
- Ok(rustfmt_bindings) => {
- writer.write_all(rustfmt_bindings.as_bytes())?;
- }
- Err(err) => {
- eprintln!(
- "Failed to run rustfmt: {} (non-fatal, continuing)",
- err
- );
- writer.write_all(bindings.as_bytes())?;
- }
- }
- Ok(())
- }
-
- /// Gets the rustfmt path to rustfmt the generated bindings.
- fn rustfmt_path(&self) -> io::Result<Cow<PathBuf>> {
- debug_assert!(self.options.rustfmt_bindings);
- if let Some(ref p) = self.options.rustfmt_path {
- return Ok(Cow::Borrowed(p));
- }
- if let Ok(rustfmt) = env::var("RUSTFMT") {
- return Ok(Cow::Owned(rustfmt.into()));
- }
- #[cfg(feature = "which-rustfmt")]
- match which::which("rustfmt") {
- Ok(p) => Ok(Cow::Owned(p)),
- Err(e) => {
- Err(io::Error::new(io::ErrorKind::Other, format!("{}", e)))
- }
- }
- #[cfg(not(feature = "which-rustfmt"))]
- // No rustfmt binary was specified, so assume that the binary is called
- // "rustfmt" and that it is in the user's PATH.
- Ok(Cow::Owned("rustfmt".into()))
- }
-
- /// Checks if rustfmt_bindings is set and runs rustfmt on the string
- fn rustfmt_generated_string<'a>(
- &self,
- source: &'a str,
- ) -> io::Result<Cow<'a, str>> {
- let _t = time::Timer::new("rustfmt_generated_string")
- .with_output(self.options.time_phases);
-
- if !self.options.rustfmt_bindings {
- return Ok(Cow::Borrowed(source));
- }
-
- let rustfmt = self.rustfmt_path()?;
- let mut cmd = Command::new(&*rustfmt);
-
- cmd.stdin(Stdio::piped()).stdout(Stdio::piped());
-
- if let Some(path) = self
- .options
- .rustfmt_configuration_file
- .as_ref()
- .and_then(|f| f.to_str())
- {
- cmd.args(["--config-path", path]);
- }
-
- let mut child = cmd.spawn()?;
- let mut child_stdin = child.stdin.take().unwrap();
- let mut child_stdout = child.stdout.take().unwrap();
-
- let source = source.to_owned();
-
- // Write to stdin in a new thread, so that we can read from stdout on this
- // thread. This keeps the child from blocking on writing to its stdout which
- // might block us from writing to its stdin.
- let stdin_handle = ::std::thread::spawn(move || {
- let _ = child_stdin.write_all(source.as_bytes());
- source
- });
-
- let mut output = vec![];
- io::copy(&mut child_stdout, &mut output)?;
-
- let status = child.wait()?;
- let source = stdin_handle.join().expect(
- "The thread writing to rustfmt's stdin doesn't do \
- anything that could panic",
- );
-
- match String::from_utf8(output) {
- Ok(bindings) => match status.code() {
- Some(0) => Ok(Cow::Owned(bindings)),
- Some(2) => Err(io::Error::new(
- io::ErrorKind::Other,
- "Rustfmt parsing errors.".to_string(),
- )),
- Some(3) => {
- warn!("Rustfmt could not format some lines.");
- Ok(Cow::Owned(bindings))
- }
- _ => Err(io::Error::new(
- io::ErrorKind::Other,
- "Internal rustfmt error".to_string(),
- )),
- },
- _ => Ok(Cow::Owned(source)),
- }
- }
-
- /// Emit all the warning messages raised while generating the bindings in a build script.
- ///
- /// If you are using `bindgen` outside of a build script you should use [`Bindings::warnings`]
- /// and handle the messages accordingly instead.
- #[inline]
- pub fn emit_warnings(&self) {
- for message in &self.warnings {
- println!("cargo:warning={}", message);
- }
- }
-
- /// Return all the warning messages raised while generating the bindings.
- #[inline]
- pub fn warnings(&self) -> &[String] {
- &self.warnings
- }
-}
-
-impl std::fmt::Display for Bindings {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let mut bytes = vec![];
- self.write(Box::new(&mut bytes) as Box<dyn Write>)
- .expect("writing to a vec cannot fail");
- f.write_str(
- std::str::from_utf8(&bytes)
- .expect("we should only write bindings that are valid utf-8"),
- )
- }
-}
-
-/// Determines whether the given cursor is in any of the files matched by the
-/// options.
-fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
- ctx.options().builtins || !cursor.is_builtin()
-}
-
-/// Parse one `Item` from the Clang cursor.
-fn parse_one(
- ctx: &mut BindgenContext,
- cursor: clang::Cursor,
- parent: Option<ItemId>,
-) -> clang_sys::CXChildVisitResult {
- if !filter_builtins(ctx, &cursor) {
- return CXChildVisit_Continue;
- }
-
- use clang_sys::CXChildVisit_Continue;
- match Item::parse(cursor, parent, ctx) {
- Ok(..) => {}
- Err(ParseError::Continue) => {}
- Err(ParseError::Recurse) => {
- cursor.visit(|child| parse_one(ctx, child, parent));
- }
- }
- CXChildVisit_Continue
-}
-
-/// Parse the Clang AST into our `Item` internal representation.
-fn parse(context: &mut BindgenContext) -> Result<(), BindgenError> {
- use clang_sys::*;
-
- let mut error = None;
- for d in context.translation_unit().diags().iter() {
- let msg = d.format();
- let is_err = d.severity() >= CXDiagnostic_Error;
- if is_err {
- let error = error.get_or_insert_with(String::new);
- error.push_str(&msg);
- error.push('\n');
- } else {
- eprintln!("clang diag: {}", msg);
- }
- }
-
- if let Some(message) = error {
- return Err(BindgenError::ClangDiagnostic(message));
- }
-
- let cursor = context.translation_unit().cursor();
-
- if context.options().emit_ast {
- fn dump_if_not_builtin(cur: &clang::Cursor) -> CXChildVisitResult {
- if !cur.is_builtin() {
- clang::ast_dump(cur, 0)
- } else {
- CXChildVisit_Continue
- }
- }
- cursor.visit(|cur| dump_if_not_builtin(&cur));
- }
-
- let root = context.root_module();
- context.with_module(root, |context| {
- cursor.visit(|cursor| parse_one(context, cursor, None))
- });
-
- assert!(
- context.current_module() == context.root_module(),
- "How did this happen?"
- );
- Ok(())
-}
-
-/// Extracted Clang version data
-#[derive(Debug)]
-pub struct ClangVersion {
- /// Major and minor semver, if parsing was successful
- pub parsed: Option<(u32, u32)>,
- /// full version string
- pub full: String,
-}
-
-/// Get the major and the minor semver numbers of Clang's version
-pub fn clang_version() -> ClangVersion {
- ensure_libclang_is_loaded();
-
- //Debian clang version 11.0.1-2
- let raw_v: String = clang::extract_clang_version();
- let split_v: Option<Vec<&str>> = raw_v
- .split_whitespace()
- .find(|t| t.chars().next().map_or(false, |v| v.is_ascii_digit()))
- .map(|v| v.split('.').collect());
- if let Some(v) = split_v {
- if v.len() >= 2 {
- let maybe_major = v[0].parse::<u32>();
- let maybe_minor = v[1].parse::<u32>();
- if let (Ok(major), Ok(minor)) = (maybe_major, maybe_minor) {
- return ClangVersion {
- parsed: Some((major, minor)),
- full: raw_v.clone(),
- };
- }
- }
- };
- ClangVersion {
- parsed: None,
- full: raw_v.clone(),
- }
-}
-
-/// Looks for the env var `var_${TARGET}`, and falls back to just `var` when it is not found.
-fn get_target_dependent_env_var(var: &str) -> Option<String> {
- if let Ok(target) = env::var("TARGET") {
- if let Ok(v) = env::var(&format!("{}_{}", var, target)) {
- return Some(v);
- }
- if let Ok(v) =
- env::var(&format!("{}_{}", var, target.replace('-', "_")))
- {
- return Some(v);
- }
- }
- env::var(var).ok()
-}
-
-/// A ParseCallbacks implementation that will act on file includes by echoing a rerun-if-changed
-/// line
-///
-/// When running inside a `build.rs` script, this can be used to make cargo invalidate the
-/// generated bindings whenever any of the files included from the header change:
-/// ```
-/// use bindgen::builder;
-/// let bindings = builder()
-/// .header("path/to/input/header")
-/// .parse_callbacks(Box::new(bindgen::CargoCallbacks))
-/// .generate();
-/// ```
-#[derive(Debug)]
-pub struct CargoCallbacks;
-
-impl callbacks::ParseCallbacks for CargoCallbacks {
- fn include_file(&self, filename: &str) {
- println!("cargo:rerun-if-changed={}", filename);
- }
-}
-
-/// Test command_line_flag function.
-#[test]
-fn commandline_flag_unit_test_function() {
- //Test 1
- let bindings = crate::builder();
- let command_line_flags = bindings.command_line_flags();
-
- let test_cases = vec![
- "--rust-target",
- "--no-derive-default",
- "--generate",
- "functions,types,vars,methods,constructors,destructors",
- ]
- .iter()
- .map(|&x| x.into())
- .collect::<Vec<String>>();
-
- assert!(test_cases.iter().all(|x| command_line_flags.contains(x)));
-
- //Test 2
- let bindings = crate::builder()
- .header("input_header")
- .allowlist_type("Distinct_Type")
- .allowlist_function("safe_function");
-
- let command_line_flags = bindings.command_line_flags();
- let test_cases = vec![
- "--rust-target",
- "input_header",
- "--no-derive-default",
- "--generate",
- "functions,types,vars,methods,constructors,destructors",
- "--allowlist-type",
- "Distinct_Type",
- "--allowlist-function",
- "safe_function",
- ]
- .iter()
- .map(|&x| x.into())
- .collect::<Vec<String>>();
- println!("{:?}", command_line_flags);
-
- assert!(test_cases.iter().all(|x| command_line_flags.contains(x)));
-}
-
-#[test]
-fn test_rust_to_clang_target() {
- assert_eq!(rust_to_clang_target("aarch64-apple-ios"), "arm64-apple-ios");
-}
-
-#[test]
-fn test_rust_to_clang_target_riscv() {
- assert_eq!(
- rust_to_clang_target("riscv64gc-unknown-linux-gnu"),
- "riscv64-unknown-linux-gnu"
- )
-}
diff --git a/src/log_stubs.rs b/src/log_stubs.rs
deleted file mode 100644
index 83159831..00000000
--- a/src/log_stubs.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-#![allow(unused)]
-
-macro_rules! log {
- (target: $target:expr, $lvl:expr, $($arg:tt)+) => {{
- let _ = $target;
- let _ = log!($lvl, $($arg)+);
- }};
- ($lvl:expr, $($arg:tt)+) => {{
- let _ = $lvl;
- let _ = format_args!($($arg)+);
- }};
-}
-macro_rules! error {
- (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
- ($($arg:tt)+) => { log!("", $($arg)+) };
-}
-macro_rules! warn {
- (target: $target:expr, $($arg:tt)*) => { log!(target: $target, "", $($arg)*) };
- ($($arg:tt)*) => { log!("", $($arg)*) };
-}
-macro_rules! info {
- (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
- ($($arg:tt)+) => { log!("", $($arg)+) };
-}
-macro_rules! debug {
- (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
- ($($arg:tt)+) => { log!("", $($arg)+) };
-}
-macro_rules! trace {
- (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
- ($($arg:tt)+) => { log!("", $($arg)+) };
-}
diff --git a/src/main.rs b/src/main.rs
deleted file mode 100644
index 50f3e714..00000000
--- a/src/main.rs
+++ /dev/null
@@ -1,109 +0,0 @@
-extern crate bindgen;
-#[cfg(feature = "logging")]
-extern crate env_logger;
-#[macro_use]
-#[cfg(feature = "logging")]
-extern crate log;
-extern crate clap;
-
-use bindgen::clang_version;
-use std::env;
-use std::panic;
-
-#[macro_use]
-#[cfg(not(feature = "logging"))]
-mod log_stubs;
-
-mod options;
-use crate::options::builder_from_flags;
-
-fn clang_version_check() {
- let version = clang_version();
- let expected_version = if cfg!(feature = "testing_only_libclang_9") {
- Some((9, 0))
- } else if cfg!(feature = "testing_only_libclang_5") {
- Some((5, 0))
- } else {
- None
- };
-
- info!(
- "Clang Version: {}, parsed: {:?}",
- version.full, version.parsed
- );
-
- if expected_version.is_some() {
- // assert_eq!(version.parsed, version.parsed);
- }
-}
-
-pub fn main() {
- #[cfg(feature = "logging")]
- env_logger::init();
-
- match builder_from_flags(env::args()) {
- Ok((builder, output, verbose)) => {
- clang_version_check();
- let builder_result = panic::catch_unwind(|| {
- builder.generate().expect("Unable to generate bindings")
- });
-
- if builder_result.is_err() {
- if verbose {
- print_verbose_err();
- }
- std::process::exit(1);
- }
-
- let bindings = builder_result.unwrap();
- bindings.write(output).expect("Unable to write output");
- }
- Err(error) => {
- println!("{}", error);
- std::process::exit(1);
- }
- };
-}
-
-fn print_verbose_err() {
- println!("Bindgen unexpectedly panicked");
- println!(
- "This may be caused by one of the known-unsupported \
- things (https://rust-lang.github.io/rust-bindgen/cpp.html), \
- please modify the bindgen flags to work around it as \
- described in https://rust-lang.github.io/rust-bindgen/cpp.html"
- );
- println!(
- "Otherwise, please file an issue at \
- https://github.com/rust-lang/rust-bindgen/issues/new"
- );
-}
-
-#[cfg(test)]
-mod test {
- fn build_flags_output_helper(builder: &bindgen::Builder) {
- let mut command_line_flags = builder.command_line_flags();
- command_line_flags.insert(0, "bindgen".to_string());
-
- let flags_quoted: Vec<String> = command_line_flags
- .iter()
- .map(|x| format!("{}", shlex::quote(x)))
- .collect();
- let flags_str = flags_quoted.join(" ");
- println!("{}", flags_str);
-
- let (builder, _output, _verbose) =
- crate::options::builder_from_flags(command_line_flags.into_iter())
- .unwrap();
- builder.generate().expect("failed to generate bindings");
- }
-
- #[test]
- fn commandline_multiple_headers() {
- let bindings = bindgen::Builder::default()
- .header("tests/headers/char.h")
- .header("tests/headers/func_ptr.h")
- .header("tests/headers/16-byte-alignment.h");
- build_flags_output_helper(&bindings);
- }
-}
diff --git a/src/options.rs b/src/options.rs
deleted file mode 100644
index 1025a36d..00000000
--- a/src/options.rs
+++ /dev/null
@@ -1,1092 +0,0 @@
-use bindgen::{
- builder, AliasVariation, Builder, CodegenConfig, EnumVariation,
- MacroTypeVariation, NonCopyUnionStyle, RustTarget,
- DEFAULT_ANON_FIELDS_PREFIX, RUST_TARGET_STRINGS,
-};
-use clap::{App, Arg};
-use std::fs::File;
-use std::io::{self, stderr, Error, ErrorKind, Write};
-use std::path::PathBuf;
-use std::str::FromStr;
-
-/// Construct a new [`Builder`](./struct.Builder.html) from command line flags.
-pub fn builder_from_flags<I>(
- args: I,
-) -> Result<(Builder, Box<dyn io::Write>, bool), io::Error>
-where
- I: Iterator<Item = String>,
-{
- let rust_target_help = format!(
- "Version of the Rust compiler to target. Valid options are: {:?}. Defaults to {:?}.",
- RUST_TARGET_STRINGS,
- String::from(RustTarget::default())
- );
-
- let matches = App::new("bindgen")
- .about("Generates Rust bindings from C/C++ headers.")
- .setting(clap::AppSettings::NoAutoVersion)
- .override_usage("bindgen [FLAGS] [OPTIONS] <header> -- <clang-args>...")
- .args(&[
- Arg::new("header")
- .help("C or C++ header file")
- .required_unless_present("V"),
- Arg::new("depfile")
- .long("depfile")
- .takes_value(true)
- .help("Path to write depfile to"),
- Arg::new("default-enum-style")
- .long("default-enum-style")
- .help("The default style of code used to generate enums.")
- .value_name("variant")
- .default_value("consts")
- .possible_values([
- "consts",
- "moduleconsts",
- "bitfield",
- "newtype",
- "rust",
- "rust_non_exhaustive",
- ])
- .multiple_occurrences(false),
- Arg::new("bitfield-enum")
- .long("bitfield-enum")
- .help(
- "Mark any enum whose name matches <regex> as a set of \
- bitfield flags.",
- )
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("newtype-enum")
- .long("newtype-enum")
- .help("Mark any enum whose name matches <regex> as a newtype.")
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("newtype-global-enum")
- .long("newtype-global-enum")
- .help("Mark any enum whose name matches <regex> as a global newtype.")
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("rustified-enum")
- .long("rustified-enum")
- .help("Mark any enum whose name matches <regex> as a Rust enum.")
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("constified-enum")
- .long("constified-enum")
- .help(
- "Mark any enum whose name matches <regex> as a series of \
- constants.",
- )
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("constified-enum-module")
- .long("constified-enum-module")
- .help(
- "Mark any enum whose name matches <regex> as a module of \
- constants.",
- )
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("default-macro-constant-type")
- .long("default-macro-constant-type")
- .help("The default signed/unsigned type for C macro constants.")
- .value_name("variant")
- .default_value("unsigned")
- .possible_values(["signed", "unsigned"])
- .multiple_occurrences(false),
- Arg::new("default-alias-style")
- .long("default-alias-style")
- .help("The default style of code used to generate typedefs.")
- .value_name("variant")
- .default_value("type_alias")
- .possible_values([
- "type_alias",
- "new_type",
- "new_type_deref",
- ])
- .multiple_occurrences(false),
- Arg::new("normal-alias")
- .long("normal-alias")
- .help(
- "Mark any typedef alias whose name matches <regex> to use \
- normal type aliasing.",
- )
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("new-type-alias")
- .long("new-type-alias")
- .help(
- "Mark any typedef alias whose name matches <regex> to have \
- a new type generated for it.",
- )
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("new-type-alias-deref")
- .long("new-type-alias-deref")
- .help(
- "Mark any typedef alias whose name matches <regex> to have \
- a new type with Deref and DerefMut to the inner type.",
- )
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("default-non-copy-union-style")
- .long("default-non-copy-union-style")
- .help(
- "The default style of code used to generate unions with \
- non-Copy members. Note that ManuallyDrop was first \
- stabilized in Rust 1.20.0.",
- )
- .value_name("style")
- .default_value("bindgen_wrapper")
- .possible_values([
- "bindgen_wrapper",
- "manually_drop",
- ])
- .multiple_occurrences(false),
- Arg::new("bindgen-wrapper-union")
- .long("bindgen-wrapper-union")
- .help(
- "Mark any union whose name matches <regex> and who has a \
- non-Copy member to use a bindgen-generated wrapper for \
- fields.",
- )
- .value_name("regex")
- .takes_value(true)
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("manually-drop-union")
- .long("manually-drop-union")
- .help(
- "Mark any union whose name matches <regex> and who has a \
- non-Copy member to use ManuallyDrop (stabilized in Rust \
- 1.20.0) for fields.",
- )
- .value_name("regex")
- .takes_value(true)
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("blocklist-type")
- .alias("blacklist-type")
- .long("blocklist-type")
- .help("Mark <type> as hidden.")
- .value_name("type")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("blocklist-function")
- .alias("blacklist-function")
- .long("blocklist-function")
- .help("Mark <function> as hidden.")
- .value_name("function")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("blocklist-item")
- .alias("blacklist-item")
- .long("blocklist-item")
- .help("Mark <item> as hidden.")
- .value_name("item")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("blocklist-file")
- .alias("blacklist-file")
- .long("blocklist-file")
- .help("Mark all contents of <path> as hidden.")
- .value_name("path")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("no-layout-tests")
- .long("no-layout-tests")
- .help("Avoid generating layout tests for any type."),
- Arg::new("no-derive-copy")
- .long("no-derive-copy")
- .help("Avoid deriving Copy on any type."),
- Arg::new("no-derive-debug")
- .long("no-derive-debug")
- .help("Avoid deriving Debug on any type."),
- Arg::new("no-derive-default")
- .long("no-derive-default")
- .hide(true)
- .help("Avoid deriving Default on any type."),
- Arg::new("impl-debug").long("impl-debug").help(
- "Create Debug implementation, if it can not be derived \
- automatically.",
- ),
- Arg::new("impl-partialeq")
- .long("impl-partialeq")
- .help(
- "Create PartialEq implementation, if it can not be derived \
- automatically.",
- ),
- Arg::new("with-derive-default")
- .long("with-derive-default")
- .help("Derive Default on any type."),
- Arg::new("with-derive-hash")
- .long("with-derive-hash")
- .help("Derive hash on any type."),
- Arg::new("with-derive-partialeq")
- .long("with-derive-partialeq")
- .help("Derive partialeq on any type."),
- Arg::new("with-derive-partialord")
- .long("with-derive-partialord")
- .help("Derive partialord on any type."),
- Arg::new("with-derive-eq")
- .long("with-derive-eq")
- .help(
- "Derive eq on any type. Enable this option also \
- enables --with-derive-partialeq",
- ),
- Arg::new("with-derive-ord")
- .long("with-derive-ord")
- .help(
- "Derive ord on any type. Enable this option also \
- enables --with-derive-partialord",
- ),
- Arg::new("no-doc-comments")
- .long("no-doc-comments")
- .help(
- "Avoid including doc comments in the output, see: \
- https://github.com/rust-lang/rust-bindgen/issues/426",
- ),
- Arg::new("no-recursive-allowlist")
- .long("no-recursive-allowlist")
- .alias("no-recursive-whitelist")
- .help(
- "Disable allowlisting types recursively. This will cause \
- bindgen to emit Rust code that won't compile! See the \
- `bindgen::Builder::allowlist_recursively` method's \
- documentation for details.",
- ),
- Arg::new("objc-extern-crate")
- .long("objc-extern-crate")
- .help("Use extern crate instead of use for objc."),
- Arg::new("generate-block")
- .long("generate-block")
- .help("Generate block signatures instead of void pointers."),
- Arg::new("block-extern-crate")
- .long("block-extern-crate")
- .help("Use extern crate instead of use for block."),
- Arg::new("distrust-clang-mangling")
- .long("distrust-clang-mangling")
- .help("Do not trust the libclang-provided mangling"),
- Arg::new("builtins").long("builtins").help(
- "Output bindings for builtin definitions, e.g. \
- __builtin_va_list.",
- ),
- Arg::new("ctypes-prefix")
- .long("ctypes-prefix")
- .help(
- "Use the given prefix before raw types instead of \
- ::std::os::raw.",
- )
- .value_name("prefix"),
- Arg::new("anon-fields-prefix")
- .long("anon-fields-prefix")
- .help("Use the given prefix for the anon fields.")
- .value_name("prefix")
- .default_value(DEFAULT_ANON_FIELDS_PREFIX),
- Arg::new("time-phases")
- .long("time-phases")
- .help("Time the different bindgen phases and print to stderr"),
- // All positional arguments after the end of options marker, `--`
- Arg::new("clang-args").last(true).multiple_occurrences(true),
- Arg::new("emit-clang-ast")
- .long("emit-clang-ast")
- .help("Output the Clang AST for debugging purposes."),
- Arg::new("emit-ir")
- .long("emit-ir")
- .help("Output our internal IR for debugging purposes."),
- Arg::new("emit-ir-graphviz")
- .long("emit-ir-graphviz")
- .help("Dump graphviz dot file.")
- .value_name("path"),
- Arg::new("enable-cxx-namespaces")
- .long("enable-cxx-namespaces")
- .help("Enable support for C++ namespaces."),
- Arg::new("disable-name-namespacing")
- .long("disable-name-namespacing")
- .help(
- "Disable namespacing via mangling, causing bindgen to \
- generate names like \"Baz\" instead of \"foo_bar_Baz\" \
- for an input name \"foo::bar::Baz\".",
- ),
- Arg::new("disable-nested-struct-naming")
- .long("disable-nested-struct-naming")
- .help(
- "Disable nested struct naming, causing bindgen to generate \
- names like \"bar\" instead of \"foo_bar\" for a nested \
- definition \"struct foo { struct bar { } b; };\"."
- ),
- Arg::new("disable-untagged-union")
- .long("disable-untagged-union")
- .help(
- "Disable support for native Rust unions.",
- ),
- Arg::new("disable-header-comment")
- .long("disable-header-comment")
- .help("Suppress insertion of bindgen's version identifier into generated bindings.")
- .multiple_occurrences(true),
- Arg::new("ignore-functions")
- .long("ignore-functions")
- .help(
- "Do not generate bindings for functions or methods. This \
- is useful when you only care about struct layouts.",
- ),
- Arg::new("generate")
- .long("generate")
- .help(
- "Generate only given items, split by commas. \
- Valid values are \"functions\",\"types\", \"vars\", \
- \"methods\", \"constructors\" and \"destructors\".",
- )
- .takes_value(true),
- Arg::new("ignore-methods")
- .long("ignore-methods")
- .help("Do not generate bindings for methods."),
- Arg::new("no-convert-floats")
- .long("no-convert-floats")
- .help("Do not automatically convert floats to f32/f64."),
- Arg::new("no-prepend-enum-name")
- .long("no-prepend-enum-name")
- .help("Do not prepend the enum name to constant or newtype variants."),
- Arg::new("no-include-path-detection")
- .long("no-include-path-detection")
- .help("Do not try to detect default include paths"),
- Arg::new("fit-macro-constant-types")
- .long("fit-macro-constant-types")
- .help("Try to fit macro constants into types smaller than u32/i32"),
- Arg::new("unstable-rust")
- .long("unstable-rust")
- .help("Generate unstable Rust code (deprecated; use --rust-target instead).")
- .multiple_occurrences(true), // FIXME: Pass legacy test suite
- Arg::new("opaque-type")
- .long("opaque-type")
- .help("Mark <type> as opaque.")
- .value_name("type")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("output")
- .short('o')
- .long("output")
- .help("Write Rust bindings to <output>.")
- .takes_value(true),
- Arg::new("raw-line")
- .long("raw-line")
- .help("Add a raw line of Rust code at the beginning of output.")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("module-raw-line")
- .long("module-raw-line")
- .help("Add a raw line of Rust code to a given module.")
- .multiple_occurrences(true)
- .number_of_values(2)
- .value_names(&["module-name", "raw-line"]),
- Arg::new("rust-target")
- .long("rust-target")
- .help(rust_target_help.as_ref())
- .takes_value(true),
- Arg::new("use-core")
- .long("use-core")
- .help("Use types from Rust core instead of std."),
- Arg::new("conservative-inline-namespaces")
- .long("conservative-inline-namespaces")
- .help(
- "Conservatively generate inline namespaces to avoid name \
- conflicts.",
- ),
- Arg::new("use-msvc-mangling")
- .long("use-msvc-mangling")
- .help("MSVC C++ ABI mangling. DEPRECATED: Has no effect."),
- Arg::new("allowlist-function")
- .long("allowlist-function")
- .alias("whitelist-function")
- .help(
- "Allowlist all the free-standing functions matching \
- <regex>. Other non-allowlisted functions will not be \
- generated.",
- )
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("generate-inline-functions")
- .long("generate-inline-functions")
- .help("Generate inline functions."),
- Arg::new("allowlist-type")
- .long("allowlist-type")
- .alias("whitelist-type")
- .help(
- "Only generate types matching <regex>. Other non-allowlisted types will \
- not be generated.",
- )
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("allowlist-var")
- .long("allowlist-var")
- .alias("whitelist-var")
- .help(
- "Allowlist all the free-standing variables matching \
- <regex>. Other non-allowlisted variables will not be \
- generated.",
- )
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("allowlist-file")
- .alias("allowlist-file")
- .long("allowlist-file")
- .help("Allowlist all contents of <path>.")
- .value_name("path")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("verbose")
- .long("verbose")
- .help("Print verbose error messages."),
- Arg::new("dump-preprocessed-input")
- .long("dump-preprocessed-input")
- .help(
- "Preprocess and dump the input header files to disk. \
- Useful when debugging bindgen, using C-Reduce, or when \
- filing issues. The resulting file will be named \
- something like `__bindgen.i` or `__bindgen.ii`.",
- ),
- Arg::new("no-record-matches")
- .long("no-record-matches")
- .help(
- "Do not record matching items in the regex sets. \
- This disables reporting of unused items.",
- ),
- Arg::new("size_t-is-usize")
- .long("size_t-is-usize")
- .help("Ignored - this is enabled by default.")
- .hidden(true),
- Arg::with_name("no-size_t-is-usize")
- .long("no-size_t-is-usize")
- .help("Do not bind size_t as usize (useful on platforms \
- where those types are incompatible)."),
- Arg::new("no-rustfmt-bindings")
- .long("no-rustfmt-bindings")
- .help("Do not format the generated bindings with rustfmt."),
- Arg::new("rustfmt-bindings")
- .long("rustfmt-bindings")
- .help(
- "Format the generated bindings with rustfmt. DEPRECATED: \
- --rustfmt-bindings is now enabled by default. Disable \
- with --no-rustfmt-bindings.",
- ),
- Arg::new("rustfmt-configuration-file")
- .long("rustfmt-configuration-file")
- .help(
- "The absolute path to the rustfmt configuration file. \
- The configuration file will be used for formatting the bindings. \
- This parameter is incompatible with --no-rustfmt-bindings.",
- )
- .value_name("path")
- .multiple_occurrences(false)
- .number_of_values(1),
- Arg::new("no-partialeq")
- .long("no-partialeq")
- .help("Avoid deriving PartialEq for types matching <regex>.")
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("no-copy")
- .long("no-copy")
- .help("Avoid deriving Copy for types matching <regex>.")
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("no-debug")
- .long("no-debug")
- .help("Avoid deriving Debug for types matching <regex>.")
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("no-default")
- .long("no-default")
- .help("Avoid deriving/implement Default for types matching <regex>.")
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("no-hash")
- .long("no-hash")
- .help("Avoid deriving Hash for types matching <regex>.")
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("must-use-type")
- .long("must-use-type")
- .help("Add #[must_use] annotation to types matching <regex>.")
- .value_name("regex")
- .multiple_occurrences(true)
- .number_of_values(1),
- Arg::new("enable-function-attribute-detection")
- .long("enable-function-attribute-detection")
- .help(
- "Enables detecting unexposed attributes in functions (slow).
- Used to generate #[must_use] annotations.",
- ),
- Arg::new("use-array-pointers-in-arguments")
- .long("use-array-pointers-in-arguments")
- .help("Use `*const [T; size]` instead of `*const T` for C arrays"),
- Arg::new("wasm-import-module-name")
- .long("wasm-import-module-name")
- .value_name("name")
- .help("The name to be used in a #[link(wasm_import_module = ...)] statement"),
- Arg::new("dynamic-loading")
- .long("dynamic-loading")
- .takes_value(true)
- .help("Use dynamic loading mode with the given library name."),
- Arg::new("dynamic-link-require-all")
- .long("dynamic-link-require-all")
- .help("Require successful linkage to all functions in the library."),
- Arg::new("respect-cxx-access-specs")
- .long("respect-cxx-access-specs")
- .help("Makes generated bindings `pub` only for items if the items are publically accessible in C++."),
- Arg::new("translate-enum-integer-types")
- .long("translate-enum-integer-types")
- .help("Always translate enum integer types to native Rust integer types."),
- Arg::new("c-naming")
- .long("c-naming")
- .help("Generate types with C style naming."),
- Arg::new("explicit-padding")
- .long("explicit-padding")
- .help("Always output explicit padding fields."),
- Arg::new("vtable-generation")
- .long("vtable-generation")
- .help("Enables generation of vtable functions."),
- Arg::new("sort-semantically")
- .long("sort-semantically")
- .help("Enables sorting of code generation in a predefined manner."),
- Arg::new("merge-extern-blocks")
- .long("merge-extern-blocks")
- .help("Deduplicates extern blocks."),
- Arg::new("V")
- .long("version")
- .help("Prints the version, and exits"),
- ]) // .args()
- .get_matches_from(args);
-
- let verbose = matches.is_present("verbose");
- if matches.is_present("V") {
- println!(
- "bindgen {}",
- option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")
- );
- if verbose {
- println!("Clang: {}", crate::clang_version().full);
- }
- std::process::exit(0);
- }
-
- let mut builder = builder();
-
- if let Some(header) = matches.value_of("header") {
- builder = builder.header(header);
- } else {
- return Err(Error::new(ErrorKind::Other, "Header not found"));
- }
-
- if matches.is_present("unstable-rust") {
- builder = builder.rust_target(RustTarget::Nightly);
- writeln!(
- &mut stderr(),
- "warning: the `--unstable-rust` option is deprecated"
- )
- .expect("Unable to write error message");
- }
-
- if let Some(rust_target) = matches.value_of("rust-target") {
- builder = builder.rust_target(RustTarget::from_str(rust_target)?);
- }
-
- if let Some(variant) = matches.value_of("default-enum-style") {
- builder = builder.default_enum_style(EnumVariation::from_str(variant)?)
- }
-
- if let Some(bitfields) = matches.values_of("bitfield-enum") {
- for regex in bitfields {
- builder = builder.bitfield_enum(regex);
- }
- }
-
- if let Some(newtypes) = matches.values_of("newtype-enum") {
- for regex in newtypes {
- builder = builder.newtype_enum(regex);
- }
- }
-
- if let Some(newtypes) = matches.values_of("newtype-global-enum") {
- for regex in newtypes {
- builder = builder.newtype_global_enum(regex);
- }
- }
-
- if let Some(rustifieds) = matches.values_of("rustified-enum") {
- for regex in rustifieds {
- builder = builder.rustified_enum(regex);
- }
- }
-
- if let Some(const_enums) = matches.values_of("constified-enum") {
- for regex in const_enums {
- builder = builder.constified_enum(regex);
- }
- }
-
- if let Some(constified_mods) = matches.values_of("constified-enum-module") {
- for regex in constified_mods {
- builder = builder.constified_enum_module(regex);
- }
- }
-
- if let Some(variant) = matches.value_of("default-macro-constant-type") {
- builder = builder
- .default_macro_constant_type(MacroTypeVariation::from_str(variant)?)
- }
-
- if let Some(variant) = matches.value_of("default-alias-style") {
- builder =
- builder.default_alias_style(AliasVariation::from_str(variant)?);
- }
-
- if let Some(type_alias) = matches.values_of("normal-alias") {
- for regex in type_alias {
- builder = builder.type_alias(regex);
- }
- }
-
- if let Some(new_type) = matches.values_of("new-type-alias") {
- for regex in new_type {
- builder = builder.new_type_alias(regex);
- }
- }
-
- if let Some(new_type_deref) = matches.values_of("new-type-alias-deref") {
- for regex in new_type_deref {
- builder = builder.new_type_alias_deref(regex);
- }
- }
-
- if let Some(variant) = matches.value_of("default-non-copy-union-style") {
- builder = builder.default_non_copy_union_style(
- NonCopyUnionStyle::from_str(variant)?,
- );
- }
-
- if let Some(bindgen_wrapper_union) =
- matches.values_of("bindgen-wrapper-union")
- {
- for regex in bindgen_wrapper_union {
- builder = builder.bindgen_wrapper_union(regex);
- }
- }
-
- if let Some(manually_drop_union) = matches.values_of("manually-drop-union")
- {
- for regex in manually_drop_union {
- builder = builder.manually_drop_union(regex);
- }
- }
-
- if let Some(hidden_types) = matches.values_of("blocklist-type") {
- for ty in hidden_types {
- builder = builder.blocklist_type(ty);
- }
- }
-
- if let Some(hidden_functions) = matches.values_of("blocklist-function") {
- for fun in hidden_functions {
- builder = builder.blocklist_function(fun);
- }
- }
-
- if let Some(hidden_identifiers) = matches.values_of("blocklist-item") {
- for id in hidden_identifiers {
- builder = builder.blocklist_item(id);
- }
- }
-
- if let Some(hidden_files) = matches.values_of("blocklist-file") {
- for file in hidden_files {
- builder = builder.blocklist_file(file);
- }
- }
-
- if matches.is_present("builtins") {
- builder = builder.emit_builtins();
- }
-
- if matches.is_present("no-layout-tests") {
- builder = builder.layout_tests(false);
- }
-
- if matches.is_present("no-derive-copy") {
- builder = builder.derive_copy(false);
- }
-
- if matches.is_present("no-derive-debug") {
- builder = builder.derive_debug(false);
- }
-
- if matches.is_present("impl-debug") {
- builder = builder.impl_debug(true);
- }
-
- if matches.is_present("impl-partialeq") {
- builder = builder.impl_partialeq(true);
- }
-
- if matches.is_present("with-derive-default") {
- builder = builder.derive_default(true);
- }
-
- if matches.is_present("with-derive-hash") {
- builder = builder.derive_hash(true);
- }
-
- if matches.is_present("with-derive-partialeq") {
- builder = builder.derive_partialeq(true);
- }
-
- if matches.is_present("with-derive-partialord") {
- builder = builder.derive_partialord(true);
- }
-
- if matches.is_present("with-derive-eq") {
- builder = builder.derive_eq(true);
- }
-
- if matches.is_present("with-derive-ord") {
- builder = builder.derive_ord(true);
- }
-
- if matches.is_present("no-derive-default") {
- builder = builder.derive_default(false);
- }
-
- if matches.is_present("no-prepend-enum-name") {
- builder = builder.prepend_enum_name(false);
- }
-
- if matches.is_present("no-include-path-detection") {
- builder = builder.detect_include_paths(false);
- }
-
- if matches.is_present("fit-macro-constant-types") {
- builder = builder.fit_macro_constants(true);
- }
-
- if matches.is_present("time-phases") {
- builder = builder.time_phases(true);
- }
-
- if matches.is_present("use-array-pointers-in-arguments") {
- builder = builder.array_pointers_in_arguments(true);
- }
-
- if let Some(wasm_import_name) = matches.value_of("wasm-import-module-name")
- {
- builder = builder.wasm_import_module_name(wasm_import_name);
- }
-
- if let Some(prefix) = matches.value_of("ctypes-prefix") {
- builder = builder.ctypes_prefix(prefix);
- }
-
- if let Some(prefix) = matches.value_of("anon-fields-prefix") {
- builder = builder.anon_fields_prefix(prefix);
- }
-
- if let Some(what_to_generate) = matches.value_of("generate") {
- let mut config = CodegenConfig::empty();
- for what in what_to_generate.split(',') {
- match what {
- "functions" => config.insert(CodegenConfig::FUNCTIONS),
- "types" => config.insert(CodegenConfig::TYPES),
- "vars" => config.insert(CodegenConfig::VARS),
- "methods" => config.insert(CodegenConfig::METHODS),
- "constructors" => config.insert(CodegenConfig::CONSTRUCTORS),
- "destructors" => config.insert(CodegenConfig::DESTRUCTORS),
- otherwise => {
- return Err(Error::new(
- ErrorKind::Other,
- format!("Unknown generate item: {}", otherwise),
- ));
- }
- }
- }
- builder = builder.with_codegen_config(config);
- }
-
- if matches.is_present("emit-clang-ast") {
- builder = builder.emit_clang_ast();
- }
-
- if matches.is_present("emit-ir") {
- builder = builder.emit_ir();
- }
-
- if let Some(path) = matches.value_of("emit-ir-graphviz") {
- builder = builder.emit_ir_graphviz(path);
- }
-
- if matches.is_present("enable-cxx-namespaces") {
- builder = builder.enable_cxx_namespaces();
- }
-
- if matches.is_present("enable-function-attribute-detection") {
- builder = builder.enable_function_attribute_detection();
- }
-
- if matches.is_present("disable-name-namespacing") {
- builder = builder.disable_name_namespacing();
- }
-
- if matches.is_present("disable-nested-struct-naming") {
- builder = builder.disable_nested_struct_naming();
- }
-
- if matches.is_present("disable-untagged-union") {
- builder = builder.disable_untagged_union();
- }
-
- if matches.is_present("disable-header-comment") {
- builder = builder.disable_header_comment();
- }
-
- if matches.is_present("ignore-functions") {
- builder = builder.ignore_functions();
- }
-
- if matches.is_present("ignore-methods") {
- builder = builder.ignore_methods();
- }
-
- if matches.is_present("no-convert-floats") {
- builder = builder.no_convert_floats();
- }
-
- if matches.is_present("no-doc-comments") {
- builder = builder.generate_comments(false);
- }
-
- if matches.is_present("no-recursive-allowlist") {
- builder = builder.allowlist_recursively(false);
- }
-
- if matches.is_present("objc-extern-crate") {
- builder = builder.objc_extern_crate(true);
- }
-
- if matches.is_present("generate-block") {
- builder = builder.generate_block(true);
- }
-
- if matches.is_present("block-extern-crate") {
- builder = builder.block_extern_crate(true);
- }
-
- if let Some(opaque_types) = matches.values_of("opaque-type") {
- for ty in opaque_types {
- builder = builder.opaque_type(ty);
- }
- }
-
- if let Some(lines) = matches.values_of("raw-line") {
- for line in lines {
- builder = builder.raw_line(line);
- }
- }
-
- if let Some(mut values) = matches.values_of("module-raw-line") {
- while let Some(module) = values.next() {
- let line = values.next().unwrap();
- builder = builder.module_raw_line(module, line);
- }
- }
-
- if matches.is_present("use-core") {
- builder = builder.use_core();
- }
-
- if matches.is_present("distrust-clang-mangling") {
- builder = builder.trust_clang_mangling(false);
- }
-
- if matches.is_present("conservative-inline-namespaces") {
- builder = builder.conservative_inline_namespaces();
- }
-
- if matches.is_present("generate-inline-functions") {
- builder = builder.generate_inline_functions(true);
- }
-
- if let Some(allowlist) = matches.values_of("allowlist-function") {
- for regex in allowlist {
- builder = builder.allowlist_function(regex);
- }
- }
-
- if let Some(allowlist) = matches.values_of("allowlist-type") {
- for regex in allowlist {
- builder = builder.allowlist_type(regex);
- }
- }
-
- if let Some(allowlist) = matches.values_of("allowlist-var") {
- for regex in allowlist {
- builder = builder.allowlist_var(regex);
- }
- }
-
- if let Some(hidden_files) = matches.values_of("allowlist-file") {
- for file in hidden_files {
- builder = builder.allowlist_file(file);
- }
- }
-
- if let Some(args) = matches.values_of("clang-args") {
- for arg in args {
- builder = builder.clang_arg(arg);
- }
- }
-
- let output = if let Some(path) = matches.value_of("output") {
- let file = File::create(path)?;
- if let Some(depfile) = matches.value_of("depfile") {
- builder = builder.depfile(path, depfile);
- }
- Box::new(io::BufWriter::new(file)) as Box<dyn io::Write>
- } else {
- if let Some(depfile) = matches.value_of("depfile") {
- builder = builder.depfile("-", depfile);
- }
- Box::new(io::BufWriter::new(io::stdout())) as Box<dyn io::Write>
- };
-
- if matches.is_present("dump-preprocessed-input") {
- builder.dump_preprocessed_input()?;
- }
-
- if matches.is_present("no-record-matches") {
- builder = builder.record_matches(false);
- }
-
- if matches.is_present("no-size_t-is-usize") {
- builder = builder.size_t_is_usize(false);
- }
-
- let no_rustfmt_bindings = matches.is_present("no-rustfmt-bindings");
- if no_rustfmt_bindings {
- builder = builder.rustfmt_bindings(false);
- }
-
- if let Some(path_str) = matches.value_of("rustfmt-configuration-file") {
- let path = PathBuf::from(path_str);
-
- if no_rustfmt_bindings {
- return Err(Error::new(
- ErrorKind::Other,
- "Cannot supply both --rustfmt-configuration-file and --no-rustfmt-bindings",
- ));
- }
-
- if !path.is_absolute() {
- return Err(Error::new(
- ErrorKind::Other,
- "--rustfmt-configuration--file needs to be an absolute path!",
- ));
- }
-
- if path.to_str().is_none() {
- return Err(Error::new(
- ErrorKind::Other,
- "--rustfmt-configuration-file contains non-valid UTF8 characters.",
- ));
- }
-
- builder = builder.rustfmt_configuration_file(Some(path));
- }
-
- if let Some(no_partialeq) = matches.values_of("no-partialeq") {
- for regex in no_partialeq {
- builder = builder.no_partialeq(regex);
- }
- }
-
- if let Some(no_copy) = matches.values_of("no-copy") {
- for regex in no_copy {
- builder = builder.no_copy(regex);
- }
- }
-
- if let Some(no_debug) = matches.values_of("no-debug") {
- for regex in no_debug {
- builder = builder.no_debug(regex);
- }
- }
-
- if let Some(no_default) = matches.values_of("no-default") {
- for regex in no_default {
- builder = builder.no_default(regex);
- }
- }
-
- if let Some(no_hash) = matches.values_of("no-hash") {
- for regex in no_hash {
- builder = builder.no_hash(regex);
- }
- }
-
- if let Some(must_use_type) = matches.values_of("must-use-type") {
- for regex in must_use_type {
- builder = builder.must_use_type(regex);
- }
- }
-
- if let Some(dynamic_library_name) = matches.value_of("dynamic-loading") {
- builder = builder.dynamic_library_name(dynamic_library_name);
- }
-
- if matches.is_present("dynamic-link-require-all") {
- builder = builder.dynamic_link_require_all(true);
- }
-
- if matches.is_present("respect-cxx-access-specs") {
- builder = builder.respect_cxx_access_specs(true);
- }
-
- if matches.is_present("translate-enum-integer-types") {
- builder = builder.translate_enum_integer_types(true);
- }
-
- if matches.is_present("c-naming") {
- builder = builder.c_naming(true);
- }
-
- if matches.is_present("explicit-padding") {
- builder = builder.explicit_padding(true);
- }
-
- if matches.is_present("vtable-generation") {
- builder = builder.vtable_generation(true);
- }
-
- if matches.is_present("sort-semantically") {
- builder = builder.sort_semantically(true);
- }
-
- if matches.is_present("merge-extern-blocks") {
- builder = builder.merge_extern_blocks(true);
- }
-
- Ok((builder, output, verbose))
-}
diff --git a/src/parse.rs b/src/parse.rs
deleted file mode 100644
index f60de431..00000000
--- a/src/parse.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-//! Common traits and types related to parsing our IR from Clang cursors.
-
-use crate::clang;
-use crate::ir::context::{BindgenContext, ItemId, TypeId};
-use crate::ir::ty::TypeKind;
-
-/// Not so much an error in the traditional sense, but a control flow message
-/// when walking over Clang's AST with a cursor.
-#[derive(Debug)]
-pub enum ParseError {
- /// Recurse down the current AST node's children.
- Recurse,
- /// Continue on to the next sibling AST node, or back up to the parent's
- /// siblings if we've exhausted all of this node's siblings (and so on).
- Continue,
-}
-
-/// The result of parsing a Clang AST node.
-#[derive(Debug)]
-pub enum ParseResult<T> {
- /// We've already resolved this item before, here is the extant `ItemId` for
- /// it.
- AlreadyResolved(ItemId),
-
- /// This is a newly parsed item. If the cursor is `Some`, it points to the
- /// AST node where the new `T` was declared.
- New(T, Option<clang::Cursor>),
-}
-
-/// An intermediate representation "sub-item" (i.e. one of the types contained
-/// inside an `ItemKind` variant) that can be parsed from a Clang cursor.
-pub trait ClangSubItemParser: Sized {
- /// Attempt to parse this type from the given cursor.
- ///
- /// The fact that is a reference guarantees it's held by the context, and
- /// allow returning already existing types.
- fn parse(
- cursor: clang::Cursor,
- context: &mut BindgenContext,
- ) -> Result<ParseResult<Self>, ParseError>;
-}
-
-/// An intermediate representation item that can be parsed from a Clang cursor.
-pub trait ClangItemParser: Sized {
- /// Parse this item from the given Clang cursor.
- fn parse(
- cursor: clang::Cursor,
- parent: Option<ItemId>,
- context: &mut BindgenContext,
- ) -> Result<ItemId, ParseError>;
-
- /// Parse this item from the given Clang type.
- fn from_ty(
- ty: &clang::Type,
- location: clang::Cursor,
- parent: Option<ItemId>,
- ctx: &mut BindgenContext,
- ) -> Result<TypeId, ParseError>;
-
- /// Identical to `from_ty`, but use the given `id` as the `ItemId` for the
- /// newly parsed item.
- fn from_ty_with_id(
- id: ItemId,
- ty: &clang::Type,
- location: clang::Cursor,
- parent: Option<ItemId>,
- ctx: &mut BindgenContext,
- ) -> Result<TypeId, ParseError>;
-
- /// Parse this item from the given Clang type, or if we haven't resolved all
- /// the other items this one depends on, an unresolved reference.
- fn from_ty_or_ref(
- ty: clang::Type,
- location: clang::Cursor,
- parent_id: Option<ItemId>,
- context: &mut BindgenContext,
- ) -> TypeId;
-
- /// Identical to `from_ty_or_ref`, but use the given `potential_id` as the
- /// `ItemId` for the newly parsed item.
- fn from_ty_or_ref_with_id(
- potential_id: ItemId,
- ty: clang::Type,
- location: clang::Cursor,
- parent_id: Option<ItemId>,
- context: &mut BindgenContext,
- ) -> TypeId;
-
- /// Create a named template type.
- fn type_param(
- with_id: Option<ItemId>,
- location: clang::Cursor,
- ctx: &mut BindgenContext,
- ) -> Option<TypeId>;
-
- /// Create a builtin type.
- fn builtin_type(
- kind: TypeKind,
- is_const: bool,
- context: &mut BindgenContext,
- ) -> TypeId;
-}
diff --git a/src/regex_set.rs b/src/regex_set.rs
deleted file mode 100644
index 9262c4ee..00000000
--- a/src/regex_set.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-//! A type that represents the union of a set of regular expressions.
-
-use regex::RegexSet as RxSet;
-use std::cell::Cell;
-
-/// A dynamic set of regular expressions.
-#[derive(Clone, Debug, Default)]
-pub struct RegexSet {
- items: Vec<String>,
- /// Whether any of the items in the set was ever matched. The length of this
- /// vector is exactly the length of `items`.
- matched: Vec<Cell<bool>>,
- set: Option<RxSet>,
- /// Whether we should record matching items in the `matched` vector or not.
- record_matches: bool,
-}
-
-impl RegexSet {
- /// Is this set empty?
- pub fn is_empty(&self) -> bool {
- self.items.is_empty()
- }
-
- /// Insert a new regex into this set.
- pub fn insert<S>(&mut self, string: S)
- where
- S: AsRef<str>,
- {
- self.items.push(string.as_ref().to_owned());
- self.matched.push(Cell::new(false));
- self.set = None;
- }
-
- /// Returns slice of String from its field 'items'
- pub fn get_items(&self) -> &[String] {
- &self.items[..]
- }
-
- /// Returns an iterator over regexes in the set which didn't match any
- /// strings yet.
- pub fn unmatched_items(&self) -> impl Iterator<Item = &String> {
- self.items.iter().enumerate().filter_map(move |(i, item)| {
- if !self.record_matches || self.matched[i].get() {
- return None;
- }
-
- Some(item)
- })
- }
-
- /// Construct a RegexSet from the set of entries we've accumulated.
- ///
- /// Must be called before calling `matches()`, or it will always return
- /// false.
- pub fn build(&mut self, record_matches: bool) {
- let items = self.items.iter().map(|item| format!("^{}$", item));
- self.record_matches = record_matches;
- self.set = match RxSet::new(items) {
- Ok(x) => Some(x),
- Err(e) => {
- warn!("Invalid regex in {:?}: {:?}", self.items, e);
- None
- }
- }
- }
-
- /// Does the given `string` match any of the regexes in this set?
- pub fn matches<S>(&self, string: S) -> bool
- where
- S: AsRef<str>,
- {
- let s = string.as_ref();
- let set = match self.set {
- Some(ref set) => set,
- None => return false,
- };
-
- if !self.record_matches {
- return set.is_match(s);
- }
-
- let matches = set.matches(s);
- if !matches.matched_any() {
- return false;
- }
- for i in matches.iter() {
- self.matched[i].set(true);
- }
-
- true
- }
-}
diff --git a/src/time.rs b/src/time.rs
deleted file mode 100644
index c13a640c..00000000
--- a/src/time.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-use std::io::{self, Write};
-use std::time::{Duration, Instant};
-
-/// RAII timer to measure how long phases take.
-#[derive(Debug)]
-pub struct Timer<'a> {
- output: bool,
- name: &'a str,
- start: Instant,
-}
-
-impl<'a> Timer<'a> {
- /// Creates a Timer with the given name, and starts it. By default,
- /// will print to stderr when it is `drop`'d
- pub fn new(name: &'a str) -> Self {
- Timer {
- output: true,
- name,
- start: Instant::now(),
- }
- }
-
- /// Sets whether or not the Timer will print a message
- /// when it is dropped.
- pub fn with_output(mut self, output: bool) -> Self {
- self.output = output;
- self
- }
-
- /// Returns the time elapsed since the timer's creation
- pub fn elapsed(&self) -> Duration {
- Instant::now() - self.start
- }
-
- fn print_elapsed(&mut self) {
- if self.output {
- let elapsed = self.elapsed();
- let time = (elapsed.as_secs() as f64) * 1e3 +
- (elapsed.subsec_nanos() as f64) / 1e6;
- let stderr = io::stderr();
- // Arbitrary output format, subject to change.
- writeln!(stderr.lock(), " time: {:>9.3} ms.\t{}", time, self.name)
- .expect("timer write should not fail");
- }
- }
-}
-
-impl<'a> Drop for Timer<'a> {
- fn drop(&mut self) {
- self.print_elapsed();
- }
-}