bindgen-0.71.1/.cargo_vcs_info.json0000644000000001450000000000100125300ustar { "git": { "sha1": "af7fd38d5e80514406fb6a8bba2d407d252c30b9" }, "path_in_vcs": "bindgen" }bindgen-0.71.1/Cargo.toml0000644000000057750000000000100105440ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.70.0" name = "bindgen" version = "0.71.1" authors = [ "Jyun-Yan You ", "Emilio Cobos Álvarez ", "Nick Fitzgerald ", "The Servo project developers", ] build = "build.rs" autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Automatically generates Rust FFI bindings to C and C++ libraries." homepage = "https://rust-lang.github.io/rust-bindgen/" documentation = "https://docs.rs/bindgen" readme = "README.md" keywords = [ "bindings", "ffi", "code-generation", ] categories = [ "external-ffi-bindings", "development-tools::ffi", ] license = "BSD-3-Clause" repository = "https://github.com/rust-lang/rust-bindgen" [package.metadata.docs.rs] features = ["experimental"] [package.metadata.release] pre-release-hook = [ "../node_modules/doctoc/doctoc.js", "../CHANGELOG.md", ] release = true [[package.metadata.release.pre-release-replacements]] file = "../CHANGELOG.md" replace = """ # Unreleased ## Added ## Changed ## Removed ## Fixed ## Security # {{version}} ({{date}})""" search = "# Unreleased" [lib] name = "bindgen" path = "lib.rs" [dependencies.annotate-snippets] version = "0.11.4" optional = true [dependencies.bitflags] version = "2.2.1" [dependencies.cexpr] version = "0.6" [dependencies.clang-sys] version = "1" features = ["clang_11_0"] [dependencies.clap] version = "4" features = ["derive"] optional = true [dependencies.clap_complete] version = "4" optional = true [dependencies.itertools] version = ">=0.10,<0.14" default-features = false [dependencies.log] version = "0.4" optional = true [dependencies.prettyplease] version = "0.2.7" features = ["verbatim"] optional = true [dependencies.proc-macro2] version = "1" [dependencies.quote] version = "1" default-features = false [dependencies.regex] version = "1.5.3" features = [ "std", "unicode-perl", ] default-features = false [dependencies.rustc-hash] version = "2.1.0" [dependencies.shlex] version = "1" [dependencies.syn] version = "2.0" features = [ "full", "extra-traits", "visit-mut", ] [features] __cli = [ "dep:clap", "dep:clap_complete", ] __testing_only_extra_assertions = [] __testing_only_libclang_16 = [] __testing_only_libclang_9 = [] default = [ "logging", "prettyplease", "runtime", ] experimental = ["dep:annotate-snippets"] logging = ["dep:log"] runtime = ["clang-sys/runtime"] static = ["clang-sys/static"] which-rustfmt = [] [lints.clippy] [lints.rust] bindgen-0.71.1/Cargo.toml.orig000064400000000000000000000047121046102023000142130ustar 00000000000000lints.workspace = true [package] authors = [ "Jyun-Yan You ", "Emilio Cobos Álvarez ", "Nick Fitzgerald ", "The Servo project developers", ] description = "Automatically generates Rust FFI bindings to C and C++ libraries." keywords = ["bindings", "ffi", "code-generation"] categories = ["external-ffi-bindings", "development-tools::ffi"] license = "BSD-3-Clause" name = "bindgen" readme = "../README.md" repository = "https://github.com/rust-lang/rust-bindgen" documentation = "https://docs.rs/bindgen" homepage = "https://rust-lang.github.io/rust-bindgen/" version = "0.71.1" build = "build.rs" rust-version.workspace = true edition.workspace = true [lib] name = "bindgen" path = "lib.rs" [dependencies] annotate-snippets = { workspace = true, optional = true } bitflags.workspace = true cexpr.workspace = true clang-sys = { workspace = true, features = ["clang_11_0"] } clap = { workspace = true, features = ["derive"], optional = true } clap_complete = { workspace = true, optional = true } itertools = { workspace = true } log = { workspace = true, optional = true } prettyplease = { workspace = true, optional = true, features = ["verbatim"] } proc-macro2.workspace = true quote.workspace = true regex = { workspace = true, features = ["std", "unicode-perl"] } rustc-hash.workspace = true shlex.workspace = true syn = { workspace = true, features = ["full", "extra-traits", "visit-mut"] } [features] default = ["logging", "prettyplease", "runtime"] logging = ["dep:log"] static = ["clang-sys/static"] runtime = ["clang-sys/runtime"] # This feature is no longer used for anything and should be removed in bindgen 0.70 which-rustfmt = [] experimental = ["dep:annotate-snippets"] ## The following features are for internal use and they shouldn't be used if ## you're not hacking on bindgen # Features used by `bindgen-cli` __cli = ["dep:clap", "dep:clap_complete"] # Features used for CI testing __testing_only_extra_assertions = [] __testing_only_libclang_9 = [] __testing_only_libclang_16 = [] [package.metadata.docs.rs] features = ["experimental"] [package.metadata.release] release = true pre-release-hook = ["../node_modules/doctoc/doctoc.js", "../CHANGELOG.md"] # Add version and date to changelog file [[package.metadata.release.pre-release-replacements]] file = "../CHANGELOG.md" search = "# Unreleased" replace = "# Unreleased\n## Added\n## Changed\n## Removed\n## Fixed\n## Security\n\n# {{version}} ({{date}})" bindgen-0.71.1/LICENSE000064400000000000000000000027501046102023000123310ustar 00000000000000BSD 3-Clause License Copyright (c) 2013, Jyun-Yan You All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. bindgen-0.71.1/README.md000064400000000000000000000063421046102023000126040ustar 00000000000000[![crates.io](https://img.shields.io/crates/v/bindgen.svg)](https://crates.io/crates/bindgen) [![docs.rs](https://docs.rs/bindgen/badge.svg)](https://docs.rs/bindgen/) # `bindgen` **`bindgen` automatically generates Rust FFI bindings to C (and some C++) libraries.** For example, given the C header `doggo.h`: ```c typedef struct Doggo { int many; char wow; } Doggo; void eleven_out_of_ten_majestic_af(Doggo* pupper); ``` `bindgen` produces Rust FFI code allowing you to call into the `doggo` library's functions and use its types: ```rust /* automatically generated by rust-bindgen 0.99.9 */ #[repr(C)] pub struct Doggo { pub many: ::std::os::raw::c_int, pub wow: ::std::os::raw::c_char, } extern "C" { pub fn eleven_out_of_ten_majestic_af(pupper: *mut Doggo); } ``` ## Users Guide [📚 Read the `bindgen` users guide here! 📚](https://rust-lang.github.io/rust-bindgen) ## MSRV The `bindgen` minimum supported Rust version is **1.70.0**. The `bindgen-cli` minimum supported Rust version is **1.70.0**. No MSRV bump policy has been established yet, so MSRV may increase in any release. The MSRV is the minimum Rust version that can be used to *compile* each crate. However, `bindgen` and `bindgen-cli` can generate bindings that are compatible with Rust versions below the current MSRV. Most of the time, the `bindgen-cli` crate will have a more recent MSRV than `bindgen` as crates such as `clap` require it. ## API Reference [API reference documentation is on docs.rs](https://docs.rs/bindgen) ## Environment Variables In addition to the [library API](https://docs.rs/bindgen) and [executable command-line API][bindgen-cmdline], `bindgen` can be controlled through environment variables. End-users should set these environment variables to modify `bindgen`'s behavior without modifying the source code of direct consumers of `bindgen`. - `BINDGEN_EXTRA_CLANG_ARGS`: extra arguments to pass to `clang` - Arguments are whitespace-separated - Use shell-style quoting to pass through whitespace - Examples: - Specify alternate sysroot: `--sysroot=/path/to/sysroot` - Add include search path with spaces: `-I"/path/with spaces"` - `BINDGEN_EXTRA_CLANG_ARGS_`: similar to `BINDGEN_EXTRA_CLANG_ARGS`, but used to set per-target arguments to pass to clang. Useful to set system include directories in a target-specific way in cross-compilation environments with multiple targets. Has precedence over `BINDGEN_EXTRA_CLANG_ARGS`. Additionally, `bindgen` uses `libclang` to parse C and C++ header files. To modify how `bindgen` searches for `libclang`, see the [`clang-sys` documentation][clang-sys-env]. For more details on how `bindgen` uses `libclang`, see the [`bindgen` users guide][bindgen-book-clang]. ## Releases We don't follow a specific release calendar, but if you need a release please file an issue requesting that (ping `@emilio` for increased effectiveness). ## Contributing [See `CONTRIBUTING.md` for hacking on `bindgen`!](./CONTRIBUTING.md) [bindgen-cmdline]: https://rust-lang.github.io/rust-bindgen/command-line-usage.html [clang-sys-env]: https://github.com/KyleMayes/clang-sys#environment-variables [bindgen-book-clang]: https://rust-lang.github.io/rust-bindgen/requirements.html#clang bindgen-0.71.1/build.rs000064400000000000000000000020111046102023000127570ustar 00000000000000use std::env; use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; fn main() { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let mut dst = File::create(Path::new(&out_dir).join("host-target.txt")).unwrap(); dst.write_all(env::var("TARGET").unwrap().as_bytes()) .unwrap(); // On behalf of clang_sys, rebuild ourselves if important configuration // variables change, to ensure that bindings get rebuilt if the // underlying libclang changes. println!("cargo:rerun-if-env-changed=LLVM_CONFIG_PATH"); println!("cargo:rerun-if-env-changed=LIBCLANG_PATH"); println!("cargo:rerun-if-env-changed=LIBCLANG_STATIC_PATH"); println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS"); println!( "cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_{}", env::var("TARGET").unwrap() ); println!( "cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_{}", env::var("TARGET").unwrap().replace('-', "_") ); } bindgen-0.71.1/callbacks.rs000064400000000000000000000223421046102023000136100ustar 00000000000000//! 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; /// An enum to allow ignoring parsing of macros. #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] 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] Default, } /// A trait to allow configuring different kinds of types in different /// situations. pub trait ParseCallbacks: fmt::Debug { #[cfg(feature = "__cli")] #[doc(hidden)] fn cli_args(&self) -> Vec { vec![] } /// This function will be run on every macro that is identified. fn will_parse_macro(&self, _name: &str) -> MacroParsingBehavior { MacroParsingBehavior::Default } /// This function will run for every extern variable and function. The returned value determines /// the name visible in the bindings. fn generated_name_override( &self, _item_info: ItemInfo<'_>, ) -> Option { None } /// This function will run for every extern variable and function. The returned value determines /// the link name in the bindings. fn generated_link_name_override( &self, _item_info: ItemInfo<'_>, ) -> Option { None } /// 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 { 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 { 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 { None } /// Allows to rename an item, replacing `_original_item_name`. fn item_name(&self, _original_item_name: &str) -> Option { None } /// This will be called on every header filename passed to (`Builder::header`)[`crate::Builder::header`]. fn header_file(&self, _filename: &str) {} /// 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 every time `bindgen` reads an environment variable whether it has any /// content or not. fn read_env_var(&self, _key: &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 { 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, _info: &DeriveInfo<'_>) -> Vec { vec![] } /// Provide a list of custom attributes. /// /// If no additional attributes are wanted, this function should return an /// empty `Vec`. fn add_attributes(&self, _info: &AttributeInfo<'_>) -> Vec { vec![] } /// Process a source code comment. fn process_comment(&self, _comment: &str) -> Option { None } /// Potentially override the visibility of a composite type field. /// /// Caution: This allows overriding standard C++ visibility inferred by /// `respect_cxx_access_specs`. fn field_visibility( &self, _info: FieldInfo<'_>, ) -> Option { None } /// Process a function name that as exactly one `va_list` argument /// to be wrapped as a variadic function with the wrapped static function /// feature. /// /// The returned string is new function name. #[cfg(feature = "experimental")] fn wrap_as_variadic_fn(&self, _name: &str) -> Option { None } /// This will get called everytime an item (currently struct, union, and alias) is found with some information about it fn new_item_found(&self, _id: DiscoveredItemId, _item: DiscoveredItem) {} // TODO add callback for ResolvedTypeRef } /// An identifier for a discovered item. Used to identify an aliased type (see [`DiscoveredItem::Alias`]) #[derive(Ord, PartialOrd, PartialEq, Eq, Hash, Debug, Clone, Copy)] pub struct DiscoveredItemId(usize); impl DiscoveredItemId { /// Constructor pub fn new(value: usize) -> Self { Self(value) } } /// Struct passed to [`ParseCallbacks::new_item_found`] containing information about discovered /// items (struct, union, and alias) #[derive(Debug, Hash, Clone, Ord, PartialOrd, Eq, PartialEq)] pub enum DiscoveredItem { /// Represents a struct with its original name in C and its generated binding name Struct { /// The original name (learnt from C) of the structure /// Can be None if the union is anonymous. original_name: Option, /// The name of the generated binding final_name: String, }, /// Represents a union with its original name in C and its generated binding name Union { /// The original name (learnt from C) of the structure. /// Can be None if the union is anonymous. original_name: Option, /// The name of the generated binding final_name: String, }, /// Represents an alias like a typedef /// ```c /// typedef struct MyStruct { /// ... /// } StructAlias; /// ``` /// Here, the name of the alias is `StructAlias` and it's an alias for `MyStruct` Alias { /// The name of the alias in C (`StructAlias`) alias_name: String, /// The identifier of the discovered type alias_for: DiscoveredItemId, }, // functions, modules, etc. } /// Relevant information about a type to which new derive attributes will be added using /// [`ParseCallbacks::add_derives`]. #[derive(Debug)] #[non_exhaustive] pub struct DeriveInfo<'a> { /// The name of the type. pub name: &'a str, /// The kind of the type. pub kind: TypeKind, } /// Relevant information about a type to which new attributes will be added using /// [`ParseCallbacks::add_attributes`]. #[derive(Debug)] #[non_exhaustive] pub struct AttributeInfo<'a> { /// The name of the type. pub name: &'a str, /// The kind of the type. pub kind: TypeKind, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] /// The kind of the current type. pub enum TypeKind { /// The type is a Rust `struct`. Struct, /// The type is a Rust `enum`. Enum, /// The type is a Rust `union`. Union, } /// A struct providing information about the item being passed to [`ParseCallbacks::generated_name_override`]. #[non_exhaustive] pub struct ItemInfo<'a> { /// The name of the item pub name: &'a str, /// The kind of item pub kind: ItemKind, } /// An enum indicating the kind of item for an `ItemInfo`. #[non_exhaustive] pub enum ItemKind { /// A Function Function, /// A Variable Var, } /// Relevant information about a field for which visibility can be determined using /// [`ParseCallbacks::field_visibility`]. #[derive(Debug)] #[non_exhaustive] pub struct FieldInfo<'a> { /// The name of the type. pub type_name: &'a str, /// The name of the field. pub field_name: &'a str, /// The name of the type of the field. pub field_type_name: Option<&'a str>, } bindgen-0.71.1/clang.rs000064400000000000000000002241051046102023000127560ustar 00000000000000//! A higher level Clang API built on top of the generated bindings in the //! `clang_sys` module. #![allow(non_upper_case_globals, dead_code)] #![deny(clippy::missing_docs_in_private_items)] use crate::ir::context::BindgenContext; use clang_sys::*; use std::cmp; use std::ffi::{CStr, CString}; use std::fmt; use std::fs::OpenOptions; 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::sync::OnceLock; 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(crate) struct Attribute { name: &'static [u8], kind: Option, token_kind: CXTokenKind, } impl Attribute { /// A `warn_unused_result` attribute. pub(crate) 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(crate) const NO_RETURN: Self = Self { name: b"_Noreturn", kind: None, token_kind: CXToken_Keyword, }; /// A `[[noreturn]]` attribute. pub(crate) 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(crate) 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(crate) fn usr(&self) -> Option { 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(crate) fn is_declaration(&self) -> bool { unsafe { clang_isDeclaration(self.kind()) != 0 } } /// Is this cursor's referent an anonymous record or so? pub(crate) fn is_anonymous(&self) -> bool { unsafe { clang_Cursor_isAnonymous(self.x) != 0 } } /// Get this cursor's referent's spelling. pub(crate) 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(crate) fn display_name(&self) -> String { unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) } } /// Get the mangled name of this cursor's referent. pub(crate) 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(crate) fn cxx_manglings(&self) -> Result, ()> { 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(crate) 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(crate) 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(crate) fn fallible_semantic_parent(&self) -> Option { 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(crate) 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(crate) fn num_template_args(&self) -> Option { // 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 { None } else { canonical.num_template_args() } }) } /// 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(crate) 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(crate) 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(crate) 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(crate) 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(crate) fn kind(&self) -> CXCursorKind { self.x.kind } /// Returns true if the cursor is a definition pub(crate) fn is_definition(&self) -> bool { unsafe { clang_isCursorDefinition(self.x) != 0 } } /// Is the referent a template specialization? pub(crate) 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(crate) 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(crate) 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(crate) 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(crate) 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(crate) fn is_valid(&self) -> bool { unsafe { clang_isInvalid(self.kind()) == 0 } } /// Get the source location for the referent. pub(crate) fn location(&self) -> SourceLocation { unsafe { SourceLocation { x: clang_getCursorLocation(self.x), } } } /// Get the source location range for the referent. pub(crate) fn extent(&self) -> CXSourceRange { unsafe { clang_getCursorExtent(self.x) } } /// Get the raw declaration comment for this referent, if one exists. pub(crate) fn raw_comment(&self) -> Option { 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(crate) fn comment(&self) -> Comment { unsafe { Comment { x: clang_Cursor_getParsedComment(self.x), } } } /// Get the referent's type. pub(crate) 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(crate) fn definition(&self) -> Option { 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(crate) fn referenced(&self) -> Option { 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(crate) 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(crate) fn specialized(&self) -> Option { 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(crate) 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(crate) fn visit(&self, mut visitor: Visitor) where Visitor: FnMut(Cursor) -> CXChildVisitResult, { let data = &mut visitor as *mut Visitor; unsafe { clang_visitChildren(self.x, visit_children::, data.cast()); } } /// Traverse all of this cursor's children, sorted by where they appear in source code. /// /// Call the given function on each AST node traversed. pub(crate) fn visit_sorted( &self, ctx: &mut BindgenContext, mut visitor: Visitor, ) where Visitor: FnMut(&mut BindgenContext, Cursor), { // FIXME(#2556): The current source order stuff doesn't account well for different levels // of includes, or includes that show up at the same byte offset because they are passed in // via CLI. const SOURCE_ORDER_ENABLED: bool = false; if !SOURCE_ORDER_ENABLED { return self.visit(|c| { visitor(ctx, c); CXChildVisit_Continue }); } let mut children = self.collect_children(); for child in &children { if child.kind() == CXCursor_InclusionDirective { if let Some(included_file) = child.get_included_file_name() { let location = child.location(); let (source_file, _, _, offset) = location.location(); if let Some(source_file) = source_file.name() { ctx.add_include(source_file, included_file, offset); } } } } children .sort_by(|child1, child2| child1.cmp_by_source_order(child2, ctx)); for child in children { visitor(ctx, child); } } /// Compare source order of two cursors, considering `#include` directives. /// /// Built-in items provided by the compiler (which don't have a source file), /// are sorted first. Remaining files are sorted by their position in the source file. /// If the items' source files differ, they are sorted by the position of the first /// `#include` for their source file. If no source files are included, `None` is returned. fn cmp_by_source_order( &self, other: &Self, ctx: &BindgenContext, ) -> cmp::Ordering { let (file, _, _, offset) = self.location().location(); let (other_file, _, _, other_offset) = other.location().location(); let (file, other_file) = match (file.name(), other_file.name()) { (Some(file), Some(other_file)) => (file, other_file), // Built-in definitions should come first. (Some(_), None) => return cmp::Ordering::Greater, (None, Some(_)) => return cmp::Ordering::Less, (None, None) => return cmp::Ordering::Equal, }; if file == other_file { // Both items are in the same source file, compare by byte offset. return offset.cmp(&other_offset); } let include_location = ctx.included_file_location(&file); let other_include_location = ctx.included_file_location(&other_file); match (include_location, other_include_location) { (Some((file2, offset2)), _) if file2 == other_file => { offset2.cmp(&other_offset) } (Some(_), None) => cmp::Ordering::Greater, (_, Some((other_file2, other_offset2))) if file == other_file2 => { offset.cmp(&other_offset2) } (None, Some(_)) => cmp::Ordering::Less, (Some((file2, offset2)), Some((other_file2, other_offset2))) => { if file2 == other_file2 { offset2.cmp(&other_offset2) } else { cmp::Ordering::Equal } } (None, None) => cmp::Ordering::Equal, } } /// Collect all of this cursor's children into a vec and return them. pub(crate) fn collect_children(&self) -> Vec { let mut children = vec![]; self.visit(|c| { children.push(c); CXChildVisit_Continue }); children } /// Does this cursor have any children? pub(crate) 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(crate) 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(crate) 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(crate) fn is_inlined_function(&self) -> bool { unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 } } /// Is the referent a defaulted function? pub(crate) fn is_defaulted_function(&self) -> bool { unsafe { clang_CXXMethod_isDefaulted(self.x) != 0 } } /// Is the referent a deleted function? pub(crate) 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(crate) 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(crate) fn bit_width_expr(&self) -> Option { 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(crate) fn bit_width(&self) -> Option { // 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(crate) fn enum_type(&self) -> Option { 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(crate) fn enum_val_boolean(&self) -> Option { 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(crate) fn enum_val_signed(&self) -> Option { unsafe { if self.kind() == CXCursor_EnumConstantDecl { #[allow(clippy::unnecessary_cast)] 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(crate) fn enum_val_unsigned(&self) -> Option { unsafe { if self.kind() == CXCursor_EnumConstantDecl { #[allow(clippy::unnecessary_cast)] Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64) } else { None } } } /// Does this cursor have the given attributes? pub(crate) fn has_attrs( &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 == Some(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(crate) fn typedef_type(&self) -> Option { 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(crate) fn linkage(&self) -> CXLinkageKind { unsafe { clang_getCursorLinkage(self.x) } } /// Get the visibility of this cursor's referent. pub(crate) 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(crate) fn args(&self) -> Option> { // 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(crate) fn num_args(&self) -> Result { 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(crate) fn access_specifier(&self) -> CX_CXXAccessSpecifier { unsafe { clang_getCXXAccessSpecifier(self.x) } } /// Is the cursor's referent publicly accessible in C++? /// /// Returns true if `self.access_specifier()` is `CX_CXXPublic` or /// `CX_CXXInvalidAccessSpecifier`. pub(crate) 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(crate) fn is_mutable_field(&self) -> bool { unsafe { clang_CXXField_isMutable(self.x) != 0 } } /// Get the offset of the field represented by the Cursor. pub(crate) fn offset_of_field(&self) -> Result { 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(crate) 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(crate) 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(crate) 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(crate) 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(crate) fn is_virtual_base(&self) -> bool { unsafe { clang_isVirtualBase(self.x) != 0 } } /// Try to evaluate this cursor. pub(crate) fn evaluate(&self) -> Option { EvalResult::new(*self) } /// Return the result type for this cursor pub(crate) fn ret_type(&self) -> Option { 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(crate) fn tokens(&self) -> RawTokens { RawTokens::new(self) } /// Gets the tokens that correspond to that cursor as `cexpr` tokens. pub(crate) fn cexpr_tokens(self) -> Vec { 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(crate) fn get_included_file_name(&self) -> Option { let file = unsafe { clang_getIncludedFile(self.x) }; if file.is_null() { None } else { Some(unsafe { cxstring_into_string(clang_getFileName(file)) }) } } /// Is this cursor's referent a namespace that is inline? pub(crate) fn is_inline_namespace(&self) -> bool { unsafe { clang_Cursor_isInlineNamespace(self.x) != 0 } } } /// A struct that owns the tokenizer result from a given cursor. pub(crate) 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(crate) fn iter(&self) -> ClangTokenIterator { ClangTokenIterator { tu: self.tu, raw: self.as_slice().iter(), } } } impl Drop for RawTokens<'_> { 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(crate) struct ClangToken { spelling: CXString, /// The extent of the token. This is the same as the relevant member from /// `CXToken`. pub(crate) extent: CXSourceRange, /// The kind of the token. This is the same as the relevant member from /// `CXToken`. pub(crate) kind: CXTokenKind, } impl ClangToken { /// Get the token spelling, without being converted to utf-8. pub(crate) 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(crate) fn as_cexpr_token(&self) -> Option { 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(crate) struct ClangTokenIterator<'a> { tu: CXTranslationUnit, raw: slice::Iter<'a, CXToken>, } impl Iterator for ClangTokenIterator<'_> { type Item = ClangToken; fn next(&mut self) -> Option { 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(crate) fn is_valid_identifier(name: &str) -> bool { let mut chars = name.chars(); let first_valid = chars.next().is_some_and(|c| c.is_alphabetic() || c == '_'); first_valid && chars.all(|c| c.is_alphanumeric() || c == '_') } extern "C" fn visit_children( 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(&self, state: &mut H) { unsafe { clang_hashCursor(self.x) }.hash(state); } } /// The type of a node in clang's AST. #[derive(Clone, Copy)] pub(crate) 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(crate) 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 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(crate) fn kind(&self) -> CXTypeKind { self.x.kind } /// Get a cursor pointing to this type's declaration. pub(crate) fn declaration(&self) -> Cursor { unsafe { Cursor { x: clang_getTypeDeclaration(self.x), } } } /// Get the canonical declaration of this type, if it is available. pub(crate) fn canonical_declaration( &self, location: Option<&Cursor>, ) -> Option { 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(crate) 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(crate) 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(crate) 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(crate) fn fallible_size( &self, ctx: &BindgenContext, ) -> Result { 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(crate) 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(crate) fn fallible_align( &self, ctx: &BindgenContext, ) -> Result { 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(crate) fn fallible_layout( &self, ctx: &BindgenContext, ) -> Result { 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(crate) fn num_template_args(&self) -> Option { 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(crate) fn template_args(&self) -> Option { 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(crate) fn args(&self) -> Option> { 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(crate) fn num_args(&self) -> Result { 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(crate) fn pointee_type(&self) -> Option { 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(crate) fn elem_type(&self) -> Option { 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(crate) fn num_elements(&self) -> Option { let num_elements_returned = unsafe { clang_getNumElements(self.x) }; if num_elements_returned == -1 { None } else { Some(num_elements_returned as usize) } } /// Get the canonical version of this type. This sees through `typedef`s and /// aliases to get the underlying, canonical type. pub(crate) fn canonical_type(&self) -> Type { unsafe { Type { x: clang_getCanonicalType(self.x), } } } /// Is this type a variadic function type? pub(crate) 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(crate) fn ret_type(&self) -> Option { 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(crate) 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(crate) fn named(&self) -> Type { unsafe { Type { x: clang_Type_getNamedType(self.x), } } } /// For atomic types, get the underlying type. pub(crate) fn atomic_value_type(&self) -> Type { unsafe { Type { x: clang_Type_getValueType(self.x), } } } /// Is this a valid type? pub(crate) fn is_valid(&self) -> bool { self.kind() != CXType_Invalid } /// Is this a valid and exposed type? pub(crate) fn is_valid_and_exposed(&self) -> bool { self.is_valid() && self.kind() != CXType_Unexposed } /// Is this type a fully instantiated template? pub(crate) fn is_fully_instantiated_template(&self) -> bool { // Yep, the spelling of this containing type-parameter is extremely // nasty... But can happen in . Unfortunately I couldn't // reduce it enough :( self.template_args().is_some_and(|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 /// class Foo { /// typename T::Associated member; /// }; /// ``` pub(crate) fn is_associated_type(&self) -> bool { // This is terrible :( fn hacky_parse_associated_type>(spelling: S) -> bool { static ASSOC_TYPE_RE: OnceLock = OnceLock::new(); ASSOC_TYPE_RE .get_or_init(|| { regex::Regex::new(r"typename type\-parameter\-\d+\-\d+::.+") .unwrap() }) .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(crate) struct CanonicalTypeDeclaration(Type, Cursor); impl CanonicalTypeDeclaration { /// Get the type. pub(crate) fn ty(&self) -> &Type { &self.0 } /// Get the type's canonical declaration cursor. pub(crate) fn cursor(&self) -> &Cursor { &self.1 } } /// An iterator for a type's template arguments. pub(crate) struct TypeTemplateArgIterator { x: CXType, length: u32, index: u32, } impl Iterator for TypeTemplateArgIterator { type Item = Type; fn next(&mut self) -> Option { 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(crate) struct SourceLocation { x: CXSourceLocation, } impl SourceLocation { /// Get the (file, line, column, byte offset) tuple for this source /// location. pub(crate) 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_getFileLocation( 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(crate) struct Comment { x: CXComment, } impl Comment { /// What kind of comment is this? pub(crate) fn kind(&self) -> CXCommentKind { unsafe { clang_Comment_getKind(self.x) } } /// Get this comment's children comment pub(crate) 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(crate) 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(crate) 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(crate) struct CommentChildrenIterator { parent: CXComment, length: c_uint, index: c_uint, } impl Iterator for CommentChildrenIterator { type Item = Comment; fn next(&mut self) -> Option { 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(crate) struct CommentAttribute { /// HTML start tag attribute name pub(crate) name: String, /// HTML start tag attribute value pub(crate) value: String, } /// An iterator for a comment's attributes pub(crate) struct CommentAttributesIterator { x: CXComment, length: c_uint, index: c_uint, } impl Iterator for CommentAttributesIterator { type Item = CommentAttribute; fn next(&mut self) -> Option { 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(crate) struct File { x: CXFile, } impl File { /// Get the name of this source file. pub(crate) fn name(&self) -> Option { 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(crate) 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(crate) fn new(pch: bool, diag: bool) -> Index { unsafe { Index { x: clang_createIndex(c_int::from(pch), c_int::from(diag)), } } } } 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(crate) 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(crate) fn parse( ix: &Index, file: &str, cmd_args: &[Box], unsaved: &[UnsavedFile], opts: CXTranslationUnit_Flags, ) -> Option { let fname = CString::new(file).unwrap(); let _c_args: Vec = cmd_args .iter() .map(|s| CString::new(s.as_bytes()).unwrap()) .collect(); let c_args: Vec<*const c_char> = _c_args.iter().map(|s| s.as_ptr()).collect(); let mut c_unsaved: Vec = 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(crate) fn diags(&self) -> Vec { 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(crate) fn cursor(&self) -> Cursor { unsafe { Cursor { x: clang_getTranslationUnitCursor(self.x), } } } /// Save a translation unit to the given file. pub(crate) fn save(&mut self, file: &str) -> Result<(), CXSaveError> { let Ok(file) = CString::new(file) else { return Err(CXSaveError_Unknown); }; let ret = unsafe { clang_saveTranslationUnit( self.x, file.as_ptr(), clang_defaultSaveOptions(self.x), ) }; if ret != 0 { Err(ret) } else { Ok(()) } } /// Is this the null translation unit? pub(crate) fn is_null(&self) -> bool { self.x.is_null() } } impl Drop for TranslationUnit { fn drop(&mut self) { unsafe { clang_disposeTranslationUnit(self.x); } } } /// Translation unit used for macro fallback parsing pub(crate) struct FallbackTranslationUnit { file_path: String, header_path: String, pch_path: String, idx: Box, tu: TranslationUnit, } impl fmt::Debug for FallbackTranslationUnit { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "FallbackTranslationUnit {{ }}") } } impl FallbackTranslationUnit { /// Create a new fallback translation unit pub(crate) fn new( file: String, header_path: String, pch_path: String, c_args: &[Box], ) -> Option { // Create empty file OpenOptions::new() .write(true) .create(true) .truncate(true) .open(&file) .ok()?; let f_index = Box::new(Index::new(true, false)); let f_translation_unit = TranslationUnit::parse( &f_index, &file, c_args, &[], CXTranslationUnit_None, )?; Some(FallbackTranslationUnit { file_path: file, header_path, pch_path, tu: f_translation_unit, idx: f_index, }) } /// Get reference to underlying translation unit. pub(crate) fn translation_unit(&self) -> &TranslationUnit { &self.tu } /// Reparse a translation unit. pub(crate) fn reparse( &mut self, unsaved_contents: &str, ) -> Result<(), CXErrorCode> { let unsaved = &[UnsavedFile::new(&self.file_path, unsaved_contents)]; let mut c_unsaved: Vec = unsaved.iter().map(|f| f.x).collect(); let ret = unsafe { clang_reparseTranslationUnit( self.tu.x, unsaved.len() as c_uint, c_unsaved.as_mut_ptr(), clang_defaultReparseOptions(self.tu.x), ) }; if ret != 0 { Err(ret) } else { Ok(()) } } } impl Drop for FallbackTranslationUnit { fn drop(&mut self) { let _ = std::fs::remove_file(&self.file_path); let _ = std::fs::remove_file(&self.header_path); let _ = std::fs::remove_file(&self.pch_path); } } /// A diagnostic message generated while parsing a translation unit. pub(crate) struct Diagnostic { x: CXDiagnostic, } impl Diagnostic { /// Format this diagnostic message as a string, using the given option bit /// flags. pub(crate) 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(crate) 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(crate) struct UnsavedFile { x: CXUnsavedFile, /// The name of the unsaved file. Kept here to avoid leaving dangling pointers in /// `CXUnsavedFile`. pub(crate) name: CString, contents: CString, } impl UnsavedFile { /// Construct a new unsaved file with the given `name` and `contents`. pub(crate) fn new(name: &str, contents: &str) -> UnsavedFile { let name = CString::new(name.as_bytes()).unwrap(); let contents = CString::new(contents.as_bytes()).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(crate) fn kind_to_str(x: CXCursorKind) -> String { unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) } } /// Convert a type kind to a static string. pub(crate) fn type_to_str(x: CXTypeKind) -> String { unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) } } /// Dump the Clang AST to stdout for debugging purposes. pub(crate) fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { fn print_indent>(depth: isize, s: S) { for _ in 0..depth { print!(" "); } println!("{}", s.as_ref()); } fn print_cursor>(depth: isize, prefix: S, c: &Cursor) { let prefix = prefix.as_ref(); print_indent( depth, format!(" {prefix}kind = {}", kind_to_str(c.kind())), ); print_indent( depth, format!(" {prefix}spelling = \"{}\"", c.spelling()), ); print_indent(depth, format!(" {prefix}location = {}", c.location())); print_indent( depth, format!(" {prefix}is-definition? {}", c.is_definition()), ); print_indent( depth, format!(" {prefix}is-declaration? {}", c.is_declaration()), ); print_indent( depth, format!( " {prefix}is-inlined-function? {}", c.is_inlined_function() ), ); let templ_kind = c.template_kind(); if templ_kind != CXCursor_NoDeclFound { print_indent( depth, format!(" {prefix}template-kind = {}", kind_to_str(templ_kind)), ); } if let Some(usr) = c.usr() { print_indent(depth, format!(" {prefix}usr = \"{usr}\"")); } if let Ok(num) = c.num_args() { print_indent(depth, format!(" {prefix}number-of-args = {num}")); } if let Some(num) = c.num_template_args() { print_indent( depth, format!(" {prefix}number-of-template-args = {num}"), ); } if c.is_bit_field() { let width = match c.bit_width() { Some(w) => w.to_string(), None => "".to_string(), }; print_indent(depth, format!(" {prefix}bit-width = {width}")); } if let Some(ty) = c.enum_type() { print_indent( depth, format!(" {prefix}enum-type = {}", type_to_str(ty.kind())), ); } if let Some(val) = c.enum_val_signed() { print_indent(depth, format!(" {prefix}enum-val = {val}")); } if let Some(ty) = c.typedef_type() { print_indent( depth, format!(" {prefix}typedef-type = {}", type_to_str(ty.kind())), ); } if let Some(ty) = c.ret_type() { print_indent( depth, format!(" {prefix}ret-type = {}", 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>(depth: isize, prefix: S, ty: &Type) { let prefix = prefix.as_ref(); let kind = ty.kind(); print_indent(depth, format!(" {prefix}kind = {}", type_to_str(kind))); if kind == CXType_Invalid { return; } print_indent(depth, format!(" {prefix}cconv = {}", ty.call_conv())); print_indent( depth, format!(" {prefix}spelling = \"{}\"", ty.spelling()), ); let num_template_args = unsafe { clang_Type_getNumTemplateArguments(ty.x) }; if num_template_args >= 0 { print_indent( depth, format!( " {prefix}number-of-template-args = {num_template_args}" ), ); } if let Some(num) = ty.num_elements() { print_indent(depth, format!(" {prefix}number-of-elements = {num}")); } print_indent( depth, format!(" {prefix}is-variadic? {}", 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(crate) fn extract_clang_version() -> String { unsafe { cxstring_into_string(clang_getClangVersion()) } } /// A wrapper for the result of evaluating an expression. #[derive(Debug)] pub(crate) struct EvalResult { x: CXEvalResult, ty: Type, } impl EvalResult { /// Evaluate `cursor` and return the result. pub(crate) fn new(cursor: Cursor) -> Option { // 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) }, ty: cursor.cur_type().canonical_type(), }) } fn kind(&self) -> CXEvalResultKind { unsafe { clang_EvalResult_getKind(self.x) } } /// Try to get back the result as a double. pub(crate) fn as_double(&self) -> Option { match self.kind() { CXEval_Float => { Some(unsafe { clang_EvalResult_getAsDouble(self.x) }) } _ => None, } } /// Try to get back the result as an integer. pub(crate) fn as_int(&self) -> Option { 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 as c_ulonglong { return None; } return Some(value as i64); } let value = unsafe { clang_EvalResult_getAsLongLong(self.x) }; if value > i64::MAX as c_longlong { return None; } if value < i64::MIN as c_longlong { return None; } #[allow(clippy::unnecessary_cast)] Some(value as i64) } /// Evaluates the expression as a literal string, that may or may not be /// valid utf-8. pub(crate) fn as_literal_string(&self) -> Option> { if self.kind() != CXEval_StrLiteral { return None; } let char_ty = self.ty.pointee_type().or_else(|| self.ty.elem_type())?; match char_ty.kind() { CXType_Char_S | CXType_SChar | CXType_Char_U | CXType_UChar => { let ret = unsafe { CStr::from_ptr(clang_EvalResult_getAsStr(self.x)) }; Some(ret.to_bytes().to_vec()) } // FIXME: Support generating these. CXType_Char16 => None, CXType_Char32 => None, CXType_WChar => None, _ => None, } } } impl Drop for EvalResult { fn drop(&mut self) { unsafe { clang_EvalResult_dispose(self.x) }; } } /// ABI kinds as defined in /// #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub(crate) enum ABIKind { /// All the regular targets like Linux, Mac, WASM, etc. implement the Itanium ABI GenericItanium, /// The ABI used when compiling for the MSVC target Microsoft, } /// Target information obtained from libclang. #[derive(Debug)] pub(crate) struct TargetInfo { /// The target triple. pub(crate) triple: String, /// The width of the pointer _in bits_. pub(crate) pointer_width: usize, /// The ABI of the target pub(crate) abi: ABIKind, } impl TargetInfo { /// Tries to obtain target information from libclang. pub(crate) 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); let abi = if triple.contains("msvc") { ABIKind::Microsoft } else { ABIKind::GenericItanium }; TargetInfo { triple, pointer_width: pointer_width as usize, abi, } } } bindgen-0.71.1/codegen/bitfield_unit.rs000064400000000000000000000056101046102023000161150ustar 00000000000000#[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct __BindgenBitfieldUnit { storage: Storage, } impl __BindgenBitfieldUnit { #[inline] pub const fn new(storage: Storage) -> Self { Self { storage } } } impl __BindgenBitfieldUnit where Storage: AsRef<[u8]> + AsMut<[u8]>, { #[inline] fn extract_bit(byte: u8, index: usize) -> bool { 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 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]; Self::extract_bit(byte, index) } #[inline] fn change_bit(byte: u8, index: usize, val: bool) -> u8 { 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 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]; *byte = Self::change_bit(*byte, index, val); } #[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); } } } bindgen-0.71.1/codegen/bitfield_unit_raw_ref_macros.rs000064400000000000000000000121211046102023000211610ustar 00000000000000#[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct __BindgenBitfieldUnit { storage: Storage, } impl __BindgenBitfieldUnit { #[inline] pub const fn new(storage: Storage) -> Self { Self { storage } } } impl __BindgenBitfieldUnit where Storage: AsRef<[u8]> + AsMut<[u8]>, { #[inline] fn extract_bit(byte: u8, index: usize) -> bool { 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 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]; Self::extract_bit(byte, index) } #[inline] pub unsafe fn raw_get_bit(this: *const Self, index: usize) -> bool { debug_assert!(index / 8 < core::mem::size_of::()); let byte_index = index / 8; let byte = *(core::ptr::addr_of!((*this).storage) as *const u8) .offset(byte_index as isize); Self::extract_bit(byte, index) } #[inline] fn change_bit(byte: u8, index: usize, val: bool) -> u8 { 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 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]; *byte = Self::change_bit(*byte, index, val); } #[inline] pub unsafe fn raw_set_bit(this: *mut Self, index: usize, val: bool) { debug_assert!(index / 8 < core::mem::size_of::()); let byte_index = index / 8; let byte = (core::ptr::addr_of_mut!((*this).storage) as *mut u8) .offset(byte_index as isize); *byte = Self::change_bit(*byte, index, val); } #[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 unsafe fn raw_get( this: *const Self, bit_offset: usize, bit_width: u8, ) -> u64 { debug_assert!(bit_width <= 64); debug_assert!(bit_offset / 8 < core::mem::size_of::()); debug_assert!( (bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::() ); let mut val = 0; for i in 0..(bit_width as usize) { if Self::raw_get_bit(this, 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); } } #[inline] pub unsafe fn raw_set( this: *mut Self, bit_offset: usize, bit_width: u8, val: u64, ) { debug_assert!(bit_width <= 64); debug_assert!(bit_offset / 8 < core::mem::size_of::()); debug_assert!( (bit_offset + (bit_width as usize)) / 8 <= core::mem::size_of::() ); 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::raw_set_bit(this, index + bit_offset, val_bit_is_set); } } } bindgen-0.71.1/codegen/bitfield_unit_tests.rs000064400000000000000000000177761046102023000173570ustar 00000000000000//! 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 = {expected:064b}"); println!("actual = {actual:064b}"); 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 = {actual:064b}"); 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; } bindgen-0.71.1/codegen/dyngen.rs000064400000000000000000000166631046102023000145720ustar 00000000000000use crate::codegen; use crate::ir::context::BindgenContext; use crate::ir::function::ClangAbi; use proc_macro2::{Ident, TokenStream}; /// Used to build the output tokens for dynamic bindings. #[derive(Default)] pub(crate) struct DynamicItems { /// Tracks the tokens that will appears inside the library struct -- e.g.: /// ```ignore /// struct Lib { /// __library: ::libloading::Library, /// pub x: Result, // <- tracks these /// ... /// } /// ``` struct_members: Vec, /// 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, /// Tracks the initialization of the fields inside the `::new` constructor of the library /// struct, e.g.: /// ```ignore /// impl Lib { /// /// pub unsafe fn new

(path: P) -> Result /// where /// P: AsRef<::std::ffi::OsStr>, /// { /// ... /// let foo = __library.get(...) ...; // <- tracks these /// ... /// } /// /// ... /// } /// ``` constructor_inits: Vec, /// 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

(path: P) -> Result /// where /// P: AsRef<::std::ffi::OsStr>, /// { /// ... /// Ok(LibFoo { /// __library: __library, /// foo, /// bar, // <- tracks these /// ... /// }) /// } /// } /// ``` init_fields: Vec, } impl DynamicItems { pub(crate) fn new() -> Self { Self::default() } pub(crate) fn get_tokens( &self, lib_ident: Ident, ctx: &BindgenContext, ) -> 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; let library_new = if ctx.options().wrap_unsafe_ops { quote!(unsafe { ::libloading::Library::new(path) }) } else { quote!(::libloading::Library::new(path)) }; let from_library = if ctx.options().wrap_unsafe_ops { quote!(unsafe { Self::from_library(library) }) } else { quote!(Self::from_library(library)) }; quote! { pub struct #lib_ident { __library: ::libloading::Library, #(#struct_members)* } impl #lib_ident { pub unsafe fn new

( path: P ) -> Result where P: AsRef<::std::ffi::OsStr> { let library = #library_new?; #from_library } pub unsafe fn from_library( library: L ) -> Result 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(crate) fn push_func( &mut self, ident: Ident, abi: ClangAbi, is_variadic: bool, is_required: bool, args: Vec, args_identifiers: Vec, ret: TokenStream, ret_ty: TokenStream, attributes: Vec, ctx: &BindgenContext, ) { 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 = if ctx.options().wrap_unsafe_ops { quote!(unsafe { (#fn_)(#( #args_identifiers ),*) }) } else { 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()); let library_get = if ctx.options().wrap_unsafe_ops { quote!(unsafe { __library.get(#ident_str) }) } else { quote!(__library.get(#ident_str)) }; self.constructor_inits.push(if is_required { quote! { let #ident = #library_get.map(|sym| *sym)?; } } else { quote! { let #ident = #library_get.map(|sym| *sym); } }); self.init_fields.push(quote! { #ident }); } pub fn push_var( &mut self, ident: Ident, ty: TokenStream, is_required: bool, wrap_unsafe_ops: bool, ) { let member = if is_required { quote! { *mut #ty } } else { quote! { Result<*mut #ty, ::libloading::Error> } }; self.struct_members.push(quote! { pub #ident: #member, }); let deref = if is_required { quote! { self.#ident } } else { quote! { *self.#ident.as_ref().expect("Expected variable, got error.") } }; self.struct_implementation.push(quote! { pub unsafe fn #ident (&self) -> *mut #ty { #deref } }); let ident_str = codegen::helpers::ast_ty::cstr_expr(ident.to_string()); let library_get = if wrap_unsafe_ops { quote!(unsafe { __library.get::<*mut #ty>(#ident_str) }) } else { quote!(__library.get::<*mut #ty>(#ident_str)) }; let qmark = if is_required { quote!(?) } else { quote!() }; let var_get = quote! { let #ident = #library_get.map(|sym| *sym)#qmark; }; self.constructor_inits.push(var_get); self.init_fields.push(quote! { #ident }); } } bindgen-0.71.1/codegen/error.rs000064400000000000000000000033401046102023000144230ustar 00000000000000use std::error; use std::fmt; /// Errors that can occur during code generation. #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) 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, /// Function ABI is not supported. UnsupportedAbi(&'static str), /// The pointer type size does not match the target's pointer size. InvalidPointerSize { ty_name: String, ty_size: usize, ptr_size: usize, }, } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Error::NoLayoutForOpaqueBlob => { "Tried to generate an opaque blob, but had no layout.".fmt(f) } Error::InstantiationOfOpaqueType => { "Instantiation of opaque template type or partial template specialization." .fmt(f) } Error::UnsupportedAbi(abi) => { write!( f, "{abi} ABI is not supported by the configured Rust target." ) } Error::InvalidPointerSize { ty_name, ty_size, ptr_size } => { write!(f, "The {ty_name} pointer type has size {ty_size} but the current target's pointer size is {ptr_size}.") } } } } impl error::Error for Error {} /// A `Result` of `T` or an error of `bindgen::codegen::error::Error`. pub(crate) type Result = ::std::result::Result; bindgen-0.71.1/codegen/helpers.rs000064400000000000000000000312611046102023000147370ustar 00000000000000//! Helpers for code generation that don't need macro expansion. use proc_macro2::{Ident, Span}; use crate::ir::context::BindgenContext; use crate::ir::layout::Layout; pub(crate) mod attributes { use proc_macro2::{Ident, Span, TokenStream}; use std::{borrow::Cow, str::FromStr}; pub(crate) fn repr(which: &str) -> TokenStream { let which = Ident::new(which, Span::call_site()); quote! { #[repr( #which )] } } pub(crate) fn repr_list(which_ones: &[&str]) -> TokenStream { let which_ones = which_ones .iter() .map(|one| TokenStream::from_str(one).expect("repr to be valid")); quote! { #[repr( #( #which_ones ),* )] } } pub(crate) fn derives(which_ones: &[&str]) -> TokenStream { let which_ones = which_ones .iter() .map(|one| TokenStream::from_str(one).expect("derive to be valid")); quote! { #[derive( #( #which_ones ),* )] } } pub(crate) fn inline() -> TokenStream { quote! { #[inline] } } pub(crate) fn must_use() -> TokenStream { quote! { #[must_use] } } pub(crate) fn non_exhaustive() -> TokenStream { quote! { #[non_exhaustive] } } pub(crate) fn doc(comment: String) -> TokenStream { if comment.is_empty() { quote!() } else { quote!(#[doc = #comment]) } } pub(crate) 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: Cow<'_, str> = if MANGLE { name.into() } else { format!("\u{1}{name}").into() }; quote! { #[link_name = #name] } } } /// The `ffi_safe` argument should be true if this is a type that the user might /// reasonably use, e.g. not struct padding, where the `__BindgenOpaqueArray` is /// just noise. /// TODO: Should this be `MaybeUninit`, since padding bytes are effectively /// uninitialized? pub(crate) fn blob( ctx: &BindgenContext, layout: Layout, ffi_safe: bool, ) -> syn::Type { 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 = opaque.known_rust_type_for_array().unwrap_or_else(|| { warn!("Found unknown alignment on code generation!"); syn::parse_quote! { u8 } }); let data_len = opaque.array_size().unwrap_or(layout.size); if data_len == 1 { ty } else if ffi_safe && ctx.options().rust_features().min_const_generics { ctx.generated_opaque_array(); if ctx.options().enable_cxx_namespaces { syn::parse_quote! { root::__BindgenOpaqueArray<#ty, #data_len> } } else { syn::parse_quote! { __BindgenOpaqueArray<#ty, #data_len> } } } else { // This is not FFI safe as an argument; the struct above is // preferable. syn::parse_quote! { [ #ty ; #data_len ] } } } /// Integer type of the same size as the given `Layout`. pub(crate) fn integer_type(layout: Layout) -> Option { Layout::known_type_for_size(layout.size) } pub(crate) const BITFIELD_UNIT: &str = "__BindgenBitfieldUnit"; /// Generates a bitfield allocation unit type for a type with the given `Layout`. pub(crate) fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> syn::Type { let size = layout.size; let bitfield_unit_name = Ident::new(BITFIELD_UNIT, Span::call_site()); let ty = syn::parse_quote! { #bitfield_unit_name<[u8; #size]> }; if ctx.options().enable_cxx_namespaces { return syn::parse_quote! { root::#ty }; } ty } pub(crate) mod ast_ty { use crate::ir::context::BindgenContext; use crate::ir::function::FunctionSig; use crate::ir::layout::Layout; use crate::ir::ty::{FloatKind, IntKind}; use crate::RustTarget; use proc_macro2::TokenStream; use std::str::FromStr; pub(crate) fn c_void(ctx: &BindgenContext) -> syn::Type { // ctypes_prefix takes precedence match ctx.options().ctypes_prefix { Some(ref prefix) => { let prefix = TokenStream::from_str(prefix.as_str()).unwrap(); syn::parse_quote! { #prefix::c_void } } None => { if ctx.options().use_core { syn::parse_quote! { ::core::ffi::c_void } } else { syn::parse_quote! { ::std::os::raw::c_void } } } } } pub(crate) fn raw_type(ctx: &BindgenContext, name: &str) -> syn::Type { let ident = ctx.rust_ident_raw(name); match ctx.options().ctypes_prefix { Some(ref prefix) => { let prefix = TokenStream::from_str(prefix.as_str()).unwrap(); syn::parse_quote! { #prefix::#ident } } None => { if ctx.options().use_core && ctx.options().rust_features().core_ffi_c { syn::parse_quote! { ::core::ffi::#ident } } else { syn::parse_quote! { ::std::os::raw::#ident } } } } } pub(crate) fn int_kind_rust_type( ctx: &BindgenContext, ik: IntKind, layout: Option, ) -> syn::Type { match ik { IntKind::Bool => syn::parse_quote! { bool }, IntKind::Char { .. } => raw_type(ctx, "c_char"), IntKind::SChar => raw_type(ctx, "c_schar"), IntKind::UChar => raw_type(ctx, "c_uchar"), IntKind::Short => raw_type(ctx, "c_short"), IntKind::UShort => raw_type(ctx, "c_ushort"), IntKind::Int => raw_type(ctx, "c_int"), IntKind::UInt => raw_type(ctx, "c_uint"), IntKind::Long => raw_type(ctx, "c_long"), IntKind::ULong => raw_type(ctx, "c_ulong"), IntKind::LongLong => raw_type(ctx, "c_longlong"), IntKind::ULongLong => raw_type(ctx, "c_ulonglong"), IntKind::WChar => { let layout = layout.expect("Couldn't compute wchar_t's layout?"); Layout::known_type_for_size(layout.size) .expect("Non-representable wchar_t?") } IntKind::I8 => syn::parse_quote! { i8 }, IntKind::U8 => syn::parse_quote! { u8 }, IntKind::I16 => syn::parse_quote! { i16 }, IntKind::U16 => syn::parse_quote! { u16 }, IntKind::I32 => syn::parse_quote! { i32 }, IntKind::U32 => syn::parse_quote! { u32 }, IntKind::I64 => syn::parse_quote! { i64 }, IntKind::U64 => syn::parse_quote! { u64 }, IntKind::Custom { name, .. } => { syn::parse_str(name).expect("Invalid integer type.") } IntKind::U128 => { if true { syn::parse_quote! { u128 } } else { // Best effort thing, but wrong alignment // unfortunately. syn::parse_quote! { [u64; 2] } } } IntKind::I128 => { if true { syn::parse_quote! { i128 } } else { syn::parse_quote! { [u64; 2] } } } } } pub(crate) fn float_kind_rust_type( ctx: &BindgenContext, fk: FloatKind, layout: Option, ) -> syn::Type { // 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::Float16, _) => { // TODO: do f16 when rust lands it ctx.generated_bindgen_float16(); if ctx.options().enable_cxx_namespaces { syn::parse_quote! { root::__BindgenFloat16 } } else { syn::parse_quote! { __BindgenFloat16 } } } (FloatKind::Float, true) => syn::parse_quote! { f32 }, (FloatKind::Double, true) => syn::parse_quote! { f64 }, (FloatKind::Float, false) => raw_type(ctx, "c_float"), (FloatKind::Double, false) => raw_type(ctx, "c_double"), (FloatKind::LongDouble, _) => { if let Some(layout) = layout { match layout.size { 4 => syn::parse_quote! { f32 }, 8 => syn::parse_quote! { f64 }, // TODO(emilio): If rust ever gains f128 we should // use it here and below. _ => super::integer_type(layout) .unwrap_or(syn::parse_quote! { f64 }), } } else { debug_assert!( false, "How didn't we know the layout for a primitive type?" ); syn::parse_quote! { f64 } } } (FloatKind::Float128, _) => { if true { syn::parse_quote! { u128 } } else { syn::parse_quote! { [u64; 2] } } } } } pub(crate) 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(crate) 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(crate) fn cstr_expr(mut string: String) -> TokenStream { string.push('\0'); let b = proc_macro2::Literal::byte_string(string.as_bytes()); quote! { #b } } pub(crate) fn float_expr( ctx: &BindgenContext, f: f64, ) -> Result { if f.is_finite() { let val = proc_macro2::Literal::f64_unsuffixed(f); return Ok(quote!(#val)); } let prefix = ctx.trait_prefix(); let rust_target = ctx.options().rust_target; if f.is_nan() { // FIXME: This should be done behind a `RustFeature` instead #[allow(deprecated)] let tokens = if rust_target >= RustTarget::Stable_1_43 { quote! { f64::NAN } } else { quote! { ::#prefix::f64::NAN } }; return Ok(tokens); } if f.is_infinite() { let tokens = if f.is_sign_positive() { // FIXME: This should be done behind a `RustFeature` instead #[allow(deprecated)] if rust_target >= RustTarget::Stable_1_43 { quote! { f64::INFINITY } } else { quote! { ::#prefix::f64::INFINITY } } } else { // FIXME: This should be done behind a `RustFeature` instead #[allow(deprecated)] // Negative infinity if rust_target >= RustTarget::Stable_1_43 { quote! { f64::NEG_INFINITY } } else { quote! { ::#prefix::f64::NEG_INFINITY } } }; return Ok(tokens); } warn!("Unknown non-finite float number: {f:?}"); Err(()) } pub(crate) fn arguments_from_signature( signature: &FunctionSig, ctx: &BindgenContext, ) -> Vec { let mut unnamed_arguments = 0; signature .argument_types() .iter() .map(|&(ref name, _ty)| { let name = if let Some(ref name) = *name { ctx.rust_ident(name) } else { unnamed_arguments += 1; ctx.rust_ident(format!("arg{unnamed_arguments}")) }; quote! { #name } }) .collect() } } bindgen-0.71.1/codegen/impl_debug.rs000064400000000000000000000203041046102023000154000ustar 00000000000000use 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}; use std::fmt::Write as _; pub(crate) 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(crate) 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)>; } impl ImplDebug<'_> for FieldData { type Extra = (); fn impl_debug( &self, ctx: &BindgenContext, _: Self::Extra, ) -> Option<(String, Vec)> { if let Some(name) = self.name() { ctx.resolve_item(self.ty()).impl_debug(ctx, name) } else { None } } } impl ImplDebug<'_> for BitfieldUnit { type Extra = (); fn impl_debug( &self, ctx: &BindgenContext, _: Self::Extra, ) -> Option<(String, Vec)> { 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() { let _ = write!(format_string, "{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)> { 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 = self.as_type()?; fn debug_print( name: &str, name_ident: proc_macro2::TokenStream, ) -> Option<(String, Vec)> { 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!("{name}: opaque"), 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!("{name}: Non-debuggable generic"), vec![])) } TypeKind::Array(_, len) => { // Generics are not required to implement Debug if self.has_type_param_in_array(ctx) { Some((format!("{name}: Array with length {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! {{ use std::fmt::Write as _; let mut output = String::new(); let mut iter = self.#name_ident.iter(); if let Some(value) = iter.next() { let _ = write!(output, "{value:?}"); for value in iter { let _ = write!(output, ", {value:?}"); } } output }}], )) } } 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!("{name}: FunctionPointer"), vec![])) } _ => debug_print(name, quote! { #name_ident }), } } TypeKind::Opaque => None, } } } bindgen-0.71.1/codegen/impl_partialeq.rs000064400000000000000000000106251046102023000163010ustar 00000000000000use 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(crate) fn gen_partialeq_impl( ctx: &BindgenContext, comp_info: &CompInfo, item: &Item, ty_for_impl: &proc_macro2::TokenStream, ) -> Option { 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().untagged_union); tokens.push(quote! { &self.bindgen_union_field[..] == &other.bindgen_union_field[..] }); } else { for base in comp_info.base_members() { 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) } } } bindgen-0.71.1/codegen/mod.rs000064400000000000000000006132061046102023000140610ustar 00000000000000mod dyngen; pub(crate) mod error; mod helpers; mod impl_debug; mod impl_partialeq; mod postprocessing; mod serialize; pub(crate) 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::callbacks::{ AttributeInfo, DeriveInfo, DiscoveredItem, DiscoveredItemId, FieldInfo, TypeKind as DeriveTypeKind, }; use crate::codegen::error::Error; use crate::ir::analysis::{HasVtable, Sizedness}; use crate::ir::annotations::{ Annotations, FieldAccessorKind, FieldVisibilityKind, }; 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::{ ClangAbi, 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::{Ident, Span}; use quote::{ToTokens, TokenStreamExt}; use crate::{Entry, HashMap, HashSet}; use std::borrow::Cow; use std::cell::Cell; use std::collections::VecDeque; use std::ffi::CStr; use std::fmt::{self, Write}; use std::ops; use std::str::{self, FromStr}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum CodegenError { Serialize { msg: String, loc: String }, Io(String), } impl From for CodegenError { fn from(err: std::io::Error) -> Self { Self::Io(err.to_string()) } } impl fmt::Display for CodegenError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Serialize { msg, loc } => { write!(f, "serialization error at {loc}: {msg}") } Self::Io(err) => err.fmt(f), } } } // Name of type defined in constified enum module pub(crate) static CONSTIFIED_ENUM_MODULE_REPR_NAME: &str = "Type"; fn top_level_path( ctx: &BindgenContext, item: &Item, ) -> Vec { 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! { #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 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(); if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() { derivable_traits |= DerivableTraits::COPY; // 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 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 WrapAsVariadic { new_name: String, idx_of_va_list_arg: usize, } struct CodegenResult<'a> { items: Vec, 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, /// 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, /// 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, vars_seen: HashSet, /// 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, /// List of items to serialize. With optionally the argument for the wrap as /// variadic transformation to be applied. items_to_serialize: Vec<(ItemId, Option)>, } impl<'a> CodegenResult<'a> { fn new(codegen_id: &'a Cell) -> 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(), items_to_serialize: 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>(&self, item: Id) -> bool { self.items_seen.contains(&item.into()) } fn set_seen>(&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(&mut self, cb: F) -> Vec 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 ops::Deref for CodegenResult<'_> { type Target = Vec; fn deref(&self) -> &Self::Target { &self.items } } impl ops::DerefMut for CodegenResult<'_> { 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) -> syn::Type; } impl ToPtr for syn::Type { fn to_ptr(self, is_const: bool) -> syn::Type { if is_const { syn::parse_quote! { *const #self } } else { syn::parse_quote! { *mut #self } } } } /// An extension trait for `syn::Type` that lets us append any implicit /// template parameters that exist for some type, if necessary. trait WithImplicitTemplateParams { fn with_implicit_template_params( self, ctx: &BindgenContext, item: &Item, ) -> Self; } impl WithImplicitTemplateParams for syn::Type { fn with_implicit_template_params( self, ctx: &BindgenContext, item: &Item, ) -> Self { let item = item.id().into_resolver().through_type_refs().resolve(ctx); let params = 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(..) => None, _ => { let params = item.used_template_params(ctx); if params.is_empty() { None } else { Some(params.into_iter().map(|p| { p.try_to_rust_ty(ctx, &()).expect( "template params cannot fail to be a rust type", ) })) } } }; if let Some(params) = params { syn::parse_quote! { #self<#(#params),*> } } else { self } } } trait CodeGenerator { /// Extra information from the caller. type Extra; /// Extra information returned to the caller. type Return; fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, 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!( "::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( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, _extra: &(), ) { debug!("::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( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { debug!("::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_float16_type() { utils::prepend_float16_type(&mut *result); } if ctx.need_bindgen_complex_type() { utils::prepend_complex_type(&mut *result); } if ctx.need_opaque_array_type() { utils::prepend_opaque_array_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("::") .into_boxed_str(); 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( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { use crate::ir::var::VarType; debug!("::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 var_ty = self.ty(); let ty = var_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 = var_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) => { let prefix = ctx.trait_prefix(); let options = ctx.options(); let rust_features = options.rust_features; let mut cstr_bytes = bytes.clone(); cstr_bytes.push(0); let len = proc_macro2::Literal::usize_unsuffixed( cstr_bytes.len(), ); let cstr = if options.generate_cstr && rust_features.const_cstr { CStr::from_bytes_with_nul(&cstr_bytes).ok() } else { None }; if let Some(cstr) = cstr { let cstr_ty = quote! { ::#prefix::ffi::CStr }; if rust_features.literal_cstr { let cstr = proc_macro2::Literal::c_string(cstr); result.push(quote! { #(#attrs)* pub const #canonical_ident: &#cstr_ty = #cstr; }); } else { let bytes = proc_macro2::Literal::byte_string(&cstr_bytes); result.push(quote! { #(#attrs)* #[allow(unsafe_code)] pub const #canonical_ident: &#cstr_ty = unsafe { #cstr_ty::from_bytes_with_nul_unchecked(#bytes) }; }); } } else { // TODO: Here we ignore the type we just made up, probably // we should refactor how the variable type and ty ID work. let array_ty = quote! { [u8; #len] }; let bytes = proc_macro2::Literal::byte_string(&cstr_bytes); let lifetime = if true { None } else { Some(quote! { 'static }) } .into_iter(); result.push(quote! { #(#attrs)* pub const #canonical_ident: &#(#lifetime )*#array_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 if let Some(link_name) = self.link_name() { attrs.push(attributes::link_name::(link_name)); } else { 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 safety = ctx .options() .rust_features .unsafe_extern_blocks .then(|| quote!(unsafe)); let tokens = quote!( #safety extern "C" { #(#attrs)* pub static #maybe_mut #canonical_ident: #ty; } ); if ctx.options().dynamic_library_name.is_some() { result.dynamic_items().push_var( canonical_ident, self.ty() .to_rust_ty_or_opaque(ctx, &()) .into_token_stream(), ctx.options().dynamic_link_require_all, ctx.options().wrap_unsafe_ops, ); } else { result.push(tokens); } } } } impl CodeGenerator for Type { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { debug!("::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 `{spelling}` ({}) does not match the target pointer size ({})", 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 `{spelling}` ({}) does not match the target pointer size ({})", 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. inner_item .try_to_rust_ty_or_opaque(ctx, &()) .unwrap_or_else(|_| self.to_opaque(ctx, item)) .with_implicit_template_params(ctx, inner_item) }; { // 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); ctx.options().for_each_callback(|cb| { cb.new_item_found( DiscoveredItemId::new(item.id().as_usize()), DiscoveredItem::Alias { alias_name: rust_name.to_string(), alias_for: DiscoveredItemId::new( inner_item.id().as_usize(), ), }, ); }); 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 if matches!(inner_rust_type, syn::Type::Path(_)) && 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 => { 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); let mut derives: Vec<_> = derivable_traits.into(); // The custom derives callback may return a list of derive attributes; // add them to the end of the list. let custom_derives = ctx.options().all_callbacks(|cb| { cb.add_derives(&DeriveInfo { name: &name, kind: DeriveTypeKind::Struct, }) }); // 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())); attributes.push(attributes::derives(&derives)); let custom_attributes = ctx.options().all_callbacks(|cb| { cb.add_attributes(&AttributeInfo { name: &name, kind: DeriveTypeKind::Struct, }) }); attributes.extend( custom_attributes .iter() .map(|s| s.parse().unwrap()), ); 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 => { let visibility = ctx .options() .last_callback(|cb| { cb.field_visibility(FieldInfo { type_name: &item.canonical_name(ctx), field_name: "0", field_type_name: inner_item .expect_type() .name(), }) }) .unwrap_or(ctx.options().default_visibility); let access_spec = access_specifier(visibility); quote! { (#access_spec #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 CodeGenerator for Vtable<'_> { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, 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 TypeKind::Function(ref signature) = signature_item.expect_type().kind() else { 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::>(); 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 ItemCanonicalName for Vtable<'_> { fn canonical_name(&self, ctx: &BindgenContext) -> String { format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx)) } } impl TryToRustTy for Vtable<'_> { type Extra = (); fn try_to_rust_ty( &self, ctx: &BindgenContext, _: &(), ) -> error::Result { let name = ctx.rust_ident(self.canonical_name(ctx)); Ok(syn::parse_quote! { #name }) } } impl CodeGenerator for TemplateInstantiation { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, 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; } // For consistency with other layout tests, gate this on offset_of. let compile_time = ctx.options().rust_features().offset_of; // 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 fn_name = if compile_time { None } else { let mut fn_name = format!("__bindgen_test_layout_{name}_instantiation"); let times_seen = result.overload_number(&fn_name); if times_seen > 0 { write!(&mut fn_name, "_{times_seen}").unwrap(); } Some(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 size_of_err = format!("Size of template specialization: {name}"); let align_of_err = format!("Align of template specialization: {name}"); if compile_time { // In an ideal world this would be assert_eq!, but that is not // supported in const fn due to the need for string formatting. // If #size_of_expr > #size, this will index OOB, and if // #size_of_expr < #size, the subtraction will overflow, both // of which print enough information to see what has gone wrong. result.push(quote! { #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { [#size_of_err][#size_of_expr - #size]; [#align_of_err][#align_of_expr - #align]; }; }); } else { result.push(quote! { #[test] fn #fn_name() { assert_eq!(#size_of_expr, #size, #size_of_err); assert_eq!(#align_of_expr, #align, #align_of_err); } }); } } } } /// Trait for implementing the code generation of a struct or union field. trait FieldCodegen<'a> { type Extra; #[allow(clippy::too_many_arguments)] fn codegen( &self, ctx: &BindgenContext, visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, extra: Self::Extra, ) where F: Extend, M: Extend; } impl FieldCodegen<'_> for Field { type Extra = (); fn codegen( &self, ctx: &BindgenContext, visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, _: (), ) where F: Extend, M: Extend, { match *self { Field::DataMember(ref data) => { data.codegen( ctx, visibility_kind, accessor_kind, parent, parent_item, last_field, result, struct_layout, fields, methods, (), ); } Field::Bitfields(ref unit) => { unit.codegen( ctx, visibility_kind, accessor_kind, parent, parent_item, last_field, result, struct_layout, fields, methods, (), ); } } } } fn wrap_union_field_if_needed( ctx: &BindgenContext, struct_layout: &StructLayoutTracker, ty: syn::Type, result: &mut CodegenResult, ) -> syn::Type { if struct_layout.is_rust_union() { if struct_layout.can_copy_union_fields() { ty } else { let prefix = ctx.trait_prefix(); syn::parse_quote! { ::#prefix::mem::ManuallyDrop<#ty> } } } else { result.saw_bindgen_union(); if ctx.options().enable_cxx_namespaces { syn::parse_quote! { root::__BindgenUnionField<#ty> } } else { syn::parse_quote! { __BindgenUnionField<#ty> } } } } impl FieldCodegen<'_> for FieldData { type Extra = (); fn codegen( &self, ctx: &BindgenContext, parent_visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, _: (), ) where F: Extend, M: Extend, { // 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 ty = self .ty() .to_rust_ty_or_opaque(ctx, &()) .with_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) { // Only FAM if its the last field if ctx.options().flexarray_dst && last_field { struct_layout.saw_flexible_array(); syn::parse_quote! { FAM } } else { result.saw_incomplete_array(); let inner = item.to_rust_ty_or_opaque(ctx, &()); if ctx.options().enable_cxx_namespaces { syn::parse_quote! { root::__IncompleteArrayField<#inner> } } else { syn::parse_quote! { __IncompleteArrayField<#inner> } } } } else { ty }; let mut field = quote! {}; if ctx.options().generate_comments { if let Some(raw_comment) = self.comment() { let comment = ctx.options().process_comment(raw_comment); 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_name = field_name.as_str(); let field_ident = ctx.rust_ident_raw(field_name); if let Some(padding_field) = struct_layout.saw_field(field_name, field_ty, self.offset()) { fields.extend(Some(padding_field)); } let visibility = compute_visibility( ctx, self.is_public(), ctx.options().last_callback(|cb| { cb.field_visibility(FieldInfo { type_name: &parent_item.canonical_name(ctx), field_name, field_type_name: field_ty.name(), }) }), self.annotations(), parent_visibility_kind, ); let accessor_kind = self.annotations().accessor_kind().unwrap_or(accessor_kind); match visibility { FieldVisibilityKind::Private => { field.append_all(quote! { #field_ident : #ty , }); } FieldVisibilityKind::PublicCrate => { field.append_all(quote! { pub(crate) #field_ident : #ty , }); } FieldVisibilityKind::Public => { 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_{field_name}_mut")); methods.extend(Some(match accessor_kind { FieldAccessorKind::None => unreachable!(), FieldAccessorKind::Regular => { quote! { #[inline] pub fn #getter_name(&self) -> & #ty { &self.#field_ident } #[inline] pub fn #mutable_getter_name(&mut self) -> &mut #ty { &mut self.#field_ident } } } FieldAccessorKind::Unsafe => { quote! { #[inline] pub unsafe fn #getter_name(&self) -> & #ty { &self.#field_ident } #[inline] pub unsafe fn #mutable_getter_name(&mut self) -> &mut #ty { &mut self.#field_ident } } } FieldAccessorKind::Immutable => { quote! { #[inline] pub fn #getter_name(&self) -> & #ty { &self.#field_ident } } } })); } } 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(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( visibility: FieldVisibilityKind, ) -> proc_macro2::TokenStream { match visibility { FieldVisibilityKind::Private => quote! {}, FieldVisibilityKind::PublicCrate => quote! { pub(crate) }, FieldVisibilityKind::Public => quote! { pub }, } } /// Compute a fields or structs visibility based on multiple conditions. /// 1. If the element was declared public, and we respect such CXX accesses specs /// (context option) => By default Public, but this can be overruled by an `annotation`. /// /// 2. If the element was declared private, and we respect such CXX accesses specs /// (context option) => By default Private, but this can be overruled by an `annotation`. /// /// 3. If we do not respect visibility modifiers, the result depends on the `annotation`, /// if any, or the passed `default_kind`. /// fn compute_visibility( ctx: &BindgenContext, is_declared_public: bool, callback_override: Option, annotations: &Annotations, default_kind: FieldVisibilityKind, ) -> FieldVisibilityKind { callback_override .or_else(|| annotations.visibility_kind()) .unwrap_or_else(|| { match (is_declared_public, ctx.options().respect_cxx_access_specs) { (true, true) => { // declared as public, cxx specs are respected FieldVisibilityKind::Public } (false, true) => { // declared as private, cxx specs are respected FieldVisibilityKind::Private } (_, false) => { // cxx specs are not respected, declaration does not matter. default_kind } } }) } impl FieldCodegen<'_> for BitfieldUnit { type Extra = (); fn codegen( &self, ctx: &BindgenContext, visibility_kind: FieldVisibilityKind, accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, _: (), ) where F: Extend, M: Extend, { 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 = { let unit_field_ty = unit_field_ty.clone(); if parent.is_union() { wrap_union_field_if_needed( ctx, struct_layout, unit_field_ty, result, ) } else { unit_field_ty } }; { 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 access_spec = access_specifier(visibility_kind); let align_field = quote! { #access_spec #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 unit_visibility = visibility_kind; let bfields = self.bitfields(); for (idx, bf) in bfields.iter().enumerate() { // 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; } let mut bitfield_representable_as_int = true; let mut bitfield_visibility = visibility_kind; bf.codegen( ctx, visibility_kind, accessor_kind, parent, parent_item, last_field && idx == bfields.len() - 1, result, struct_layout, fields, methods, ( &unit_field_name, &unit_field_ty, &mut bitfield_representable_as_int, &mut bitfield_visibility, ), ); if bitfield_visibility < unit_visibility { unit_visibility = bitfield_visibility; } // 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(unit_visibility); 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_raw_getter_name( ctx: &BindgenContext, bitfield: &Bitfield, ) -> proc_macro2::TokenStream { let name = bitfield.getter_name(); let name = ctx.rust_ident_raw(format!("{name}_raw")); 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 } } fn bitfield_raw_setter_name( ctx: &BindgenContext, bitfield: &Bitfield, ) -> proc_macro2::TokenStream { let setter = bitfield.setter_name(); let setter = ctx.rust_ident_raw(format!("{setter}_raw")); quote! { #setter } } impl<'a> FieldCodegen<'a> for Bitfield { type Extra = ( &'a str, &'a syn::Type, &'a mut bool, &'a mut FieldVisibilityKind, ); fn codegen( &self, ctx: &BindgenContext, visibility_kind: FieldVisibilityKind, _accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, _last_field: bool, _result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, _fields: &mut F, methods: &mut M, ( unit_field_name, unit_field_ty, bitfield_representable_as_int, bitfield_visibility, ): ( &'a str, &'a syn::Type, &mut bool, &'a mut FieldVisibilityKind, ), ) where F: Extend, M: Extend, { let prefix = ctx.trait_prefix(); let getter_name = bitfield_getter_name(ctx, self); let setter_name = bitfield_setter_name(ctx, self); let raw_getter_name = bitfield_raw_getter_name(ctx, self); let raw_setter_name = bitfield_raw_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_ident = bitfield_ty.name(); let bitfield_ty_layout = bitfield_ty .layout(ctx) .expect("Bitfield without layout? Gah!"); let bitfield_int_ty = if let Some(int_ty) = helpers::integer_type(bitfield_ty_layout) { *bitfield_representable_as_int = true; int_ty } else { *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 override_visibility = self.name().and_then(|field_name| { ctx.options().last_callback(|cb| { cb.field_visibility(FieldInfo { type_name: &parent_item.canonical_name(ctx), field_name, field_type_name: bitfield_ty_ident, }) }) }); *bitfield_visibility = compute_visibility( ctx, self.is_public(), override_visibility, self.annotations(), visibility_kind, ); let access_spec = access_specifier(*bitfield_visibility); 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 ) } } })); if ctx.options().rust_features.raw_ref_macros { methods.extend(Some(quote! { #[inline] #access_spec unsafe fn #raw_getter_name(this: *const Self) -> #bitfield_ty { unsafe { ::#prefix::mem::transmute(<#unit_field_ty>::raw_get( (*::#prefix::ptr::addr_of!((*this).#unit_field_ident)).as_ref() as *const _, #offset, #width, ) as #bitfield_int_ty) } } #[inline] #access_spec unsafe fn #raw_setter_name(this: *mut Self, val: #bitfield_ty) { unsafe { let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); <#unit_field_ty>::raw_set( (*::#prefix::ptr::addr_of_mut!((*this).#unit_field_ident)).as_mut() as *mut _, #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 ) } } })); if ctx.options().rust_features.raw_ref_macros { methods.extend(Some(quote! { #[inline] #access_spec unsafe fn #raw_getter_name(this: *const Self) -> #bitfield_ty { unsafe { ::#prefix::mem::transmute(<#unit_field_ty>::raw_get( ::#prefix::ptr::addr_of!((*this).#unit_field_ident), #offset, #width, ) as #bitfield_int_ty) } } #[inline] #access_spec unsafe fn #raw_setter_name(this: *mut Self, val: #bitfield_ty) { unsafe { let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); <#unit_field_ty>::raw_set( ::#prefix::ptr::addr_of_mut!((*this).#unit_field_ident), #offset, #width, val as u64, ) } } })); } } } } impl CodeGenerator for CompInfo { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { debug!("::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 visibility = item .annotations() .visibility_kind() .unwrap_or(ctx.options().default_visibility); let mut struct_layout = StructLayoutTracker::new( ctx, self, ty, &canonical_name, visibility, packed, ); 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> > , }); } 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 inner = inner_item .to_rust_ty_or_opaque(ctx, &()) .with_implicit_template_params(ctx, inner_item); let field_name = ctx.rust_ident(&base.field_name); struct_layout.saw_base(inner_item.expect_type()); let visibility = match ( base.is_public(), ctx.options().respect_cxx_access_specs, ) { (true, true) => FieldVisibilityKind::Public, (false, true) => FieldVisibilityKind::Private, _ => ctx.options().default_visibility, }; let access_spec = access_specifier(visibility); fields.push(quote! { #access_spec #field_name: #inner, }); } } let mut methods = vec![]; if !is_opaque { let struct_accessor_kind = item .annotations() .accessor_kind() .unwrap_or(FieldAccessorKind::None); let field_decls = self.fields(); for (idx, field) in field_decls.iter().enumerate() { field.codegen( ctx, visibility, struct_accessor_kind, self, item, idx == field_decls.len() - 1, 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), false); 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, false); 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); } } } } 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, false); fields.push(quote! { pub bindgen_union_field: #ty , }); } } if forward_decl { fields.push(quote! { _unused: [u8; 0], }); } let (flex_array_generic, flex_inner_ty) = if ctx.options().flexarray_dst { match self.flex_array_member(ctx) { Some(ty) => { let inner = ty.to_rust_ty_or_opaque(ctx, &()); ( Some(quote! { FAM: ?Sized = [ #inner; 0 ] }), Some(quote! { #inner }), ) } None => (None, None), } } else { (None, None) }; // Generics, including the flexible array member. // // generics - generic parameters for the struct declaration // impl_generics_labels - generic parameters for `impl<...>` // impl_generics_params - generic parameters for `impl structname<...>` // // `impl` blocks are for non-FAM related impls like Default, etc let (generics, impl_generics_labels, impl_generics_params) = if !generic_param_names.is_empty() || flex_array_generic.is_some() { let (flex_sized, flex_fam) = match flex_inner_ty.as_ref() { None => (None, None), Some(ty) => ( Some(quote! { [ #ty; 0 ] }), Some(quote! { FAM: ?Sized = [ #ty; 0 ] }), ), }; ( quote! { < #( #generic_param_names , )* #flex_fam > }, quote! { < #( #generic_param_names , )* > }, quote! { < #( #generic_param_names , )* #flex_sized > }, ) } else { (quote! {}, quote! {}, 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; let needs_flexarray_impl = flex_array_generic.is_some(); if let Some(comment) = item.comment(ctx) { attributes.push(attributes::doc(comment)); } // if a type has both a "packed" attribute and an "align(N)" attribute, then check if the // "packed" attr is redundant, and do not include it if so. if packed && !is_opaque && !(explicit_align.is_some() && self.already_packed(ctx).unwrap_or(false)) { 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 true { 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)); let is_rust_union = is_union && struct_layout.is_rust_union(); ctx.options().for_each_callback(|cb| { let discovered_item = match self.kind() { CompKind::Struct => DiscoveredItem::Struct { original_name: item .kind() .expect_type() .name() .map(String::from), final_name: canonical_ident.to_string(), }, CompKind::Union => DiscoveredItem::Union { original_name: item .kind() .expect_type() .name() .map(String::from), final_name: canonical_ident.to_string(), }, }; cb.new_item_found( DiscoveredItemId::new(item.id().as_usize()), discovered_item, ); }); // The custom derives callback may return a list of derive attributes; // add them to the end of the list. let custom_derives = ctx.options().all_callbacks(|cb| { cb.add_derives(&DeriveInfo { name: &canonical_name, kind: if is_rust_union { DeriveTypeKind::Union } else { DeriveTypeKind::Struct }, }) }); // 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)); } attributes.extend( item.annotations() .attributes() .iter() .map(|s| s.parse().unwrap()), ); let custom_attributes = ctx.options().all_callbacks(|cb| { cb.add_attributes(&AttributeInfo { name: &canonical_name, kind: if is_rust_union { DeriveTypeKind::Union } else { DeriveTypeKind::Struct }, }) }); attributes.extend(custom_attributes.iter().map(|s| s.parse().unwrap())); if item.must_use(ctx) { attributes.push(attributes::must_use()); } let mut tokens = if 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 {canonical_ident} has an unknown attribute that may affect layout"); } 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 compile_time = ctx.options().rust_features().offset_of; let fn_name = if compile_time { None } else { let fn_name = format!("bindgen_test_layout_{canonical_ident}"); Some(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 size_of_err = format!("Size of {canonical_ident}"); let align_of_err = format!("Alignment of {canonical_ident}"); let check_struct_align = if compile_time { quote! { [#align_of_err][#align_of_expr - #align]; } } else { quote! { assert_eq!(#align_of_expr, #align, #align_of_err); } }; let should_skip_field_offset_checks = is_opaque; 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); let offset_of_err = format!("Offset of field: {canonical_ident}::{field_name}"); if compile_time { quote! { [#offset_of_err][ ::#prefix::mem::offset_of!(#canonical_ident, #field_name) - #field_offset ]; } } else { quote! { assert_eq!( unsafe { ::#prefix::ptr::addr_of!((*ptr).#field_name) as usize - ptr as usize }, #field_offset, #offset_of_err ); } } }) }) .collect() }; let uninit_decl = if check_field_offset.is_empty() || compile_time { None } else { // 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(); }) }; if compile_time { result.push(quote! { #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { [#size_of_err][#size_of_expr - #size]; #check_struct_align #( #check_field_offset )* }; }); } else { result.push(quote! { #[test] fn #fn_name() { #uninit_decl assert_eq!(#size_of_expr, #size, #size_of_err); #check_struct_align #( #check_field_offset )* } }); } } } 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 #impl_generics_params }; if needs_clone_impl { result.push(quote! { impl #impl_generics_labels Clone for #ty_for_impl { fn clone(&self) -> Self { *self } } }); } if needs_flexarray_impl { result.push(self.generate_flexarray( ctx, &canonical_ident, flex_inner_ty, &generic_param_names, &impl_generics_labels, )); } 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::::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 compatibility is // involved. result.push(quote! { impl #impl_generics_labels 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 #impl_generics_labels ::#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() { quote! {} } else { let bounds = generic_param_names.iter().map(|t| { quote! { #t: PartialEq } }); quote! { where #( #bounds ),* } }; let prefix = ctx.trait_prefix(); result.push(quote! { impl #impl_generics_labels ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds { #impl_ } }); } } if !methods.is_empty() { result.push(quote! { impl #impl_generics_labels #ty_for_impl { #( #methods )* } }); } } } impl CompInfo { fn generate_flexarray( &self, ctx: &BindgenContext, canonical_ident: &Ident, flex_inner_ty: Option, generic_param_names: &[Ident], impl_generics_labels: &proc_macro2::TokenStream, ) -> proc_macro2::TokenStream { let prefix = ctx.trait_prefix(); let flex_array = flex_inner_ty.as_ref().map(|ty| quote! { [ #ty ] }); let dst_ty_for_impl = quote! { #canonical_ident < #( #generic_param_names , )* #flex_array > }; let sized_ty_for_impl = quote! { #canonical_ident < #( #generic_param_names , )* [ #flex_inner_ty; 0 ] > }; let layout = if ctx.options().rust_features().layout_for_ptr { quote! { pub fn layout(len: usize) -> ::#prefix::alloc::Layout { // SAFETY: Null pointers are OK if we don't deref them unsafe { let p: *const Self = ::#prefix::ptr::from_raw_parts(::#prefix::ptr::null::<()>(), len); ::#prefix::alloc::Layout::for_value_raw(p) } } } } else { quote!() }; let (from_ptr_dst, from_ptr_sized) = if ctx .options() .rust_features() .ptr_metadata { let flex_ref_inner = ctx.wrap_unsafe_ops(quote! { Self::flex_ptr(self, len) }); let flex_ref_mut_inner = ctx.wrap_unsafe_ops(quote! { Self::flex_ptr_mut(self, len).assume_init() }); let flex_ptr_inner = ctx.wrap_unsafe_ops(quote! { &*::#prefix::ptr::from_raw_parts(ptr as *const (), len) }); let flex_ptr_mut_inner = ctx.wrap_unsafe_ops(quote! { // Initialize reference without ever exposing it, as its possibly uninitialized let mut uninit = ::#prefix::mem::MaybeUninit::<&mut #dst_ty_for_impl>::uninit(); (uninit.as_mut_ptr() as *mut *mut #dst_ty_for_impl) .write(::#prefix::ptr::from_raw_parts_mut(ptr as *mut (), len)); uninit }); ( quote! { #[inline] pub fn fixed(&self) -> (& #sized_ty_for_impl, usize) { unsafe { let (ptr, len) = (self as *const Self).to_raw_parts(); (&*(ptr as *const #sized_ty_for_impl), len) } } #[inline] pub fn fixed_mut(&mut self) -> (&mut #sized_ty_for_impl, usize) { unsafe { let (ptr, len) = (self as *mut Self).to_raw_parts(); (&mut *(ptr as *mut #sized_ty_for_impl), len) } } }, quote! { /// Convert a sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. pub unsafe fn flex_ref(&self, len: usize) -> &#dst_ty_for_impl { // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. #flex_ref_inner } /// Convert a mutable sized prefix to an unsized structure with the given length. /// /// SAFETY: Underlying storage is initialized up to at least `len` elements. #[inline] pub unsafe fn flex_ref_mut(&mut self, len: usize) -> &mut #dst_ty_for_impl { // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. #flex_ref_mut_inner } /// Construct DST variant from a pointer and a size. /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. #[inline] pub unsafe fn flex_ptr<'unbounded>(ptr: *const Self, len: usize) -> &'unbounded #dst_ty_for_impl { #flex_ptr_inner } /// Construct mutable DST variant from a pointer and a /// size. The returned `&mut` reference is initialized /// pointing to memory referenced by `ptr`, but there's /// no requirement that that memory be initialized. /// /// NOTE: lifetime of returned reference is not tied to any underlying storage. /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. #[inline] pub unsafe fn flex_ptr_mut<'unbounded>( ptr: *mut Self, len: usize, ) -> ::#prefix::mem::MaybeUninit<&'unbounded mut #dst_ty_for_impl> { #flex_ptr_mut_inner } }, ) } else { (quote!(), quote!()) }; quote! { impl #impl_generics_labels #dst_ty_for_impl { #layout #from_ptr_dst } impl #impl_generics_labels #sized_ty_for_impl { #from_ptr_sized } } } } impl Method { fn codegen_method( &self, ctx: &BindgenContext, methods: &mut Vec, method_names: &mut HashSet, result: &mut CodegenResult<'_>, _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 Some(times_seen) = times_seen else { 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 TypeKind::Function(ref signature) = *signature_item.expect_type().kind() else { panic!("How in the world?") }; let supported_abi = signature.abi(ctx, Some(&*name)).is_ok(); 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; } if method_names.contains(&name) { let mut count = 1; let mut new_name; while { new_name = format!("{name}{count}"); method_names.contains(&new_name) } { count += 1; } name = new_name; } method_names.insert(name.clone()); 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 = ctx.wrap_unsafe_ops(quote! ( #( #stmts );*)); let mut attrs = vec![attributes::inline()]; if signature.must_use() { 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, Default)] 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 #[default] 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 fmt::Display for EnumVariation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { Self::Rust { non_exhaustive: false, } => "rust", Self::Rust { non_exhaustive: true, } => "rust_non_exhaustive", Self::NewType { is_bitfield: true, .. } => "bitfield", Self::NewType { is_bitfield: false, is_global, } => { if *is_global { "newtype_global" } else { "newtype" } } Self::Consts => "consts", Self::ModuleConsts => "moduleconsts", }; s.fmt(f) } } impl FromStr for EnumVariation { type Err = std::io::Error; /// Create a `EnumVariation` from a string. fn from_str(s: &str) -> Result { 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 { attrs: Vec, ident: Ident, tokens: proc_macro2::TokenStream, emitted_any_variants: bool, }, NewType { canonical_name: &'a str, tokens: proc_macro2::TokenStream, is_bitfield: bool, is_global: bool, }, Consts { variants: Vec, }, ModuleConsts { module_name: &'a str, module_items: Vec, }, } impl<'a> EnumBuilder<'a> { /// 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, repr: syn::Type, enum_variation: EnumVariation, has_typedef: bool, ) -> Self { let ident = Ident::new(name, Span::call_site()); match enum_variation { EnumVariation::NewType { is_bitfield, is_global, } => EnumBuilder::NewType { 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 { attrs, ident, tokens, emitted_any_variants: false, } } EnumVariation::Consts => { let mut variants = Vec::new(); if !has_typedef { variants.push(quote! { #( #attrs )* pub type #ident = #repr; }); } EnumBuilder::Consts { variants } } 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 { module_name: name, module_items: vec![type_definition], } } } } /// Add a variant to this enum. fn with_variant( self, ctx: &BindgenContext, variant: &EnumVariant, mangling_prefix: Option<&str>, rust_ty: syn::Type, result: &mut CodegenResult<'_>, 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(u64::from(v)) } 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 = ctx.options().process_comment(raw_comment); doc = attributes::doc(comment); } } match self { EnumBuilder::Rust { attrs, ident, tokens, emitted_any_variants: _, } => { let name = ctx.rust_ident(variant_name); EnumBuilder::Rust { attrs, ident, tokens: quote! { #tokens #doc #name = #expr, }, emitted_any_variants: true, } } EnumBuilder::NewType { canonical_name, is_global, .. } => { if 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 { 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, } } } } fn build( self, ctx: &BindgenContext, rust_ty: syn::Type, result: &mut CodegenResult<'_>, ) -> proc_macro2::TokenStream { match self { EnumBuilder::Rust { attrs, ident, tokens, emitted_any_variants, .. } => { let variants = if emitted_any_variants { tokens } else { quote!(__bindgen_cannot_repr_c_on_empty_enum = 0) }; 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( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) { debug!("::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 = if let Some(repr) = repr { match *repr.canonical_type(ctx).kind() { TypeKind::Int(int_kind) => int_kind, _ => panic!("Unexpected type as enum repr"), } } else { 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: {signed}, size: {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 true { 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() { 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 = ctx.options().all_callbacks(|cb| { cb.add_derives(&DeriveInfo { name: &name, kind: DeriveTypeKind::Enum, }) }); // 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.extend( item.annotations() .attributes() .iter() .map(|s| s.parse().unwrap()), ); // The custom attribute callback may return a list of attributes; // add them to the end of the list. let custom_attributes = ctx.options().all_callbacks(|cb| { cb.add_attributes(&AttributeInfo { name: &name, kind: DeriveTypeKind::Enum, }) }); attrs.extend(custom_attributes.iter().map(|s| s.parse().unwrap())); attrs.push(attributes::derives(&derives)); } fn add_constant( 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: syn::Type, result: &mut CodegenResult<'_>, ) { 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 has_typedef = ctx.is_enum_typedef_combo(item.id()); let mut builder = EnumBuilder::new(&name, attrs, repr, variation, has_typedef); // 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() { 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, Default)] pub enum MacroTypeVariation { /// Use i32 or i64 Signed, /// Use u32 or u64 #[default] Unsigned, } impl fmt::Display for MacroTypeVariation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { Self::Signed => "signed", Self::Unsigned => "unsigned", }; s.fmt(f) } } impl FromStr for MacroTypeVariation { type Err = std::io::Error; /// Create a `MacroTypeVariation` from a string. fn from_str(s: &str) -> Result { 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, Default)] pub enum AliasVariation { /// Convert to regular Rust alias #[default] TypeAlias, /// Create a new type by wrapping the old type in a struct and using #[repr(transparent)] NewType, /// Same as `NewType` but also impl Deref to be able to use the methods of the wrapped type NewTypeDeref, } impl fmt::Display for AliasVariation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { Self::TypeAlias => "type_alias", Self::NewType => "new_type", Self::NewTypeDeref => "new_type_deref", }; s.fmt(f) } } impl FromStr for AliasVariation { type Err = std::io::Error; /// Create an `AliasVariation` from a string. fn from_str(s: &str) -> Result { 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` `union`s 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 fmt::Display for NonCopyUnionStyle { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { Self::BindgenWrapper => "bindgen_wrapper", Self::ManuallyDrop => "manually_drop", }; s.fmt(f) } } impl Default for NonCopyUnionStyle { fn default() -> Self { Self::BindgenWrapper } } impl FromStr for NonCopyUnionStyle { type Err = std::io::Error; fn from_str(s: &str) -> Result { 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. pub(crate) 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; /// Do not override this provided trait method. fn try_to_opaque( &self, ctx: &BindgenContext, extra: &Self::Extra, ) -> error::Result { self.try_get_layout(ctx, extra) .map(|layout| helpers::blob(ctx, layout, true)) } } /// 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. pub(crate) 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, ) -> syn::Type { let layout = self.get_layout(ctx, extra); helpers::blob(ctx, layout, true) } } impl 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. pub(crate) trait TryToRustTy { type Extra; fn try_to_rust_ty( &self, ctx: &BindgenContext, extra: &Self::Extra, ) -> error::Result; } /// 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. pub(crate) trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque { type Extra; fn try_to_rust_ty_or_opaque( &self, ctx: &BindgenContext, extra: &::Extra, ) -> error::Result; } impl TryToRustTyOrOpaque for T where T: TryToRustTy + TryToOpaque, { type Extra = E; fn try_to_rust_ty_or_opaque( &self, ctx: &BindgenContext, extra: &E, ) -> error::Result { self.try_to_rust_ty(ctx, extra).or_else(|_| { if let Ok(layout) = self.try_get_layout(ctx, extra) { Ok(helpers::blob(ctx, layout, true)) } else { Err(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}` traits? 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. pub(crate) trait ToRustTyOrOpaque: TryToRustTy + ToOpaque { type Extra; fn to_rust_ty_or_opaque( &self, ctx: &BindgenContext, extra: &::Extra, ) -> syn::Type; } impl ToRustTyOrOpaque for T where T: TryToRustTy + ToOpaque, { type Extra = E; fn to_rust_ty_or_opaque( &self, ctx: &BindgenContext, extra: &E, ) -> syn::Type { self.try_to_rust_ty(ctx, extra) .unwrap_or_else(|_| self.to_opaque(ctx, extra)) } } impl TryToOpaque for T where T: Copy + Into, { type Extra = (); fn try_get_layout( &self, ctx: &BindgenContext, _: &(), ) -> error::Result { ctx.resolve_item((*self).into()).try_get_layout(ctx, &()) } } impl TryToRustTy for T where T: Copy + Into, { type Extra = (); fn try_to_rust_ty( &self, ctx: &BindgenContext, _: &(), ) -> error::Result { 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 { 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 { 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 { self.layout(ctx).ok_or(Error::NoLayoutForOpaqueBlob) } } impl TryToRustTy for Type { type Extra = Item; fn try_to_rust_ty( &self, ctx: &BindgenContext, item: &Item, ) -> error::Result { 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) => { Ok(int_kind_rust_type(ctx, ik, self.layout(ctx))) } 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 { syn::parse_quote! { root::__BindgenComplex<#float_path> } } else { syn::parse_quote! { __BindgenComplex<#float_path> } }) } TypeKind::Function(ref signature) => { // We can't rely on the sizeof(Option>) == // sizeof(NonZero<_>) optimization with opaque blobs (because // they aren't NonZero), so don't *ever* use an or_opaque // variant here. let ty = signature.try_to_rust_ty(ctx, item)?; let prefix = ctx.trait_prefix(); Ok(syn::parse_quote! { ::#prefix::option::Option<#ty> }) } TypeKind::Array(item, len) | TypeKind::Vector(item, len) => { let ty = item.try_to_rust_ty(ctx, &())?; Ok(syn::parse_quote! { [ #ty ; #len ] }) } TypeKind::Enum(..) => { let path = item.namespace_aware_canonical_path(ctx); let path = proc_macro2::TokenStream::from_str(&path.join("::")) .unwrap(); Ok(syn::parse_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) => { // Check that this type has the same size as the target's pointer type. let size = self.get_layout(ctx, item).size; if size != ctx.target_pointer_size() { return Err(Error::InvalidPointerSize { ty_name: self.name().unwrap_or("unknown").into(), ty_size: size, ptr_size: ctx.target_pointer_size(), }); } 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 ty = inner .to_rust_ty_or_opaque(ctx, &()) .with_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(syn::parse_quote! { #ident }) } TypeKind::ObjCSel => Ok(syn::parse_quote! { objc::runtime::Sel }), TypeKind::ObjCId => Ok(syn::parse_quote! { id }), TypeKind::ObjCInterface(ref interface) => { let name = ctx.rust_ident(interface.name()); Ok(syn::parse_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 { item.expect_type() .layout(ctx) .ok_or(Error::NoLayoutForOpaqueBlob) } } impl TryToRustTy for TemplateInstantiation { type Extra = Item; fn try_to_rust_ty( &self, ctx: &BindgenContext, item: &Item, ) -> error::Result { if self.is_opaque(ctx, item) { return Err(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::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 ty = arg .try_to_rust_ty(ctx, &())? .with_implicit_template_params(ctx, arg); Ok(ty) }) .collect::>>()?; Ok(if template_args.is_empty() { syn::parse_quote! { #ty } } else { syn::parse_quote! { #ty<#(#template_args),*> } }) } } impl TryToRustTy for FunctionSig { type Extra = Item; fn try_to_rust_ty( &self, ctx: &BindgenContext, item: &Item, ) -> error::Result { // 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); match self.abi(ctx, None) { Ok(abi) => Ok( syn::parse_quote! { unsafe extern #abi fn ( #( #arguments ),* ) #ret }, ), Err(err) => { if matches!(err, Error::UnsupportedAbi(_)) { unsupported_abi_diagnostic( self.name(), self.is_variadic(), item.location(), ctx, &err, ); } Err(err) } } } } 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; fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, item: &Item, ) -> Self::Return { debug!("::codegen: item = {item:?}"); debug_assert!(item.is_enabled_for_codegen(ctx)); let is_internal = matches!(self.linkage(), Linkage::Internal); let signature_item = ctx.resolve_item(self.signature()); let signature = signature_item.kind().expect_type().canonical_type(ctx); let TypeKind::Function(ref signature) = *signature.kind() else { panic!("Signature kind is not a Function: {signature:?}") }; if is_internal { if !ctx.options().wrap_static_fns { // We cannot do anything with internal functions if we are not wrapping them so // just avoid generating anything for them. return None; } if signature.is_variadic() { // We cannot generate wrappers for variadic static functions so we avoid // generating any code for them. variadic_fn_diagnostic(self.name(), item.location(), ctx); return None; } } // 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 mut attributes = vec![]; if true { 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(ctx, Some(name)) { Err(err) => { if matches!(err, Error::UnsupportedAbi(_)) { unsupported_abi_diagnostic( name, signature.is_variadic(), item.location(), ctx, &err, ); } return None; } Ok(ClangAbi::Unknown(unknown_abi)) => { panic!( "Invalid or unknown abi {unknown_abi:?} for function {canonical_name:?} ({self:?})" ); } Ok(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 mut has_link_name_attr = false; if let Some(link_name) = self.link_name() { attributes.push(attributes::link_name::(link_name)); has_link_name_attr = true; } else { 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)); has_link_name_attr = true; } } // 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 should_wrap = is_internal && ctx.options().wrap_static_fns && !has_link_name_attr; if should_wrap { let name = canonical_name.clone() + ctx.wrap_static_fns_suffix(); attributes.push(attributes::link_name::(&name)); } let wrap_as_variadic = if should_wrap && !signature.is_variadic() { utils::wrap_as_variadic_fn(ctx, signature, name) } else { None }; let (ident, args) = if let Some(WrapAsVariadic { idx_of_va_list_arg, new_name, }) = &wrap_as_variadic { ( new_name, utils::fnsig_arguments_iter( ctx, // Prune argument at index (idx_of_va_list_arg) signature.argument_types().iter().enumerate().filter_map( |(idx, t)| { if idx == *idx_of_va_list_arg { None } else { Some(t) } }, ), // and replace it by a `...` (variadic symbol and the end of the signature) true, ), ) } else { (&canonical_name, utils::fnsig_arguments(ctx, signature)) }; let ret = utils::fnsig_return_ty(ctx, signature); let ident = ctx.rust_ident(ident); let safety = ctx .options() .rust_features .unsafe_extern_blocks .then(|| quote!(unsafe)); let tokens = quote! { #wasm_link_attribute #safety extern #abi { #(#attributes)* pub fn #ident ( #( #args ),* ) #ret; } }; // Add the item to the serialization list if necessary if should_wrap { result .items_to_serialize .push((item.id(), wrap_as_variadic)); } // 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 ret_ty = utils::fnsig_return_ty(ctx, signature); result.dynamic_items().push_func( ident, abi, signature.is_variadic(), ctx.options().dynamic_link_require_all, args, args_identifiers, ret, ret_ty, attributes, ctx, ); } else { result.push(tokens); } Some(times_seen) } } #[cfg_attr(not(feature = "experimental"), allow(unused_variables))] fn unsupported_abi_diagnostic( fn_name: &str, variadic: bool, location: Option<&crate::clang::SourceLocation>, ctx: &BindgenContext, error: &Error, ) { warn!( "Skipping {}function `{fn_name}` because the {error}", if variadic { "variadic " } else { "" }, ); #[cfg(feature = "experimental")] if ctx.options().emit_diagnostics { use crate::diagnostics::{get_line, Diagnostic, Level, Slice}; let mut diag = Diagnostic::default(); diag.with_title( format!( "Skipping {}function `{fn_name}` because the {error}", if variadic { "variadic " } else { "" }, ), Level::Warning, ) .add_annotation( "No code will be generated for this function.", Level::Warning, ) .add_annotation( format!( "The configured Rust version is {}.", ctx.options().rust_target ), Level::Note, ); if let Some(loc) = location { let (file, line, col, _) = loc.location(); if let Some(filename) = file.name() { if let Ok(Some(source)) = get_line(&filename, line) { let mut slice = Slice::default(); slice .with_source(source) .with_location(filename, line, col); diag.add_slice(slice); } } } diag.display(); } } fn variadic_fn_diagnostic( fn_name: &str, _location: Option<&crate::clang::SourceLocation>, _ctx: &BindgenContext, ) { warn!( "Cannot generate wrapper for the static variadic function `{fn_name}`." ); #[cfg(feature = "experimental")] if _ctx.options().emit_diagnostics { use crate::diagnostics::{get_line, Diagnostic, Level, Slice}; let mut diag = Diagnostic::default(); diag.with_title(format!("Cannot generate wrapper for the static function `{fn_name}`."), Level::Warning) .add_annotation("The `--wrap-static-fns` feature does not support variadic functions.", Level::Note) .add_annotation("No code will be generated for this function.", Level::Note); if let Some(loc) = _location { let (file, line, col, _) = loc.location(); if let Some(filename) = file.name() { if let Ok(Some(source)) = get_line(&filename, line) { let mut slice = Slice::default(); slice .with_source(source) .with_location(filename, line, col); diag.add_slice(slice); } } } diag.display(); } } fn objc_method_codegen( ctx: &BindgenContext, method: &ObjCMethod, methods: &mut Vec, 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() { quote! { ( #( #fn_args ),* ) #fn_ret } } else { let self_arr = [quote! { &self }]; let args = self_arr.iter().chain(fn_args.iter()); quote! { ( #( #args ),* ) #fn_ret } }; let methods_and_args = method.format_method_call(&fn_args); let body = { 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)) }; ctx.wrap_unsafe_ops(body) }; let method_name = ctx.rust_ident(format!("{prefix}{}", method.rust_name())); methods.push(quote! { unsafe fn #method_name #sig where ::Target: objc::Message + Sized { #body } }); } impl CodeGenerator for ObjCInterface { type Extra = Item; type Return = (); fn codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult<'_>, 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 = 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 = Default::default(); for protocol_id in &self.conforms_to { 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 TypeKind::ObjCInterface(parent) = parent else { 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 = 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 { 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 {parent_struct_name} cannot be downcasted to {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 = 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, ) -> Result<(proc_macro2::TokenStream, BindgenOptions), CodegenError> { 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, context); result.push(dynamic_items_tokens); } utils::serialize_items(&result, context)?; Ok(postprocessing::postprocessing( result.items, context.options(), )) }) } pub(crate) mod utils { use super::helpers::BITFIELD_UNIT; use super::serialize::CSerialize; use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque}; use crate::ir::context::BindgenContext; use crate::ir::context::TypeId; use crate::ir::function::{Abi, ClangAbi, FunctionSig}; use crate::ir::item::{Item, ItemCanonicalPath}; use crate::ir::ty::TypeKind; use crate::{args_are_cpp, file_is_cpp}; use std::borrow::Cow; use std::io::Write; use std::mem; use std::path::PathBuf; use std::str::FromStr; pub(super) fn serialize_items( result: &CodegenResult, context: &BindgenContext, ) -> Result<(), CodegenError> { if result.items_to_serialize.is_empty() { return Ok(()); } let path = context.options().wrap_static_fns_path.as_ref().map_or_else( || std::env::temp_dir().join("bindgen").join("extern"), PathBuf::from, ); let dir = path.parent().unwrap(); if !dir.exists() { std::fs::create_dir_all(dir)?; } let is_cpp = args_are_cpp(&context.options().clang_args) || context .options() .input_headers .iter() .any(|h| file_is_cpp(h)); let source_path = path.with_extension(if is_cpp { "cpp" } else { "c" }); let mut code = Vec::new(); if !context.options().input_headers.is_empty() { for header in &context.options().input_headers { writeln!(code, "#include \"{header}\"")?; } writeln!(code)?; } if !context.options().input_header_contents.is_empty() { for (name, contents) in &context.options().input_header_contents { writeln!(code, "// {name}\n{contents}")?; } writeln!(code)?; } writeln!(code, "// Static wrappers\n")?; for (id, wrap_as_variadic) in &result.items_to_serialize { let item = context.resolve_item(*id); item.serialize(context, wrap_as_variadic, &mut vec![], &mut code)?; } std::fs::write(source_path, code)?; Ok(()) } pub(super) fn wrap_as_variadic_fn( ctx: &BindgenContext, signature: &FunctionSig, name: &str, ) -> Option { // Fast path, exclude because: // - with 0 args: no va_list possible, so no point searching for one // - with 1 args: cannot have a `va_list` and another arg (required by va_start) if signature.argument_types().len() <= 1 { return None; } let mut it = signature.argument_types().iter().enumerate().filter_map( |(idx, (_name, mut type_id))| { // Hand rolled visitor that checks for the presence of `va_list` loop { let ty = ctx.resolve_type(type_id); if Some("__builtin_va_list") == ty.name() { return Some(idx); } match ty.kind() { TypeKind::Alias(type_id_alias) => { type_id = *type_id_alias; } TypeKind::ResolvedTypeRef(type_id_typedef) => { type_id = *type_id_typedef; } _ => break, } } None }, ); // Return THE idx (by checking that there is no idx after) // This is done since we cannot handle multiple `va_list` it.next().filter(|_| it.next().is_none()).and_then(|idx| { // Call the `wrap_as_variadic_fn` callback #[cfg(feature = "experimental")] { ctx.options() .last_callback(|c| c.wrap_as_variadic_fn(name)) .map(|new_name| super::WrapAsVariadic { new_name, idx_of_va_list_arg: idx, }) } #[cfg(not(feature = "experimental"))] { let _ = name; let _ = idx; None } }) } pub(crate) fn prepend_bitfield_unit_type( ctx: &BindgenContext, result: &mut Vec, ) { if ctx.options().blocklisted_items.matches(BITFIELD_UNIT) || ctx.options().blocklisted_types.matches(BITFIELD_UNIT) { return; } let bitfield_unit_src = if ctx.options().rust_features().raw_ref_macros { include_str!("./bitfield_unit_raw_ref_macros.rs") } else { include_str!("./bitfield_unit.rs") }; let bitfield_unit_src = if true { 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(crate) fn prepend_objc_header( ctx: &BindgenContext, result: &mut Vec, ) { 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); } pub(crate) fn prepend_block_header( ctx: &BindgenContext, result: &mut Vec, ) { 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); } pub(crate) fn prepend_union_types( ctx: &BindgenContext, result: &mut Vec, ) { let prefix = ctx.trait_prefix(); // If the target supports `const fn`, declare eligible functions // as `const fn` else just `fn`. let const_fn = if true { 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(::#prefix::marker::PhantomData); }; let transmute = ctx.wrap_unsafe_ops(quote!(::#prefix::mem::transmute(self))); let union_field_impl = quote! { impl __BindgenUnionField { #[inline] pub #const_fn new() -> Self { __BindgenUnionField(::#prefix::marker::PhantomData) } #[inline] pub unsafe fn as_ref(&self) -> &T { #transmute } #[inline] pub unsafe fn as_mut(&mut self) -> &mut T { #transmute } } }; let union_field_default_impl = quote! { impl ::#prefix::default::Default for __BindgenUnionField { #[inline] fn default() -> Self { Self::new() } } }; let union_field_clone_impl = quote! { impl ::#prefix::clone::Clone for __BindgenUnionField { #[inline] fn clone(&self) -> Self { *self } } }; let union_field_copy_impl = quote! { impl ::#prefix::marker::Copy for __BindgenUnionField {} }; let union_field_debug_impl = quote! { impl ::#prefix::fmt::Debug for __BindgenUnionField { 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 ::#prefix::hash::Hash for __BindgenUnionField { fn hash(&self, _state: &mut H) { } } }; let union_field_partialeq_impl = quote! { impl ::#prefix::cmp::PartialEq for __BindgenUnionField { fn eq(&self, _other: &__BindgenUnionField) -> bool { true } } }; let union_field_eq_impl = quote! { impl ::#prefix::cmp::Eq for __BindgenUnionField { } }; 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); } pub(crate) fn prepend_incomplete_array_types( ctx: &BindgenContext, result: &mut Vec, ) { let prefix = ctx.trait_prefix(); // If the target supports `const fn`, declare eligible functions // as `const fn` else just `fn`. let const_fn = if true { quote! { const fn } } else { quote! { fn } }; let incomplete_array_decl = quote! { #[repr(C)] #[derive(Default)] pub struct __IncompleteArrayField( ::#prefix::marker::PhantomData, [T; 0]); }; let from_raw_parts = ctx.wrap_unsafe_ops(quote! ( ::#prefix::slice::from_raw_parts(self.as_ptr(), len) )); let from_raw_parts_mut = ctx.wrap_unsafe_ops(quote! ( ::#prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len) )); let incomplete_array_impl = quote! { impl __IncompleteArrayField { #[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] { #from_raw_parts } #[inline] pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { #from_raw_parts_mut } } }; let incomplete_array_debug_impl = quote! { impl ::#prefix::fmt::Debug for __IncompleteArrayField { 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); } pub(crate) fn prepend_float16_type( result: &mut Vec, ) { let float16_type = quote! { #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] #[repr(transparent)] pub struct __BindgenFloat16(pub u16); }; let items = vec![float16_type]; let old_items = mem::replace(result, items); result.extend(old_items); } pub(crate) fn prepend_complex_type( result: &mut Vec, ) { let complex_type = quote! { #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] #[repr(C)] pub struct __BindgenComplex { pub re: T, pub im: T } }; let items = vec![complex_type]; let old_items = mem::replace(result, items); result.extend(old_items); } pub(crate) fn prepend_opaque_array_type( result: &mut Vec, ) { let ty = quote! { /// If Bindgen could only determine the size and alignment of a /// type, it is represented like this. #[derive(PartialEq, Copy, Clone, Debug, Hash)] #[repr(C)] pub struct __BindgenOpaqueArray(pub [T; N]); impl Default for __BindgenOpaqueArray { fn default() -> Self { Self([::default(); N]) } } }; result.insert(0, ty); } pub(crate) fn build_path( item: &Item, ctx: &BindgenContext, ) -> error::Result { let path = item.namespace_aware_canonical_path(ctx); let tokens = proc_macro2::TokenStream::from_str(&path.join("::")).unwrap(); Ok(syn::parse_quote! { #tokens }) } fn primitive_ty(ctx: &BindgenContext, name: &str) -> syn::Type { let ident = ctx.rust_ident_raw(name); syn::parse_quote! { #ident } } pub(crate) fn type_from_named( ctx: &BindgenContext, name: &str, ) -> Option { // 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, }) } fn fnsig_return_ty_internal( ctx: &BindgenContext, sig: &FunctionSig, ) -> syn::Type { if sig.is_divergent() { return syn::parse_quote! { ! }; } let canonical_type_kind = sig .return_type() .into_resolver() .through_type_refs() .through_type_aliases() .resolve(ctx) .kind() .expect_type() .kind(); match canonical_type_kind { TypeKind::Void => syn::parse_quote! { () }, _ => sig.return_type().to_rust_ty_or_opaque(ctx, &()), } } pub(crate) fn fnsig_return_ty( ctx: &BindgenContext, sig: &FunctionSig, ) -> proc_macro2::TokenStream { match fnsig_return_ty_internal(ctx, sig) { syn::Type::Tuple(syn::TypeTuple { elems, .. }) if elems.is_empty() => { quote! {} } ty => quote! { -> #ty }, } } pub(crate) fn fnsig_argument_type( ctx: &BindgenContext, ty: &TypeId, ) -> syn::Type { use super::ToPtr; 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 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() || arg_ty.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()); syn::parse_quote! { #name } } else { arg_item.to_rust_ty_or_opaque(ctx, &()) } } _ => arg_item.to_rust_ty_or_opaque(ctx, &()), } } pub(crate) fn fnsig_arguments_iter< 'a, I: Iterator, TypeId)>, >( ctx: &BindgenContext, args_iter: I, is_variadic: bool, ) -> Vec { let mut unnamed_arguments = 0; let mut args = args_iter .map(|(name, ty)| { let arg_ty = fnsig_argument_type(ctx, ty); let arg_name = if let Some(ref name) = *name { ctx.rust_mangle(name).into_owned() } else { 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::>(); if is_variadic { args.push(quote! { ... }); } args } pub(crate) fn fnsig_arguments( ctx: &BindgenContext, sig: &FunctionSig, ) -> Vec { fnsig_arguments_iter( ctx, sig.argument_types().iter(), sig.is_variadic(), ) } pub(crate) fn fnsig_argument_identifiers( ctx: &BindgenContext, sig: &FunctionSig, ) -> Vec { let mut unnamed_arguments = 0; let args = sig .argument_types() .iter() .map(|&(ref name, _ty)| { let arg_name = if let Some(ref name) = *name { ctx.rust_mangle(name).into_owned() } else { unnamed_arguments += 1; format!("arg{unnamed_arguments}") }; assert!(!arg_name.is_empty()); let arg_name = ctx.rust_ident(arg_name); quote! { #arg_name } }) .collect::>(); args } pub(crate) 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 ret_ty = fnsig_return_ty_internal(ctx, sig); 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(crate) fn names_will_be_identical_after_mangling( canonical_name: &str, mangled_name: &str, call_conv: Option, ) -> 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(ClangAbi::Known(Abi::C)) | // None is the case for global variables None => { (b'_', false) } Some(ClangAbi::Known(Abi::Stdcall)) => (b'_', true), Some(ClangAbi::Known(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 } } bindgen-0.71.1/codegen/postprocessing/merge_extern_blocks.rs000064400000000000000000000043021046102023000223740ustar 00000000000000use syn::{ visit_mut::{visit_file_mut, visit_item_mod_mut, VisitMut}, File, Item, ItemForeignMod, ItemMod, }; pub(super) fn merge_extern_blocks(file: &mut File) { Visitor.visit_file_mut(file); } struct Visitor; impl VisitMut for Visitor { fn visit_file_mut(&mut self, file: &mut File) { visit_items(&mut file.items); visit_file_mut(self, file); } fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) { if let Some((_, ref mut items)) = item_mod.content { visit_items(items); } visit_item_mod_mut(self, item_mod); } } fn visit_items(items: &mut Vec) { // Keep all the extern blocks in a different `Vec` for faster search. let mut extern_blocks = Vec::::new(); for item in std::mem::take(items) { if let Item::ForeignMod(ItemForeignMod { attrs, abi, brace_token, unsafety, items: extern_block_items, }) = item { let mut exists = false; for extern_block in &mut extern_blocks { // Check if there is a extern block with the same ABI and // attributes. if extern_block.attrs == attrs && extern_block.abi == abi { // Merge the items of the two blocks. extern_block.items.extend_from_slice(&extern_block_items); exists = true; break; } } // If no existing extern block had the same ABI and attributes, store // it. if !exists { extern_blocks.push(ItemForeignMod { attrs, abi, brace_token, unsafety, items: extern_block_items, }); } } else { // If the item is not an extern block, we don't have to do anything and just // push it back. items.push(item); } } // Move all the extern blocks alongside the rest of the items. for extern_block in extern_blocks { items.push(Item::ForeignMod(extern_block)); } } bindgen-0.71.1/codegen/postprocessing/mod.rs000064400000000000000000000027461046102023000171440ustar 00000000000000use proc_macro2::TokenStream; use quote::ToTokens; use syn::{parse2, File}; 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 File), } // 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: |file| $pass(file), } }; } const PASSES: &[PostProcessingPass] = &[pass!(merge_extern_blocks), pass!(sort_semantically)]; pub(crate) fn postprocessing( items: Vec, options: &BindgenOptions, ) -> TokenStream { let items = items.into_iter().collect(); let require_syn = PASSES.iter().any(|pass| (pass.should_run)(options)); if !require_syn { return 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. // The `unwrap` here is deliberate because bindgen should generate valid rust items at all // times. let mut file = parse2::(items).unwrap(); for pass in PASSES { if (pass.should_run)(options) { (pass.run)(&mut file); } } file.into_token_stream() } bindgen-0.71.1/codegen/postprocessing/sort_semantically.rs000064400000000000000000000022271046102023000221130ustar 00000000000000use syn::{ visit_mut::{visit_file_mut, visit_item_mod_mut, VisitMut}, File, Item, ItemMod, }; pub(super) fn sort_semantically(file: &mut File) { Visitor.visit_file_mut(file); } struct Visitor; impl VisitMut for Visitor { fn visit_file_mut(&mut self, file: &mut File) { visit_items(&mut file.items); visit_file_mut(self, file); } fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) { if let Some((_, ref mut items)) = item_mod.content { visit_items(items); } visit_item_mod_mut(self, item_mod); } } fn visit_items(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, _ => 18, }); } bindgen-0.71.1/codegen/serialize.rs000064400000000000000000000337231046102023000152710ustar 00000000000000use std::io::Write; use crate::callbacks::IntKind; use crate::ir::comp::CompKind; use crate::ir::context::{BindgenContext, TypeId}; use crate::ir::function::{Function, FunctionKind}; use crate::ir::item::Item; use crate::ir::item::ItemCanonicalName; use crate::ir::item_kind::ItemKind; use crate::ir::ty::{FloatKind, Type, TypeKind}; use super::{CodegenError, WrapAsVariadic}; fn get_loc(item: &Item) -> String { item.location() .map_or_else(|| "unknown".to_owned(), |x| x.to_string()) } pub(super) trait CSerialize<'a> { type Extra; fn serialize( &self, ctx: &BindgenContext, extra: Self::Extra, stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError>; } impl<'a> CSerialize<'a> for Item { type Extra = &'a Option; fn serialize( &self, ctx: &BindgenContext, extra: Self::Extra, stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { ItemKind::Function(func) => { func.serialize(ctx, (self, extra), stack, writer) } kind => Err(CodegenError::Serialize { msg: format!("Cannot serialize item kind {kind:?}"), loc: get_loc(self), }), } } } impl<'a> CSerialize<'a> for Function { type Extra = (&'a Item, &'a Option); fn serialize( &self, ctx: &BindgenContext, (item, wrap_as_variadic): Self::Extra, stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { if self.kind() != FunctionKind::Function { return Err(CodegenError::Serialize { msg: format!( "Cannot serialize function kind {:?}", self.kind(), ), loc: get_loc(item), }); } let TypeKind::Function(signature) = ctx.resolve_type(self.signature()).kind() else { unreachable!() }; assert!(!signature.is_variadic()); let name = self.name(); // Function arguments stored as `(name, type_id)` tuples. let args = { let mut count = 0; let idx_to_prune = wrap_as_variadic.as_ref().map( |WrapAsVariadic { idx_of_va_list_arg, .. }| *idx_of_va_list_arg, ); signature .argument_types() .iter() .cloned() .enumerate() .filter_map(|(idx, (opt_name, type_id))| { if Some(idx) == idx_to_prune { None } else { Some(( opt_name.unwrap_or_else(|| { let name = format!("arg_{count}"); count += 1; name }), type_id, )) } }) .collect::>() }; // The name used for the wrapper self. let wrap_name = format!("{name}{}", ctx.wrap_static_fns_suffix()); // The function's return type let (ret_item, ret_ty) = { let type_id = signature.return_type(); let ret_item = ctx.resolve_item(type_id); let ret_ty = ret_item.expect_type(); // Write `ret_ty`. ret_ty.serialize(ctx, ret_item, stack, writer)?; (ret_item, ret_ty) }; const INDENT: &str = " "; // Write `wrap_name(args`. write!(writer, " {wrap_name}(")?; serialize_args(&args, ctx, writer)?; if wrap_as_variadic.is_none() { // Write `) { name(` if the function returns void and `) { return name(` if it does not. if ret_ty.is_void() { write!(writer, ") {{ {name}(")?; } else { write!(writer, ") {{ return {name}(")?; } } else { // Write `, ...) {` writeln!(writer, ", ...) {{")?; // Declare the return type `RET_TY ret;` if their is a need to do so if !ret_ty.is_void() { write!(writer, "{INDENT}")?; ret_ty.serialize(ctx, ret_item, stack, writer)?; writeln!(writer, " ret;")?; } // Setup va_list writeln!(writer, "{INDENT}va_list ap;\n")?; writeln!( writer, "{INDENT}va_start(ap, {});", args.last().unwrap().0 )?; write!(writer, "{INDENT}")?; // Write `ret = name(` or `name(` depending if the function returns something if !ret_ty.is_void() { write!(writer, "ret = ")?; } write!(writer, "{name}(")?; } // Get the arguments names and insert at the right place if necessary `ap` let mut args: Vec<_> = args.into_iter().map(|(name, _)| name).collect(); if let Some(WrapAsVariadic { idx_of_va_list_arg, .. }) = wrap_as_variadic { args.insert(*idx_of_va_list_arg, "ap".to_owned()); } // Write `arg_names);`. serialize_sep(", ", args.iter(), ctx, writer, |name, _, buf| { write!(buf, "{name}").map_err(From::from) })?; #[rustfmt::skip] write!(writer, ");{}", if wrap_as_variadic.is_none() { " " } else { "\n" })?; if wrap_as_variadic.is_some() { // End va_list and return the result if their is one writeln!(writer, "{INDENT}va_end(ap);")?; if !ret_ty.is_void() { writeln!(writer, "{INDENT}return ret;")?; } } writeln!(writer, "}}")?; Ok(()) } } impl CSerialize<'_> for TypeId { type Extra = (); fn serialize( &self, ctx: &BindgenContext, (): Self::Extra, stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { let item = ctx.resolve_item(*self); item.expect_type().serialize(ctx, item, stack, writer) } } impl<'a> CSerialize<'a> for Type { type Extra = &'a Item; fn serialize( &self, ctx: &BindgenContext, item: Self::Extra, stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { TypeKind::Void => { if self.is_const() { write!(writer, "const ")?; } write!(writer, "void")?; } TypeKind::NullPtr => { if self.is_const() { write!(writer, "const ")?; } write!(writer, "nullptr_t")?; } TypeKind::Int(int_kind) => { if self.is_const() { write!(writer, "const ")?; } match int_kind { IntKind::Bool => write!(writer, "bool")?, IntKind::SChar => write!(writer, "signed char")?, IntKind::UChar => write!(writer, "unsigned char")?, IntKind::WChar => write!(writer, "wchar_t")?, IntKind::Short => write!(writer, "short")?, IntKind::UShort => write!(writer, "unsigned short")?, IntKind::Int => write!(writer, "int")?, IntKind::UInt => write!(writer, "unsigned int")?, IntKind::Long => write!(writer, "long")?, IntKind::ULong => write!(writer, "unsigned long")?, IntKind::LongLong => write!(writer, "long long")?, IntKind::ULongLong => write!(writer, "unsigned long long")?, IntKind::Char { .. } => write!(writer, "char")?, int_kind => { return Err(CodegenError::Serialize { msg: format!( "Cannot serialize integer kind {int_kind:?}" ), loc: get_loc(item), }) } } } TypeKind::Float(float_kind) => { if self.is_const() { write!(writer, "const ")?; } match float_kind { FloatKind::Float16 => write!(writer, "_Float16")?, FloatKind::Float => write!(writer, "float")?, FloatKind::Double => write!(writer, "double")?, FloatKind::LongDouble => write!(writer, "long double")?, FloatKind::Float128 => write!(writer, "__float128")?, } } TypeKind::Complex(float_kind) => { if self.is_const() { write!(writer, "const ")?; } match float_kind { FloatKind::Float16 => write!(writer, "_Float16 complex")?, FloatKind::Float => write!(writer, "float complex")?, FloatKind::Double => write!(writer, "double complex")?, FloatKind::LongDouble => { write!(writer, "long double complex")?; } FloatKind::Float128 => write!(writer, "__complex128")?, } } TypeKind::Alias(type_id) => { if let Some(name) = self.name() { if self.is_const() { write!(writer, "const {name}")?; } else { write!(writer, "{name}")?; } } else { type_id.serialize(ctx, (), stack, writer)?; } } TypeKind::Array(type_id, length) => { type_id.serialize(ctx, (), stack, writer)?; write!(writer, " [{length}]")?; } TypeKind::Function(signature) => { if self.is_const() { stack.push("const ".to_string()); } signature.return_type().serialize( ctx, (), &mut vec![], writer, )?; write!(writer, " (")?; while let Some(item) = stack.pop() { write!(writer, "{item}")?; } write!(writer, ")")?; let args = signature.argument_types(); if args.is_empty() { write!(writer, " (void)")?; } else { write!(writer, " (")?; serialize_sep( ", ", args.iter(), ctx, writer, |(name, type_id), ctx, buf| { let mut stack = vec![]; if let Some(name) = name { stack.push(name.clone()); } type_id.serialize(ctx, (), &mut stack, buf) }, )?; write!(writer, ")")?; } } TypeKind::ResolvedTypeRef(type_id) => { if self.is_const() { write!(writer, "const ")?; } type_id.serialize(ctx, (), stack, writer)?; } TypeKind::Pointer(type_id) => { if self.is_const() { stack.push("*const ".to_owned()); } else { stack.push("*".to_owned()); } type_id.serialize(ctx, (), stack, writer)?; } TypeKind::Comp(comp_info) => { if self.is_const() { write!(writer, "const ")?; } let name = item.canonical_name(ctx); match comp_info.kind() { CompKind::Struct => write!(writer, "struct {name}")?, CompKind::Union => write!(writer, "union {name}")?, }; } TypeKind::Enum(_enum_ty) => { if self.is_const() { write!(writer, "const ")?; } let name = item.canonical_name(ctx); write!(writer, "enum {name}")?; } ty => { return Err(CodegenError::Serialize { msg: format!("Cannot serialize type kind {ty:?}"), loc: get_loc(item), }) } }; if !stack.is_empty() { write!(writer, " ")?; while let Some(item) = stack.pop() { write!(writer, "{item}")?; } } Ok(()) } } fn serialize_args( args: &[(String, TypeId)], ctx: &BindgenContext, writer: &mut W, ) -> Result<(), CodegenError> { if args.is_empty() { write!(writer, "void")?; } else { serialize_sep( ", ", args.iter(), ctx, writer, |(name, type_id), ctx, buf| { type_id.serialize(ctx, (), &mut vec![name.clone()], buf) }, )?; } Ok(()) } fn serialize_sep< W: Write, F: FnMut(I::Item, &BindgenContext, &mut W) -> Result<(), CodegenError>, I: Iterator, >( sep: &str, mut iter: I, ctx: &BindgenContext, buf: &mut W, mut f: F, ) -> Result<(), CodegenError> { if let Some(item) = iter.next() { f(item, ctx, buf)?; let sep = sep.as_bytes(); for item in iter { buf.write_all(sep)?; f(item, ctx, buf)?; } } Ok(()) } bindgen-0.71.1/codegen/struct_layout.rs000064400000000000000000000334051046102023000162200ustar 00000000000000//! 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 crate::FieldVisibilityKind; use proc_macro2::{Ident, Span}; use std::cmp; const MAX_GUARANTEED_ALIGN: usize = 8; /// Trace the layout of struct. #[derive(Debug)] pub(crate) struct StructLayoutTracker<'a> { name: &'a str, ctx: &'a BindgenContext, comp: &'a CompInfo, is_packed: bool, known_type_layout: Option, is_rust_union: bool, can_copy_union_fields: bool, latest_offset: usize, padding_count: usize, latest_field_layout: Option, max_field_align: usize, last_field_was_bitfield: bool, visibility: FieldVisibilityKind, last_field_was_flexible_array: bool, } /// Returns a size aligned to a given value. pub(crate) 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(crate) 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(crate) fn new( ctx: &'a BindgenContext, comp: &'a CompInfo, ty: &'a Type, name: &'a str, visibility: FieldVisibilityKind, is_packed: bool, ) -> Self { let known_type_layout = ty.layout(ctx); let (is_rust_union, can_copy_union_fields) = comp.is_rust_union(ctx, known_type_layout.as_ref(), name); StructLayoutTracker { name, ctx, comp, visibility, 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, last_field_was_flexible_array: false, } } pub(crate) fn can_copy_union_fields(&self) -> bool { self.can_copy_union_fields } pub(crate) fn is_rust_union(&self) -> bool { self.is_rust_union } pub(crate) fn saw_flexible_array(&mut self) { self.last_field_was_flexible_array = true; } pub(crate) 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(crate) 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(crate) fn saw_bitfield_unit(&mut self, layout: Layout) { debug!("saw bitfield unit for {}: {layout:?}", self.name); self.align_to_latest_field(layout); self.latest_offset += layout.size; debug!( "Offset: : {} -> {}", self.latest_offset - layout.size, self.latest_offset ); self.latest_field_layout = Some(layout); self.last_field_was_bitfield = true; self.max_field_align = cmp::max(self.max_field_align, layout.align); } /// Returns a padding field if necessary for a given new field _before_ /// adding that field. pub(crate) fn saw_field( &mut self, field_name: &str, field_ty: &Type, field_offset: Option, ) -> Option { 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(crate) fn saw_field_with_layout( &mut self, field_name: &str, field_layout: Layout, field_offset: Option, ) -> Option { 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(mut l) = self.known_type_layout { if field_layout.align < l.align { l.align = field_layout.align; } 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: : {} -> {}", self.latest_offset - padding_bytes, self.latest_offset ); debug!( "align field {field_name} to {}/{} with {padding_bytes} padding bytes {field_layout:?}", self.latest_offset, field_offset.unwrap_or(0) / 8, ); 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(crate) fn add_tail_padding( &mut self, comp_name: &str, comp_layout: Layout, ) -> Option { // 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; } // Also doesn't make sense for structs with flexible array members if self.last_field_was_flexible_array { 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 {comp_name}: offset {} -> size {}", self.latest_offset, comp_layout.size ); let size = comp_layout.size - self.latest_offset; Some(self.padding_field(Layout::new(size, 0))) } pub(crate) fn pad_struct( &mut self, layout: Layout, ) -> Option { debug!("pad_struct:\n\tself = {self:#?}\n\tlayout = {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 = true; // 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 {}, {layout:?}", self.name); Some(self.padding_field(layout)) } else { None } } pub(crate) fn requires_explicit_align(&self, layout: Layout) -> bool { let repr_align = true; // 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, false); 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); let vis = super::access_specifier(self.visibility); quote! { #vis #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 Some(layout) = self.latest_field_layout else { 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? {}: {layout:?} {new_field_layout:?}", self.last_field_was_bitfield, ); // 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 } } bindgen-0.71.1/deps.rs000064400000000000000000000034111046102023000126200ustar 00000000000000/// 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>) -> std::io::Result<()> { std::fs::write(&self.depfile_path, self.to_string(deps)) } fn to_string(&self, deps: &BTreeSet>) -> String { // Transforms a string by escaping spaces and backslashes. let escape = |s: &str| s.replace('\\', "\\\\").replace(' ', "\\ "); let mut buf = format!("{}:", escape(&self.output_module)); for file in deps { buf = format!("{buf} {}", escape(file)); } buf } } #[cfg(test)] mod tests { use super::*; #[test] fn escaping_depfile() { let spec = DepfileSpec { output_module: "Mod Name".to_owned(), depfile_path: PathBuf::new(), }; let deps: BTreeSet<_> = vec![ r"/absolute/path".into(), r"C:\win\absolute\path".into(), r"../relative/path".into(), r"..\win\relative\path".into(), r"../path/with spaces/in/it".into(), r"..\win\path\with spaces\in\it".into(), r"path\with/mixed\separators".into(), ] .into_iter() .collect(); assert_eq!( spec.to_string(&deps), "Mod\\ Name: \ ../path/with\\ spaces/in/it \ ../relative/path \ ..\\\\win\\\\path\\\\with\\ spaces\\\\in\\\\it \ ..\\\\win\\\\relative\\\\path \ /absolute/path \ C:\\\\win\\\\absolute\\\\path \ path\\\\with/mixed\\\\separators" ); } } bindgen-0.71.1/diagnostics.rs000064400000000000000000000103311046102023000141730ustar 00000000000000//! Types and function used to emit pretty diagnostics for `bindgen`. //! //! The entry point of this module is the [`Diagnostic`] type. use std::fmt::Write; use std::io::{self, BufRead, BufReader}; use std::{borrow::Cow, fs::File}; use annotate_snippets::{Renderer, Snippet}; pub(crate) use annotate_snippets::Level; /// A `bindgen` diagnostic. #[derive(Default)] pub(crate) struct Diagnostic<'a> { title: Option<(Cow<'a, str>, Level)>, slices: Vec>, footer: Vec<(Cow<'a, str>, Level)>, } impl<'a> Diagnostic<'a> { /// Add a title to the diagnostic and set its type. pub(crate) fn with_title( &mut self, title: impl Into>, level: Level, ) -> &mut Self { self.title = Some((title.into(), level)); self } /// Add a slice of source code to the diagnostic. pub(crate) fn add_slice(&mut self, slice: Slice<'a>) -> &mut Self { self.slices.push(slice); self } /// Add a footer annotation to the diagnostic. This annotation will have its own type. pub(crate) fn add_annotation( &mut self, msg: impl Into>, level: Level, ) -> &mut Self { self.footer.push((msg.into(), level)); self } /// Print this diagnostic. /// /// The diagnostic is printed using `cargo:warning` if `bindgen` is being invoked by a build /// script or using `eprintln` otherwise. pub(crate) fn display(&self) { std::thread_local! { static INVOKED_BY_BUILD_SCRIPT: bool = std::env::var_os("CARGO_CFG_TARGET_ARCH").is_some(); } let mut footer = vec![]; let mut slices = vec![]; let snippet = if let Some((msg, level)) = &self.title { (*level).title(msg) } else { return; }; for (msg, level) in &self.footer { footer.push((*level).title(msg)); } // add additional info that this is generated by bindgen // so as to not confuse with rustc warnings footer.push( Level::Info.title("This diagnostic was generated by bindgen."), ); for slice in &self.slices { if let Some(source) = &slice.source { let mut snippet = Snippet::source(source) .line_start(slice.line.unwrap_or_default()); if let Some(origin) = &slice.filename { snippet = snippet.origin(origin); } slices.push(snippet); } } let renderer = Renderer::styled(); let dl = renderer.render(snippet.snippets(slices).footers(footer)); if INVOKED_BY_BUILD_SCRIPT.with(Clone::clone) { // This is just a hack which hides the `warning:` added by cargo at the beginning of // every line. This should be fine as our diagnostics already have a colorful title. // FIXME (pvdrz): Could it be that this doesn't work in other languages? let hide_warning = "\r \r"; let string = dl.to_string(); for line in string.lines() { println!("cargo:warning={hide_warning}{line}"); } } else { eprintln!("{dl}\n"); } } } /// A slice of source code. #[derive(Default)] pub(crate) struct Slice<'a> { source: Option>, filename: Option, line: Option, } impl<'a> Slice<'a> { /// Set the source code. pub(crate) fn with_source( &mut self, source: impl Into>, ) -> &mut Self { self.source = Some(source.into()); self } /// Set the file, line and column. pub(crate) fn with_location( &mut self, mut name: String, line: usize, col: usize, ) -> &mut Self { write!(name, ":{line}:{col}").expect("Writing to a string cannot fail"); self.filename = Some(name); self.line = Some(line); self } } pub(crate) fn get_line( filename: &str, line: usize, ) -> io::Result> { let file = BufReader::new(File::open(filename)?); if let Some(line) = file.lines().nth(line.wrapping_sub(1)) { return line.map(Some); } Ok(None) } bindgen-0.71.1/extra_assertions.rs000064400000000000000000000010741046102023000152650ustar 00000000000000//! 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_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 )* ) } }; } bindgen-0.71.1/features.rs000064400000000000000000000375251046102023000135200ustar 00000000000000//! Contains code for selecting features #![deny(unused_extern_crates)] #![deny(clippy::missing_docs_in_private_items)] #![allow(deprecated)] use std::str::FromStr; use std::{fmt, io}; /// Represents the version of the Rust language to target. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] #[repr(transparent)] pub struct RustTarget(Version); impl RustTarget { /// Create a new [`RustTarget`] for a stable release of Rust. pub fn stable(minor: u64, patch: u64) -> Result { let target = Self(Version::Stable(minor, patch)); if target < EARLIEST_STABLE_RUST { return Err(InvalidRustTarget::TooEarly); } Ok(target) } const fn minor(&self) -> Option { match self.0 { Version::Nightly => None, Version::Stable(minor, _) => Some(minor), } } const fn is_compatible(&self, other: &Self) -> bool { match (self.0, other.0) { (Version::Stable(minor, _), Version::Stable(other_minor, _)) => { // We ignore the patch version number as they only include backwards compatible bug // fixes. minor >= other_minor } // Nightly is compatible with everything (Version::Nightly, _) => true, // No stable release is compatible with nightly (Version::Stable { .. }, Version::Nightly) => false, } } } impl Default for RustTarget { fn default() -> Self { LATEST_STABLE_RUST } } impl fmt::Display for RustTarget { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { Version::Stable(minor, patch) => write!(f, "1.{minor}.{patch}"), Version::Nightly => "nightly".fmt(f), } } } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] enum Version { Stable(u64, u64), Nightly, } pub enum InvalidRustTarget { TooEarly, } impl fmt::Display for InvalidRustTarget { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::TooEarly => write!(f, "the earliest Rust version supported by bindgen is {EARLIEST_STABLE_RUST}"), } } } /// This macro defines the Rust editions supported by bindgen. macro_rules! define_rust_editions { ($($variant:ident($value:literal) => $minor:literal,)*) => { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] #[doc = "Represents Rust Edition for the generated bindings"] pub enum RustEdition { $( #[doc = concat!("The ", stringify!($value), " edition of Rust.")] $variant, )* } impl FromStr for RustEdition { type Err = InvalidRustEdition; fn from_str(s: &str) -> Result { match s { $(stringify!($value) => Ok(Self::$variant),)* _ => Err(InvalidRustEdition(s.to_owned())), } } } impl fmt::Display for RustEdition { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { $(Self::$variant => stringify!($value).fmt(f),)* } } } impl RustEdition { pub(crate) const ALL: [Self; [$($value,)*].len()] = [$(Self::$variant,)*]; pub(crate) fn is_available(self, target: RustTarget) -> bool { let Some(minor) = target.minor() else { return true; }; match self { $(Self::$variant => $minor <= minor,)* } } } } } #[derive(Debug)] pub struct InvalidRustEdition(String); impl fmt::Display for InvalidRustEdition { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\"{}\" is not a valid Rust edition", self.0) } } impl std::error::Error for InvalidRustEdition {} define_rust_editions! { Edition2018(2018) => 31, Edition2021(2021) => 56, Edition2024(2024) => 85, } impl RustTarget { /// Returns the latest edition supported by this target. pub(crate) fn latest_edition(self) -> RustEdition { RustEdition::ALL .iter() .rev() .find(|edition| edition.is_available(self)) .copied() .expect("bindgen should always support at least one edition") } } impl Default for RustEdition { fn default() -> Self { RustTarget::default().latest_edition() } } /// This macro defines the [`RustTarget`] and [`RustFeatures`] types. macro_rules! define_rust_targets { ( Nightly => {$($nightly_feature:ident $(($nightly_edition:literal))|* $(: #$issue:literal)?),* $(,)?} $(,)? $( $variant:ident($minor:literal) => {$($feature:ident $(($edition:literal))|* $(: #$pull:literal)?),* $(,)?}, )* $(,)? ) => { impl RustTarget { /// The nightly version of Rust, which introduces the following features:" $(#[doc = concat!( "- [`", stringify!($nightly_feature), "`]", "(", $("https://github.com/rust-lang/rust/pull/", stringify!($issue),)* ")", )])* #[deprecated = "The use of this constant is deprecated, please use `RustTarget::nightly` instead."] pub const Nightly: Self = Self::nightly(); /// The nightly version of Rust, which introduces the following features:" $(#[doc = concat!( "- [`", stringify!($nightly_feature), "`]", "(", $("https://github.com/rust-lang/rust/pull/", stringify!($issue),)* ")", )])* pub const fn nightly() -> Self { Self(Version::Nightly) } $( #[doc = concat!("Version 1.", stringify!($minor), " of Rust, which introduced the following features:")] $(#[doc = concat!( "- [`", stringify!($feature), "`]", "(", $("https://github.com/rust-lang/rust/pull/", stringify!($pull),)* ")", )])* #[deprecated = "The use of this constant is deprecated, please use `RustTarget::stable` instead."] pub const $variant: Self = Self(Version::Stable($minor, 0)); )* const fn stable_releases() -> [(Self, u64); [$($minor,)*].len()] { [$((Self::$variant, $minor),)*] } } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub(crate) struct RustFeatures { $($(pub(crate) $feature: bool,)*)* $(pub(crate) $nightly_feature: bool,)* } impl RustFeatures { /// Compute the features that must be enabled in a specific Rust target with a specific edition. pub(crate) fn new(target: RustTarget, edition: RustEdition) -> Self { let mut features = Self { $($($feature: false,)*)* $($nightly_feature: false,)* }; if target.is_compatible(&RustTarget::nightly()) { $( let editions: &[RustEdition] = &[$(stringify!($nightly_edition).parse::().ok().expect("invalid edition"),)*]; if editions.is_empty() || editions.contains(&edition) { features.$nightly_feature = true; } )* } $( if target.is_compatible(&RustTarget::$variant) { $( let editions: &[RustEdition] = &[$(stringify!($edition).parse::().ok().expect("invalid edition"),)*]; if editions.is_empty() || editions.contains(&edition) { features.$feature = true; } )* } )* features } } }; } // NOTE: When adding or removing features here, make sure to add the stabilization PR // number for the feature if it has been stabilized or the tracking issue number if the feature is // not stable. define_rust_targets! { Nightly => { vectorcall_abi: #124485, ptr_metadata: #81513, layout_for_ptr: #69835, }, Stable_1_82(82) => { unsafe_extern_blocks: #127921, }, Stable_1_77(77) => { offset_of: #106655, literal_cstr(2021)|(2024): #117472, }, Stable_1_73(73) => { thiscall_abi: #42202 }, Stable_1_71(71) => { c_unwind_abi: #106075 }, Stable_1_68(68) => { abi_efiapi: #105795 }, Stable_1_64(64) => { core_ffi_c: #94503 }, Stable_1_51(51) => { raw_ref_macros: #80886, min_const_generics: #74878, }, Stable_1_59(59) => { const_cstr: #54745 }, Stable_1_47(47) => { larger_arrays: #74060 }, Stable_1_43(43) => { associated_constants: #68952 }, Stable_1_40(40) => { non_exhaustive: #44109 }, Stable_1_36(36) => { maybe_uninit: #60445 }, Stable_1_33(33) => { repr_packed_n: #57049 }, } /// Latest stable release of Rust that is supported by bindgen pub const LATEST_STABLE_RUST: RustTarget = { // FIXME: replace all this code by // ``` // RustTarget::stable_releases() // .into_iter() // .max_by_key(|(_, m)| m) // .map(|(t, _)| t) // .unwrap() // ``` // once those operations can be used in constants. let targets = RustTarget::stable_releases(); let mut i = 0; let mut latest_target = None; let mut latest_minor = 0; while i < targets.len() { let (target, minor) = targets[i]; if latest_minor < minor { latest_minor = minor; latest_target = Some(target); } i += 1; } match latest_target { Some(target) => target, None => unreachable!(), } }; /// Earliest stable release of Rust that is supported by bindgen pub const EARLIEST_STABLE_RUST: RustTarget = { // FIXME: replace all this code by // ``` // RustTarget::stable_releases() // .into_iter() // .min_by_key(|(_, m)| m) // .map(|(t, _)| t) // .unwrap_or(LATEST_STABLE_RUST) // ``` // once those operations can be used in constants. let targets = RustTarget::stable_releases(); let mut i = 0; let mut earliest_target = None; let Some(mut earliest_minor) = LATEST_STABLE_RUST.minor() else { unreachable!() }; while i < targets.len() { let (target, minor) = targets[i]; if earliest_minor > minor { earliest_minor = minor; earliest_target = Some(target); } i += 1; } match earliest_target { Some(target) => target, None => unreachable!(), } }; fn invalid_input(input: &str, msg: impl fmt::Display) -> io::Error { io::Error::new( io::ErrorKind::InvalidInput, format!("\"{input}\" is not a valid Rust target, {msg}"), ) } impl FromStr for RustTarget { type Err = io::Error; fn from_str(input: &str) -> Result { if input == "nightly" { return Ok(Self::Nightly); } let Some((major_str, tail)) = input.split_once('.') else { return Err(invalid_input(input, "accepted values are of the form \"1.71\", \"1.71.1\" or \"nightly\"." ) ); }; if major_str != "1" { return Err(invalid_input( input, "The largest major version of Rust released is \"1\"", )); } let (minor, patch) = if let Some((minor_str, patch_str)) = tail.split_once('.') { let Ok(minor) = minor_str.parse::() else { return Err(invalid_input(input, "the minor version number must be an unsigned 64-bit integer")); }; let Ok(patch) = patch_str.parse::() else { return Err(invalid_input(input, "the patch version number must be an unsigned 64-bit integer")); }; (minor, patch) } else { let Ok(minor) = tail.parse::() else { return Err(invalid_input(input, "the minor version number must be an unsigned 64-bit integer")); }; (minor, 0) }; Self::stable(minor, patch).map_err(|err| invalid_input(input, err)) } } impl RustFeatures { /// Compute the features that must be enabled in a specific Rust target with the latest edition /// available in that target. pub(crate) fn new_with_latest_edition(target: RustTarget) -> Self { Self::new(target, target.latest_edition()) } } impl Default for RustFeatures { fn default() -> Self { Self::new_with_latest_edition(RustTarget::default()) } } #[cfg(test)] mod test { use super::*; #[test] fn release_versions_for_editions() { assert_eq!( "1.33".parse::().unwrap().latest_edition(), RustEdition::Edition2018 ); assert_eq!( "1.56".parse::().unwrap().latest_edition(), RustEdition::Edition2021 ); assert_eq!( "1.85".parse::().unwrap().latest_edition(), RustEdition::Edition2024 ); assert_eq!( "nightly".parse::().unwrap().latest_edition(), RustEdition::Edition2024 ); } #[test] fn target_features() { let features = RustFeatures::new_with_latest_edition(RustTarget::Stable_1_71); assert!( features.c_unwind_abi && features.abi_efiapi && !features.thiscall_abi ); let features = RustFeatures::new( RustTarget::Stable_1_77, RustEdition::Edition2018, ); assert!(!features.literal_cstr); let features = RustFeatures::new_with_latest_edition(RustTarget::Stable_1_77); assert!(features.literal_cstr); let f_nightly = RustFeatures::new_with_latest_edition(RustTarget::Nightly); assert!( f_nightly.vectorcall_abi && f_nightly.ptr_metadata && f_nightly.layout_for_ptr ); } fn test_target(input: &str, expected: RustTarget) { // Two targets are equivalent if they enable the same set of features let expected = RustFeatures::new_with_latest_edition(expected); let found = RustFeatures::new_with_latest_edition( input.parse::().unwrap(), ); assert_eq!( expected, found, "target {input} enables features:\n{found:#?}\nand should enable features:\n{expected:#?}" ); } fn test_invalid_target(input: &str) { assert!( input.parse::().is_err(), "{input} should be an invalid target" ); } #[test] fn valid_targets() { test_target("1.71", RustTarget::Stable_1_71); test_target("1.71.0", RustTarget::Stable_1_71); test_target("1.71.1", RustTarget::Stable_1_71); test_target("1.72", RustTarget::Stable_1_71); test_target("1.73", RustTarget::Stable_1_73); test_target("1.18446744073709551615", LATEST_STABLE_RUST); test_target("nightly", RustTarget::Nightly); } #[test] fn invalid_targets() { test_invalid_target("2.0"); test_invalid_target("1.cat"); test_invalid_target("1.0.cat"); test_invalid_target("1.18446744073709551616"); test_invalid_target("1.0.18446744073709551616"); test_invalid_target("1.-1.0"); test_invalid_target("1.0.-1"); test_invalid_target("beta"); test_invalid_target("1.0.0"); test_invalid_target("1.32.0"); } } bindgen-0.71.1/ir/analysis/derive.rs000064400000000000000000000625001046102023000154040ustar 00000000000000//! 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(crate) 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, // 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 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>, } 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 CannotDerive<'_> { fn insert>( &mut self, id: Id, can_derive: CanDerive, ) -> ConstrainResult { let id = id.into(); trace!( "inserting {id:?} can_derive<{}>={can_derive:?}", self.derive_trait, ); 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().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() }); 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 => 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()).copied().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()).copied().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().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().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() }); 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) .copied() .unwrap_or_default(); match can_derive { CanDerive::Yes => trace!(" member {sub_id:?} can derive {}", self.derive_trait), CanDerive::Manually => trace!(" member {sub_id:?} cannot derive {}, but it may be implemented", self.derive_trait), CanDerive::No => trace!(" member {sub_id:?} cannot derive {}", 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 {self}, but it may be implemented"); CanDerive::Manually } (_, false) => { trace!(" function pointer cannot derive {self}"); CanDerive::No } } } fn can_derive_vector(&self) -> CanDerive { if *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 } else { trace!(" vector can derive {self}"); CanDerive::Yes } } fn can_derive_pointer(&self) -> CanDerive { if *self == DeriveTrait::Default { trace!(" pointer cannot derive Default"); CanDerive::No } else { 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; 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 { // The transitive closure of all allowlisted items, including explicitly // blocklisted items. self.ctx .allowlisted_items() .iter() .copied() .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) { 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).is_some_and(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(&self, id: ItemId, mut f: F) where F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&id) { for item in edges { trace!("enqueue {item:?} into worklist"); f(*item); } } } } impl<'ctx> From> for HashMap { fn from(analysis: CannotDerive<'ctx>) -> Self { extra_assert!(analysis .can_derive .values() .all(|v| *v != CanDerive::Yes)); analysis.can_derive } } /// Convert a `HashMap` into a `HashSet`. /// /// Elements that are not `CanDerive::Yes` are kept in the set, so that it /// represents all items that cannot derive. pub(crate) fn as_cannot_derive_set( can_derive: HashMap, ) -> HashSet { can_derive .into_iter() .filter_map(|(k, v)| if v == CanDerive::Yes { None } else { Some(k) }) .collect() } bindgen-0.71.1/ir/analysis/has_destructor.rs000064400000000000000000000143641046102023000171640ustar 00000000000000//! 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(crate) 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, // Dependencies saying that if a key ItemId has been inserted into the // `have_destructor` set, then each of the ids in Vec 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>, } impl HasDestructorAnalysis<'_> { 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>(&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 {id:?} twice because if it was \ already in the set, `constrain` should have exited early." ); ConstrainResult::Changed } } impl<'ctx> MonotoneFramework for HasDestructorAnalysis<'ctx> { type Node = ItemId; type Extra = &'ctx BindgenContext; type Output = HashSet; 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 { self.ctx.allowlisted_items().iter().copied().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(&self, id: ItemId, mut f: F) where F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&id) { for item in edges { trace!("enqueue {item:?} into worklist"); f(*item); } } } } impl<'ctx> From> for HashSet { fn from(analysis: HasDestructorAnalysis<'ctx>) -> Self { analysis.have_destructor } } bindgen-0.71.1/ir/analysis/has_float.rs000064400000000000000000000205721046102023000160710ustar 00000000000000//! 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(crate) struct HasFloat<'ctx> { ctx: &'ctx BindgenContext, // The incremental result of this analysis's computation. Everything in this // set has float. has_float: HashSet, // Dependencies saying that if a key ItemId has been inserted into the // `has_float` set, then each of the ids in Vec 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>, } impl HasFloat<'_> { 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>(&mut self, id: Id) -> ConstrainResult { let id = id.into(); trace!("inserting {id:?} into the has_float set"); let was_not_already_in_set = self.has_float.insert(id); assert!( was_not_already_in_set, "We shouldn't try and insert {id:?} twice because if it was \ already in the set, `constrain` should have exited early." ); ConstrainResult::Changed } } impl<'ctx> MonotoneFramework for HasFloat<'ctx> { type Node = ItemId; type Extra = &'ctx BindgenContext; type Output = HashSet; 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 { self.ctx.allowlisted_items().iter().copied().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 Some(ty) = item.as_type() else { 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 \ instantiation 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 \ instantiation also has" ); return self.insert(id); } trace!(" template instantiation do not have float"); ConstrainResult::Same } } } fn each_depending_on(&self, id: ItemId, mut f: F) where F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&id) { for item in edges { trace!("enqueue {item:?} into worklist"); f(*item); } } } } impl<'ctx> From> for HashSet { fn from(analysis: HasFloat<'ctx>) -> Self { analysis.has_float } } bindgen-0.71.1/ir/analysis/has_type_param_in_array.rs000064400000000000000000000211121046102023000210000ustar 00000000000000//! 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 parameter 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(crate) 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, // 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 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>, } impl HasTypeParameterInArray<'_> { 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>(&mut self, id: Id) -> ConstrainResult { let id = id.into(); trace!("inserting {id:?} into the has_type_parameter_in_array set"); 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 {id:?} twice because if it was \ already in the set, `constrain` should have exited early." ); ConstrainResult::Changed } } impl<'ctx> MonotoneFramework for HasTypeParameterInArray<'ctx> { type Node = ItemId; type Extra = &'ctx BindgenContext; type Output = HashSet; 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 { self.ctx.allowlisted_items().iter().copied().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 Some(ty) = item.as_type() else { 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); if let TypeKind::TypeParam = *inner_ty.kind() { trace!(" Array with Named type has type parameter"); self.insert(id) } else { 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 \ instantiation 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 \ instantiation also has" ); return self.insert(id); } trace!(" template instantiation do not have array"); ConstrainResult::Same } } } fn each_depending_on(&self, id: ItemId, mut f: F) where F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&id) { for item in edges { trace!("enqueue {item:?} into worklist"); f(*item); } } } } impl<'ctx> From> for HashSet { fn from(analysis: HasTypeParameterInArray<'ctx>) -> Self { analysis.has_type_parameter_in_array } } bindgen-0.71.1/ir/analysis/has_vtable.rs000064400000000000000000000164541046102023000162450ustar 00000000000000//! 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, Default)] pub(crate) enum HasVtableResult { /// The item does not have a vtable pointer. #[default] 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 HasVtableResult { /// Take the least upper bound of `self` and `rhs`. pub(crate) 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(crate) 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, // Dependencies saying that if a key ItemId has been inserted into the // `have_vtable` set, then each of the ids in Vec 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>, } impl HasVtableAnalysis<'_> { 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>( &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(&mut self, from: Id1, to: Id2) -> ConstrainResult where Id1: Into, Id2: Into, { let from = from.into(); let to = to.into(); match self.have_vtable.get(&from) { 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; 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 { self.ctx.allowlisted_items().iter().copied().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(&self, id: ItemId, mut f: F) where F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&id) { for item in edges { trace!("enqueue {item:?} into worklist"); f(*item); } } } } impl<'ctx> From> for HashMap { 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(crate) 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; } bindgen-0.71.1/ir/analysis/mod.rs000064400000000000000000000327471046102023000147170ustar 00000000000000//! 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(crate) use self::template_params::UsedTemplateParameters; mod derive; pub use self::derive::DeriveTrait; pub(crate) use self::derive::{as_cannot_derive_set, CannotDerive}; mod has_vtable; pub(crate) use self::has_vtable::{ HasVtable, HasVtableAnalysis, HasVtableResult, }; mod has_destructor; pub(crate) use self::has_destructor::HasDestructorAnalysis; mod has_type_param_in_array; pub(crate) use self::has_type_param_in_array::HasTypeParameterInArray; mod has_float; pub(crate) use self::has_float::HasFloat; mod sizedness; pub(crate) 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(crate) 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 + 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; /// 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(&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, Default)] pub(crate) enum ConstrainResult { /// The incremental results were updated, and the fix-point computation /// should continue. Changed, /// The incremental results were not updated. #[default] 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(crate) fn analyze(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(crate) fn generate_dependencies( ctx: &BindgenContext, consider_edge: F, ) -> HashMap> 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::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>); 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 { reversed.0.entry(*node).or_insert_with(Vec::new); for referent in edges { reversed .0 .entry(*referent) .or_insert_with(Vec::new) .push(*node); } } reversed } } #[derive(Clone, Debug, PartialEq, Eq)] struct ReachableFrom<'a> { reachable: HashMap>, graph: &'a Graph, reversed: Graph, } impl<'a> MonotoneFramework for ReachableFrom<'a> { type Node = Node; type Extra = &'a Graph; type Output = HashMap>; fn new(graph: &'a Graph) -> Self { let reversed = graph.reverse(); ReachableFrom { reachable: Default::default(), graph, reversed, } } fn initial_worklist(&self) -> Vec { self.graph.0.keys().copied().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_default().len(); for sub_node in &self.graph.0[&node] { self.reachable.get_mut(&node).unwrap().insert(*sub_node); let sub_reachable = self.reachable.entry(*sub_node).or_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::Same } else { ConstrainResult::Changed } } fn each_depending_on(&self, node: Node, mut f: F) where F: FnMut(Node), { for dep in &self.reversed.0[&node] { f(*dep); } } } impl<'a> From> for HashMap> { fn from(reachable: ReachableFrom<'a>) -> Self { reachable.reachable } } #[test] fn monotone() { let g = Graph::make_test_graph(); let reachable = analyze::(&g); println!("reachable = {reachable:#?}"); fn nodes(nodes: A) -> HashSet where A: AsRef<[usize]>, { nodes.as_ref().iter().copied().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); } } bindgen-0.71.1/ir/analysis/sizedness.rs000064400000000000000000000264171046102023000161440ustar 00000000000000//! 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, Default)] pub(crate) 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. #[default] 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 Flongo : public T {}; /// /// class Empty {}; /// /// class NonEmpty { int x; }; /// ``` /// /// Then `Flongo` is zero-sized, and needs an `_address` byte /// inserted, while `Flongo` is *not* zero-sized, and should *not* /// have an `_address` byte inserted. /// /// We don't properly handle this situation correctly right now: /// 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 SizednessResult { /// Take the least upper bound of `self` and `rhs`. pub(crate) 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(crate) struct SizednessAnalysis<'ctx> { ctx: &'ctx BindgenContext, dependencies: HashMap>, // Incremental results of the analysis. Missing entries are implicitly // considered `ZeroSized`. sized: HashMap, } impl SizednessAnalysis<'_> { 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 {result:?} for {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) { 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; 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::>(), ) }) }) .collect(); let sized = HashMap::default(); SizednessAnalysis { ctx, dependencies, sized, } } fn initial_worklist(&self) -> Vec { self.ctx .allowlisted_items() .iter() .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) { 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(&self, id: TypeId, mut f: F) where F: FnMut(TypeId), { if let Some(edges) = self.dependencies.get(&id) { for ty in edges { trace!("enqueue {ty:?} into worklist"); f(*ty); } } } } impl<'ctx> From> for HashMap { 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(crate) 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 } } bindgen-0.71.1/ir/analysis/template_params.rs000064400000000000000000000547571046102023000173230ustar 00000000000000//! 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` inside a generic Rust struct to make up for //! this. That doesn't work for templated type aliases, however: //! //! ```C++ //! template //! using Fml = int; //! ``` //! //! If we generate the naive Rust code for this alias, we get: //! //! ```ignore //! pub(crate) type Fml = ::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`. 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 //! 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 //! class DoesntUseT { //! int x; //! }; //! //! template //! class Fml { //! DoesntUseT 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(crate) 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>, dependencies: HashMap>, // 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, } impl UsedTemplateParameters<'_> { 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>( &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() }); 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 {arg:?} is used if definition's \ parameter {param:?} is used", ); 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(); 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(); trace!( " union with {sub_id:?}'s usage: {:?}", used_by_sub_id.clone().collect::>() ); 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; 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().copied().collect(); let allowlisted_and_blocklisted_items: ItemSet = allowlisted_items .iter() .copied() .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(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 { 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 { // The transitive closure of all allowlisted items, including explicitly // blocklisted items. self.ctx .allowlisted_items() .iter() .copied() .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(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::Same } else { ConstrainResult::Changed } } fn each_depending_on(&self, item: ItemId, mut f: F) where F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&item) { for item in edges { trace!("enqueue {item:?} into worklist"); f(*item); } } } } impl<'ctx> From> for HashMap { fn from(used_templ_params: UsedTemplateParameters<'ctx>) -> Self { used_templ_params .used .into_iter() .map(|(k, v)| (k, v.unwrap())) .collect() } } bindgen-0.71.1/ir/annotations.rs000064400000000000000000000205311046102023000146360ustar 00000000000000//! 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 std::str::FromStr; use crate::clang; /// What kind of visibility modifier should be used for a struct or field? #[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Default)] pub enum FieldVisibilityKind { /// Fields are marked as private, i.e., struct Foo {bar: bool} Private, /// Fields are marked as crate public, i.e., struct Foo {pub(crate) bar: bool} PublicCrate, /// Fields are marked as public, i.e., struct Foo {pub bar: bool} #[default] Public, } impl FromStr for FieldVisibilityKind { type Err = String; fn from_str(s: &str) -> Result { match s { "private" => Ok(Self::Private), "crate" => Ok(Self::PublicCrate), "public" => Ok(Self::Public), _ => Err(format!("Invalid visibility kind: `{s}`")), } } } impl std::fmt::Display for FieldVisibilityKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let s = match self { FieldVisibilityKind::Private => "private", FieldVisibilityKind::PublicCrate => "crate", FieldVisibilityKind::Public => "public", }; s.fmt(f) } } /// What kind of accessor should we provide for a field? #[derive(Copy, PartialEq, Eq, Clone, Debug)] pub(crate) 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](https://www.doxygen.nl/manual/docblocks.html). #[derive(Default, Clone, PartialEq, Eq, Debug)] pub(crate) 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>, /// 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, /// Visibility of struct fields. You can set this on /// structs (it will apply to all the fields), or individual fields. visibility_kind: Option, /// 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, /// Whether this enum variant should be constified. /// /// This is controlled by the `constant` attribute, this way: /// /// ```cpp /// enum Foo { /// Bar = 0, /**<

*/ /// 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, /// List of explicit attributes for this type. attributes: Vec, } 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(crate) fn new(cursor: &clang::Cursor) -> Option { 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(crate) fn hide(&self) -> bool { self.hide } /// Should this type be opaque? pub(crate) fn opaque(&self) -> bool { self.opaque } /// For a given type, indicates the type it should replace. /// /// For example, in the following code: /// /// ```cpp /// /// /**
*/ /// struct Foo { int x; }; /// /// struct Bar { char foo; }; /// ``` /// /// the generated code would look something like: /// /// ``` /// /**
*/ /// struct Bar { /// x: ::std::os::raw::c_int, /// }; /// ``` /// /// That is, code for `Foo` is used to generate `Bar`. pub(crate) 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(crate) fn derives(&self) -> &[String] { &self.derives } /// The list of attributes that have been specified in this annotation. pub(crate) fn attributes(&self) -> &[String] { &self.attributes } /// Should we avoid implementing the `Copy` trait? pub(crate) fn disallow_copy(&self) -> bool { self.disallow_copy } /// Should we avoid implementing the `Debug` trait? pub(crate) fn disallow_debug(&self) -> bool { self.disallow_debug } /// Should we avoid implementing the `Default` trait? pub(crate) fn disallow_default(&self) -> bool { self.disallow_default } /// Should this type get a `#[must_use]` annotation? pub(crate) fn must_use_type(&self) -> bool { self.must_use_type } /// What kind of accessors should we provide for this type's fields? pub(crate) fn visibility_kind(&self) -> Option { self.visibility_kind } /// What kind of accessors should we provide for this type's fields? pub(crate) fn accessor_kind(&self) -> Option { 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() .is_some_and(|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), "attribute" => self.attributes.push(attr.value), "private" => { self.visibility_kind = if attr.value == "false" { Some(FieldVisibilityKind::Public) } else { Some(FieldVisibilityKind::Private) }; } "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(crate) fn constify_enum_variant(&self) -> bool { self.constify_enum_variant } } bindgen-0.71.1/ir/comment.rs000064400000000000000000000054761046102023000137560ustar 00000000000000//! 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(crate) fn preprocess(comment: &str) -> String { match kind(comment) { Some(Kind::SingleLines) => preprocess_single_lines(comment), Some(Kind::MultiLine) => preprocess_multi_line(comment), None => comment.to_owned(), } } /// Gets the kind of the doc comment, if it is one. fn kind(comment: &str) -> Option { if comment.starts_with("/*") { Some(Kind::MultiLine) } else if comment.starts_with("//") { Some(Kind::SingleLines) } else { None } } /// Preprocesses multiple single line comments. /// /// Handles lines starting with both `//` and `///`. fn preprocess_single_lines(comment: &str) -> String { debug_assert!(comment.starts_with("//"), "comment is not single line"); let lines: Vec<_> = comment .lines() .map(|l| l.trim().trim_start_matches('/')) .collect(); lines.join("\n") } fn preprocess_multi_line(comment: &str) -> String { let comment = comment .trim_start_matches('/') .trim_end_matches('/') .trim_end_matches('*'); // Strip any potential `*` characters preceding each line. 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. .collect(); // Remove the trailing line corresponding to the `*/`. if lines.last().is_some_and(|l| l.trim().is_empty()) { 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("///"), ""); assert_eq!(preprocess("/// hello"), " hello"); assert_eq!(preprocess("// hello"), " hello"); assert_eq!(preprocess("// hello"), " hello"); } #[test] fn processes_multi_lines_correctly() { assert_eq!(preprocess("/**/"), ""); assert_eq!( preprocess("/** hello \n * world \n * foo \n */"), " hello\n world\n foo" ); assert_eq!( preprocess("/**\nhello\n*world\n*foo\n*/"), "hello\nworld\nfoo" ); } } bindgen-0.71.1/ir/comp.rs000064400000000000000000001712101046102023000132400ustar 00000000000000//! Compound types (unions and structs) in our intermediate representation. use itertools::Itertools; 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::ParseError; use crate::HashMap; use crate::NonCopyUnionStyle; use std::cmp; use std::io; use std::mem; /// The kind of compound type. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) enum CompKind { /// A struct. Struct, /// A union. Union, } /// The kind of C++ method. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) 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(crate) fn is_destructor(&self) -> bool { matches!( *self, MethodKind::Destructor | MethodKind::VirtualDestructor { .. } ) } /// Is this a pure virtual method? pub(crate) 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(crate) 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(crate) fn new( kind: MethodKind, signature: FunctionId, is_const: bool, ) -> Self { Method { kind, signature, is_const, } } /// What kind of method is this? pub(crate) fn kind(&self) -> MethodKind { self.kind } /// Is this a constructor? pub(crate) fn is_constructor(&self) -> bool { self.kind == MethodKind::Constructor } /// Is this a virtual method? pub(crate) fn is_virtual(&self) -> bool { matches!( self.kind, MethodKind::Virtual { .. } | MethodKind::VirtualDestructor { .. } ) } /// Is this a static method? pub(crate) fn is_static(&self) -> bool { self.kind == MethodKind::Static } /// Get the ID for the `Function` signature for this method. pub(crate) fn signature(&self) -> FunctionId { self.signature } /// Is this a const qualified method? pub(crate) fn is_const(&self) -> bool { self.is_const } } /// Methods common to the various field types. pub(crate) 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; /// Is this field 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; } /// 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(crate) struct BitfieldUnit { nth: usize, layout: Layout, bitfields: Vec, } 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(crate) fn nth(&self) -> usize { self.nth } /// Get the layout within which these bitfields reside. pub(crate) fn layout(&self) -> Layout { self.layout } /// Get the bitfields within this unit. pub(crate) fn bitfields(&self) -> &[Bitfield] { &self.bitfields } } /// A struct representing a C++ field. #[derive(Debug)] pub(crate) 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(crate) fn layout(&self, ctx: &BindgenContext) -> Option { 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(&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( &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#" bitfield unit "#, layout.size, layout.align )?; for bf in bitfields { bf.dot_attributes(ctx, out)?; } writeln!(out, "
unit.size{}
unit.align{}
") } } } } impl DotAttributes for FieldData { fn dot_attributes( &self, _ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!( out, "{}{:?}", self.name().unwrap_or("(anonymous)"), self.ty() ) } } impl DotAttributes for Bitfield { fn dot_attributes( &self, _ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!( out, "{} : {}{:?}", self.name().unwrap_or("(anonymous)"), self.width(), self.ty() ) } } /// A logical bitfield within some physical bitfield allocation unit. #[derive(Debug)] pub(crate) 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, /// Name of the generated Rust setter for this bitfield. /// /// Should be assigned before codegen. setter_name: Option, } 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(crate) fn offset_into_unit(&self) -> usize { self.offset_into_unit } /// Get the bit width of this bitfield. pub(crate) 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(crate) 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(crate) 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 { self.data.bitfield_width() } fn is_public(&self) -> bool { self.data.is_public() } fn annotations(&self) -> &Annotations { self.data.annotations() } fn offset(&self) -> Option { 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, ty: TypeId, comment: Option, annotations: Option, bitfield_width: Option, public: bool, offset: Option, ) -> 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 { self.0.bitfield_width() } fn is_public(&self) -> bool { self.0.is_public() } fn annotations(&self) -> &Annotations { self.0.annotations() } fn offset(&self) -> Option { 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( ctx: &BindgenContext, raw_fields: I, packed: bool, ) -> Result<(Vec, bool), ()> where I: IntoIterator, { 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( ctx: &BindgenContext, bitfield_unit_count: &mut usize, fields: &mut E, raw_bitfields: I, packed: bool, ) -> Result<(), ()> where E: Extend, I: IntoIterator, { 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( fields: &mut E, bitfield_unit_count: &mut usize, unit_size_in_bits: usize, unit_align_in_bits: usize, bitfields: Vec, packed: bool, ) where E: Extend, { *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), After { fields: Vec, 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 = 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!( "{}{anon_field_counter}", ctx.options().anon_fields_prefix, )); } 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); } } } } } } /// Return the flex array member for the struct/class, if any. fn flex_array_member(&self, ctx: &BindgenContext) -> Option { let fields = match self { CompFields::Before(_) => panic!("raw fields"), CompFields::After { fields, .. } => fields, CompFields::Error => return None, // panic? }; match fields.last()? { Field::Bitfields(..) => None, Field::DataMember(FieldData { ty, .. }) => ctx .resolve_type(*ty) .is_incomplete_array(ctx) .map(|item| item.expect_type_id(ctx)), } } } impl Trace for CompFields { type Extra = (); fn trace(&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(crate) struct FieldData { /// The name of the field, empty if it's an unnamed bitfield width. name: Option, /// The inner type. ty: TypeId, /// The doc comment on the field if any. comment: Option, /// 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, /// If the C++ field is declared `public` public: bool, /// The offset of the field (in bits) offset: Option, } 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 { self.bitfield_width } fn is_public(&self) -> bool { self.public } fn annotations(&self) -> &Annotations { &self.annotations } fn offset(&self) -> Option { self.offset } } /// The kind of inheritance a base class is using. #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) 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(crate) struct Base { /// The type of this base class. pub(crate) ty: TypeId, /// The kind of inheritance we're doing. pub(crate) kind: BaseKind, /// Name of the field in which this base should be stored. pub(crate) field_name: String, /// Whether this base is inherited from publicly. pub(crate) is_pub: bool, } impl Base { /// Whether this base class is inheriting virtually. pub(crate) fn is_virtual(&self) -> bool { self.kind == BaseKind::Virtual } /// Whether this base class should have it's own field for storage. pub(crate) 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 publicly. pub(crate) 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(crate) 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, /// The method declarations inside this class, if in C++ mode. methods: Vec, /// The different constructors this struct or class contains. constructors: Vec, /// 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, /// The inner types that were declared inside this class, in something like: /// /// ```c++ /// class Foo { /// typedef int FooTy; /// struct Bar { /// int baz; /// }; /// } /// /// static Foo::Bar const = {3}; /// ``` inner_types: Vec, /// Set of static constants declared inside this class. inner_vars: Vec, /// 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(crate) 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(crate) fn layout(&self, ctx: &BindgenContext) -> Option { // 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(crate) fn fields(&self) -> &[Field] { match self.fields { CompFields::Error => &[], CompFields::After { ref fields, .. } => fields, CompFields::Before(..) => { panic!("Should always have computed bitfield units first"); } } } /// Return the flex array member and its element type if any pub(crate) fn flex_array_member( &self, ctx: &BindgenContext, ) -> Option { self.fields.flex_array_member(ctx) } 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 { if let Some(layout) = field.layout(ctx) { callback(layout); } } } CompFields::Before(ref raw_fields) => { for field in raw_fields { 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(crate) 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(crate) 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(crate) fn has_own_virtual_method(&self) -> bool { self.has_own_virtual_method } /// Did we see a destructor when parsing this type? pub(crate) fn has_own_destructor(&self) -> bool { self.has_destructor } /// Get this type's set of methods. pub(crate) fn methods(&self) -> &[Method] { &self.methods } /// Get this type's set of constructors. pub(crate) fn constructors(&self) -> &[FunctionId] { &self.constructors } /// Get this type's destructor. pub(crate) fn destructor(&self) -> Option<(MethodKind, FunctionId)> { self.destructor } /// What kind of compound type is this? pub(crate) fn kind(&self) -> CompKind { self.kind } /// Is this a union? pub(crate) fn is_union(&self) -> bool { self.kind() == CompKind::Union } /// The set of types that this one inherits from. pub(crate) fn base_members(&self) -> &[Base] { &self.base_members } /// Construct a new compound type from a Clang type. pub(crate) fn from_ty( potential_id: ItemId, ty: &clang::Type, location: Option, ctx: &mut BindgenContext, ) -> Result { 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.is_anonymous() && 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 shouldn'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() == 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 { 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(crate) fn inner_types(&self) -> &[TypeId] { &self.inner_types } /// Get the set of static variables declared within this compound type. pub(crate) 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(crate) fn found_unknown_attr(&self) -> bool { self.found_unknown_attr } /// Is this compound type packed? pub(crate) 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 } /// Return true if a compound type is "naturally packed". This means we can exclude the /// "packed" attribute without changing the layout. /// This is useful for types that need an "align(N)" attribute since rustc won't compile /// structs that have both of those attributes. pub(crate) fn already_packed(&self, ctx: &BindgenContext) -> Option { let mut total_size: usize = 0; for field in self.fields() { let layout = field.layout(ctx)?; if layout.align != 0 && total_size % layout.align != 0 { return Some(false); } total_size += layout.size; } Some(true) } /// Returns true if compound type has been forward declared pub(crate) fn is_forward_declaration(&self) -> bool { self.is_forward_declaration } /// Compute this compound structure's bitfield allocation units. pub(crate) 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(crate) 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(crate) fn is_rust_union( &self, ctx: &BindgenContext, layout: Option<&Layout>, name: &str, ) -> (bool, bool) { if !self.is_union() { return (false, false); } if !ctx.options().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.is_some_and(|l| l.size == 0) { return (false, false); } (true, all_can_copy) } } impl DotAttributes for CompInfo { fn dot_attributes( &self, ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!(out, "CompKind{:?}", self.kind)?; if self.has_own_virtual_method { writeln!(out, "has_vtabletrue")?; } if self.has_destructor { writeln!(out, "has_destructortrue")?; } if self.has_nonempty_base { writeln!(out, "has_nonempty_basetrue")?; } if self.has_non_type_template_params { writeln!( out, "has_non_type_template_paramstrue" )?; } if self.packed_attr { writeln!(out, "packed_attrtrue")?; } if self.is_forward_declaration { writeln!( out, "is_forward_declarationtrue" )?; } if !self.fields().is_empty() { writeln!(out, r#"fields"#)?; for field in self.fields() { field.dot_attributes(ctx, out)?; } writeln!(out, "
")?; } Ok(()) } } impl IsOpaque for CompInfo { type Extra = Option; fn is_opaque(&self, ctx: &BindgenContext, layout: &Option) -> 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 { self.template_params.clone() } } impl Trace for CompInfo { type Extra = Item; fn trace(&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, &()); } } bindgen-0.71.1/ir/context.rs000064400000000000000000003411331046102023000137710ustar 00000000000000//! 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::clang::{self, ABIKind, Cursor}; use crate::codegen::CodegenError; use crate::BindgenOptions; use crate::{Entry, HashMap, HashSet}; use proc_macro2::{Ident, Span, TokenStream}; use quote::ToTokens; use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::collections::{BTreeSet, HashMap as StdHashMap}; use std::fs::OpenOptions; use std::io::Write; use std::mem; use std::path::Path; /// An identifier for some kind of IR item. #[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] pub(crate) struct ItemId(usize); /// Declare a newtype around `ItemId` with conversion methods. macro_rules! item_id_newtype { ( $( #[$attr:meta] )* pub(crate) 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(crate) struct $name(ItemId); impl $name { /// Create an `ItemResolver` from this ID. #[allow(dead_code)] pub(crate) fn into_resolver(self) -> ItemResolver { let id: ItemId = self.into(); id.into() } } impl ::std::cmp::PartialEq for $name where T: Copy + Into { 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 } } #[allow(dead_code)] impl ItemId { $( #[$checked_attr] )* pub(crate) fn $checked(&self, ctx: &BindgenContext) -> Option<$name> { if ctx.resolve_item(*self).kind().$check_method() { Some($name(*self)) } else { None } } $( #[$expected_attr] )* pub(crate) 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(crate) fn $unchecked(&self) -> $name { $name(*self) } } } } item_id_newtype! { /// An identifier for an `Item` whose `ItemKind` is known to be /// `ItemKind::Type`. pub(crate) 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(crate) 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(crate) 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(crate) 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 for usize { fn from(id: ItemId) -> usize { id.0 } } impl ItemId { /// Get a numeric representation of this ID. pub(crate) fn as_usize(&self) -> usize { (*self).into() } } impl ::std::cmp::PartialEq for ItemId where T: Copy + Into, { fn eq(&self, rhs: &T) -> bool { let rhs: ItemId = (*rhs).into(); self.0 == rhs.0 } } impl CanDeriveDebug for T where T: Copy + Into, { fn can_derive_debug(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_debug && ctx.lookup_can_derive_debug(*self) } } impl CanDeriveDefault for T where T: Copy + Into, { fn can_derive_default(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_default && ctx.lookup_can_derive_default(*self) } } impl CanDeriveCopy for T where T: Copy + Into, { fn can_derive_copy(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_copy && ctx.lookup_can_derive_copy(*self) } } impl CanDeriveHash for T where T: Copy + Into, { fn can_derive_hash(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_hash && ctx.lookup_can_derive_hash(*self) } } impl CanDerivePartialOrd for T where T: Copy + Into, { fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_partialord && ctx.lookup_can_derive_partialeq_or_partialord(*self) == CanDerive::Yes } } impl CanDerivePartialEq for T where T: Copy + Into, { fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool { ctx.options().derive_partialeq && ctx.lookup_can_derive_partialeq_or_partialord(*self) == CanDerive::Yes } } impl CanDeriveEq for T where T: Copy + Into, { 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 CanDeriveOrd for T where T: Copy + Into, { 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(crate) struct BindgenContext { /// The map of all the items parsed so far, keyed off `ItemId`. items: Vec>, /// Clang USR to type map. This is needed to be able to associate types with /// item ids during parsing. types: HashMap, /// Maps from a cursor to the item ID of the named template type parameter /// for that cursor. type_params: HashMap, /// A cursor to module map. Similar reason than above. modules: HashMap, /// 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, /// 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, /// 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, cexpr::expr::EvalResult>, /// A map with all include locations. /// /// This is needed so that items are created in the order they are defined in. /// /// The key is the included file, the value is a pair of the source file and /// the position of the `#include` directive in the source file. includes: StdHashMap, /// A set of all the included filenames. deps: BTreeSet>, /// The active replacements collected from replaces="xxx" annotations. replacements: HashMap, ItemId>, collected_typerefs: bool, in_codegen: bool, /// The translation unit for parsing. translation_unit: clang::TranslationUnit, /// The translation unit for macro fallback parsing. fallback_tu: Option, /// 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 an opaque array was generated generated_opaque_array: Cell, /// Whether a bindgen complex was generated generated_bindgen_complex: Cell, /// Whether a bindgen float16 was generated generated_bindgen_float16: Cell, /// 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, /// Cache for calls to `ParseCallbacks::blocklisted_type_implements_trait` blocklisted_types_implement_traits: RefCell>>, /// 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, /// 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>, /// 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, /// The set of enums that are defined by a pair of `enum` and `typedef`, /// which is legal in C (but not C++). /// /// ```c++ /// // in either order /// enum Enum { Variants... }; /// typedef int16_t Enum; /// ``` /// /// The stored `ItemId` is that of the `TypeKind::Enum`, not of the /// `TypeKind::Alias`. /// /// This is populated when we enter codegen by `compute_enum_typedef_combos` /// and is always `None` before that and `Some` after. enum_typedef_combos: Option>, /// 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>, /// 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>, /// 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>, /// 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>, /// 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>, /// The sizedness of types. /// /// This is populated by `compute_sizedness` and is always `None` before /// that function is invoked and `Some` afterwards. sizedness: Option>, /// 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>, /// 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>, /// 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>, /// 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>, } /// A traversal of allowlisted items. struct AllowlistedItemsTraversal<'ctx> { ctx: &'ctx BindgenContext, traversal: ItemTraversal<'ctx, ItemSet, Vec>, } impl Iterator for AllowlistedItemsTraversal<'_> { type Item = ItemId; fn next(&mut self) -> Option { 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(crate) fn new( ctx: &'ctx BindgenContext, roots: R, predicate: for<'a> fn(&'a BindgenContext, Edge) -> bool, ) -> Self where R: IntoIterator, { 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 deps = options.input_headers.iter().cloned().collect(); BindgenContext { items: vec![Some(root_module)], includes: Default::default(), 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, fallback_tu: None, target_info, options, generated_bindgen_complex: Cell::new(false), generated_bindgen_float16: Cell::new(false), generated_opaque_array: Cell::new(false), allowlisted: None, blocklisted_types_implement_traits: Default::default(), codegen_items: None, used_template_parameters: None, need_bitfield_allocation: Default::default(), enum_typedef_combos: None, 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, } } /// Returns `true` if the target architecture is wasm32 pub(crate) 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(crate) 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(crate) fn target_pointer_size(&self) -> usize { self.target_info.pointer_width / 8 } /// Returns the ABI, which is mostly useful for determining the mangling kind. pub(crate) fn abi_kind(&self) -> ABIKind { self.target_info.abi } /// Get the stack of partially parsed types that we are in the middle of /// parsing. pub(crate) 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(crate) 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(crate) fn finish_parsing(&mut self) -> PartialType { self.currently_parsed_types.pop().expect( "should have been parsing a type, if we finished parsing a type", ) } /// Add the location of the `#include` directive for the `included_file`. pub(crate) fn add_include( &mut self, source_file: String, included_file: String, offset: usize, ) { self.includes .entry(included_file) .or_insert((source_file, offset)); } /// Get the location of the first `#include` directive for the `included_file`. pub(crate) fn included_file_location( &self, included_file: &str, ) -> Option<(String, usize)> { self.includes.get(included_file).cloned() } /// Add an included file. pub(crate) fn add_dep(&mut self, dep: Box) { self.deps.insert(dep); } /// Get any included files. pub(crate) fn deps(&self) -> &BTreeSet> { &self.deps } /// Define a new item. /// /// This inserts it into the internal items set, and its type into the /// internal types set. pub(crate) fn add_item( &mut self, item: Item, declaration: Option, location: Option, ) { debug!("BindgenContext::add_item({item:?}, declaration: {declaration:?}, loc: {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 {declaration:?} found for type {:?}", 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(crate) fn add_type_param(&mut self, item: Item, definition: Cursor) { debug!("BindgenContext::add_type_param: item = {item:?}; definition = {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(crate) fn get_type_param(&self, definition: &Cursor) -> Option { assert_eq!( definition.kind(), clang_sys::CXCursor_TemplateTypeParameter ); self.type_params.get(definition).copied() } // 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(crate) 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(crate) fn rust_ident(&self, name: S) -> Ident where S: AsRef, { self.rust_ident_raw(self.rust_mangle(name.as_ref())) } /// Returns a mangled name as a rust identifier. pub(crate) fn rust_ident_raw(&self, name: T) -> Ident where T: AsRef, { Ident::new(name.as_ref(), Span::call_site()) } /// Iterate over all items that have been defined. pub(crate) fn items(&self) -> impl Iterator { 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(crate) fn collected_typerefs(&self) -> bool { self.collected_typerefs } /// Gather all the unresolved type references. fn collect_typerefs( &mut self, ) -> Vec<(ItemId, clang::Type, Cursor, Option)> { debug_assert!(!self.collected_typerefs); self.collected_typerefs = true; let mut typerefs = vec![]; for (id, item) in self.items() { let kind = item.kind(); let Some(ty) = kind.as_type() else { 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(&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 = 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 Some(ty) = item.kind().as_type() else { 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 {id:?} with {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().is_some_and(|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( mut self, cb: F, ) -> Result<(Out, BindgenOptions), CodegenError> where F: FnOnce(&Self) -> Result, { 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_enum_typedef_combos(); 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)?; Ok((ret, self.options)) } /// 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 {id:?} is a child of {ancestor:?}"); self.resolve_item(ancestor) .as_module() .is_some_and(|m| m.children().contains(&id)) }) }, "{id:?} should be in some ancestor module's children set" ); } } } /// 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::(self)); } /// Look up whether the type with the given ID is sized or not. pub(crate) 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) .copied() .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::(self)); } /// Look up whether the item with `id` has vtable or not. pub(crate) 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()) .copied() .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::(self)); } /// Look up whether the item with `id` has a destructor. pub(crate) 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::(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(crate) 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).is_some_and(|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(crate) 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) .is_some_and(|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(crate) 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(crate) 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(crate) 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(crate) 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(crate) fn resolve_item_fallible>( &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(crate) fn resolve_item>(&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(crate) 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(crate) fn add_semantic_parent( &mut self, definition: Cursor, parent_id: ItemId, ) { self.semantic_parents.insert(definition, parent_id); } /// Returns a known semantic parent for a given definition. pub(crate) fn known_semantic_parent( &self, definition: Cursor, ) -> Option { self.semantic_parents.get(&definition).copied() } /// 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) }) .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`. /// /// 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>` 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 /// class Incomplete { /// T p; /// }; /// /// template /// class Foo { /// Incomplete 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: Cursor, ) -> Option { 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` versus `Bar`. // 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(crate) fn get_resolved_type( &self, decl: &clang::CanonicalTypeDeclaration, ) -> Option { self.types .get(&TypeKey::Declaration(*decl.cursor())) .or_else(|| { decl.cursor() .usr() .and_then(|usr| self.types.get(&TypeKey::Usr(usr))) }) .copied() } /// Looks up for an already resolved type, either because it's builtin, or /// because we already have it in the map. pub(crate) fn builtin_or_resolved_ty( &mut self, with_id: ItemId, parent_id: Option, ty: &clang::Type, location: Option, ) -> Option { 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(crate) fn build_ty_wrapper( &mut self, with_id: ItemId, wrapped_id: TypeId, parent_id: Option, 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(crate) fn build_const_wrapper( &mut self, with_id: ItemId, wrapped_id: TypeId, parent_id: Option, 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, 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(crate) 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 { 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_Float16 | CXType_Half => TypeKind::Float(FloatKind::Float16), 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_Float16 | CXType_Half => FloatKind::Float16, 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(crate) fn translation_unit(&self) -> &clang::TranslationUnit { &self.translation_unit } /// Initialize fallback translation unit if it does not exist and /// then return a mutable reference to the fallback translation unit. pub(crate) fn try_ensure_fallback_translation_unit( &mut self, ) -> Option<&mut clang::FallbackTranslationUnit> { if self.fallback_tu.is_none() { let file = format!( "{}/.macro_eval.c", match self.options().clang_macro_fallback_build_dir { Some(ref path) => path.as_os_str().to_str()?, None => ".", } ); let index = clang::Index::new(false, false); let mut header_names_to_compile = Vec::new(); let mut header_paths = Vec::new(); let mut header_contents = String::new(); for input_header in &self.options.input_headers { let path = Path::new(input_header.as_ref()); if let Some(header_path) = path.parent() { if header_path == Path::new("") { header_paths.push("."); } else { header_paths.push(header_path.as_os_str().to_str()?); } } else { header_paths.push("."); } let header_name = path.file_name()?.to_str()?; header_names_to_compile .push(header_name.split(".h").next()?.to_string()); header_contents += format!("\n#include <{header_name}>").as_str(); } let header_to_precompile = format!( "{}/{}", match self.options().clang_macro_fallback_build_dir { Some(ref path) => path.as_os_str().to_str()?, None => ".", }, header_names_to_compile.join("-") + "-precompile.h" ); let pch = header_to_precompile.clone() + ".pch"; let mut header_to_precompile_file = OpenOptions::new() .create(true) .truncate(true) .write(true) .open(&header_to_precompile) .ok()?; header_to_precompile_file .write_all(header_contents.as_bytes()) .ok()?; let mut c_args = Vec::new(); c_args.push("-x".to_string().into_boxed_str()); c_args.push("c-header".to_string().into_boxed_str()); for header_path in header_paths { c_args.push(format!("-I{header_path}").into_boxed_str()); } c_args.extend( self.options .clang_args .iter() .filter(|next| { !self.options.input_headers.contains(next) && next.as_ref() != "-include" }) .cloned(), ); let mut tu = clang::TranslationUnit::parse( &index, &header_to_precompile, &c_args, &[], clang_sys::CXTranslationUnit_ForSerialization, )?; tu.save(&pch).ok()?; let mut c_args = vec![ "-include-pch".to_string().into_boxed_str(), pch.clone().into_boxed_str(), ]; c_args.extend( self.options .clang_args .clone() .iter() .filter(|next| { !self.options.input_headers.contains(next) && next.as_ref() != "-include" }) .cloned(), ); self.fallback_tu = Some(clang::FallbackTranslationUnit::new( file, header_to_precompile, pch, &c_args, )?); } self.fallback_tu.as_mut() } /// Have we parsed the macro named `macro_name` already? pub(crate) fn parsed_macro(&self, macro_name: &[u8]) -> bool { self.parsed_macros.contains_key(macro_name) } /// Get the currently parsed macros. pub(crate) fn parsed_macros( &self, ) -> &StdHashMap, cexpr::expr::EvalResult> { debug_assert!(!self.in_codegen_phase()); &self.parsed_macros } /// Mark the macro named `macro_name` as parsed. pub(crate) fn note_parsed_macro( &mut self, id: Vec, value: cexpr::expr::EvalResult, ) { self.parsed_macros.insert(id, value); } /// Are we in the codegen phase? pub(crate) 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(crate) fn replace(&mut self, name: &[String], potential_ty: ItemId) { match self.replacements.entry(name.into()) { Entry::Vacant(entry) => { debug!("Defining replacement for {name:?} as {potential_ty:?}"); entry.insert(potential_ty); } Entry::Occupied(occupied) => { warn!( "Replacement for {name:?} already defined as {:?}; \ ignoring duplicate replacement definition as {potential_ty:?}", occupied.get(), ); } } } /// Has the item with the given `name` and `id` been replaced by another /// type? pub(crate) fn is_replaced_type>( &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(crate) 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: &Cursor, ) -> (Option, 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 looking_for_name = false; for token in cursor.tokens().iter() { match token.spelling() { b"inline" => { debug_assert!( kind != ModuleKind::Inline, "Multiple inline keywords?" ); kind = ModuleKind::Inline; // When hitting a nested inline namespace we get a spelling // that looks like ["inline", "foo"]. Deal with it properly. looking_for_name = true; } // 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. b"namespace" | b"::" => { looking_for_name = true; } b"{" => { // This should be an anonymous namespace. assert!(looking_for_name); break; } name => { if looking_for_name { if module_name.is_none() { module_name = Some( String::from_utf8_lossy(name).into_owned(), ); } break; } else { // 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 {token:?} in {cursor:?}", String::from_utf8_lossy(name), ); } } } } if cursor.is_inline_namespace() { kind = ModuleKind::Inline; } (module_name, kind) } /// Given a `CXCursor_Namespace` cursor, return the item ID of the /// corresponding module, or create one on the fly. pub(crate) fn module(&mut self, cursor: 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(crate) fn with_module(&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(crate) 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(crate) 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| { if self.options.parse_callbacks.is_empty() { // Sized integer types from get mapped to Rust primitive // types regardless of whether they are blocklisted, so ensure that // standard traits are considered derivable for them too. if self.is_stdint_type(name) { Some(CanDerive::Yes) } else { Some(CanDerive::No) } } else { self.options.last_callback(|cb| { cb.blocklisted_type_implements_trait( name, derive_trait, ) }) } }) .unwrap_or(CanDerive::No) }) } /// Is the given type a type from that corresponds to a Rust primitive type? pub(crate) 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(crate) 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() && self.options().allowlisted_items.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:?}"); if self.options().allowlisted_items.matches(&name) { return true; } 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 TypeKind::Enum(ref enum_) = *ty.kind() else { 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) || self .options() .allowlisted_items .matches(name) }) } } }) .map(|(id, _)| id) .collect::>(); // 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::(); let codegen_items = if self.options().allowlist_recursively { AllowlistedItemsTraversal::new( self, roots, traversal::codegen_edges, ) .collect::() } else { allowlisted.clone() }; self.allowlisted = Some(allowlisted); self.codegen_items = Some(codegen_items); for item in self.options().allowlisted_functions.unmatched_items() { unused_regex_diagnostic(item, "--allowlist-function", self); } for item in self.options().allowlisted_vars.unmatched_items() { unused_regex_diagnostic(item, "--allowlist-var", self); } for item in self.options().allowlisted_types.unmatched_items() { unused_regex_diagnostic(item, "--allowlist-type", self); } for item in self.options().allowlisted_items.unmatched_items() { unused_regex_diagnostic(item, "--allowlist-items", self); } } /// Convenient method for getting the prefix to use for most traits in /// codegen depending on the `use_core` option. pub(crate) fn trait_prefix(&self) -> Ident { if self.options().use_core { self.rust_ident_raw("core") } else { self.rust_ident_raw("std") } } /// Call if an opaque array is generated pub(crate) fn generated_opaque_array(&self) { self.generated_opaque_array.set(true) } /// Whether we need to generate the opaque array type pub(crate) fn need_opaque_array_type(&self) -> bool { self.generated_opaque_array.get() } /// Call if a bindgen complex is generated pub(crate) fn generated_bindgen_complex(&self) { self.generated_bindgen_complex.set(true); } /// Whether we need to generate the bindgen complex type pub(crate) fn need_bindgen_complex_type(&self) -> bool { self.generated_bindgen_complex.get() } /// Call if a bindgen float16 is generated pub(crate) fn generated_bindgen_float16(&self) { self.generated_bindgen_float16.set(true); } /// Whether we need to generate the bindgen float16 type pub(crate) fn need_bindgen_float16_type(&self) -> bool { self.generated_bindgen_float16.get() } /// Compute which `enum`s have an associated `typedef` definition. fn compute_enum_typedef_combos(&mut self) { let _t = self.timer("compute_enum_typedef_combos"); assert!(self.enum_typedef_combos.is_none()); let mut enum_typedef_combos = HashSet::default(); for item in &self.items { if let Some(ItemKind::Module(module)) = item.as_ref().map(Item::kind) { // Find typedefs in this module, and build set of their names. let mut names_of_typedefs = HashSet::default(); for child_id in module.children() { if let Some(ItemKind::Type(ty)) = self.items[child_id.0].as_ref().map(Item::kind) { if let (Some(name), TypeKind::Alias(type_id)) = (ty.name(), ty.kind()) { // We disregard aliases that refer to the enum // itself, such as in `typedef enum { ... } Enum;`. if type_id .into_resolver() .through_type_refs() .through_type_aliases() .resolve(self) .expect_type() .is_int() { names_of_typedefs.insert(name); } } } } // Find enums in this module, and record the ID of each one that // has a typedef. for child_id in module.children() { if let Some(ItemKind::Type(ty)) = self.items[child_id.0].as_ref().map(Item::kind) { if let (Some(name), true) = (ty.name(), ty.is_enum()) { if names_of_typedefs.contains(name) { enum_typedef_combos.insert(*child_id); } } } } } } self.enum_typedef_combos = Some(enum_typedef_combos); } /// Look up whether `id` refers to an `enum` whose underlying type is /// defined by a `typedef`. pub(crate) fn is_enum_typedef_combo(&self, id: ItemId) -> bool { assert!( self.in_codegen_phase(), "We only compute enum_typedef_combos when we enter codegen", ); self.enum_typedef_combos.as_ref().unwrap().contains(&id) } /// 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::(( self, DeriveTrait::Debug, )))); } } /// Look up whether the item with `id` can /// derive debug or not. pub(crate) fn lookup_can_derive_debug>( &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::(( self, DeriveTrait::Default, )))); } } /// Look up whether the item with `id` can /// derive default or not. pub(crate) fn lookup_can_derive_default>( &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::(( 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::(( self, DeriveTrait::Hash, )))); } } /// Look up whether the item with `id` can /// derive hash or not. pub(crate) fn lookup_can_derive_hash>( &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::(( self, DeriveTrait::PartialEqOrPartialOrd, ))); } } /// Look up whether the item with `id` can derive `Partial{Eq,Ord}`. pub(crate) fn lookup_can_derive_partialeq_or_partialord< Id: Into, >( &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) .copied() .unwrap_or(CanDerive::Yes) } /// Look up whether the item with `id` can derive `Copy` or not. pub(crate) fn lookup_can_derive_copy>( &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::(self)); } /// Look up whether the item with `id` has type parameter in array or not. pub(crate) fn lookup_has_type_param_in_array>( &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::(self)); } } /// Look up whether the item with `id` has array or not. pub(crate) fn lookup_has_float>(&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(crate) 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(crate) 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(crate) 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(crate) 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(crate) 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(crate) 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) } /// Wrap some tokens in an `unsafe` block if the `--wrap-unsafe-ops` option is enabled. pub(crate) fn wrap_unsafe_ops(&self, tokens: impl ToTokens) -> TokenStream { if self.options.wrap_unsafe_ops { quote!(unsafe { #tokens }) } else { tokens.into_token_stream() } } /// Get the suffix to be added to `static` functions if the `--wrap-static-fns` option is /// enabled. pub(crate) fn wrap_static_fns_suffix(&self) -> &str { self.options() .wrap_static_fns_suffix .as_deref() .unwrap_or(crate::DEFAULT_NON_EXTERN_FNS_SUFFIX) } } /// A builder struct for configuring item resolution options. #[derive(Debug, Copy, Clone)] pub(crate) struct ItemResolver { id: ItemId, through_type_refs: bool, through_type_aliases: bool, } impl ItemId { /// Create an `ItemResolver` from this item ID. pub(crate) fn into_resolver(self) -> ItemResolver { self.into() } } impl From for ItemResolver where T: Into, { fn from(id: T) -> ItemResolver { ItemResolver::new(id) } } impl ItemResolver { /// Construct a new `ItemResolver` from the given ID. pub(crate) fn new>(id: Id) -> ItemResolver { let id = id.into(); ItemResolver { id, through_type_refs: false, through_type_aliases: false, } } /// Keep resolving through `Type::TypeRef` items. pub(crate) fn through_type_refs(mut self) -> ItemResolver { self.through_type_refs = true; self } /// Keep resolving through `Type::Alias` items. pub(crate) fn through_type_aliases(mut self) -> ItemResolver { self.through_type_aliases = true; self } /// Finish configuring and perform the actual item resolution. pub(crate) 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(crate) 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(crate) 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(crate) 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(crate) fn id(&self) -> ItemId { self.id } } impl TemplateParameters for PartialType { fn self_template_params(&self, _ctx: &BindgenContext) -> Vec { // 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, } } } fn unused_regex_diagnostic(item: &str, name: &str, _ctx: &BindgenContext) { warn!("unused option: {name} {item}"); #[cfg(feature = "experimental")] if _ctx.options().emit_diagnostics { use crate::diagnostics::{Diagnostic, Level}; Diagnostic::default() .with_title( format!("Unused regular expression: `{item}`."), Level::Warning, ) .add_annotation( format!("This regular expression was passed to `{name}`."), Level::Note, ) .display(); } } bindgen-0.71.1/ir/derive.rs000064400000000000000000000077661046102023000135760ustar 00000000000000//! 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(crate) 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(crate) 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(crate) 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(crate) 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(crate) 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(crate) 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(crate) 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(crate) 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, Default)] pub enum CanDerive { /// Yes, we can derive automatically. #[default] 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 CanDerive { /// Take the least upper bound of `self` and `rhs`. pub(crate) 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); } } bindgen-0.71.1/ir/dot.rs000064400000000000000000000045621046102023000130750ustar 00000000000000//! 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 `` rows to a dot /// file. pub(crate) trait DotAttributes { /// Write this thing's attributes to the given output. Each attribute must /// be its own `...`. fn dot_attributes( &self, ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: Write; } /// Write a graphviz dot file containing our IR. pub(crate) fn write_dot_file

(ctx: &BindgenContext, path: P) -> io::Result<()> where P: AsRef, { let file = File::create(path)?; let mut dot_file = io::BufWriter::new(file); writeln!(&mut dot_file, "digraph {{")?; let mut err: Option> = None; for (id, item) in ctx.items() { let is_allowlisted = ctx.allowlisted_items().contains(&id); writeln!( &mut dot_file, r#"{} [fontname="courier", color={}, label=<

"#, id.as_usize(), if is_allowlisted { "black" } else { "gray" } )?; item.dot_attributes(ctx, &mut dot_file)?; writeln!(&mut dot_file, r#"
>];"#)?; item.trace( ctx, &mut |sub_id: ItemId, edge_kind| { if err.is_some() { return; } match writeln!( &mut dot_file, "{} -> {} [label={edge_kind:?}, color={}];", id.as_usize(), sub_id.as_usize(), 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(()) } bindgen-0.71.1/ir/enum_ty.rs000064400000000000000000000235021046102023000137620ustar 00000000000000//! 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::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(crate) 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, /// The different variants, with explicit values. variants: Vec, } impl Enum { /// Construct a new `Enum` with the given representation and variants. pub(crate) fn new( repr: Option, variants: Vec, ) -> Self { Enum { repr, variants } } /// Get this enumeration's representation. pub(crate) fn repr(&self) -> Option { self.repr } /// Get this enumeration's variants. pub(crate) fn variants(&self) -> &[EnumVariant] { &self.variants } /// Construct an enumeration from the given Clang type. pub(crate) fn from_ty( ty: &clang::Type, ctx: &mut BindgenContext, ) -> Result { 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.is_some_and(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 .options() .last_callback(|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 .options() .last_callback(|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(crate) 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(crate) 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, /// The integer value of the variant. val: EnumVariantValue, /// The custom behavior this variant may have, if any. custom_behavior: Option, } /// 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(crate) fn new( name: String, name_for_allowlisting: String, comment: Option, val: EnumVariantValue, custom_behavior: Option, ) -> Self { EnumVariant { name, name_for_allowlisting, comment, val, custom_behavior, } } /// Get this variant's name. pub(crate) fn name(&self) -> &str { &self.name } /// Get this variant's name. pub(crate) fn name_for_allowlisting(&self) -> &str { &self.name_for_allowlisting } /// Get this variant's value. pub(crate) fn val(&self) -> EnumVariantValue { self.val } /// Get this variant's documentation. pub(crate) fn comment(&self) -> Option<&str> { self.comment.as_deref() } /// Returns whether this variant should be enforced to be a constant by code /// generation. pub(crate) fn force_constification(&self) -> bool { self.custom_behavior == Some(EnumVariantCustomBehavior::Constify) } /// Returns whether the current variant should be hidden completely from the /// resulting rust enum. pub(crate) fn hidden(&self) -> bool { self.custom_behavior == Some(EnumVariantCustomBehavior::Hide) } } bindgen-0.71.1/ir/function.rs000064400000000000000000000654661046102023000141460ustar 00000000000000//! 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::callbacks::{ItemInfo, ItemKind}; use crate::clang::{self, ABIKind, Attribute}; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; use clang_sys::CXCallingConv; use quote::TokenStreamExt; use std::io; use std::str::FromStr; const RUST_DERIVE_FUNPTR_LIMIT: usize = 12; /// What kind of a function are we looking at? #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) 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(crate) fn from_cursor(cursor: &clang::Cursor) -> Option { // 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(crate) 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(crate) struct Function { /// The name of this function. name: String, /// The mangled name, that is, the symbol. mangled_name: Option, /// The link name. If specified, overwrite `mangled_name`. link_name: Option, /// The ID pointing to the current function signature. signature: TypeId, /// The kind of function this is. kind: FunctionKind, /// The linkage of the function. linkage: Linkage, } impl Function { /// Construct a new function. pub(crate) fn new( name: String, mangled_name: Option, link_name: Option, signature: TypeId, kind: FunctionKind, linkage: Linkage, ) -> Self { Function { name, mangled_name, link_name, signature, kind, linkage, } } /// Get this function's name. pub(crate) fn name(&self) -> &str { &self.name } /// Get this function's name. pub(crate) fn mangled_name(&self) -> Option<&str> { self.mangled_name.as_deref() } /// Get this function's link name. pub fn link_name(&self) -> Option<&str> { self.link_name.as_deref() } /// Get this function's signature type. pub(crate) fn signature(&self) -> TypeId { self.signature } /// Get this function's kind. pub(crate) fn kind(&self) -> FunctionKind { self.kind } /// Get this function's linkage. pub(crate) fn linkage(&self) -> Linkage { self.linkage } } impl DotAttributes for Function { fn dot_attributes( &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, "mangled name{mangled}")?; } Ok(()) } } /// A valid rust ABI. #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)] pub enum Abi { /// The default C ABI. C, /// The "stdcall" ABI. Stdcall, /// The "efiapi" ABI. EfiApi, /// The "fastcall" ABI. Fastcall, /// The "thiscall" ABI. ThisCall, /// The "vectorcall" ABI. Vectorcall, /// The "aapcs" ABI. Aapcs, /// The "win64" ABI. Win64, /// The "C-unwind" ABI. CUnwind, /// The "system" ABI. System, } impl FromStr for Abi { type Err = String; fn from_str(s: &str) -> Result { match s { "C" => Ok(Self::C), "stdcall" => Ok(Self::Stdcall), "efiapi" => Ok(Self::EfiApi), "fastcall" => Ok(Self::Fastcall), "thiscall" => Ok(Self::ThisCall), "vectorcall" => Ok(Self::Vectorcall), "aapcs" => Ok(Self::Aapcs), "win64" => Ok(Self::Win64), "C-unwind" => Ok(Self::CUnwind), "system" => Ok(Self::System), _ => Err(format!("Invalid or unknown ABI {s:?}")), } } } impl std::fmt::Display for Abi { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let s = match *self { Self::C => "C", Self::Stdcall => "stdcall", Self::EfiApi => "efiapi", Self::Fastcall => "fastcall", Self::ThisCall => "thiscall", Self::Vectorcall => "vectorcall", Self::Aapcs => "aapcs", Self::Win64 => "win64", Self::CUnwind => "C-unwind", Abi::System => "system", }; s.fmt(f) } } impl quote::ToTokens for Abi { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { let abi = self.to_string(); tokens.append_all(quote! { #abi }); } } /// An ABI extracted from a clang cursor. #[derive(Debug, Copy, Clone)] pub(crate) enum ClangAbi { /// An ABI known by Rust. Known(Abi), /// An unknown or invalid ABI. Unknown(CXCallingConv), } impl ClangAbi { /// Returns whether this Abi is known or not. fn is_unknown(&self) -> bool { matches!(*self, ClangAbi::Unknown(..)) } } impl quote::ToTokens for ClangAbi { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { match *self { Self::Known(abi) => abi.to_tokens(tokens), Self::Unknown(cc) => panic!( "Cannot turn unknown calling convention to tokens: {cc:?}" ), } } } /// A function signature. #[derive(Debug)] pub(crate) struct FunctionSig { /// The name of this function signature. name: String, /// 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, 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: ClangAbi, } fn get_abi(cc: CXCallingConv) -> ClangAbi { use clang_sys::*; match cc { CXCallingConv_Default => ClangAbi::Known(Abi::C), CXCallingConv_C => ClangAbi::Known(Abi::C), CXCallingConv_X86StdCall => ClangAbi::Known(Abi::Stdcall), CXCallingConv_X86FastCall => ClangAbi::Known(Abi::Fastcall), CXCallingConv_X86ThisCall => ClangAbi::Known(Abi::ThisCall), CXCallingConv_X86VectorCall => ClangAbi::Known(Abi::Vectorcall), CXCallingConv_AAPCS => ClangAbi::Known(Abi::Aapcs), CXCallingConv_X86_64Win64 => ClangAbi::Known(Abi::Win64), CXCallingConv_AArch64VectorCall => ClangAbi::Known(Abi::Vectorcall), other => ClangAbi::Unknown(other), } } /// Get the mangled name for the cursor's referent. pub(crate) fn cursor_mangling( ctx: &BindgenContext, cursor: &clang::Cursor, ) -> Option { 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_itanium_abi = ctx.abi_kind() == ABIKind::GenericItanium; 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_itanium_abi && is_destructor && !m.ends_with("D1Ev") { continue; } return Some(m); } } let mut mangling = cursor.mangling(); if mangling.is_empty() { return None; } if is_itanium_abi && 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, 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 { /// Get the function name. pub(crate) fn name(&self) -> &str { &self.name } /// Construct a new function signature from the given Clang type. pub(crate) fn from_ty( ty: &clang::Type, cursor: &clang::Cursor, ctx: &mut BindgenContext, ) -> Result { 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() }; // Check if the type contains __attribute__((noreturn)) outside of parentheses. This is // somewhat fragile, but it seems to be the only way to get at this information as of // libclang 9. let ty_spelling = ty.spelling(); let has_attribute_noreturn = ty_spelling .match_indices("__attribute__((noreturn))") .any(|(i, _)| { let depth = ty_spelling[..i] .bytes() .filter_map(|ch| match ch { b'(' => Some(1), b')' => Some(-1), _ => None, }) .sum::(); depth == 0 }); is_divergent = is_divergent || has_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 { name: spelling, return_type: ret, argument_types: args, is_variadic: ty.is_variadic(), is_divergent, must_use, abi, }) } /// Get this function signature's return type. pub(crate) fn return_type(&self) -> TypeId { self.return_type } /// Get this function signature's argument (name, type) pairs. pub(crate) fn argument_types(&self) -> &[(Option, TypeId)] { &self.argument_types } /// Get this function signature's ABI. pub(crate) fn abi( &self, ctx: &BindgenContext, name: Option<&str>, ) -> crate::codegen::error::Result { // FIXME (pvdrz): Try to do this check lazily instead. Maybe store the ABI inside `ctx` // instead?. let abi = if let Some(name) = name { if let Some((abi, _)) = ctx .options() .abi_overrides .iter() .find(|(_, regex_set)| regex_set.matches(name)) { ClangAbi::Known(*abi) } else { self.abi } } else if let Some((abi, _)) = ctx .options() .abi_overrides .iter() .find(|(_, regex_set)| regex_set.matches(&self.name)) { ClangAbi::Known(*abi) } else { self.abi }; match abi { ClangAbi::Known(Abi::ThisCall) if !ctx.options().rust_features().thiscall_abi => { Err(crate::codegen::error::Error::UnsupportedAbi("thiscall")) } ClangAbi::Known(Abi::Vectorcall) if !ctx.options().rust_features().vectorcall_abi => { Err(crate::codegen::error::Error::UnsupportedAbi("vectorcall")) } ClangAbi::Known(Abi::CUnwind) if !ctx.options().rust_features().c_unwind_abi => { Err(crate::codegen::error::Error::UnsupportedAbi("C-unwind")) } ClangAbi::Known(Abi::EfiApi) if !ctx.options().rust_features().abi_efiapi => { Err(crate::codegen::error::Error::UnsupportedAbi("efiapi")) } ClangAbi::Known(Abi::Win64) if self.is_variadic() => { Err(crate::codegen::error::Error::UnsupportedAbi("Win64")) } abi => Ok(abi), } } /// Is this function signature variadic? pub(crate) 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(crate) 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: /// /// * , /// * , /// * and pub(crate) fn function_pointers_can_derive(&self) -> bool { if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT { return false; } matches!(self.abi, ClangAbi::Known(Abi::C) | ClangAbi::Unknown(..)) } /// Whether this function has attributes marking it as divergent. pub(crate) fn is_divergent(&self) -> bool { self.is_divergent } } impl ClangSubItemParser for Function { fn parse( cursor: clang::Cursor, context: &mut BindgenContext, ) -> Result, 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); } let linkage = cursor.linkage(); let linkage = match linkage { CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External, CXLinkage_Internal => Linkage::Internal, _ => return Err(ParseError::Continue), }; if cursor.is_inlined_function() || cursor.definition().is_some_and(|x| x.is_inlined_function()) { if !context.options().generate_inline_functions && !context.options().wrap_static_fns { return Err(ParseError::Continue); } if cursor.is_deleted_function() { return Err(ParseError::Continue); } // We cannot handle `inline` functions that are not `static`. if context.options().wrap_static_fns && cursor.is_inlined_function() && matches!(linkage, Linkage::External) { 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"); } if let Some(nm) = context.options().last_callback(|callbacks| { callbacks.generated_name_override(ItemInfo { name: name.as_str(), kind: ItemKind::Function, }) }) { name = nm; } assert!(!name.is_empty(), "Empty function name."); let mangled_name = cursor_mangling(context, &cursor); let link_name = context.options().last_callback(|callbacks| { callbacks.generated_link_name_override(ItemInfo { name: name.as_str(), kind: ItemKind::Function, }) }); let function = Self::new( name.clone(), mangled_name, link_name, sig, kind, linkage, ); Ok(ParseResult::New(function, Some(cursor))) } } impl Trace for FunctionSig { type Extra = (); fn trace(&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); } } } bindgen-0.71.1/ir/int.rs000064400000000000000000000055551046102023000131040ustar 00000000000000//! 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, /// A `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(crate) 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(crate) fn known_size(&self) -> Option { 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(crate) fn signedness_matches(&self, val: i64) -> bool { val >= 0 || self.is_signed() } } bindgen-0.71.1/ir/item.rs000064400000000000000000001777701046102023000132610ustar 00000000000000//! 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::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::{ClangSubItemParser, ParseError, ParseResult}; use std::cell::{Cell, OnceCell}; use std::collections::BTreeSet; use std::fmt::Write; use std::io; use std::iter; use std::sync::OnceLock; /// 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(crate) 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(crate) 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; /// Get the canonical path for this item. fn canonical_path(&self, ctx: &BindgenContext) -> Vec; } /// A trait for determining if some IR thing is opaque or not. pub(crate) 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(crate) 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 iterating over an item and its parents and up its ancestor chain /// up to (but not including) the implicit root module. pub(crate) trait ItemAncestors { /// Get an iterable over this item's ancestors. fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a>; } #[cfg(feature = "__testing_only_extra_assertions")] type DebugOnlyItemSet = ItemSet; #[cfg(not(feature = "__testing_only_extra_assertions"))] struct DebugOnlyItemSet; #[cfg(not(feature = "__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(crate) struct ItemAncestorsIter<'a> { item: ItemId, ctx: &'a BindgenContext, seen: DebugOnlyItemSet, } impl<'a> ItemAncestorsIter<'a> { fn new>(ctx: &'a BindgenContext, id: Id) -> Self { ItemAncestorsIter { item: id.into(), ctx, seen: DebugOnlyItemSet::new(), } } } impl Iterator for ItemAncestorsIter<'_> { type Item = ItemId; fn next(&mut self) -> Option { 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 AsTemplateParam for T where T: Copy + Into, { type Extra = (); fn as_template_param( &self, ctx: &BindgenContext, _: &(), ) -> Option { ctx.resolve_item((*self).into()).as_template_param(ctx, &()) } } impl AsTemplateParam for Item { type Extra = (); fn as_template_param( &self, ctx: &BindgenContext, _: &(), ) -> Option { self.kind.as_template_param(ctx, self) } } impl AsTemplateParam for ItemKind { type Extra = Item; fn as_template_param( &self, ctx: &BindgenContext, item: &Item, ) -> Option { match *self { ItemKind::Type(ref ty) => ty.as_template_param(ctx, item), ItemKind::Module(..) | ItemKind::Function(..) | ItemKind::Var(..) => None, } } } impl ItemCanonicalName for T where T: Copy + Into, { 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 ItemCanonicalPath for T where T: Copy + Into, { fn namespace_aware_canonical_path( &self, ctx: &BindgenContext, ) -> Vec { 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 { debug_assert!( ctx.in_codegen_phase(), "You're not supposed to call this yet" ); ctx.resolve_item(*self).canonical_path(ctx) } } impl ItemAncestors for T where T: Copy + Into, { 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 Trace for Id where Id: Copy + Into, { type Extra = (); fn trace(&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(&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(crate) 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: OnceCell, /// The next local ID to use for a child or template instantiation. next_child_local_id: Cell, /// 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: OnceCell, /// The path to use for allowlisting and other name-based checks, as /// returned by `path_for_allowlisting`, lazily constructed. path_for_allowlisting: OnceCell>, /// A doc comment over the item, if any. comment: Option, /// 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, } impl AsRef for Item { fn as_ref(&self) -> &ItemId { &self.id } } impl Item { /// Construct a new `Item`. pub(crate) fn new( id: ItemId, comment: Option, annotations: Option, parent_id: ItemId, kind: ItemKind, location: Option, ) -> Self { debug_assert!(id != parent_id || kind.is_module()); Item { id, local_id: OnceCell::new(), next_child_local_id: Cell::new(1), canonical_name: OnceCell::new(), path_for_allowlisting: OnceCell::new(), parent_id, comment, annotations: annotations.unwrap_or_default(), kind, location, } } /// Construct a new opaque item type. pub(crate) 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(crate) 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(crate) 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(crate) fn set_parent_for_replacement>( &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(crate) 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().is_some_and(|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(crate) fn comment(&self, ctx: &BindgenContext) -> Option { if !ctx.options().generate_comments { return None; } self.comment .as_ref() .map(|comment| ctx.options().process_comment(comment)) } /// What kind of item is this? pub(crate) fn kind(&self) -> &ItemKind { &self.kind } /// Get a mutable reference to this item's kind. pub(crate) fn kind_mut(&mut self) -> &mut ItemKind { &mut self.kind } /// Where in the source is this item located? pub(crate) 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(crate) fn local_id(&self, ctx: &BindgenContext) -> usize { *self.local_id.get_or_init(|| { 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(crate) 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(crate) 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 Some(parent_item) = ctx.resolve_item_fallible(parent) else { 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(crate) 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(crate) 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(crate) fn expect_function(&self) -> &Function { self.kind().expect_function() } /// Is this item a module? pub(crate) fn is_module(&self) -> bool { matches!(self.kind, ItemKind::Module(..)) } /// Get this item's annotations. pub(crate) 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(crate) 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) } ItemKind::Var(..) => { ctx.options().blocklisted_vars.matches(&name) } // TODO: Add namespace blocklisting? ItemKind::Module(..) => false, } } /// Take out item `NameOptions` pub(crate) 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(crate) 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 { 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_or_else( || format!("_bindgen_mod_{}", self.exposed_id(ctx)), ToOwned::to_owned, ), ItemKind::Type(ref ty) => ty.sanitized_name(ctx).map_or_else( || format!("_bindgen_ty_{}", self.exposed_id(ctx)), Into::into, ), 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(crate) 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.options() .last_callback(|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(crate) 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( TypeKind::Comp(..) | TypeKind::TemplateInstantiation(..) | TypeKind::Enum(..), ) = ty_kind { 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(crate) 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(crate) 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 ItemKind::Type(ref type_) = *item.kind() else { 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(crate) 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(crate) fn path_for_allowlisting( &self, ctx: &BindgenContext, ) -> &Vec { self.path_for_allowlisting .get_or_init(|| self.compute_path(ctx, UserMangled::No)) } fn compute_path( &self, ctx: &BindgenContext, mangled: UserMangled, ) -> Vec { 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().is_some_and(|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 ItemKind::Type(ref ty) = self.kind else { 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(crate) fn must_use(&self, ctx: &BindgenContext) -> bool { self.annotations().must_use_type() || ctx.must_use_type_by_name(self) } } impl IsOpaque for T where T: Copy + Into, { 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().is_some_and(|ty| ty.is_opaque(ctx, self)) || ctx.opaque_by_name(self.path_for_allowlisting(ctx)) } } impl HasVtable for T where T: Copy + Into, { fn has_vtable(&self, ctx: &BindgenContext) -> bool { let id: ItemId = (*self).into(); id.as_type_id(ctx).is_some_and(|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).is_some_and(|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 Sizedness for T where T: Copy + Into, { 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 HasTypeParamInArray for T where T: Copy + Into, { 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()) } } /// A set of items. pub(crate) type ItemSet = BTreeSet; impl DotAttributes for Item { fn dot_attributes( &self, ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!( out, "{:?} name{}", self.id, self.name(ctx).get() )?; if self.is_opaque(ctx, &()) { writeln!(out, "opaquetrue")?; } self.kind.dot_attributes(ctx, out) } } impl TemplateParameters for T where T: Copy + Into, { fn self_template_params(&self, ctx: &BindgenContext) -> Vec { 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 { self.kind.self_template_params(ctx) } } impl TemplateParameters for ItemKind { fn self_template_params(&self, ctx: &BindgenContext) -> Vec { 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, ctx: &mut BindgenContext, result: &mut Result, ) -> 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 Item { /// Create a builtin type. pub(crate) 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() } /// Parse this item from the given Clang cursor. pub(crate) fn parse( cursor: clang::Cursor, parent_id: Option, ctx: &mut BindgenContext, ) -> Result { 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); #[allow(clippy::missing_docs_in_private_items)] 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) => {} } } match cursor.kind() { // On Clang 18+, extern "C" is reported accurately as a LinkageSpec. // Older LLVM treat it as UnexposedDecl. CXCursor_LinkageSpec | CXCursor_UnexposedDecl => { Err(ParseError::Recurse) } // We allowlist cursors here known to be unhandled, to prevent being // too noisy about this. CXCursor_MacroDefinition | CXCursor_MacroExpansion | CXCursor_UsingDeclaration | CXCursor_UsingDirective | CXCursor_StaticAssert | CXCursor_FunctionTemplate => { debug!("Unhandled cursor kind {:?}: {cursor:?}", cursor.kind(),); Err(ParseError::Continue) } CXCursor_InclusionDirective => { let file = cursor.get_included_file_name(); match file { None => { warn!("Inclusion of a nameless file in {cursor:?}"); } Some(included_file) => { for cb in &ctx.options().parse_callbacks { cb.include_file(&included_file); } ctx.add_dep(included_file.into_boxed_str()); } } Err(ParseError::Continue) } _ => { // ignore toplevel operator overloads let spelling = cursor.spelling(); if !spelling.starts_with("operator") { warn!( "Unhandled cursor kind {:?}: {cursor:?}", cursor.kind(), ); } Err(ParseError::Continue) } } } /// 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. pub(crate) fn from_ty_or_ref( ty: clang::Type, location: clang::Cursor, parent_id: Option, 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`. pub(crate) fn from_ty_or_ref_with_id( potential_id: ItemId, ty: clang::Type, location: clang::Cursor, parent_id: Option, 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!("{ty:?} already resolved: {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() } /// Parse this item from the given Clang type. See [`Item::from_ty_with_id`]. pub(crate) fn from_ty( ty: &clang::Type, location: clang::Cursor, parent_id: Option, ctx: &mut BindgenContext, ) -> Result { 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. pub(crate) fn from_ty_with_id( id: ItemId, ty: &clang::Type, location: clang::Cursor, parent_id: Option, ctx: &mut BindgenContext, ) -> Result { use clang_sys::*; debug!( "Item::from_ty_with_id: {id:?}\n\ \tty = {ty:?},\n\ \tlocation = {location:?}", ); if ty.kind() == CXType_Unexposed || location.cur_type().kind() == 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 = location .raw_comment() .or_else(|| 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) .ok_or(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`. They're always local so /// it's the only exception when there's no declaration for a type. pub(crate) fn type_param( with_id: Option, location: clang::Cursor, ctx: &mut BindgenContext, ) -> Option { 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 { static ANON_TYPE_PARAM_RE: OnceLock = OnceLock::new(); let anon_type_param_re = ANON_TYPE_PARAM_RE.get_or_init(|| { 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 .get_or_init(|| { 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 { 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 { 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(crate) struct NameOptions<'a> { item: &'a Item, ctx: &'a BindgenContext, within_namespaces: bool, user_mangled: UserMangled, } impl<'a> NameOptions<'a> { /// Construct a new `NameOptions` pub(crate) 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(crate) 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(crate) fn get(&self) -> String { self.item.real_canonical_name(self.ctx, self) } } bindgen-0.71.1/ir/item_kind.rs000064400000000000000000000074601046102023000142520ustar 00000000000000//! 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(crate) 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 underlying `Module`, or `None` if it /// is some other kind. pub(crate) fn as_module(&self) -> Option<&Module> { match *self { ItemKind::Module(ref module) => Some(module), _ => None, } } /// Transform our `ItemKind` into a string. pub(crate) 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(crate) fn is_module(&self) -> bool { self.as_module().is_some() } /// Get a reference to this `ItemKind`'s underlying `Function`, or `None` if /// it is some other kind. pub(crate) fn as_function(&self) -> Option<&Function> { match *self { ItemKind::Function(ref func) => Some(func), _ => None, } } /// Is this a function? pub(crate) fn is_function(&self) -> bool { self.as_function().is_some() } /// Get a reference to this `ItemKind`'s underlying `Function`, or panic if /// it is some other kind. pub(crate) fn expect_function(&self) -> &Function { self.as_function().expect("Not a function") } /// Get a reference to this `ItemKind`'s underlying `Type`, or `None` if /// it is some other kind. pub(crate) fn as_type(&self) -> Option<&Type> { match *self { ItemKind::Type(ref ty) => Some(ty), _ => None, } } /// Get a mutable reference to this `ItemKind`'s underlying `Type`, or `None` /// if it is some other kind. pub(crate) fn as_type_mut(&mut self) -> Option<&mut Type> { match *self { ItemKind::Type(ref mut ty) => Some(ty), _ => None, } } /// Is this a type? pub(crate) fn is_type(&self) -> bool { self.as_type().is_some() } /// Get a reference to this `ItemKind`'s underlying `Type`, or panic if it is /// some other kind. pub(crate) fn expect_type(&self) -> &Type { self.as_type().expect("Not a type") } /// Get a reference to this `ItemKind`'s underlying `Var`, or `None` if it is /// some other kind. pub(crate) fn as_var(&self) -> Option<&Var> { match *self { ItemKind::Var(ref v) => Some(v), _ => None, } } /// Is this a variable? pub(crate) fn is_var(&self) -> bool { self.as_var().is_some() } } impl DotAttributes for ItemKind { fn dot_attributes( &self, ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!(out, "kind{}", 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), } } } bindgen-0.71.1/ir/layout.rs000064400000000000000000000075721046102023000136300ustar 00000000000000//! 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(crate) struct Layout { /// The size (in bytes) of this layout. pub(crate) size: usize, /// The alignment (in bytes) of this layout. pub(crate) align: usize, /// Whether this layout's members are packed or not. pub(crate) packed: bool, } #[test] fn test_layout_for_size() { use std::mem::size_of; let ptr_size = 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(crate) fn known_type_for_size(size: usize) -> Option { Some(match size { 16 => syn::parse_quote! { u128 }, 8 => syn::parse_quote! { u64 }, 4 => syn::parse_quote! { u32 }, 2 => syn::parse_quote! { u16 }, 1 => syn::parse_quote! { u8 }, _ => return None, }) } /// Construct a new `Layout` with the given `size` and `align`. It is not /// packed. pub(crate) 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(crate) fn for_size(ctx: &BindgenContext, size: usize) -> Self { Self::for_size_internal(ctx.target_pointer_size(), size) } /// Get this layout as an opaque type. pub(crate) 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(crate) struct Opaque(pub(crate) Layout); impl Opaque { /// Construct a new opaque type from the given clang type. pub(crate) 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(crate) fn known_rust_type_for_array(&self) -> Option { Layout::known_type_for_size(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(crate) fn array_size(&self) -> Option { if self.known_rust_type_for_array().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(crate) fn array_size_within_derive_limit(&self) -> CanDerive { if self .array_size() .is_some_and(|size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) { CanDerive::Yes } else { CanDerive::Manually } } } bindgen-0.71.1/ir/mod.rs000064400000000000000000000012111046102023000130520ustar 00000000000000//! The ir module defines bindgen's intermediate representation. //! //! Parsing C/C++ generates the IR, while code generation outputs Rust code from //! the IR. #![deny(clippy::missing_docs_in_private_items)] pub(crate) mod analysis; pub(crate) mod annotations; pub(crate) mod comment; pub(crate) mod comp; pub(crate) mod context; pub(crate) mod derive; pub(crate) mod dot; pub(crate) mod enum_ty; pub(crate) mod function; pub(crate) mod int; pub(crate) mod item; pub(crate) mod item_kind; pub(crate) mod layout; pub(crate) mod module; pub(crate) mod objc; pub(crate) mod template; pub(crate) mod traversal; pub(crate) mod ty; pub(crate) mod var; bindgen-0.71.1/ir/module.rs000064400000000000000000000047601046102023000135740ustar 00000000000000//! 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(crate) 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(crate) struct Module { /// The name of the module, or none if it's anonymous. name: Option, /// 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(crate) fn new(name: Option, kind: ModuleKind) -> Self { Module { name, kind, children: ItemSet::new(), } } /// Get this module's name. pub(crate) fn name(&self) -> Option<&str> { self.name.as_deref() } /// Get a mutable reference to this module's children. pub(crate) fn children_mut(&mut self) -> &mut ItemSet { &mut self.children } /// Get this module's children. pub(crate) fn children(&self) -> &ItemSet { &self.children } /// Whether this namespace is inline. pub(crate) fn is_inline(&self) -> bool { self.kind == ModuleKind::Inline } } impl DotAttributes for Module { fn dot_attributes( &self, _ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!(out, "ModuleKind{:?}", self.kind) } } impl ClangSubItemParser for Module { fn parse( cursor: clang::Cursor, ctx: &mut BindgenContext, ) -> Result, ParseError> { use clang_sys::*; match cursor.kind() { CXCursor_Namespace => { let module_id = ctx.module(cursor); ctx.with_module(module_id, |ctx| { cursor.visit_sorted(ctx, |ctx, child| { parse_one(ctx, child, Some(module_id.into())); }); }); Ok(ParseResult::AlreadyResolved(module_id.into())) } _ => Err(ParseError::Continue), } } } bindgen-0.71.1/ir/objc.rs000064400000000000000000000261741046102023000132270ustar 00000000000000//! 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 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(crate) struct ObjCInterface { /// The name /// like, `NSObject` name: String, category: Option, is_protocol: bool, /// The list of template names almost always, `ObjectType` or `KeyType` pub(crate) template_names: Vec, /// The list of protocols that this interface conforms to. pub(crate) conforms_to: Vec, /// The direct parent for this interface. pub(crate) parent_class: Option, /// List of the methods defined in this interface methods: Vec, class_methods: Vec, } /// The objective c methods #[derive(Debug)] pub(crate) 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(crate) 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(crate) fn rust_name(&self) -> String { if let Some(ref cat) = self.category { format!("{}_{cat}", self.name()) } else if self.is_protocol { format!("P{}", self.name()) } else { format!("I{}", self.name().to_owned()) } } /// Is this a template interface? pub(crate) fn is_template(&self) -> bool { !self.template_names.is_empty() } /// List of the methods defined in this interface pub(crate) fn methods(&self) -> &Vec { &self.methods } /// Is this a protocol? pub(crate) fn is_protocol(&self) -> bool { self.is_protocol } /// Is this a category? pub(crate) fn is_category(&self) -> bool { self.category.is_some() } /// List of the class methods defined in this interface pub(crate) fn class_methods(&self) -> &Vec { &self.class_methods } /// Parses the Objective C interface from the cursor pub(crate) fn from_ty( cursor: &clang::Cursor, ctx: &mut BindgenContext, ) -> Option { 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 appropriately 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 {needle}, find the item", interface.name, ); 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, } } /// Method name as converted to rust /// like, `dataWithBytes_length`_ pub(crate) fn rust_name(&self) -> &str { self.rust_name.as_ref() } /// Returns the methods signature as `FunctionSig` pub(crate) fn signature(&self) -> &FunctionSig { &self.signature } /// Is this a class method? pub(crate) fn is_class_method(&self) -> bool { self.is_class_method } /// Formats the method call pub(crate) fn format_method_call( &self, args: &[TokenStream], ) -> TokenStream { let split_name: Vec> = self .name .split(':') .enumerate() .map(|(idx, name)| { if name.is_empty() { None } else if idx == 0 { // Try to parse the method name as an identifier. Having a keyword is ok // unless it is `crate`, `self`, `super` or `Self`, so we try to add the `_` // suffix to it and parse it. if ["crate", "self", "super", "Self"].contains(&name) { Some(Ident::new(&format!("{name}_"), Span::call_site())) } else { Some(Ident::new(name, Span::call_site())) } } else { // Try to parse the current joining name as an identifier. This might fail if the name // is a keyword, so we try to "r#" to it and parse again, this could also fail // if the name is `crate`, `self`, `super` or `Self`, so we try to add the `_` // suffix to it and parse again. If this also fails, we panic with the first // error. Some( syn::parse_str::(name) .or_else(|err| { syn::parse_str::(&format!("r#{name}")) .map_err(|_| err) }) .or_else(|err| { syn::parse_str::(&format!("{name}_")) .map_err(|_| err) }) .expect("Invalid identifier"), ) } }) .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, {args:?} vs {split_name:?}" ); // Get arguments without type signatures to pass to `msg_send!` let mut args_without_types = vec![]; for arg in args { 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(&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); } } } bindgen-0.71.1/ir/template.rs000064400000000000000000000262701046102023000141220ustar 00000000000000//! 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 //! class List { //! // ... //! }; //! ``` //! //! * "Template instantiation": an instantiation is a use of a template with //! concrete template arguments. For example, `List`. //! //! * "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 { //! // 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; /// 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 /// class Foo { /// T use_of_t; /// U use_of_u; /// /// template /// using Bar = V*; /// /// class Inner { /// T x; /// U y; /// Bar z; /// }; /// /// template /// class Lol { /// // No use of W, but here's a use of T. /// T t; /// }; /// /// template /// class Wtf { /// // X is not used because W is not used. /// Lol 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(crate) 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; /// 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::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 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 where Self: AsRef, { 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(crate) 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; /// 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(crate) 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, } impl TemplateInstantiation { /// Construct a new template instantiation from the given parts. pub(crate) fn new(definition: TypeId, args: I) -> TemplateInstantiation where I: IntoIterator, { TemplateInstantiation { definition, args: args.into_iter().collect(), } } /// Get the template definition for this instantiation. pub(crate) fn template_definition(&self) -> TypeId { self.definition } /// Get the concrete template arguments used in this instantiation. pub(crate) fn template_arguments(&self) -> &[TypeId] { &self.args[..] } /// Parse a `TemplateInstantiation` from a clang `Type`. pub(crate) fn from_ty( ty: &clang::Type, ctx: &mut BindgenContext, ) -> Option { 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 Some(definition) = definition else { 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". 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(&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); } } } bindgen-0.71.1/ir/traversal.rs000064400000000000000000000334251046102023000143120ustar 00000000000000//! 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(crate) struct Edge { to: ItemId, kind: EdgeKind, } impl Edge { /// Construct a new edge whose referent is `to` and is of the given `kind`. pub(crate) fn new(to: ItemId, kind: EdgeKind) -> Edge { Edge { to, kind } } } impl From 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(crate) 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` to `T` in the following /// snippet: /// /// ```C++ /// template /// class Foo { }; /// ``` TemplateParameterDefinition, /// An edge from a template instantiation to the template declaration that /// is being instantiated. For example, the edge from `Foo` to /// to `Foo`: /// /// ```C++ /// template /// class Foo { }; /// /// using Bar = Foo; /// ``` TemplateDeclaration, /// An edge from a template instantiation to its template argument. For /// example, `Foo` to `Bar`: /// /// ```C++ /// template /// class Foo { }; /// /// class Bar { }; /// /// using FooBar = Foo; /// ``` 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(crate) 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(crate) 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(crate) 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(crate) 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(crate) 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, item: ItemId) -> bool; } impl<'ctx> TraversalStorage<'ctx> for ItemSet { fn new(_: &'ctx BindgenContext) -> Self { ItemSet::new() } fn add(&mut self, _: Option, 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(crate) struct Paths<'ctx>(BTreeMap, &'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, 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 = {item:?}\nvia path = {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(crate) 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; } impl TraversalQueue for Vec { fn push(&mut self, item: ItemId) { self.push(item); } fn next(&mut self) -> Option { self.pop() } } impl TraversalQueue for VecDeque { fn push(&mut self, item: ItemId) { self.push_back(item); } fn next(&mut self) -> Option { self.pop_front() } } /// Something that can receive edges from a `Trace` implementation. pub(crate) 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 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(crate) 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( &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(crate) 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, } impl<'ctx, Storage, Queue> ItemTraversal<'ctx, Storage, Queue> where Storage: TraversalStorage<'ctx>, Queue: TraversalQueue, { /// Begin a new traversal, starting from the given roots. pub(crate) fn new( ctx: &'ctx BindgenContext, roots: R, predicate: TraversalPredicate, ) -> ItemTraversal<'ctx, Storage, Queue> where R: IntoIterator, { 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 { 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(crate) type AssertNoDanglingItemsTraversal<'ctx> = ItemTraversal<'ctx, Paths<'ctx>, VecDeque>; bindgen-0.71.1/ir/ty.rs000064400000000000000000001343321046102023000127420ustar 00000000000000//! 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::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::{ParseError, ParseResult}; use std::borrow::Cow; use std::io; pub use super::int::IntKind; /// 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(crate) struct Type { /// The name of the type, or None if it was an unnamed struct or union. name: Option, /// The layout of the type, if known. layout: Option, /// 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(crate) const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32; impl Type { /// Get the underlying `CompInfo` for this type as a mutable reference, or /// `None` if this is some other kind of type. pub(crate) 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(crate) fn new( name: Option, layout: Option, kind: TypeKind, is_const: bool, ) -> Self { Type { name, layout, kind, is_const, } } /// Which kind of type is this? pub(crate) fn kind(&self) -> &TypeKind { &self.kind } /// Get a mutable reference to this type's kind. pub(crate) fn kind_mut(&mut self) -> &mut TypeKind { &mut self.kind } /// Get this type's name. pub(crate) fn name(&self) -> Option<&str> { self.name.as_deref() } /// Whether this is a block pointer type. pub(crate) fn is_block_pointer(&self) -> bool { matches!(self.kind, TypeKind::BlockPointer(..)) } /// Is this an integer type, including `bool` or `char`? pub(crate) fn is_int(&self) -> bool { matches!(self.kind, TypeKind::Int(_)) } /// Is this a compound type? pub(crate) fn is_comp(&self) -> bool { matches!(self.kind, TypeKind::Comp(..)) } /// Is this a union? pub(crate) fn is_union(&self) -> bool { match self.kind { TypeKind::Comp(ref comp) => comp.is_union(), _ => false, } } /// Is this type of kind `TypeKind::TypeParam`? pub(crate) fn is_type_param(&self) -> bool { matches!(self.kind, TypeKind::TypeParam) } /// Is this a template instantiation type? pub(crate) fn is_template_instantiation(&self) -> bool { matches!(self.kind, TypeKind::TemplateInstantiation(..)) } /// Is this a function type? pub(crate) fn is_function(&self) -> bool { matches!(self.kind, TypeKind::Function(..)) } /// Is this an enum type? pub(crate) fn is_enum(&self) -> bool { matches!(self.kind, TypeKind::Enum(..)) } /// Is this void? pub(crate) fn is_void(&self) -> bool { matches!(self.kind, TypeKind::Void) } /// Is this either a builtin or named type? pub(crate) 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(crate) 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(crate) fn is_float(&self) -> bool { matches!(self.kind, TypeKind::Float(..)) } /// Is this a boolean type? pub(crate) fn is_bool(&self) -> bool { matches!(self.kind, TypeKind::Int(IntKind::Bool)) } /// Is this an integer type? pub(crate) 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(crate) fn as_integer(&self) -> Option { match self.kind { TypeKind::Int(int_kind) => Some(int_kind), _ => None, } } /// Is this a `const` qualified type? pub(crate) fn is_const(&self) -> bool { self.is_const } /// Is this an unresolved reference? pub(crate) fn is_unresolved_ref(&self) -> bool { matches!(self.kind, TypeKind::UnresolvedTypeRef(_, _, _)) } /// Is this a incomplete array type? pub(crate) fn is_incomplete_array( &self, ctx: &BindgenContext, ) -> Option { 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(crate) fn layout(&self, ctx: &BindgenContext) -> Option { self.layout.or_else(|| { match self.kind { TypeKind::Comp(ref ci) => ci.layout(ctx), TypeKind::Array(inner, 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(crate) 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 { if clang::is_valid_identifier(name) { return Cow::Borrowed(name); } let name = name.replace([' ', ':', '.'], "_"); Cow::Owned(name) } /// Get this type's sanitized name. pub(crate) fn sanitized_name<'a>( &'a self, ctx: &BindgenContext, ) -> Option> { 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 [`Self::safe_canonical_type`]. pub(crate) 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(crate) 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(crate) 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 { self.kind.as_template_param(ctx, item) } } impl AsTemplateParam for TypeKind { type Extra = Item; fn as_template_param( &self, ctx: &BindgenContext, item: &Item, ) -> Option { 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( &self, ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { if let Some(ref layout) = self.layout { writeln!( out, "size{} align{}", layout.size, layout.align )?; if layout.packed { writeln!(out, "packedtrue")?; } } if self.is_const { writeln!(out, "consttrue")?; } self.kind.dot_attributes(ctx, out) } } impl DotAttributes for TypeKind { fn dot_attributes( &self, ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!( out, "type kind{}", 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_remaining() { 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 { self.kind.self_template_params(ctx) } } impl TemplateParameters for TypeKind { fn self_template_params(&self, ctx: &BindgenContext) -> Vec { 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(crate) enum FloatKind { /// A half (`_Float16` or `__fp16`) Float16, /// 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(crate) 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 should /// 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), /// 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, Cursor, /* parent_id */ Option), /// 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(crate) fn from_clang_ty( potential_id: ItemId, ty: &clang::Type, location: Cursor, parent_id: Option, ctx: &mut BindgenContext, ) -> Result, 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!("{ty:?} already resolved: {location:?}"); return Ok(ParseResult::AlreadyResolved(ty.into())); } } let layout = ty.fallible_layout(ctx).ok(); let cursor = ty.declaration(); let is_anonymous = cursor.is_anonymous(); let mut name = if is_anonymous { None } else { Some(cursor.spelling()).filter(|n| !n.is_empty()) }; debug!( "from_clang_ty: {potential_id:?}, ty: {ty:?}, loc: {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 = Some("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 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 = Some(location.spelling()); } let complex = CompInfo::from_ty( potential_id, ty, Some(location), ctx, ); if let Ok(complex) = complex { TypeKind::Comp(complex) } else { 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 = Some(location.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 Ok(inner_type) = inner else { 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 = {location:?}; referenced = {referenced:?}; referenced_ty = {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 = {location:?}; referenced = {referenced:?}; referenced_ty = {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 {ty:?}, recursing inside, loc: {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_id = Item::from_ty_or_ref(inner, location, None, ctx); if inner_id == potential_id { warn!( "Generating opaque type instead of self-referential \ typedef"); // This can happen if we bail out of recursive situations // within the clang parsing. TypeKind::Opaque } else { // Check if this type definition is an alias to a pointer of a `struct` / // `union` / `enum` with the same name and add the `_ptr` suffix to it to // avoid name collisions. if let Some(ref mut name) = name { if inner.kind() == CXType_Pointer && !ctx.options().c_naming { let pointee = inner.pointee_type().unwrap(); if pointee.kind() == CXType_Elaborated && pointee.declaration().spelling() == *name { *name += "_ptr"; } } } TypeKind::Alias(inner_id) } } CXType_Enum => { let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?"); if !is_anonymous { let pretty_name = ty.spelling(); if clang::is_valid_identifier(&pretty_name) { name = Some(pretty_name); } } TypeKind::Enum(enum_) } CXType_Record => { let complex = CompInfo::from_ty( potential_id, ty, Some(location), ctx, ) .expect("Not a complex type?"); if !is_anonymous { // 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 = Some(pretty_name); } } TypeKind::Comp(complex) } CXType_Vector => { let inner = Item::from_ty( ty.elem_type().as_ref().unwrap(), location, None, ctx, )?; 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_Atomic => { // TODO(emilio): Maybe we can preserve the "is atomic" bit somehow and generate // something more useful... But for now this is better than panicking or // generating nothing. return Self::from_clang_ty( potential_id, &ty.atomic_value_type(), location, parent_id, ctx, ); } 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?"); if !is_anonymous { name = Some(interface.rust_name()); } TypeKind::ObjCInterface(interface) } CXType_Dependent => { return Err(ParseError::Continue); } _ => { warn!( "unsupported type: kind = {:?}; ty = {ty:?}; at {location:?}", ty.kind(), ); return Err(ParseError::Continue); } } }; name = name.filter(|n| !n.is_empty()); let is_const = ty.is_const() || (ty.kind() == CXType_ConstantArray && ty.elem_type().is_some_and(|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(&self, context: &BindgenContext, tracer: &mut T, item: &Item) where T: Tracer, { if self.name().is_some_and(|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 => {} } } } bindgen-0.71.1/ir/var.rs000064400000000000000000000440151046102023000130740ustar 00000000000000//! 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::{ItemInfo, ItemKind, MacroParsingBehavior}; use crate::clang; use crate::clang::ClangToken; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; use std::io; use std::num::Wrapping; /// The type for a constant variable. #[derive(Debug)] pub(crate) 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), } /// A `Var` is our intermediate representation of a variable. #[derive(Debug)] pub(crate) struct Var { /// The name of the variable. name: String, /// The mangled name of the variable. mangled_name: Option, /// The link name of the variable. link_name: Option, /// The type of the variable. ty: TypeId, /// The value of the variable, that needs to be suitable for `ty`. val: Option, /// Whether this variable is const. is_const: bool, } impl Var { /// Construct a new `Var`. pub(crate) fn new( name: String, mangled_name: Option, link_name: Option, ty: TypeId, val: Option, is_const: bool, ) -> Var { assert!(!name.is_empty()); Var { name, mangled_name, link_name, ty, val, is_const, } } /// Is this variable `const` qualified? pub(crate) fn is_const(&self) -> bool { self.is_const } /// The value of this constant variable, if any. pub(crate) fn val(&self) -> Option<&VarType> { self.val.as_ref() } /// Get this variable's type. pub(crate) fn ty(&self) -> TypeId { self.ty } /// Get this variable's name. pub(crate) fn name(&self) -> &str { &self.name } /// Get this variable's mangled name. pub(crate) fn mangled_name(&self) -> Option<&str> { self.mangled_name.as_deref() } /// Get this variable's link name. pub fn link_name(&self) -> Option<&str> { self.link_name.as_deref() } } impl DotAttributes for Var { fn dot_attributes( &self, _ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { if self.is_const { writeln!(out, "consttrue")?; } if let Some(ref mangled) = self.mangled_name { writeln!(out, "mangled name{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 < i64::from(i32::MIN) || value > i64::from(i32::MAX) { IntKind::I64 } else if !ctx.options().fit_macro_constants || value < i64::from(i16::MIN) || value > i64::from(i16::MAX) { IntKind::I32 } else if value < i64::from(i8::MIN) || value > i64::from(i8::MAX) { IntKind::I16 } else { IntKind::I8 } } else if value > i64::from(u32::MAX) { IntKind::U64 } else if !ctx.options().fit_macro_constants || value > i64::from(u16::MAX) { IntKind::U32 } else if value > i64::from(u8::MAX) { 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::>().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, ParseError> { use cexpr::expr::EvalResult; use cexpr::literal::CChar; use clang_sys::*; match cursor.kind() { CXCursor_MacroDefinition => { for callbacks in &ctx.options().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.as_ref()); // We handled the macro, skip macro processing below. return Err(ParseError::Continue); } } let value = parse_macro(ctx, &cursor); let Some((id, value)) = value else { 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(); duplicated_macro_diagnostic(&name, cursor.location(), ctx); 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 <= u64::from(u8::MAX)); 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, ); for callbacks in &ctx.options().parse_callbacks { callbacks.str_macro(&name, &val); } (TypeKind::Pointer(char_ty), VarType::String(val)) } EvalResult::Int(Wrapping(value)) => { let kind = ctx .options() .last_callback(|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, None, ty, Some(val), true), Some(cursor), )) } CXCursor_VarDecl => { let mut name = cursor.spelling(); if cursor.linkage() == CXLinkage_External { if let Some(nm) = ctx.options().last_callback(|callbacks| { callbacks.generated_name_override(ItemInfo { name: name.as_str(), kind: ItemKind::Var, }) }) { name = nm; } } // No more changes to name let name = name; if name.is_empty() { warn!("Empty constant name?"); return Err(ParseError::Continue); } let link_name = ctx.options().last_callback(|callbacks| { callbacks.generated_link_name_override(ItemInfo { name: name.as_str(), kind: ItemKind::Var, }) }); 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() || ([CXType_ConstantArray, CXType_IncompleteArray] .contains(&ty.kind()) && ty.elem_type() .is_some_and(|element| element.is_const())); let ty = match Item::from_ty(&ty, cursor, None, ctx) { Ok(ty) => ty, Err(e) => { assert!( matches!(ty.kind(), CXType_Auto | CXType_Unexposed), "Couldn't resolve constant type, and it \ wasn't an nondeductible auto type or unexposed \ type: {ty:?}" ); 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.is_some_and(|t| t.is_integer()); let is_float = canonical_ty.is_some_and(|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 TypeKind::Int(kind) = *canonical_ty.unwrap().kind() else { 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, link_name, ty, value, is_const); Ok(ParseResult::New(var, Some(cursor))) } _ => { /* TODO */ Err(ParseError::Continue) } } } } /// This function uses a [`FallbackTranslationUnit`][clang::FallbackTranslationUnit] to parse each /// macro that cannot be parsed by the normal bindgen process for `#define`s. /// /// To construct the [`FallbackTranslationUnit`][clang::FallbackTranslationUnit], first precompiled /// headers are generated for all input headers. An empty temporary `.c` file is generated to pass /// to the translation unit. On the evaluation of each macro, a [`String`] is generated with the /// new contents of the empty file and passed in for reparsing. The precompiled headers and /// preservation of the [`FallbackTranslationUnit`][clang::FallbackTranslationUnit] across macro /// evaluations are both optimizations that have significantly improved the performance. fn parse_macro_clang_fallback( ctx: &mut BindgenContext, cursor: &clang::Cursor, ) -> Option<(Vec, cexpr::expr::EvalResult)> { if !ctx.options().clang_macro_fallback { return None; } let ftu = ctx.try_ensure_fallback_translation_unit()?; let contents = format!("int main() {{ {}; }}", cursor.spelling()); ftu.reparse(&contents).ok()?; // Children of root node of AST let root_children = ftu.translation_unit().cursor().collect_children(); // Last child in root is function declaration // Should be FunctionDecl let main_func = root_children.last()?; // Children should all be statements in function declaration let all_stmts = main_func.collect_children(); // First child in all_stmts should be the statement containing the macro to evaluate // Should be CompoundStmt let macro_stmt = all_stmts.first()?; // Children should all be expressions from the compound statement let paren_exprs = macro_stmt.collect_children(); // First child in all_exprs is the expression utilizing the given macro to be evaluated // Should be ParenExpr let paren = paren_exprs.first()?; Some(( cursor.spelling().into_bytes(), cexpr::expr::EvalResult::Int(Wrapping(paren.evaluate()?.as_int()?)), )) } /// Try and parse a macro using all the macros parsed until now. fn parse_macro( ctx: &mut BindgenContext, cursor: &clang::Cursor, ) -> Option<(Vec, 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)), _ => parse_macro_clang_fallback(ctx, cursor), } } fn parse_int_literal_tokens(cursor: &clang::Cursor) -> Option { 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 { 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 } fn duplicated_macro_diagnostic( macro_name: &str, _location: clang::SourceLocation, _ctx: &BindgenContext, ) { warn!("Duplicated macro definition: {macro_name}"); #[cfg(feature = "experimental")] // FIXME (pvdrz & amanjeev): This diagnostic message shows way too often to be actually // useful. We have to change the logic where this function is called to be able to emit this // message only when the duplication is an actual issue. // // If I understood correctly, `bindgen` ignores all `#undef` directives. Meaning that this: // ```c // #define FOO 1 // #undef FOO // #define FOO 2 // ``` // // Will trigger this message even though there's nothing wrong with it. #[allow(clippy::overly_complex_bool_expr)] if false && _ctx.options().emit_diagnostics { use crate::diagnostics::{get_line, Diagnostic, Level, Slice}; use std::borrow::Cow; let mut slice = Slice::default(); let mut source = Cow::from(macro_name); let (file, line, col, _) = _location.location(); if let Some(filename) = file.name() { if let Ok(Some(code)) = get_line(&filename, line) { source = code.into(); } slice.with_location(filename, line, col); } slice.with_source(source); Diagnostic::default() .with_title("Duplicated macro definition.", Level::Warning) .add_slice(slice) .add_annotation("This macro had a duplicate.", Level::Note) .display(); } } bindgen-0.71.1/lib.rs000064400000000000000000001262401046102023000124410ustar 00000000000000//! 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)] #![deny(clippy::disallowed_methods)] // 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 quote; #[cfg(feature = "logging")] #[macro_use] extern crate log; #[cfg(not(feature = "logging"))] #[macro_use] mod log_stubs; #[macro_use] mod extra_assertions; mod codegen; mod deps; mod options; mod time; pub mod callbacks; mod clang; #[cfg(feature = "experimental")] mod diagnostics; mod features; mod ir; mod parse; mod regex_set; pub use codegen::{ AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle, }; pub use features::{RustEdition, RustTarget, LATEST_STABLE_RUST}; pub use ir::annotations::FieldVisibilityKind; pub use ir::function::Abi; #[cfg(feature = "__cli")] pub use options::cli::builder_from_flags; use codegen::CodegenError; use features::RustFeatures; use ir::comment; use ir::context::{BindgenContext, ItemId}; use ir::item::Item; use options::BindgenOptions; use parse::ParseError; use std::borrow::Cow; use std::collections::hash_map::Entry; use std::env; use std::ffi::OsStr; use std::fs::{File, OpenOptions}; use std::io::{self, Write}; use std::mem::size_of; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::rc::Rc; use std::str::FromStr; // Some convenient typedefs for a fast hash map and hash set. type HashMap = rustc_hash::FxHashMap; type HashSet = rustc_hash::FxHashSet; /// Default prefix for the anon fields. pub const DEFAULT_ANON_FIELDS_PREFIX: &str = "__bindgen_anon_"; const DEFAULT_NON_EXTERN_FNS_SUFFIX: &str = "__extern"; 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: &[Box]) -> bool { for w in clang_args.windows(2) { if w[0].as_ref() == "-xc++" || w[1].as_ref() == "-xc++" { return true; } if w[0].as_ref() == "-x" && w[1].as_ref() == "c++" { return true; } if w[0].as_ref() == "-include" && file_is_cpp(w[1].as_ref()) { return true; } } false } bitflags! { /// A type used to indicate which kind of items we have to generate. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 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 methods 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() } } /// Formatting tools that can be used to format the bindings #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[non_exhaustive] pub enum Formatter { /// Do not format the bindings. None, /// Use `rustfmt` to format the bindings. Rustfmt, #[cfg(feature = "prettyplease")] /// Use `prettyplease` to format the bindings. Prettyplease, } impl Default for Formatter { fn default() -> Self { Self::Rustfmt } } impl FromStr for Formatter { type Err = String; fn from_str(s: &str) -> Result { match s { "none" => Ok(Self::None), "rustfmt" => Ok(Self::Rustfmt), #[cfg(feature = "prettyplease")] "prettyplease" => Ok(Self::Prettyplease), _ => Err(format!("`{s}` is not a valid formatter")), } } } impl std::fmt::Display for Formatter { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let s = match self { Self::None => "none", Self::Rustfmt => "rustfmt", #[cfg(feature = "prettyplease")] Self::Prettyplease => "prettyplease", }; s.fmt(f) } } /// 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) /// 5. [`rustified_non_exhaustive_enum()`](#method.rustified_non_exhaustive_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`. /// /// # Regular expression arguments /// /// Some [`Builder`] methods, such as `allowlist_*` and `blocklist_*`, allow regular /// expressions as arguments. These regular expressions will be enclosed in parentheses and /// anchored with `^` and `$`. So, if the argument passed is ``, the regular expression to be /// stored will be `^()$`. /// /// As a consequence, regular expressions passed to `bindgen` will try to match the whole name of /// an item instead of a section of it, which means that to match any items with the prefix /// `prefix`, the `prefix.*` regular expression must be used. /// /// Certain methods, like [`Builder::allowlist_function`], use regular expressions over function /// names. To match C++ methods, prefix the name of the type where they belong, followed by an /// underscore. So, if the type `Foo` has a method `bar`, it can be matched with the `Foo_bar` /// regular expression. /// /// Additionally, Objective-C interfaces can be matched by prefixing the regular expression with /// `I`. For example, the `IFoo` regular expression matches the `Foo` interface, and the `IFoo_foo` /// regular expression matches the `foo` method of the `Foo` interface. /// /// Releases of `bindgen` with a version lesser or equal to `0.62.0` used to accept the wildcard /// pattern `*` as a valid regular expression. This behavior has been deprecated, and the `.*` /// regular expression must be used instead. #[derive(Debug, Default, Clone)] pub struct Builder { options: BindgenOptions, } /// Construct a new [`Builder`](./struct.Builder.html). pub fn builder() -> Builder { Default::default() } fn get_extra_clang_args( parse_callbacks: &[Rc], ) -> Vec { // Add any extra arguments from the environment to the clang command line. let extra_clang_args = match get_target_dependent_env_var( parse_callbacks, "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 { /// Generate the Rust bindings using the options built up thus far. pub fn generate(mut self) -> Result { // Keep rust_features synced with rust_target self.options.rust_features = match self.options.rust_edition { Some(edition) => { if !edition.is_available(self.options.rust_target) { return Err(BindgenError::UnsupportedEdition( edition, self.options.rust_target, )); } RustFeatures::new(self.options.rust_target, edition) } None => { RustFeatures::new_with_latest_edition(self.options.rust_target) } }; // Add any extra arguments from the environment to the clang command line. self.options.clang_args.extend( get_extra_clang_args(&self.options.parse_callbacks) .into_iter() .map(String::into_boxed_str), ); for header in &self.options.input_headers { self.options .for_each_callback(|cb| cb.header_file(header.as_ref())); } // Transform input headers to arguments on the clang command line. self.options.clang_args.extend( self.options.input_headers [..self.options.input_headers.len().saturating_sub(1)] .iter() .flat_map(|header| ["-include".into(), header.clone()]), ); let input_unsaved_files = std::mem::take(&mut self.options.input_header_contents) .into_iter() .map(|(name, contents)| { clang::UnsavedFile::new(name.as_ref(), contents.as_ref()) }) .collect::>(); 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.options.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 (name, contents) in &self.options.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.as_ref()); } for a in get_extra_clang_args(&self.options.parse_callbacks) { 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", )) } } } impl BindgenOptions { fn build(&mut self) { const REGEX_SETS_LEN: usize = 29; let regex_sets: [_; REGEX_SETS_LEN] = [ &mut self.blocklisted_types, &mut self.blocklisted_functions, &mut self.blocklisted_items, &mut self.blocklisted_files, &mut self.blocklisted_vars, &mut self.opaque_types, &mut self.allowlisted_vars, &mut self.allowlisted_types, &mut self.allowlisted_functions, &mut self.allowlisted_files, &mut self.allowlisted_items, &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; #[cfg(feature = "experimental")] { let sets_len = REGEX_SETS_LEN + self.abi_overrides.len(); let names = if self.emit_diagnostics { <[&str; REGEX_SETS_LEN]>::into_iter([ "--blocklist-type", "--blocklist-function", "--blocklist-item", "--blocklist-file", "--blocklist-var", "--opaque-type", "--allowlist-type", "--allowlist-function", "--allowlist-var", "--allowlist-file", "--allowlist-item", "--bitfield-enum", "--newtype-enum", "--newtype-global-enum", "--rustified-enum", "--rustified-enum-non-exhaustive", "--constified-enum-module", "--constified-enum", "--type-alias", "--new-type-alias", "--new-type-alias-deref", "--bindgen-wrapper-union", "--manually-drop-union", "--no-partialeq", "--no-copy", "--no-debug", "--no-default", "--no-hash", "--must-use", ]) .chain((0..self.abi_overrides.len()).map(|_| "--override-abi")) .map(Some) .collect() } else { vec![None; sets_len] }; for (regex_set, name) in self.abi_overrides.values_mut().chain(regex_sets).zip(names) { regex_set.build_with_diagnostics(record_matches, name); } } #[cfg(not(feature = "experimental"))] for regex_set in self.abi_overrides.values_mut().chain(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; } /// Get features supported by target Rust version pub fn rust_features(&self) -> RustFeatures { self.rust_features } fn last_callback( &self, f: impl Fn(&dyn callbacks::ParseCallbacks) -> Option, ) -> Option { self.parse_callbacks .iter() .filter_map(|cb| f(cb.as_ref())) .last() } fn all_callbacks( &self, f: impl Fn(&dyn callbacks::ParseCallbacks) -> Vec, ) -> Vec { self.parse_callbacks .iter() .flat_map(|cb| f(cb.as_ref())) .collect() } fn for_each_callback(&self, f: impl Fn(&dyn callbacks::ParseCallbacks)) { self.parse_callbacks.iter().for_each(|cb| f(cb.as_ref())); } fn process_comment(&self, comment: &str) -> String { let comment = comment::preprocess(comment); self.parse_callbacks .last() .and_then(|cb| cb.process_comment(&comment)) .unwrap_or(comment) } } #[cfg(feature = "runtime")] fn ensure_libclang_is_loaded() { use std::sync::{Arc, OnceLock}; 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. static LIBCLANG: OnceLock> = OnceLock::new(); let libclang = LIBCLANG.get_or_init(|| { 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), /// Code generation reported an error. Codegen(CodegenError), /// The passed edition is not available on that Rust target. UnsupportedEdition(RustEdition, RustTarget), } 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}") } BindgenError::Codegen(err) => { write!(f, "codegen error: {err}") } BindgenError::UnsupportedEdition(edition, target) => { write!(f, "edition {edition} is not available on Rust {target}") } } } } impl std::error::Error for BindgenError {} /// Generated Rust bindings. #[derive(Debug)] pub struct Bindings { options: BindgenOptions, 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) -> Box { const TRIPLE_HYPHENS_MESSAGE: &str = "Target triple should contain hyphens"; let mut clang_target = rust_target.to_owned(); if clang_target.starts_with("riscv32") { let idx = clang_target.find('-').expect(TRIPLE_HYPHENS_MESSAGE); clang_target.replace_range(..idx, "riscv32"); } else if clang_target.starts_with("riscv64") { let idx = clang_target.find('-').expect(TRIPLE_HYPHENS_MESSAGE); clang_target.replace_range(..idx, "riscv64"); } else if clang_target.starts_with("aarch64-apple-") { let idx = clang_target.find('-').expect(TRIPLE_HYPHENS_MESSAGE); clang_target.replace_range(..idx, "arm64"); } if clang_target.ends_with("-espidf") { let idx = clang_target.rfind('-').expect(TRIPLE_HYPHENS_MESSAGE); clang_target.replace_range((idx + 1).., "elf"); } clang_target.into() } /// Returns the effective target, and whether it was explicitly specified on the /// clang flags. fn find_effective_target(clang_args: &[Box]) -> (Box, 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().into(), true); } if opt.as_ref() == "-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, ) -> Result { ensure_libclang_is_loaded(); #[cfg(feature = "runtime")] match clang_sys::get_library().unwrap().version() { None => { warn!("Could not detect a Clang version, make sure you are using libclang 9 or newer"); } Some(version) => { if version < clang_sys::Version::V9_0 { warn!("Detected Clang version {version:?} which is unsupported and can cause invalid code generation, use libclang 9 or newer"); } } } #[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}").into_boxed_str(), ); }; 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.as_ref(); // 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 }) .map(|arg| arg.clone().into()) .collect::>() }; 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_headers.iter().any(|h| file_is_cpp(h)); 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".into()); options.clang_args.push(path.into_boxed_str()); } } } } 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_headers.last() { let path = Path::new(h.as_ref()); 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_headers.is_empty() { options.clang_args.push("-include".into()); } options.clang_args.push(f.name.to_str().unwrap().into()); } 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(), size_of::<*mut ()>(), "{effective_target:?} {HOST_TARGET:?}" ); } { let _t = time::Timer::new("parse").with_output(time_phases); parse(&mut context)?; } let (module, options) = codegen::codegen(context).map_err(BindgenError::Codegen)?; Ok(Bindings { options, module }) } /// Write these bindings as source text to a file. pub fn write_to_file>(&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) -> io::Result<()> { const NL: &str = if cfg!(windows) { "\r\n" } else { "\n" }; if !self.options.disable_header_comment { let version = option_env!("CARGO_PKG_VERSION").unwrap_or("(unknown version)"); write!( writer, "/* automatically generated by rust-bindgen {version} */{NL}{NL}", )?; } for line in &self.options.raw_lines { writer.write_all(line.as_bytes())?; writer.write_all(NL.as_bytes())?; } if !self.options.raw_lines.is_empty() { writer.write_all(NL.as_bytes())?; } match self.format_tokens(&self.module) { Ok(formatted_bindings) => { writer.write_all(formatted_bindings.as_bytes())?; } Err(err) => { eprintln!( "Failed to run rustfmt: {err} (non-fatal, continuing)" ); writer.write_all(self.module.to_string().as_bytes())?; } } Ok(()) } /// Gets the rustfmt path to rustfmt the generated bindings. fn rustfmt_path(&self) -> io::Result> { debug_assert!(matches!(self.options.formatter, Formatter::Rustfmt)); 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())); } // 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())) } /// Formats a token stream with the formatter set up in `BindgenOptions`. fn format_tokens( &self, tokens: &proc_macro2::TokenStream, ) -> io::Result { let _t = time::Timer::new("rustfmt_generated_string") .with_output(self.options.time_phases); match self.options.formatter { Formatter::None => return Ok(tokens.to_string()), #[cfg(feature = "prettyplease")] Formatter::Prettyplease => { return Ok(prettyplease::unparse(&syn::parse_quote!(#tokens))); } Formatter::Rustfmt => (), } 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 = tokens.to_string(); // 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(bindings), Some(2) => Err(io::Error::new( io::ErrorKind::Other, "Rustfmt parsing errors.".to_string(), )), Some(3) => { rustfmt_non_fatal_error_diagnostic( "Rustfmt could not format some lines", &self.options, ); Ok(bindings) } _ => Err(io::Error::new( io::ErrorKind::Other, "Internal rustfmt error".to_string(), )), }, _ => Ok(source), } } } fn rustfmt_non_fatal_error_diagnostic(msg: &str, _options: &BindgenOptions) { warn!("{msg}"); #[cfg(feature = "experimental")] if _options.emit_diagnostics { use crate::diagnostics::{Diagnostic, Level}; Diagnostic::default() .with_title(msg, Level::Warning) .add_annotation( "The bindings will be generated but not formatted.", Level::Note, ) .display(); } } 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) .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, ) { if !filter_builtins(ctx, &cursor) { return; } match Item::parse(cursor, parent, ctx) { Ok(..) => {} Err(ParseError::Continue) => {} Err(ParseError::Recurse) => { cursor .visit_sorted(ctx, |ctx, child| parse_one(ctx, child, parent)); } } } /// 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() { 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() { CXChildVisit_Continue } else { clang::ast_dump(cur, 0) } } cursor.visit(|cur| dump_if_not_builtin(&cur)); } let root = context.root_module(); context.with_module(root, |ctx| { cursor.visit_sorted(ctx, |ctx, child| parse_one(ctx, child, 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> = raw_v .split_whitespace() .find(|t| t.chars().next().is_some_and(|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::(); let maybe_minor = v[1].parse::(); 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(), } } fn env_var + AsRef>( parse_callbacks: &[Rc], key: K, ) -> Result { for callback in parse_callbacks { callback.read_env_var(key.as_ref()); } env::var(key) } /// Looks for the env var `var_${TARGET}`, and falls back to just `var` when it is not found. fn get_target_dependent_env_var( parse_callbacks: &[Rc], var: &str, ) -> Option { if let Ok(target) = env_var(parse_callbacks, "TARGET") { if let Ok(v) = env_var(parse_callbacks, format!("{var}_{target}")) { return Some(v); } if let Ok(v) = env_var( parse_callbacks, format!("{var}_{}", target.replace('-', "_")), ) { return Some(v); } } env_var(parse_callbacks, var).ok() } /// A `ParseCallbacks` implementation that will act on file includes by echoing a rerun-if-changed /// line and on env variable usage by echoing a rerun-if-env-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::new())) /// .generate(); /// ``` #[derive(Debug)] pub struct CargoCallbacks { rerun_on_header_files: bool, } /// Create a new `CargoCallbacks` value with [`CargoCallbacks::rerun_on_header_files`] disabled. /// /// This constructor has been deprecated in favor of [`CargoCallbacks::new`] where /// [`CargoCallbacks::rerun_on_header_files`] is enabled by default. #[deprecated = "Use `CargoCallbacks::new()` instead. Please, check the documentation for further information."] pub const CargoCallbacks: CargoCallbacks = CargoCallbacks { rerun_on_header_files: false, }; impl CargoCallbacks { /// Create a new `CargoCallbacks` value. pub fn new() -> Self { Self { rerun_on_header_files: true, } } /// Whether Cargo should re-run the build script if any of the input header files has changed. /// /// This option is enabled by default unless the deprecated [`const@CargoCallbacks`] /// constructor is used. pub fn rerun_on_header_files(mut self, doit: bool) -> Self { self.rerun_on_header_files = doit; self } } impl Default for CargoCallbacks { fn default() -> Self { Self::new() } } impl callbacks::ParseCallbacks for CargoCallbacks { fn header_file(&self, filename: &str) { if self.rerun_on_header_files { println!("cargo:rerun-if-changed={filename}"); } } fn include_file(&self, filename: &str) { println!("cargo:rerun-if-changed={filename}"); } fn read_env_var(&self, key: &str) { println!("cargo:rerun-if-env-changed={key}"); } } /// Test `command_line_flag` function. #[test] fn commandline_flag_unit_test_function() { //Test 1 let bindings = builder(); let command_line_flags = bindings.command_line_flags(); let test_cases = [ "--rust-target", "--no-derive-default", "--generate", "functions,types,vars,methods,constructors,destructors", ] .iter() .map(|&x| x.into()) .collect::>(); assert!(test_cases.iter().all(|x| command_line_flags.contains(x))); //Test 2 let bindings = builder() .header("input_header") .allowlist_type("Distinct_Type") .allowlist_function("safe_function"); let command_line_flags = bindings.command_line_flags(); let test_cases = [ "--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::>(); 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").as_ref(), "arm64-apple-ios" ); } #[test] fn test_rust_to_clang_target_riscv() { assert_eq!( rust_to_clang_target("riscv64gc-unknown-linux-gnu").as_ref(), "riscv64-unknown-linux-gnu" ); assert_eq!( rust_to_clang_target("riscv64imac-unknown-none-elf").as_ref(), "riscv64-unknown-none-elf" ); assert_eq!( rust_to_clang_target("riscv32imc-unknown-none-elf").as_ref(), "riscv32-unknown-none-elf" ); assert_eq!( rust_to_clang_target("riscv32imac-unknown-none-elf").as_ref(), "riscv32-unknown-none-elf" ); assert_eq!( rust_to_clang_target("riscv32imafc-unknown-none-elf").as_ref(), "riscv32-unknown-none-elf" ); assert_eq!( rust_to_clang_target("riscv32i-unknown-none-elf").as_ref(), "riscv32-unknown-none-elf" ); } #[test] fn test_rust_to_clang_target_espidf() { assert_eq!( rust_to_clang_target("riscv32imc-esp-espidf").as_ref(), "riscv32-esp-elf" ); assert_eq!( rust_to_clang_target("xtensa-esp32-espidf").as_ref(), "xtensa-esp32-elf" ); } bindgen-0.71.1/log_stubs.rs000064400000000000000000000020071046102023000136660ustar 00000000000000#![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)+) }; } bindgen-0.71.1/options/as_args.rs000064400000000000000000000031121046102023000147750ustar 00000000000000use std::path::PathBuf; use crate::regex_set::RegexSet; /// Trait used to turn [`crate::BindgenOptions`] fields into CLI args. pub(super) trait AsArgs { fn as_args(&self, args: &mut Vec, flag: &str); } /// If the `bool` is `true`, `flag` is pushed into `args`. /// /// be careful about the truth value of the field as some options, like `--no-layout-tests`, are /// actually negations of the fields. impl AsArgs for bool { fn as_args(&self, args: &mut Vec, flag: &str) { if *self { args.push(flag.to_string()); } } } /// Iterate over all the items of the `RegexSet` and push `flag` followed by the item into `args` /// for each item. impl AsArgs for RegexSet { fn as_args(&self, args: &mut Vec, flag: &str) { for item in self.get_items() { args.extend_from_slice(&[flag.to_owned(), item.clone().into()]); } } } /// If the `Option` is `Some(value)`, push `flag` followed by `value`. impl AsArgs for Option { fn as_args(&self, args: &mut Vec, flag: &str) { if let Some(string) = self { args.extend_from_slice(&[flag.to_owned(), string.clone()]); } } } /// If the `Option` is `Some(path)`, push `flag` followed by the [`std::path::Path::display`] /// representation of `path`. impl AsArgs for Option { fn as_args(&self, args: &mut Vec, flag: &str) { if let Some(path) = self { args.extend_from_slice(&[ flag.to_owned(), path.display().to_string(), ]); } } } bindgen-0.71.1/options/cli.rs000064400000000000000000001165571046102023000141470ustar 00000000000000#![allow(unused_qualifications)] // Clap somehow generates a lot of these use crate::{ builder, callbacks::{ AttributeInfo, DeriveInfo, ItemInfo, ParseCallbacks, TypeKind, }, features::{RustEdition, EARLIEST_STABLE_RUST}, regex_set::RegexSet, Abi, AliasVariation, Builder, CodegenConfig, EnumVariation, FieldVisibilityKind, Formatter, MacroTypeVariation, NonCopyUnionStyle, RustTarget, }; use clap::{ error::{Error, ErrorKind}, CommandFactory, Parser, }; use proc_macro2::TokenStream; use std::io; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{fs::File, process::exit}; fn rust_target_help() -> String { format!( "Version of the Rust compiler to target. Any Rust version after {EARLIEST_STABLE_RUST} is supported. Defaults to {}.", RustTarget::default() ) } fn rust_edition_help() -> String { format!("Rust edition to target. Defaults to the latest edition supported by the chosen Rust target. Possible values: ({}). ", RustEdition::ALL.map(|e| e.to_string()).join("|")) } fn parse_codegen_config( what_to_generate: &str, ) -> Result { 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::raw( ErrorKind::InvalidValue, format!("Unknown codegen item kind: {otherwise}"), )); } } } Ok(config) } fn parse_rustfmt_config_path(path_str: &str) -> Result { let path = Path::new(path_str); if !path.is_absolute() { return Err(Error::raw( ErrorKind::InvalidValue, "--rustfmt-configuration-file needs to be an absolute path!", )); } if path.to_str().is_none() { return Err(Error::raw( ErrorKind::InvalidUtf8, "--rustfmt-configuration-file contains non-valid UTF8 characters.", )); } Ok(path.to_path_buf()) } fn parse_abi_override(abi_override: &str) -> Result<(Abi, String), Error> { let (regex, abi_str) = abi_override .rsplit_once('=') .ok_or_else(|| Error::raw(ErrorKind::InvalidValue, "Missing `=`"))?; let abi = abi_str .parse() .map_err(|err| Error::raw(ErrorKind::InvalidValue, err))?; Ok((abi, regex.to_owned())) } fn parse_custom_derive( custom_derive: &str, ) -> Result<(Vec, String), Error> { let (regex, derives) = custom_derive .rsplit_once('=') .ok_or_else(|| Error::raw(ErrorKind::InvalidValue, "Missing `=`"))?; let derives = derives.split(',').map(|s| s.to_owned()).collect(); Ok((derives, regex.to_owned())) } fn parse_custom_attribute( custom_attribute: &str, ) -> Result<(Vec, String), Error> { let mut brace_level = 0; let (regex, attributes) = custom_attribute .rsplit_once(|c| { match c { ']' => brace_level += 1, '[' => brace_level -= 1, _ => {} } c == '=' && brace_level == 0 }) .ok_or_else(|| Error::raw(ErrorKind::InvalidValue, "Missing `=`"))?; let mut brace_level = 0; let attributes = attributes .split(|c| { match c { ']' => brace_level += 1, '[' => brace_level -= 1, _ => {} } c == ',' && brace_level == 0 }) .map(|s| s.to_owned()) .collect::>(); for attribute in &attributes { if let Err(err) = TokenStream::from_str(attribute) { return Err(Error::raw(ErrorKind::InvalidValue, err)); } } Ok((attributes, regex.to_owned())) } #[derive(Parser, Debug)] #[clap( about = "Generates Rust bindings from C/C++ headers.", override_usage = "bindgen
-- ...", trailing_var_arg = true )] #[allow(clippy::doc_markdown)] struct BindgenCommand { /// C or C++ header file. header: Option, /// Path to write depfile to. #[arg(long)] depfile: Option, /// The default STYLE of code used to generate enums. #[arg(long, value_name = "STYLE")] default_enum_style: Option, /// Mark any enum whose name matches REGEX as a set of bitfield flags. #[arg(long, value_name = "REGEX")] bitfield_enum: Vec, /// Mark any enum whose name matches REGEX as a newtype. #[arg(long, value_name = "REGEX")] newtype_enum: Vec, /// Mark any enum whose name matches REGEX as a global newtype. #[arg(long, value_name = "REGEX")] newtype_global_enum: Vec, /// Mark any enum whose name matches REGEX as a Rust enum. #[arg(long, value_name = "REGEX")] rustified_enum: Vec, /// Mark any enum whose name matches REGEX as a non-exhaustive Rust enum. #[arg(long, value_name = "REGEX")] rustified_non_exhaustive_enum: Vec, /// Mark any enum whose name matches REGEX as a series of constants. #[arg(long, value_name = "REGEX")] constified_enum: Vec, /// Mark any enum whose name matches REGEX as a module of constants. #[arg(long, value_name = "REGEX")] constified_enum_module: Vec, /// The default signed/unsigned TYPE for C macro constants. #[arg(long, value_name = "TYPE")] default_macro_constant_type: Option, /// The default STYLE of code used to generate typedefs. #[arg(long, value_name = "STYLE")] default_alias_style: Option, /// Mark any typedef alias whose name matches REGEX to use normal type aliasing. #[arg(long, value_name = "REGEX")] normal_alias: Vec, /// Mark any typedef alias whose name matches REGEX to have a new type generated for it. #[arg(long, value_name = "REGEX")] new_type_alias: Vec, /// Mark any typedef alias whose name matches REGEX to have a new type with Deref and DerefMut to the inner type. #[arg(long, value_name = "REGEX")] new_type_alias_deref: Vec, /// The default STYLE of code used to generate unions with non-Copy members. Note that ManuallyDrop was first stabilized in Rust 1.20.0. #[arg(long, value_name = "STYLE")] default_non_copy_union_style: Option, /// Mark any union whose name matches REGEX and who has a non-Copy member to use a bindgen-generated wrapper for fields. #[arg(long, value_name = "REGEX")] bindgen_wrapper_union: Vec, /// 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. #[arg(long, value_name = "REGEX")] manually_drop_union: Vec, /// Mark TYPE as hidden. #[arg(long, value_name = "TYPE")] blocklist_type: Vec, /// Mark FUNCTION as hidden. #[arg(long, value_name = "FUNCTION")] blocklist_function: Vec, /// Mark ITEM as hidden. #[arg(long, value_name = "ITEM")] blocklist_item: Vec, /// Mark FILE as hidden. #[arg(long, value_name = "FILE")] blocklist_file: Vec, /// Mark VAR as hidden. #[arg(long, value_name = "VAR")] blocklist_var: Vec, /// Avoid generating layout tests for any type. #[arg(long)] no_layout_tests: bool, /// Avoid deriving Copy on any type. #[arg(long)] no_derive_copy: bool, /// Avoid deriving Debug on any type. #[arg(long)] no_derive_debug: bool, /// Avoid deriving Default on any type. #[arg(long, hide = true)] no_derive_default: bool, /// Create a Debug implementation if it cannot be derived automatically. #[arg(long)] impl_debug: bool, /// Create a PartialEq implementation if it cannot be derived automatically. #[arg(long)] impl_partialeq: bool, /// Derive Default on any type. #[arg(long)] with_derive_default: bool, /// Derive Hash on any type. #[arg(long)] with_derive_hash: bool, /// Derive PartialEq on any type. #[arg(long)] with_derive_partialeq: bool, /// Derive PartialOrd on any type. #[arg(long)] with_derive_partialord: bool, /// Derive Eq on any type. #[arg(long)] with_derive_eq: bool, /// Derive Ord on any type. #[arg(long)] with_derive_ord: bool, /// Avoid including doc comments in the output, see: #[arg(long)] no_doc_comments: bool, /// 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(long)] no_recursive_allowlist: bool, /// Use extern crate instead of use for objc. #[arg(long)] objc_extern_crate: bool, /// Generate block signatures instead of void pointers. #[arg(long)] generate_block: bool, /// Generate string constants as `&CStr` instead of `&[u8]`. #[arg(long)] generate_cstr: bool, /// Use extern crate instead of use for block. #[arg(long)] block_extern_crate: bool, /// Do not trust the libclang-provided mangling #[arg(long)] distrust_clang_mangling: bool, /// Output bindings for builtin definitions, e.g. __builtin_va_list. #[arg(long)] builtins: bool, /// Use the given PREFIX before raw types instead of ::std::os::raw. #[arg(long, value_name = "PREFIX")] ctypes_prefix: Option, /// Use the given PREFIX for anonymous fields. #[arg(long, value_name = "PREFIX")] anon_fields_prefix: Option, /// Time the different bindgen phases and print to stderr #[arg(long)] time_phases: bool, /// Output the Clang AST for debugging purposes. #[arg(long)] emit_clang_ast: bool, /// Output our internal IR for debugging purposes. #[arg(long)] emit_ir: bool, /// Dump a graphviz dot file to PATH. #[arg(long, value_name = "PATH")] emit_ir_graphviz: Option, /// Enable support for C++ namespaces. #[arg(long)] enable_cxx_namespaces: bool, /// Disable namespacing via mangling, causing bindgen to generate names like `Baz` instead of `foo_bar_Baz` for an input name `foo::bar::Baz`. #[arg(long)] disable_name_namespacing: bool, /// 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(long)] disable_nested_struct_naming: bool, /// Disable support for native Rust unions. #[arg(long)] disable_untagged_union: bool, /// Suppress insertion of bindgen's version identifier into generated bindings. #[arg(long)] disable_header_comment: bool, /// Do not generate bindings for functions or methods. This is useful when you only care about struct layouts. #[arg(long)] ignore_functions: bool, /// Generate only given items, split by commas. Valid values are `functions`,`types`, `vars`, `methods`, `constructors` and `destructors`. #[arg(long, value_parser = parse_codegen_config)] generate: Option, /// Do not generate bindings for methods. #[arg(long)] ignore_methods: bool, /// Do not automatically convert floats to f32/f64. #[arg(long)] no_convert_floats: bool, /// Do not prepend the enum name to constant or newtype variants. #[arg(long)] no_prepend_enum_name: bool, /// Do not try to detect default include paths #[arg(long)] no_include_path_detection: bool, /// Try to fit macro constants into types smaller than u32/i32 #[arg(long)] fit_macro_constant_types: bool, /// Mark TYPE as opaque. #[arg(long, value_name = "TYPE")] opaque_type: Vec, /// Write Rust bindings to OUTPUT. #[arg(long, short, value_name = "OUTPUT")] output: Option, /// Add a raw line of Rust code at the beginning of output. #[arg(long)] raw_line: Vec, /// Add a RAW_LINE of Rust code to a given module with name MODULE_NAME. #[arg(long, number_of_values = 2, value_names = ["MODULE_NAME", "RAW_LINE"])] module_raw_line: Vec, #[arg(long, help = rust_target_help())] rust_target: Option, #[arg(long, value_name = "EDITION", help = rust_edition_help())] rust_edition: Option, /// Use types from Rust core instead of std. #[arg(long)] use_core: bool, /// Conservatively generate inline namespaces to avoid name conflicts. #[arg(long)] conservative_inline_namespaces: bool, /// Allowlist all the free-standing functions matching REGEX. Other non-allowlisted functions will not be generated. #[arg(long, value_name = "REGEX")] allowlist_function: Vec, /// Generate inline functions. #[arg(long)] generate_inline_functions: bool, /// Only generate types matching REGEX. Other non-allowlisted types will not be generated. #[arg(long, value_name = "REGEX")] allowlist_type: Vec, /// Allowlist all the free-standing variables matching REGEX. Other non-allowlisted variables will not be generated. #[arg(long, value_name = "REGEX")] allowlist_var: Vec, /// Allowlist all contents of PATH. #[arg(long, value_name = "PATH")] allowlist_file: Vec, /// Allowlist all items matching REGEX. Other non-allowlisted items will not be generated. #[arg(long, value_name = "REGEX")] allowlist_item: Vec, /// Print verbose error messages. #[arg(long)] verbose: bool, /// 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(long)] dump_preprocessed_input: bool, /// Do not record matching items in the regex sets. This disables reporting of unused items. #[arg(long)] no_record_matches: bool, /// Do not bind size_t as usize (useful on platforms where those types are incompatible). #[arg(long = "no-size_t-is-usize")] no_size_t_is_usize: bool, /// Do not format the generated bindings with rustfmt. This option is deprecated, please use /// `--formatter=none` instead. #[arg(long)] no_rustfmt_bindings: bool, /// Which FORMATTER should be used for the bindings #[arg( long, value_name = "FORMATTER", conflicts_with = "no_rustfmt_bindings" )] formatter: Option, /// The absolute PATH to the rustfmt configuration file. The configuration file will be used for formatting the bindings. This parameter sets `formatter` to `rustfmt`. #[arg(long, value_name = "PATH", conflicts_with = "no_rustfmt_bindings", value_parser=parse_rustfmt_config_path)] rustfmt_configuration_file: Option, /// Avoid deriving PartialEq for types matching REGEX. #[arg(long, value_name = "REGEX")] no_partialeq: Vec, /// Avoid deriving Copy and Clone for types matching REGEX. #[arg(long, value_name = "REGEX")] no_copy: Vec, /// Avoid deriving Debug for types matching REGEX. #[arg(long, value_name = "REGEX")] no_debug: Vec, /// Avoid deriving/implementing Default for types matching REGEX. #[arg(long, value_name = "REGEX")] no_default: Vec, /// Avoid deriving Hash for types matching REGEX. #[arg(long, value_name = "REGEX")] no_hash: Vec, /// Add `#[must_use]` annotation to types matching REGEX. #[arg(long, value_name = "REGEX")] must_use_type: Vec, /// Enables detecting unexposed attributes in functions (slow). Used to generate `#[must_use]` annotations. #[arg(long)] enable_function_attribute_detection: bool, /// Use `*const [T; size]` instead of `*const T` for C arrays #[arg(long)] use_array_pointers_in_arguments: bool, /// The NAME to be used in a #[link(wasm_import_module = ...)] statement #[arg(long, value_name = "NAME")] wasm_import_module_name: Option, /// Use dynamic loading mode with the given library NAME. #[arg(long, value_name = "NAME")] dynamic_loading: Option, /// Require successful linkage to all functions in the library. #[arg(long)] dynamic_link_require_all: bool, /// Prefix the name of exported symbols. #[arg(long)] prefix_link_name: Option, /// Makes generated bindings `pub` only for items if the items are publicly accessible in C++. #[arg(long)] respect_cxx_access_specs: bool, /// Always translate enum integer types to native Rust integer types. #[arg(long)] translate_enum_integer_types: bool, /// Generate types with C style naming. #[arg(long)] c_naming: bool, /// Always output explicit padding fields. #[arg(long)] explicit_padding: bool, /// Enables generation of vtable functions. #[arg(long)] vtable_generation: bool, /// Enables sorting of code generation in a predefined manner. #[arg(long)] sort_semantically: bool, /// Deduplicates extern blocks. #[arg(long)] merge_extern_blocks: bool, /// Overrides the ABI of functions matching REGEX. The OVERRIDE value must be of the shape REGEX=ABI where ABI can be one of C, stdcall, efiapi, fastcall, thiscall, aapcs, win64 or C-unwind<.> #[arg(long, value_name = "OVERRIDE", value_parser = parse_abi_override)] override_abi: Vec<(Abi, String)>, /// Wrap unsafe operations in unsafe blocks. #[arg(long)] wrap_unsafe_ops: bool, /// Enable fallback for clang macro parsing. #[arg(long)] clang_macro_fallback: bool, /// Set path for temporary files generated by fallback for clang macro parsing. #[arg(long)] clang_macro_fallback_build_dir: Option, /// Use DSTs to represent structures with flexible array members. #[arg(long)] flexarray_dst: bool, /// Derive custom traits on any kind of type. The CUSTOM value must be of the shape REGEX=DERIVE where DERIVE is a coma-separated list of derive macros. #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_derive)] with_derive_custom: Vec<(Vec, String)>, /// Derive custom traits on a `struct`. The CUSTOM value must be of the shape REGEX=DERIVE where DERIVE is a coma-separated list of derive macros. #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_derive)] with_derive_custom_struct: Vec<(Vec, String)>, /// Derive custom traits on an `enum. The CUSTOM value must be of the shape REGEX=DERIVE where DERIVE is a coma-separated list of derive macros. #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_derive)] with_derive_custom_enum: Vec<(Vec, String)>, /// Derive custom traits on a `union`. The CUSTOM value must be of the shape REGEX=DERIVE where DERIVE is a coma-separated list of derive macros. #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_derive)] with_derive_custom_union: Vec<(Vec, String)>, /// Add custom attributes on any kind of type. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a coma-separated list of attributes. #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_attribute)] with_attribute_custom: Vec<(Vec, String)>, /// Add custom attributes on a `struct`. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a coma-separated list of attributes. #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_attribute)] with_attribute_custom_struct: Vec<(Vec, String)>, /// Add custom attributes on an `enum. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a coma-separated list of attributes. #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_attribute)] with_attribute_custom_enum: Vec<(Vec, String)>, /// Add custom attributes on a `union`. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a coma-separated list of attributes. #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_attribute)] with_attribute_custom_union: Vec<(Vec, String)>, /// Generate wrappers for `static` and `static inline` functions. #[arg(long)] wrap_static_fns: bool, /// Sets the PATH for the source file that must be created due to the presence of `static` and /// `static inline` functions. #[arg(long, value_name = "PATH")] wrap_static_fns_path: Option, /// Sets the SUFFIX added to the extern wrapper functions generated for `static` and `static /// inline` functions. #[arg(long, value_name = "SUFFIX")] wrap_static_fns_suffix: Option, /// Set the default VISIBILITY of fields, including bitfields and accessor methods for /// bitfields. This flag is ignored if the `--respect-cxx-access-specs` flag is used. #[arg(long, value_name = "VISIBILITY")] default_visibility: Option, /// Whether to emit diagnostics or not. #[cfg(feature = "experimental")] #[arg(long, requires = "experimental")] emit_diagnostics: bool, /// Generates completions for the specified SHELL, sends them to `stdout` and exits. #[arg(long, value_name = "SHELL")] generate_shell_completions: Option, /// Enables experimental features. #[arg(long)] experimental: bool, /// Prints the version, and exits #[arg(short = 'V', long)] version: bool, /// Arguments to be passed straight through to clang. clang_args: Vec, } /// Construct a new [`Builder`](./struct.Builder.html) from command line flags. pub fn builder_from_flags( args: I, ) -> Result<(Builder, Box, bool), io::Error> where I: Iterator, { let command = BindgenCommand::parse_from(args); let BindgenCommand { header, depfile, default_enum_style, bitfield_enum, newtype_enum, newtype_global_enum, rustified_enum, rustified_non_exhaustive_enum, constified_enum, constified_enum_module, default_macro_constant_type, default_alias_style, normal_alias, new_type_alias, new_type_alias_deref, default_non_copy_union_style, bindgen_wrapper_union, manually_drop_union, blocklist_type, blocklist_function, blocklist_item, blocklist_file, blocklist_var, no_layout_tests, no_derive_copy, no_derive_debug, no_derive_default, impl_debug, impl_partialeq, with_derive_default, with_derive_hash, with_derive_partialeq, with_derive_partialord, with_derive_eq, with_derive_ord, no_doc_comments, no_recursive_allowlist, objc_extern_crate, generate_block, generate_cstr, block_extern_crate, distrust_clang_mangling, builtins, ctypes_prefix, anon_fields_prefix, time_phases, emit_clang_ast, emit_ir, emit_ir_graphviz, enable_cxx_namespaces, disable_name_namespacing, disable_nested_struct_naming, disable_untagged_union, disable_header_comment, ignore_functions, generate, ignore_methods, no_convert_floats, no_prepend_enum_name, no_include_path_detection, fit_macro_constant_types, opaque_type, output, raw_line, module_raw_line, rust_target, rust_edition, use_core, conservative_inline_namespaces, allowlist_function, generate_inline_functions, allowlist_type, allowlist_var, allowlist_file, allowlist_item, verbose, dump_preprocessed_input, no_record_matches, no_size_t_is_usize, no_rustfmt_bindings, formatter, rustfmt_configuration_file, no_partialeq, no_copy, no_debug, no_default, no_hash, must_use_type, enable_function_attribute_detection, use_array_pointers_in_arguments, wasm_import_module_name, dynamic_loading, dynamic_link_require_all, prefix_link_name, respect_cxx_access_specs, translate_enum_integer_types, c_naming, explicit_padding, vtable_generation, sort_semantically, merge_extern_blocks, override_abi, wrap_unsafe_ops, clang_macro_fallback, clang_macro_fallback_build_dir, flexarray_dst, with_derive_custom, with_derive_custom_struct, with_derive_custom_enum, with_derive_custom_union, with_attribute_custom, with_attribute_custom_struct, with_attribute_custom_enum, with_attribute_custom_union, wrap_static_fns, wrap_static_fns_path, wrap_static_fns_suffix, default_visibility, #[cfg(feature = "experimental")] emit_diagnostics, generate_shell_completions, experimental: _, version, clang_args, } = command; if let Some(shell) = generate_shell_completions { clap_complete::generate( shell, &mut BindgenCommand::command(), "bindgen", &mut io::stdout(), ); exit(0) } if version { println!( "bindgen {}", option_env!("CARGO_PKG_VERSION").unwrap_or("unknown") ); if verbose { println!("Clang: {}", crate::clang_version().full); } exit(0) } if header.is_none() { return Err(io::Error::new(io::ErrorKind::Other, "Header not found")); } let mut builder = builder(); #[derive(Debug)] struct PrefixLinkNameCallback { prefix: String, } impl ParseCallbacks for PrefixLinkNameCallback { fn generated_link_name_override( &self, item_info: ItemInfo<'_>, ) -> Option { let mut prefix = self.prefix.clone(); prefix.push_str(item_info.name); Some(prefix) } } #[derive(Debug)] struct CustomDeriveCallback { derives: Vec, kind: Option, regex_set: RegexSet, } impl ParseCallbacks for CustomDeriveCallback { fn cli_args(&self) -> Vec { let mut args = vec![]; let flag = match &self.kind { None => "--with-derive-custom", Some(TypeKind::Struct) => "--with-derive-custom-struct", Some(TypeKind::Enum) => "--with-derive-custom-enum", Some(TypeKind::Union) => "--with-derive-custom-union", }; let derives = self.derives.join(","); for item in self.regex_set.get_items() { args.extend_from_slice(&[ flag.to_owned(), format!("{item}={derives}"), ]); } args } fn add_derives(&self, info: &DeriveInfo<'_>) -> Vec { if self.kind.map_or(true, |kind| kind == info.kind) && self.regex_set.matches(info.name) { return self.derives.clone(); } vec![] } } #[derive(Debug)] struct CustomAttributeCallback { attributes: Vec, kind: Option, regex_set: RegexSet, } impl ParseCallbacks for CustomAttributeCallback { fn cli_args(&self) -> Vec { let mut args = vec![]; let flag = match &self.kind { None => "--with-attribute-custom", Some(TypeKind::Struct) => "--with-attribute-custom-struct", Some(TypeKind::Enum) => "--with-attribute-custom-enum", Some(TypeKind::Union) => "--with-attribute-custom-union", }; let attributes = self.attributes.join(","); for item in self.regex_set.get_items() { args.extend_from_slice(&[ flag.to_owned(), format!("{item}={attributes}"), ]); } args } fn add_attributes(&self, info: &AttributeInfo<'_>) -> Vec { if self.kind.map_or(true, |kind| kind == info.kind) && self.regex_set.matches(info.name) { return self.attributes.clone(); } vec![] } } /// Macro used to apply CLI arguments to a builder. /// /// This is done by passing an identifier for each argument and a function to be applied over /// the builder. For example: /// ```rust,ignore /// fn apply_arg(builder: Builder, arg_value: Value) -> Builder { /// todo!() /// } /// /// apply_args!( /// builder { /// arg => apply_arg, /// } /// ); /// ``` /// /// If the identifier of the argument is the same as an already existing builder method then /// you can omit the second part: /// ```rust,ignore /// apply_args!( /// builder { /// arg /// } /// ); /// ``` /// Which expands to the same code as: /// ```rust,ignore /// apply_args!( /// builder { /// arg => Builder::arg, /// } /// ); /// ``` macro_rules! apply_args { ($builder:ident {}) => { $builder }; ($builder:ident {$arg:ident => $function:expr, $($token:tt)*}) => { { $builder = CliArg::apply($arg, $builder, $function); apply_args!($builder {$($token)*}) } }; ($builder:ident {$arg:ident, $($token:tt)*}) => { { $builder = CliArg::apply($arg, $builder, Builder::$arg); apply_args!($builder {$($token)*}) } } } builder = apply_args!( builder { header, rust_target, rust_edition, default_enum_style, bitfield_enum, newtype_enum, newtype_global_enum, rustified_enum, rustified_non_exhaustive_enum, constified_enum, constified_enum_module, default_macro_constant_type, default_alias_style, normal_alias => Builder::type_alias, new_type_alias, new_type_alias_deref, default_non_copy_union_style, bindgen_wrapper_union, manually_drop_union, blocklist_type, blocklist_function, blocklist_item, blocklist_file, blocklist_var, builtins => |b, _| b.emit_builtins(), no_layout_tests => |b, _| b.layout_tests(false), no_derive_copy => |b, _| b.derive_copy(false), no_derive_debug => |b, _| b.derive_debug(false), impl_debug, impl_partialeq, with_derive_default => Builder::derive_default, with_derive_hash => Builder::derive_hash, with_derive_partialeq => Builder::derive_partialeq, with_derive_partialord => Builder::derive_partialord, with_derive_eq => Builder::derive_eq, with_derive_ord => Builder::derive_ord, no_derive_default => |b, _| b.derive_default(false), no_prepend_enum_name => |b, _| b.prepend_enum_name(false), no_include_path_detection => |b, _| b.detect_include_paths(false), fit_macro_constant_types => Builder::fit_macro_constants, time_phases, use_array_pointers_in_arguments => Builder::array_pointers_in_arguments, wasm_import_module_name, ctypes_prefix, anon_fields_prefix, generate => Builder::with_codegen_config, emit_clang_ast => |b, _| b.emit_clang_ast(), emit_ir => |b, _| b.emit_ir(), emit_ir_graphviz, enable_cxx_namespaces => |b, _| b.enable_cxx_namespaces(), enable_function_attribute_detection => |b, _| b.enable_function_attribute_detection(), disable_name_namespacing => |b, _| b.disable_name_namespacing(), disable_nested_struct_naming => |b, _| b.disable_nested_struct_naming(), disable_untagged_union => |b, _| b.disable_untagged_union(), disable_header_comment => |b, _| b.disable_header_comment(), ignore_functions => |b, _| b.ignore_functions(), ignore_methods => |b, _| b.ignore_methods(), no_convert_floats => |b, _| b.no_convert_floats(), no_doc_comments => |b, _| b.generate_comments(false), no_recursive_allowlist => |b, _| b.allowlist_recursively(false), objc_extern_crate, generate_block, generate_cstr, block_extern_crate, opaque_type, raw_line, use_core => |b, _| b.use_core(), distrust_clang_mangling => |b, _| b.trust_clang_mangling(false), conservative_inline_namespaces => |b, _| b.conservative_inline_namespaces(), generate_inline_functions, allowlist_function, allowlist_type, allowlist_var, allowlist_file, allowlist_item, clang_args => Builder::clang_arg, no_record_matches => |b, _| b.record_matches(false), no_size_t_is_usize => |b, _| b.size_t_is_usize(false), no_rustfmt_bindings => |b, _| b.formatter(Formatter::None), formatter, no_partialeq, no_copy, no_debug, no_default, no_hash, must_use_type, dynamic_loading => Builder::dynamic_library_name, dynamic_link_require_all, prefix_link_name => |b, prefix| b.parse_callbacks(Box::new(PrefixLinkNameCallback { prefix })), respect_cxx_access_specs, translate_enum_integer_types, c_naming, explicit_padding, vtable_generation, sort_semantically, merge_extern_blocks, override_abi => |b, (abi, regex)| b.override_abi(abi, regex), wrap_unsafe_ops, clang_macro_fallback => |b, _| b.clang_macro_fallback(), clang_macro_fallback_build_dir, flexarray_dst, wrap_static_fns, wrap_static_fns_path, wrap_static_fns_suffix, default_visibility, } ); let mut values = module_raw_line.into_iter(); while let Some(module) = values.next() { let line = values.next().unwrap(); builder = builder.module_raw_line(module, line); } let output = if let Some(path) = &output { let file = File::create(path)?; if let Some(depfile) = depfile { builder = builder.depfile(path, depfile); } Box::new(io::BufWriter::new(file)) as Box } else { if let Some(depfile) = depfile { builder = builder.depfile("-", depfile); } Box::new(io::BufWriter::new(io::stdout())) as Box }; if dump_preprocessed_input { builder.dump_preprocessed_input()?; } if let Some(path) = rustfmt_configuration_file { builder = builder.rustfmt_configuration_file(Some(path)); } for (custom_derives, kind, _name) in [ (with_derive_custom, None, "--with-derive-custom"), ( with_derive_custom_struct, Some(TypeKind::Struct), "--with-derive-custom-struct", ), ( with_derive_custom_enum, Some(TypeKind::Enum), "--with-derive-custom-enum", ), ( with_derive_custom_union, Some(TypeKind::Union), "--with-derive-custom-union", ), ] { #[cfg(feature = "experimental")] let name = emit_diagnostics.then_some(_name); for (derives, regex) in custom_derives { let mut regex_set = RegexSet::default(); regex_set.insert(regex); #[cfg(feature = "experimental")] regex_set.build_with_diagnostics(false, name); #[cfg(not(feature = "experimental"))] regex_set.build(false); builder = builder.parse_callbacks(Box::new(CustomDeriveCallback { derives, kind, regex_set, })); } } for (custom_attributes, kind, _name) in [ (with_attribute_custom, None, "--with-attribute-custom"), ( with_attribute_custom_struct, Some(TypeKind::Struct), "--with-attribute-custom-struct", ), ( with_attribute_custom_enum, Some(TypeKind::Enum), "--with-attribute-custom-enum", ), ( with_attribute_custom_union, Some(TypeKind::Union), "--with-attribute-custom-union", ), ] { #[cfg(feature = "experimental")] let name = emit_diagnostics.then_some(_name); for (attributes, regex) in custom_attributes { let mut regex_set = RegexSet::default(); regex_set.insert(regex); #[cfg(feature = "experimental")] regex_set.build_with_diagnostics(false, name); #[cfg(not(feature = "experimental"))] regex_set.build(false); builder = builder.parse_callbacks(Box::new(CustomAttributeCallback { attributes, kind, regex_set, })); } } #[cfg(feature = "experimental")] if emit_diagnostics { builder = builder.emit_diagnostics(); } Ok((builder, output, verbose)) } /// Trait for CLI arguments that can be applied to a [`Builder`]. trait CliArg { /// The value of this argument. type Value; /// Apply the current argument to the passed [`Builder`]. fn apply( self, builder: Builder, f: impl Fn(Builder, Self::Value) -> Builder, ) -> Builder; } /// Boolean arguments are applied when they evaluate to `true`. impl CliArg for bool { type Value = bool; fn apply( self, mut builder: Builder, f: impl Fn(Builder, Self::Value) -> Builder, ) -> Builder { if self { builder = f(builder, self); } builder } } /// Optional arguments are applied when they are `Some`. impl CliArg for Option { type Value = T; fn apply( self, mut builder: Builder, f: impl Fn(Builder, Self::Value) -> Builder, ) -> Builder { if let Some(value) = self { builder = f(builder, value); } builder } } /// Multiple valued arguments are applied once for each value. impl CliArg for Vec { type Value = T; fn apply( self, mut builder: Builder, f: impl Fn(Builder, Self::Value) -> Builder, ) -> Builder { for value in self { builder = f(builder, value); } builder } } bindgen-0.71.1/options/helpers.rs000064400000000000000000000026001046102023000150210ustar 00000000000000/// Helper function that appends extra documentation to [`crate::Builder`] methods that support regular /// expressions in their input. macro_rules! regex_option { ($(#[$attrs:meta])* pub fn $($tokens:tt)*) => { $(#[$attrs])* /// /// Regular expressions are supported. Check the [regular expression /// arguments](./struct.Builder.html#regular-expression-arguments) section and the /// [regex](https://docs.rs/regex) crate documentation for further information. pub fn $($tokens)* }; } /// Helper macro to set the default value of each option. /// /// This macro is an internal implementation detail of the `options` macro and should not be used /// directly. macro_rules! default { () => { Default::default() }; ($expr:expr) => { $expr }; } /// Helper macro to set the conversion to CLI arguments for each option. /// /// This macro is an internal implementation detail of the `options` macro and should not be used /// directly. macro_rules! as_args { ($flag:literal) => { |field, args| AsArgs::as_args(field, args, $flag) }; ($expr:expr) => { $expr }; } /// Helper function to ignore an option when converting it into CLI arguments. /// /// This function is only used inside `options` and should not be used in other contexts. pub(super) fn ignore(_: &T, _: &mut Vec) {} bindgen-0.71.1/options/mod.rs000064400000000000000000002546041046102023000141530ustar 00000000000000//! Declarations and setter methods for `bindgen` options. //! //! The main entry point of this module is the `options` macro. #[macro_use] mod helpers; mod as_args; #[cfg(feature = "__cli")] pub(crate) mod cli; use crate::callbacks::ParseCallbacks; use crate::codegen::{ AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle, }; use crate::deps::DepfileSpec; use crate::features::{RustEdition, RustFeatures, RustTarget}; use crate::regex_set::RegexSet; use crate::Abi; use crate::Builder; use crate::CodegenConfig; use crate::FieldVisibilityKind; use crate::Formatter; use crate::HashMap; use crate::DEFAULT_ANON_FIELDS_PREFIX; use std::env; use std::path::{Path, PathBuf}; use std::rc::Rc; use as_args::AsArgs; use helpers::ignore; /// Macro used to generate the [`BindgenOptions`] type and the [`Builder`] setter methods for each /// one of the fields of `BindgenOptions`. /// /// The input format of this macro resembles a `struct` pattern. Each field of the `BindgenOptions` /// type is declared by adding the name of the field and its type using the `name: type` syntax and /// a block of code with the following items: /// /// - `default`: The default value for the field. If this item is omitted, `Default::default()` is /// used instead, meaning that the type of the field must implement `Default`. /// - `methods`: A block of code containing methods for the `Builder` type. These methods should be /// related to the field being declared. /// - `as_args`: This item declares how the field should be converted into a valid CLI argument for /// `bindgen` and is used in the [`Builder::command_line_flags`] method which is used to do a /// roundtrip test of the CLI args in the `bindgen-test` crate. This item can take one of the /// following: /// - A string literal with the flag if the type of the field implements the [`AsArgs`] trait. /// - A closure with the signature `|field, args: &mut Vec| -> ()` that pushes arguments /// into the `args` buffer based on the value of the field. This is used if the field does not /// implement `AsArgs` or if the implementation of the trait is not logically correct for the /// option and a custom behavior must be taken into account. /// - The `ignore` literal, which does not emit any CLI arguments for this field. This is useful /// if the field cannot be used from the `bindgen` CLI. /// /// As an example, this would be the declaration of a `bool` field called `be_fun` whose default /// value is `false` (the `Default` value for `bool`): /// ```rust,ignore /// be_fun: bool { /// methods: { /// /// Ask `bindgen` to be fun. This option is disabled by default. /// fn be_fun(mut self) -> Self { /// self.options.be_fun = true; /// self /// } /// }, /// as_args: "--be-fun", /// } /// ``` /// /// However, we could also set the `be_fun` field to `true` by default and use a `--not-fun` flag /// instead. This means that we have to add the `default` item and use a closure in the `as_args` /// item: /// ```rust,ignore /// be_fun: bool { /// default: true, /// methods: { /// /// Ask `bindgen` to not be fun. `bindgen` is fun by default. /// fn not_fun(mut self) -> Self { /// self.options.be_fun = false; /// self /// } /// }, /// as_args: |be_fun, args| (!be_fun).as_args(args, "--not-fun"), /// } /// ``` /// More complex examples can be found in the sole invocation of this macro. macro_rules! options { ($( $(#[doc = $docs:literal])+ $field:ident: $ty:ty { $(default: $default:expr,)? methods: {$($methods_tokens:tt)*}$(,)? as_args: $as_args:expr$(,)? }$(,)? )*) => { #[derive(Debug, Clone)] pub(crate) struct BindgenOptions { $($(#[doc = $docs])* pub(crate) $field: $ty,)* } impl Default for BindgenOptions { fn default() -> Self { Self { $($field: default!($($default)*),)* } } } impl Builder { /// Generates the command line flags used to create this [`Builder`]. pub fn command_line_flags(&self) -> Vec { let mut args = vec![]; let headers = match self.options.input_headers.split_last() { Some((header, headers)) => { // The last input header is passed as an argument in the first position. args.push(header.clone().into()); headers }, None => &[] }; $({ let func: fn(&$ty, &mut Vec) = as_args!($as_args); func(&self.options.$field, &mut args); })* // Add the `--experimental` flag if `bindgen` is built with the `experimental` // feature. if cfg!(feature = "experimental") { args.push("--experimental".to_owned()); } // Add all the clang arguments. args.push("--".to_owned()); if !self.options.clang_args.is_empty() { args.extend(self.options.clang_args.iter().map(|s| s.clone().into())); } // We need to pass all but the last header via the `-include` clang argument. for header in headers { args.push("-include".to_owned()); args.push(header.clone().into()); } args } $($($methods_tokens)*)* } }; } options! { /// Types that have been blocklisted and should not appear anywhere in the generated code. blocklisted_types: RegexSet { methods: { regex_option! { /// Do not generate any bindings for the given type. /// /// This option is not recursive, meaning that it will only block types whose names /// explicitly match the argument of this method. pub fn blocklist_type>(mut self, arg: T) -> Builder { self.options.blocklisted_types.insert(arg); self } } }, as_args: "--blocklist-type", }, /// Functions that have been blocklisted and should not appear in the generated code. blocklisted_functions: RegexSet { methods: { regex_option! { /// Do not generate any bindings for the given function. /// /// This option is not recursive, meaning that it will only block functions whose /// names explicitly match the argument of this method. pub fn blocklist_function>(mut self, arg: T) -> Builder { self.options.blocklisted_functions.insert(arg); self } } }, as_args: "--blocklist-function", }, /// Items that have been blocklisted and should not appear in the generated code. blocklisted_items: RegexSet { methods: { regex_option! { /// Do not generate any bindings for the given item, regardless of whether it is a /// type, function, module, etc. /// /// This option is not recursive, meaning that it will only block items whose names /// explicitly match the argument of this method. pub fn blocklist_item>(mut self, arg: T) -> Builder { self.options.blocklisted_items.insert(arg); self } } }, as_args: "--blocklist-item", }, /// Files whose contents should be blocklisted and should not appear in the generated code. blocklisted_files: RegexSet { methods: { regex_option! { /// Do not generate any bindings for the contents of the given file, regardless of /// whether the contents of the file are types, functions, modules, etc. /// /// This option is not recursive, meaning that it will only block files whose names /// explicitly match the argument of this method. /// /// This method will use the argument to match the complete path of the file /// instead of a section of it. pub fn blocklist_file>(mut self, arg: T) -> Builder { self.options.blocklisted_files.insert(arg); self } } }, as_args: "--blocklist-file", }, /// Variables that have been blocklisted and should not appear in the generated code. blocklisted_vars: RegexSet { methods: { regex_option! { /// Do not generate any bindings for the given variable. /// /// This option is not recursive, meaning that it will only block variables whose /// names explicitly match the argument of this method. pub fn blocklist_var>(mut self, arg: T) -> Builder { self.options.blocklisted_vars.insert(arg); self } } }, as_args: "--blocklist-var", }, /// Types that should be treated as opaque structures in the generated code. opaque_types: RegexSet { methods: { regex_option! { /// Treat the given type as opaque in the generated bindings. /// /// Opaque in this context means that none of the generated bindings will contain /// information about the inner representation of the type and the type itself will /// be represented as a chunk of bytes with the alignment and size of the type. pub fn opaque_type>(mut self, arg: T) -> Builder { self.options.opaque_types.insert(arg); self } } }, as_args: "--opaque-type", }, /// The explicit `rustfmt` path. rustfmt_path: Option { methods: { /// Set an explicit path to the `rustfmt` binary. /// /// This option only comes into effect if `rustfmt` is set to be the formatter used by /// `bindgen`. Check the documentation of the [`Builder::formatter`] method for more /// information. pub fn with_rustfmt>(mut self, path: P) -> Self { self.options.rustfmt_path = Some(path.into()); self } }, // This option cannot be set from the CLI. as_args: ignore, }, /// The path to which we should write a Makefile-syntax depfile (if any). depfile: Option { methods: { /// Add a depfile output which will be written alongside the generated bindings. pub fn depfile, D: Into>( mut self, output_module: H, depfile: D, ) -> Builder { self.options.depfile = Some(DepfileSpec { output_module: output_module.into(), depfile_path: depfile.into(), }); self } }, as_args: |depfile, args| { if let Some(depfile) = depfile { args.push("--depfile".into()); args.push(depfile.depfile_path.display().to_string()); } }, }, /// Types that have been allowlisted and should appear in the generated code. allowlisted_types: RegexSet { methods: { regex_option! { /// Generate bindings for the given type. /// /// This option is transitive by default. Check the documentation of the /// [`Builder::allowlist_recursively`] method for further information. pub fn allowlist_type>(mut self, arg: T) -> Builder { self.options.allowlisted_types.insert(arg); self } } }, as_args: "--allowlist-type", }, /// Functions that have been allowlisted and should appear in the generated code. allowlisted_functions: RegexSet { methods: { regex_option! { /// Generate bindings for the given function. /// /// This option is transitive by default. Check the documentation of the /// [`Builder::allowlist_recursively`] method for further information. pub fn allowlist_function>(mut self, arg: T) -> Builder { self.options.allowlisted_functions.insert(arg); self } } }, as_args: "--allowlist-function", }, /// Variables that have been allowlisted and should appear in the generated code. allowlisted_vars: RegexSet { methods: { regex_option! { /// Generate bindings for the given variable. /// /// This option is transitive by default. Check the documentation of the /// [`Builder::allowlist_recursively`] method for further information. pub fn allowlist_var>(mut self, arg: T) -> Builder { self.options.allowlisted_vars.insert(arg); self } } }, as_args: "--allowlist-var", }, /// Files whose contents have been allowlisted and should appear in the generated code. allowlisted_files: RegexSet { methods: { regex_option! { /// Generate bindings for the content of the given file. /// /// This option is transitive by default. Check the documentation of the /// [`Builder::allowlist_recursively`] method for further information. /// /// This method will use the argument to match the complete path of the file /// instead of a section of it. pub fn allowlist_file>(mut self, arg: T) -> Builder { self.options.allowlisted_files.insert(arg); self } } }, as_args: "--allowlist-file", }, /// Items that have been allowlisted and should appear in the generated code. allowlisted_items: RegexSet { methods: { regex_option! { /// Generate bindings for the given item, regardless of whether it is a type, /// function, module, etc. /// /// This option is transitive by default. Check the documentation of the /// [`Builder::allowlist_recursively`] method for further information. pub fn allowlist_item>(mut self, arg: T) -> Builder { self.options.allowlisted_items.insert(arg); self } } }, as_args: "--allowlist-item", }, /// The default style of for generated `enum`s. default_enum_style: EnumVariation { methods: { /// Set the default style for generated `enum`s. /// /// If this method is not called, the [`EnumVariation::Consts`] style will be used by /// default. /// /// To set the style for individual `enum`s, use [`Builder::bitfield_enum`], /// [`Builder::newtype_enum`], [`Builder::newtype_global_enum`], /// [`Builder::rustified_enum`], [`Builder::rustified_non_exhaustive_enum`], /// [`Builder::constified_enum_module`] or [`Builder::constified_enum`]. pub fn default_enum_style( mut self, arg: EnumVariation, ) -> Builder { self.options.default_enum_style = arg; self } }, as_args: |variation, args| { if *variation != Default::default() { args.push("--default-enum-style".to_owned()); args.push(variation.to_string()); } }, }, /// `enum`s marked as bitfield-like. This is, newtypes with bitwise operations. bitfield_enums: RegexSet { methods: { regex_option! { /// Mark the given `enum` as being bitfield-like. /// /// This is similar to the [`Builder::newtype_enum`] style, but with the bitwise /// operators implemented. pub fn bitfield_enum>(mut self, arg: T) -> Builder { self.options.bitfield_enums.insert(arg); self } } }, as_args: "--bitfield-enum", }, /// `enum`s marked as newtypes. newtype_enums: RegexSet { methods: { regex_option! { /// Mark the given `enum` as a newtype. /// /// This means that an integer newtype will be declared to represent the `enum` /// type and its variants will be represented as constants inside of this type's /// `impl` block. pub fn newtype_enum>(mut self, arg: T) -> Builder { self.options.newtype_enums.insert(arg); self } } }, as_args: "--newtype-enum", }, /// `enum`s marked as global newtypes . newtype_global_enums: RegexSet { methods: { regex_option! { /// Mark the given `enum` as a global newtype. /// /// This is similar to the [`Builder::newtype_enum`] style, but the constants for /// each variant are free constants instead of being declared inside an `impl` /// block for the newtype. pub fn newtype_global_enum>(mut self, arg: T) -> Builder { self.options.newtype_global_enums.insert(arg); self } } }, as_args: "--newtype-global-enum", }, /// `enum`s marked as Rust `enum`s. rustified_enums: RegexSet { methods: { regex_option! { /// Mark the given `enum` as a Rust `enum`. /// /// This means that each variant of the `enum` will be represented as a Rust `enum` /// variant. /// /// **Use this with caution**, creating an instance of a Rust `enum` with an /// invalid value will cause undefined behaviour. To avoid this, use the /// [`Builder::newtype_enum`] style instead. pub fn rustified_enum>(mut self, arg: T) -> Builder { self.options.rustified_enums.insert(arg); self } } }, as_args: "--rustified-enum", }, /// `enum`s marked as non-exhaustive Rust `enum`s. rustified_non_exhaustive_enums: RegexSet { methods: { regex_option! { /// Mark the given `enum` as a non-exhaustive Rust `enum`. /// /// This is similar to the [`Builder::rustified_enum`] style, but the `enum` is /// tagged with the `#[non_exhaustive]` attribute. pub fn rustified_non_exhaustive_enum>(mut self, arg: T) -> Builder { self.options.rustified_non_exhaustive_enums.insert(arg); self } } }, as_args: "--rustified-non-exhaustive-enums", }, /// `enum`s marked as modules of constants. constified_enum_modules: RegexSet { methods: { regex_option! { /// Mark the given `enum` as a module with a set of integer constants. pub fn constified_enum_module>(mut self, arg: T) -> Builder { self.options.constified_enum_modules.insert(arg); self } } }, as_args: "--constified-enum-module", }, /// `enum`s marked as a set of constants. constified_enums: RegexSet { methods: { regex_option! { /// Mark the given `enum` as a set of integer constants. /// /// This is similar to the [`Builder::constified_enum_module`] style, but the /// constants are generated in the current module instead of in a new module. pub fn constified_enum>(mut self, arg: T) -> Builder { self.options.constified_enums.insert(arg); self } } }, as_args: "--constified-enum", }, /// The default type signedness for C macro constants. default_macro_constant_type: MacroTypeVariation { methods: { /// Set the default type signedness to be used for macro constants. /// /// If this method is not called, [`MacroTypeVariation::Unsigned`] is used by default. /// /// To set the type for individual macro constants, use the /// [`ParseCallbacks::int_macro`] method. pub fn default_macro_constant_type(mut self, arg: MacroTypeVariation) -> Builder { self.options.default_macro_constant_type = arg; self } }, as_args: |variation, args| { if *variation != Default::default() { args.push("--default-macro-constant-type".to_owned()); args.push(variation.to_string()); } }, }, /// The default style of code generation for `typedef`s. default_alias_style: AliasVariation { methods: { /// Set the default style of code generation for `typedef`s. /// /// If this method is not called, the [`AliasVariation::TypeAlias`] style is used by /// default. /// /// To set the style for individual `typedefs`s, use [`Builder::type_alias`], /// [`Builder::new_type_alias`] or [`Builder::new_type_alias_deref`]. pub fn default_alias_style( mut self, arg: AliasVariation, ) -> Builder { self.options.default_alias_style = arg; self } }, as_args: |variation, args| { if *variation != Default::default() { args.push("--default-alias-style".to_owned()); args.push(variation.to_string()); } }, }, /// `typedef` patterns that will use regular type aliasing. type_alias: RegexSet { methods: { regex_option! { /// Mark the given `typedef` as a regular Rust `type` alias. /// /// This is the default behavior, meaning that this method only comes into effect /// if a style different from [`AliasVariation::TypeAlias`] was passed to the /// [`Builder::default_alias_style`] method. pub fn type_alias>(mut self, arg: T) -> Builder { self.options.type_alias.insert(arg); self } } }, as_args: "--type-alias", }, /// `typedef` patterns that will be aliased by creating a newtype. new_type_alias: RegexSet { methods: { regex_option! { /// Mark the given `typedef` as a Rust newtype by having the aliased /// type be wrapped in a `struct` with `#[repr(transparent)]`. /// /// This method can be used to enforce stricter type checking. pub fn new_type_alias>(mut self, arg: T) -> Builder { self.options.new_type_alias.insert(arg); self } } }, as_args: "--new-type-alias", }, /// `typedef` patterns that will be wrapped in a newtype implementing `Deref` and `DerefMut`. new_type_alias_deref: RegexSet { methods: { regex_option! { /// Mark the given `typedef` to be generated as a newtype that can be dereferenced. /// /// This is similar to the [`Builder::new_type_alias`] style, but the newtype /// implements `Deref` and `DerefMut` with the aliased type as a target. pub fn new_type_alias_deref>(mut self, arg: T) -> Builder { self.options.new_type_alias_deref.insert(arg); self } } }, as_args: "--new-type-alias-deref", }, /// The default style of code to generate for `union`s containing non-`Copy` members. default_non_copy_union_style: NonCopyUnionStyle { methods: { /// Set the default style of code to generate for `union`s with non-`Copy` members. /// /// If this method is not called, the [`NonCopyUnionStyle::BindgenWrapper`] style is /// used by default. /// /// To set the style for individual `union`s, use [`Builder::bindgen_wrapper_union`] or /// [`Builder::manually_drop_union`]. pub fn default_non_copy_union_style(mut self, arg: NonCopyUnionStyle) -> Self { self.options.default_non_copy_union_style = arg; self } }, as_args: |style, args| { if *style != Default::default() { args.push("--default-non-copy-union-style".to_owned()); args.push(style.to_string()); } }, }, /// The patterns marking non-`Copy` `union`s as using the `bindgen` generated wrapper. bindgen_wrapper_union: RegexSet { methods: { regex_option! { /// Mark the given `union` to use a `bindgen`-generated wrapper for its members if at /// least one them is not `Copy`. /// /// This is the default behavior, meaning that this method only comes into effect /// if a style different from [`NonCopyUnionStyle::BindgenWrapper`] was passed to /// the [`Builder::default_non_copy_union_style`] method. pub fn bindgen_wrapper_union>(mut self, arg: T) -> Self { self.options.bindgen_wrapper_union.insert(arg); self } } }, as_args: "--bindgen-wrapper-union", }, /// The patterns marking non-`Copy` `union`s as using the `ManuallyDrop` wrapper. manually_drop_union: RegexSet { methods: { regex_option! { /// Mark the given `union` to use [`::core::mem::ManuallyDrop`] for its members if /// at least one of them is not `Copy`. /// /// The `ManuallyDrop` type was stabilized in Rust 1.20.0, do not use this option /// if your target version is lower than this. pub fn manually_drop_union>(mut self, arg: T) -> Self { self.options.manually_drop_union.insert(arg); self } } }, as_args: "--manually-drop-union", }, /// Whether we should generate built-in definitions. builtins: bool { methods: { /// Generate Rust bindings for built-in definitions (for example `__builtin_va_list`). /// /// Bindings for built-in definitions are not emitted by default. pub fn emit_builtins(mut self) -> Builder { self.options.builtins = true; self } }, as_args: "--builtins", }, /// Whether we should dump the Clang AST for debugging purposes. emit_ast: bool { methods: { /// Emit the Clang AST to `stdout` for debugging purposes. /// /// The Clang AST is not emitted by default. pub fn emit_clang_ast(mut self) -> Builder { self.options.emit_ast = true; self } }, as_args: "--emit-clang-ast", }, /// Whether we should dump our IR for debugging purposes. emit_ir: bool { methods: { /// Emit the `bindgen` internal representation to `stdout` for debugging purposes. /// /// This internal representation is not emitted by default. pub fn emit_ir(mut self) -> Builder { self.options.emit_ir = true; self } }, as_args: "--emit-ir", }, /// Output path for the `graphviz` DOT file. emit_ir_graphviz: Option { methods: { /// Set the path for the file where the`bindgen` internal representation will be /// emitted as a graph using the `graphviz` DOT language. /// /// This graph representation is not emitted by default. pub fn emit_ir_graphviz>(mut self, path: T) -> Builder { let path = path.into(); self.options.emit_ir_graphviz = Some(path); self } }, as_args: "--emit-ir-graphviz", }, /// Whether we should emulate C++ namespaces with Rust modules. enable_cxx_namespaces: bool { methods: { /// Emulate C++ namespaces using Rust modules in the generated bindings. /// /// C++ namespaces are not emulated by default. pub fn enable_cxx_namespaces(mut self) -> Builder { self.options.enable_cxx_namespaces = true; self } }, as_args: "--enable-cxx-namespaces", }, /// Whether we should try to find unexposed attributes in functions. enable_function_attribute_detection: bool { methods: { /// Enable detecting function attributes on C functions. /// /// This enables the following features: /// - Add `#[must_use]` attributes to Rust items whose C counterparts are marked as so. /// This feature also requires that the Rust target version supports the attribute. /// - Set `!` as the return type for Rust functions whose C counterparts are marked as /// diverging. /// /// This option can be quite slow in some cases (check [#1465]), so it is disabled by /// default. /// /// [#1465]: https://github.com/rust-lang/rust-bindgen/issues/1465 pub fn enable_function_attribute_detection(mut self) -> Self { self.options.enable_function_attribute_detection = true; self } }, as_args: "--enable-function-attribute-detection", }, /// Whether we should avoid mangling names with namespaces. disable_name_namespacing: bool { methods: { /// 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 does not change the names used for allowlisting and blocklisting, /// which should still be mangled with the namespaces. Additionally, this option may /// cause `bindgen` to generate duplicate names. pub fn disable_name_namespacing(mut self) -> Builder { self.options.disable_name_namespacing = true; self } }, as_args: "--disable-name-namespacing", }, /// Whether we should avoid generating nested `struct` names. disable_nested_struct_naming: bool { methods: { /// Disable nested `struct` naming. /// /// The following `struct`s have different names for C and C++. In C, they are visible /// as `foo` and `bar`. In C++, they are visible as `foo` and `foo::bar`. /// /// ```c /// struct foo { /// struct bar { /// } b; /// }; /// ``` /// /// `bindgen` tries to avoid duplicate names by default, so it follows the C++ naming /// convention and it generates `foo` and `foo_bar` instead of just `foo` and `bar`. /// /// This method disables this behavior and it is indented to be used only for headers /// that were written in C. pub fn disable_nested_struct_naming(mut self) -> Builder { self.options.disable_nested_struct_naming = true; self } }, as_args: "--disable-nested-struct-naming", }, /// Whether we should avoid embedding version identifiers into source code. disable_header_comment: bool { methods: { /// Do not insert the `bindgen` version identifier into the generated bindings. /// /// This identifier is inserted by default. pub fn disable_header_comment(mut self) -> Self { self.options.disable_header_comment = true; self } }, as_args: "--disable-header-comment", }, /// Whether we should generate layout tests for generated `struct`s. layout_tests: bool { default: true, methods: { /// Set whether layout tests should be generated. /// /// Layout tests are generated by default. pub fn layout_tests(mut self, doit: bool) -> Self { self.options.layout_tests = doit; self } }, as_args: |value, args| (!value).as_args(args, "--no-layout-tests"), }, /// Whether we should implement `Debug` for types that cannot derive it. impl_debug: bool { methods: { /// Set whether `Debug` should be implemented for types that cannot derive it. /// /// This option is disabled by default. pub fn impl_debug(mut self, doit: bool) -> Self { self.options.impl_debug = doit; self } }, as_args: "--impl-debug", }, /// Whether we should implement `PartialEq` types that cannot derive it. impl_partialeq: bool { methods: { /// Set whether `PartialEq` should be implemented for types that cannot derive it. /// /// This option is disabled by default. pub fn impl_partialeq(mut self, doit: bool) -> Self { self.options.impl_partialeq = doit; self } }, as_args: "--impl-partialeq", }, /// Whether we should derive `Copy` when possible. derive_copy: bool { default: true, methods: { /// Set whether the `Copy` trait should be derived when possible. /// /// `Copy` is derived by default. pub fn derive_copy(mut self, doit: bool) -> Self { self.options.derive_copy = doit; self } }, as_args: |value, args| (!value).as_args(args, "--no-derive-copy"), }, /// Whether we should derive `Debug` when possible. derive_debug: bool { default: true, methods: { /// Set whether the `Debug` trait should be derived when possible. /// /// The [`Builder::impl_debug`] method can be used to implement `Debug` for types that /// cannot derive it. /// /// `Debug` is derived by default. pub fn derive_debug(mut self, doit: bool) -> Self { self.options.derive_debug = doit; self } }, as_args: |value, args| (!value).as_args(args, "--no-derive-debug"), }, /// Whether we should derive `Default` when possible. derive_default: bool { methods: { /// Set whether the `Default` trait should be derived when possible. /// /// `Default` is not derived by default. pub fn derive_default(mut self, doit: bool) -> Self { self.options.derive_default = doit; self } }, as_args: |&value, args| { let arg = if value { "--with-derive-default" } else { "--no-derive-default" }; args.push(arg.to_owned()); }, }, /// Whether we should derive `Hash` when possible. derive_hash: bool { methods: { /// Set whether the `Hash` trait should be derived when possible. /// /// `Hash` is not derived by default. pub fn derive_hash(mut self, doit: bool) -> Self { self.options.derive_hash = doit; self } }, as_args: "--with-derive-hash", }, /// Whether we should derive `PartialOrd` when possible. derive_partialord: bool { methods: { /// Set whether the `PartialOrd` trait should be derived when possible. /// /// Take into account that `Ord` cannot be derived for a type that does not implement /// `PartialOrd`. For this reason, setting this method to `false` also sets /// automatically [`Builder::derive_ord`] to `false`. /// /// `PartialOrd` is not derived by default. pub fn derive_partialord(mut self, doit: bool) -> Self { self.options.derive_partialord = doit; if !doit { self.options.derive_ord = false; } self } }, as_args: "--with-derive-partialord", }, /// Whether we should derive `Ord` when possible. derive_ord: bool { methods: { /// Set whether the `Ord` trait should be derived when possible. /// /// Take into account that `Ord` cannot be derived for a type that does not implement /// `PartialOrd`. For this reason, the value set with this method will also be set /// automatically for [`Builder::derive_partialord`]. /// /// `Ord` is not derived by default. pub fn derive_ord(mut self, doit: bool) -> Self { self.options.derive_ord = doit; self.options.derive_partialord = doit; self } }, as_args: "--with-derive-ord", }, /// Whether we should derive `PartialEq` when possible. derive_partialeq: bool { methods: { /// Set whether the `PartialEq` trait should be derived when possible. /// /// Take into account that `Eq` cannot be derived for a type that does not implement /// `PartialEq`. For this reason, setting this method to `false` also sets /// automatically [`Builder::derive_eq`] to `false`. /// /// The [`Builder::impl_partialeq`] method can be used to implement `PartialEq` for /// types that cannot derive it. /// /// `PartialEq` is not derived by default. pub fn derive_partialeq(mut self, doit: bool) -> Self { self.options.derive_partialeq = doit; if !doit { self.options.derive_eq = false; } self } }, as_args: "--with-derive-partialeq", }, /// Whether we should derive `Eq` when possible. derive_eq: bool { methods: { /// Set whether the `Eq` trait should be derived when possible. /// /// Take into account that `Eq` cannot be derived for a type that does not implement /// `PartialEq`. For this reason, the value set with this method will also be set /// automatically for [`Builder::derive_partialeq`]. /// /// `Eq` is not derived by default. pub fn derive_eq(mut self, doit: bool) -> Self { self.options.derive_eq = doit; if doit { self.options.derive_partialeq = doit; } self } }, as_args: "--with-derive-eq", }, /// Whether we should use `core` instead of `std`. /// /// If this option is enabled and the Rust target version is greater than 1.64, the prefix for /// C platform-specific types will be `::core::ffi` instead of `::core::os::raw`. use_core: bool { methods: { /// Use `core` instead of `std` in the generated bindings. /// /// `std` is used by default. pub fn use_core(mut self) -> Builder { self.options.use_core = true; self } }, as_args: "--use-core", }, /// An optional prefix for the C platform-specific types. ctypes_prefix: Option { methods: { /// Use the given prefix for the C platform-specific types instead of `::std::os::raw`. /// /// Alternatively, the [`Builder::use_core`] method can be used to set the prefix to /// `::core::ffi` or `::core::os::raw`. pub fn ctypes_prefix>(mut self, prefix: T) -> Builder { self.options.ctypes_prefix = Some(prefix.into()); self } }, as_args: "--ctypes-prefix", }, /// The prefix for anonymous fields. anon_fields_prefix: String { default: DEFAULT_ANON_FIELDS_PREFIX.into(), methods: { /// Use the given prefix for the anonymous fields. /// /// An anonymous field, is a field of a C/C++ type that does not have a name. For /// example, in the following C code: /// ```c /// struct integer { /// struct { /// int inner; /// }; /// } /// ``` /// /// The only field of the `integer` `struct` is an anonymous field and its Rust /// representation will be named using this prefix followed by an integer identifier. /// /// The default prefix is `__bindgen_anon_`. pub fn anon_fields_prefix>(mut self, prefix: T) -> Builder { self.options.anon_fields_prefix = prefix.into(); self } }, as_args: |prefix, args| { if prefix != DEFAULT_ANON_FIELDS_PREFIX { args.push("--anon-fields-prefix".to_owned()); args.push(prefix.clone()); } }, }, /// Whether to measure the time for each one of the `bindgen` phases. time_phases: bool { methods: { /// Set whether to measure the elapsed time for each one of the `bindgen` phases. This /// information is printed to `stderr`. /// /// The elapsed time is not measured by default. pub fn time_phases(mut self, doit: bool) -> Self { self.options.time_phases = doit; self } }, as_args: "--time-phases", }, /// Whether to convert C float types to `f32` and `f64`. convert_floats: bool { default: true, methods: { /// Avoid converting C float types to `f32` and `f64`. pub fn no_convert_floats(mut self) -> Self { self.options.convert_floats = false; self } }, as_args: |value, args| (!value).as_args(args, "--no-convert-floats"), }, /// The set of raw lines to be prepended to the top-level module of the generated Rust code. raw_lines: Vec> { methods: { /// Add a line of Rust code at the beginning of the generated bindings. The string is /// passed through without any modification. pub fn raw_line>(mut self, arg: T) -> Self { self.options.raw_lines.push(arg.into().into_boxed_str()); self } }, as_args: |raw_lines, args| { for line in raw_lines { args.push("--raw-line".to_owned()); args.push(line.clone().into()); } }, }, /// The set of raw lines to prepend to different modules. module_lines: HashMap, Vec>> { methods: { /// Add a given line to the beginning of a given module. /// /// This option only comes into effect if the [`Builder::enable_cxx_namespaces`] method /// is also being called. pub fn module_raw_line(mut self, module: T, line: U) -> Self where T: Into, U: Into, { self.options .module_lines .entry(module.into().into_boxed_str()) .or_default() .push(line.into().into_boxed_str()); self } }, as_args: |module_lines, args| { for (module, lines) in module_lines { for line in lines { args.push("--module-raw-line".to_owned()); args.push(module.clone().into()); args.push(line.clone().into()); } } }, }, /// The input header files. input_headers: Vec> { methods: { /// Add an input C/C++ header to generate bindings for. /// /// This can be used to generate bindings for a single header: /// /// ```ignore /// let bindings = bindgen::Builder::default() /// .header("input.h") /// .generate() /// .unwrap(); /// ``` /// /// Or for multiple headers: /// /// ```ignore /// let bindings = bindgen::Builder::default() /// .header("first.h") /// .header("second.h") /// .header("third.h") /// .generate() /// .unwrap(); /// ``` pub fn header>(mut self, header: T) -> Builder { self.options.input_headers.push(header.into().into_boxed_str()); self } /// Add input C/C++ header(s) to generate bindings for. /// /// This can be used to generate bindings for a single header: /// /// ```ignore /// let bindings = bindgen::Builder::default() /// .headers(["input.h"]) /// .generate() /// .unwrap(); /// ``` /// /// Or for multiple headers: /// /// ```ignore /// let bindings = bindgen::Builder::default() /// .headers(["first.h", "second.h", "third.h"]) /// .generate() /// .unwrap(); /// ``` pub fn headers(mut self, headers: I) -> Builder where I::Item: Into, { self.options .input_headers .extend(headers.into_iter().map(Into::into).map(Into::into)); self } }, // This field is handled specially inside the macro. as_args: ignore, }, /// The set of arguments to be passed straight through to Clang. clang_args: Vec> { methods: { /// Add an argument to be passed straight through to Clang. pub fn clang_arg>(self, arg: T) -> Builder { self.clang_args([arg.into().into_boxed_str()]) } /// Add several arguments to be passed straight through to Clang. pub fn clang_args(mut self, args: I) -> Builder where I::Item: AsRef, { for arg in args { self.options.clang_args.push(arg.as_ref().to_owned().into_boxed_str()); } self } }, // This field is handled specially inside the macro. as_args: ignore, }, /// Tuples of unsaved file contents of the form (name, contents). input_header_contents: Vec<(Box, Box)> { methods: { /// Add `contents` as an input C/C++ header named `name`. /// /// This can be used to inject additional C/C++ code as an input without having to /// create additional header files. 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") .into(); self.options .input_header_contents .push((absolute_path, contents.into())); self } }, // Header contents cannot be added from the CLI. as_args: ignore, }, /// A user-provided visitor to allow customizing different kinds of situations. parse_callbacks: Vec> { methods: { /// Add a new [`ParseCallbacks`] instance to configure types in different situations. /// /// This can also be used with [`CargoCallbacks`](struct@crate::CargoCallbacks) to emit /// `cargo:rerun-if-changed=...` for all `#include`d header files. pub fn parse_callbacks(mut self, cb: Box) -> Self { self.options.parse_callbacks.push(Rc::from(cb)); self } }, as_args: |_callbacks, _args| { #[cfg(feature = "__cli")] for cb in _callbacks { _args.extend(cb.cli_args()); } }, }, /// Which kind of items should we generate. We generate all of them by default. codegen_config: CodegenConfig { default: CodegenConfig::all(), methods: { /// Do not generate any functions. /// /// Functions are generated by default. pub fn ignore_functions(mut self) -> Builder { self.options.codegen_config.remove(CodegenConfig::FUNCTIONS); self } /// Do not generate any methods. /// /// Methods are generated by default. pub fn ignore_methods(mut self) -> Builder { self.options.codegen_config.remove(CodegenConfig::METHODS); self } /// Choose what to generate using a [`CodegenConfig`]. /// /// This option overlaps with [`Builder::ignore_functions`] and /// [`Builder::ignore_methods`]. /// /// All the items in `CodegenConfig` are generated by default. pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self { self.options.codegen_config = config; self } }, as_args: |codegen_config, args| { if !codegen_config.functions() { args.push("--ignore-functions".to_owned()); } args.push("--generate".to_owned()); //Temporary placeholder for the 4 options below. let mut options: Vec = Vec::new(); if codegen_config.functions() { options.push("functions".to_owned()); } if codegen_config.types() { options.push("types".to_owned()); } if codegen_config.vars() { options.push("vars".to_owned()); } if codegen_config.methods() { options.push("methods".to_owned()); } if codegen_config.constructors() { options.push("constructors".to_owned()); } if codegen_config.destructors() { options.push("destructors".to_owned()); } args.push(options.join(",")); if !codegen_config.methods() { args.push("--ignore-methods".to_owned()); } }, }, /// Whether to treat inline namespaces conservatively. conservative_inline_namespaces: bool { methods: { /// 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 do not 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 using /// `bindgen` becomes a bit more difficult, because you cannot reference paths like /// `std::string` (you'd need to use the proper inline namespace). /// /// We could complicate a lot of the logic to detect name collisions and, in the /// absence of collisions, generate a `pub use inline_ns::*` or something like that. /// /// That is probably something we can do to improve the usability of this option if we /// realize it is needed way more often. Our guess is that this extra logic is not /// going to be very useful. /// /// This option is disabled by default. pub fn conservative_inline_namespaces(mut self) -> Builder { self.options.conservative_inline_namespaces = true; self } }, as_args: "--conservative-inline-namespaces", }, /// Whether to keep documentation comments in the generated output. generate_comments: bool { default: true, methods: { /// Set whether the generated bindings should contain documentation comments. /// /// Documentation comments are included by default. /// /// Note that clang excludes comments from system headers by default, pass /// `"-fretain-comments-from-system-headers"` to the [`Builder::clang_arg`] method to /// include them. /// /// It is also possible to process all comments and not just documentation using the /// `"-fparse-all-comments"` flag. Check [these slides on clang comment parsing]( /// https://llvm.org/devmtg/2012-11/Gribenko_CommentParsing.pdf) for more information /// and examples. pub fn generate_comments(mut self, doit: bool) -> Self { self.options.generate_comments = doit; self } }, as_args: |value, args| (!value).as_args(args, "--no-doc-comments"), }, /// Whether to generate inline functions. generate_inline_functions: bool { methods: { /// Set whether to generate inline functions. /// /// This option is disabled by default. /// /// 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. /// /// Check the [`Builder::wrap_static_fns`] method for an alternative. pub fn generate_inline_functions(mut self, doit: bool) -> Self { self.options.generate_inline_functions = doit; self } }, as_args: "--generate-inline-functions", }, /// Whether to allowlist types recursively. allowlist_recursively: bool { default: true, methods: { /// Set whether to recursively allowlist items. /// /// Items are allowlisted recursively by default. /// /// 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` type that it transitively references. If `false` is passed to this /// method, `bindgen` will not emit bindings for anything except the explicitly /// allowlisted items, meaning that the definition for `MoonBoots` would not be /// generated. 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 missing definitions is by using /// the [`Builder::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 } }, as_args: |value, args| (!value).as_args(args, "--no-recursive-allowlist"), }, /// Whether to emit `#[macro_use] extern crate objc;` instead of `use objc;` in the prologue of /// the files generated from objective-c files. objc_extern_crate: bool { methods: { /// Emit `#[macro_use] extern crate objc;` instead of `use objc;` in the prologue of /// the files generated from objective-c files. /// /// `use objc;` is emitted by default. pub fn objc_extern_crate(mut self, doit: bool) -> Self { self.options.objc_extern_crate = doit; self } }, as_args: "--objc-extern-crate", }, /// Whether to generate proper block signatures instead of `void` pointers. generate_block: bool { methods: { /// Generate proper block signatures instead of `void` pointers. /// /// `void` pointers are used by default. pub fn generate_block(mut self, doit: bool) -> Self { self.options.generate_block = doit; self } }, as_args: "--generate-block", }, /// Whether to generate strings as `CStr`. generate_cstr: bool { methods: { /// Set whether string constants should be generated as `&CStr` instead of `&[u8]`. /// /// A minimum Rust target of 1.59 is required for this to have any effect as support /// for `CStr::from_bytes_with_nul_unchecked` in `const` contexts is needed. /// /// This option is disabled by default but will become enabled by default in a future /// release, so enabling this is recommended. pub fn generate_cstr(mut self, doit: bool) -> Self { self.options.generate_cstr = doit; self } }, as_args: "--generate-cstr", }, /// Whether to emit `#[macro_use] extern crate block;` instead of `use block;` in the prologue /// of the files generated from apple block files. block_extern_crate: bool { methods: { /// Emit `#[macro_use] extern crate block;` instead of `use block;` in the prologue of /// the files generated from apple block files. /// /// `use block;` is emitted by default. pub fn block_extern_crate(mut self, doit: bool) -> Self { self.options.block_extern_crate = doit; self } }, as_args: "--block-extern-crate", }, /// Whether to use the clang-provided name mangling. enable_mangling: bool { default: true, methods: { /// Set whether to use the clang-provided name mangling. This is probably needed for /// C++ features. /// /// The mangling provided by clang is used by default. /// /// We allow disabling this option because some old `libclang` versions seem to return /// incorrect results in some cases for non-mangled functions, check [#528] for more /// information. /// /// [#528]: 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 } }, as_args: |value, args| (!value).as_args(args, "--distrust-clang-mangling"), }, /// Whether to detect include paths using `clang_sys`. detect_include_paths: bool { default: true, methods: { /// Set whether to detect include paths using `clang_sys`. /// /// `clang_sys` is used to detect include paths by default. pub fn detect_include_paths(mut self, doit: bool) -> Self { self.options.detect_include_paths = doit; self } }, as_args: |value, args| (!value).as_args(args, "--no-include-path-detection"), }, /// Whether we should try to fit macro constants into types smaller than `u32` and `i32`. fit_macro_constants: bool { methods: { /// Set whether `bindgen` should try to fit macro constants into types smaller than `u32` /// and `i32`. /// /// This option is disabled by default. pub fn fit_macro_constants(mut self, doit: bool) -> Self { self.options.fit_macro_constants = doit; self } }, as_args: "--fit-macro-constant-types", }, /// Whether to prepend the `enum` name to constant or newtype variants. prepend_enum_name: bool { default: true, methods: { /// Set whether to prepend the `enum` name to constant or newtype variants. /// /// The `enum` name is prepended by default. pub fn prepend_enum_name(mut self, doit: bool) -> Self { self.options.prepend_enum_name = doit; self } }, as_args: |value, args| (!value).as_args(args, "--no-prepend-enum-name"), }, /// Version of the Rust compiler to target. rust_target: RustTarget { methods: { /// Specify the Rust target version. /// /// The default target is the latest stable Rust version. pub fn rust_target(mut self, rust_target: RustTarget) -> Self { self.options.set_rust_target(rust_target); self } }, as_args: |rust_target, args| { args.push("--rust-target".to_owned()); args.push(rust_target.to_string()); }, }, /// The Rust edition to use for code generation. rust_edition: Option { methods: { /// Specify the Rust target edition. /// /// The default edition is the latest edition supported by the chosen Rust target. pub fn rust_edition(mut self, rust_edition: RustEdition) -> Self { self.options.rust_edition = Some(rust_edition); self } } as_args: |edition, args| { if let Some(edition) = edition { args.push("--rust-edition".to_owned()); args.push(edition.to_string()); } }, }, /// Features to be enabled. They are derived from `rust_target`. rust_features: RustFeatures { methods: {}, // This field cannot be set from the CLI, as_args: ignore, }, /// Enable support for native Rust unions if they are supported. untagged_union: bool { default: true, methods: { /// Disable support for native Rust unions, if supported. /// /// The default value of this option is set based on the value passed to /// [`Builder::rust_target`]. pub fn disable_untagged_union(mut self) -> Self { self.options.untagged_union = false; self } } as_args: |value, args| (!value).as_args(args, "--disable-untagged-union"), }, /// Whether we should record which items in the regex sets did match any C items. record_matches: bool { default: true, methods: { /// Set whether we should record which items in our regex sets did match any C items. /// /// Matches are recorded by default. pub fn record_matches(mut self, doit: bool) -> Self { self.options.record_matches = doit; self } }, as_args: |value, args| (!value).as_args(args, "--no-record-matches"), }, /// Whether `size_t` should be translated to `usize` automatically. size_t_is_usize: bool { default: true, methods: { /// Set whether `size_t` should be translated to `usize`. /// /// If `size_t` is translated to `usize`, type definitions for `size_t` will not be /// emitted. /// /// `size_t` is translated to `usize` by default. pub fn size_t_is_usize(mut self, is: bool) -> Self { self.options.size_t_is_usize = is; self } }, as_args: |value, args| (!value).as_args(args, "--no-size_t-is-usize"), }, /// The tool that should be used to format the generated bindings. formatter: Formatter { methods: { /// Set whether `rustfmt` should be used to format the generated bindings. /// /// `rustfmt` is used by default. /// /// This method overlaps in functionality with the more general [`Builder::formatter`]. /// Thus, the latter should be preferred. #[deprecated] pub fn rustfmt_bindings(mut self, doit: bool) -> Self { self.options.formatter = if doit { Formatter::Rustfmt } else { Formatter::None }; self } /// Set which tool should be used to format the generated bindings. /// /// The default formatter is [`Formatter::Rustfmt`]. /// /// To be able to use `prettyplease` as a formatter, the `"prettyplease"` feature for /// `bindgen` must be enabled in the Cargo manifest. pub fn formatter(mut self, formatter: Formatter) -> Self { self.options.formatter = formatter; self } }, as_args: |formatter, args| { if *formatter != Default::default() { args.push("--formatter".to_owned()); args.push(formatter.to_string()); } }, }, /// The absolute path to the `rustfmt` configuration file. rustfmt_configuration_file: Option { methods: { /// Set the absolute path to the `rustfmt` configuration file. /// /// The default `rustfmt` options are used if `None` is passed to this method or if /// this method is not called at all. /// /// Calling this method will set the [`Builder::rustfmt_bindings`] option to `true` /// and the [`Builder::formatter`] option to [`Formatter::Rustfmt`]. pub fn rustfmt_configuration_file(mut self, path: Option) -> Self { self = self.formatter(Formatter::Rustfmt); self.options.rustfmt_configuration_file = path; self } }, as_args: "--rustfmt-configuration-file", }, /// Types that should not derive `PartialEq`. no_partialeq_types: RegexSet { methods: { regex_option! { /// Do not derive `PartialEq` for a given type. pub fn no_partialeq>(mut self, arg: T) -> Builder { self.options.no_partialeq_types.insert(arg.into()); self } } }, as_args: "--no-partialeq", }, /// Types that should not derive `Copy`. no_copy_types: RegexSet { methods: { regex_option! { /// Do not derive `Copy` and `Clone` for a given type. pub fn no_copy>(mut self, arg: T) -> Self { self.options.no_copy_types.insert(arg.into()); self } } }, as_args: "--no-copy", }, /// Types that should not derive `Debug`. no_debug_types: RegexSet { methods: { regex_option! { /// Do not derive `Debug` for a given type. pub fn no_debug>(mut self, arg: T) -> Self { self.options.no_debug_types.insert(arg.into()); self } } }, as_args: "--no-debug", }, /// Types that should not derive or implement `Default`. no_default_types: RegexSet { methods: { regex_option! { /// Do not derive or implement `Default` for a given type. pub fn no_default>(mut self, arg: T) -> Self { self.options.no_default_types.insert(arg.into()); self } } }, as_args: "--no-default", }, /// Types that should not derive `Hash`. no_hash_types: RegexSet { methods: { regex_option! { /// Do not derive `Hash` for a given type. pub fn no_hash>(mut self, arg: T) -> Builder { self.options.no_hash_types.insert(arg.into()); self } } }, as_args: "--no-hash", }, /// Types that should be annotated with `#[must_use]`. must_use_types: RegexSet { methods: { regex_option! { /// Annotate the given type with the `#[must_use]` attribute. pub fn must_use_type>(mut self, arg: T) -> Builder { self.options.must_use_types.insert(arg.into()); self } } }, as_args: "--must-use-type", }, /// Whether C arrays should be regular pointers in rust or array pointers array_pointers_in_arguments: bool { methods: { /// Translate arrays `T arr[size]` into array pointers `*mut [T; size]` instead of /// translating them as `*mut T` which is the default. /// /// The same is done for `*const` pointers. pub fn array_pointers_in_arguments(mut self, doit: bool) -> Self { self.options.array_pointers_in_arguments = doit; self } }, as_args: "--use-array-pointers-in-arguments", }, /// The name of the `wasm_import_module`. wasm_import_module_name: Option { methods: { /// Adds the `#[link(wasm_import_module = import_name)]` attribute to all the `extern` /// blocks generated by `bindgen`. /// /// This attribute is not added by default. pub fn wasm_import_module_name>( mut self, import_name: T, ) -> Self { self.options.wasm_import_module_name = Some(import_name.into()); self } }, as_args: "--wasm-import-module-name", }, /// The name of the dynamic library (if we are generating bindings for a shared library). dynamic_library_name: Option { methods: { /// Generate bindings for a shared library with the given name. /// /// This option is disabled by default. pub fn dynamic_library_name>( mut self, dynamic_library_name: T, ) -> Self { self.options.dynamic_library_name = Some(dynamic_library_name.into()); self } }, as_args: "--dynamic-loading", }, /// Whether to require successful linkage for all routines in a shared library. dynamic_link_require_all: bool { methods: { /// Set whether to 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. /// /// This option only comes into effect if the [`Builder::dynamic_library_name`] option /// is set. /// /// This option is disabled by default. pub fn dynamic_link_require_all(mut self, req: bool) -> Self { self.options.dynamic_link_require_all = req; self } }, as_args: "--dynamic-link-require-all", }, /// Whether to only make generated bindings `pub` if the items would be publicly accessible by /// C++. respect_cxx_access_specs: bool { methods: { /// Set whether to respect the C++ access specifications. /// /// Passing `true` to this method will set the visibility of the generated Rust items /// as `pub` only if the corresponding C++ items are publicly accessible instead of /// marking all the items as public, which is the default. pub fn respect_cxx_access_specs(mut self, doit: bool) -> Self { self.options.respect_cxx_access_specs = doit; self } }, as_args: "--respect-cxx-access-specs", }, /// Whether to translate `enum` integer types to native Rust integer types. translate_enum_integer_types: bool { methods: { /// Set whether to always translate `enum` integer types to native Rust integer types. /// /// Passing `true` to this method will result in `enum`s having types such as `u32` and /// `i16` instead of `c_uint` and `c_short` which is the default. The `#[repr]` types /// of Rust `enum`s are always translated to Rust integer types. pub fn translate_enum_integer_types(mut self, doit: bool) -> Self { self.options.translate_enum_integer_types = doit; self } }, as_args: "--translate-enum-integer-types", }, /// Whether to generate types with C style naming. c_naming: bool { methods: { /// Set whether to generate types with C style naming. /// /// Passing `true` to this method will add prefixes to the generated type names. For /// example, instead of a `struct` with name `A` we will generate a `struct` with /// `struct_A`. Currently applies to `struct`s, `union`s, and `enum`s. pub fn c_naming(mut self, doit: bool) -> Self { self.options.c_naming = doit; self } }, as_args: "--c-naming", }, /// Whether to always emit explicit padding fields. force_explicit_padding: bool { methods: { /// Set whether to always emit explicit padding fields. /// /// This option should be enabled if a `struct` needs to be serialized in its native /// format (padding bytes and all). This could be required if such `struct` will be /// written to a file or sent over the network, as anything reading the padding bytes /// of a struct may cause undefined behavior. /// /// Padding fields are not emitted by default. pub fn explicit_padding(mut self, doit: bool) -> Self { self.options.force_explicit_padding = doit; self } }, as_args: "--explicit-padding", }, /// Whether to emit vtable functions. vtable_generation: bool { methods: { /// Set whether to enable experimental support to generate virtual table functions. /// /// This option should mostly work, though some edge cases are likely to be broken. /// /// Virtual table generation is disabled by default. pub fn vtable_generation(mut self, doit: bool) -> Self { self.options.vtable_generation = doit; self } }, as_args: "--vtable-generation", }, /// Whether to sort the generated Rust items. sort_semantically: bool { methods: { /// Set whether to sort the generated Rust items in a predefined manner. /// /// Items are not ordered by default. pub fn sort_semantically(mut self, doit: bool) -> Self { self.options.sort_semantically = doit; self } }, as_args: "--sort-semantically", }, /// Whether to deduplicate `extern` blocks. merge_extern_blocks: bool { methods: { /// Merge all extern blocks under the same module into a single one. /// /// Extern blocks are not merged by default. pub fn merge_extern_blocks(mut self, doit: bool) -> Self { self.options.merge_extern_blocks = doit; self } }, as_args: "--merge-extern-blocks", }, /// Whether to wrap unsafe operations in unsafe blocks. wrap_unsafe_ops: bool { methods: { /// Wrap all unsafe operations in unsafe blocks. /// /// Unsafe operations are not wrapped by default. pub fn wrap_unsafe_ops(mut self, doit: bool) -> Self { self.options.wrap_unsafe_ops = doit; self } }, as_args: "--wrap-unsafe-ops", }, /// Use DSTs to represent structures with flexible array members. flexarray_dst: bool { methods: { /// Use DSTs to represent structures with flexible array members. /// /// This option is disabled by default. pub fn flexarray_dst(mut self, doit: bool) -> Self { self.options.flexarray_dst = doit; self } }, as_args: "--flexarray-dst", }, /// Patterns for functions whose ABI should be overridden. abi_overrides: HashMap { methods: { regex_option! { /// Override the ABI of a given function. pub fn override_abi>(mut self, abi: Abi, arg: T) -> Self { self.options .abi_overrides .entry(abi) .or_default() .insert(arg.into()); self } } }, as_args: |overrides, args| { for (abi, set) in overrides { for item in set.get_items() { args.push("--override-abi".to_owned()); args.push(format!("{item}={abi}")); } } }, }, /// Whether to generate wrappers for `static` functions. wrap_static_fns: bool { methods: { /// Set whether to generate wrappers for `static`` functions. /// /// Passing `true` to this method will generate a C source file with non-`static` /// functions that call the `static` functions found in the input headers and can be /// called from Rust once the source file is compiled. /// /// The path of this source file can be set using the [`Builder::wrap_static_fns_path`] /// method. pub fn wrap_static_fns(mut self, doit: bool) -> Self { self.options.wrap_static_fns = doit; self } }, as_args: "--wrap-static-fns", }, /// The suffix to be added to the function wrappers for `static` functions. wrap_static_fns_suffix: Option { methods: { /// Set the suffix added to the wrappers for `static` functions. /// /// This option only comes into effect if `true` is passed to the /// [`Builder::wrap_static_fns`] method. /// /// The default suffix is `__extern`. pub fn wrap_static_fns_suffix>(mut self, suffix: T) -> Self { self.options.wrap_static_fns_suffix = Some(suffix.as_ref().to_owned()); self } }, as_args: "--wrap-static-fns-suffix", }, /// The path of the file where the wrappers for `static` functions will be emitted. wrap_static_fns_path: Option { methods: { /// Set the path for the source code file that would be created if any wrapper /// functions must be generated due to the presence of `static` functions. /// /// `bindgen` will automatically add the right extension to the header and source code /// files. /// /// This option only comes into effect if `true` is passed to the /// [`Builder::wrap_static_fns`] method. /// /// The default path is `temp_dir/bindgen/extern`, where `temp_dir` is the path /// returned by [`std::env::temp_dir`] . pub fn wrap_static_fns_path>(mut self, path: T) -> Self { self.options.wrap_static_fns_path = Some(path.as_ref().to_owned()); self } }, as_args: "--wrap-static-fns-path", }, /// Default visibility of fields. default_visibility: FieldVisibilityKind { methods: { /// Set the default visibility of fields, including bitfields and accessor methods for /// bitfields. /// /// This option only comes into effect if the [`Builder::respect_cxx_access_specs`] /// option is disabled. pub fn default_visibility( mut self, visibility: FieldVisibilityKind, ) -> Self { self.options.default_visibility = visibility; self } }, as_args: |visibility, args| { if *visibility != Default::default() { args.push("--default-visibility".to_owned()); args.push(visibility.to_string()); } }, }, /// Whether to emit diagnostics or not. emit_diagnostics: bool { methods: { #[cfg(feature = "experimental")] /// Emit diagnostics. /// /// These diagnostics are emitted to `stderr` if you are using `bindgen-cli` or printed /// using `cargo:warning=` if you are using `bindgen` as a `build-dependency`. /// /// Diagnostics are not emitted by default. /// /// The layout and contents of these diagnostic messages are not covered by versioning /// and can change without notice. pub fn emit_diagnostics(mut self) -> Self { self.options.emit_diagnostics = true; self } }, as_args: "--emit-diagnostics", }, /// Whether to use Clang evaluation on temporary files as a fallback for macros that fail to /// parse. clang_macro_fallback: bool { methods: { /// Use Clang as a fallback for macros that fail to parse using `CExpr`. /// /// This uses a workaround to evaluate each macro in a temporary file. Because this /// results in slower compilation, this option is opt-in. pub fn clang_macro_fallback(mut self) -> Self { self.options.clang_macro_fallback = true; self } }, as_args: "--clang-macro-fallback", } /// Path to use for temporary files created by clang macro fallback code like precompiled /// headers. clang_macro_fallback_build_dir: Option { methods: { /// Set a path to a directory to which `.c` and `.h.pch` files should be written for the /// purpose of using clang to evaluate macros that can't be easily parsed. /// /// The default location for `.h.pch` files is the directory that the corresponding /// `.h` file is located in. The default for the temporary `.c` file used for clang /// parsing is the current working directory. Both of these defaults are overridden /// by this option. pub fn clang_macro_fallback_build_dir>(mut self, path: P) -> Self { self.options.clang_macro_fallback_build_dir = Some(path.as_ref().to_owned()); self } }, as_args: "--clang-macro-fallback-build-dir", } } bindgen-0.71.1/parse.rs000064400000000000000000000027451046102023000130100ustar 00000000000000//! Common traits and types related to parsing our IR from Clang cursors. #![deny(clippy::missing_docs_in_private_items)] use crate::clang; use crate::ir::context::{BindgenContext, ItemId}; /// 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(crate) 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(crate) enum ParseResult { /// 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), } /// 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(crate) 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, ParseError>; } bindgen-0.71.1/regex_set.rs000064400000000000000000000140241046102023000136540ustar 00000000000000//! A type that represents the union of a set of regular expressions. #![deny(clippy::missing_docs_in_private_items)] use regex::RegexSet as RxSet; use std::cell::Cell; /// A dynamic set of regular expressions. #[derive(Clone, Debug, Default)] pub(crate) struct RegexSet { items: Vec>, /// Whether any of the items in the set was ever matched. The length of this /// vector is exactly the length of `items`. matched: Vec>, set: Option, /// Whether we should record matching items in the `matched` vector or not. record_matches: bool, } impl RegexSet { /// Is this set empty? pub(crate) fn is_empty(&self) -> bool { self.items.is_empty() } /// Insert a new regex into this set. pub(crate) fn insert(&mut self, string: S) where S: AsRef, { self.items.push(string.as_ref().to_owned().into_boxed_str()); self.matched.push(Cell::new(false)); self.set = None; } /// Returns slice of String from its field 'items' pub(crate) fn get_items(&self) -> &[Box] { &self.items } /// Returns an iterator over regexes in the set which didn't match any /// strings yet. pub(crate) fn unmatched_items(&self) -> impl Iterator { self.items.iter().enumerate().filter_map(move |(i, item)| { if !self.record_matches || self.matched[i].get() { return None; } Some(item.as_ref()) }) } /// Construct a `RegexSet` from the set of entries we've accumulated. /// /// Must be called before calling `matches()`, or it will always return /// false. #[inline] #[allow(unused)] pub(crate) fn build(&mut self, record_matches: bool) { self.build_inner(record_matches, None); } #[cfg(all(feature = "__cli", feature = "experimental"))] /// Construct a `RegexSet` from the set of entries we've accumulated and emit diagnostics if the /// name of the regex set is passed to it. /// /// Must be called before calling `matches()`, or it will always return /// false. #[inline] pub(crate) fn build_with_diagnostics( &mut self, record_matches: bool, name: Option<&'static str>, ) { self.build_inner(record_matches, name); } #[cfg(all(not(feature = "__cli"), feature = "experimental"))] /// Construct a RegexSet from the set of entries we've accumulated and emit diagnostics if the /// name of the regex set is passed to it. /// /// Must be called before calling `matches()`, or it will always return /// false. #[inline] pub(crate) fn build_with_diagnostics( &mut self, record_matches: bool, name: Option<&'static str>, ) { self.build_inner(record_matches, name); } fn build_inner( &mut self, record_matches: bool, _name: Option<&'static str>, ) { 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 {:?}: {e:?}", self.items); #[cfg(feature = "experimental")] if let Some(name) = _name { invalid_regex_warning(self, e, name); } None } } } /// Does the given `string` match any of the regexes in this set? pub(crate) fn matches(&self, string: S) -> bool where S: AsRef, { let s = string.as_ref(); let Some(ref set) = self.set else { 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 { self.matched[i].set(true); } true } } #[cfg(feature = "experimental")] fn invalid_regex_warning( set: &RegexSet, err: regex::Error, name: &'static str, ) { use crate::diagnostics::{Diagnostic, Level, Slice}; let mut diagnostic = Diagnostic::default(); match err { regex::Error::Syntax(string) => { if string.starts_with("regex parse error:\n") { let mut source = String::new(); let mut parsing_source = true; for line in string.lines().skip(1) { if parsing_source { if line.starts_with(' ') { source.push_str(line); source.push('\n'); continue; } parsing_source = false; } let error = "error: "; if line.starts_with(error) { let (_, msg) = line.split_at(error.len()); diagnostic.add_annotation(msg.to_owned(), Level::Error); } else { diagnostic.add_annotation(line.to_owned(), Level::Info); } } let mut slice = Slice::default(); slice.with_source(source); diagnostic.add_slice(slice); diagnostic.with_title( "Error while parsing a regular expression.", Level::Warning, ); } else { diagnostic.with_title(string, Level::Warning); } } err => { let err = err.to_string(); diagnostic.with_title(err, Level::Warning); } } diagnostic.add_annotation( format!("This regular expression was passed via `{name}`."), Level::Note, ); if set.items.iter().any(|item| item.as_ref() == "*") { diagnostic.add_annotation("Wildcard patterns \"*\" are no longer considered valid. Use \".*\" instead.", Level::Help); } diagnostic.display(); } bindgen-0.71.1/time.rs000064400000000000000000000025701046102023000126300ustar 00000000000000use 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 + f64::from(elapsed.subsec_nanos()) / 1e6; let stderr = io::stderr(); // Arbitrary output format, subject to change. writeln!(stderr.lock(), " time: {time:>9.3} ms.\t{}", self.name) .expect("timer write should not fail"); } } } impl Drop for Timer<'_> { fn drop(&mut self) { self.print_elapsed(); } }