diff options
Diffstat (limited to 'src')
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(¶m.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(¤t).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(); - } -} |