bindgen-0.59.1/.cargo_vcs_info.json0000644000000001120000000000000125270ustar { "git": { "sha1": "9a9438f3d6a3523c69d7bc890e8608b63dbe38a5" } } bindgen-0.59.1/Cargo.lock0000644000000305130000000000000105120ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" dependencies = [ "memchr", ] [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ "winapi", ] [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", "winapi", ] [[package]] name = "bindgen" version = "0.59.1" dependencies = [ "bitflags", "cexpr", "clang-sys", "clap", "diff", "env_logger", "lazy_static", "lazycell", "log", "peeking_take_while", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "tempfile", "which", ] [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitvec" version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" dependencies = [ "funty", "radium", "tap", "wyz", ] [[package]] name = "cexpr" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89" dependencies = [ "nom", ] [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clang-sys" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0659001ab56b791be01d4b729c44376edc6718cf389a502e579b77b758f3296c" dependencies = [ "glob", "libc", "libloading", ] [[package]] name = "clap" version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "ansi_term", "atty", "bitflags", "strsim", "textwrap", "unicode-width", "vec_map", ] [[package]] name = "diff" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] name = "env_logger" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd" dependencies = [ "atty", "humantime", "log", "regex", "termcolor", ] [[package]] name = "funty" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" [[package]] name = "getrandom" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if 1.0.0", "libc", "wasi", ] [[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "hermit-abi" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ "libc", ] [[package]] name = "humantime" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" [[package]] name = "libloading" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0" dependencies = [ "cfg-if 1.0.0", "winapi", ] [[package]] name = "log" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ "cfg-if 0.1.10", ] [[package]] name = "memchr" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "nom" version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" dependencies = [ "bitvec", "funty", "memchr", "version_check", ] [[package]] name = "peeking_take_while" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "ppv-lite86" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ "proc-macro2", ] [[package]] name = "radium" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" [[package]] name = "rand" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ "libc", "rand_chacha", "rand_core", "rand_hc", ] [[package]] name = "rand_chacha" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ "getrandom", ] [[package]] name = "rand_hc" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ "rand_core", ] [[package]] name = "redox_syscall" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" dependencies = [ "bitflags", ] [[package]] name = "regex" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" dependencies = [ "aho-corasick", "memchr", "regex-syntax", "thread_local", ] [[package]] name = "regex-syntax" version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" [[package]] name = "remove_dir_all" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ "winapi", ] [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "shlex" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d" [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", "rand", "redox_syscall", "remove_dir_all", "winapi", ] [[package]] name = "termcolor" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" dependencies = [ "winapi-util", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ "unicode-width", ] [[package]] name = "thread_local" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" dependencies = [ "lazy_static", ] [[package]] name = "unicode-width" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "which" version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" dependencies = [ "libc", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "wyz" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" bindgen-0.59.1/Cargo.toml0000644000000053310000000000000105350ustar # 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 believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "bindgen" version = "0.59.1" authors = ["Jyun-Yan You ", "Emilio Cobos Álvarez ", "Nick Fitzgerald ", "The Servo project developers"] build = "build.rs" include = ["LICENSE", "README.md", "Cargo.toml", "build.rs", "src/*.rs", "src/**/*.rs"] 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" [lib] path = "src/lib.rs" [[bin]] name = "bindgen" path = "src/main.rs" doc = false required-features = ["clap"] [dependencies.bitflags] version = "1.0.3" [dependencies.cexpr] version = "0.5" [dependencies.clang-sys] version = "1" features = ["clang_6_0"] [dependencies.clap] version = "2" optional = true [dependencies.env_logger] version = "0.8" optional = true [dependencies.lazy_static] version = "1" [dependencies.lazycell] version = "1" [dependencies.log] version = "0.4" optional = true [dependencies.peeking_take_while] version = "0.1.2" [dependencies.proc-macro2] version = "1" default-features = false [dependencies.quote] version = "1" default-features = false [dependencies.regex] version = "1.0" features = ["std", "unicode"] default-features = false [dependencies.rustc-hash] version = "1.0.1" [dependencies.shlex] version = "1" [dependencies.which] version = "3.0" optional = true default-features = false [dev-dependencies.clap] version = "2" [dev-dependencies.diff] version = "0.1" [dev-dependencies.shlex] version = "1" [dev-dependencies.tempfile] version = "3" [features] default = ["logging", "clap", "runtime", "which-rustfmt"] logging = ["env_logger", "log"] runtime = ["clang-sys/runtime"] static = ["clang-sys/static"] testing_only_docs = [] testing_only_extra_assertions = [] testing_only_libclang_3_9 = [] testing_only_libclang_4 = [] testing_only_libclang_5 = [] testing_only_libclang_9 = [] which-rustfmt = ["which"] [badges.travis-ci] repository = "rust-lang/rust-bindgen" bindgen-0.59.1/Cargo.toml.orig000064400000000000000000000042600000000000000141740ustar 00000000000000[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.59.1" edition = "2018" build = "build.rs" include = [ "LICENSE", "README.md", "Cargo.toml", "build.rs", "src/*.rs", "src/**/*.rs", ] [badges] travis-ci = { repository = "rust-lang/rust-bindgen" } [lib] path = "src/lib.rs" [[bin]] name = "bindgen" path = "src/main.rs" doc = false required-features = ["clap"] [dev-dependencies] diff = "0.1" clap = "2" shlex = "1" tempfile = "3" [dependencies] bitflags = "1.0.3" cexpr = "0.5" # This kinda sucks: https://github.com/rust-lang/cargo/issues/1982 clap = { version = "2", optional = true } clang-sys = { version = "1", features = ["clang_6_0"] } lazycell = "1" lazy_static = "1" peeking_take_while = "0.1.2" quote = { version = "1", default-features = false } regex = { version = "1.0", default-features = false , features = [ "std", "unicode"]} which = { version = "3.0", optional = true, default-features = false } shlex = "1" rustc-hash = "1.0.1" proc-macro2 = { version = "1", default-features = false } [dependencies.env_logger] optional = true version = "0.8" [dependencies.log] optional = true version = "0.4" [features] default = ["logging", "clap", "runtime", "which-rustfmt"] logging = ["env_logger", "log"] static = ["clang-sys/static"] runtime = ["clang-sys/runtime"] # Dynamically discover a `rustfmt` binary using the `which` crate which-rustfmt = ["which"] # These features only exist for CI testing -- don't use them if you're not hacking # on bindgen! testing_only_docs = [] testing_only_extra_assertions = [] testing_only_libclang_9 = [] testing_only_libclang_5 = [] testing_only_libclang_4 = [] testing_only_libclang_3_9 = [] bindgen-0.59.1/LICENSE000064400000000000000000000027500000000000000123140ustar 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.59.1/README.md000064400000000000000000000055160000000000000125710ustar 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 minimum supported Rust version is **1.44**. No MSRV bump policy has been established yet, so MSRV may increase in any release. ## 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.59.1/build.rs000064400000000000000000000054010000000000000127500ustar 00000000000000mod target { use std::env; use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; pub 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(); } } mod testgen { use std::char; use std::env; use std::ffi::OsStr; use std::fs::{self, File}; use std::io::Write; use std::path::{Path, PathBuf}; pub fn main() { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let mut dst = File::create(Path::new(&out_dir).join("tests.rs")).unwrap(); let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); let headers_dir = manifest_dir.join("tests").join("headers"); let headers = match fs::read_dir(headers_dir) { Ok(dir) => dir, // We may not have headers directory after packaging. Err(..) => return, }; let entries = headers.map(|result| result.expect("Couldn't read header file")); println!("cargo:rerun-if-changed=tests/headers"); for entry in entries { match entry.path().extension().and_then(OsStr::to_str) { Some("h") | Some("hpp") => { let func = entry .file_name() .to_str() .unwrap() .replace(|c| !char::is_alphanumeric(c), "_") .replace("__", "_") .to_lowercase(); writeln!( dst, "test_header!(header_{}, {:?});", func, entry.path(), ) .unwrap(); } _ => {} } } dst.flush().unwrap(); } } fn main() { target::main(); testgen::main(); // 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_{}", std::env::var("TARGET").unwrap() ); println!( "cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_{}", std::env::var("TARGET").unwrap().replace("-", "_") ); } bindgen-0.59.1/csmith-fuzzing/README.md000064400000000000000000000047010000000000000155450ustar 00000000000000# Fuzzing `bindgen` with `csmith` [`csmith`][csmith] generates random C and C++ programs that can be used as test cases for compilers. When testing `bindgen` with `csmith`, we interpret the generated programs as header files, and emit Rust bindings to them. If `bindgen` panics, the emitted bindings won't compile with `rustc`, or the generated layout tests in the bindings fail, then we report an issue containing the test case! - [Prerequisites](#prerequisites) - [Running the Fuzzer](#running-the-fuzzer) - [Reporting Issues](#reporting-issues) ## Prerequisites Requires `python3`, `csmith`, and `creduce` to be in `$PATH`. Many OS package managers have `csmith` and `creduce` packages: ``` $ sudo apt install csmith creduce $ brew install csmith creduce $ # Etc... ``` ## Running the Fuzzer Run `csmith` and test `bindgen` on the generated test cases with this command: ``` $ ./driver.py ``` The driver will keep running until it encounters an error in `bindgen`. Each invocation of `./driver.py` will use its own temporary directories, so running it in multiple terminals in parallel is supported. `csmith` is run with `--no-checksum --nomain --max-block-size 1 --max-block-depth 1` which disables the `main` function, and makes function bodies as simple as possible as `bindgen` does not care about them, but they cannot be completely disabled in `csmith`. Run `csmith --help` to see what exactly those options do. ## Reporting Issues Once the fuzz driver finds a test case that causes some kind of error in `bindgen` or its emitted bindings, it is helpful to [run C-Reduce on the test case][creducing] to remove the parts that are irrelevant to reproducing the error. This is ***very*** helpful for the folks who further investigate the issue and come up with a fix! Additionally, mention that you discovered the issue via `csmith` and we will add the `A-csmith` label. You can find all the issues discovered with `csmith`, and related to fuzzing with `csmith`, by looking up [all issues tagged with the `A-csmith` label][csmith-issues]. [csmith]: https://github.com/csmith-project/csmith [creducing]: ../CONTRIBUTING.md#using-creduce-to-minimize-test-cases [csmith-issues]: https://github.com/rust-lang/rust-bindgen/issues?q=label%3AA-csmith bindgen-0.59.1/src/callbacks.rs000064400000000000000000000075710000000000000143710ustar 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; use std::panic::UnwindSafe; /// An enum to allow ignoring parsing of macros. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum MacroParsingBehavior { /// Ignore the macro, generating no code for it, or anything that depends on /// it. Ignore, /// The default behavior bindgen would have otherwise. Default, } impl Default for MacroParsingBehavior { fn default() -> Self { MacroParsingBehavior::Default } } /// A trait to allow configuring different kinds of types in different /// situations. pub trait ParseCallbacks: fmt::Debug + UnwindSafe { /// This function will be run on every macro that is identified. fn will_parse_macro(&self, _name: &str) -> MacroParsingBehavior { MacroParsingBehavior::Default } /// The integer kind an integer macro should have, given a name and the /// value of that macro, or `None` if you want the default to be chosen. fn int_macro(&self, _name: &str, _value: i64) -> Option { 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 file inclusion, with the full path of the included file. fn include_file(&self, _filename: &str) {} /// This will be called to determine whether a particular blocklisted type /// implements a trait or not. This will be used to implement traits on /// other types containing the blocklisted type. /// /// * `None`: use the default behavior /// * `Some(ImplementsTrait::Yes)`: `_name` implements `_derive_trait` /// * `Some(ImplementsTrait::Manually)`: any type including `_name` can't /// derive `_derive_trait` but can implemented it manually /// * `Some(ImplementsTrait::No)`: `_name` doesn't implement `_derive_trait` fn blocklisted_type_implements_trait( &self, _name: &str, _derive_trait: DeriveTrait, ) -> Option { None } /// Provide a list of custom derive attributes. /// /// If no additional attributes are wanted, this function should return an /// empty `Vec`. fn add_derives(&self, _name: &str) -> Vec { vec![] } } bindgen-0.59.1/src/clang.rs000064400000000000000000001731400000000000000135320ustar 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)] use crate::ir::context::BindgenContext; use cexpr; use clang_sys::*; use regex; use std::ffi::{CStr, CString}; use std::fmt; use std::hash::Hash; use std::hash::Hasher; use std::os::raw::{c_char, c_int, c_longlong, c_uint, c_ulong, c_ulonglong}; use std::{mem, ptr, slice}; /// A cursor into the Clang AST, pointing to an AST node. /// /// We call the AST node pointed to by the cursor the cursor's "referent". #[derive(Copy, Clone)] pub struct Cursor { x: CXCursor, } impl fmt::Debug for Cursor { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!( fmt, "Cursor({} kind: {}, loc: {}, usr: {:?})", self.spelling(), kind_to_str(self.kind()), self.location(), self.usr() ) } } impl Cursor { /// Get the Unified Symbol Resolution for this cursor's referent, if /// available. /// /// The USR can be used to compare entities across translation units. pub fn usr(&self) -> Option { let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) }; if s.is_empty() { None } else { Some(s) } } /// Is this cursor's referent a declaration? pub fn is_declaration(&self) -> bool { unsafe { clang_isDeclaration(self.kind()) != 0 } } /// Get this cursor's referent's spelling. pub fn spelling(&self) -> String { unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) } } /// Get this cursor's referent's display name. /// /// This is not necessarily a valid identifier. It includes extra /// information, such as parameters for a function, etc. pub fn display_name(&self) -> String { unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) } } /// Get the mangled name of this cursor's referent. pub fn mangling(&self) -> String { unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) } } /// Gets the C++ manglings for this cursor, or an error if the manglings /// are not available. pub fn cxx_manglings(&self) -> Result, ()> { 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.offset(i as isize); result.push(cxstring_to_string_leaky(*string_ptr)); } clang_disposeStringSet(manglings); Ok(result) } } /// Returns whether the cursor refers to a built-in definition. pub fn is_builtin(&self) -> bool { let (file, _, _, _) = self.location().location(); file.name().is_none() } /// Get the `Cursor` for this cursor's referent's lexical parent. /// /// The lexical parent is the parent of the definition. The semantic parent /// is the parent of the declaration. Generally, the lexical parent doesn't /// have any effect on semantics, while the semantic parent does. /// /// In the following snippet, the `Foo` class would be the semantic parent /// of the out-of-line `method` definition, while the lexical parent is the /// translation unit. /// /// ```c++ /// class Foo { /// void method(); /// }; /// /// void Foo::method() { /* ... */ } /// ``` pub fn lexical_parent(&self) -> Cursor { unsafe { Cursor { x: clang_getCursorLexicalParent(self.x), } } } /// Get the referent's semantic parent, if one is available. /// /// See documentation for `lexical_parent` for details on semantic vs /// lexical parents. pub fn fallible_semantic_parent(&self) -> Option { let sp = unsafe { Cursor { x: clang_getCursorSemanticParent(self.x), } }; if sp == *self || !sp.is_valid() { return None; } Some(sp) } /// Get the referent's semantic parent. /// /// See documentation for `lexical_parent` for details on semantic vs /// lexical parents. pub fn semantic_parent(&self) -> Cursor { self.fallible_semantic_parent().unwrap() } /// Return the number of template arguments used by this cursor's referent, /// if the referent is either a template instantiation. Returns `None` /// otherwise. /// /// NOTE: This may not return `Some` for partial template specializations, /// see #193 and #194. pub fn num_template_args(&self) -> Option { // XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while // `clang_Cursor_getNumTemplateArguments` is totally unreliable. // Therefore, try former first, and only fallback to the latter if we // have to. self.cur_type() .num_template_args() .or_else(|| { let n: c_int = unsafe { clang_Cursor_getNumTemplateArguments(self.x) }; if n >= 0 { Some(n as u32) } else { debug_assert_eq!(n, -1); None } }) .or_else(|| { let canonical = self.canonical(); if canonical != *self { canonical.num_template_args() } else { None } }) } /// Get a cursor pointing to this referent's containing translation unit. /// /// Note that we shouldn't create a `TranslationUnit` struct here, because /// bindgen assumes there will only be one of them alive at a time, and /// disposes it on drop. That can change if this would be required, but I /// think we can survive fine without it. pub fn translation_unit(&self) -> Cursor { assert!(self.is_valid()); unsafe { let tu = clang_Cursor_getTranslationUnit(self.x); let cursor = Cursor { x: clang_getTranslationUnitCursor(tu), }; assert!(cursor.is_valid()); cursor } } /// Is the referent a top level construct? pub fn is_toplevel(&self) -> bool { let mut semantic_parent = self.fallible_semantic_parent(); while semantic_parent.is_some() && (semantic_parent.unwrap().kind() == CXCursor_Namespace || semantic_parent.unwrap().kind() == CXCursor_NamespaceAlias || semantic_parent.unwrap().kind() == CXCursor_NamespaceRef) { semantic_parent = semantic_parent.unwrap().fallible_semantic_parent(); } let tu = self.translation_unit(); // Yes, this can happen with, e.g., macro definitions. semantic_parent == tu.fallible_semantic_parent() } /// There are a few kinds of types that we need to treat specially, mainly /// not tracking the type declaration but the location of the cursor, given /// clang doesn't expose a proper declaration for these types. pub fn is_template_like(&self) -> bool { match self.kind() { CXCursor_ClassTemplate | CXCursor_ClassTemplatePartialSpecialization | CXCursor_TypeAliasTemplateDecl => true, _ => false, } } /// Is this Cursor pointing to a function-like macro definition? pub fn is_macro_function_like(&self) -> bool { unsafe { clang_Cursor_isMacroFunctionLike(self.x) != 0 } } /// Get the kind of referent this cursor is pointing to. pub fn kind(&self) -> CXCursorKind { self.x.kind } /// Returns true if the cursor is a definition pub fn is_definition(&self) -> bool { unsafe { clang_isCursorDefinition(self.x) != 0 } } /// Is the referent a template specialization? pub fn is_template_specialization(&self) -> bool { self.specialized().is_some() } /// Is the referent a fully specialized template specialization without any /// remaining free template arguments? pub fn is_fully_specialized_template(&self) -> bool { self.is_template_specialization() && self.kind() != CXCursor_ClassTemplatePartialSpecialization && self.num_template_args().unwrap_or(0) > 0 } /// Is the referent a template specialization that still has remaining free /// template arguments? pub fn is_in_non_fully_specialized_template(&self) -> bool { if self.is_toplevel() { return false; } let parent = self.semantic_parent(); if parent.is_fully_specialized_template() { return false; } if !parent.is_template_like() { return parent.is_in_non_fully_specialized_template(); } return true; } /// Is this cursor pointing a valid referent? pub fn is_valid(&self) -> bool { unsafe { clang_isInvalid(self.kind()) == 0 } } /// Get the source location for the referent. pub fn location(&self) -> SourceLocation { unsafe { SourceLocation { x: clang_getCursorLocation(self.x), } } } /// Get the source location range for the referent. pub fn extent(&self) -> CXSourceRange { unsafe { clang_getCursorExtent(self.x) } } /// Get the raw declaration comment for this referent, if one exists. pub fn raw_comment(&self) -> Option { let s = unsafe { cxstring_into_string(clang_Cursor_getRawCommentText(self.x)) }; if s.is_empty() { None } else { Some(s) } } /// Get the referent's parsed comment. pub fn comment(&self) -> Comment { unsafe { Comment { x: clang_Cursor_getParsedComment(self.x), } } } /// Get the referent's type. pub fn cur_type(&self) -> Type { unsafe { Type { x: clang_getCursorType(self.x), } } } /// Given that this cursor's referent is a reference to another type, or is /// a declaration, get the cursor pointing to the referenced type or type of /// the declared thing. pub fn definition(&self) -> Option { unsafe { let ret = Cursor { x: clang_getCursorDefinition(self.x), }; if ret.is_valid() && ret.kind() != CXCursor_NoDeclFound { Some(ret) } else { None } } } /// Given that this cursor's referent is reference type, get the cursor /// pointing to the referenced type. pub fn referenced(&self) -> Option { unsafe { let ret = Cursor { x: clang_getCursorReferenced(self.x), }; if ret.is_valid() { Some(ret) } else { None } } } /// Get the canonical cursor for this referent. /// /// Many types can be declared multiple times before finally being properly /// defined. This method allows us to get the canonical cursor for the /// referent type. pub fn canonical(&self) -> Cursor { unsafe { Cursor { x: clang_getCanonicalCursor(self.x), } } } /// Given that this cursor points to either a template specialization or a /// template instantiation, get a cursor pointing to the template definition /// that is being specialized. pub fn specialized(&self) -> Option { unsafe { let ret = Cursor { x: clang_getSpecializedCursorTemplate(self.x), }; if ret.is_valid() { Some(ret) } else { None } } } /// Assuming that this cursor's referent is a template declaration, get the /// kind of cursor that would be generated for its specializations. pub fn template_kind(&self) -> CXCursorKind { unsafe { clang_getTemplateCursorKind(self.x) } } /// Traverse this cursor's referent and its children. /// /// Call the given function on each AST node traversed. pub fn visit(&self, mut visitor: Visitor) where Visitor: FnMut(Cursor) -> CXChildVisitResult, { unsafe { clang_visitChildren( self.x, visit_children::, mem::transmute(&mut visitor), ); } } /// Collect all of this cursor's children into a vec and return them. pub 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 fn has_children(&self) -> bool { let mut has_children = false; self.visit(|_| { has_children = true; CXChildVisit_Break }); has_children } /// Does this cursor have at least `n` children? pub fn has_at_least_num_children(&self, n: usize) -> bool { assert!(n > 0); let mut num_left = n; self.visit(|_| { num_left -= 1; if num_left == 0 { CXChildVisit_Break } else { CXChildVisit_Continue } }); num_left == 0 } /// Returns whether the given location contains a cursor with the given /// kind in the first level of nesting underneath (doesn't look /// recursively). pub fn contains_cursor(&self, kind: CXCursorKind) -> bool { let mut found = false; self.visit(|c| { if c.kind() == kind { found = true; CXChildVisit_Break } else { CXChildVisit_Continue } }); found } /// Is the referent an inlined function? pub fn is_inlined_function(&self) -> bool { unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 } } /// Is the referent a defaulted function? pub fn is_defaulted_function(&self) -> bool { unsafe { clang_CXXMethod_isDefaulted(self.x) != 0 } } /// Is the referent a deleted function? pub fn is_deleted_function(&self) -> bool { // Unfortunately, libclang doesn't yet have an API for checking if a // member function is deleted, but the following should be a good // enough approximation. // Deleted functions are implicitly inline according to paragraph 4 of // [dcl.fct.def.delete] in the C++ standard. Normal inline functions // have a definition in the same translation unit, so if this is an // inline function without a definition, and it's not a defaulted // function, we can reasonably safely conclude that it's a deleted // function. self.is_inlined_function() && self.definition().is_none() && !self.is_defaulted_function() } /// Get the width of this cursor's referent bit field, or `None` if the /// referent is not a bit field. pub fn bit_width(&self) -> Option { unsafe { let w = clang_getFieldDeclBitWidth(self.x); if w == -1 { None } else { Some(w as u32) } } } /// Get the integer representation type used to hold this cursor's referent /// enum type. pub fn enum_type(&self) -> Option { unsafe { let t = Type { x: clang_getEnumDeclIntegerType(self.x), }; if t.is_valid() { Some(t) } else { None } } } /// Get the boolean constant value for this cursor's enum variant referent. /// /// Returns None if the cursor's referent is not an enum variant. pub fn enum_val_boolean(&self) -> Option { unsafe { if self.kind() == CXCursor_EnumConstantDecl { Some(clang_getEnumConstantDeclValue(self.x) != 0) } else { None } } } /// Get the signed constant value for this cursor's enum variant referent. /// /// Returns None if the cursor's referent is not an enum variant. pub fn enum_val_signed(&self) -> Option { unsafe { if self.kind() == CXCursor_EnumConstantDecl { Some(clang_getEnumConstantDeclValue(self.x) as i64) } else { None } } } /// Get the unsigned constant value for this cursor's enum variant referent. /// /// Returns None if the cursor's referent is not an enum variant. pub fn enum_val_unsigned(&self) -> Option { unsafe { if self.kind() == CXCursor_EnumConstantDecl { Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64) } else { None } } } /// Whether this cursor has the `warn_unused_result` attribute. pub fn has_warn_unused_result_attr(&self) -> bool { // FIXME(emilio): clang-sys doesn't expose this (from clang 9). const CXCursor_WarnUnusedResultAttr: CXCursorKind = 440; self.has_attr("warn_unused_result", Some(CXCursor_WarnUnusedResultAttr)) } /// Does this cursor have the given attribute? /// /// `name` is checked against unexposed attributes. fn has_attr(&self, name: &str, clang_kind: Option) -> bool { let mut found_attr = false; self.visit(|cur| { let kind = cur.kind(); found_attr = clang_kind.map_or(false, |k| k == kind) || (kind == CXCursor_UnexposedAttr && cur.tokens().iter().any(|t| { t.kind == CXToken_Identifier && t.spelling() == name.as_bytes() })); if found_attr { CXChildVisit_Break } else { CXChildVisit_Continue } }); found_attr } /// Given that this cursor's referent is a `typedef`, get the `Type` that is /// being aliased. pub 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 fn linkage(&self) -> CXLinkageKind { unsafe { clang_getCursorLinkage(self.x) } } /// Get the visibility of this cursor's referent. pub fn visibility(&self) -> CXVisibilityKind { unsafe { clang_getCursorVisibility(self.x) } } /// Given that this cursor's referent is a function, return cursors to its /// parameters. /// /// Returns None if the cursor's referent is not a function/method call or /// declaration. pub fn args(&self) -> Option> { // match self.kind() { // CXCursor_FunctionDecl | // CXCursor_CXXMethod => { self.num_args().ok().map(|num| { (0..num) .map(|i| Cursor { x: unsafe { clang_Cursor_getArgument(self.x, i as c_uint) }, }) .collect() }) } /// Given that this cursor's referent is a function/method call or /// declaration, return the number of arguments it takes. /// /// Returns Err if the cursor's referent is not a function/method call or /// declaration. pub fn num_args(&self) -> Result { unsafe { let w = clang_Cursor_getNumArguments(self.x); if w == -1 { Err(()) } else { Ok(w as u32) } } } /// Get the access specifier for this cursor's referent. pub fn access_specifier(&self) -> CX_CXXAccessSpecifier { unsafe { clang_getCXXAccessSpecifier(self.x) } } /// Is the cursor's referrent publically accessible in C++? /// /// Returns true if self.access_specifier() is `CX_CXXPublic` or /// `CX_CXXInvalidAccessSpecifier`. pub fn public_accessible(&self) -> bool { let access = self.access_specifier(); access == CX_CXXPublic || access == CX_CXXInvalidAccessSpecifier } /// Is this cursor's referent a field declaration that is marked as /// `mutable`? pub fn is_mutable_field(&self) -> bool { unsafe { clang_CXXField_isMutable(self.x) != 0 } } /// Get the offset of the field represented by the Cursor. pub fn offset_of_field(&self) -> Result { let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) }; if offset < 0 { Err(LayoutError::from(offset as i32)) } else { Ok(offset as usize) } } /// Is this cursor's referent a member function that is declared `static`? pub fn method_is_static(&self) -> bool { unsafe { clang_CXXMethod_isStatic(self.x) != 0 } } /// Is this cursor's referent a member function that is declared `const`? pub fn method_is_const(&self) -> bool { unsafe { clang_CXXMethod_isConst(self.x) != 0 } } /// Is this cursor's referent a member function that is virtual? pub fn method_is_virtual(&self) -> bool { unsafe { clang_CXXMethod_isVirtual(self.x) != 0 } } /// Is this cursor's referent a member function that is pure virtual? pub fn method_is_pure_virtual(&self) -> bool { unsafe { clang_CXXMethod_isPureVirtual(self.x) != 0 } } /// Is this cursor's referent a struct or class with virtual members? pub fn is_virtual_base(&self) -> bool { unsafe { clang_isVirtualBase(self.x) != 0 } } /// Try to evaluate this cursor. pub fn evaluate(&self) -> Option { EvalResult::new(*self) } /// Return the result type for this cursor pub 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 fn tokens(&self) -> RawTokens { RawTokens::new(self) } /// Gets the tokens that correspond to that cursor as `cexpr` tokens. pub 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 fn get_included_file_name(&self) -> Option { let file = unsafe { clang_sys::clang_getIncludedFile(self.x) }; if file.is_null() { None } else { Some(unsafe { cxstring_into_string(clang_sys::clang_getFileName(file)) }) } } } /// A struct that owns the tokenizer result from a given cursor. pub struct RawTokens<'a> { cursor: &'a Cursor, tu: CXTranslationUnit, tokens: *mut CXToken, token_count: c_uint, } impl<'a> RawTokens<'a> { fn new(cursor: &'a Cursor) -> Self { let mut tokens = ptr::null_mut(); let mut token_count = 0; let range = cursor.extent(); let tu = unsafe { clang_Cursor_getTranslationUnit(cursor.x) }; unsafe { clang_tokenize(tu, range, &mut tokens, &mut token_count) }; Self { cursor, tu, tokens, token_count, } } fn as_slice(&self) -> &[CXToken] { if self.tokens.is_null() { return &[]; } unsafe { slice::from_raw_parts(self.tokens, self.token_count as usize) } } /// Get an iterator over these tokens. pub fn iter(&self) -> ClangTokenIterator { ClangTokenIterator { tu: self.tu, raw: self.as_slice().iter(), } } } impl<'a> Drop for RawTokens<'a> { fn drop(&mut self) { if !self.tokens.is_null() { unsafe { clang_disposeTokens( self.tu, self.tokens, self.token_count as c_uint, ); } } } } /// A raw clang token, that exposes only kind, spelling, and extent. This is a /// slightly more convenient version of `CXToken` which owns the spelling /// string and extent. #[derive(Debug)] pub struct ClangToken { spelling: CXString, /// The extent of the token. This is the same as the relevant member from /// `CXToken`. pub extent: CXSourceRange, /// The kind of the token. This is the same as the relevant member from /// `CXToken`. pub kind: CXTokenKind, } impl ClangToken { /// Get the token spelling, without being converted to utf-8. pub fn spelling(&self) -> &[u8] { let c_str = unsafe { CStr::from_ptr(clang_getCString(self.spelling) as *const _) }; c_str.to_bytes() } /// Converts a ClangToken to a `cexpr` token if possible. pub fn as_cexpr_token(&self) -> Option { use cexpr::token; let kind = match self.kind { CXToken_Punctuation => token::Kind::Punctuation, CXToken_Literal => token::Kind::Literal, CXToken_Identifier => token::Kind::Identifier, CXToken_Keyword => token::Kind::Keyword, // NB: cexpr is not too happy about comments inside // expressions, so we strip them down here. CXToken_Comment => return None, _ => { warn!("Found unexpected token kind: {:?}", self); return None; } }; Some(token::Token { kind, raw: self.spelling().to_vec().into_boxed_slice(), }) } } impl Drop for ClangToken { fn drop(&mut self) { unsafe { clang_disposeString(self.spelling) } } } /// An iterator over a set of Tokens. pub struct ClangTokenIterator<'a> { tu: CXTranslationUnit, raw: slice::Iter<'a, CXToken>, } impl<'a> Iterator for ClangTokenIterator<'a> { type Item = ClangToken; fn next(&mut self) -> Option { let raw = self.raw.next()?; unsafe { let kind = clang_getTokenKind(*raw); let spelling = clang_getTokenSpelling(self.tu, *raw); let extent = clang_getTokenExtent(self.tu, *raw); Some(ClangToken { kind, extent, spelling, }) } } } /// Checks whether the name looks like an identifier, i.e. is alphanumeric /// (including '_') and does not start with a digit. pub fn is_valid_identifier(name: &str) -> bool { let mut chars = name.chars(); let first_valid = chars .next() .map(|c| c.is_alphabetic() || c == '_') .unwrap_or(false); first_valid && chars.all(|c| c.is_alphanumeric() || c == '_') } extern "C" fn visit_children( cur: CXCursor, _parent: CXCursor, data: CXClientData, ) -> CXChildVisitResult where Visitor: FnMut(Cursor) -> CXChildVisitResult, { let func: &mut Visitor = unsafe { mem::transmute(data) }; 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 struct Type { x: CXType, } impl PartialEq for Type { fn eq(&self, other: &Self) -> bool { unsafe { clang_equalTypes(self.x, other.x) != 0 } } } impl Eq for Type {} impl fmt::Debug for Type { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!( fmt, "Type({}, kind: {}, cconv: {}, decl: {:?}, canon: {:?})", self.spelling(), type_to_str(self.kind()), self.call_conv(), self.declaration(), self.declaration().canonical() ) } } /// An error about the layout of a struct, class, or type. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum LayoutError { /// Asked for the layout of an invalid type. Invalid, /// Asked for the layout of an incomplete type. Incomplete, /// Asked for the layout of a dependent type. Dependent, /// Asked for the layout of a type that does not have constant size. NotConstantSize, /// Asked for the layout of a field in a type that does not have such a /// field. InvalidFieldName, /// An unknown layout error. Unknown, } impl ::std::convert::From for LayoutError { fn from(val: i32) -> Self { use self::LayoutError::*; match val { CXTypeLayoutError_Invalid => Invalid, CXTypeLayoutError_Incomplete => Incomplete, CXTypeLayoutError_Dependent => Dependent, CXTypeLayoutError_NotConstantSize => NotConstantSize, CXTypeLayoutError_InvalidFieldName => InvalidFieldName, _ => Unknown, } } } impl Type { /// Get this type's kind. pub fn kind(&self) -> CXTypeKind { self.x.kind } /// Get a cursor pointing to this type's declaration. pub fn declaration(&self) -> Cursor { unsafe { Cursor { x: clang_getTypeDeclaration(self.x), } } } /// Get the canonical declaration of this type, if it is available. pub fn canonical_declaration( &self, location: Option<&Cursor>, ) -> Option { let mut declaration = self.declaration(); if !declaration.is_valid() { if let Some(location) = location { let mut location = *location; if let Some(referenced) = location.referenced() { location = referenced; } if location.is_template_like() { declaration = location; } } } let canonical = declaration.canonical(); if canonical.is_valid() && canonical.kind() != CXCursor_NoDeclFound { Some(CanonicalTypeDeclaration(*self, canonical)) } else { None } } /// Get a raw display name for this type. pub fn spelling(&self) -> String { let s = unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) }; // Clang 5.0 introduced changes in the spelling API so it returned the // full qualified name. Let's undo that here. if s.split("::").all(|s| is_valid_identifier(s)) { if let Some(s) = s.split("::").last() { return s.to_owned(); } } s } /// Is this type const qualified? pub fn is_const(&self) -> bool { unsafe { clang_isConstQualifiedType(self.x) != 0 } } #[inline] fn is_non_deductible_auto_type(&self) -> bool { debug_assert_eq!(self.kind(), CXType_Auto); self.canonical_type() == *self } #[inline] fn clang_size_of(&self, ctx: &BindgenContext) -> c_longlong { match self.kind() { // Work-around https://bugs.llvm.org/show_bug.cgi?id=40975 CXType_RValueReference | CXType_LValueReference => { ctx.target_pointer_size() as c_longlong } // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813 CXType_Auto if self.is_non_deductible_auto_type() => return -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() => return -6, _ => unsafe { clang_Type_getAlignOf(self.x) }, } } /// What is the size of this type? Paper over invalid types by returning `0` /// for them. pub fn size(&self, ctx: &BindgenContext) -> usize { let val = self.clang_size_of(ctx); if val < 0 { 0 } else { val as usize } } /// What is the size of this type? pub fn fallible_size( &self, ctx: &BindgenContext, ) -> Result { let val = self.clang_size_of(ctx); if val < 0 { Err(LayoutError::from(val as i32)) } else { Ok(val as usize) } } /// What is the alignment of this type? Paper over invalid types by /// returning `0`. pub fn align(&self, ctx: &BindgenContext) -> usize { let val = self.clang_align_of(ctx); if val < 0 { 0 } else { val as usize } } /// What is the alignment of this type? pub fn fallible_align( &self, ctx: &BindgenContext, ) -> Result { let val = self.clang_align_of(ctx); if val < 0 { Err(LayoutError::from(val as i32)) } else { Ok(val as usize) } } /// Get the layout for this type, or an error describing why it does not /// have a valid layout. pub fn fallible_layout( &self, ctx: &BindgenContext, ) -> Result { use crate::ir::layout::Layout; let size = self.fallible_size(ctx)?; let align = self.fallible_align(ctx)?; Ok(Layout::new(size, align)) } /// Get the number of template arguments this type has, or `None` if it is /// not some kind of template. pub fn num_template_args(&self) -> Option { let n = unsafe { clang_Type_getNumTemplateArguments(self.x) }; if n >= 0 { Some(n as u32) } else { debug_assert_eq!(n, -1); None } } /// If this type is a class template specialization, return its /// template arguments. Otherwise, return None. pub fn template_args(&self) -> Option { self.num_template_args().map(|n| TypeTemplateArgIterator { x: self.x, length: n, index: 0, }) } /// Given that this type is a function prototype, return the types of its parameters. /// /// Returns None if the type is not a function prototype. pub fn args(&self) -> Option> { self.num_args().ok().map(|num| { (0..num) .map(|i| Type { x: unsafe { clang_getArgType(self.x, i as c_uint) }, }) .collect() }) } /// Given that this type is a function prototype, return the number of arguments it takes. /// /// Returns Err if the type is not a function prototype. pub fn num_args(&self) -> Result { unsafe { let w = clang_getNumArgTypes(self.x); if w == -1 { Err(()) } else { Ok(w as u32) } } } /// Given that this type is a pointer type, return the type that it points /// to. pub fn pointee_type(&self) -> Option { match self.kind() { CXType_Pointer | CXType_RValueReference | CXType_LValueReference | CXType_MemberPointer | CXType_BlockPointer | CXType_ObjCObjectPointer => { let ret = Type { x: unsafe { clang_getPointeeType(self.x) }, }; debug_assert!(ret.is_valid()); Some(ret) } _ => None, } } /// Given that this type is an array, vector, or complex type, return the /// type of its elements. pub fn elem_type(&self) -> Option { let current_type = Type { x: unsafe { clang_getElementType(self.x) }, }; if current_type.is_valid() { Some(current_type) } else { None } } /// Given that this type is an array or vector type, return its number of /// elements. pub fn num_elements(&self) -> Option { let num_elements_returned = unsafe { clang_getNumElements(self.x) }; if num_elements_returned != -1 { Some(num_elements_returned as usize) } else { None } } /// Get the canonical version of this type. This sees through `typedef`s and /// aliases to get the underlying, canonical type. pub fn canonical_type(&self) -> Type { unsafe { Type { x: clang_getCanonicalType(self.x), } } } /// Is this type a variadic function type? pub fn is_variadic(&self) -> bool { unsafe { clang_isFunctionTypeVariadic(self.x) != 0 } } /// Given that this type is a function type, get the type of its return /// value. pub fn ret_type(&self) -> Option { let rt = Type { x: unsafe { clang_getResultType(self.x) }, }; if rt.is_valid() { Some(rt) } else { None } } /// Given that this type is a function type, get its calling convention. If /// this is not a function type, `CXCallingConv_Invalid` is returned. pub fn call_conv(&self) -> CXCallingConv { unsafe { clang_getFunctionTypeCallingConv(self.x) } } /// For elaborated types (types which use `class`, `struct`, or `union` to /// disambiguate types from local bindings), get the underlying type. pub fn named(&self) -> Type { unsafe { Type { x: clang_Type_getNamedType(self.x), } } } /// Is this a valid type? pub fn is_valid(&self) -> bool { self.kind() != CXType_Invalid } /// Is this a valid and exposed type? pub fn is_valid_and_exposed(&self) -> bool { self.is_valid() && self.kind() != CXType_Unexposed } /// Is this type a fully instantiated template? pub fn is_fully_instantiated_template(&self) -> bool { // Yep, the spelling of this containing type-parameter is extremely // nasty... But can happen in . Unfortunately I couldn't // reduce it enough :( self.template_args().map_or(false, |args| args.len() > 0) && match self.declaration().kind() { CXCursor_ClassTemplatePartialSpecialization | CXCursor_TypeAliasTemplateDecl | CXCursor_TemplateTemplateParameter => false, _ => true, } } /// Is this type an associated template type? Eg `T::Associated` in /// this example: /// /// ```c++ /// template /// class Foo { /// typename T::Associated member; /// }; /// ``` pub fn is_associated_type(&self) -> bool { // This is terrible :( fn hacky_parse_associated_type>(spelling: S) -> bool { lazy_static! { static ref ASSOC_TYPE_RE: regex::Regex = regex::Regex::new( r"typename type\-parameter\-\d+\-\d+::.+" ) .unwrap(); } ASSOC_TYPE_RE.is_match(spelling.as_ref()) } self.kind() == CXType_Unexposed && (hacky_parse_associated_type(self.spelling()) || hacky_parse_associated_type( self.canonical_type().spelling(), )) } } /// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its /// cursor is the canonical declaration for its type. If you have a /// `CanonicalTypeDeclaration` instance, you know for sure that the type and /// cursor match up in a canonical declaration relationship, and it simply /// cannot be otherwise. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct CanonicalTypeDeclaration(Type, Cursor); impl CanonicalTypeDeclaration { /// Get the type. pub fn ty(&self) -> &Type { &self.0 } /// Get the type's canonical declaration cursor. pub fn cursor(&self) -> &Cursor { &self.1 } } /// An iterator for a type's template arguments. pub struct TypeTemplateArgIterator { x: CXType, length: u32, index: u32, } impl Iterator for TypeTemplateArgIterator { type Item = Type; fn next(&mut self) -> Option { if self.index < self.length { let idx = self.index as c_uint; self.index += 1; Some(Type { x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) }, }) } else { None } } } impl ExactSizeIterator for TypeTemplateArgIterator { fn len(&self) -> usize { assert!(self.index <= self.length); (self.length - self.index) as usize } } /// A `SourceLocation` is a file, line, column, and byte offset location for /// some source text. pub struct SourceLocation { x: CXSourceLocation, } impl SourceLocation { /// Get the (file, line, column, byte offset) tuple for this source /// location. pub fn location(&self) -> (File, usize, usize, usize) { unsafe { let mut file = mem::zeroed(); let mut line = 0; let mut col = 0; let mut off = 0; clang_getSpellingLocation( self.x, &mut file, &mut line, &mut col, &mut off, ); (File { x: file }, line as usize, col as usize, off as usize) } } } impl fmt::Display for SourceLocation { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let (file, line, col, _) = self.location(); if let Some(name) = file.name() { write!(f, "{}:{}:{}", name, line, col) } else { "builtin definitions".fmt(f) } } } /// A comment in the source text. /// /// Comments are sort of parsed by Clang, and have a tree structure. pub struct Comment { x: CXComment, } impl Comment { /// What kind of comment is this? pub fn kind(&self) -> CXCommentKind { unsafe { clang_Comment_getKind(self.x) } } /// Get this comment's children comment pub fn get_children(&self) -> CommentChildrenIterator { CommentChildrenIterator { parent: self.x, length: unsafe { clang_Comment_getNumChildren(self.x) }, index: 0, } } /// Given that this comment is the start or end of an HTML tag, get its tag /// name. pub fn get_tag_name(&self) -> String { unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) } } /// Given that this comment is an HTML start tag, get its attributes. pub fn get_tag_attrs(&self) -> CommentAttributesIterator { CommentAttributesIterator { x: self.x, length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) }, index: 0, } } } /// An iterator for a comment's children pub struct CommentChildrenIterator { parent: CXComment, length: c_uint, index: c_uint, } impl Iterator for CommentChildrenIterator { type Item = Comment; fn next(&mut self) -> Option { if self.index < self.length { let idx = self.index; self.index += 1; Some(Comment { x: unsafe { clang_Comment_getChild(self.parent, idx) }, }) } else { None } } } /// An HTML start tag comment attribute pub struct CommentAttribute { /// HTML start tag attribute name pub name: String, /// HTML start tag attribute value pub value: String, } /// An iterator for a comment's attributes pub struct CommentAttributesIterator { x: CXComment, length: c_uint, index: c_uint, } impl Iterator for CommentAttributesIterator { type Item = CommentAttribute; fn next(&mut self) -> Option { if self.index < self.length { let idx = self.index; self.index += 1; Some(CommentAttribute { name: unsafe { cxstring_into_string(clang_HTMLStartTag_getAttrName( self.x, idx, )) }, value: unsafe { cxstring_into_string(clang_HTMLStartTag_getAttrValue( self.x, idx, )) }, }) } else { None } } } /// A source file. pub struct File { x: CXFile, } impl File { /// Get the name of this source file. pub fn name(&self) -> Option { if self.x.is_null() { return None; } Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) }) } } fn cxstring_to_string_leaky(s: CXString) -> String { if s.data.is_null() { return "".to_owned(); } let c_str = unsafe { CStr::from_ptr(clang_getCString(s) as *const _) }; c_str.to_string_lossy().into_owned() } fn cxstring_into_string(s: CXString) -> String { let ret = cxstring_to_string_leaky(s); unsafe { clang_disposeString(s) }; ret } /// An `Index` is an environment for a set of translation units that will /// typically end up linked together in one final binary. pub struct Index { x: CXIndex, } impl Index { /// Construct a new `Index`. /// /// The `pch` parameter controls whether declarations in pre-compiled /// headers are included when enumerating a translation unit's "locals". /// /// The `diag` parameter controls whether debugging diagnostics are enabled. pub fn new(pch: bool, diag: bool) -> Index { unsafe { Index { x: clang_createIndex(pch as c_int, diag as c_int), } } } } impl fmt::Debug for Index { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "Index {{ }}") } } impl Drop for Index { fn drop(&mut self) { unsafe { clang_disposeIndex(self.x); } } } /// A translation unit (or "compilation unit"). pub struct TranslationUnit { x: CXTranslationUnit, } impl fmt::Debug for TranslationUnit { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "TranslationUnit {{ }}") } } impl TranslationUnit { /// Parse a source file into a translation unit. pub fn parse( ix: &Index, file: &str, cmd_args: &[String], unsaved: &[UnsavedFile], opts: CXTranslationUnit_Flags, ) -> Option { let fname = CString::new(file).unwrap(); let _c_args: Vec = cmd_args .iter() .map(|s| CString::new(s.clone()).unwrap()) .collect(); let c_args: Vec<*const c_char> = _c_args.iter().map(|s| s.as_ptr()).collect(); let mut c_unsaved: Vec = unsaved.iter().map(|f| f.x).collect(); let tu = unsafe { clang_parseTranslationUnit( ix.x, fname.as_ptr(), c_args.as_ptr(), c_args.len() as c_int, c_unsaved.as_mut_ptr(), c_unsaved.len() as c_uint, opts, ) }; if tu.is_null() { None } else { Some(TranslationUnit { x: tu }) } } /// Get the Clang diagnostic information associated with this translation /// unit. pub fn diags(&self) -> Vec { unsafe { let num = clang_getNumDiagnostics(self.x) as usize; let mut diags = vec![]; for i in 0..num { diags.push(Diagnostic { x: clang_getDiagnostic(self.x, i as c_uint), }); } diags } } /// Get a cursor pointing to the root of this translation unit's AST. pub fn cursor(&self) -> Cursor { unsafe { Cursor { x: clang_getTranslationUnitCursor(self.x), } } } /// Is this the null translation unit? pub fn is_null(&self) -> bool { self.x.is_null() } } impl Drop for TranslationUnit { fn drop(&mut self) { unsafe { clang_disposeTranslationUnit(self.x); } } } /// A diagnostic message generated while parsing a translation unit. pub struct Diagnostic { x: CXDiagnostic, } impl Diagnostic { /// Format this diagnostic message as a string, using the given option bit /// flags. pub fn format(&self) -> String { unsafe { let opts = clang_defaultDiagnosticDisplayOptions(); cxstring_into_string(clang_formatDiagnostic(self.x, opts)) } } /// What is the severity of this diagnostic message? pub fn severity(&self) -> CXDiagnosticSeverity { unsafe { clang_getDiagnosticSeverity(self.x) } } } impl Drop for Diagnostic { /// Destroy this diagnostic message. fn drop(&mut self) { unsafe { clang_disposeDiagnostic(self.x); } } } /// A file which has not been saved to disk. pub struct UnsavedFile { x: CXUnsavedFile, /// The name of the unsaved file. Kept here to avoid leaving dangling pointers in /// `CXUnsavedFile`. pub name: CString, contents: CString, } impl UnsavedFile { /// Construct a new unsaved file with the given `name` and `contents`. pub fn new(name: &str, contents: &str) -> UnsavedFile { let name = CString::new(name).unwrap(); let contents = CString::new(contents).unwrap(); let x = CXUnsavedFile { Filename: name.as_ptr(), Contents: contents.as_ptr(), Length: contents.as_bytes().len() as c_ulong, }; UnsavedFile { x: x, name: name, contents: contents, } } } impl fmt::Debug for UnsavedFile { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!( fmt, "UnsavedFile(name: {:?}, contents: {:?})", self.name, self.contents ) } } /// Convert a cursor kind into a static string. pub fn kind_to_str(x: CXCursorKind) -> String { unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) } } /// Convert a type kind to a static string. pub fn type_to_str(x: CXTypeKind) -> String { unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) } } /// Dump the Clang AST to stdout for debugging purposes. pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { fn print_indent>(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!(" {}kind = {}", prefix, kind_to_str(c.kind())), ); print_indent( depth, format!(" {}spelling = \"{}\"", prefix, c.spelling()), ); print_indent(depth, format!(" {}location = {}", prefix, c.location())); print_indent( depth, format!(" {}is-definition? {}", prefix, c.is_definition()), ); print_indent( depth, format!(" {}is-declaration? {}", prefix, c.is_declaration()), ); print_indent( depth, format!( " {}is-inlined-function? {}", prefix, c.is_inlined_function() ), ); let templ_kind = c.template_kind(); if templ_kind != CXCursor_NoDeclFound { print_indent( depth, format!( " {}template-kind = {}", prefix, kind_to_str(templ_kind) ), ); } if let Some(usr) = c.usr() { print_indent(depth, format!(" {}usr = \"{}\"", prefix, usr)); } if let Ok(num) = c.num_args() { print_indent(depth, format!(" {}number-of-args = {}", prefix, num)); } if let Some(num) = c.num_template_args() { print_indent( depth, format!(" {}number-of-template-args = {}", prefix, num), ); } if let Some(width) = c.bit_width() { print_indent(depth, format!(" {}bit-width = {}", prefix, width)); } if let Some(ty) = c.enum_type() { print_indent( depth, format!(" {}enum-type = {}", prefix, type_to_str(ty.kind())), ); } if let Some(val) = c.enum_val_signed() { print_indent(depth, format!(" {}enum-val = {}", prefix, val)); } if let Some(ty) = c.typedef_type() { print_indent( depth, format!(" {}typedef-type = {}", prefix, type_to_str(ty.kind())), ); } if let Some(ty) = c.ret_type() { print_indent( depth, format!(" {}ret-type = {}", prefix, type_to_str(ty.kind())), ); } if let Some(refd) = c.referenced() { if refd != *c { println!(""); print_cursor( depth, String::from(prefix) + "referenced.", &refd, ); } } let canonical = c.canonical(); if canonical != *c { println!(""); print_cursor( depth, String::from(prefix) + "canonical.", &canonical, ); } if let Some(specialized) = c.specialized() { if specialized != *c { println!(""); print_cursor( depth, String::from(prefix) + "specialized.", &specialized, ); } } if let Some(parent) = c.fallible_semantic_parent() { println!(""); print_cursor( depth, String::from(prefix) + "semantic-parent.", &parent, ); } } fn print_type>(depth: isize, prefix: S, ty: &Type) { let prefix = prefix.as_ref(); let kind = ty.kind(); print_indent(depth, format!(" {}kind = {}", prefix, type_to_str(kind))); if kind == CXType_Invalid { return; } print_indent(depth, format!(" {}cconv = {}", prefix, ty.call_conv())); print_indent( depth, format!(" {}spelling = \"{}\"", prefix, ty.spelling()), ); let num_template_args = unsafe { clang_Type_getNumTemplateArguments(ty.x) }; if num_template_args >= 0 { print_indent( depth, format!( " {}number-of-template-args = {}", prefix, num_template_args ), ); } if let Some(num) = ty.num_elements() { print_indent( depth, format!(" {}number-of-elements = {}", prefix, num), ); } print_indent( depth, format!(" {}is-variadic? {}", prefix, ty.is_variadic()), ); let canonical = ty.canonical_type(); if canonical != *ty { println!(""); print_type(depth, String::from(prefix) + "canonical.", &canonical); } if let Some(pointee) = ty.pointee_type() { if pointee != *ty { println!(""); print_type(depth, String::from(prefix) + "pointee.", &pointee); } } if let Some(elem) = ty.elem_type() { if elem != *ty { println!(""); print_type(depth, String::from(prefix) + "elements.", &elem); } } if let Some(ret) = ty.ret_type() { if ret != *ty { println!(""); print_type(depth, String::from(prefix) + "return.", &ret); } } let named = ty.named(); if named != *ty && named.is_valid() { println!(""); print_type(depth, String::from(prefix) + "named.", &named); } } print_indent(depth, "("); print_cursor(depth, "", c); println!(""); let ty = c.cur_type(); print_type(depth, "type.", &ty); let declaration = ty.declaration(); if declaration != *c && declaration.kind() != CXCursor_NoDeclFound { println!(""); print_cursor(depth, "type.declaration.", &declaration); } // Recurse. let mut found_children = false; c.visit(|s| { if !found_children { println!(""); found_children = true; } ast_dump(&s, depth + 1) }); print_indent(depth, ")"); CXChildVisit_Continue } /// Try to extract the clang version to a string pub fn extract_clang_version() -> String { unsafe { cxstring_into_string(clang_getClangVersion()) } } /// A wrapper for the result of evaluating an expression. #[derive(Debug)] pub struct EvalResult { x: CXEvalResult, } impl EvalResult { /// Evaluate `cursor` and return the result. pub fn new(cursor: Cursor) -> Option { // Work around https://bugs.llvm.org/show_bug.cgi?id=42532, see: // * https://github.com/rust-lang/rust-bindgen/issues/283 // * https://github.com/rust-lang/rust-bindgen/issues/1590 { let mut found_cant_eval = false; cursor.visit(|c| { if c.kind() == CXCursor_TypeRef && c.cur_type().canonical_type().kind() == CXType_Unexposed { found_cant_eval = true; return CXChildVisit_Break; } CXChildVisit_Recurse }); if found_cant_eval { return None; } } Some(EvalResult { x: unsafe { clang_Cursor_Evaluate(cursor.x) }, }) } fn kind(&self) -> CXEvalResultKind { unsafe { clang_EvalResult_getKind(self.x) } } /// Try to get back the result as a double. pub fn as_double(&self) -> Option { match self.kind() { CXEval_Float => { Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64) } _ => None, } } /// Try to get back the result as an integer. pub fn as_int(&self) -> Option { if self.kind() != CXEval_Int { return None; } if !clang_EvalResult_isUnsignedInt::is_loaded() { // FIXME(emilio): There's no way to detect underflow here, and clang // will just happily give us a value. return Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i64); } if unsafe { clang_EvalResult_isUnsignedInt(self.x) } != 0 { let value = unsafe { clang_EvalResult_getAsUnsigned(self.x) }; if value > i64::max_value() as c_ulonglong { return None; } return Some(value as i64); } let value = unsafe { clang_EvalResult_getAsLongLong(self.x) }; if value > i64::max_value() as c_longlong { return None; } if value < i64::min_value() as c_longlong { return None; } Some(value as i64) } /// Evaluates the expression as a literal string, that may or may not be /// valid utf-8. pub fn as_literal_string(&self) -> Option> { match self.kind() { CXEval_StrLiteral => { let ret = unsafe { CStr::from_ptr(clang_EvalResult_getAsStr(self.x)) }; Some(ret.to_bytes().to_vec()) } _ => None, } } } impl Drop for EvalResult { fn drop(&mut self) { unsafe { clang_EvalResult_dispose(self.x) }; } } /// Target information obtained from libclang. #[derive(Debug)] pub struct TargetInfo { /// The target triple. pub triple: String, /// The width of the pointer _in bits_. pub pointer_width: usize, } impl TargetInfo { /// Tries to obtain target information from libclang. pub fn new(tu: &TranslationUnit) -> Option { if !clang_getTranslationUnitTargetInfo::is_loaded() { return None; } 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); Some(TargetInfo { triple, pointer_width: pointer_width as usize, }) } } bindgen-0.59.1/src/codegen/bitfield_unit.rs000075500000000000000000000052260000000000000166750ustar 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] pub fn get_bit(&self, index: usize) -> bool { debug_assert!(index / 8 < self.storage.as_ref().len()); let byte_index = index / 8; let byte = self.storage.as_ref()[byte_index]; let bit_index = if cfg!(target_endian = "big") { 7 - (index % 8) } else { index % 8 }; let mask = 1 << bit_index; byte & mask == mask } #[inline] pub fn set_bit(&mut self, index: usize, val: bool) { debug_assert!(index / 8 < self.storage.as_ref().len()); let byte_index = index / 8; let byte = &mut self.storage.as_mut()[byte_index]; let bit_index = if cfg!(target_endian = "big") { 7 - (index % 8) } else { index % 8 }; let mask = 1 << bit_index; if val { *byte |= mask; } else { *byte &= !mask; } } #[inline] pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { debug_assert!(bit_width <= 64); debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); debug_assert!( (bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len() ); let mut val = 0; for i in 0..(bit_width as usize) { if self.get_bit(i + bit_offset) { let index = if cfg!(target_endian = "big") { bit_width as usize - 1 - i } else { i }; val |= 1 << index; } } val } #[inline] pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { debug_assert!(bit_width <= 64); debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); debug_assert!( (bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len() ); for i in 0..(bit_width as usize) { let mask = 1 << i; let val_bit_is_set = val & mask == mask; let index = if cfg!(target_endian = "big") { bit_width as usize - 1 - i } else { i }; self.set_bit(index + bit_offset, val_bit_is_set); } } } bindgen-0.59.1/src/codegen/bitfield_unit_tests.rs000064400000000000000000000200060000000000000201050ustar 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 = {:064b}", expected); println!("actual = {:064b}", actual); assert_eq!(expected, actual); })* } } } bitfield_unit_get! { // Let's just exhaustively test getting the bits from a single byte, since // there are few enough combinations... With [0b11100010], then get(0, 1) is 0; With [0b11100010], then get(1, 1) is 1; With [0b11100010], then get(2, 1) is 0; With [0b11100010], then get(3, 1) is 0; With [0b11100010], then get(4, 1) is 0; With [0b11100010], then get(5, 1) is 1; With [0b11100010], then get(6, 1) is 1; With [0b11100010], then get(7, 1) is 1; With [0b11100010], then get(0, 2) is 0b10; With [0b11100010], then get(1, 2) is 0b01; With [0b11100010], then get(2, 2) is 0b00; With [0b11100010], then get(3, 2) is 0b00; With [0b11100010], then get(4, 2) is 0b10; With [0b11100010], then get(5, 2) is 0b11; With [0b11100010], then get(6, 2) is 0b11; With [0b11100010], then get(0, 3) is 0b010; With [0b11100010], then get(1, 3) is 0b001; With [0b11100010], then get(2, 3) is 0b000; With [0b11100010], then get(3, 3) is 0b100; With [0b11100010], then get(4, 3) is 0b110; With [0b11100010], then get(5, 3) is 0b111; With [0b11100010], then get(0, 4) is 0b0010; With [0b11100010], then get(1, 4) is 0b0001; With [0b11100010], then get(2, 4) is 0b1000; With [0b11100010], then get(3, 4) is 0b1100; With [0b11100010], then get(4, 4) is 0b1110; With [0b11100010], then get(0, 5) is 0b00010; With [0b11100010], then get(1, 5) is 0b10001; With [0b11100010], then get(2, 5) is 0b11000; With [0b11100010], then get(3, 5) is 0b11100; With [0b11100010], then get(0, 6) is 0b100010; With [0b11100010], then get(1, 6) is 0b110001; With [0b11100010], then get(2, 6) is 0b111000; With [0b11100010], then get(0, 7) is 0b1100010; With [0b11100010], then get(1, 7) is 0b1110001; With [0b11100010], then get(0, 8) is 0b11100010; // OK. Now let's test getting bits from across byte boundaries. With [0b01010101, 0b11111111, 0b00000000, 0b11111111], then get(0, 16) is 0b1111111101010101; With [0b01010101, 0b11111111, 0b00000000, 0b11111111], then get(1, 16) is 0b0111111110101010; With [0b01010101, 0b11111111, 0b00000000, 0b11111111], then get(2, 16) is 0b0011111111010101; With [0b01010101, 0b11111111, 0b00000000, 0b11111111], then get(3, 16) is 0b0001111111101010; With [0b01010101, 0b11111111, 0b00000000, 0b11111111], then get(4, 16) is 0b0000111111110101; With [0b01010101, 0b11111111, 0b00000000, 0b11111111], then get(5, 16) is 0b0000011111111010; With [0b01010101, 0b11111111, 0b00000000, 0b11111111], then get(6, 16) is 0b0000001111111101; With [0b01010101, 0b11111111, 0b00000000, 0b11111111], then get(7, 16) is 0b0000000111111110; With [0b01010101, 0b11111111, 0b00000000, 0b11111111], then get(8, 16) is 0b0000000011111111; } macro_rules! bitfield_unit_set { ( $( set($start:expr, $len:expr, $val:expr) is $expected:expr; )* ) => { #[test] fn bitfield_unit_set() { $( let mut unit = __BindgenBitfieldUnit::<[u8; 4]>::new([0, 0, 0, 0]); unit.set($start, $len, $val); let actual = unit.get(0, 32); println!(); println!("set({}, {}, {:032b}", $start, $len, $val); println!("expected = {:064b}", $expected); println!("actual = {:064b}", actual); assert_eq!($expected, actual); )* } } } bitfield_unit_set! { // Once again, let's exhaustively test single byte combinations. set(0, 1, 0b11111111) is 0b00000001; set(1, 1, 0b11111111) is 0b00000010; set(2, 1, 0b11111111) is 0b00000100; set(3, 1, 0b11111111) is 0b00001000; set(4, 1, 0b11111111) is 0b00010000; set(5, 1, 0b11111111) is 0b00100000; set(6, 1, 0b11111111) is 0b01000000; set(7, 1, 0b11111111) is 0b10000000; set(0, 2, 0b11111111) is 0b00000011; set(1, 2, 0b11111111) is 0b00000110; set(2, 2, 0b11111111) is 0b00001100; set(3, 2, 0b11111111) is 0b00011000; set(4, 2, 0b11111111) is 0b00110000; set(5, 2, 0b11111111) is 0b01100000; set(6, 2, 0b11111111) is 0b11000000; set(0, 3, 0b11111111) is 0b00000111; set(1, 3, 0b11111111) is 0b00001110; set(2, 3, 0b11111111) is 0b00011100; set(3, 3, 0b11111111) is 0b00111000; set(4, 3, 0b11111111) is 0b01110000; set(5, 3, 0b11111111) is 0b11100000; set(0, 4, 0b11111111) is 0b00001111; set(1, 4, 0b11111111) is 0b00011110; set(2, 4, 0b11111111) is 0b00111100; set(3, 4, 0b11111111) is 0b01111000; set(4, 4, 0b11111111) is 0b11110000; set(0, 5, 0b11111111) is 0b00011111; set(1, 5, 0b11111111) is 0b00111110; set(2, 5, 0b11111111) is 0b01111100; set(3, 5, 0b11111111) is 0b11111000; set(0, 6, 0b11111111) is 0b00111111; set(1, 6, 0b11111111) is 0b01111110; set(2, 6, 0b11111111) is 0b11111100; set(0, 7, 0b11111111) is 0b01111111; set(1, 7, 0b11111111) is 0b11111110; set(0, 8, 0b11111111) is 0b11111111; // And, now let's cross byte boundaries. set(0, 16, 0b1111111111111111) is 0b00000000000000001111111111111111; set(1, 16, 0b1111111111111111) is 0b00000000000000011111111111111110; set(2, 16, 0b1111111111111111) is 0b00000000000000111111111111111100; set(3, 16, 0b1111111111111111) is 0b00000000000001111111111111111000; set(4, 16, 0b1111111111111111) is 0b00000000000011111111111111110000; set(5, 16, 0b1111111111111111) is 0b00000000000111111111111111100000; set(6, 16, 0b1111111111111111) is 0b00000000001111111111111111000000; set(7, 16, 0b1111111111111111) is 0b00000000011111111111111110000000; set(8, 16, 0b1111111111111111) is 0b00000000111111111111111100000000; } bindgen-0.59.1/src/codegen/dyngen.rs000064400000000000000000000125660000000000000153420ustar 00000000000000use crate::codegen; use crate::ir::function::Abi; use proc_macro2::Ident; /// Used to build the output tokens for dynamic bindings. #[derive(Default)] pub struct DynamicItems { /// Tracks the tokens that will appears inside the library struct -- e.g.: /// ```ignore /// struct Lib { /// __library: ::libloading::Library, /// pub x: Result, // <- 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 fn new() -> Self { Self::default() } pub fn get_tokens(&self, lib_ident: Ident) -> proc_macro2::TokenStream { let struct_members = &self.struct_members; let constructor_inits = &self.constructor_inits; let init_fields = &self.init_fields; let struct_implementation = &self.struct_implementation; quote! { extern crate libloading; pub struct #lib_ident { __library: ::libloading::Library, #(#struct_members)* } impl #lib_ident { pub unsafe fn new

( path: P ) -> Result where P: AsRef<::std::ffi::OsStr> { let library = ::libloading::Library::new(path)?; Self::from_library(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 )* } } } pub fn push( &mut self, ident: Ident, abi: Abi, is_variadic: bool, is_required: bool, args: Vec, args_identifiers: Vec, ret: proc_macro2::TokenStream, ret_ty: proc_macro2::TokenStream, ) { if !is_variadic { assert_eq!(args.len(), args_identifiers.len()); } let signature = quote! { unsafe extern #abi fn ( #( #args),* ) #ret }; let member = if is_required { signature } else { quote! { Result<#signature, ::libloading::Error> } }; self.struct_members.push(quote! { pub #ident: #member, }); // N.B: If the signature was required, it won't be wrapped in a Result<...> // and we can simply call it directly. let fn_ = if is_required { quote! { self.#ident } } else { quote! { self.#ident.as_ref().expect("Expected function, got error.") } }; let call_body = quote! { (#fn_)(#( #args_identifiers ),*) }; // We can't implement variadic functions from C easily, so we allow to // access the function pointer so that the user can call it just fine. if !is_variadic { self.struct_implementation.push(quote! { pub unsafe fn #ident ( &self, #( #args ),* ) -> #ret_ty { #call_body } }); } // N.B: Unwrap the signature upon construction if it is required to be resolved. let ident_str = codegen::helpers::ast_ty::cstr_expr(ident.to_string()); self.constructor_inits.push(if is_required { quote! { let #ident = __library.get(#ident_str).map(|sym| *sym)?; } } else { quote! { let #ident = __library.get(#ident_str).map(|sym| *sym); } }); self.init_fields.push(quote! { #ident }); } } bindgen-0.59.1/src/codegen/error.rs000064400000000000000000000020550000000000000151770ustar 00000000000000use std::error; use std::fmt; /// Errors that can occur during code generation. #[derive(Clone, Debug, PartialEq, Eq)] pub enum Error { /// Tried to generate an opaque blob for a type that did not have a layout. NoLayoutForOpaqueBlob, /// Tried to instantiate an opaque template definition, or a template /// definition that is too difficult for us to understand (like a partial /// template specialization). InstantiationOfOpaqueType, } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(match *self { Error::NoLayoutForOpaqueBlob => { "Tried to generate an opaque blob, but had no layout" } Error::InstantiationOfOpaqueType => { "Instantiation of opaque template type or partial template \ specialization" } }) } } impl error::Error for Error {} /// A `Result` of `T` or an error of `bindgen::codegen::error::Error`. pub type Result = ::std::result::Result; bindgen-0.59.1/src/codegen/helpers.rs000064400000000000000000000214070000000000000155120ustar 00000000000000//! Helpers for code generation that don't need macro expansion. use crate::ir::context::BindgenContext; use crate::ir::layout::Layout; use proc_macro2::{Ident, Span, TokenStream}; use quote::TokenStreamExt; pub mod attributes { use proc_macro2::{Ident, Span, TokenStream}; use std::str::FromStr; pub fn repr(which: &str) -> TokenStream { let which = Ident::new(which, Span::call_site()); quote! { #[repr( #which )] } } pub fn repr_list(which_ones: &[&str]) -> TokenStream { let which_ones = which_ones .iter() .cloned() .map(|one| TokenStream::from_str(one).expect("repr to be valid")); quote! { #[repr( #( #which_ones ),* )] } } pub fn derives(which_ones: &[&str]) -> TokenStream { let which_ones = which_ones .iter() .cloned() .map(|one| Ident::new(one, Span::call_site())); quote! { #[derive( #( #which_ones ),* )] } } pub fn inline() -> TokenStream { quote! { #[inline] } } pub fn must_use() -> TokenStream { quote! { #[must_use] } } pub fn non_exhaustive() -> TokenStream { quote! { #[non_exhaustive] } } pub fn doc(comment: String) -> TokenStream { // NOTE(emilio): By this point comments are already preprocessed and in // `///` form. Quote turns them into `#[doc]` comments, but oh well. TokenStream::from_str(&comment).unwrap() } pub fn link_name(name: &str) -> TokenStream { // LLVM mangles the name by default but it's already mangled. // Prefixing the name with \u{1} should tell LLVM to not mangle it. let name = format!("\u{1}{}", name); quote! { #[link_name = #name] } } } /// Generates a proper type for a field or type with a given `Layout`, that is, /// a type with the correct size and alignment restrictions. pub fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream { let opaque = layout.opaque(); // FIXME(emilio, #412): We fall back to byte alignment, but there are // some things that legitimately are more than 8-byte aligned. // // Eventually we should be able to `unwrap` here, but... let ty_name = match opaque.known_rust_type_for_array(ctx) { Some(ty) => ty, None => { warn!("Found unknown alignment on code generation!"); "u8" } }; let ty_name = Ident::new(ty_name, Span::call_site()); let data_len = opaque.array_size(ctx).unwrap_or(layout.size); if data_len == 1 { quote! { #ty_name } } else { quote! { [ #ty_name ; #data_len ] } } } /// Integer type of the same size as the given `Layout`. pub fn integer_type( ctx: &BindgenContext, layout: Layout, ) -> Option { let name = Layout::known_type_for_size(ctx, layout.size)?; let name = Ident::new(name, Span::call_site()); Some(quote! { #name }) } /// Generates a bitfield allocation unit type for a type with the given `Layout`. pub fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> TokenStream { let mut tokens = quote! {}; if ctx.options().enable_cxx_namespaces { tokens.append_all(quote! { root:: }); } let size = layout.size; tokens.append_all(quote! { __BindgenBitfieldUnit<[u8; #size]> }); tokens } pub mod ast_ty { use crate::ir::context::BindgenContext; use crate::ir::function::FunctionSig; use crate::ir::layout::Layout; use crate::ir::ty::FloatKind; use proc_macro2::{self, TokenStream}; use std::str::FromStr; pub fn c_void(ctx: &BindgenContext) -> TokenStream { // ctypes_prefix takes precedence match ctx.options().ctypes_prefix { Some(ref prefix) => { let prefix = TokenStream::from_str(prefix.as_str()).unwrap(); quote! { #prefix::c_void } } None => { if ctx.options().use_core && ctx.options().rust_features.core_ffi_c_void { quote! { ::core::ffi::c_void } } else { quote! { ::std::os::raw::c_void } } } } } pub fn raw_type(ctx: &BindgenContext, name: &str) -> TokenStream { let ident = ctx.rust_ident_raw(name); match ctx.options().ctypes_prefix { Some(ref prefix) => { let prefix = TokenStream::from_str(prefix.as_str()).unwrap(); quote! { #prefix::#ident } } None => quote! { ::std::os::raw::#ident }, } } pub fn float_kind_rust_type( ctx: &BindgenContext, fk: FloatKind, layout: Option, ) -> TokenStream { // TODO: we probably should take the type layout into account more // often? // // Also, maybe this one shouldn't be the default? match (fk, ctx.options().convert_floats) { (FloatKind::Float, true) => quote! { f32 }, (FloatKind::Double, true) => quote! { f64 }, (FloatKind::Float, false) => raw_type(ctx, "c_float"), (FloatKind::Double, false) => raw_type(ctx, "c_double"), (FloatKind::LongDouble, _) => { match layout { Some(layout) => { match layout.size { 4 => quote! { f32 }, 8 => quote! { f64 }, // TODO(emilio): If rust ever gains f128 we should // use it here and below. _ => super::integer_type(ctx, layout) .unwrap_or(quote! { f64 }), } } None => { debug_assert!( false, "How didn't we know the layout for a primitive type?" ); quote! { f64 } } } } (FloatKind::Float128, _) => { if ctx.options().rust_features.i128_and_u128 { quote! { u128 } } else { quote! { [u64; 2] } } } } } pub fn int_expr(val: i64) -> TokenStream { // Don't use quote! { #val } because that adds the type suffix. let val = proc_macro2::Literal::i64_unsuffixed(val); quote!(#val) } pub fn uint_expr(val: u64) -> TokenStream { // Don't use quote! { #val } because that adds the type suffix. let val = proc_macro2::Literal::u64_unsuffixed(val); quote!(#val) } pub fn byte_array_expr(bytes: &[u8]) -> TokenStream { let mut bytes: Vec<_> = bytes.iter().cloned().collect(); bytes.push(0); quote! { [ #(#bytes),* ] } } pub fn cstr_expr(mut string: String) -> TokenStream { string.push('\0'); let b = proc_macro2::Literal::byte_string(&string.as_bytes()); quote! { #b } } pub fn float_expr(ctx: &BindgenContext, f: f64) -> Result { if f.is_finite() { let val = proc_macro2::Literal::f64_unsuffixed(f); return Ok(quote!(#val)); } let prefix = ctx.trait_prefix(); if f.is_nan() { return Ok(quote! { ::#prefix::f64::NAN }); } if f.is_infinite() { return Ok(if f.is_sign_positive() { quote! { ::#prefix::f64::INFINITY } } else { quote! { ::#prefix::f64::NEG_INFINITY } }); } warn!("Unknown non-finite float number: {:?}", f); return Err(()); } pub fn arguments_from_signature( signature: &FunctionSig, ctx: &BindgenContext, ) -> Vec { let mut unnamed_arguments = 0; signature .argument_types() .iter() .map(|&(ref name, _ty)| match *name { Some(ref name) => { let name = ctx.rust_ident(name); quote! { #name } } None => { unnamed_arguments += 1; let name = ctx.rust_ident(format!("arg{}", unnamed_arguments)); quote! { #name } } }) .collect() } } bindgen-0.59.1/src/codegen/impl_debug.rs000064400000000000000000000203530000000000000161560ustar 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 proc_macro2; pub fn gen_debug_impl( ctx: &BindgenContext, fields: &[Field], item: &Item, kind: CompKind, ) -> proc_macro2::TokenStream { let struct_name = item.canonical_name(ctx); let mut format_string = format!("{} {{{{ ", struct_name); let mut tokens = vec![]; if item.is_opaque(ctx, &()) { format_string.push_str("opaque"); } else { match kind { CompKind::Union => { format_string.push_str("union"); } CompKind::Struct => { let processed_fields = fields.iter().filter_map(|f| match f { &Field::DataMember(ref fd) => fd.impl_debug(ctx, ()), &Field::Bitfields(ref bu) => bu.impl_debug(ctx, ()), }); for (i, (fstring, toks)) in processed_fields.enumerate() { if i > 0 { format_string.push_str(", "); } tokens.extend(toks); format_string.push_str(&fstring); } } } } format_string.push_str(" }}"); tokens.insert(0, quote! { #format_string }); let prefix = ctx.trait_prefix(); quote! { fn fmt(&self, f: &mut ::#prefix::fmt::Formatter<'_>) -> ::#prefix ::fmt::Result { write!(f, #( #tokens ),*) } } } /// A trait for the things which we can codegen tokens that contribute towards a /// generated `impl Debug`. pub trait ImplDebug<'a> { /// Any extra parameter required by this a particular `ImplDebug` implementation. type Extra; /// Generate a format string snippet to be included in the larger `impl Debug` /// format string, and the code to get the format string's interpolation values. fn impl_debug( &self, ctx: &BindgenContext, extra: Self::Extra, ) -> Option<(String, Vec)>; } impl<'a> ImplDebug<'a> 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<'a> ImplDebug<'a> 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() { format_string.push_str(&format!("{} : {{:?}}", bitfield_name)); let getter_name = bitfield.getter_name(); let name_ident = ctx.rust_ident_raw(getter_name); tokens.push(quote! { self.#name_ident () }); } } Some((format_string, tokens)) } } impl<'a> ImplDebug<'a> for Item { type Extra = &'a str; fn impl_debug( &self, ctx: &BindgenContext, name: &str, ) -> Option<(String, Vec)> { let name_ident = ctx.rust_ident(name); // We don't know if blocklisted items `impl Debug` or not, so we can't // add them to the format string we're building up. if !ctx.allowlisted_items().contains(&self.id()) { return None; } let ty = match self.as_type() { Some(ty) => ty, None => { return None; } }; fn debug_print( name: &str, name_ident: proc_macro2::TokenStream, ) -> Option<(String, Vec)> { Some(( format!("{}: {{:?}}", name), vec![quote! { self.#name_ident }], )) } match *ty.kind() { // Handle the simple cases. TypeKind::Void | TypeKind::NullPtr | TypeKind::Int(..) | TypeKind::Float(..) | TypeKind::Complex(..) | TypeKind::Function(..) | TypeKind::Enum(..) | TypeKind::Reference(..) | TypeKind::UnresolvedTypeRef(..) | TypeKind::ObjCInterface(..) | TypeKind::ObjCId | TypeKind::Comp(..) | TypeKind::ObjCSel => debug_print(name, quote! { #name_ident }), TypeKind::TemplateInstantiation(ref inst) => { if inst.is_opaque(ctx, self) { Some((format!("{}: opaque", name), vec![])) } else { debug_print(name, quote! { #name_ident }) } } // The generic is not required to implement Debug, so we can not debug print that type TypeKind::TypeParam => { Some((format!("{}: Non-debuggable generic", name), vec![])) } TypeKind::Array(_, len) => { // Generics are not required to implement Debug if self.has_type_param_in_array(ctx) { Some(( format!("{}: Array with length {}", name, len), vec![], )) } else if len < RUST_DERIVE_IN_ARRAY_LIMIT || ctx.options().rust_features().larger_arrays { // The simple case debug_print(name, quote! { #name_ident }) } else { if ctx.options().use_core { // There is no String in core; reducing field visibility to avoid breaking // no_std setups. Some((format!("{}: [...]", name), vec![])) } else { // Let's implement our own print function Some(( format!("{}: [{{}}]", name), vec![quote! { self.#name_ident .iter() .enumerate() .map(|(i, v)| format!("{}{:?}", if i > 0 { ", " } else { "" }, v)) .collect::() }], )) } } } TypeKind::Vector(_, len) => { if ctx.options().use_core { // There is no format! in core; reducing field visibility to avoid breaking // no_std setups. Some((format!("{}(...)", name), vec![])) } else { let self_ids = 0..len; Some(( format!("{}({{}})", name), vec![quote! { #(format!("{:?}", self.#self_ids)),* }], )) } } TypeKind::ResolvedTypeRef(t) | TypeKind::TemplateAlias(t, _) | TypeKind::Alias(t) | TypeKind::BlockPointer(t) => { // We follow the aliases ctx.resolve_item(t).impl_debug(ctx, name) } TypeKind::Pointer(inner) => { let inner_type = ctx.resolve_type(inner).canonical_type(ctx); match *inner_type.kind() { TypeKind::Function(ref sig) if !sig.function_pointers_can_derive() => { Some((format!("{}: FunctionPointer", name), vec![])) } _ => debug_print(name, quote! { #name_ident }), } } TypeKind::Opaque => None, } } } bindgen-0.59.1/src/codegen/impl_partialeq.rs000064400000000000000000000106730000000000000170560ustar 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}; use proc_macro2; /// Generate a manual implementation of `PartialEq` trait for the /// specified compound type. pub fn gen_partialeq_impl( ctx: &BindgenContext, comp_info: &CompInfo, item: &Item, ty_for_impl: &proc_macro2::TokenStream, ) -> Option { let mut tokens = vec![]; if item.is_opaque(ctx, &()) { tokens.push(quote! { &self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..] }); } else if comp_info.kind() == CompKind::Union { assert!(!ctx.options().rust_features().untagged_union); tokens.push(quote! { &self.bindgen_union_field[..] == &other.bindgen_union_field[..] }); } else { for base in comp_info.base_members().iter() { if !base.requires_storage(ctx) { continue; } let ty_item = ctx.resolve_item(base.ty); let field_name = &base.field_name; if ty_item.is_opaque(ctx, &()) { let field_name = ctx.rust_ident(field_name); tokens.push(quote! { &self. #field_name [..] == &other. #field_name [..] }); } else { tokens.push(gen_field(ctx, ty_item, field_name)); } } for field in comp_info.fields() { match *field { Field::DataMember(ref fd) => { let ty_item = ctx.resolve_item(fd.ty()); let name = fd.name().unwrap(); tokens.push(gen_field(ctx, ty_item, name)); } Field::Bitfields(ref bu) => { for bitfield in bu.bitfields() { if let Some(_) = bitfield.name() { 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.59.1/src/codegen/mod.rs000064400000000000000000004750500000000000000146360ustar 00000000000000mod dyngen; mod error; mod helpers; mod impl_debug; mod impl_partialeq; pub mod struct_layout; #[cfg(test)] #[allow(warnings)] pub(crate) mod bitfield_unit; #[cfg(all(test, target_endian = "little"))] mod bitfield_unit_tests; use self::dyngen::DynamicItems; use self::helpers::attributes; use self::struct_layout::StructLayoutTracker; use super::BindgenOptions; use crate::ir::analysis::{HasVtable, Sizedness}; use crate::ir::annotations::FieldAccessorKind; use crate::ir::comment; use crate::ir::comp::{ Base, Bitfield, BitfieldUnit, CompInfo, CompKind, Field, FieldData, FieldMethods, Method, MethodKind, }; use crate::ir::context::{BindgenContext, ItemId}; use crate::ir::derive::{ CanDerive, CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq, CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd, }; use crate::ir::dot; use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue}; use crate::ir::function::{Abi, Function, FunctionKind, FunctionSig, Linkage}; use crate::ir::int::IntKind; use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath}; use crate::ir::item_kind::ItemKind; use crate::ir::layout::Layout; use crate::ir::module::Module; use crate::ir::objc::{ObjCInterface, ObjCMethod}; use crate::ir::template::{ AsTemplateParam, TemplateInstantiation, TemplateParameters, }; use crate::ir::ty::{Type, TypeKind}; use crate::ir::var::Var; use proc_macro2::{self, Ident, Span}; use quote::TokenStreamExt; use crate::{Entry, HashMap, HashSet}; use std; use std::borrow::Cow; use std::cell::Cell; use std::collections::VecDeque; use std::fmt::Write; use std::iter; use std::ops; use std::str::FromStr; // Name of type defined in constified enum module pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &'static 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! { 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) -> DerivableTraits { let mut derivable_traits = DerivableTraits::empty(); 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; } let all_template_params = item.all_template_params(ctx); if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() { derivable_traits |= DerivableTraits::COPY; if ctx.options().rust_features().builtin_clone_impls || !all_template_params.is_empty() { // FIXME: This requires extra logic if you have a big array in a // templated struct. The reason for this is that the magic: // fn clone(&self) -> Self { *self } // doesn't work for templates. // // It's not hard to fix though. derivable_traits |= DerivableTraits::CLONE; } } 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 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, } 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(), } } 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<'a> ops::Deref for CodegenResult<'a> { type Target = Vec; fn deref(&self) -> &Self::Target { &self.items } } impl<'a> ops::DerefMut for CodegenResult<'a> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.items } } /// A trait to convert a rust type into a pointer, optionally const, to the same /// type. trait ToPtr { fn to_ptr(self, is_const: bool) -> proc_macro2::TokenStream; } impl ToPtr for proc_macro2::TokenStream { fn to_ptr(self, is_const: bool) -> proc_macro2::TokenStream { if is_const { quote! { *const #self } } else { quote! { *mut #self } } } } /// An extension trait for `proc_macro2::TokenStream` that lets us append any implicit /// template parameters that exist for some type, if necessary. trait AppendImplicitTemplateParams { fn append_implicit_template_params( &mut self, ctx: &BindgenContext, item: &Item, ); } impl AppendImplicitTemplateParams for proc_macro2::TokenStream { fn append_implicit_template_params( &mut self, ctx: &BindgenContext, item: &Item, ) { let item = item.id().into_resolver().through_type_refs().resolve(ctx); match *item.expect_type().kind() { TypeKind::UnresolvedTypeRef(..) => { unreachable!("already resolved unresolved type refs") } TypeKind::ResolvedTypeRef(..) => { unreachable!("we resolved item through type refs") } // None of these types ever have implicit template parameters. TypeKind::Void | TypeKind::NullPtr | TypeKind::Pointer(..) | TypeKind::Reference(..) | TypeKind::Int(..) | TypeKind::Float(..) | TypeKind::Complex(..) | TypeKind::Array(..) | TypeKind::TypeParam | TypeKind::Opaque | TypeKind::Function(..) | TypeKind::Enum(..) | TypeKind::ObjCId | TypeKind::ObjCSel | TypeKind::TemplateInstantiation(..) => return, _ => {} } let params: Vec<_> = item .used_template_params(ctx) .iter() .map(|p| { p.try_to_rust_ty(ctx, &()) .expect("template params cannot fail to be a rust type") }) .collect(); if !params.is_empty() { self.append_all(quote! { < #( #params ),* > }); } } } trait CodeGenerator { /// Extra information from the caller. type Extra; /// Extra information returned to the caller. type Return; fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, extra: &Self::Extra, ) -> Self::Return; } impl Item { fn process_before_codegen( &self, ctx: &BindgenContext, result: &mut CodegenResult, ) -> bool { if !self.is_enabled_for_codegen(ctx) { return false; } if self.is_blocklisted(ctx) || result.seen(self.id()) { debug!( "::process_before_codegen: Ignoring hidden or seen: \ self = {:?}", self ); return false; } if !ctx.codegen_items().contains(&self.id()) { // TODO(emilio, #453): Figure out what to do when this happens // legitimately, we could track the opaque stuff and disable the // assertion there I guess. warn!("Found non-allowlisted item in code generation: {:?}", self); } result.set_seen(self.id()); true } } impl CodeGenerator for Item { type Extra = (); type Return = (); fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, _extra: &(), ) { debug!("::codegen: self = {:?}", self); if !self.process_before_codegen(ctx, result) { return; } match *self.kind() { ItemKind::Module(ref module) => { module.codegen(ctx, result, self); } ItemKind::Function(ref fun) => { fun.codegen(ctx, result, self); } ItemKind::Var(ref var) => { var.codegen(ctx, result, self); } ItemKind::Type(ref ty) => { ty.codegen(ctx, result, self); } } } } impl CodeGenerator for Module { type Extra = Item; type Return = (); fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, item: &Item, ) { debug!("::codegen: item = {:?}", item); let codegen_self = |result: &mut CodegenResult, found_any: &mut bool| { for child in self.children() { if ctx.codegen_items().contains(child) { *found_any = true; ctx.resolve_item(*child).codegen(ctx, result, &()); } } if item.id() == ctx.root_module() { if result.saw_block { utils::prepend_block_header(ctx, &mut *result); } if result.saw_bindgen_union { utils::prepend_union_types(ctx, &mut *result); } if result.saw_incomplete_array { utils::prepend_incomplete_array_types(ctx, &mut *result); } if ctx.need_bindgen_complex_type() { utils::prepend_complex_type(&mut *result); } if result.saw_objc { utils::prepend_objc_header(ctx, &mut *result); } if result.saw_bitfield_unit { utils::prepend_bitfield_unit_type(ctx, &mut *result); } } }; if !ctx.options().enable_cxx_namespaces || (self.is_inline() && !ctx.options().conservative_inline_namespaces) { codegen_self(result, &mut false); return; } let mut found_any = false; let inner_items = result.inner(|result| { result.push(root_import(ctx, item)); let path = item.namespace_aware_canonical_path(ctx).join("::"); if let Some(raw_lines) = ctx.options().module_lines.get(&path) { for raw_line in raw_lines { found_any = true; result.push( proc_macro2::TokenStream::from_str(raw_line).unwrap(), ); } } codegen_self(result, &mut found_any); }); // Don't bother creating an empty module. if !found_any { return; } let name = item.canonical_name(ctx); let ident = ctx.rust_ident(name); result.push(if item.id() == ctx.root_module() { quote! { #[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] pub mod #ident { #( #inner_items )* } } } else { quote! { pub mod #ident { #( #inner_items )* } } }); } } impl CodeGenerator for Var { type Extra = Item; type Return = (); fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, item: &Item, ) { use crate::ir::var::VarType; debug!("::codegen: item = {:?}", item); debug_assert!(item.is_enabled_for_codegen(ctx)); let canonical_name = item.canonical_name(ctx); if result.seen_var(&canonical_name) { return; } result.saw_var(&canonical_name); let canonical_ident = ctx.rust_ident(&canonical_name); // We can't generate bindings to static variables of templates. The // number of actual variables for a single declaration are open ended // and we don't know what instantiations do or don't exist. if !item.all_template_params(ctx).is_empty() { return; } let mut attrs = vec![]; if let Some(comment) = item.comment(ctx) { attrs.push(attributes::doc(comment)); } let ty = self.ty().to_rust_ty_or_opaque(ctx, &()); if let Some(val) = self.val() { match *val { VarType::Bool(val) => { result.push(quote! { #(#attrs)* pub const #canonical_ident : #ty = #val ; }); } VarType::Int(val) => { let int_kind = self .ty() .into_resolver() .through_type_aliases() .through_type_refs() .resolve(ctx) .expect_type() .as_integer() .unwrap(); let val = if int_kind.is_signed() { helpers::ast_ty::int_expr(val) } else { helpers::ast_ty::uint_expr(val as _) }; result.push(quote! { #(#attrs)* pub const #canonical_ident : #ty = #val ; }); } VarType::String(ref bytes) => { // Account the trailing zero. // // TODO: Here we ignore the type we just made up, probably // we should refactor how the variable type and ty id work. let len = bytes.len() + 1; let ty = quote! { [u8; #len] }; match String::from_utf8(bytes.clone()) { Ok(string) => { let cstr = helpers::ast_ty::cstr_expr(string); result.push(quote! { #(#attrs)* pub const #canonical_ident : &'static #ty = #cstr ; }); } Err(..) => { let bytes = helpers::ast_ty::byte_array_expr(bytes); result.push(quote! { #(#attrs)* pub const #canonical_ident : #ty = #bytes ; }); } } } VarType::Float(f) => { match helpers::ast_ty::float_expr(ctx, f) { Ok(expr) => result.push(quote! { #(#attrs)* pub const #canonical_ident : #ty = #expr ; }), Err(..) => return, } } VarType::Char(c) => { result.push(quote! { #(#attrs)* pub const #canonical_ident : #ty = #c ; }); } } } else { // If necessary, apply a `#[link_name]` attribute let link_name = self.mangled_name().unwrap_or(self.name()); if !utils::names_will_be_identical_after_mangling( &canonical_name, link_name, None, ) { attrs.push(attributes::link_name(link_name)); } let maybe_mut = if self.is_const() { quote! {} } else { quote! { mut } }; let tokens = quote!( extern "C" { #(#attrs)* pub static #maybe_mut #canonical_ident: #ty; } ); result.push(tokens); } } } impl CodeGenerator for Type { type Extra = Item; type Return = (); fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, item: &Item, ) { debug!("::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. return; } 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. let spelling = self.name().expect("Unnamed alias?"); if utils::type_from_named(ctx, spelling).is_some() { return; } let mut outer_params = item.used_template_params(ctx); let is_opaque = item.is_opaque(ctx, &()); let inner_rust_type = if is_opaque { outer_params = vec![]; self.to_opaque(ctx, item) } else { // Its possible that we have better layout information than // the inner type does, so fall back to an opaque blob based // on our layout if converting the inner item fails. let mut inner_ty = inner_item .try_to_rust_ty_or_opaque(ctx, &()) .unwrap_or_else(|_| self.to_opaque(ctx, item)); inner_ty.append_implicit_template_params(ctx, inner_item); inner_ty }; { // FIXME(emilio): This is a workaround to avoid generating // incorrect type aliases because of types that we haven't // been able to resolve (because, eg, they depend on a // template parameter). // // It's kind of a shame not generating them even when they // could be referenced, but we already do the same for items // with invalid template parameters, and at least this way // they can be replaced, instead of generating plain invalid // code. let inner_canon_type = inner_item.expect_type().canonical_type(ctx); if inner_canon_type.is_invalid_type_param() { warn!( "Item contained invalid named type, skipping: \ {:?}, {:?}", item, inner_item ); return; } } let rust_name = ctx.rust_ident(&name); let mut tokens = if let Some(comment) = item.comment(ctx) { attributes::doc(comment) } else { quote! {} }; let alias_style = if ctx.options().type_alias.matches(&name) { AliasVariation::TypeAlias } else if ctx.options().new_type_alias.matches(&name) { AliasVariation::NewType } else if ctx.options().new_type_alias_deref.matches(&name) { AliasVariation::NewTypeDeref } else { ctx.options().default_alias_style }; // We prefer using `pub use` over `pub type` because of: // https://github.com/rust-lang/rust/issues/26264 if inner_rust_type.to_string().chars().all(|c| match c { // These are the only characters allowed in simple // paths, eg `good::dogs::Bront`. 'A'..='Z' | 'a'..='z' | '0'..='9' | ':' | '_' | ' ' => true, _ => false, }) && outer_params.is_empty() && !is_opaque && alias_style == AliasVariation::TypeAlias && inner_item.expect_type().canonical_type(ctx).is_enum() { tokens.append_all(quote! { pub use }); let path = top_level_path(ctx, item); tokens.append_separated(path, quote!(::)); tokens.append_all(quote! { :: #inner_rust_type as #rust_name ; }); result.push(tokens); return; } tokens.append_all(match alias_style { AliasVariation::TypeAlias => quote! { pub type #rust_name }, AliasVariation::NewType | AliasVariation::NewTypeDeref => { assert!( ctx.options().rust_features().repr_transparent, "repr_transparent feature is required to use {:?}", alias_style ); let mut attributes = vec![attributes::repr("transparent")]; let derivable_traits = derives_of_item(item, ctx); if !derivable_traits.is_empty() { let derives: Vec<_> = derivable_traits.into(); attributes.push(attributes::derives(&derives)) } quote! { #( #attributes )* pub struct #rust_name } } }); let params: Vec<_> = outer_params .into_iter() .filter_map(|p| p.as_template_param(ctx, &())) .collect(); if params .iter() .any(|p| ctx.resolve_type(*p).is_invalid_type_param()) { warn!( "Item contained invalid template \ parameter: {:?}", item ); return; } let params: Vec<_> = params .iter() .map(|p| { p.try_to_rust_ty(ctx, &()).expect( "type parameters can always convert to rust ty OK", ) }) .collect(); if !params.is_empty() { tokens.append_all(quote! { < #( #params ),* > }); } tokens.append_all(match alias_style { AliasVariation::TypeAlias => quote! { = #inner_rust_type ; }, AliasVariation::NewType | AliasVariation::NewTypeDeref => { quote! { (pub #inner_rust_type) ; } } }); if alias_style == AliasVariation::NewTypeDeref { let prefix = ctx.trait_prefix(); tokens.append_all(quote! { impl ::#prefix::ops::Deref for #rust_name { type Target = #inner_rust_type; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl ::#prefix::ops::DerefMut for #rust_name { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } }); } result.push(tokens); } TypeKind::Enum(ref ei) => ei.codegen(ctx, result, item), TypeKind::ObjCId | TypeKind::ObjCSel => { result.saw_objc(); } TypeKind::ObjCInterface(ref interface) => { interface.codegen(ctx, result, item) } ref u @ TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing {:?}!", u) } } } } struct Vtable<'a> { item_id: ItemId, #[allow(dead_code)] methods: &'a [Method], #[allow(dead_code)] base_classes: &'a [Base], } impl<'a> Vtable<'a> { fn new( item_id: ItemId, methods: &'a [Method], base_classes: &'a [Base], ) -> Self { Vtable { item_id, methods, base_classes, } } } impl<'a> CodeGenerator for Vtable<'a> { type Extra = Item; type Return = (); fn codegen<'b>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'b>, item: &Item, ) { assert_eq!(item.id(), self.item_id); debug_assert!(item.is_enabled_for_codegen(ctx)); // For now, generate an empty struct, later we should generate function // pointers and whatnot. let name = ctx.rust_ident(&self.canonical_name(ctx)); let void = helpers::ast_ty::c_void(ctx); result.push(quote! { #[repr(C)] pub struct #name ( #void ); }); } } impl<'a> ItemCanonicalName for Vtable<'a> { fn canonical_name(&self, ctx: &BindgenContext) -> String { format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx)) } } impl<'a> TryToRustTy for Vtable<'a> { type Extra = (); fn try_to_rust_ty( &self, ctx: &BindgenContext, _: &(), ) -> error::Result { let name = ctx.rust_ident(self.canonical_name(ctx)); Ok(quote! { #name }) } } impl CodeGenerator for TemplateInstantiation { type Extra = Item; type Return = (); fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, item: &Item, ) { debug_assert!(item.is_enabled_for_codegen(ctx)); // Although uses of instantiations don't need code generation, and are // just converted to rust types in fields, vars, etc, we take this // opportunity to generate tests for their layout here. If the // instantiation is opaque, then its presumably because we don't // properly understand it (maybe because of specializations), and so we // shouldn't emit layout tests either. if !ctx.options().layout_tests || self.is_opaque(ctx, item) { return; } // If there are any unbound type parameters, then we can't generate a // layout test because we aren't dealing with a concrete type with a // concrete size and alignment. if ctx.uses_any_template_parameters(item.id()) { return; } let layout = item.kind().expect_type().layout(ctx); if let Some(layout) = layout { let size = layout.size; let align = layout.align; let name = item.full_disambiguated_name(ctx); let mut fn_name = format!("__bindgen_test_layout_{}_instantiation", name); let times_seen = result.overload_number(&fn_name); if times_seen > 0 { write!(&mut fn_name, "_{}", times_seen).unwrap(); } let fn_name = ctx.rust_ident_raw(fn_name); let prefix = ctx.trait_prefix(); let ident = item.to_rust_ty_or_opaque(ctx, &()); let size_of_expr = quote! { ::#prefix::mem::size_of::<#ident>() }; let align_of_expr = quote! { ::#prefix::mem::align_of::<#ident>() }; let item = quote! { #[test] fn #fn_name() { assert_eq!(#size_of_expr, #size, concat!("Size of template specialization: ", stringify!(#ident))); assert_eq!(#align_of_expr, #align, concat!("Alignment of template specialization: ", stringify!(#ident))); } }; result.push(item); } } } /// Trait for implementing the code generation of a struct or union field. trait FieldCodegen<'a> { type Extra; fn codegen( &self, ctx: &BindgenContext, fields_should_be_private: bool, codegen_depth: usize, accessor_kind: FieldAccessorKind, parent: &CompInfo, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, extra: Self::Extra, ) where F: Extend, M: Extend; } impl<'a> FieldCodegen<'a> for Field { type Extra = (); fn codegen( &self, ctx: &BindgenContext, fields_should_be_private: bool, codegen_depth: usize, accessor_kind: FieldAccessorKind, parent: &CompInfo, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, _: (), ) where F: Extend, M: Extend, { match *self { Field::DataMember(ref data) => { data.codegen( ctx, fields_should_be_private, codegen_depth, accessor_kind, parent, result, struct_layout, fields, methods, (), ); } Field::Bitfields(ref unit) => { unit.codegen( ctx, fields_should_be_private, codegen_depth, accessor_kind, parent, result, struct_layout, fields, methods, (), ); } } } } impl<'a> FieldCodegen<'a> for FieldData { type Extra = (); fn codegen( &self, ctx: &BindgenContext, fields_should_be_private: bool, codegen_depth: usize, accessor_kind: FieldAccessorKind, parent: &CompInfo, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, _: (), ) where F: Extend, 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 mut ty = self.ty().to_rust_ty_or_opaque(ctx, &()); ty.append_implicit_template_params(ctx, field_item); // NB: If supported, we use proper `union` types. let ty = if parent.is_union() && !struct_layout.is_rust_union() { result.saw_bindgen_union(); if ctx.options().enable_cxx_namespaces { quote! { root::__BindgenUnionField<#ty> } } else { quote! { __BindgenUnionField<#ty> } } } else if let Some(item) = field_ty.is_incomplete_array(ctx) { result.saw_incomplete_array(); let inner = item.to_rust_ty_or_opaque(ctx, &()); if ctx.options().enable_cxx_namespaces { quote! { root::__IncompleteArrayField<#inner> } } else { quote! { __IncompleteArrayField<#inner> } } } else { ty }; let mut field = quote! {}; if ctx.options().generate_comments { if let Some(raw_comment) = self.comment() { let comment = comment::preprocess(raw_comment, codegen_depth + 1); field = attributes::doc(comment); } } let field_name = self .name() .map(|name| ctx.rust_mangle(name).into_owned()) .expect("Each field should have a name in codegen!"); let field_ident = ctx.rust_ident_raw(field_name.as_str()); if let Some(padding_field) = struct_layout.saw_field(&field_name, field_ty, self.offset()) { fields.extend(Some(padding_field)); } let is_private = (!self.is_public() && ctx.options().respect_cxx_access_specs) || self.annotations() .private_fields() .unwrap_or(fields_should_be_private); let accessor_kind = self.annotations().accessor_kind().unwrap_or(accessor_kind); if is_private { field.append_all(quote! { #field_ident : #ty , }); } else { field.append_all(quote! { pub #field_ident : #ty , }); } fields.extend(Some(field)); // TODO: Factor the following code out, please! if accessor_kind == FieldAccessorKind::None { return; } let getter_name = ctx.rust_ident_raw(format!("get_{}", field_name)); let mutable_getter_name = ctx.rust_ident_raw(format!("get_{}_mut", field_name)); let field_name = ctx.rust_ident_raw(field_name); methods.extend(Some(match accessor_kind { FieldAccessorKind::None => unreachable!(), FieldAccessorKind::Regular => { quote! { #[inline] pub fn #getter_name(&self) -> & #ty { &self.#field_name } #[inline] pub fn #mutable_getter_name(&mut self) -> &mut #ty { &mut self.#field_name } } } FieldAccessorKind::Unsafe => { quote! { #[inline] pub unsafe fn #getter_name(&self) -> & #ty { &self.#field_name } #[inline] pub unsafe fn #mutable_getter_name(&mut self) -> &mut #ty { &mut self.#field_name } } } FieldAccessorKind::Immutable => { quote! { #[inline] pub fn #getter_name(&self) -> & #ty { &self.#field_name } } } })); } } impl BitfieldUnit { /// Get the constructor name for this bitfield unit. fn ctor_name(&self) -> proc_macro2::TokenStream { let ctor_name = Ident::new( &format!("new_bitfield_{}", self.nth()), Span::call_site(), ); quote! { #ctor_name } } } impl Bitfield { /// Extend an under construction bitfield unit constructor with this /// bitfield. This sets the relevant bits on the `__bindgen_bitfield_unit` /// variable that's being constructed. fn extend_ctor_impl( &self, ctx: &BindgenContext, param_name: proc_macro2::TokenStream, mut ctor_impl: proc_macro2::TokenStream, ) -> proc_macro2::TokenStream { let bitfield_ty = ctx.resolve_type(self.ty()); let bitfield_ty_layout = bitfield_ty .layout(ctx) .expect("Bitfield without layout? Gah!"); let bitfield_int_ty = helpers::integer_type(ctx, bitfield_ty_layout) .expect( "Should already have verified that the bitfield is \ representable as an int", ); let offset = self.offset_into_unit(); let width = self.width() as u8; let prefix = ctx.trait_prefix(); ctor_impl.append_all(quote! { __bindgen_bitfield_unit.set( #offset, #width, { let #param_name: #bitfield_int_ty = unsafe { ::#prefix::mem::transmute(#param_name) }; #param_name as u64 } ); }); ctor_impl } } fn access_specifier( ctx: &BindgenContext, is_pub: bool, ) -> proc_macro2::TokenStream { if is_pub || !ctx.options().respect_cxx_access_specs { quote! { pub } } else { quote! {} } } impl<'a> FieldCodegen<'a> for BitfieldUnit { type Extra = (); fn codegen( &self, ctx: &BindgenContext, fields_should_be_private: bool, codegen_depth: usize, accessor_kind: FieldAccessorKind, parent: &CompInfo, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, methods: &mut M, _: (), ) where F: Extend, 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 = { if parent.is_union() && !struct_layout.is_rust_union() { result.saw_bindgen_union(); if ctx.options().enable_cxx_namespaces { quote! { root::__BindgenUnionField<#unit_field_ty> } } else { quote! { __BindgenUnionField<#unit_field_ty> } } } else { unit_field_ty.clone() } }; { let align_field_name = format!("_bitfield_align_{}", self.nth()); let align_field_ident = ctx.rust_ident(&align_field_name); let align_ty = match self.layout().align { n if n >= 8 => quote! { u64 }, 4 => quote! { u32 }, 2 => quote! { u16 }, _ => quote! { u8 }, }; let align_field = quote! { pub #align_field_ident: [#align_ty; 0], }; fields.extend(Some(align_field)); } let unit_field_name = format!("_bitfield_{}", self.nth()); let unit_field_ident = ctx.rust_ident(&unit_field_name); let ctor_name = self.ctor_name(); let mut ctor_params = vec![]; let mut ctor_impl = quote! {}; // We cannot generate any constructor if the underlying storage can't // implement AsRef<[u8]> / AsMut<[u8]> / etc, or can't derive Default. // // We don't check `larger_arrays` here because Default does still have // the 32 items limitation. let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT; let mut access_spec = !fields_should_be_private; for bf in self.bitfields() { // Codegen not allowed for anonymous bitfields if bf.name().is_none() { continue; } if layout.size > RUST_DERIVE_IN_ARRAY_LIMIT && !ctx.options().rust_features().larger_arrays { continue; } access_spec &= bf.is_public(); let mut bitfield_representable_as_int = true; bf.codegen( ctx, fields_should_be_private, codegen_depth, accessor_kind, parent, result, struct_layout, fields, methods, (&unit_field_name, &mut bitfield_representable_as_int), ); // Generating a constructor requires the bitfield to be representable as an integer. if !bitfield_representable_as_int { generate_ctor = false; continue; } let param_name = bitfield_getter_name(ctx, bf); let bitfield_ty_item = ctx.resolve_item(bf.ty()); let bitfield_ty = bitfield_ty_item.expect_type(); let bitfield_ty = bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item); ctor_params.push(quote! { #param_name : #bitfield_ty }); ctor_impl = bf.extend_ctor_impl(ctx, param_name, ctor_impl); } let access_spec = access_specifier(ctx, access_spec); let field = quote! { #access_spec #unit_field_ident : #field_ty , }; fields.extend(Some(field)); if generate_ctor { methods.extend(Some(quote! { #[inline] #access_spec fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_ty { let mut __bindgen_bitfield_unit: #unit_field_ty = Default::default(); #ctor_impl __bindgen_bitfield_unit } })); } struct_layout.saw_bitfield_unit(layout); } } fn bitfield_getter_name( ctx: &BindgenContext, bitfield: &Bitfield, ) -> proc_macro2::TokenStream { let name = bitfield.getter_name(); let name = ctx.rust_ident_raw(name); quote! { #name } } fn bitfield_setter_name( ctx: &BindgenContext, bitfield: &Bitfield, ) -> proc_macro2::TokenStream { let setter = bitfield.setter_name(); let setter = ctx.rust_ident_raw(setter); quote! { #setter } } impl<'a> FieldCodegen<'a> for Bitfield { type Extra = (&'a str, &'a mut bool); fn codegen( &self, ctx: &BindgenContext, fields_should_be_private: bool, _codegen_depth: usize, _accessor_kind: FieldAccessorKind, parent: &CompInfo, _result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, _fields: &mut F, methods: &mut M, (unit_field_name, bitfield_representable_as_int): (&'a str, &mut bool), ) where F: Extend, M: Extend, { let prefix = ctx.trait_prefix(); let getter_name = bitfield_getter_name(ctx, self); let setter_name = bitfield_setter_name(ctx, self); let unit_field_ident = Ident::new(unit_field_name, Span::call_site()); let bitfield_ty_item = ctx.resolve_item(self.ty()); let bitfield_ty = bitfield_ty_item.expect_type(); let bitfield_ty_layout = bitfield_ty .layout(ctx) .expect("Bitfield without layout? Gah!"); let bitfield_int_ty = match helpers::integer_type(ctx, bitfield_ty_layout) { Some(int_ty) => { *bitfield_representable_as_int = true; int_ty } None => { *bitfield_representable_as_int = false; return; } }; let bitfield_ty = bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item); let offset = self.offset_into_unit(); let width = self.width() as u8; let access_spec = access_specifier( ctx, self.is_public() && !fields_should_be_private, ); if parent.is_union() && !struct_layout.is_rust_union() { methods.extend(Some(quote! { #[inline] #access_spec fn #getter_name(&self) -> #bitfield_ty { unsafe { ::#prefix::mem::transmute( self.#unit_field_ident.as_ref().get(#offset, #width) as #bitfield_int_ty ) } } #[inline] #access_spec fn #setter_name(&mut self, val: #bitfield_ty) { unsafe { let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); self.#unit_field_ident.as_mut().set( #offset, #width, val as u64 ) } } })); } else { methods.extend(Some(quote! { #[inline] #access_spec fn #getter_name(&self) -> #bitfield_ty { unsafe { ::#prefix::mem::transmute( self.#unit_field_ident.get(#offset, #width) as #bitfield_int_ty ) } } #[inline] #access_spec fn #setter_name(&mut self, val: #bitfield_ty) { unsafe { let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); self.#unit_field_ident.set( #offset, #width, val as u64 ) } } })); } } } impl CodeGenerator for CompInfo { type Extra = Item; type Return = (); fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, item: &Item, ) { debug!("::codegen: item = {:?}", item); debug_assert!(item.is_enabled_for_codegen(ctx)); // Don't output classes with template parameters that aren't types, and // also don't output template specializations, neither total or partial. if self.has_non_type_template_params() { return; } let ty = item.expect_type(); let layout = ty.layout(ctx); let mut packed = self.is_packed(ctx, layout.as_ref()); let canonical_name = item.canonical_name(ctx); let canonical_ident = ctx.rust_ident(&canonical_name); // Generate the vtable from the method list if appropriate. // // TODO: I don't know how this could play with virtual methods that are // not in the list of methods found by us, we'll see. Also, could the // order of the vtable pointers vary? // // FIXME: Once we generate proper vtables, we need to codegen the // vtable, but *not* generate a field for it in the case that // HasVtable::has_vtable_ptr is false but HasVtable::has_vtable is true. // // Also, we need to generate the vtable in such a way it "inherits" from // the parent too. let is_opaque = item.is_opaque(ctx, &()); let mut fields = vec![]; let mut struct_layout = StructLayoutTracker::new(ctx, self, ty, &canonical_name); if !is_opaque { if item.has_vtable_ptr(ctx) { let vtable = Vtable::new(item.id(), self.methods(), self.base_members()); vtable.codegen(ctx, result, item); let vtable_type = vtable .try_to_rust_ty(ctx, &()) .expect("vtable to Rust type conversion is infallible") .to_ptr(true); fields.push(quote! { pub vtable_: #vtable_type , }); struct_layout.saw_vtable(); } for base in self.base_members() { if !base.requires_storage(ctx) { continue; } let inner_item = ctx.resolve_item(base.ty); let mut inner = inner_item.to_rust_ty_or_opaque(ctx, &()); inner.append_implicit_template_params(ctx, &inner_item); let field_name = ctx.rust_ident(&base.field_name); struct_layout.saw_base(inner_item.expect_type()); let access_spec = access_specifier(ctx, base.is_public()); fields.push(quote! { #access_spec #field_name: #inner, }); } } let mut methods = vec![]; if !is_opaque { let codegen_depth = item.codegen_depth(ctx); let fields_should_be_private = item.annotations().private_fields().unwrap_or(false); let struct_accessor_kind = item .annotations() .accessor_kind() .unwrap_or(FieldAccessorKind::None); for field in self.fields() { field.codegen( ctx, fields_should_be_private, codegen_depth, struct_accessor_kind, self, result, &mut struct_layout, &mut fields, &mut methods, (), ); } // Check whether an explicit padding field is needed // at the end. if let Some(comp_layout) = layout { fields.extend( struct_layout .add_tail_padding(&canonical_name, comp_layout), ); } } if is_opaque { // Opaque item should not have generated methods, fields. debug_assert!(fields.is_empty()); debug_assert!(methods.is_empty()); } let is_union = self.kind() == CompKind::Union; let layout = item.kind().expect_type().layout(ctx); let zero_sized = item.is_zero_sized(ctx); let forward_decl = self.is_forward_declaration(); let mut explicit_align = None; // C++ requires every struct to be addressable, so what C++ compilers do // is making the struct 1-byte sized. // // This is apparently not the case for C, see: // https://github.com/rust-lang/rust-bindgen/issues/551 // // Just get the layout, and assume C++ if not. // // NOTE: This check is conveniently here to avoid the dummy fields we // may add for unused template parameters. if !forward_decl && zero_sized { let has_address = if is_opaque { // Generate the address field if it's an opaque type and // couldn't determine the layout of the blob. layout.is_none() } else { layout.map_or(true, |l| l.size != 0) }; if has_address { let layout = Layout::new(1, 1); let ty = helpers::blob(ctx, Layout::new(1, 1)); struct_layout.saw_field_with_layout( "_address", layout, /* offset = */ Some(0), ); fields.push(quote! { pub _address: #ty, }); } } if is_opaque { match layout { Some(l) => { explicit_align = Some(l.align); let ty = helpers::blob(ctx, l); fields.push(quote! { pub _bindgen_opaque_blob: #ty , }); } None => { warn!("Opaque type without layout! Expect dragons!"); } } } else if !is_union && !zero_sized { if let Some(padding_field) = layout.and_then(|layout| struct_layout.pad_struct(layout)) { fields.push(padding_field); } if let Some(layout) = layout { if struct_layout.requires_explicit_align(layout) { if layout.align == 1 { packed = true; } else { explicit_align = Some(layout.align); if !ctx.options().rust_features.repr_align { let ty = helpers::blob( ctx, Layout::new(0, layout.align), ); fields.push(quote! { pub __bindgen_align: #ty , }); } } } } } else if is_union && !forward_decl { // TODO(emilio): It'd be nice to unify this with the struct path // above somehow. let layout = layout.expect("Unable to get layout information?"); if struct_layout.requires_explicit_align(layout) { explicit_align = Some(layout.align); } if !struct_layout.is_rust_union() { let ty = helpers::blob(ctx, layout); fields.push(quote! { pub bindgen_union_field: #ty , }) } } if forward_decl { fields.push(quote! { _unused: [u8; 0], }); } let mut generic_param_names = vec![]; for (idx, ty) in item.used_template_params(ctx).iter().enumerate() { let param = ctx.resolve_type(*ty); let name = param.name().unwrap(); let ident = ctx.rust_ident(name); generic_param_names.push(ident.clone()); let prefix = ctx.trait_prefix(); let field_name = ctx.rust_ident(format!("_phantom_{}", idx)); fields.push(quote! { pub #field_name : ::#prefix::marker::PhantomData< ::#prefix::cell::UnsafeCell<#ident> > , }); } let generics = if !generic_param_names.is_empty() { let generic_param_names = generic_param_names.clone(); quote! { < #( #generic_param_names ),* > } } else { quote! {} }; let mut attributes = vec![]; let mut needs_clone_impl = false; let mut needs_default_impl = false; let mut needs_debug_impl = false; let mut needs_partialeq_impl = false; if let Some(comment) = item.comment(ctx) { attributes.push(attributes::doc(comment)); } if packed && !is_opaque { let n = layout.map_or(1, |l| l.align); assert!(ctx.options().rust_features().repr_packed_n || n == 1); let packed_repr = if n == 1 { "packed".to_string() } else { format!("packed({})", n) }; attributes.push(attributes::repr_list(&["C", &packed_repr])); } else { attributes.push(attributes::repr("C")); } if ctx.options().rust_features().repr_align { if let Some(explicit) = explicit_align { // Ensure that the struct has the correct alignment even in // presence of alignas. let explicit = helpers::ast_ty::int_expr(explicit as i64); attributes.push(quote! { #[repr(align(#explicit))] }); } } let derivable_traits = derives_of_item(item, ctx); if !derivable_traits.contains(DerivableTraits::DEBUG) { needs_debug_impl = ctx.options().derive_debug && ctx.options().impl_debug && !ctx.no_debug_by_name(item) && !item.annotations().disallow_debug(); } if !derivable_traits.contains(DerivableTraits::DEFAULT) { needs_default_impl = ctx.options().derive_default && !self.is_forward_declaration() && !ctx.no_default_by_name(item) && !item.annotations().disallow_default(); } let all_template_params = item.all_template_params(ctx); if derivable_traits.contains(DerivableTraits::COPY) && !derivable_traits.contains(DerivableTraits::CLONE) { needs_clone_impl = true; } if !derivable_traits.contains(DerivableTraits::PARTIAL_EQ) { needs_partialeq_impl = ctx.options().derive_partialeq && ctx.options().impl_partialeq && ctx.lookup_can_derive_partialeq_or_partialord(item.id()) == CanDerive::Manually; } let mut derives: Vec<_> = derivable_traits.into(); derives.extend(item.annotations().derives().iter().map(String::as_str)); // The custom derives callback may return a list of derive attributes; // add them to the end of the list. let custom_derives; if let Some(cb) = &ctx.options().parse_callbacks { custom_derives = cb.add_derives(&canonical_name); // In most cases this will be a no-op, since custom_derives will be empty. derives.extend(custom_derives.iter().map(|s| s.as_str())); }; if !derives.is_empty() { attributes.push(attributes::derives(&derives)) } let mut tokens = if is_union && struct_layout.is_rust_union() { quote! { #( #attributes )* pub union #canonical_ident } } else { quote! { #( #attributes )* pub struct #canonical_ident } }; tokens.append_all(quote! { #generics { #( #fields )* } }); result.push(tokens); // Generate the inner types and all that stuff. // // TODO: In the future we might want to be smart, and use nested // modules, and whatnot. for ty in self.inner_types() { let child_item = ctx.resolve_item(*ty); // assert_eq!(child_item.parent_id(), item.id()); child_item.codegen(ctx, result, &()); } // NOTE: Some unexposed attributes (like alignment attributes) may // affect layout, so we're bad and pray to the gods for avoid sending // all the tests to shit when parsing things like max_align_t. if self.found_unknown_attr() { warn!( "Type {} has an unknown attribute that may affect layout", canonical_ident ); } if all_template_params.is_empty() { if !is_opaque { for var in self.inner_vars() { ctx.resolve_item(*var).codegen(ctx, result, &()); } } if ctx.options().layout_tests && !self.is_forward_declaration() { if let Some(layout) = layout { let fn_name = format!("bindgen_test_layout_{}", canonical_ident); let fn_name = ctx.rust_ident_raw(fn_name); let prefix = ctx.trait_prefix(); let size_of_expr = quote! { ::#prefix::mem::size_of::<#canonical_ident>() }; let align_of_expr = quote! { ::#prefix::mem::align_of::<#canonical_ident>() }; let size = layout.size; let align = layout.align; let check_struct_align = if align > ctx.target_pointer_size() && !ctx.options().rust_features().repr_align { None } else { Some(quote! { assert_eq!(#align_of_expr, #align, concat!("Alignment of ", stringify!(#canonical_ident))); }) }; // FIXME when [issue #465](https://github.com/rust-lang/rust-bindgen/issues/465) ready let too_many_base_vtables = self .base_members() .iter() .filter(|base| base.ty.has_vtable(ctx)) .count() > 1; let should_skip_field_offset_checks = is_opaque || too_many_base_vtables; let check_field_offset = if should_skip_field_offset_checks { vec![] } else { let asserts = 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().and_then(|offset| { let field_offset = offset / 8; let field_name = ctx.rust_ident(name); Some(quote! { assert_eq!( unsafe { &(*(::#prefix::ptr::null::<#canonical_ident>())).#field_name as *const _ as usize }, #field_offset, concat!("Offset of field: ", stringify!(#canonical_ident), "::", stringify!(#field_name)) ); }) }) }) .collect::>(); asserts }; let item = quote! { #[test] fn #fn_name() { assert_eq!(#size_of_expr, #size, concat!("Size of: ", stringify!(#canonical_ident))); #check_struct_align #( #check_field_offset )* } }; result.push(item); } } let mut method_names = Default::default(); if ctx.options().codegen_config.methods() { for method in self.methods() { assert!(method.kind() != MethodKind::Constructor); method.codegen_method( ctx, &mut methods, &mut method_names, result, self, ); } } if ctx.options().codegen_config.constructors() { for sig in self.constructors() { Method::new( MethodKind::Constructor, *sig, /* const */ false, ) .codegen_method( ctx, &mut methods, &mut method_names, result, self, ); } } if ctx.options().codegen_config.destructors() { if let Some((kind, destructor)) = self.destructor() { debug_assert!(kind.is_destructor()); Method::new(kind, destructor, false).codegen_method( ctx, &mut methods, &mut method_names, result, self, ); } } } // NB: We can't use to_rust_ty here since for opaque types this tries to // use the specialization knowledge to generate a blob field. let ty_for_impl = quote! { #canonical_ident #generics }; if needs_clone_impl { result.push(quote! { impl #generics Clone for #ty_for_impl { fn clone(&self) -> Self { *self } } }); } if needs_default_impl { let prefix = ctx.trait_prefix(); let body = if ctx.options().rust_features().maybe_uninit { quote! { let mut s = ::#prefix::mem::MaybeUninit::::uninit(); unsafe { ::#prefix::ptr::write_bytes(s.as_mut_ptr(), 0, 1); s.assume_init() } } } else { quote! { unsafe { let mut s: Self = ::#prefix::mem::uninitialized(); ::#prefix::ptr::write_bytes(&mut s, 0, 1); s } } }; // Note we use `ptr::write_bytes()` instead of `mem::zeroed()` because the latter does // not necessarily ensure padding bytes are zeroed. Some C libraries are sensitive to // non-zero padding bytes, especially when forwards/backwards compatability is // involved. result.push(quote! { impl #generics Default for #ty_for_impl { fn default() -> Self { #body } } }); } if needs_debug_impl { let impl_ = impl_debug::gen_debug_impl( ctx, self.fields(), item, self.kind(), ); let prefix = ctx.trait_prefix(); result.push(quote! { impl #generics ::#prefix::fmt::Debug for #ty_for_impl { #impl_ } }); } if needs_partialeq_impl { if let Some(impl_) = impl_partialeq::gen_partialeq_impl( ctx, self, item, &ty_for_impl, ) { let partialeq_bounds = if !generic_param_names.is_empty() { let bounds = generic_param_names.iter().map(|t| { quote! { #t: PartialEq } }); quote! { where #( #bounds ),* } } else { quote! {} }; let prefix = ctx.trait_prefix(); result.push(quote! { impl #generics ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds { #impl_ } }); } } if !methods.is_empty() { result.push(quote! { impl #generics #ty_for_impl { #( #methods )* } }); } } } trait MethodCodegen { fn codegen_method<'a>( &self, ctx: &BindgenContext, methods: &mut Vec, method_names: &mut HashMap, result: &mut CodegenResult<'a>, parent: &CompInfo, ); } impl MethodCodegen for Method { fn codegen_method<'a>( &self, ctx: &BindgenContext, methods: &mut Vec, method_names: &mut HashMap, result: &mut CodegenResult<'a>, _parent: &CompInfo, ) { assert!({ let cc = &ctx.options().codegen_config; match self.kind() { MethodKind::Constructor => cc.constructors(), MethodKind::Destructor => cc.destructors(), MethodKind::VirtualDestructor { .. } => cc.destructors(), MethodKind::Static | MethodKind::Normal | MethodKind::Virtual { .. } => cc.methods(), } }); // TODO(emilio): We could generate final stuff at least. if self.is_virtual() { return; // FIXME } // First of all, output the actual function. let function_item = ctx.resolve_item(self.signature()); if !function_item.process_before_codegen(ctx, result) { return; } let function = function_item.expect_function(); let times_seen = function.codegen(ctx, result, &function_item); let times_seen = match times_seen { Some(seen) => seen, None => return, }; let signature_item = ctx.resolve_item(function.signature()); let mut name = match self.kind() { MethodKind::Constructor => "new".into(), MethodKind::Destructor => "destruct".into(), _ => function.name().to_owned(), }; let signature = match *signature_item.expect_type().kind() { TypeKind::Function(ref sig) => sig, _ => panic!("How in the world?"), }; if let (Abi::ThisCall, false) = (signature.abi(), ctx.options().rust_features().thiscall_abi) { return; } // Do not generate variadic methods, since rust does not allow // implementing them, and we don't do a good job at it anyway. if signature.is_variadic() { return; } let count = { let count = method_names.entry(name.clone()).or_insert(0); *count += 1; *count - 1 }; if count != 0 { name.push_str(&count.to_string()); } let mut function_name = function_item.canonical_name(ctx); if times_seen > 0 { write!(&mut function_name, "{}", times_seen).unwrap(); } let function_name = ctx.rust_ident(function_name); let mut args = utils::fnsig_arguments(ctx, signature); let mut ret = utils::fnsig_return_ty(ctx, signature); if !self.is_static() && !self.is_constructor() { args[0] = if self.is_const() { quote! { &self } } else { quote! { &mut self } }; } // If it's a constructor, we always return `Self`, and we inject the // "this" parameter, so there's no need to ask the user for it. // // Note that constructors in Clang are represented as functions with // return-type = void. if self.is_constructor() { args.remove(0); ret = quote! { -> Self }; } let mut exprs = helpers::ast_ty::arguments_from_signature(&signature, ctx); let mut stmts = vec![]; // If it's a constructor, we need to insert an extra parameter with a // variable called `__bindgen_tmp` we're going to create. if self.is_constructor() { let prefix = ctx.trait_prefix(); let tmp_variable_decl = if ctx .options() .rust_features() .maybe_uninit { exprs[0] = quote! { __bindgen_tmp.as_mut_ptr() }; quote! { let mut __bindgen_tmp = ::#prefix::mem::MaybeUninit::uninit() } } else { exprs[0] = quote! { &mut __bindgen_tmp }; quote! { let mut __bindgen_tmp = ::#prefix::mem::uninitialized() } }; stmts.push(tmp_variable_decl); } else if !self.is_static() { assert!(!exprs.is_empty()); exprs[0] = quote! { self }; }; let call = quote! { #function_name (#( #exprs ),* ) }; stmts.push(call); if self.is_constructor() { stmts.push(if ctx.options().rust_features().maybe_uninit { quote! { __bindgen_tmp.assume_init() } } else { quote! { __bindgen_tmp } }) } let block = quote! { #( #stmts );* }; let mut attrs = vec![]; attrs.push(attributes::inline()); if signature.must_use() && ctx.options().rust_features().must_use_function { attrs.push(attributes::must_use()); } let name = ctx.rust_ident(&name); methods.push(quote! { #(#attrs)* pub unsafe fn #name ( #( #args ),* ) #ret { #block } }); } } /// A helper type that represents different enum variations. #[derive(Copy, Clone, PartialEq, Debug)] pub enum EnumVariation { /// The code for this enum will use a Rust enum. Note that creating this in unsafe code /// (including FFI) with an invalid value will invoke undefined behaviour, whether or not /// its marked as non_exhaustive. Rust { /// Indicates whether the generated struct should be `#[non_exhaustive]` non_exhaustive: bool, }, /// The code for this enum will use a newtype NewType { /// Indicates whether the newtype will have bitwise operators is_bitfield: bool, }, /// The code for this enum will use consts Consts, /// The code for this enum will use a module containing consts ModuleConsts, } impl EnumVariation { fn is_rust(&self) -> bool { match *self { EnumVariation::Rust { .. } => true, _ => false, } } /// Both the `Const` and `ModuleConsts` variants will cause this to return /// true. fn is_const(&self) -> bool { match *self { EnumVariation::Consts | EnumVariation::ModuleConsts => true, _ => false, } } } impl Default for EnumVariation { fn default() -> EnumVariation { EnumVariation::Consts } } impl std::str::FromStr for EnumVariation { type Err = std::io::Error; /// Create a `EnumVariation` from a string. fn from_str(s: &str) -> Result { 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 }), "consts" => Ok(EnumVariation::Consts), "moduleconsts" => Ok(EnumVariation::ModuleConsts), "newtype" => Ok(EnumVariation::NewType { is_bitfield: false }), _ => Err(std::io::Error::new( std::io::ErrorKind::InvalidInput, concat!( "Got an invalid EnumVariation. Accepted values ", "are 'rust', 'rust_non_exhaustive', 'bitfield', 'consts',", "'moduleconsts', and 'newtype'." ), )), } } } /// A helper type to construct different enum variations. enum EnumBuilder<'a> { Rust { codegen_depth: usize, attrs: Vec, ident: Ident, tokens: proc_macro2::TokenStream, emitted_any_variants: bool, }, NewType { codegen_depth: usize, canonical_name: &'a str, tokens: proc_macro2::TokenStream, is_bitfield: bool, }, Consts { repr: proc_macro2::TokenStream, variants: Vec, codegen_depth: usize, }, ModuleConsts { codegen_depth: usize, module_name: &'a str, module_items: Vec, }, } impl<'a> EnumBuilder<'a> { /// Returns the depth of the code generation for a variant of this enum. fn codegen_depth(&self) -> usize { match *self { EnumBuilder::Rust { codegen_depth, .. } | EnumBuilder::NewType { codegen_depth, .. } | EnumBuilder::ModuleConsts { codegen_depth, .. } | EnumBuilder::Consts { codegen_depth, .. } => codegen_depth, } } /// Returns true if the builder is for a rustified enum. fn is_rust_enum(&self) -> bool { match *self { EnumBuilder::Rust { .. } => true, _ => false, } } /// 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: proc_macro2::TokenStream, enum_variation: EnumVariation, enum_codegen_depth: usize, ) -> Self { let ident = Ident::new(name, Span::call_site()); match enum_variation { EnumVariation::NewType { is_bitfield } => EnumBuilder::NewType { codegen_depth: enum_codegen_depth, canonical_name: name, tokens: quote! { #( #attrs )* pub struct #ident (pub #repr); }, is_bitfield, }, EnumVariation::Rust { .. } => { // `repr` is guaranteed to be Rustified in Enum::codegen attrs.insert(0, quote! { #[repr( #repr )] }); let tokens = quote!(); EnumBuilder::Rust { codegen_depth: enum_codegen_depth + 1, attrs, ident, tokens, emitted_any_variants: false, } } EnumVariation::Consts => { let mut variants = Vec::new(); variants.push(quote! { #( #attrs )* pub type #ident = #repr; }); EnumBuilder::Consts { repr, variants, codegen_depth: enum_codegen_depth, } } EnumVariation::ModuleConsts => { let ident = Ident::new( CONSTIFIED_ENUM_MODULE_REPR_NAME, Span::call_site(), ); let type_definition = quote! { #( #attrs )* pub type #ident = #repr; }; EnumBuilder::ModuleConsts { codegen_depth: enum_codegen_depth + 1, module_name: name, module_items: vec![type_definition], } } } } /// Add a variant to this enum. fn with_variant<'b>( self, ctx: &BindgenContext, variant: &EnumVariant, mangling_prefix: Option<&str>, rust_ty: proc_macro2::TokenStream, result: &mut CodegenResult<'b>, is_ty_named: bool, ) -> Self { let variant_name = ctx.rust_mangle(variant.name()); let is_rust_enum = self.is_rust_enum(); let expr = match variant.val() { EnumVariantValue::Boolean(v) if is_rust_enum => { helpers::ast_ty::uint_expr(v as u64) } EnumVariantValue::Boolean(v) => quote!(#v), EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), EnumVariantValue::Unsigned(v) => helpers::ast_ty::uint_expr(v), }; let mut doc = quote! {}; if ctx.options().generate_comments { if let Some(raw_comment) = variant.comment() { let comment = comment::preprocess(raw_comment, self.codegen_depth()); doc = attributes::doc(comment); } } match self { EnumBuilder::Rust { attrs, ident, tokens, emitted_any_variants: _, codegen_depth, } => { let name = ctx.rust_ident(variant_name); EnumBuilder::Rust { attrs, ident, codegen_depth, tokens: quote! { #tokens #doc #name = #expr, }, emitted_any_variants: true, } } EnumBuilder::NewType { canonical_name, .. } => { if ctx.options().rust_features().associated_const && is_ty_named { 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 { ref repr, .. } => { let constant_name = match mangling_prefix { Some(prefix) => { Cow::Owned(format!("{}_{}", prefix, variant_name)) } None => variant_name, }; let ty = if is_ty_named { &rust_ty } else { repr }; let ident = ctx.rust_ident(constant_name); result.push(quote! { #doc pub const #ident : #ty = #expr ; }); self } EnumBuilder::ModuleConsts { codegen_depth, module_name, mut module_items, } => { let name = ctx.rust_ident(variant_name); let ty = ctx.rust_ident(CONSTIFIED_ENUM_MODULE_REPR_NAME); module_items.push(quote! { #doc pub const #name : #ty = #expr ; }); EnumBuilder::ModuleConsts { module_name, module_items, codegen_depth, } } } } fn build<'b>( self, ctx: &BindgenContext, rust_ty: proc_macro2::TokenStream, result: &mut CodegenResult<'b>, ) -> proc_macro2::TokenStream { match self { EnumBuilder::Rust { attrs, ident, tokens, emitted_any_variants, .. } => { let variants = if !emitted_any_variants { quote!(__bindgen_cannot_repr_c_on_empty_enum = 0) } else { tokens }; quote! { #( #attrs )* pub enum #ident { #variants } } } EnumBuilder::NewType { canonical_name, tokens, is_bitfield, .. } => { if !is_bitfield { return tokens; } let rust_ty_name = ctx.rust_ident_raw(canonical_name); let prefix = ctx.trait_prefix(); result.push(quote! { impl ::#prefix::ops::BitOr<#rust_ty> for #rust_ty { type Output = Self; #[inline] fn bitor(self, other: Self) -> Self { #rust_ty_name(self.0 | other.0) } } }); result.push(quote! { impl ::#prefix::ops::BitOrAssign for #rust_ty { #[inline] fn bitor_assign(&mut self, rhs: #rust_ty) { self.0 |= rhs.0; } } }); result.push(quote! { impl ::#prefix::ops::BitAnd<#rust_ty> for #rust_ty { type Output = Self; #[inline] fn bitand(self, other: Self) -> Self { #rust_ty_name(self.0 & other.0) } } }); result.push(quote! { impl ::#prefix::ops::BitAndAssign for #rust_ty { #[inline] fn bitand_assign(&mut self, rhs: #rust_ty) { self.0 &= rhs.0; } } }); tokens } EnumBuilder::Consts { variants, .. } => quote! { #( #variants )* }, EnumBuilder::ModuleConsts { module_items, module_name, .. } => { let ident = ctx.rust_ident(module_name); quote! { pub mod #ident { #( #module_items )* } } } } } } impl CodeGenerator for Enum { type Extra = Item; type Return = (); fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, item: &Item, ) { debug!("::codegen: item = {:?}", item); debug_assert!(item.is_enabled_for_codegen(ctx)); let name = item.canonical_name(ctx); let ident = ctx.rust_ident(&name); let enum_ty = item.expect_type(); let layout = enum_ty.layout(ctx); let variation = self.computed_enum_variation(ctx, item); let repr_translated; let repr = match self.repr().map(|repr| ctx.resolve_type(repr)) { Some(repr) if !ctx.options().translate_enum_integer_types && !variation.is_rust() => { repr } repr => { // An enum's integer type is translated to a native Rust // integer type in 3 cases: // * the enum is Rustified and we need a translated type for // the repr attribute // * the representation couldn't be determined from the C source // * it was explicitly requested as a bindgen option let kind = match repr { Some(repr) => match *repr.canonical_type(ctx).kind() { TypeKind::Int(int_kind) => int_kind, _ => panic!("Unexpected type as enum repr"), }, None => { warn!( "Guessing type of enum! Forward declarations of enums \ shouldn't be legal!" ); IntKind::Int } }; let signed = kind.is_signed(); let size = layout .map(|l| l.size) .or_else(|| kind.known_size()) .unwrap_or(0); let translated = match (signed, size) { (true, 1) => IntKind::I8, (false, 1) => IntKind::U8, (true, 2) => IntKind::I16, (false, 2) => IntKind::U16, (true, 4) => IntKind::I32, (false, 4) => IntKind::U32, (true, 8) => IntKind::I64, (false, 8) => IntKind::U64, _ => { warn!( "invalid enum decl: signed: {}, size: {}", signed, size ); IntKind::I32 } }; repr_translated = Type::new(None, None, TypeKind::Int(translated), false); &repr_translated } }; let mut attrs = vec![]; // TODO(emilio): Delegate this to the builders? match variation { EnumVariation::Rust { non_exhaustive } => { if non_exhaustive && ctx.options().rust_features().non_exhaustive { attrs.push(attributes::non_exhaustive()); } else if non_exhaustive && !ctx.options().rust_features().non_exhaustive { panic!("The rust target you're using doesn't seem to support non_exhaustive enums"); } } EnumVariation::NewType { .. } => { if ctx.options().rust_features.repr_transparent { attrs.push(attributes::repr("transparent")); } else { attrs.push(attributes::repr("C")); } } _ => {} }; if let Some(comment) = item.comment(ctx) { attrs.push(attributes::doc(comment)); } if !variation.is_const() { let mut derives = derives_of_item(item, ctx); // For backwards compat, enums always derive Clone/Eq/PartialEq/Hash, even // if we don't generate those by default. derives.insert( DerivableTraits::CLONE | DerivableTraits::COPY | DerivableTraits::HASH | DerivableTraits::PARTIAL_EQ | DerivableTraits::EQ, ); let derives: Vec<_> = derives.into(); attrs.push(attributes::derives(&derives)); } fn add_constant<'a>( ctx: &BindgenContext, enum_: &Type, // Only to avoid recomputing every time. enum_canonical_name: &Ident, // May be the same as "variant" if it's because the // enum is unnamed and we still haven't seen the // value. variant_name: &Ident, referenced_name: &Ident, enum_rust_ty: proc_macro2::TokenStream, result: &mut CodegenResult<'a>, ) { let constant_name = if enum_.name().is_some() { if ctx.options().prepend_enum_name { format!("{}_{}", enum_canonical_name, variant_name) } else { format!("{}", variant_name) } } else { format!("{}", variant_name) }; let constant_name = ctx.rust_ident(constant_name); result.push(quote! { pub const #constant_name : #enum_rust_ty = #enum_canonical_name :: #referenced_name ; }); } let repr = repr.to_rust_ty_or_opaque(ctx, item); let mut builder = EnumBuilder::new( &name, attrs, repr, variation, item.codegen_depth(ctx), ); // A map where we keep a value -> variant relation. let mut seen_values = HashMap::<_, Ident>::default(); let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &()); let is_toplevel = item.is_toplevel(ctx); // Used to mangle the constants we generate in the unnamed-enum case. let parent_canonical_name = if is_toplevel { None } else { Some(item.parent_id().canonical_name(ctx)) }; let constant_mangling_prefix = if ctx.options().prepend_enum_name { if enum_ty.name().is_none() { parent_canonical_name.as_ref().map(|n| &**n) } else { Some(&*name) } } else { None }; // NB: We defer the creation of constified variants, in case we find // another variant with the same value (which is the common thing to // do). let mut constified_variants = VecDeque::new(); let mut iter = self.variants().iter().peekable(); while let Some(variant) = iter.next().or_else(|| constified_variants.pop_front()) { if variant.hidden() { continue; } if variant.force_constification() && iter.peek().is_some() { constified_variants.push_back(variant); continue; } match seen_values.entry(variant.val()) { Entry::Occupied(ref entry) => { if variation.is_rust() { let variant_name = ctx.rust_mangle(variant.name()); let mangled_name = if is_toplevel || enum_ty.name().is_some() { variant_name } else { let parent_name = parent_canonical_name.as_ref().unwrap(); Cow::Owned(format!( "{}_{}", parent_name, variant_name )) }; let existing_variant_name = entry.get(); // Use associated constants for named enums. if enum_ty.name().is_some() && ctx.options().rust_features().associated_const { let enum_canonical_name = &ident; let variant_name = ctx.rust_ident_raw(&*mangled_name); result.push(quote! { impl #enum_rust_ty { pub const #variant_name : #enum_rust_ty = #enum_canonical_name :: #existing_variant_name ; } }); } else { add_constant( ctx, enum_ty, &ident, &Ident::new(&*mangled_name, Span::call_site()), existing_variant_name, enum_rust_ty.clone(), result, ); } } else { builder = builder.with_variant( ctx, variant, constant_mangling_prefix, enum_rust_ty.clone(), result, enum_ty.name().is_some(), ); } } Entry::Vacant(entry) => { builder = builder.with_variant( ctx, variant, constant_mangling_prefix, enum_rust_ty.clone(), result, enum_ty.name().is_some(), ); let variant_name = ctx.rust_ident(variant.name()); // If it's an unnamed enum, or constification is enforced, // we also generate a constant so it can be properly // accessed. if (variation.is_rust() && enum_ty.name().is_none()) || variant.force_constification() { let mangled_name = if is_toplevel { variant_name.clone() } else { let parent_name = parent_canonical_name.as_ref().unwrap(); Ident::new( &format!("{}_{}", parent_name, variant_name), Span::call_site(), ) }; add_constant( ctx, enum_ty, &ident, &mangled_name, &variant_name, enum_rust_ty.clone(), result, ); } entry.insert(variant_name); } } } let item = builder.build(ctx, enum_rust_ty, result); result.push(item); } } /// Enum for the default type of macro constants. #[derive(Copy, Clone, PartialEq, Debug)] pub enum MacroTypeVariation { /// Use i32 or i64 Signed, /// Use u32 or u64 Unsigned, } impl MacroTypeVariation { /// Convert a `MacroTypeVariation` to its str representation. pub fn as_str(&self) -> &str { match self { MacroTypeVariation::Signed => "signed", MacroTypeVariation::Unsigned => "unsigned", } } } impl Default for MacroTypeVariation { fn default() -> MacroTypeVariation { MacroTypeVariation::Unsigned } } impl std::str::FromStr for MacroTypeVariation { type Err = std::io::Error; /// Create a `MacroTypeVariation` from a string. fn from_str(s: &str) -> Result { 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, Debug)] pub enum AliasVariation { /// Convert to regular Rust alias TypeAlias, /// Create a new type by wrapping the old type in a struct and using #[repr(transparent)] NewType, /// Same as NewStruct but also impl Deref to be able to use the methods of the wrapped type NewTypeDeref, } impl AliasVariation { /// Convert an `AliasVariation` to its str representation. pub fn as_str(&self) -> &str { match self { AliasVariation::TypeAlias => "type_alias", AliasVariation::NewType => "new_type", AliasVariation::NewTypeDeref => "new_type_deref", } } } impl Default for AliasVariation { fn default() -> AliasVariation { AliasVariation::TypeAlias } } impl std::str::FromStr for AliasVariation { type Err = std::io::Error; /// Create an `AliasVariation` from a string. fn from_str(s: &str) -> Result { 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'" ), )), } } } /// Fallible conversion to an opaque blob. /// /// Implementors of this trait should provide the `try_get_layout` method to /// fallibly get this thing's layout, which the provided `try_to_opaque` trait /// method will use to convert the `Layout` into an opaque blob Rust type. trait TryToOpaque { type Extra; /// Get the layout for this thing, if one is available. fn try_get_layout( &self, ctx: &BindgenContext, extra: &Self::Extra, ) -> error::Result; /// 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)) } } /// Infallible conversion of an IR thing to an opaque blob. /// /// The resulting layout is best effort, and is unfortunately not guaranteed to /// be correct. When all else fails, we fall back to a single byte layout as a /// last resort, because C++ does not permit zero-sized types. See the note in /// the `ToRustTyOrOpaque` doc comment about fallible versus infallible traits /// and when each is appropriate. /// /// Don't implement this directly. Instead implement `TryToOpaque`, and then /// leverage the blanket impl for this trait. trait ToOpaque: TryToOpaque { fn get_layout(&self, ctx: &BindgenContext, extra: &Self::Extra) -> Layout { self.try_get_layout(ctx, extra) .unwrap_or_else(|_| Layout::for_size(ctx, 1)) } fn to_opaque( &self, ctx: &BindgenContext, extra: &Self::Extra, ) -> proc_macro2::TokenStream { let layout = self.get_layout(ctx, extra); helpers::blob(ctx, layout) } } impl ToOpaque for T where T: TryToOpaque {} /// Fallible conversion from an IR thing to an *equivalent* Rust type. /// /// If the C/C++ construct represented by the IR thing cannot (currently) be /// represented in Rust (for example, instantiations of templates with /// const-value generic parameters) then the impl should return an `Err`. It /// should *not* attempt to return an opaque blob with the correct size and /// alignment. That is the responsibility of the `TryToOpaque` trait. trait TryToRustTy { type Extra; fn try_to_rust_ty( &self, ctx: &BindgenContext, extra: &Self::Extra, ) -> error::Result; } /// Fallible conversion to a Rust type or an opaque blob with the correct size /// and alignment. /// /// Don't implement this directly. Instead implement `TryToRustTy` and /// `TryToOpaque`, and then leverage the blanket impl for this trait below. trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque { type Extra; fn try_to_rust_ty_or_opaque( &self, ctx: &BindgenContext, extra: &::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)) } else { Err(error::Error::NoLayoutForOpaqueBlob) } }) } } /// Infallible conversion to a Rust type, or an opaque blob with a best effort /// of correct size and alignment. /// /// Don't implement this directly. Instead implement `TryToRustTy` and /// `TryToOpaque`, and then leverage the blanket impl for this trait below. /// /// ### Fallible vs. Infallible Conversions to Rust Types /// /// When should one use this infallible `ToRustTyOrOpaque` trait versus the /// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` triats? All fallible trait /// implementations that need to convert another thing into a Rust type or /// opaque blob in a nested manner should also use fallible trait methods and /// propagate failure up the stack. Only infallible functions and methods like /// CodeGenerator implementations should use the infallible /// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely /// we are to get a usable `Layout` even if we can't generate an equivalent Rust /// type for a C++ construct. trait ToRustTyOrOpaque: TryToRustTy + ToOpaque { type Extra; fn to_rust_ty_or_opaque( &self, ctx: &BindgenContext, extra: &::Extra, ) -> proc_macro2::TokenStream; } impl ToRustTyOrOpaque for T where T: TryToRustTy + ToOpaque, { type Extra = E; fn to_rust_ty_or_opaque( &self, ctx: &BindgenContext, extra: &E, ) -> proc_macro2::TokenStream { self.try_to_rust_ty(ctx, extra) .unwrap_or_else(|_| self.to_opaque(ctx, extra)) } } impl 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::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) => { match ik { IntKind::Bool => Ok(quote! { bool }), IntKind::Char { .. } => Ok(raw_type(ctx, "c_char")), IntKind::SChar => Ok(raw_type(ctx, "c_schar")), IntKind::UChar => Ok(raw_type(ctx, "c_uchar")), IntKind::Short => Ok(raw_type(ctx, "c_short")), IntKind::UShort => Ok(raw_type(ctx, "c_ushort")), IntKind::Int => Ok(raw_type(ctx, "c_int")), IntKind::UInt => Ok(raw_type(ctx, "c_uint")), IntKind::Long => Ok(raw_type(ctx, "c_long")), IntKind::ULong => Ok(raw_type(ctx, "c_ulong")), IntKind::LongLong => Ok(raw_type(ctx, "c_longlong")), IntKind::ULongLong => Ok(raw_type(ctx, "c_ulonglong")), IntKind::WChar => { let layout = self .layout(ctx) .expect("Couldn't compute wchar_t's layout?"); let ty = Layout::known_type_for_size(ctx, layout.size) .expect("Non-representable wchar_t?"); let ident = ctx.rust_ident_raw(ty); Ok(quote! { #ident }) } IntKind::I8 => Ok(quote! { i8 }), IntKind::U8 => Ok(quote! { u8 }), IntKind::I16 => Ok(quote! { i16 }), IntKind::U16 => Ok(quote! { u16 }), IntKind::I32 => Ok(quote! { i32 }), IntKind::U32 => Ok(quote! { u32 }), IntKind::I64 => Ok(quote! { i64 }), IntKind::U64 => Ok(quote! { u64 }), IntKind::Custom { name, .. } => { Ok(proc_macro2::TokenStream::from_str(name).unwrap()) } IntKind::U128 => { Ok(if ctx.options().rust_features.i128_and_u128 { quote! { u128 } } else { // Best effort thing, but wrong alignment // unfortunately. quote! { [u64; 2] } }) } IntKind::I128 => { Ok(if ctx.options().rust_features.i128_and_u128 { quote! { i128 } } else { quote! { [u64; 2] } }) } } } TypeKind::Float(fk) => { Ok(float_kind_rust_type(ctx, fk, self.layout(ctx))) } TypeKind::Complex(fk) => { let float_path = float_kind_rust_type(ctx, fk, self.layout(ctx)); ctx.generated_bindgen_complex(); Ok(if ctx.options().enable_cxx_namespaces { quote! { root::__BindgenComplex<#float_path> } } else { quote! { __BindgenComplex<#float_path> } }) } TypeKind::Function(ref fs) => { // We can't rely on the sizeof(Option>) == // sizeof(NonZero<_>) optimization with opaque blobs (because // they aren't NonZero), so don't *ever* use an or_opaque // variant here. let ty = fs.try_to_rust_ty(ctx, &())?; let prefix = ctx.trait_prefix(); Ok(quote! { ::#prefix::option::Option<#ty> }) } TypeKind::Array(item, len) | TypeKind::Vector(item, len) => { let ty = item.try_to_rust_ty(ctx, &())?; Ok(quote! { [ #ty ; #len ] }) } TypeKind::Enum(..) => { let path = item.namespace_aware_canonical_path(ctx); let path = proc_macro2::TokenStream::from_str(&path.join("::")) .unwrap(); Ok(quote!(#path)) } TypeKind::TemplateInstantiation(ref inst) => { inst.try_to_rust_ty(ctx, item) } TypeKind::ResolvedTypeRef(inner) => inner.try_to_rust_ty(ctx, &()), TypeKind::TemplateAlias(..) | TypeKind::Alias(..) | TypeKind::BlockPointer(..) => { if self.is_block_pointer() && !ctx.options().generate_block { let void = c_void(ctx); return Ok(void.to_ptr(/* is_const = */ false)); } let template_params = item .used_template_params(ctx) .into_iter() .filter(|param| param.is_template_param(ctx, &())) .collect::>(); if item.is_opaque(ctx, &()) && !template_params.is_empty() { self.try_to_opaque(ctx, item) } else if let Some(ty) = self .name() .and_then(|name| utils::type_from_named(ctx, name)) { Ok(ty) } else { utils::build_path(item, ctx) } } TypeKind::Comp(ref info) => { let template_params = item.all_template_params(ctx); if info.has_non_type_template_params() || (item.is_opaque(ctx, &()) && !template_params.is_empty()) { return self.try_to_opaque(ctx, item); } utils::build_path(item, ctx) } TypeKind::Opaque => self.try_to_opaque(ctx, item), TypeKind::Pointer(inner) | TypeKind::Reference(inner) => { let is_const = ctx.resolve_type(inner).is_const(); let inner = inner.into_resolver().through_type_refs().resolve(ctx); let inner_ty = inner.expect_type(); let is_objc_pointer = match inner_ty.kind() { TypeKind::ObjCInterface(..) => true, _ => false, }; // Regardless if we can properly represent the inner type, we // should always generate a proper pointer here, so use // infallible conversion of the inner type. let mut ty = inner.to_rust_ty_or_opaque(ctx, &()); ty.append_implicit_template_params(ctx, inner); // Avoid the first function pointer level, since it's already // represented in Rust. if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer { Ok(ty) } else { Ok(ty.to_ptr(is_const)) } } TypeKind::TypeParam => { let name = item.canonical_name(ctx); let ident = ctx.rust_ident(&name); Ok(quote! { #ident }) } TypeKind::ObjCSel => Ok(quote! { objc::runtime::Sel }), TypeKind::ObjCId => Ok(quote! { id }), TypeKind::ObjCInterface(ref interface) => { let name = ctx.rust_ident(interface.name()); Ok(quote! { #name }) } ref u @ TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing {:?}!", u) } } } } impl TryToOpaque for TemplateInstantiation { type Extra = Item; fn try_get_layout( &self, ctx: &BindgenContext, item: &Item, ) -> error::Result { item.expect_type() .layout(ctx) .ok_or(error::Error::NoLayoutForOpaqueBlob) } } impl TryToRustTy for TemplateInstantiation { type Extra = Item; fn try_to_rust_ty( &self, ctx: &BindgenContext, item: &Item, ) -> error::Result { if self.is_opaque(ctx, item) { return Err(error::Error::InstantiationOfOpaqueType); } let def = self .template_definition() .into_resolver() .through_type_refs() .resolve(ctx); let mut ty = quote! {}; let def_path = def.namespace_aware_canonical_path(ctx); ty.append_separated( def_path.into_iter().map(|p| ctx.rust_ident(p)), quote!(::), ); let def_params = def.self_template_params(ctx); if def_params.is_empty() { // This can happen if we generated an opaque type for a partial // template specialization, and we've hit an instantiation of // that partial specialization. extra_assert!(def.is_opaque(ctx, &())); return Err(error::Error::InstantiationOfOpaqueType); } // TODO: If the definition type is a template class/struct // definition's member template definition, it could rely on // generic template parameters from its outer template // class/struct. When we emit bindings for it, it could require // *more* type arguments than we have here, and we will need to // reconstruct them somehow. We don't have any means of doing // that reconstruction at this time. let template_args = self .template_arguments() .iter() .zip(def_params.iter()) // Only pass type arguments for the type parameters that // the def uses. .filter(|&(_, param)| ctx.uses_template_parameter(def.id(), *param)) .map(|(arg, _)| { let arg = arg.into_resolver().through_type_refs().resolve(ctx); let mut ty = arg.try_to_rust_ty(ctx, &())?; ty.append_implicit_template_params(ctx, arg); Ok(ty) }) .collect::>>()?; if template_args.is_empty() { return Ok(ty); } Ok(quote! { #ty < #( #template_args ),* > }) } } impl TryToRustTy for FunctionSig { type Extra = (); fn try_to_rust_ty( &self, ctx: &BindgenContext, _: &(), ) -> error::Result { // TODO: we might want to consider ignoring the reference return value. let ret = utils::fnsig_return_ty(ctx, &self); let arguments = utils::fnsig_arguments(ctx, &self); let abi = self.abi(); match abi { Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => { warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target"); Ok(proc_macro2::TokenStream::new()) } _ => Ok(quote! { unsafe extern #abi fn ( #( #arguments ),* ) #ret }), } } } impl CodeGenerator for Function { type Extra = Item; /// If we've actually generated the symbol, the number of times we've seen /// it. type Return = Option; fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, item: &Item, ) -> Self::Return { debug!("::codegen: item = {:?}", item); debug_assert!(item.is_enabled_for_codegen(ctx)); // We can't currently do anything with Internal functions so just // avoid generating anything for them. match self.linkage() { Linkage::Internal => return None, Linkage::External => {} } // Pure virtual methods have no actual symbol, so we can't generate // something meaningful for them. match self.kind() { FunctionKind::Method(ref method_kind) if method_kind.is_pure_virtual() => { return None; } _ => {} } // Similar to static member variables in a class template, we can't // generate bindings to template functions, because the set of // instantiations is open ended and we have no way of knowing which // monomorphizations actually exist. if !item.all_template_params(ctx).is_empty() { return None; } let name = self.name(); let mut canonical_name = item.canonical_name(ctx); let mangled_name = self.mangled_name(); { let seen_symbol_name = mangled_name.unwrap_or(&canonical_name); // TODO: Maybe warn here if there's a type/argument mismatch, or // something? if result.seen_function(seen_symbol_name) { return None; } result.saw_function(seen_symbol_name); } let signature_item = ctx.resolve_item(self.signature()); let signature = signature_item.kind().expect_type().canonical_type(ctx); let signature = match *signature.kind() { TypeKind::Function(ref sig) => sig, _ => panic!("Signature kind is not a Function: {:?}", signature), }; let args = utils::fnsig_arguments(ctx, signature); let ret = utils::fnsig_return_ty(ctx, signature); let mut attributes = vec![]; if signature.must_use() && ctx.options().rust_features().must_use_function { attributes.push(attributes::must_use()); } if let Some(comment) = item.comment(ctx) { attributes.push(attributes::doc(comment)); } let abi = match signature.abi() { Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => { warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target"); return None; } Abi::Win64 if signature.is_variadic() => { warn!("Skipping variadic function with Win64 ABI that isn't supported"); return None; } Abi::Unknown(unknown_abi) => { panic!( "Invalid or unknown abi {:?} for function {:?} ({:?})", unknown_abi, canonical_name, self ); } abi => abi, }; // Handle overloaded functions by giving each overload its own unique // suffix. let times_seen = result.overload_number(&canonical_name); if times_seen > 0 { write!(&mut canonical_name, "{}", times_seen).unwrap(); } let link_name = mangled_name.unwrap_or(name); if !utils::names_will_be_identical_after_mangling( &canonical_name, link_name, Some(abi), ) { attributes.push(attributes::link_name(link_name)); } // Unfortunately this can't piggyback on the `attributes` list because // the #[link(wasm_import_module)] needs to happen before the `extern // "C"` block. It doesn't get picked up properly otherwise let wasm_link_attribute = ctx.options().wasm_import_module_name.as_ref().map(|name| { quote! { #[link(wasm_import_module = #name)] } }); let ident = ctx.rust_ident(canonical_name); let tokens = quote! { #wasm_link_attribute extern #abi { #(#attributes)* pub fn #ident ( #( #args ),* ) #ret; } }; // If we're doing dynamic binding generation, add to the dynamic items. if ctx.options().dynamic_library_name.is_some() && self.kind() == FunctionKind::Function { let args_identifiers = utils::fnsig_argument_identifiers(ctx, signature); let return_item = ctx.resolve_item(signature.return_type()); let ret_ty = match *return_item.kind().expect_type().kind() { TypeKind::Void => quote! {()}, _ => return_item.to_rust_ty_or_opaque(ctx, &()), }; result.dynamic_items().push( ident, abi, signature.is_variadic(), ctx.options().dynamic_link_require_all, args, args_identifiers, ret, ret_ty, ); } else { result.push(tokens); } Some(times_seen) } } fn objc_method_codegen( ctx: &BindgenContext, method: &ObjCMethod, class_name: Option<&str>, prefix: &str, ) -> proc_macro2::TokenStream { let signature = method.signature(); let fn_args = utils::fnsig_arguments(ctx, signature); let fn_ret = utils::fnsig_return_ty(ctx, signature); let sig = if method.is_class_method() { let fn_args = fn_args.clone(); quote! { ( #( #fn_args ),* ) #fn_ret } } else { let fn_args = fn_args.clone(); let args = iter::once(quote! { &self }).chain(fn_args.into_iter()); quote! { ( #( #args ),* ) #fn_ret } }; let methods_and_args = method.format_method_call(&fn_args); let body = if method.is_class_method() { let class_name = ctx.rust_ident( class_name .expect("Generating a class method without class name?") .to_owned(), ); quote! { msg_send!(class!(#class_name), #methods_and_args) } } else { quote! { msg_send!(*self, #methods_and_args) } }; let method_name = ctx.rust_ident(format!("{}{}", prefix, method.rust_name())); quote! { unsafe fn #method_name #sig where ::Target: objc::Message + Sized { #body } } } impl CodeGenerator for ObjCInterface { type Extra = Item; type Return = (); fn codegen<'a>( &self, ctx: &BindgenContext, result: &mut CodegenResult<'a>, item: &Item, ) { debug_assert!(item.is_enabled_for_codegen(ctx)); let mut impl_items = vec![]; for method in self.methods() { let impl_item = objc_method_codegen(ctx, method, None, ""); impl_items.push(impl_item); } let instance_method_names: Vec<_> = self.methods().iter().map(|m| m.rust_name()).collect(); for class_method in self.class_methods() { let ambiquity = instance_method_names.contains(&class_method.rust_name()); let prefix = if ambiquity { "class_" } else { "" }; let impl_item = objc_method_codegen( ctx, class_method, Some(self.name()), prefix, ); impl_items.push(impl_item); } 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),*> : #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(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!(objc::class!(#class_name), alloc) }) } } }; result.push(struct_block); let mut protocol_set: HashSet = Default::default(); for protocol_id in self.conforms_to.iter() { protocol_set.insert(*protocol_id); let protocol_name = ctx.rust_ident( ctx.resolve_type(protocol_id.expect_type_id(ctx)) .name() .unwrap(), ); let impl_trait = quote! { impl #protocol_name for #class_name { } }; result.push(impl_trait); } let mut parent_class = self.parent_class; while let Some(parent_id) = parent_class { let parent = parent_id .expect_type_id(ctx) .into_resolver() .through_type_refs() .resolve(ctx) .expect_type() .kind(); let parent = match parent { TypeKind::ObjCInterface(ref parent) => parent, _ => break, }; parent_class = parent.parent_class; let parent_name = ctx.rust_ident(parent.rust_name()); let impl_trait = if parent.is_template() { let template_names: Vec = parent .template_names .iter() .map(|g| ctx.rust_ident(g)) .collect(); quote! { impl <#(#template_names :'static),*> #parent_name <#(#template_names),*> for #class_name { } } } else { quote! { impl #parent_name for #class_name { } } }; result.push(impl_trait); for protocol_id in parent.conforms_to.iter() { if protocol_set.insert(*protocol_id) { let protocol_name = ctx.rust_ident( ctx.resolve_type(protocol_id.expect_type_id(ctx)) .name() .unwrap(), ); let impl_trait = quote! { impl #protocol_name for #class_name { } }; result.push(impl_trait); } } if !parent.is_template() { let parent_struct_name = parent.name(); let child_struct_name = self.name(); let parent_struct = ctx.rust_ident(parent_struct_name); let from_block = quote! { impl From<#class_name> for #parent_struct { fn from(child: #class_name) -> #parent_struct { #parent_struct(child.0) } } }; result.push(from_block); let error_msg = format!( "This {} cannot be downcasted to {}", parent_struct_name, child_struct_name ); let try_into_block = quote! { impl std::convert::TryFrom<#parent_struct> for #class_name { type Error = &'static str; fn try_from(parent: #parent_struct) -> Result<#class_name, Self::Error> { let is_kind_of : bool = unsafe { msg_send!(parent, isKindOfClass:class!(#class_name))}; if is_kind_of { Ok(#class_name(parent.0)) } else { Err(#error_msg) } } } }; result.push(try_into_block); } } } if !self.is_protocol() { let impl_block = if self.is_template() { let template_names: Vec = 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, ) -> (Vec, BindgenOptions) { context.gen(|context| { let _t = context.timer("codegen"); let counter = Cell::new(0); let mut result = CodegenResult::new(&counter); debug!("codegen: {:?}", context.options()); if context.options().emit_ir { let codegen_items = context.codegen_items(); for (id, item) in context.items() { if codegen_items.contains(&id) { println!("ir: {:?} = {:#?}", id, item); } } } if let Some(path) = context.options().emit_ir_graphviz.as_ref() { match dot::write_dot_file(context, path) { Ok(()) => info!( "Your dot file was generated successfully into: {}", path ), Err(e) => warn!("{}", e), } } if let Some(spec) = context.options().depfile.as_ref() { match spec.write(context.deps()) { Ok(()) => info!( "Your depfile was generated successfully into: {}", spec.depfile_path.display() ), Err(e) => warn!("{}", e), } } context.resolve_item(context.root_module()).codegen( context, &mut result, &(), ); if let Some(ref lib_name) = context.options().dynamic_library_name { let lib_ident = context.rust_ident(lib_name); let dynamic_items_tokens = result.dynamic_items().get_tokens(lib_ident); result.push(dynamic_items_tokens); } result.items }) } pub mod utils { use super::{error, ToRustTyOrOpaque}; use crate::ir::context::BindgenContext; use crate::ir::function::{Abi, FunctionSig}; use crate::ir::item::{Item, ItemCanonicalPath}; use crate::ir::ty::TypeKind; use proc_macro2; use std::borrow::Cow; use std::mem; use std::str::FromStr; pub fn prepend_bitfield_unit_type( ctx: &BindgenContext, result: &mut Vec, ) { let bitfield_unit_src = include_str!("./bitfield_unit.rs"); let bitfield_unit_src = if ctx.options().rust_features().min_const_fn { Cow::Borrowed(bitfield_unit_src) } else { Cow::Owned(bitfield_unit_src.replace("const fn ", "fn ")) }; let bitfield_unit_type = proc_macro2::TokenStream::from_str(&bitfield_unit_src).unwrap(); let bitfield_unit_type = quote!(#bitfield_unit_type); let items = vec![bitfield_unit_type]; let old_items = mem::replace(result, items); result.extend(old_items); } pub fn prepend_objc_header( ctx: &BindgenContext, result: &mut Vec, ) { let use_objc = if ctx.options().objc_extern_crate { quote! { #[macro_use] extern crate objc; } } else { quote! { use objc; } }; let id_type = quote! { #[allow(non_camel_case_types)] pub type id = *mut objc::runtime::Object; }; let items = vec![use_objc, id_type]; let old_items = mem::replace(result, items); result.extend(old_items.into_iter()); } pub fn prepend_block_header( ctx: &BindgenContext, result: &mut Vec, ) { let use_block = if ctx.options().block_extern_crate { quote! { extern crate block; } } else { quote! { use block; } }; let items = vec![use_block]; let old_items = mem::replace(result, items); result.extend(old_items.into_iter()); } pub fn prepend_union_types( ctx: &BindgenContext, result: &mut Vec, ) { let prefix = ctx.trait_prefix(); // If the target supports `const fn`, declare eligible functions // as `const fn` else just `fn`. let const_fn = if ctx.options().rust_features().min_const_fn { quote! { const fn } } else { quote! { fn } }; // TODO(emilio): The fmt::Debug impl could be way nicer with // std::intrinsics::type_name, but... let union_field_decl = quote! { #[repr(C)] pub struct __BindgenUnionField(::#prefix::marker::PhantomData); }; 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 { ::#prefix::mem::transmute(self) } #[inline] pub unsafe fn as_mut(&mut self) -> &mut T { ::#prefix::mem::transmute(self) } } }; let union_field_default_impl = quote! { impl ::#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::new() } } }; 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.into_iter()); } pub 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 ctx.options().rust_features().min_const_fn { quote! { const fn } } else { quote! { fn } }; let incomplete_array_decl = quote! { #[repr(C)] #[derive(Default)] pub struct __IncompleteArrayField( ::#prefix::marker::PhantomData, [T; 0]); }; 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] { ::#prefix::slice::from_raw_parts(self.as_ptr(), len) } #[inline] pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { ::#prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len) } } }; let incomplete_array_debug_impl = quote! { impl ::#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.into_iter()); } pub 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.into_iter()); } pub 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(tokens) } fn primitive_ty( ctx: &BindgenContext, name: &str, ) -> proc_macro2::TokenStream { let ident = ctx.rust_ident_raw(name); quote! { #ident } } pub fn type_from_named( ctx: &BindgenContext, name: &str, ) -> Option { // FIXME: We could use the inner item to check this is really a // primitive type but, who the heck overrides these anyway? Some(match name { "int8_t" => primitive_ty(ctx, "i8"), "uint8_t" => primitive_ty(ctx, "u8"), "int16_t" => primitive_ty(ctx, "i16"), "uint16_t" => primitive_ty(ctx, "u16"), "int32_t" => primitive_ty(ctx, "i32"), "uint32_t" => primitive_ty(ctx, "u32"), "int64_t" => primitive_ty(ctx, "i64"), "uint64_t" => primitive_ty(ctx, "u64"), "size_t" if ctx.options().size_t_is_usize => { primitive_ty(ctx, "usize") } "uintptr_t" => primitive_ty(ctx, "usize"), "ssize_t" if ctx.options().size_t_is_usize => { primitive_ty(ctx, "isize") } "intptr_t" | "ptrdiff_t" => primitive_ty(ctx, "isize"), _ => return None, }) } pub fn fnsig_return_ty( ctx: &BindgenContext, sig: &FunctionSig, ) -> proc_macro2::TokenStream { let return_item = ctx.resolve_item(sig.return_type()); if let TypeKind::Void = *return_item.kind().expect_type().kind() { quote! {} } else { let ret_ty = return_item.to_rust_ty_or_opaque(ctx, &()); quote! { -> #ret_ty } } } pub fn fnsig_arguments( ctx: &BindgenContext, sig: &FunctionSig, ) -> Vec { use super::ToPtr; let mut unnamed_arguments = 0; let mut args = sig .argument_types() .iter() .map(|&(ref name, ty)| { let arg_item = ctx.resolve_item(ty); let arg_ty = arg_item.kind().expect_type(); // From the C90 standard[1]: // // A declaration of a parameter as "array of type" shall be // adjusted to "qualified pointer to type", where the type // qualifiers (if any) are those specified within the [ and ] of // the array type derivation. // // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html let arg_ty = match *arg_ty.canonical_type(ctx).kind() { TypeKind::Array(t, _) => { let stream = if ctx.options().array_pointers_in_arguments { arg_ty.to_rust_ty_or_opaque(ctx, &arg_item) } else { t.to_rust_ty_or_opaque(ctx, &()) }; stream.to_ptr(ctx.resolve_type(t).is_const()) } TypeKind::Pointer(inner) => { let inner = ctx.resolve_item(inner); let inner_ty = inner.expect_type(); if let TypeKind::ObjCInterface(ref interface) = *inner_ty.canonical_type(ctx).kind() { let name = ctx.rust_ident(interface.name()); quote! { #name } } else { arg_item.to_rust_ty_or_opaque(ctx, &()) } } _ => arg_item.to_rust_ty_or_opaque(ctx, &()), }; let arg_name = match *name { Some(ref name) => ctx.rust_mangle(name).into_owned(), None => { unnamed_arguments += 1; format!("arg{}", unnamed_arguments) } }; assert!(!arg_name.is_empty()); let arg_name = ctx.rust_ident(arg_name); quote! { #arg_name : #arg_ty } }) .collect::>(); if sig.is_variadic() { args.push(quote! { ... }) } args } pub 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 = match *name { Some(ref name) => ctx.rust_mangle(name).into_owned(), None => { unnamed_arguments += 1; format!("arg{}", unnamed_arguments) } }; assert!(!arg_name.is_empty()); let arg_name = ctx.rust_ident(arg_name); quote! { #arg_name } }) .collect::>(); args } pub fn fnsig_block( ctx: &BindgenContext, sig: &FunctionSig, ) -> proc_macro2::TokenStream { let args = sig.argument_types().iter().map(|&(_, ty)| { let arg_item = ctx.resolve_item(ty); arg_item.to_rust_ty_or_opaque(ctx, &()) }); let return_item = ctx.resolve_item(sig.return_type()); let ret_ty = if let TypeKind::Void = *return_item.kind().expect_type().kind() { quote! { () } } else { return_item.to_rust_ty_or_opaque(ctx, &()) }; quote! { *const ::block::Block<(#(#args,)*), #ret_ty> } } // Returns true if `canonical_name` will end up as `mangled_name` at the // machine code level, i.e. after LLVM has applied any target specific // mangling. pub fn names_will_be_identical_after_mangling( canonical_name: &str, mangled_name: &str, call_conv: Option, ) -> bool { // If the mangled name and the canonical name are the same then no // mangling can have happened between the two versions. if canonical_name == mangled_name { return true; } // Working with &[u8] makes indexing simpler than with &str let canonical_name = canonical_name.as_bytes(); let mangled_name = mangled_name.as_bytes(); let (mangling_prefix, expect_suffix) = match call_conv { Some(Abi::C) | // None is the case for global variables None => { (b'_', false) } Some(Abi::Stdcall) => (b'_', true), Some(Abi::Fastcall) => (b'@', true), // This is something we don't recognize, stay on the safe side // by emitting the `#[link_name]` attribute Some(_) => return false, }; // Check that the mangled name is long enough to at least contain the // canonical name plus the expected prefix. if mangled_name.len() < canonical_name.len() + 1 { return false; } // Return if the mangled name does not start with the prefix expected // for the given calling convention. if mangled_name[0] != mangling_prefix { return false; } // Check that the mangled name contains the canonical name after the // prefix if &mangled_name[1..canonical_name.len() + 1] != canonical_name { return false; } // If the given calling convention also prescribes a suffix, check that // it exists too if expect_suffix { let suffix = &mangled_name[canonical_name.len() + 1..]; // The shortest suffix is "@0" if suffix.len() < 2 { return false; } // Check that the suffix starts with '@' and is all ASCII decimals // after that. if suffix[0] != b'@' || !suffix[1..].iter().all(u8::is_ascii_digit) { return false; } } else if mangled_name.len() != canonical_name.len() + 1 { // If we don't expect a prefix but there is one, we need the // #[link_name] attribute return false; } true } } bindgen-0.59.1/src/codegen/struct_layout.rs000064400000000000000000000321640000000000000167730ustar 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 proc_macro2::{self, Ident, Span}; use std::cmp; const MAX_GUARANTEED_ALIGN: usize = 8; /// Trace the layout of struct. #[derive(Debug)] pub struct StructLayoutTracker<'a> { name: &'a str, ctx: &'a BindgenContext, comp: &'a CompInfo, is_packed: bool, known_type_layout: Option, is_rust_union: bool, latest_offset: usize, padding_count: usize, latest_field_layout: Option, max_field_align: usize, last_field_was_bitfield: bool, } /// Returns a size aligned to a given value. pub fn align_to(size: usize, align: usize) -> usize { if align == 0 { return size; } let rem = size % align; if rem == 0 { return size; } size + align - rem } /// Returns the lower power of two byte count that can hold at most n bits. pub fn bytes_from_bits_pow2(mut n: usize) -> usize { if n == 0 { return 0; } if n <= 8 { return 1; } if !n.is_power_of_two() { n = n.next_power_of_two(); } n / 8 } #[test] fn test_align_to() { assert_eq!(align_to(1, 1), 1); assert_eq!(align_to(1, 2), 2); assert_eq!(align_to(1, 4), 4); assert_eq!(align_to(5, 1), 5); assert_eq!(align_to(17, 4), 20); } #[test] fn test_bytes_from_bits_pow2() { assert_eq!(bytes_from_bits_pow2(0), 0); for i in 1..9 { assert_eq!(bytes_from_bits_pow2(i), 1); } for i in 9..17 { assert_eq!(bytes_from_bits_pow2(i), 2); } for i in 17..33 { assert_eq!(bytes_from_bits_pow2(i), 4); } } impl<'a> StructLayoutTracker<'a> { pub fn new( ctx: &'a BindgenContext, comp: &'a CompInfo, ty: &'a Type, name: &'a str, ) -> Self { let known_type_layout = ty.layout(ctx); let is_packed = comp.is_packed(ctx, known_type_layout.as_ref()); let is_rust_union = comp.is_union() && comp.can_be_rust_union(ctx, known_type_layout.as_ref()); StructLayoutTracker { name, ctx, comp, is_packed, known_type_layout, is_rust_union, latest_offset: 0, padding_count: 0, latest_field_layout: None, max_field_align: 0, last_field_was_bitfield: false, } } pub fn is_rust_union(&self) -> bool { self.is_rust_union } pub fn saw_vtable(&mut self) { debug!("saw vtable for {}", self.name); let ptr_size = self.ctx.target_pointer_size(); self.latest_offset += ptr_size; self.latest_field_layout = Some(Layout::new(ptr_size, ptr_size)); self.max_field_align = ptr_size; } pub fn saw_base(&mut self, base_ty: &Type) { debug!("saw base for {}", self.name); if let Some(layout) = base_ty.layout(self.ctx) { self.align_to_latest_field(layout); self.latest_offset += self.padding_bytes(layout) + layout.size; self.latest_field_layout = Some(layout); self.max_field_align = cmp::max(self.max_field_align, layout.align); } } pub fn saw_bitfield_unit(&mut self, layout: Layout) { debug!("saw bitfield unit for {}: {:?}", self.name, layout); self.align_to_latest_field(layout); self.latest_offset += layout.size; debug!( "Offset: : {} -> {}", self.latest_offset - layout.size, self.latest_offset ); self.latest_field_layout = Some(layout); self.last_field_was_bitfield = true; // NB: We intentionally don't update the max_field_align here, since our // bitfields code doesn't necessarily guarantee it, so we need to // actually generate the dummy alignment. } /// Returns a padding field if necessary for a given new field _before_ /// adding that field. pub fn saw_field( &mut self, field_name: &str, field_ty: &Type, field_offset: Option, ) -> 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 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(l) = self.known_type_layout { self.padding_bytes(l) } else { 0 } } }; self.latest_offset += padding_bytes; let padding_layout = if self.is_packed || is_union { None } else { let force_padding = self.ctx.options().force_explicit_padding; // Otherwise the padding is useless. let need_padding = force_padding || padding_bytes >= field_layout.align || field_layout.align > MAX_GUARANTEED_ALIGN; debug!( "Offset: : {} -> {}", self.latest_offset - padding_bytes, self.latest_offset ); debug!( "align field {} to {}/{} with {} padding bytes {:?}", field_name, self.latest_offset, field_offset.unwrap_or(0) / 8, padding_bytes, field_layout ); let padding_align = if force_padding { 1 } else { cmp::min(field_layout.align, MAX_GUARANTEED_ALIGN) }; if need_padding && padding_bytes != 0 { Some(Layout::new(padding_bytes, padding_align)) } else { None } }; self.latest_offset += field_layout.size; self.latest_field_layout = Some(field_layout); self.max_field_align = cmp::max(self.max_field_align, field_layout.align); self.last_field_was_bitfield = false; debug!( "Offset: {}: {} -> {}", field_name, self.latest_offset - field_layout.size, self.latest_offset ); padding_layout.map(|layout| self.padding_field(layout)) } pub fn add_tail_padding( &mut self, comp_name: &str, comp_layout: Layout, ) -> Option { // 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; } if self.latest_offset == comp_layout.size { // This struct does not contain tail padding. return None; } trace!( "need a tail padding field for {}: offset {} -> size {}", comp_name, self.latest_offset, comp_layout.size ); let size = comp_layout.size - self.latest_offset; Some(self.padding_field(Layout::new(size, 0))) } pub fn pad_struct( &mut self, layout: Layout, ) -> Option { debug!( "pad_struct:\n\tself = {:#?}\n\tlayout = {:#?}", self, layout ); if layout.size < self.latest_offset { warn!( "Calculated wrong layout for {}, too more {} bytes", self.name, self.latest_offset - layout.size ); return None; } let padding_bytes = layout.size - self.latest_offset; if padding_bytes == 0 { return None; } let repr_align = self.ctx.options().rust_features().repr_align; // We always pad to get to the correct size if the struct is one of // those we can't align properly. // // Note that if the last field we saw was a bitfield, we may need to pad // regardless, because bitfields don't respect alignment as strictly as // other fields. if padding_bytes >= layout.align || (self.last_field_was_bitfield && padding_bytes >= self.latest_field_layout.unwrap().align) || (!repr_align && layout.align > MAX_GUARANTEED_ALIGN) { let layout = if self.is_packed { Layout::new(padding_bytes, 1) } else if self.last_field_was_bitfield || layout.align > MAX_GUARANTEED_ALIGN { // We've already given up on alignment here. Layout::for_size(self.ctx, padding_bytes) } else { Layout::new(padding_bytes, layout.align) }; debug!("pad bytes to struct {}, {:?}", self.name, layout); Some(self.padding_field(layout)) } else { None } } pub fn requires_explicit_align(&self, layout: Layout) -> bool { let repr_align = self.ctx.options().rust_features().repr_align; // Always force explicit repr(align) for stuff more than 16-byte aligned // to work-around https://github.com/rust-lang/rust/issues/54341. // // Worst-case this just generates redundant alignment attributes. if repr_align && self.max_field_align >= 16 { return true; } if self.max_field_align >= layout.align { return false; } // We can only generate up-to a 8-bytes of alignment unless we support // repr(align). repr_align || layout.align <= MAX_GUARANTEED_ALIGN } fn padding_bytes(&self, layout: Layout) -> usize { align_to(self.latest_offset, layout.align) - self.latest_offset } fn padding_field(&mut self, layout: Layout) -> proc_macro2::TokenStream { let ty = helpers::blob(self.ctx, layout); let padding_count = self.padding_count; self.padding_count += 1; let padding_field_name = Ident::new( &format!("__bindgen_padding_{}", padding_count), Span::call_site(), ); self.max_field_align = cmp::max(self.max_field_align, layout.align); quote! { pub #padding_field_name : #ty , } } /// Returns whether the new field is known to merge with a bitfield. /// /// This is just to avoid doing the same check also in pad_field. fn align_to_latest_field(&mut self, new_field_layout: Layout) -> bool { if self.is_packed { // Skip to align fields when packed. return false; } let layout = match self.latest_field_layout { Some(l) => l, None => return false, }; // If it was, we may or may not need to align, depending on what the // current field alignment and the bitfield size and alignment are. debug!( "align_to_bitfield? {}: {:?} {:?}", self.last_field_was_bitfield, layout, new_field_layout ); // Avoid divide-by-zero errors if align is 0. let align = cmp::max(1, layout.align); if self.last_field_was_bitfield && new_field_layout.align <= layout.size % align && new_field_layout.size <= layout.size % align { // The new field will be coalesced into some of the remaining bits. // // FIXME(emilio): I think this may not catch everything? debug!("Will merge with bitfield"); return true; } // Else, just align the obvious way. self.latest_offset += self.padding_bytes(layout); return false; } } bindgen-0.59.1/src/deps.rs000064400000000000000000000007760000000000000134050ustar 00000000000000/// Generating build depfiles from parsed bindings. use std::{collections::BTreeSet, path::PathBuf}; #[derive(Debug)] pub(crate) struct DepfileSpec { pub output_module: String, pub depfile_path: PathBuf, } impl DepfileSpec { pub fn write(&self, deps: &BTreeSet) -> std::io::Result<()> { let mut buf = format!("{}:", self.output_module); for file in deps { buf = format!("{} {}", buf, file); } std::fs::write(&self.depfile_path, &buf) } } bindgen-0.59.1/src/extra_assertions.rs000064400000000000000000000020230000000000000160320ustar 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_export] macro_rules! extra_assert { ( $cond:expr ) => { if cfg!(feature = "testing_only_extra_assertions") { assert!($cond); } }; ( $cond:expr , $( $arg:tt )+ ) => { if cfg!(feature = "testing_only_extra_assertions") { assert!($cond, $( $arg )* ) } }; } /// Simple macro that forwards to assert_eq! when using /// testing_only_extra_assertions. #[macro_export] macro_rules! extra_assert_eq { ( $lhs:expr , $rhs:expr ) => { if cfg!(feature = "testing_only_extra_assertions") { assert_eq!($lhs, $rhs); } }; ( $lhs:expr , $rhs:expr , $( $arg:tt )+ ) => { if cfg!(feature = "testing_only_extra_assertions") { assert!($lhs, $rhs, $( $arg )* ); } }; } bindgen-0.59.1/src/features.rs000064400000000000000000000224720000000000000142650ustar 00000000000000//! Contains code for selecting features #![deny(missing_docs)] #![deny(unused_extern_crates)] use std::io; use std::str::FromStr; /// Define RustTarget struct definition, Default impl, and conversions /// between RustTarget and String. macro_rules! rust_target_def { ( $( $( #[$attr:meta] )* => $release:ident => $value:expr; )* ) => { /// Represents the version of the Rust language to target. /// /// To support a beta release, use the corresponding stable release. /// /// This enum will have more variants added as necessary. #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Hash)] #[allow(non_camel_case_types)] pub enum RustTarget { $( $( #[$attr] )* $release, )* } impl Default for RustTarget { /// Gives the latest stable Rust version fn default() -> RustTarget { LATEST_STABLE_RUST } } impl FromStr for RustTarget { type Err = io::Error; /// Create a `RustTarget` from a string. /// /// * The stable/beta versions of Rust are of the form "1.0", /// "1.19", etc. /// * The nightly version should be specified with "nightly". fn from_str(s: &str) -> Result { match s.as_ref() { $( stringify!($value) => Ok(RustTarget::$release), )* _ => Err( io::Error::new( io::ErrorKind::InvalidInput, concat!( "Got an invalid rust target. Accepted values ", "are of the form ", "\"1.0\" or \"nightly\"."))), } } } impl From for String { fn from(target: RustTarget) -> Self { match target { $( RustTarget::$release => stringify!($value), )* }.into() } } } } /// Defines an array slice with all RustTarget values macro_rules! rust_target_values_def { ( $( $( #[$attr:meta] )* => $release:ident => $value:expr; )* ) => { /// Strings of allowed `RustTarget` values pub static RUST_TARGET_STRINGS: &'static [&str] = &[ $( stringify!($value), )* ]; } } /// Defines macro which takes a macro macro_rules! rust_target_base { ( $x_macro:ident ) => { $x_macro!( /// Rust stable 1.0 => Stable_1_0 => 1.0; /// Rust stable 1.1 => Stable_1_1 => 1.1; /// Rust stable 1.19 /// * Untagged unions ([RFC 1444](https://github.com/rust-lang/rfcs/blob/master/text/1444-union.md)) => Stable_1_19 => 1.19; /// Rust stable 1.20 /// * Associated constants ([PR](https://github.com/rust-lang/rust/pull/42809)) => Stable_1_20 => 1.20; /// Rust stable 1.21 /// * Builtin impls for `Clone` ([PR](https://github.com/rust-lang/rust/pull/43690)) => Stable_1_21 => 1.21; /// Rust stable 1.25 /// * `repr(align)` ([PR](https://github.com/rust-lang/rust/pull/47006)) => Stable_1_25 => 1.25; /// Rust stable 1.26 /// * [i128 / u128 support](https://doc.rust-lang.org/std/primitive.i128.html) => Stable_1_26 => 1.26; /// Rust stable 1.27 /// * `must_use` attribute on functions ([PR](https://github.com/rust-lang/rust/pull/48925)) => Stable_1_27 => 1.27; /// Rust stable 1.28 /// * `repr(transparent)` ([PR](https://github.com/rust-lang/rust/pull/51562)) => Stable_1_28 => 1.28; /// Rust stable 1.30 /// * `const fn` support for limited cases ([PR](https://github.com/rust-lang/rust/pull/54835/) /// * [c_void available in core](https://doc.rust-lang.org/core/ffi/enum.c_void.html) => Stable_1_30 => 1.30; /// Rust stable 1.33 /// * repr(packed(N)) ([PR](https://github.com/rust-lang/rust/pull/57049)) => Stable_1_33 => 1.33; /// Rust stable 1.36 /// * `MaybeUninit` instead of `mem::uninitialized()` ([PR](https://github.com/rust-lang/rust/pull/60445)) => Stable_1_36 => 1.36; /// Rust stable 1.40 /// * `non_exhaustive` enums/structs ([Tracking issue](https://github.com/rust-lang/rust/issues/44109)) => Stable_1_40 => 1.40; /// Rust stable 1.47 /// * `larger_arrays` ([Tracking issue](https://github.com/rust-lang/rust/pull/74060)) => Stable_1_47 => 1.47; /// Nightly rust /// * `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202)) => Nightly => nightly; ); } } rust_target_base!(rust_target_def); rust_target_base!(rust_target_values_def); /// Latest stable release of Rust pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_47; /// Create RustFeatures struct definition, new(), and a getter for each field macro_rules! rust_feature_def { ( $( $rust_target:ident { $( $( #[$attr:meta] )* => $feature:ident; )* } )* ) => { /// Features supported by a rust target #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[allow(missing_docs)] // Documentation should go into the relevant variants. pub(crate) struct RustFeatures { $( $( $( #[$attr] )* pub $feature: bool, )* )* } impl RustFeatures { /// Gives a RustFeatures struct with all features disabled fn new() -> Self { RustFeatures { $( $( $feature: false, )* )* } } } impl From for RustFeatures { fn from(rust_target: RustTarget) -> Self { let mut features = RustFeatures::new(); $( if rust_target >= RustTarget::$rust_target { $( features.$feature = true; )* } )* features } } } } // NOTE(emilio): When adding or removing features here, make sure to update the // documentation for the relevant variant in the rust_target_base macro // definition. rust_feature_def!( Stable_1_19 { => untagged_union; } Stable_1_20 { => associated_const; } Stable_1_21 { => builtin_clone_impls; } Stable_1_25 { => repr_align; } Stable_1_26 { => i128_and_u128; } Stable_1_27 { => must_use_function; } Stable_1_28 { => repr_transparent; } Stable_1_30 { => min_const_fn; => core_ffi_c_void; } Stable_1_33 { => repr_packed_n; } Stable_1_36 { => maybe_uninit; } Stable_1_40 { => non_exhaustive; } Stable_1_47 { => larger_arrays; } Nightly { => thiscall_abi; } ); impl Default for RustFeatures { fn default() -> Self { let default_rust_target: RustTarget = Default::default(); Self::from(default_rust_target) } } #[cfg(test)] mod test { #![allow(unused_imports)] use super::*; #[test] fn target_features() { let f_1_0 = RustFeatures::from(RustTarget::Stable_1_0); assert!( !f_1_0.core_ffi_c_void && !f_1_0.untagged_union && !f_1_0.associated_const && !f_1_0.builtin_clone_impls && !f_1_0.repr_align && !f_1_0.thiscall_abi ); let f_1_21 = RustFeatures::from(RustTarget::Stable_1_21); assert!( !f_1_21.core_ffi_c_void && f_1_21.untagged_union && f_1_21.associated_const && f_1_21.builtin_clone_impls && !f_1_21.repr_align && !f_1_21.thiscall_abi ); let f_nightly = RustFeatures::from(RustTarget::Nightly); assert!( f_nightly.core_ffi_c_void && f_nightly.untagged_union && f_nightly.associated_const && f_nightly.builtin_clone_impls && f_nightly.maybe_uninit && f_nightly.repr_align && f_nightly.thiscall_abi ); } fn test_target(target_str: &str, target: RustTarget) { let target_string: String = target.into(); assert_eq!(target_str, target_string); assert_eq!(target, RustTarget::from_str(target_str).unwrap()); } #[test] fn str_to_target() { test_target("1.0", RustTarget::Stable_1_0); test_target("1.19", RustTarget::Stable_1_19); test_target("1.21", RustTarget::Stable_1_21); test_target("1.25", RustTarget::Stable_1_25); test_target("nightly", RustTarget::Nightly); } } bindgen-0.59.1/src/ir/analysis/derive.rs000064400000000000000000000640560000000000000161660ustar 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::template::TemplateParameters; use crate::ir::traversal::{EdgeKind, Trace}; use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT; use crate::ir::ty::{Type, TypeKind}; use crate::{Entry, HashMap, HashSet}; /// Which trait to consider when doing the `CannotDerive` analysis. #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub enum DeriveTrait { /// The `Copy` trait. Copy, /// The `Debug` trait. Debug, /// The `Default` trait. Default, /// The `Hash` trait. Hash, /// The `PartialEq` and `PartialOrd` traits. PartialEqOrPartialOrd, } /// An analysis that finds for each IR item whether a trait cannot be derived. /// /// We use the monotone constraint function `cannot_derive`, defined as follows /// for type T: /// /// * If T is Opaque and the layout of the type is known, get this layout as an /// opaquetype and check whether it can derive using trivial checks. /// /// * If T is Array, a trait cannot be derived if the array is incomplete, /// if the length of the array is larger than the limit (unless the trait /// allows it), or the trait cannot be derived for the type of data the array /// contains. /// /// * If T is Vector, a trait cannot be derived if the trait cannot be derived /// for the type of data the vector contains. /// /// * If T is a type alias, a templated alias or an indirection to another type, /// the trait cannot be derived if the trait cannot be derived for type T /// refers to. /// /// * If T is a compound type, the trait cannot be derived if the trait cannot /// be derived for any of its base members or fields. /// /// * If T is an instantiation of an abstract template definition, the trait /// cannot be derived if any of the template arguments or template definition /// cannot derive the trait. /// /// * For all other (simple) types, compiler and standard library limitations /// dictate whether the trait is implemented. #[derive(Debug, Clone)] pub struct CannotDerive<'ctx> { ctx: &'ctx BindgenContext, derive_trait: DeriveTrait, // The incremental result of this analysis's computation. // Contains information whether particular item can derive `derive_trait` can_derive: HashMap, // 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<'ctx> CannotDerive<'ctx> { fn insert>( &mut self, id: Id, can_derive: CanDerive, ) -> ConstrainResult { let id = id.into(); trace!( "inserting {:?} can_derive<{}>={:?}", id, self.derive_trait, can_derive ); if let CanDerive::Yes = can_derive { return ConstrainResult::Same; } match self.can_derive.entry(id) { Entry::Occupied(mut entry) => { if *entry.get() < can_derive { entry.insert(can_derive); ConstrainResult::Changed } else { ConstrainResult::Same } } Entry::Vacant(entry) => { entry.insert(can_derive); ConstrainResult::Changed } } } fn constrain_type(&mut self, item: &Item, ty: &Type) -> CanDerive { if !self.ctx.allowlisted_items().contains(&item.id()) { let can_derive = self .ctx .blocklisted_type_implements_trait(item, self.derive_trait); match can_derive { CanDerive::Yes => trace!( " blocklisted type explicitly implements {}", self.derive_trait ), CanDerive::Manually => trace!( " blocklisted type requires manual implementation of {}", self.derive_trait ), CanDerive::No => trace!( " cannot derive {} for blocklisted type", self.derive_trait ), } return can_derive; } if self.derive_trait.not_by_name(self.ctx, &item) { trace!( " cannot derive {} for explicitly excluded type", self.derive_trait ); return CanDerive::No; } trace!("ty: {:?}", ty); if item.is_opaque(self.ctx, &()) { if !self.derive_trait.can_derive_union() && ty.is_union() && self.ctx.options().rust_features().untagged_union { trace!( " cannot derive {} for Rust unions", self.derive_trait ); return CanDerive::No; } let layout_can_derive = ty.layout(self.ctx).map_or(CanDerive::Yes, |l| { l.opaque().array_size_within_derive_limit(self.ctx) }); match layout_can_derive { CanDerive::Yes => { trace!( " we can trivially derive {} for the layout", self.derive_trait ); } _ => { trace!( " we cannot derive {} for the layout", self.derive_trait ); } }; return layout_can_derive; } match *ty.kind() { // Handle the simple cases. These can derive traits without further // information. TypeKind::Void | TypeKind::NullPtr | TypeKind::Int(..) | TypeKind::Complex(..) | TypeKind::Float(..) | TypeKind::Enum(..) | TypeKind::TypeParam | TypeKind::UnresolvedTypeRef(..) | TypeKind::Reference(..) | TypeKind::ObjCInterface(..) | TypeKind::ObjCId | TypeKind::ObjCSel => { return self.derive_trait.can_derive_simple(ty.kind()); } TypeKind::Pointer(inner) => { let inner_type = self.ctx.resolve_type(inner).canonical_type(self.ctx); if let TypeKind::Function(ref sig) = *inner_type.kind() { return self.derive_trait.can_derive_fnptr(sig); } else { return self.derive_trait.can_derive_pointer(); } } TypeKind::Function(ref sig) => { return self.derive_trait.can_derive_fnptr(sig) } // Complex cases need more information TypeKind::Array(t, len) => { let inner_type = self.can_derive.get(&t.into()).cloned().unwrap_or_default(); if inner_type != CanDerive::Yes { trace!( " arrays of T for which we cannot derive {} \ also cannot derive {}", self.derive_trait, self.derive_trait ); return CanDerive::No; } if len == 0 && !self.derive_trait.can_derive_incomplete_array() { trace!( " cannot derive {} for incomplete arrays", self.derive_trait ); return CanDerive::No; } if self.derive_trait.can_derive_large_array(&self.ctx) { trace!(" array can derive {}", self.derive_trait); return CanDerive::Yes; } if len > RUST_DERIVE_IN_ARRAY_LIMIT { trace!( " array is too large to derive {}, but it may be implemented", self.derive_trait ); return CanDerive::Manually; } trace!( " array is small enough to derive {}", self.derive_trait ); return CanDerive::Yes; } TypeKind::Vector(t, len) => { let inner_type = self.can_derive.get(&t.into()).cloned().unwrap_or_default(); if inner_type != CanDerive::Yes { trace!( " vectors of T for which we cannot derive {} \ also cannot derive {}", self.derive_trait, self.derive_trait ); return CanDerive::No; } assert_ne!(len, 0, "vectors cannot have zero length"); return self.derive_trait.can_derive_vector(); } TypeKind::Comp(ref info) => { assert!( !info.has_non_type_template_params(), "The early ty.is_opaque check should have handled this case" ); if !self.derive_trait.can_derive_compound_forward_decl() && info.is_forward_declaration() { trace!( " cannot derive {} for forward decls", self.derive_trait ); return CanDerive::No; } // NOTE: Take into account that while unions in C and C++ are copied by // default, the may have an explicit destructor in C++, so we can't // defer this check just for the union case. if !self.derive_trait.can_derive_compound_with_destructor() && self.ctx.lookup_has_destructor( item.id().expect_type_id(self.ctx), ) { trace!( " comp has destructor which cannot derive {}", self.derive_trait ); return CanDerive::No; } if info.kind() == CompKind::Union { if self.derive_trait.can_derive_union() { if self.ctx.options().rust_features().untagged_union && // https://github.com/rust-lang/rust/issues/36640 (!info.self_template_params(self.ctx).is_empty() || !item.all_template_params(self.ctx).is_empty()) { trace!( " cannot derive {} for Rust union because issue 36640", self.derive_trait ); return CanDerive::No; } // fall through to be same as non-union handling } else { if self.ctx.options().rust_features().untagged_union { trace!( " cannot derive {} for Rust unions", self.derive_trait ); return CanDerive::No; } let layout_can_derive = ty.layout(self.ctx).map_or(CanDerive::Yes, |l| { l.opaque() .array_size_within_derive_limit(self.ctx) }); match layout_can_derive { CanDerive::Yes => { trace!( " union layout can trivially derive {}", self.derive_trait ); } _ => { trace!( " union layout cannot derive {}", self.derive_trait ); } }; return layout_can_derive; } } if !self.derive_trait.can_derive_compound_with_vtable() && item.has_vtable(self.ctx) { trace!( " cannot derive {} for comp with vtable", self.derive_trait ); return CanDerive::No; } // Bitfield units are always represented as arrays of u8, but // they're not traced as arrays, so we need to check here // instead. if !self.derive_trait.can_derive_large_array(&self.ctx) && info.has_too_large_bitfield_unit() && !item.is_opaque(self.ctx, &()) { trace!( " cannot derive {} for comp with too large bitfield unit", self.derive_trait ); return CanDerive::No; } let pred = self.derive_trait.consider_edge_comp(); return self.constrain_join(item, pred); } TypeKind::ResolvedTypeRef(..) | TypeKind::TemplateAlias(..) | TypeKind::Alias(..) | TypeKind::BlockPointer(..) => { let pred = self.derive_trait.consider_edge_typeref(); return self.constrain_join(item, pred); } TypeKind::TemplateInstantiation(..) => { let pred = self.derive_trait.consider_edge_tmpl_inst(); return self.constrain_join(item, pred); } TypeKind::Opaque => unreachable!( "The early ty.is_opaque check should have handled this case" ), } } fn constrain_join( &mut self, item: &Item, consider_edge: EdgePredicate, ) -> CanDerive { let mut candidate = None; item.trace( self.ctx, &mut |sub_id, edge_kind| { // Ignore ourselves, since union with ourself is a // no-op. Ignore edges that aren't relevant to the // analysis. if sub_id == item.id() || !consider_edge(edge_kind) { return; } let can_derive = self.can_derive .get(&sub_id) .cloned() .unwrap_or_default(); match can_derive { CanDerive::Yes => trace!(" member {:?} can derive {}", sub_id, self.derive_trait), CanDerive::Manually => trace!(" member {:?} cannot derive {}, but it may be implemented", sub_id, self.derive_trait), CanDerive::No => trace!(" member {:?} cannot derive {}", sub_id, self.derive_trait), } *candidate.get_or_insert(CanDerive::Yes) |= can_derive; }, &(), ); if candidate.is_none() { trace!( " can derive {} because there are no members", self.derive_trait ); } candidate.unwrap_or_default() } } impl DeriveTrait { fn not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool { match self { DeriveTrait::Copy => ctx.no_copy_by_name(item), DeriveTrait::Debug => ctx.no_debug_by_name(item), DeriveTrait::Default => ctx.no_default_by_name(item), DeriveTrait::Hash => ctx.no_hash_by_name(item), DeriveTrait::PartialEqOrPartialOrd => { ctx.no_partialeq_by_name(item) } } } fn consider_edge_comp(&self) -> EdgePredicate { match self { DeriveTrait::PartialEqOrPartialOrd => consider_edge_default, _ => |kind| match kind { EdgeKind::BaseMember | EdgeKind::Field => true, _ => false, }, } } 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| match kind { EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration => { true } _ => false, }, } } fn can_derive_large_array(&self, ctx: &BindgenContext) -> bool { if ctx.options().rust_features().larger_arrays { match self { DeriveTrait::Default => false, _ => true, } } else { match self { DeriveTrait::Copy => true, _ => false, } } } fn can_derive_union(&self) -> bool { match self { DeriveTrait::Copy => true, _ => false, } } fn can_derive_compound_with_destructor(&self) -> bool { match self { DeriveTrait::Copy => false, _ => true, } } fn can_derive_compound_with_vtable(&self) -> bool { match self { DeriveTrait::Default => false, _ => true, } } fn can_derive_compound_forward_decl(&self) -> bool { match self { DeriveTrait::Copy | DeriveTrait::Debug => true, _ => false, } } fn can_derive_incomplete_array(&self) -> bool { match self { DeriveTrait::Copy | DeriveTrait::Hash | DeriveTrait::PartialEqOrPartialOrd => false, _ => true, } } fn can_derive_fnptr(&self, f: &FunctionSig) -> CanDerive { match (self, f.function_pointers_can_derive()) { (DeriveTrait::Copy, _) | (DeriveTrait::Default, _) | (_, true) => { trace!(" function pointer can derive {}", self); CanDerive::Yes } (DeriveTrait::Debug, false) => { trace!(" function pointer cannot derive {}, but it may be implemented", self); CanDerive::Manually } (_, false) => { trace!(" function pointer cannot derive {}", self); CanDerive::No } } } fn can_derive_vector(&self) -> CanDerive { match self { DeriveTrait::PartialEqOrPartialOrd => { // FIXME: vectors always can derive PartialEq, but they should // not derive PartialOrd: // https://github.com/rust-lang-nursery/packed_simd/issues/48 trace!(" vectors cannot derive PartialOrd"); CanDerive::No } _ => { trace!(" vector can derive {}", self); CanDerive::Yes } } } fn can_derive_pointer(&self) -> CanDerive { match self { DeriveTrait::Default => { trace!(" pointer cannot derive Default"); CanDerive::No } _ => { trace!(" pointer can derive {}", self); CanDerive::Yes } } } fn can_derive_simple(&self, kind: &TypeKind) -> CanDerive { match (self, kind) { // === Default === (DeriveTrait::Default, TypeKind::Void) | (DeriveTrait::Default, TypeKind::NullPtr) | (DeriveTrait::Default, TypeKind::Enum(..)) | (DeriveTrait::Default, TypeKind::Reference(..)) | (DeriveTrait::Default, TypeKind::TypeParam) | (DeriveTrait::Default, TypeKind::ObjCInterface(..)) | (DeriveTrait::Default, TypeKind::ObjCId) | (DeriveTrait::Default, TypeKind::ObjCSel) => { trace!(" types that always cannot derive Default"); CanDerive::No } (DeriveTrait::Default, TypeKind::UnresolvedTypeRef(..)) => { unreachable!( "Type with unresolved type ref can't reach derive default" ) } // === Hash === (DeriveTrait::Hash, TypeKind::Float(..)) | (DeriveTrait::Hash, TypeKind::Complex(..)) => { trace!(" float cannot derive Hash"); CanDerive::No } // === others === _ => { trace!(" simple type that can always derive {}", self); CanDerive::Yes } } } } impl fmt::Display for DeriveTrait { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self { DeriveTrait::Copy => "Copy", DeriveTrait::Debug => "Debug", DeriveTrait::Default => "Default", DeriveTrait::Hash => "Hash", DeriveTrait::PartialEqOrPartialOrd => "PartialEq/PartialOrd", }; s.fmt(f) } } impl<'ctx> MonotoneFramework for CannotDerive<'ctx> { type Node = ItemId; type Extra = (&'ctx BindgenContext, DeriveTrait); type Output = HashMap; 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() .cloned() .flat_map(|i| { let mut reachable = vec![i]; i.trace( self.ctx, &mut |s, _| { reachable.push(s); }, &(), ); reachable }) .collect() } fn constrain(&mut self, id: ItemId) -> ConstrainResult { trace!("constrain: {:?}", id); if let Some(CanDerive::No) = self.can_derive.get(&id).cloned() { trace!(" already know it cannot derive {}", self.derive_trait); return ConstrainResult::Same; } let item = self.ctx.resolve_item(id); let can_derive = match item.as_type() { Some(ty) => { let mut can_derive = self.constrain_type(item, ty); if let CanDerive::Yes = can_derive { if !self.derive_trait.can_derive_large_array(&self.ctx) && ty.layout(self.ctx).map_or(false, |l| { l.align > RUST_DERIVE_IN_ARRAY_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 {:?} into worklist", item); 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 fn as_cannot_derive_set( can_derive: HashMap, ) -> HashSet { can_derive .into_iter() .filter_map(|(k, v)| if v != CanDerive::Yes { Some(k) } else { None }) .collect() } bindgen-0.59.1/src/ir/analysis/has_destructor.rs000064400000000000000000000144170000000000000177350ustar 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 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<'ctx> HasDestructorAnalysis<'ctx> { fn consider_edge(kind: EdgeKind) -> bool { match kind { // These are the only edges that can affect whether a type has a // destructor or not. EdgeKind::TypeReference | EdgeKind::BaseMember | EdgeKind::Field | EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration => true, _ => false, } } 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 {:?} twice because if it was \ already in the set, `constrain` should have exited early.", id ); ConstrainResult::Changed } } impl<'ctx> MonotoneFramework for HasDestructorAnalysis<'ctx> { type Node = ItemId; type Extra = &'ctx BindgenContext; type Output = HashSet; 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().cloned().collect() } fn constrain(&mut self, id: ItemId) -> ConstrainResult { if self.have_destructor.contains(&id) { // We've already computed that this type has a destructor and that can't // change. return ConstrainResult::Same; } let item = self.ctx.resolve_item(id); let ty = match item.as_type() { None => return ConstrainResult::Same, Some(ty) => ty, }; match *ty.kind() { TypeKind::TemplateAlias(t, _) | TypeKind::Alias(t) | TypeKind::ResolvedTypeRef(t) => { if self.have_destructor.contains(&t.into()) { self.insert(id) } else { ConstrainResult::Same } } TypeKind::Comp(ref info) => { if info.has_own_destructor() { return self.insert(id); } match info.kind() { CompKind::Union => ConstrainResult::Same, CompKind::Struct => { let base_or_field_destructor = info.base_members().iter().any(|base| { self.have_destructor.contains(&base.ty.into()) }) || info.fields().iter().any( |field| match *field { Field::DataMember(ref data) => self .have_destructor .contains(&data.ty().into()), Field::Bitfields(_) => false, }, ); if base_or_field_destructor { self.insert(id) } else { ConstrainResult::Same } } } } TypeKind::TemplateInstantiation(ref inst) => { let definition_or_arg_destructor = self .have_destructor .contains(&inst.template_definition().into()) || inst.template_arguments().iter().any(|arg| { self.have_destructor.contains(&arg.into()) }); if definition_or_arg_destructor { self.insert(id) } else { ConstrainResult::Same } } _ => ConstrainResult::Same, } } fn each_depending_on(&self, id: ItemId, mut f: F) where F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&id) { for item in edges { trace!("enqueue {:?} into worklist", item); f(*item); } } } } impl<'ctx> From> for HashSet { fn from(analysis: HasDestructorAnalysis<'ctx>) -> Self { analysis.have_destructor } } bindgen-0.59.1/src/ir/analysis/has_float.rs000064400000000000000000000207200000000000000166360ustar 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 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<'ctx> HasFloat<'ctx> { fn consider_edge(kind: EdgeKind) -> bool { match kind { EdgeKind::BaseMember | EdgeKind::Field | EdgeKind::TypeReference | EdgeKind::VarType | EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration | EdgeKind::TemplateParameterDefinition => true, EdgeKind::Constructor | EdgeKind::Destructor | EdgeKind::FunctionReturn | EdgeKind::FunctionParameter | EdgeKind::InnerType | EdgeKind::InnerVar | EdgeKind::Method => false, EdgeKind::Generic => false, } } fn insert>(&mut self, id: Id) -> ConstrainResult { let id = id.into(); trace!("inserting {:?} into the has_float set", id); let was_not_already_in_set = self.has_float.insert(id); assert!( was_not_already_in_set, "We shouldn't try and insert {:?} twice because if it was \ already in the set, `constrain` should have exited early.", id ); ConstrainResult::Changed } } impl<'ctx> MonotoneFramework for HasFloat<'ctx> { type Node = ItemId; type Extra = &'ctx BindgenContext; type Output = HashSet; 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().cloned().collect() } fn constrain(&mut self, id: ItemId) -> ConstrainResult { trace!("constrain: {:?}", id); if self.has_float.contains(&id) { trace!(" already know it do not have float"); return ConstrainResult::Same; } let item = self.ctx.resolve_item(id); let ty = match item.as_type() { Some(ty) => ty, None => { trace!(" not a type; ignoring"); return ConstrainResult::Same; } }; match *ty.kind() { TypeKind::Void | TypeKind::NullPtr | TypeKind::Int(..) | TypeKind::Function(..) | TypeKind::Enum(..) | TypeKind::Reference(..) | TypeKind::TypeParam | TypeKind::Opaque | TypeKind::Pointer(..) | TypeKind::UnresolvedTypeRef(..) | TypeKind::ObjCInterface(..) | TypeKind::ObjCId | TypeKind::ObjCSel => { trace!(" simple type that do not have float"); ConstrainResult::Same } TypeKind::Float(..) | TypeKind::Complex(..) => { trace!(" float type has float"); self.insert(id) } TypeKind::Array(t, _) => { if self.has_float.contains(&t.into()) { trace!( " Array with type T that has float also has float" ); return self.insert(id); } trace!(" Array with type T that do not have float also do not have float"); ConstrainResult::Same } TypeKind::Vector(t, _) => { if self.has_float.contains(&t.into()) { trace!( " Vector with type T that has float also has float" ); return self.insert(id); } trace!(" Vector with type T that do not have float also do not have float"); ConstrainResult::Same } TypeKind::ResolvedTypeRef(t) | TypeKind::TemplateAlias(t, _) | TypeKind::Alias(t) | TypeKind::BlockPointer(t) => { if self.has_float.contains(&t.into()) { trace!( " aliases and type refs to T which have float \ also have float" ); self.insert(id) } else { trace!(" aliases and type refs to T which do not have float \ also do not have floaarrayt"); ConstrainResult::Same } } TypeKind::Comp(ref info) => { let bases_have = info .base_members() .iter() .any(|base| self.has_float.contains(&base.ty.into())); if bases_have { trace!(" bases have float, so we also have"); return self.insert(id); } let fields_have = info.fields().iter().any(|f| match *f { Field::DataMember(ref data) => { self.has_float.contains(&data.ty().into()) } Field::Bitfields(ref bfu) => bfu .bitfields() .iter() .any(|b| self.has_float.contains(&b.ty().into())), }); if fields_have { trace!(" fields have float, so we also have"); return self.insert(id); } trace!(" comp doesn't have float"); ConstrainResult::Same } TypeKind::TemplateInstantiation(ref template) => { let args_have = template .template_arguments() .iter() .any(|arg| self.has_float.contains(&arg.into())); if args_have { trace!( " template args have float, so \ insantiation also has float" ); return self.insert(id); } let def_has = self .has_float .contains(&template.template_definition().into()); if def_has { trace!( " template definition has float, so \ insantiation also has" ); return self.insert(id); } trace!(" template instantiation do not have float"); ConstrainResult::Same } } } fn each_depending_on(&self, id: ItemId, mut f: F) where F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&id) { for item in edges { trace!("enqueue {:?} into worklist", item); f(*item); } } } } impl<'ctx> From> for HashSet { fn from(analysis: HasFloat<'ctx>) -> Self { analysis.has_float } } bindgen-0.59.1/src/ir/analysis/has_type_param_in_array.rs000064400000000000000000000214350000000000000215620ustar 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 paramter in array. /// * If T is an instantiation of an abstract template definition, T has /// type parameter in array if any of the template arguments or template definition /// has. #[derive(Debug, Clone)] pub struct HasTypeParameterInArray<'ctx> { ctx: &'ctx BindgenContext, // The incremental result of this analysis's computation. Everything in this // set has array. has_type_parameter_in_array: HashSet, // 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<'ctx> HasTypeParameterInArray<'ctx> { fn consider_edge(kind: EdgeKind) -> bool { match kind { // These are the only edges that can affect whether a type has type parameter // in array or not. EdgeKind::BaseMember | EdgeKind::Field | EdgeKind::TypeReference | EdgeKind::VarType | EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration | EdgeKind::TemplateParameterDefinition => true, EdgeKind::Constructor | EdgeKind::Destructor | EdgeKind::FunctionReturn | EdgeKind::FunctionParameter | EdgeKind::InnerType | EdgeKind::InnerVar | EdgeKind::Method => false, EdgeKind::Generic => false, } } fn insert>(&mut self, id: Id) -> ConstrainResult { let id = id.into(); trace!( "inserting {:?} into the has_type_parameter_in_array set", id ); let was_not_already_in_set = self.has_type_parameter_in_array.insert(id); assert!( was_not_already_in_set, "We shouldn't try and insert {:?} twice because if it was \ already in the set, `constrain` should have exited early.", id ); ConstrainResult::Changed } } impl<'ctx> MonotoneFramework for HasTypeParameterInArray<'ctx> { type Node = ItemId; type Extra = &'ctx BindgenContext; type Output = HashSet; 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().cloned().collect() } fn constrain(&mut self, id: ItemId) -> ConstrainResult { trace!("constrain: {:?}", id); if self.has_type_parameter_in_array.contains(&id) { trace!(" already know it do not have array"); return ConstrainResult::Same; } let item = self.ctx.resolve_item(id); let ty = match item.as_type() { Some(ty) => ty, None => { trace!(" not a type; ignoring"); return ConstrainResult::Same; } }; match *ty.kind() { // Handle the simple cases. These cannot have array in type parameter // without further information. TypeKind::Void | TypeKind::NullPtr | TypeKind::Int(..) | TypeKind::Float(..) | TypeKind::Vector(..) | TypeKind::Complex(..) | TypeKind::Function(..) | TypeKind::Enum(..) | TypeKind::Reference(..) | TypeKind::TypeParam | TypeKind::Opaque | TypeKind::Pointer(..) | TypeKind::UnresolvedTypeRef(..) | TypeKind::ObjCInterface(..) | TypeKind::ObjCId | TypeKind::ObjCSel => { trace!(" simple type that do not have array"); ConstrainResult::Same } TypeKind::Array(t, _) => { let inner_ty = self.ctx.resolve_type(t).canonical_type(self.ctx); match *inner_ty.kind() { TypeKind::TypeParam => { trace!(" Array with Named type has type parameter"); self.insert(id) } _ => { trace!( " Array without Named type does have type parameter" ); ConstrainResult::Same } } } TypeKind::ResolvedTypeRef(t) | TypeKind::TemplateAlias(t, _) | TypeKind::Alias(t) | TypeKind::BlockPointer(t) => { if self.has_type_parameter_in_array.contains(&t.into()) { trace!( " aliases and type refs to T which have array \ also have array" ); self.insert(id) } else { trace!( " aliases and type refs to T which do not have array \ also do not have array" ); ConstrainResult::Same } } TypeKind::Comp(ref info) => { let bases_have = info.base_members().iter().any(|base| { self.has_type_parameter_in_array.contains(&base.ty.into()) }); if bases_have { trace!(" bases have array, so we also have"); return self.insert(id); } let fields_have = info.fields().iter().any(|f| match *f { Field::DataMember(ref data) => self .has_type_parameter_in_array .contains(&data.ty().into()), Field::Bitfields(..) => false, }); if fields_have { trace!(" fields have array, so we also have"); return self.insert(id); } trace!(" comp doesn't have array"); ConstrainResult::Same } TypeKind::TemplateInstantiation(ref template) => { let args_have = template.template_arguments().iter().any(|arg| { self.has_type_parameter_in_array.contains(&arg.into()) }); if args_have { trace!( " template args have array, so \ insantiation also has array" ); return self.insert(id); } let def_has = self .has_type_parameter_in_array .contains(&template.template_definition().into()); if def_has { trace!( " template definition has array, so \ insantiation also has" ); return self.insert(id); } trace!(" template instantiation do not have array"); ConstrainResult::Same } } } fn each_depending_on(&self, id: ItemId, mut f: F) where F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&id) { for item in edges { trace!("enqueue {:?} into worklist", item); f(*item); } } } } impl<'ctx> From> for HashSet { fn from(analysis: HasTypeParameterInArray<'ctx>) -> Self { analysis.has_type_parameter_in_array } } bindgen-0.59.1/src/ir/analysis/has_vtable.rs000064400000000000000000000166000000000000000170100ustar 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)] pub enum HasVtableResult { /// The item does not have a vtable pointer. No, /// The item has a vtable and the actual vtable pointer is within this item. SelfHasVtable, /// The item has a vtable, but the actual vtable pointer is in a base /// member. BaseHasVtable, } impl Default for HasVtableResult { fn default() -> Self { HasVtableResult::No } } impl HasVtableResult { /// Take the least upper bound of `self` and `rhs`. pub fn join(self, rhs: Self) -> Self { cmp::max(self, rhs) } } impl ops::BitOr for HasVtableResult { type Output = Self; fn bitor(self, rhs: HasVtableResult) -> Self::Output { self.join(rhs) } } impl ops::BitOrAssign for HasVtableResult { fn bitor_assign(&mut self, rhs: HasVtableResult) { *self = self.join(rhs) } } /// An analysis that finds for each IR item whether it has vtable or not /// /// We use the monotone function `has vtable`, defined as follows: /// /// * If T is a type alias, a templated alias, an indirection to another type, /// or a reference of a type, T has vtable if the type T refers to has vtable. /// * If T is a compound type, T has vtable if we saw a virtual function when /// parsing it or any of its base member has vtable. /// * If T is an instantiation of an abstract template definition, T has /// vtable if template definition has vtable #[derive(Debug, Clone)] pub struct HasVtableAnalysis<'ctx> { ctx: &'ctx BindgenContext, // The incremental result of this analysis's computation. Everything in this // set definitely has a vtable. have_vtable: HashMap, // 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<'ctx> HasVtableAnalysis<'ctx> { fn consider_edge(kind: EdgeKind) -> bool { match kind { // These are the only edges that can affect whether a type has a // vtable or not. EdgeKind::TypeReference | EdgeKind::BaseMember | EdgeKind::TemplateDeclaration => true, _ => false, } } 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).cloned() { None => ConstrainResult::Same, Some(r) => self.insert(to, r), } } } impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> { type Node = ItemId; type Extra = &'ctx BindgenContext; type Output = HashMap; 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().cloned().collect() } fn constrain(&mut self, id: ItemId) -> ConstrainResult { trace!("constrain {:?}", id); let item = self.ctx.resolve_item(id); let ty = match item.as_type() { None => return ConstrainResult::Same, Some(ty) => ty, }; // TODO #851: figure out a way to handle deriving from template type parameters. match *ty.kind() { TypeKind::TemplateAlias(t, _) | TypeKind::Alias(t) | TypeKind::ResolvedTypeRef(t) | TypeKind::Reference(t) => { trace!( " aliases and references forward to their inner type" ); self.forward(t, id) } TypeKind::Comp(ref info) => { trace!(" comp considers its own methods and bases"); let mut result = HasVtableResult::No; if info.has_own_virtual_method() { trace!(" comp has its own virtual method"); result |= HasVtableResult::SelfHasVtable; } let bases_has_vtable = info.base_members().iter().any(|base| { trace!(" comp has a base with a vtable: {:?}", base); self.have_vtable.contains_key(&base.ty.into()) }); if bases_has_vtable { result |= HasVtableResult::BaseHasVtable; } self.insert(id, result) } TypeKind::TemplateInstantiation(ref inst) => { self.forward(inst.template_definition(), id) } _ => ConstrainResult::Same, } } fn each_depending_on(&self, id: ItemId, mut f: F) where F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&id) { for item in edges { trace!("enqueue {:?} into worklist", item); f(*item); } } } } impl<'ctx> From> 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 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.59.1/src/ir/analysis/mod.rs000064400000000000000000000330530000000000000154600ustar 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 use self::template_params::UsedTemplateParameters; mod derive; pub use self::derive::{as_cannot_derive_set, CannotDerive, DeriveTrait}; mod has_vtable; pub use self::has_vtable::{HasVtable, HasVtableAnalysis, HasVtableResult}; mod has_destructor; pub use self::has_destructor::HasDestructorAnalysis; mod has_type_param_in_array; pub use self::has_type_param_in_array::HasTypeParameterInArray; mod has_float; pub use self::has_float::HasFloat; mod sizedness; pub use self::sizedness::{Sizedness, SizednessAnalysis, SizednessResult}; use crate::ir::context::{BindgenContext, ItemId}; use crate::ir::traversal::{EdgeKind, Trace}; use crate::HashMap; use std::fmt; use std::ops; /// An analysis in the monotone framework. /// /// Implementors of this trait must maintain the following two invariants: /// /// 1. The concrete data must be a member of a finite-height lattice. /// 2. The concrete `constrain` method must be monotone: that is, /// if `x <= y`, then `constrain(x) <= constrain(y)`. /// /// If these invariants do not hold, iteration to a fix-point might never /// complete. /// /// For a simple example analysis, see the `ReachableFrom` type in the `tests` /// module below. pub trait MonotoneFramework: Sized + fmt::Debug { /// The type of node in our dependency graph. /// /// This is just generic (and not `ItemId`) so that we can easily unit test /// without constructing real `Item`s and their `ItemId`s. type Node: Copy; /// Any extra data that is needed during computation. /// /// Again, this is just generic (and not `&BindgenContext`) so that we can /// easily unit test without constructing real `BindgenContext`s full of /// real `Item`s and real `ItemId`s. type Extra: Sized; /// The final output of this analysis. Once we have reached a fix-point, we /// convert `self` into this type, and return it as the final result of the /// analysis. type Output: From + 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)] pub enum ConstrainResult { /// The incremental results were updated, and the fix-point computation /// should continue. Changed, /// The incremental results were not updated. Same, } impl Default for ConstrainResult { fn default() -> Self { ConstrainResult::Same } } impl ops::BitOr for ConstrainResult { type Output = Self; fn bitor(self, rhs: ConstrainResult) -> Self::Output { if self == ConstrainResult::Changed || rhs == ConstrainResult::Changed { ConstrainResult::Changed } else { ConstrainResult::Same } } } impl ops::BitOrAssign for ConstrainResult { fn bitor_assign(&mut self, rhs: ConstrainResult) { *self = *self | rhs; } } /// Run an analysis in the monotone framework. pub fn analyze(extra: Analysis::Extra) -> Analysis::Output where Analysis: MonotoneFramework, { let mut analysis = Analysis::new(extra); let mut worklist = analysis.initial_worklist(); while let Some(node) = worklist.pop() { if let ConstrainResult::Changed = analysis.constrain(node) { analysis.each_depending_on(node, |needs_work| { worklist.push(needs_work); }); } } analysis.into() } /// Generate the dependency map for analysis pub fn generate_dependencies( 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(vec![]); { // 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(vec![]) .push(item); } }, &(), ); } } dependencies } #[cfg(test)] mod tests { use super::*; use crate::{HashMap, HashSet}; // Here we find the set of nodes that are reachable from any given // node. This is a lattice mapping nodes to subsets of all nodes. Our join // function is set union. // // This is our test graph: // // +---+ +---+ // | | | | // | 1 | .----| 2 | // | | | | | // +---+ | +---+ // | | ^ // | | | // | +---+ '------' // '----->| | // | 3 | // .------| |------. // | +---+ | // | ^ | // v | v // +---+ | +---+ +---+ // | | | | | | | // | 4 | | | 5 |--->| 6 | // | | | | | | | // +---+ | +---+ +---+ // | | | | // | | | v // | +---+ | +---+ // | | | | | | // '----->| 7 |<-----' | 8 | // | | | | // +---+ +---+ // // And here is the mapping from a node to the set of nodes that are // reachable from it within the test graph: // // 1: {3,4,5,6,7,8} // 2: {2} // 3: {3,4,5,6,7,8} // 4: {3,4,5,6,7,8} // 5: {3,4,5,6,7,8} // 6: {8} // 7: {3,4,5,6,7,8} // 8: {} #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] struct Node(usize); #[derive(Clone, Debug, Default, PartialEq, Eq)] struct Graph(HashMap>); impl Graph { fn make_test_graph() -> Graph { let mut g = Graph::default(); g.0.insert(Node(1), vec![Node(3)]); g.0.insert(Node(2), vec![Node(2)]); g.0.insert(Node(3), vec![Node(4), Node(5)]); g.0.insert(Node(4), vec![Node(7)]); g.0.insert(Node(5), vec![Node(6), Node(7)]); g.0.insert(Node(6), vec![Node(8)]); g.0.insert(Node(7), vec![Node(3)]); g.0.insert(Node(8), vec![]); g } fn reverse(&self) -> Graph { let mut reversed = Graph::default(); for (node, edges) in self.0.iter() { reversed.0.entry(*node).or_insert(vec![]); for referent in edges.iter() { reversed.0.entry(*referent).or_insert(vec![]).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) -> ReachableFrom { let reversed = graph.reverse(); ReachableFrom { reachable: Default::default(), graph: graph, reversed: reversed, } } fn initial_worklist(&self) -> Vec { self.graph.0.keys().cloned().collect() } fn constrain(&mut self, node: Node) -> ConstrainResult { // The set of nodes reachable from a node `x` is // // reachable(x) = s_0 U s_1 U ... U reachable(s_0) U reachable(s_1) U ... // // where there exist edges from `x` to each of `s_0, s_1, ...`. // // Yes, what follows is a **terribly** inefficient set union // implementation. Don't copy this code outside of this test! let original_size = self .reachable .entry(node) .or_insert(HashSet::default()) .len(); for sub_node in self.graph.0[&node].iter() { self.reachable.get_mut(&node).unwrap().insert(*sub_node); let sub_reachable = self .reachable .entry(*sub_node) .or_insert(HashSet::default()) .clone(); for transitive in sub_reachable { self.reachable.get_mut(&node).unwrap().insert(transitive); } } let new_size = self.reachable[&node].len(); if original_size != new_size { ConstrainResult::Changed } else { ConstrainResult::Same } } fn each_depending_on(&self, node: Node, mut f: F) where F: FnMut(Node), { for dep in self.reversed.0[&node].iter() { 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().cloned().map(Node).collect() } let mut expected = HashMap::default(); expected.insert(Node(1), nodes([3, 4, 5, 6, 7, 8])); expected.insert(Node(2), nodes([2])); expected.insert(Node(3), nodes([3, 4, 5, 6, 7, 8])); expected.insert(Node(4), nodes([3, 4, 5, 6, 7, 8])); expected.insert(Node(5), nodes([3, 4, 5, 6, 7, 8])); expected.insert(Node(6), nodes([8])); expected.insert(Node(7), nodes([3, 4, 5, 6, 7, 8])); expected.insert(Node(8), nodes([])); println!("expected = {:#?}", expected); assert_eq!(reachable, expected); } } bindgen-0.59.1/src/ir/analysis/sizedness.rs000064400000000000000000000266150000000000000167160ustar 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)] pub enum SizednessResult { /// The type is zero-sized. /// /// This means that if it is a C++ type, and is not being used as a base /// member, then we must add an `_address` byte to enforce the /// unique-address-per-distinct-object-instance rule. ZeroSized, /// Whether this type is zero-sized or not depends on whether a type /// parameter is zero-sized or not. /// /// For example, given these definitions: /// /// ```c++ /// template /// class 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: /// https://github.com/rust-lang/rust-bindgen/issues/586 DependsOnTypeParam, /// Has some size that is known to be greater than zero. That doesn't mean /// it has a static size, but it is not zero sized for sure. In other words, /// it might contain an incomplete array or some other dynamically sized /// type. NonZeroSized, } impl Default for SizednessResult { fn default() -> Self { SizednessResult::ZeroSized } } impl SizednessResult { /// Take the least upper bound of `self` and `rhs`. pub fn join(self, rhs: Self) -> Self { cmp::max(self, rhs) } } impl ops::BitOr for SizednessResult { type Output = Self; fn bitor(self, rhs: SizednessResult) -> Self::Output { self.join(rhs) } } impl ops::BitOrAssign for SizednessResult { fn bitor_assign(&mut self, rhs: SizednessResult) { *self = self.join(rhs) } } /// An analysis that computes the sizedness of all types. /// /// * For types with known sizes -- for example pointers, scalars, etc... -- /// they are assigned `NonZeroSized`. /// /// * For compound structure types with one or more fields, they are assigned /// `NonZeroSized`. /// /// * For compound structure types without any fields, the results of the bases /// are `join`ed. /// /// * For type parameters, `DependsOnTypeParam` is assigned. #[derive(Debug)] pub struct SizednessAnalysis<'ctx> { ctx: &'ctx BindgenContext, dependencies: HashMap>, // Incremental results of the analysis. Missing entries are implicitly // considered `ZeroSized`. sized: HashMap, } impl<'ctx> SizednessAnalysis<'ctx> { fn consider_edge(kind: EdgeKind) -> bool { match kind { // These are the only edges that can affect whether a type is // zero-sized or not. EdgeKind::TemplateArgument | EdgeKind::TemplateParameterDefinition | EdgeKind::TemplateDeclaration | EdgeKind::TypeReference | EdgeKind::BaseMember | EdgeKind::Field => true, _ => false, } } /// Insert an incremental result, and return whether this updated our /// knowledge of types and we should continue the analysis. fn insert( &mut self, id: TypeId, result: SizednessResult, ) -> ConstrainResult { trace!("inserting {:?} for {:?}", result, id); if let SizednessResult::ZeroSized = result { return ConstrainResult::Same; } match self.sized.entry(id) { Entry::Occupied(mut entry) => { if *entry.get() < result { entry.insert(result); ConstrainResult::Changed } else { ConstrainResult::Same } } Entry::Vacant(entry) => { entry.insert(result); ConstrainResult::Changed } } } fn forward(&mut self, from: TypeId, to: TypeId) -> ConstrainResult { match self.sized.get(&from).cloned() { None => ConstrainResult::Same, Some(r) => self.insert(to, r), } } } impl<'ctx> MonotoneFramework for SizednessAnalysis<'ctx> { type Node = TypeId; type Extra = &'ctx BindgenContext; type Output = HashMap; 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() .cloned() .filter_map(|id| id.as_type_id(self.ctx)) .collect() } fn constrain(&mut self, id: TypeId) -> ConstrainResult { trace!("constrain {:?}", id); if let Some(SizednessResult::NonZeroSized) = self.sized.get(&id).cloned() { trace!(" already know it is not zero-sized"); return ConstrainResult::Same; } if id.has_vtable_ptr(self.ctx) { trace!(" has an explicit vtable pointer, therefore is not zero-sized"); return self.insert(id, SizednessResult::NonZeroSized); } let ty = self.ctx.resolve_type(id); if id.is_opaque(self.ctx, &()) { trace!(" type is opaque; checking layout..."); let result = ty.layout(self.ctx).map_or(SizednessResult::ZeroSized, |l| { if l.size == 0 { trace!(" ...layout has size == 0"); SizednessResult::ZeroSized } else { trace!(" ...layout has size > 0"); SizednessResult::NonZeroSized } }); return self.insert(id, result); } match *ty.kind() { TypeKind::Void => { trace!(" void is zero-sized"); self.insert(id, SizednessResult::ZeroSized) } TypeKind::TypeParam => { trace!( " type params sizedness depends on what they're \ instantiated as" ); self.insert(id, SizednessResult::DependsOnTypeParam) } TypeKind::Int(..) | TypeKind::Float(..) | TypeKind::Complex(..) | TypeKind::Function(..) | TypeKind::Enum(..) | TypeKind::Reference(..) | TypeKind::NullPtr | TypeKind::ObjCId | TypeKind::ObjCSel | TypeKind::Pointer(..) => { trace!(" {:?} is known not to be zero-sized", ty.kind()); self.insert(id, SizednessResult::NonZeroSized) } TypeKind::ObjCInterface(..) => { trace!(" obj-c interfaces always have at least the `isa` pointer"); self.insert(id, SizednessResult::NonZeroSized) } TypeKind::TemplateAlias(t, _) | TypeKind::Alias(t) | TypeKind::BlockPointer(t) | TypeKind::ResolvedTypeRef(t) => { trace!(" aliases and type refs forward to their inner type"); self.forward(t, id) } TypeKind::TemplateInstantiation(ref inst) => { trace!( " template instantiations are zero-sized if their \ definition is zero-sized" ); self.forward(inst.template_definition(), id) } TypeKind::Array(_, 0) => { trace!(" arrays of zero elements are zero-sized"); self.insert(id, SizednessResult::ZeroSized) } TypeKind::Array(..) => { trace!(" arrays of > 0 elements are not zero-sized"); self.insert(id, SizednessResult::NonZeroSized) } TypeKind::Vector(..) => { trace!(" vectors are not zero-sized"); self.insert(id, SizednessResult::NonZeroSized) } TypeKind::Comp(ref info) => { trace!(" comp considers its own fields and bases"); if !info.fields().is_empty() { return self.insert(id, SizednessResult::NonZeroSized); } let result = info .base_members() .iter() .filter_map(|base| self.sized.get(&base.ty)) .fold(SizednessResult::ZeroSized, |a, b| a.join(*b)); self.insert(id, result) } TypeKind::Opaque => { unreachable!("covered by the .is_opaque() check above") } TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing!"); } } } fn each_depending_on(&self, id: TypeId, mut f: F) where F: FnMut(TypeId), { if let Some(edges) = self.dependencies.get(&id) { for ty in edges { trace!("enqueue {:?} into worklist", ty); f(*ty); } } } } impl<'ctx> From> 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 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.59.1/src/ir/analysis/template_params.rs000064400000000000000000000551750000000000000200700ustar 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 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 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<'ctx> UsedTemplateParameters<'ctx> { fn consider_edge(kind: EdgeKind) -> bool { match kind { // For each of these kinds of edges, if the referent uses a template // parameter, then it should be considered that the origin of the // edge also uses the template parameter. EdgeKind::TemplateArgument | EdgeKind::BaseMember | EdgeKind::Field | EdgeKind::Constructor | EdgeKind::Destructor | EdgeKind::VarType | EdgeKind::FunctionReturn | EdgeKind::FunctionParameter | EdgeKind::TypeReference => true, // An inner var or type using a template parameter is orthogonal // from whether we use it. See template-param-usage-{6,11}.hpp. EdgeKind::InnerVar | EdgeKind::InnerType => false, // We can't emit machine code for new monomorphizations of class // templates' methods (and don't detect explicit instantiations) so // we must ignore template parameters that are only used by // methods. This doesn't apply to a function type's return or // parameter types, however, because of type aliases of function // pointers that use template parameters, eg // tests/headers/struct_with_typedef_template_arg.hpp EdgeKind::Method => false, // If we considered these edges, we would end up mistakenly claiming // that every template parameter always used. EdgeKind::TemplateDeclaration | EdgeKind::TemplateParameterDefinition => false, // Since we have to be careful about which edges we consider for // this analysis to be correct, we ignore generic edges. We also // avoid a `_` wild card to force authors of new edge kinds to // determine whether they need to be considered by this analysis. EdgeKind::Generic => false, } } fn take_this_id_usage_set>( &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() .into_iter() .map(|a| { a.into_resolver() .through_type_refs() .through_type_aliases() .resolve(self.ctx) .id() }) .filter(|a| *a != this_id) .flat_map(|a| { self.used .get(&a) .expect("Should have a used entry for the template arg") .as_ref() .expect( "Because a != this_id, and all used template \ param sets other than this_id's are `Some`, \ a's used template param set should be `Some`", ) .iter() .cloned() }); used_by_this_id.extend(args); } /// A template instantiation's concrete template argument is only used if /// the template definition uses the corresponding template parameter. fn constrain_instantiation( &self, this_id: ItemId, used_by_this_id: &mut ItemSet, instantiation: &TemplateInstantiation, ) { trace!(" template instantiation"); let decl = self.ctx.resolve_type(instantiation.template_definition()); let args = instantiation.template_arguments(); let params = decl.self_template_params(self.ctx); debug_assert!(this_id != instantiation.template_definition()); let used_by_def = self.used .get(&instantiation.template_definition().into()) .expect("Should have a used entry for instantiation's template definition") .as_ref() .expect("And it should be Some because only this_id's set is None, and an \ instantiation's template definition should never be the \ instantiation itself"); for (arg, param) in args.iter().zip(params.iter()) { trace!( " instantiation's argument {:?} is used if definition's \ parameter {:?} is used", arg, param ); if used_by_def.contains(¶m.into()) { trace!(" param is used by template definition"); let arg = arg .into_resolver() .through_type_refs() .through_type_aliases() .resolve(self.ctx) .id(); if arg == this_id { continue; } let used_by_arg = self .used .get(&arg) .expect("Should have a used entry for the template arg") .as_ref() .expect( "Because arg != this_id, and all used template \ param sets other than this_id's are `Some`, \ arg's used template param set should be \ `Some`", ) .iter() .cloned(); used_by_this_id.extend(used_by_arg); } } } /// The join operation on our lattice: the set union of all of this id's /// successors. fn constrain_join(&self, used_by_this_id: &mut ItemSet, item: &Item) { trace!(" other item: join with successors' usage"); item.trace( self.ctx, &mut |sub_id, edge_kind| { // Ignore ourselves, since union with ourself is a // no-op. Ignore edges that aren't relevant to the // analysis. if sub_id == item.id() || !Self::consider_edge(edge_kind) { return; } let used_by_sub_id = self .used .get(&sub_id) .expect("Should have a used set for the sub_id successor") .as_ref() .expect( "Because sub_id != id, and all used template \ param sets other than id's are `Some`, \ sub_id's used template param set should be \ `Some`", ) .iter() .cloned(); trace!( " union with {:?}'s usage: {:?}", sub_id, used_by_sub_id.clone().collect::>() ); 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().cloned().collect(); let allowlisted_and_blocklisted_items: ItemSet = allowlisted_items .iter() .cloned() .flat_map(|i| { let mut reachable = vec![i]; i.trace( ctx, &mut |s, _| { reachable.push(s); }, &(), ); reachable }) .collect(); for item in allowlisted_and_blocklisted_items { dependencies.entry(item).or_insert(vec![]); used.entry(item).or_insert(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(Some(ItemSet::new())); dependencies .entry(sub_item) .or_insert(vec![]) .push(item); }, &(), ); } // Additionally, whether a template instantiation's template // arguments are used depends on whether the template declaration's // generic template parameters are used. ctx.resolve_item(item).as_type().map(|ty| match ty.kind() { &TypeKind::TemplateInstantiation(ref inst) => { 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(Some(ItemSet::new())); used.entry(param).or_insert(Some(ItemSet::new())); dependencies.entry(arg).or_insert(vec![]).push(param); } } _ => {} }); } if cfg!(feature = "testing_only_extra_assertions") { // Invariant: The `used` map has an entry for every allowlisted // item, as well as all explicitly blocklisted items that are // reachable from allowlisted items. // // Invariant: the `dependencies` map has an entry for every // allowlisted item. // // (This is so that every item we call `constrain` on is guaranteed // to have a set of template parameters, and we can allow // blocklisted templates to use all of their parameters). for item in allowlisted_items.iter() { extra_assert!(used.contains_key(item)); extra_assert!(dependencies.contains_key(item)); item.trace( ctx, &mut |sub_item, _| { extra_assert!(used.contains_key(&sub_item)); extra_assert!(dependencies.contains_key(&sub_item)); }, &(), ) } } UsedTemplateParameters { ctx: ctx, used: used, dependencies: dependencies, allowlisted_items: allowlisted_items, } } fn initial_worklist(&self) -> Vec { // The transitive closure of all allowlisted items, including explicitly // blocklisted items. self.ctx .allowlisted_items() .iter() .cloned() .flat_map(|i| { let mut reachable = vec![i]; i.trace( self.ctx, &mut |s, _| { reachable.push(s); }, &(), ); reachable }) .collect() } fn constrain(&mut self, id: ItemId) -> ConstrainResult { // Invariant: all hash map entries' values are `Some` upon entering and // exiting this method. extra_assert!(self.used.values().all(|v| v.is_some())); // Take the set for this id out of the hash map while we mutate it based // on other hash map entries. We *must* put it back into the hash map at // the end of this method. This allows us to side-step HashMap's lack of // an analog to slice::split_at_mut. let mut used_by_this_id = self.take_this_id_usage_set(id); trace!("constrain {:?}", id); trace!(" initially, used set is {:?}", used_by_this_id); let original_len = used_by_this_id.len(); let item = self.ctx.resolve_item(id); let ty_kind = item.as_type().map(|ty| ty.kind()); match ty_kind { // Named template type parameters trivially use themselves. Some(&TypeKind::TypeParam) => { trace!(" named type, trivially uses itself"); used_by_this_id.insert(id); } // Template instantiations only use their template arguments if the // template definition uses the corresponding template parameter. Some(&TypeKind::TemplateInstantiation(ref inst)) => { if self .allowlisted_items .contains(&inst.template_definition().into()) { self.constrain_instantiation( id, &mut used_by_this_id, inst, ); } else { self.constrain_instantiation_of_blocklisted_template( id, &mut used_by_this_id, inst, ); } } // Otherwise, add the union of each of its referent item's template // parameter usage. _ => self.constrain_join(&mut used_by_this_id, item), } trace!(" finally, used set is {:?}", used_by_this_id); let new_len = used_by_this_id.len(); assert!( new_len >= original_len, "This is the property that ensures this function is monotone -- \ if it doesn't hold, the analysis might never terminate!" ); // Put the set back in the hash map and restore our invariant. debug_assert!(self.used[&id].is_none()); self.used.insert(id, Some(used_by_this_id)); extra_assert!(self.used.values().all(|v| v.is_some())); if new_len != original_len { ConstrainResult::Changed } else { ConstrainResult::Same } } fn each_depending_on(&self, item: ItemId, mut f: F) where F: FnMut(ItemId), { if let Some(edges) = self.dependencies.get(&item) { for item in edges { trace!("enqueue {:?} into worklist", item); f(*item); } } } } impl<'ctx> From> 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.59.1/src/ir/annotations.rs000064400000000000000000000153330000000000000154140ustar 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 crate::clang; /// What kind of accessor should we provide for a field? #[derive(Copy, PartialEq, Clone, Debug)] pub enum FieldAccessorKind { /// No accessor. None, /// Plain accessor. Regular, /// Unsafe accessor. Unsafe, /// Immutable accessor. Immutable, } /// Annotations for a given item, or a field. /// /// You can see the kind of comments that are accepted in the Doxygen /// documentation: /// /// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html #[derive(Clone, PartialEq, Debug)] pub struct Annotations { /// Whether this item is marked as opaque. Only applies to types. opaque: bool, /// Whether this item should be hidden from the output. Only applies to /// types, or enum variants. hide: bool, /// Whether this type should be replaced by another. The name is a /// namespace-aware path. use_instead_of: Option>, /// 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 fields should be marked as private or not. You can set this on /// structs (it will apply to all the fields), or individual fields. private_fields: Option, /// 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, } fn parse_accessor(s: &str) -> FieldAccessorKind { match s { "false" => FieldAccessorKind::None, "unsafe" => FieldAccessorKind::Unsafe, "immutable" => FieldAccessorKind::Immutable, _ => FieldAccessorKind::Regular, } } impl Default for Annotations { fn default() -> Self { Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, disallow_debug: false, disallow_default: false, private_fields: None, accessor_kind: None, constify_enum_variant: false, derives: vec![], } } } impl Annotations { /// Construct new annotations for the given cursor and its bindgen comments /// (if any). pub 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 fn hide(&self) -> bool { self.hide } /// Should this type be opaque? pub fn opaque(&self) -> bool { self.opaque } /// For a given type, indicates the type it should replace. /// /// For example, in the following code: /// /// ```cpp /// /// /**
*/ /// 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 fn use_instead_of(&self) -> Option<&[String]> { self.use_instead_of.as_ref().map(|s| &**s) } /// The list of derives that have been specified in this annotation. pub fn derives(&self) -> &[String] { &self.derives } /// Should we avoid implementing the `Copy` trait? pub fn disallow_copy(&self) -> bool { self.disallow_copy } /// Should we avoid implementing the `Debug` trait? pub fn disallow_debug(&self) -> bool { self.disallow_debug } /// Should we avoid implementing the `Default` trait? pub fn disallow_default(&self) -> bool { self.disallow_default } /// Should the fields be private? pub fn private_fields(&self) -> Option { self.private_fields } /// What kind of accessors should we provide for this type's fields? pub 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() .map_or(false, |attr| attr.name == "rustbindgen") { *matched = true; for attr in comment.get_tag_attrs() { match attr.name.as_str() { "opaque" => self.opaque = true, "hide" => self.hide = true, "nocopy" => self.disallow_copy = true, "nodebug" => self.disallow_debug = true, "nodefault" => self.disallow_default = true, "replaces" => { self.use_instead_of = Some( attr.value.split("::").map(Into::into).collect(), ) } "derive" => self.derives.push(attr.value), "private" => { self.private_fields = Some(attr.value != "false") } "accessor" => { self.accessor_kind = Some(parse_accessor(&attr.value)) } "constant" => self.constify_enum_variant = true, _ => {} } } } for child in comment.get_children() { self.parse(&child, matched); } } /// Returns whether we've parsed a "constant" attribute. pub fn constify_enum_variant(&self) -> bool { self.constify_enum_variant } } bindgen-0.59.1/src/ir/comment.rs000064400000000000000000000067640000000000000145310ustar 00000000000000//! Utilities for manipulating C/C++ comments. use std::iter; /// The type of a comment. #[derive(Debug, PartialEq, Eq)] enum Kind { /// A `///` comment, or something of the like. /// All lines in a comment should start with the same symbol. SingleLines, /// A `/**` comment, where each other line can start with `*` and the /// entire block ends with `*/`. MultiLine, } /// Preprocesses a C/C++ comment so that it is a valid Rust comment. pub fn preprocess(comment: &str, indent: usize) -> String { match self::kind(&comment) { Some(Kind::SingleLines) => preprocess_single_lines(comment, indent), Some(Kind::MultiLine) => preprocess_multi_line(comment, indent), None => comment.to_owned(), } } /// Gets the kind of the doc comment, if it is one. fn kind(comment: &str) -> Option { if comment.starts_with("/*") { Some(Kind::MultiLine) } else if comment.starts_with("//") { Some(Kind::SingleLines) } else { None } } fn make_indent(indent: usize) -> String { const RUST_INDENTATION: usize = 4; iter::repeat(' ').take(indent * RUST_INDENTATION).collect() } /// Preprocesses multiple single line comments. /// /// Handles lines starting with both `//` and `///`. fn preprocess_single_lines(comment: &str, indent: usize) -> String { debug_assert!(comment.starts_with("//"), "comment is not single line"); let indent = make_indent(indent); let mut is_first = true; let lines: Vec<_> = comment .lines() .map(|l| l.trim().trim_start_matches('/')) .map(|l| { let indent = if is_first { "" } else { &*indent }; is_first = false; format!("{}///{}", indent, l) }) .collect(); lines.join("\n") } fn preprocess_multi_line(comment: &str, indent: usize) -> String { let comment = comment .trim_start_matches('/') .trim_end_matches('/') .trim_end_matches('*'); let indent = make_indent(indent); // Strip any potential `*` characters preceding each line. let mut is_first = true; let mut lines: Vec<_> = comment .lines() .map(|line| line.trim().trim_start_matches('*').trim_start_matches('!')) .skip_while(|line| line.trim().is_empty()) // Skip the first empty lines. .map(|line| { let indent = if is_first { "" } else { &*indent }; is_first = false; format!("{}///{}", indent, line) }) .collect(); // Remove the trailing line corresponding to the `*/`. if lines .last() .map_or(false, |l| l.trim().is_empty() || l.trim() == "///") { lines.pop(); } lines.join("\n") } #[cfg(test)] mod test { use super::*; #[test] fn picks_up_single_and_multi_line_doc_comments() { assert_eq!(kind("/// hello"), Some(Kind::SingleLines)); assert_eq!(kind("/** world */"), Some(Kind::MultiLine)); } #[test] fn processes_single_lines_correctly() { assert_eq!(preprocess("/// hello", 0), "/// hello"); assert_eq!(preprocess("// hello", 0), "/// hello"); assert_eq!(preprocess("// hello", 0), "/// hello"); } #[test] fn processes_multi_lines_correctly() { assert_eq!( preprocess("/** hello \n * world \n * foo \n */", 0), "/// hello\n/// world\n/// foo" ); assert_eq!( preprocess("/**\nhello\n*world\n*foo\n*/", 0), "///hello\n///world\n///foo" ); } } bindgen-0.59.1/src/ir/comp.rs000064400000000000000000001646250000000000000140260ustar 00000000000000//! Compound types (unions and structs) in our intermediate representation. use super::analysis::Sizedness; use super::annotations::Annotations; use super::context::{BindgenContext, FunctionId, ItemId, TypeId, VarId}; use super::dot::DotAttributes; use super::item::{IsOpaque, Item}; use super::layout::Layout; use super::template::TemplateParameters; use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT; use crate::clang; use crate::codegen::struct_layout::{align_to, bytes_from_bits_pow2}; use crate::ir::derive::CanDeriveCopy; use crate::parse::{ClangItemParser, ParseError}; use crate::HashMap; use peeking_take_while::PeekableExt; use std::cmp; use std::io; use std::mem; /// The kind of compound type. #[derive(Debug, Copy, Clone, PartialEq)] pub enum CompKind { /// A struct. Struct, /// A union. Union, } /// The kind of C++ method. #[derive(Debug, Copy, Clone, PartialEq)] pub enum MethodKind { /// A constructor. We represent it as method for convenience, to avoid code /// duplication. Constructor, /// A destructor. Destructor, /// A virtual destructor. VirtualDestructor { /// Whether it's pure virtual. pure_virtual: bool, }, /// A static method. Static, /// A normal method. Normal, /// A virtual method. Virtual { /// Whether it's pure virtual. pure_virtual: bool, }, } impl MethodKind { /// Is this a destructor method? pub fn is_destructor(&self) -> bool { match *self { MethodKind::Destructor | MethodKind::VirtualDestructor { .. } => { true } _ => false, } } /// Is this a pure virtual method? pub fn is_pure_virtual(&self) -> bool { match *self { MethodKind::Virtual { pure_virtual } | MethodKind::VirtualDestructor { pure_virtual } => pure_virtual, _ => false, } } } /// A struct representing a C++ method, either static, normal, or virtual. #[derive(Debug)] pub struct Method { kind: MethodKind, /// The signature of the method. Take into account this is not a `Type` /// item, but a `Function` one. /// /// This is tricky and probably this field should be renamed. signature: FunctionId, is_const: bool, } impl Method { /// Construct a new `Method`. pub fn new( kind: MethodKind, signature: FunctionId, is_const: bool, ) -> Self { Method { kind, signature, is_const, } } /// What kind of method is this? pub fn kind(&self) -> MethodKind { self.kind } /// Is this a constructor? pub fn is_constructor(&self) -> bool { self.kind == MethodKind::Constructor } /// Is this a virtual method? pub fn is_virtual(&self) -> bool { match self.kind { MethodKind::Virtual { .. } | MethodKind::VirtualDestructor { .. } => true, _ => false, } } /// Is this a static method? pub fn is_static(&self) -> bool { self.kind == MethodKind::Static } /// Get the id for the `Function` signature for this method. pub fn signature(&self) -> FunctionId { self.signature } /// Is this a const qualified method? pub fn is_const(&self) -> bool { self.is_const } } /// Methods common to the various field types. pub trait FieldMethods { /// Get the name of this field. fn name(&self) -> Option<&str>; /// Get the type of this field. fn ty(&self) -> TypeId; /// Get the comment for this field. fn comment(&self) -> Option<&str>; /// If this is a bitfield, how many bits does it need? fn bitfield_width(&self) -> Option; /// Is this feild declared public? fn is_public(&self) -> bool; /// Get the annotations for this field. fn annotations(&self) -> &Annotations; /// The offset of the field (in bits) fn offset(&self) -> Option; } /// A contiguous set of logical bitfields that live within the same physical /// allocation unit. See 9.2.4 [class.bit] in the C++ standard and [section /// 2.4.II.1 in the Itanium C++ /// ABI](http://itanium-cxx-abi.github.io/cxx-abi/abi.html#class-types). #[derive(Debug)] pub struct BitfieldUnit { nth: usize, layout: Layout, bitfields: Vec, } impl BitfieldUnit { /// Get the 1-based index of this bitfield unit within its containing /// struct. Useful for generating a Rust struct's field name for this unit /// of bitfields. pub fn nth(&self) -> usize { self.nth } /// Get the layout within which these bitfields reside. pub fn layout(&self) -> Layout { self.layout } /// Get the bitfields within this unit. pub fn bitfields(&self) -> &[Bitfield] { &self.bitfields } } /// A struct representing a C++ field. #[derive(Debug)] pub enum Field { /// A normal data member. DataMember(FieldData), /// A physical allocation unit containing many logical bitfields. Bitfields(BitfieldUnit), } impl Field { /// Get this field's layout. pub fn layout(&self, ctx: &BindgenContext) -> Option { 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 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 fn offset_into_unit(&self) -> usize { self.offset_into_unit } /// Get the mask value that when &'ed with this bitfield's allocation unit /// produces this bitfield's value. pub fn mask(&self) -> u64 { use std::u64; let unoffseted_mask = if self.width() as u64 == mem::size_of::() as u64 * 8 { u64::MAX } else { (1u64 << self.width()) - 1u64 }; unoffseted_mask << self.offset_into_unit() } /// Get the bit width of this bitfield. pub fn width(&self) -> u32 { self.data.bitfield_width().unwrap() } /// Name of the generated Rust getter for this bitfield. /// /// Panics if called before assigning bitfield accessor names or if /// this bitfield have no name. pub fn getter_name(&self) -> &str { assert!( self.name().is_some(), "`Bitfield::getter_name` called on anonymous field" ); self.getter_name.as_ref().expect( "`Bitfield::getter_name` should only be called after\ assigning bitfield accessor names", ) } /// Name of the generated Rust setter for this bitfield. /// /// Panics if called before assigning bitfield accessor names or if /// this bitfield have no name. pub fn setter_name(&self) -> &str { assert!( self.name().is_some(), "`Bitfield::setter_name` called on anonymous field" ); self.setter_name.as_ref().expect( "`Bitfield::setter_name` should only be called\ after assigning bitfield accessor names", ) } } impl FieldMethods for Bitfield { fn name(&self) -> Option<&str> { self.data.name() } fn ty(&self) -> TypeId { self.data.ty() } fn comment(&self) -> Option<&str> { self.data.comment() } fn bitfield_width(&self) -> Option { 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::replace(&mut bitfields_in_unit, vec![]), 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 { BeforeComputingBitfieldUnits(Vec), AfterComputingBitfieldUnits { fields: Vec, has_bitfield_units: bool, }, ErrorComputingBitfieldUnits, } impl Default for CompFields { fn default() -> CompFields { CompFields::BeforeComputingBitfieldUnits(vec![]) } } impl CompFields { fn append_raw_field(&mut self, raw: RawField) { match *self { CompFields::BeforeComputingBitfieldUnits(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::BeforeComputingBitfieldUnits(ref mut raws) => { mem::replace(raws, vec![]) } _ => { 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::AfterComputingBitfieldUnits { fields, has_bitfield_units, }; } Err(()) => { *self = CompFields::ErrorComputingBitfieldUnits; } } } fn deanonymize_fields(&mut self, ctx: &BindgenContext, methods: &[Method]) { let fields = match *self { CompFields::AfterComputingBitfieldUnits { ref mut fields, .. } => fields, // Nothing to do here. CompFields::ErrorComputingBitfieldUnits => return, CompFields::BeforeComputingBitfieldUnits(_) => { 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 let Some(_) = *name { continue; } anon_field_counter += 1; *name = Some(format!( "{}{}", ctx.options().anon_fields_prefix, anon_field_counter )); } Field::Bitfields(ref mut bu) => { for bitfield in &mut bu.bitfields { if bitfield.name().is_none() { continue; } if let Some(AccessorNamesPair { getter, setter }) = accessor_names.remove(bitfield.name().unwrap()) { bitfield.getter_name = Some(getter); bitfield.setter_name = Some(setter); } } } } } } } impl Trace for CompFields { type Extra = (); fn trace(&self, context: &BindgenContext, tracer: &mut T, _: &()) where T: Tracer, { match *self { CompFields::ErrorComputingBitfieldUnits => {} CompFields::BeforeComputingBitfieldUnits(ref fields) => { for f in fields { tracer.visit_kind(f.ty().into(), EdgeKind::Field); } } CompFields::AfterComputingBitfieldUnits { ref fields, .. } => { for f in fields { f.trace(context, tracer, &()); } } } } } /// Common data shared across different field types. #[derive(Clone, Debug)] pub struct FieldData { /// The name of the field, empty if it's an unnamed bitfield width. name: Option, /// 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_ref().map(|n| &**n) } fn ty(&self) -> TypeId { self.ty } fn comment(&self) -> Option<&str> { self.comment.as_ref().map(|c| &**c) } 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 enum BaseKind { /// Normal inheritance, like: /// /// ```cpp /// class A : public B {}; /// ``` Normal, /// Virtual inheritance, like: /// /// ```cpp /// class A: public virtual B {}; /// ``` Virtual, } /// A base class. #[derive(Clone, Debug)] pub struct Base { /// The type of this base class. pub ty: TypeId, /// The kind of inheritance we're doing. pub kind: BaseKind, /// Name of the field in which this base should be stored. pub field_name: String, /// Whether this base is inherited from publically. pub is_pub: bool, } impl Base { /// Whether this base class is inheriting virtually. pub fn is_virtual(&self) -> bool { self.kind == BaseKind::Virtual } /// Whether this base class should have it's own field for storage. pub fn requires_storage(&self, ctx: &BindgenContext) -> bool { // Virtual bases are already taken into account by the vtable // pointer. // // FIXME(emilio): Is this always right? if self.is_virtual() { return false; } // NB: We won't include zero-sized types in our base chain because they // would contribute to our size given the dummy field we insert for // zero-sized types. if self.ty.is_zero_sized(ctx) { return false; } true } /// Whether this base is inherited from publically. pub fn is_public(&self) -> bool { self.is_pub } } /// A compound type. /// /// Either a struct or union, a compound type is built up from the combination /// of fields which also are associated with their own (potentially compound) /// type. #[derive(Debug)] pub struct CompInfo { /// Whether this is a struct or a union. kind: CompKind, /// The members of this struct or union. fields: CompFields, /// The abstract template parameters of this class. Note that these are NOT /// concrete template arguments, and should always be a /// `Type(TypeKind::TypeParam(name))`. For concrete template arguments, see /// `TypeKind::TemplateInstantiation`. template_params: Vec, /// 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: /// /// 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 we saw `__attribute__((packed))` on or within this type. packed_attr: bool, /// Used to know if we've found an opaque attribute that could cause us to /// generate a type with invalid layout. This is explicitly used to avoid us /// generating bad alignments when parsing types like max_align_t. /// /// It's not clear what the behavior should be here, if generating the item /// and pray, or behave as an opaque type. found_unknown_attr: bool, /// Used to indicate when a struct has been forward declared. Usually used /// in headers so that APIs can't modify them directly. is_forward_declaration: bool, } impl CompInfo { /// Construct a new compound type. pub fn new(kind: CompKind) -> Self { CompInfo { kind, fields: CompFields::default(), template_params: vec![], methods: vec![], constructors: vec![], destructor: None, base_members: vec![], inner_types: vec![], inner_vars: vec![], has_own_virtual_method: false, has_destructor: false, has_nonempty_base: false, has_non_type_template_params: false, packed_attr: false, found_unknown_attr: false, is_forward_declaration: false, } } /// Compute the layout of this type. /// /// This is called as a fallback under some circumstances where LLVM doesn't /// give us the correct layout. /// /// If we're a union without known layout, we try to compute it from our /// members. This is not ideal, but clang fails to report the size for these /// kind of unions, see test/headers/template_union.hpp pub fn layout(&self, ctx: &BindgenContext) -> Option { // We can't do better than clang here, sorry. if self.kind == CompKind::Struct { return None; } // By definition, we don't have the right layout information here if // we're a forward declaration. if self.is_forward_declaration() { return None; } // empty union case if !self.has_fields() { return None; } let mut max_size = 0; // Don't allow align(0) let mut max_align = 1; self.each_known_field_layout(ctx, |layout| { max_size = cmp::max(max_size, layout.size); max_align = cmp::max(max_align, layout.align); }); Some(Layout::new(max_size, max_align)) } /// Get this type's set of fields. pub fn fields(&self) -> &[Field] { match self.fields { CompFields::ErrorComputingBitfieldUnits => &[], CompFields::AfterComputingBitfieldUnits { ref fields, .. } => { fields } CompFields::BeforeComputingBitfieldUnits(..) => { panic!("Should always have computed bitfield units first"); } } } fn has_fields(&self) -> bool { match self.fields { CompFields::ErrorComputingBitfieldUnits => false, CompFields::AfterComputingBitfieldUnits { ref fields, .. } => { !fields.is_empty() } CompFields::BeforeComputingBitfieldUnits(ref raw_fields) => { !raw_fields.is_empty() } } } fn each_known_field_layout( &self, ctx: &BindgenContext, mut callback: impl FnMut(Layout), ) { match self.fields { CompFields::ErrorComputingBitfieldUnits => return, CompFields::AfterComputingBitfieldUnits { ref fields, .. } => { for field in fields.iter() { if let Some(layout) = field.layout(ctx) { callback(layout); } } } CompFields::BeforeComputingBitfieldUnits(ref raw_fields) => { for field in raw_fields.iter() { let field_ty = ctx.resolve_type(field.0.ty); if let Some(layout) = field_ty.layout(ctx) { callback(layout); } } } } } fn has_bitfields(&self) -> bool { match self.fields { CompFields::ErrorComputingBitfieldUnits => false, CompFields::AfterComputingBitfieldUnits { has_bitfield_units, .. } => has_bitfield_units, CompFields::BeforeComputingBitfieldUnits(_) => { panic!("Should always have computed bitfield units first"); } } } /// Returns whether we have a too large bitfield unit, in which case we may /// not be able to derive some of the things we should be able to normally /// derive. pub fn has_too_large_bitfield_unit(&self) -> bool { if !self.has_bitfields() { return false; } self.fields().iter().any(|field| match *field { Field::DataMember(..) => false, Field::Bitfields(ref unit) => { unit.layout.size > RUST_DERIVE_IN_ARRAY_LIMIT } }) } /// Does this type have any template parameters that aren't types /// (e.g. int)? pub fn has_non_type_template_params(&self) -> bool { self.has_non_type_template_params } /// Do we see a virtual function during parsing? /// Get the has_own_virtual_method boolean. pub fn has_own_virtual_method(&self) -> bool { self.has_own_virtual_method } /// Did we see a destructor when parsing this type? pub fn has_own_destructor(&self) -> bool { self.has_destructor } /// Get this type's set of methods. pub fn methods(&self) -> &[Method] { &self.methods } /// Get this type's set of constructors. pub fn constructors(&self) -> &[FunctionId] { &self.constructors } /// Get this type's destructor. pub fn destructor(&self) -> Option<(MethodKind, FunctionId)> { self.destructor } /// What kind of compound type is this? pub fn kind(&self) -> CompKind { self.kind } /// Is this a union? pub fn is_union(&self) -> bool { self.kind() == CompKind::Union } /// The set of types that this one inherits from. pub fn base_members(&self) -> &[Base] { &self.base_members } /// Construct a new compound type from a Clang type. pub fn from_ty( potential_id: ItemId, ty: &clang::Type, location: Option, 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 = cur.bit_width(); 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"); let inner = inner.expect_type_id(ctx); ci.inner_types.push(inner); // A declaration of an union or a struct without name could // also be an unnamed field, unfortunately. if cur.spelling().is_empty() && cur.kind() != CXCursor_EnumDecl { let ty = cur.cur_type(); let public = cur.public_accessible(); let offset = cur.offset_of_field().ok(); maybe_anonymous_struct_field = Some((inner, ty, public, offset)); } } CXCursor_PackedAttr => { ci.packed_attr = true; } CXCursor_TemplateTypeParameter => { let param = Item::type_param(None, cur, ctx).expect( "Item::type_param should't fail when pointing \ at a TemplateTypeParameter", ); ci.template_params.push(param); } CXCursor_CXXBaseSpecifier => { let is_virtual_base = cur.is_virtual_base(); ci.has_own_virtual_method |= is_virtual_base; let kind = if is_virtual_base { BaseKind::Virtual } else { BaseKind::Normal }; let field_name = match ci.base_members.len() { 0 => "_base".into(), n => format!("_base_{}", n), }; let type_id = Item::from_ty_or_ref(cur.cur_type(), cur, None, ctx); ci.base_members.push(Base { ty: type_id, kind, field_name, is_pub: cur.access_specifier() == clang_sys::CX_CXXPublic, }); } CXCursor_Constructor | CXCursor_Destructor | CXCursor_CXXMethod => { let is_virtual = cur.method_is_virtual(); let is_static = cur.method_is_static(); debug_assert!(!(is_static && is_virtual), "How?"); ci.has_destructor |= cur.kind() == CXCursor_Destructor; ci.has_own_virtual_method |= is_virtual; // This used to not be here, but then I tried generating // stylo bindings with this (without path filters), and // cried a lot with a method in gfx/Point.h // (ToUnknownPoint), that somehow was causing the same type // to be inserted in the map two times. // // I couldn't make a reduced test case, but anyway... // Methods of template functions not only used to be inlined, // but also instantiated, and we wouldn't be able to call // them, so just bail out. if !ci.template_params.is_empty() { return CXChildVisit_Continue; } // NB: This gets us an owned `Function`, not a // `FunctionSig`. let signature = match Item::parse(cur, Some(potential_id), ctx) { Ok(item) if ctx .resolve_item(item) .kind() .is_function() => { item } _ => return CXChildVisit_Continue, }; let signature = signature.expect_function_id(ctx); match cur.kind() { CXCursor_Constructor => { ci.constructors.push(signature); } CXCursor_Destructor => { let kind = if is_virtual { MethodKind::VirtualDestructor { pure_virtual: cur.method_is_pure_virtual(), } } else { MethodKind::Destructor }; ci.destructor = Some((kind, signature)); } CXCursor_CXXMethod => { let is_const = cur.method_is_const(); let method_kind = if is_static { MethodKind::Static } else if is_virtual { MethodKind::Virtual { pure_virtual: cur.method_is_pure_virtual(), } } else { MethodKind::Normal }; let method = Method::new(method_kind, signature, is_const); ci.methods.push(method); } _ => unreachable!("How can we see this here?"), } } CXCursor_NonTypeTemplateParameter => { ci.has_non_type_template_params = true; } CXCursor_VarDecl => { let linkage = cur.linkage(); if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal { return CXChildVisit_Continue; } let visibility = cur.visibility(); if visibility != CXVisibility_Default { return CXChildVisit_Continue; } if let Ok(item) = Item::parse(cur, Some(potential_id), ctx) { ci.inner_vars.push(item.as_var_id_unchecked()); } } // Intentionally not handled CXCursor_CXXAccessSpecifier | CXCursor_CXXFinalAttr | CXCursor_FunctionTemplate | CXCursor_ConversionFunction => {} _ => { warn!( "unhandled comp member `{}` (kind {:?}) in `{}` ({})", cur.spelling(), clang::kind_to_str(cur.kind()), cursor.spelling(), cur.location() ); } } CXChildVisit_Continue }); if let Some((ty, _, public, offset)) = maybe_anonymous_struct_field { let field = RawField::new(None, ty, None, None, None, public, offset); ci.fields.append_raw_field(field); } Ok(ci) } fn kind_from_cursor( cursor: &clang::Cursor, ) -> Result { use clang_sys::*; Ok(match cursor.kind() { CXCursor_UnionDecl => CompKind::Union, CXCursor_ClassDecl | CXCursor_StructDecl => CompKind::Struct, CXCursor_CXXBaseSpecifier | CXCursor_ClassTemplatePartialSpecialization | CXCursor_ClassTemplate => match cursor.template_kind() { CXCursor_UnionDecl => CompKind::Union, _ => CompKind::Struct, }, _ => { warn!("Unknown kind for comp type: {:?}", cursor); return Err(ParseError::Continue); } }) } /// Get the set of types that were declared within this compound type /// (e.g. nested class definitions). pub fn inner_types(&self) -> &[TypeId] { &self.inner_types } /// Get the set of static variables declared within this compound type. pub fn inner_vars(&self) -> &[VarId] { &self.inner_vars } /// Have we found a field with an opaque type that could potentially mess up /// the layout of this compound type? pub fn found_unknown_attr(&self) -> bool { self.found_unknown_attr } /// Is this compound type packed? pub fn is_packed( &self, ctx: &BindgenContext, layout: Option<&Layout>, ) -> bool { if self.packed_attr { return true; } // Even though `libclang` doesn't expose `#pragma packed(...)`, we can // detect it through its effects. if let Some(parent_layout) = layout { let mut packed = false; self.each_known_field_layout(ctx, |layout| { packed = packed || layout.align > parent_layout.align; }); if packed { info!("Found a struct that was defined within `#pragma packed(...)`"); return true; } if self.has_own_virtual_method && parent_layout.align == 1 { return true; } } false } /// Returns true if compound type has been forward declared pub fn is_forward_declaration(&self) -> bool { self.is_forward_declaration } /// Compute this compound structure's bitfield allocation units. pub fn compute_bitfield_units( &mut self, ctx: &BindgenContext, layout: Option<&Layout>, ) { let packed = self.is_packed(ctx, layout); self.fields.compute_bitfield_units(ctx, packed) } /// Assign for each anonymous field a generated name. pub fn deanonymize_fields(&mut self, ctx: &BindgenContext) { self.fields.deanonymize_fields(ctx, &self.methods); } /// Returns whether the current union can be represented as a Rust `union` /// /// Requirements: /// 1. Current RustTarget allows for `untagged_union` /// 2. Each field can derive `Copy` /// 3. It's not zero-sized. pub fn can_be_rust_union( &self, ctx: &BindgenContext, layout: Option<&Layout>, ) -> bool { if !ctx.options().rust_features().untagged_union { return false; } if self.is_forward_declaration() { return false; } 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 { return false; } if layout.map_or(false, |l| l.size == 0) { return false; } true } } 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 { 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::ErrorComputingBitfieldUnits = 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.59.1/src/ir/context.rs000064400000000000000000003065120000000000000145450ustar 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::callbacks::ParseCallbacks; use crate::clang::{self, Cursor}; use crate::parse::ClangItemParser; use crate::BindgenOptions; use crate::{Entry, HashMap, HashSet}; use cexpr; use clang_sys; use proc_macro2::{Ident, Span}; use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::collections::{BTreeSet, HashMap as StdHashMap}; use std::iter::IntoIterator; use std::mem; /// An identifier for some kind of IR item. #[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] pub struct ItemId(usize); macro_rules! item_id_newtype { ( $( #[$attr:meta] )* pub struct $name:ident(ItemId) where $( #[$checked_attr:meta] )* checked = $checked:ident with $check_method:ident, $( #[$expected_attr:meta] )* expected = $expected:ident, $( #[$unchecked_attr:meta] )* unchecked = $unchecked:ident; ) => { $( #[$attr] )* #[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] pub struct $name(ItemId); impl $name { /// Create an `ItemResolver` from this id. pub fn into_resolver(self) -> ItemResolver { let id: ItemId = self.into(); id.into() } } impl ::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 } } impl ItemId { $( #[$checked_attr] )* pub fn $checked(&self, ctx: &BindgenContext) -> Option<$name> { if ctx.resolve_item(*self).kind().$check_method() { Some($name(*self)) } else { None } } $( #[$expected_attr] )* pub fn $expected(&self, ctx: &BindgenContext) -> $name { self.$checked(ctx) .expect(concat!( stringify!($expected), " called with ItemId that points to the wrong ItemKind" )) } $( #[$unchecked_attr] )* pub fn $unchecked(&self) -> $name { $name(*self) } } } } item_id_newtype! { /// An identifier for an `Item` whose `ItemKind` is known to be /// `ItemKind::Type`. pub struct TypeId(ItemId) where /// Convert this `ItemId` into a `TypeId` if its associated item is a type, /// otherwise return `None`. checked = as_type_id with is_type, /// Convert this `ItemId` into a `TypeId`. /// /// If this `ItemId` does not point to a type, then panic. expected = expect_type_id, /// Convert this `ItemId` into a `TypeId` without actually checking whether /// this id actually points to a `Type`. unchecked = as_type_id_unchecked; } item_id_newtype! { /// An identifier for an `Item` whose `ItemKind` is known to be /// `ItemKind::Module`. pub struct ModuleId(ItemId) where /// Convert this `ItemId` into a `ModuleId` if its associated item is a /// module, otherwise return `None`. checked = as_module_id with is_module, /// Convert this `ItemId` into a `ModuleId`. /// /// If this `ItemId` does not point to a module, then panic. expected = expect_module_id, /// Convert this `ItemId` into a `ModuleId` without actually checking /// whether this id actually points to a `Module`. unchecked = as_module_id_unchecked; } item_id_newtype! { /// An identifier for an `Item` whose `ItemKind` is known to be /// `ItemKind::Var`. pub struct VarId(ItemId) where /// Convert this `ItemId` into a `VarId` if its associated item is a var, /// otherwise return `None`. checked = as_var_id with is_var, /// Convert this `ItemId` into a `VarId`. /// /// If this `ItemId` does not point to a var, then panic. expected = expect_var_id, /// Convert this `ItemId` into a `VarId` without actually checking whether /// this id actually points to a `Var`. unchecked = as_var_id_unchecked; } item_id_newtype! { /// An identifier for an `Item` whose `ItemKind` is known to be /// `ItemKind::Function`. pub struct FunctionId(ItemId) where /// Convert this `ItemId` into a `FunctionId` if its associated item is a function, /// otherwise return `None`. checked = as_function_id with is_function, /// Convert this `ItemId` into a `FunctionId`. /// /// If this `ItemId` does not point to a function, then panic. expected = expect_function_id, /// Convert this `ItemId` into a `FunctionId` without actually checking whether /// this id actually points to a `Function`. unchecked = as_function_id_unchecked; } impl From for usize { fn from(id: ItemId) -> usize { id.0 } } impl ItemId { /// Get a numeric representation of this id. pub fn as_usize(&self) -> usize { (*self).into() } } impl ::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 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 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 clang index for parsing. index: clang::Index, /// The translation unit for parsing. translation_unit: clang::TranslationUnit, /// Target information that can be useful for some stuff. target_info: Option, /// The options given by the user via cli or other medium. options: BindgenOptions, /// Whether a bindgen complex was generated generated_bindgen_complex: 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 (`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 copy in array. /// /// This is populated when we enter codegen by `compute_cannot_derive_copy` /// and is always `None` before that and `Some` after. cannot_derive_copy_in_array: 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, for<'a> fn(&'a BindgenContext, Edge) -> bool, >, } impl<'ctx> Iterator for AllowlistedItemsTraversal<'ctx> { 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 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) -> 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, &options.input_unsaved_files, parse_options, ).expect("libclang error; possible causes include: - Invalid flag syntax - Unrecognized flags - Invalid flag arguments - File I/O errors - Host vs. target architecture mismatch If you encounter an error missing from this list, please file an issue or a PR!") }; let target_info = clang::TargetInfo::new(&translation_unit); let root_module = Self::build_root_module(ItemId(0)); let root_module_id = root_module.id().as_module_id_unchecked(); // depfiles need to include the explicitly listed headers too let mut deps = BTreeSet::default(); if let Some(filename) = &options.input_header { deps.insert(filename.clone()); } deps.extend(options.extra_input_headers.iter().cloned()); BindgenContext { items: vec![Some(root_module)], deps, types: Default::default(), type_params: Default::default(), modules: Default::default(), root_module: root_module_id, current_module: root_module_id, semantic_parents: Default::default(), currently_parsed_types: vec![], parsed_macros: Default::default(), replacements: Default::default(), collected_typerefs: false, in_codegen: false, index, translation_unit, target_info, options, generated_bindgen_complex: Cell::new(false), allowlisted: None, blocklisted_types_implement_traits: Default::default(), codegen_items: None, used_template_parameters: None, need_bitfield_allocation: Default::default(), cannot_derive_debug: None, cannot_derive_default: None, cannot_derive_copy: None, cannot_derive_copy_in_array: 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 fn is_target_wasm32(&self) -> bool { match self.target_info { Some(ref ti) => ti.triple.starts_with("wasm32-"), None => false, } } /// Creates a timer for the current bindgen phase. If time_phases is `true`, /// the timer will print to stderr when it is dropped, otherwise it will do /// nothing. pub fn timer<'a>(&self, name: &'a str) -> Timer<'a> { Timer::new(name).with_output(self.options.time_phases) } /// Returns the pointer width to use for the target for the current /// translation. pub fn target_pointer_size(&self) -> usize { if let Some(ref ti) = self.target_info { return ti.pointer_width / 8; } mem::size_of::<*mut ()>() } /// Get the stack of partially parsed types that we are in the middle of /// parsing. pub fn currently_parsed_types(&self) -> &[PartialType] { &self.currently_parsed_types[..] } /// Begin parsing the given partial type, and push it onto the /// `currently_parsed_types` stack so that we won't infinite recurse if we /// run into a reference to it while parsing it. pub fn begin_parsing(&mut self, partial_ty: PartialType) { self.currently_parsed_types.push(partial_ty); } /// Finish parsing the current partial type, pop it off the /// `currently_parsed_types` stack, and return it. pub fn finish_parsing(&mut self) -> PartialType { self.currently_parsed_types.pop().expect( "should have been parsing a type, if we finished parsing a type", ) } /// Get the user-provided callbacks by reference, if any. pub fn parse_callbacks(&self) -> Option<&dyn ParseCallbacks> { self.options().parse_callbacks.as_ref().map(|t| &**t) } /// Add another path to the set of included files. pub fn include_file(&mut self, filename: String) { if let Some(cbs) = self.parse_callbacks() { cbs.include_file(&filename); } self.deps.insert(filename); } /// Get any included files. pub fn deps(&self) -> &BTreeSet { &self.deps } /// Define a new item. /// /// This inserts it into the internal items set, and its type into the /// internal types set. pub fn add_item( &mut self, item: Item, declaration: Option, location: Option, ) { debug!( "BindgenContext::add_item({:?}, declaration: {:?}, loc: {:?}", item, declaration, location ); debug_assert!( declaration.is_some() || !item.kind().is_type() || item.kind().expect_type().is_builtin_or_type_param() || item.kind().expect_type().is_opaque(self, &item) || item.kind().expect_type().is_unresolved_ref(), "Adding a type without declaration?" ); let id = item.id(); let is_type = item.kind().is_type(); let is_unnamed = is_type && item.expect_type().name().is_none(); let is_template_instantiation = is_type && item.expect_type().is_template_instantiation(); if item.id() != self.root_module { self.add_item_to_module(&item); } if is_type && item.expect_type().is_comp() { self.need_bitfield_allocation.push(id); } let old_item = mem::replace(&mut self.items[id.0], Some(item)); assert!( old_item.is_none(), "should not have already associated an item with the given id" ); // Unnamed items can have an USR, but they can't be referenced from // other sites explicitly and the USR can match if the unnamed items are // nested, so don't bother tracking them. if is_type && !is_template_instantiation && declaration.is_some() { let mut declaration = declaration.unwrap(); if !declaration.is_valid() { if let Some(location) = location { if location.is_template_like() { declaration = location; } } } declaration = declaration.canonical(); if !declaration.is_valid() { // This could happen, for example, with types like `int*` or // similar. // // Fortunately, we don't care about those types being // duplicated, so we can just ignore them. debug!( "Invalid declaration {:?} found for type {:?}", declaration, self.resolve_item_fallible(id) .unwrap() .kind() .expect_type() ); return; } let key = if is_unnamed { TypeKey::Declaration(declaration) } else if let Some(usr) = declaration.usr() { TypeKey::USR(usr) } else { warn!( "Valid declaration with no USR: {:?}, {:?}", declaration, location ); TypeKey::Declaration(declaration) }; let old = self.types.insert(key, id.as_type_id_unchecked()); debug_assert_eq!(old, None); } } /// Ensure that every item (other than the root module) is in a module's /// children list. This is to make sure that every allowlisted item get's /// codegen'd, even if its parent is not allowlisted. See issue #769 for /// details. fn add_item_to_module(&mut self, item: &Item) { assert!(item.id() != self.root_module); assert!(self.resolve_item_fallible(item.id()).is_none()); if let Some(ref mut parent) = self.items[item.parent_id().0] { if let Some(module) = parent.as_module_mut() { debug!( "add_item_to_module: adding {:?} as child of parent module {:?}", item.id(), item.parent_id() ); module.children_mut().insert(item.id()); return; } } debug!( "add_item_to_module: adding {:?} as child of current module {:?}", item.id(), self.current_module ); self.items[(self.current_module.0).0] .as_mut() .expect("Should always have an item for self.current_module") .as_module_mut() .expect("self.current_module should always be a module") .children_mut() .insert(item.id()); } /// Add a new named template type parameter to this context's item set. pub fn add_type_param(&mut self, item: Item, definition: clang::Cursor) { debug!( "BindgenContext::add_type_param: item = {:?}; definition = {:?}", item, definition ); assert!( item.expect_type().is_type_param(), "Should directly be a named type, not a resolved reference or anything" ); assert_eq!( definition.kind(), clang_sys::CXCursor_TemplateTypeParameter ); self.add_item_to_module(&item); let id = item.id(); let old_item = mem::replace(&mut self.items[id.0], Some(item)); assert!( old_item.is_none(), "should not have already associated an item with the given id" ); let old_named_ty = self .type_params .insert(definition, id.as_type_id_unchecked()); assert!( old_named_ty.is_none(), "should not have already associated a named type with this id" ); } /// Get the named type defined at the given cursor location, if we've /// already added one. pub fn get_type_param(&self, definition: &clang::Cursor) -> Option { assert_eq!( definition.kind(), clang_sys::CXCursor_TemplateTypeParameter ); self.type_params.get(definition).cloned() } // TODO: Move all this syntax crap to other part of the code. /// Mangles a name so it doesn't conflict with any keyword. pub fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> { if name.contains("@") || name.contains("?") || name.contains("$") || match name { "abstract" | "alignof" | "as" | "async" | "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" | "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" | "_" => true, _ => false, } { let mut s = name.to_owned(); s = s.replace("@", "_"); s = s.replace("?", "_"); s = s.replace("$", "_"); s.push_str("_"); return Cow::Owned(s); } Cow::Borrowed(name) } /// Returns a mangled name as a rust identifier. pub 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 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 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 fn collected_typerefs(&self) -> bool { self.collected_typerefs } /// Gather all the unresolved type references. fn collect_typerefs( &mut self, ) -> Vec<(ItemId, clang::Type, clang::Cursor, Option)> { debug_assert!(!self.collected_typerefs); self.collected_typerefs = true; let mut typerefs = vec![]; for (id, item) in self.items() { let kind = item.kind(); let ty = match kind.as_type() { Some(ty) => ty, None => continue, }; match *ty.kind() { TypeKind::UnresolvedTypeRef(ref ty, loc, parent_id) => { typerefs.push((id, ty.clone(), 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::replace(&mut self.need_bitfield_allocation, vec![]); 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 ty = match item.kind().as_type() { Some(ty) => ty, None => continue, }; match *ty.kind() { TypeKind::Comp(..) | TypeKind::TemplateAlias(..) | TypeKind::Enum(..) | TypeKind::Alias(..) => {} _ => continue, } let path = item.path_for_allowlisting(self); let replacement = self.replacements.get(&path[1..]); if let Some(replacement) = replacement { if *replacement != id { // We set this just after parsing the annotation. It's // very unlikely, but this can happen. if self.resolve_item_fallible(*replacement).is_some() { replacements.push(( id.expect_type_id(self), replacement.expect_type_id(self), )); } } } } for (id, replacement_id) in replacements { debug!("Replacing {:?} with {:?}", id, replacement_id); let new_parent = { let item_id: ItemId = id.into(); let item = self.items[item_id.0].as_mut().unwrap(); *item.kind_mut().as_type_mut().unwrap().kind_mut() = TypeKind::ResolvedTypeRef(replacement_id); item.parent_id() }; // Relocate the replacement item from where it was declared, to // where the thing it is replacing was declared. // // First, we'll make sure that its parent id is correct. let old_parent = self.resolve_item(replacement_id).parent_id(); if new_parent == old_parent { // Same parent and therefore also same containing // module. Nothing to do here. continue; } let replacement_item_id: ItemId = replacement_id.into(); self.items[replacement_item_id.0] .as_mut() .unwrap() .set_parent_for_replacement(new_parent); // Second, make sure that it is in the correct module's children // set. let old_module = { let immut_self = &*self; old_parent .ancestors(immut_self) .chain(Some(immut_self.root_module.into())) .find(|id| { let item = immut_self.resolve_item(*id); item.as_module().map_or(false, |m| { m.children().contains(&replacement_id.into()) }) }) }; let old_module = old_module .expect("Every replacement item should be in a module"); let new_module = { let immut_self = &*self; new_parent .ancestors(immut_self) .find(|id| immut_self.resolve_item(*id).is_module()) }; let new_module = new_module.unwrap_or(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) -> (Out, BindgenOptions) where F: FnOnce(&Self) -> Out, { self.in_codegen = true; self.resolve_typerefs(); self.compute_bitfield_units(); self.process_replacements(); self.deanonymize_fields(); self.assert_no_dangling_references(); // Compute the allowlisted set after processing replacements and // resolving type refs, as those are the final mutations of the IR // graph, and their completion means that the IR graph is now frozen. self.compute_allowlisted_and_codegen_items(); // Make sure to do this after processing replacements, since that messes // with the parentage and module children, and we want to assert that it // messes with them correctly. self.assert_every_item_in_a_module(); self.compute_has_vtable(); self.compute_sizedness(); self.compute_has_destructor(); self.find_used_template_parameters(); self.compute_cannot_derive_debug(); self.compute_cannot_derive_default(); self.compute_cannot_derive_copy(); self.compute_has_type_param_in_array(); self.compute_has_float(); self.compute_cannot_derive_hash(); self.compute_cannot_derive_partialord_partialeq_or_eq(); let ret = cb(&self); (ret, self.options) } /// When the `testing_only_extra_assertions` feature is enabled, this /// function walks the IR graph and asserts that we do not have any edges /// referencing an ItemId for which we do not have an associated IR item. fn assert_no_dangling_references(&self) { if cfg!(feature = "testing_only_extra_assertions") { for _ in self.assert_no_dangling_item_traversal() { // The iterator's next method does the asserting for us. } } } fn assert_no_dangling_item_traversal( &self, ) -> traversal::AssertNoDanglingItemsTraversal { assert!(self.in_codegen_phase()); assert!(self.current_module == self.root_module); let roots = self.items().map(|(id, _)| id); traversal::AssertNoDanglingItemsTraversal::new( self, roots, traversal::all_edges, ) } /// When the `testing_only_extra_assertions` feature is enabled, walk over /// every item and ensure that it is in the children set of one of its /// module ancestors. fn assert_every_item_in_a_module(&self) { if cfg!(feature = "testing_only_extra_assertions") { assert!(self.in_codegen_phase()); assert!(self.current_module == self.root_module); for (id, _item) in self.items() { if id == self.root_module { continue; } assert!( { let id = id .into_resolver() .through_type_refs() .through_type_aliases() .resolve(self) .id(); id.ancestors(self) .chain(Some(self.root_module.into())) .any(|ancestor| { debug!( "Checking if {:?} is a child of {:?}", id, ancestor ); self.resolve_item(ancestor) .as_module() .map_or(false, |m| { m.children().contains(&id) }) }) }, "{:?} should be in some ancestor module's children set", id ); } } } /// Compute for every type whether it is sized or not, and whether it is /// sized or not as a base class. fn compute_sizedness(&mut self) { let _t = self.timer("compute_sizedness"); assert!(self.sizedness.is_none()); self.sizedness = Some(analyze::(self)); } /// Look up whether the type with the given id is sized or not. pub fn lookup_sizedness(&self, id: TypeId) -> SizednessResult { assert!( self.in_codegen_phase(), "We only compute sizedness after we've entered codegen" ); self.sizedness .as_ref() .unwrap() .get(&id) .cloned() .unwrap_or(SizednessResult::ZeroSized) } /// Compute whether the type has vtable. fn compute_has_vtable(&mut self) { let _t = self.timer("compute_has_vtable"); assert!(self.have_vtable.is_none()); self.have_vtable = Some(analyze::(self)); } /// Look up whether the item with `id` has vtable or not. pub fn lookup_has_vtable(&self, id: TypeId) -> HasVtableResult { assert!( self.in_codegen_phase(), "We only compute vtables when we enter codegen" ); // Look up the computed value for whether the item with `id` has a // vtable or not. self.have_vtable .as_ref() .unwrap() .get(&id.into()) .cloned() .unwrap_or(HasVtableResult::No) } /// Compute whether the type has a destructor. fn compute_has_destructor(&mut self) { let _t = self.timer("compute_has_destructor"); assert!(self.have_destructor.is_none()); self.have_destructor = Some(analyze::(self)); } /// Look up whether the item with `id` has a destructor. pub fn lookup_has_destructor(&self, id: TypeId) -> bool { assert!( self.in_codegen_phase(), "We only compute destructors when we enter codegen" ); self.have_destructor.as_ref().unwrap().contains(&id.into()) } fn find_used_template_parameters(&mut self) { let _t = self.timer("find_used_template_parameters"); if self.options.allowlist_recursively { let used_params = analyze::(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( id.self_template_params(self) .into_iter() .map(|p| p.into()) .collect(), ); } self.used_template_parameters = Some(used_params); } } /// Return `true` if `item` uses the given `template_param`, `false` /// otherwise. /// /// This method may only be called during the codegen phase, because the /// template usage information is only computed as we enter the codegen /// phase. /// /// If the item is blocklisted, then we say that it always uses the template /// parameter. This is a little subtle. The template parameter usage /// analysis only considers allowlisted items, and if any blocklisted item /// shows up in the generated bindings, it is the user's responsibility to /// manually provide a definition for them. To give them the most /// flexibility when doing that, we assume that they use every template /// parameter and always pass template arguments through in instantiations. pub fn uses_template_parameter( &self, item: ItemId, template_param: TypeId, ) -> bool { assert!( self.in_codegen_phase(), "We only compute template parameter usage as we enter codegen" ); if self.resolve_item(item).is_blocklisted(self) { return true; } let template_param = template_param .into_resolver() .through_type_refs() .through_type_aliases() .resolve(self) .id(); self.used_template_parameters .as_ref() .expect("should have found template parameter usage if we're in codegen") .get(&item) .map_or(false, |items_used_params| items_used_params.contains(&template_param)) } /// Return `true` if `item` uses any unbound, generic template parameters, /// `false` otherwise. /// /// Has the same restrictions that `uses_template_parameter` has. pub fn uses_any_template_parameters(&self, item: ItemId) -> bool { assert!( self.in_codegen_phase(), "We only compute template parameter usage as we enter codegen" ); self.used_template_parameters .as_ref() .expect( "should have template parameter usage info in codegen phase", ) .get(&item) .map_or(false, |used| !used.is_empty()) } // This deserves a comment. Builtin types don't get a valid declaration, so // we can't add it to the cursor->type map. // // That being said, they're not generated anyway, and are few, so the // duplication and special-casing is fine. // // If at some point we care about the memory here, probably a map TypeKind // -> builtin type ItemId would be the best to improve that. fn add_builtin_item(&mut self, item: Item) { debug!("add_builtin_item: item = {:?}", item); debug_assert!(item.kind().is_type()); self.add_item_to_module(&item); let id = item.id(); let old_item = mem::replace(&mut self.items[id.0], Some(item)); assert!(old_item.is_none(), "Inserted type twice?"); } fn build_root_module(id: ItemId) -> Item { let module = Module::new(Some("root".into()), ModuleKind::Normal); Item::new(id, None, None, id, ItemKind::Module(module)) } /// Get the root module. pub fn root_module(&self) -> ModuleId { self.root_module } /// Resolve a type with the given id. /// /// Panics if there is no item for the given `TypeId` or if the resolved /// item is not a `Type`. pub fn resolve_type(&self, type_id: TypeId) -> &Type { self.resolve_item(type_id).kind().expect_type() } /// Resolve a function with the given id. /// /// Panics if there is no item for the given `FunctionId` or if the resolved /// item is not a `Function`. pub fn resolve_func(&self, func_id: FunctionId) -> &Function { self.resolve_item(func_id).kind().expect_function() } /// Resolve the given `ItemId` as a type, or `None` if there is no item with /// the given id. /// /// Panics if the id resolves to an item that is not a type. pub fn safe_resolve_type(&self, type_id: TypeId) -> Option<&Type> { self.resolve_item_fallible(type_id) .map(|t| t.kind().expect_type()) } /// Resolve the given `ItemId` into an `Item`, or `None` if no such item /// exists. pub fn resolve_item_fallible>( &self, id: Id, ) -> Option<&Item> { self.items.get(id.into().0)?.as_ref() } /// Resolve the given `ItemId` into an `Item`. /// /// Panics if the given id does not resolve to any item. pub fn resolve_item>(&self, item_id: Id) -> &Item { let item_id = item_id.into(); match self.resolve_item_fallible(item_id) { Some(item) => item, None => panic!("Not an item: {:?}", item_id), } } /// Get the current module. pub fn current_module(&self) -> ModuleId { self.current_module } /// Add a semantic parent for a given type definition. /// /// We do this from the type declaration, in order to be able to find the /// correct type definition afterwards. /// /// TODO(emilio): We could consider doing this only when /// declaration.lexical_parent() != definition.lexical_parent(), but it's /// not sure it's worth it. pub fn add_semantic_parent( &mut self, definition: clang::Cursor, parent_id: ItemId, ) { self.semantic_parents.insert(definition, parent_id); } /// Returns a known semantic parent for a given definition. pub fn known_semantic_parent( &self, definition: clang::Cursor, ) -> Option { self.semantic_parents.get(&definition).cloned() } /// Given a cursor pointing to the location of a template instantiation, /// return a tuple of the form `(declaration_cursor, declaration_id, /// num_expected_template_args)`. /// /// Note that `declaration_id` is not guaranteed to be in the context's item /// set! It is possible that it is a partial type that we are still in the /// middle of parsing. fn get_declaration_info_for_template_instantiation( &self, instantiation: &Cursor, ) -> Option<(Cursor, ItemId, usize)> { instantiation .cur_type() .canonical_declaration(Some(instantiation)) .and_then(|canon_decl| { self.get_resolved_type(&canon_decl).and_then( |template_decl_id| { let num_params = template_decl_id.num_self_template_params(self); if num_params == 0 { None } else { Some(( *canon_decl.cursor(), template_decl_id.into(), num_params, )) } }, ) }) .or_else(|| { // If we haven't already parsed the declaration of // the template being instantiated, then it *must* // be on the stack of types we are currently // parsing. If it wasn't then clang would have // already errored out before we started // constructing our IR because you can't instantiate // a template until it is fully defined. instantiation .referenced() .and_then(|referenced| { self.currently_parsed_types() .iter() .find(|partial_ty| *partial_ty.decl() == referenced) .cloned() }) .and_then(|template_decl| { let num_template_params = template_decl.num_self_template_params(self); if num_template_params == 0 { None } else { Some(( *template_decl.decl(), template_decl.id(), num_template_params, )) } }) }) } /// Parse a template instantiation, eg `Foo`. /// /// 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: clang::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), ); // 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), ); // Bypass all the validations in add_item explicitly. debug!("instantiate_template: inserting item: {:?}", item); self.add_item_to_module(&item); debug_assert_eq!(with_id, item.id()); self.items[with_id.0] = Some(item); Some(with_id.as_type_id_unchecked()) } /// If we have already resolved the type for the given type declaration, /// return its `ItemId`. Otherwise, return `None`. pub fn get_resolved_type( &self, decl: &clang::CanonicalTypeDeclaration, ) -> Option { self.types .get(&TypeKey::Declaration(*decl.cursor())) .or_else(|| { decl.cursor() .usr() .and_then(|usr| self.types.get(&TypeKey::USR(usr))) }) .cloned() } /// Looks up for an already resolved type, either because it's builtin, or /// because we already have it in the map. pub fn builtin_or_resolved_ty( &mut self, with_id: ItemId, parent_id: Option, 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 decl.cursor().is_template_like() && *ty != decl.cursor().cur_type() && location.is_some() { let location = location.unwrap(); // 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_else(|| Some(id)); } return Some(self.build_ty_wrapper(with_id, id, parent_id, ty)); } } debug!("Not resolved, maybe builtin?"); self.build_builtin_ty(ty) } /// Make a new item that is a resolved type reference to the `wrapped_id`. /// /// This is unfortunately a lot of bloat, but is needed to properly track /// constness et al. /// /// We should probably make the constness tracking separate, so it doesn't /// bloat that much, but hey, we already bloat the heck out of builtin /// types. pub fn build_ty_wrapper( &mut self, with_id: ItemId, wrapped_id: TypeId, parent_id: Option, ty: &clang::Type, ) -> TypeId { self.build_wrapper(with_id, wrapped_id, parent_id, ty, ty.is_const()) } /// A wrapper over a type that adds a const qualifier explicitly. /// /// Needed to handle const methods in C++, wrapping the type . pub fn build_const_wrapper( &mut self, with_id: ItemId, wrapped_id: TypeId, parent_id: Option, 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 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(self.current_module.into()), ItemKind::Type(ty), ); self.add_builtin_item(item); with_id.as_type_id_unchecked() } /// Returns the next item id to be used for an item. pub fn next_item_id(&mut self) -> ItemId { let ret = ItemId(self.items.len()); self.items.push(None); ret } fn build_builtin_ty(&mut self, ty: &clang::Type) -> Option { use clang_sys::*; let type_kind = match ty.kind() { CXType_NullPtr => TypeKind::NullPtr, CXType_Void => TypeKind::Void, CXType_Bool => TypeKind::Int(IntKind::Bool), CXType_Int => TypeKind::Int(IntKind::Int), CXType_UInt => TypeKind::Int(IntKind::UInt), CXType_Char_S => TypeKind::Int(IntKind::Char { is_signed: true }), CXType_Char_U => TypeKind::Int(IntKind::Char { is_signed: false }), CXType_SChar => TypeKind::Int(IntKind::SChar), CXType_UChar => TypeKind::Int(IntKind::UChar), CXType_Short => TypeKind::Int(IntKind::Short), CXType_UShort => TypeKind::Int(IntKind::UShort), CXType_WChar => TypeKind::Int(IntKind::WChar), CXType_Char16 => TypeKind::Int(IntKind::U16), CXType_Char32 => TypeKind::Int(IntKind::U32), CXType_Long => TypeKind::Int(IntKind::Long), CXType_ULong => TypeKind::Int(IntKind::ULong), CXType_LongLong => TypeKind::Int(IntKind::LongLong), CXType_ULongLong => TypeKind::Int(IntKind::ULongLong), CXType_Int128 => TypeKind::Int(IntKind::I128), CXType_UInt128 => TypeKind::Int(IntKind::U128), CXType_Float => TypeKind::Float(FloatKind::Float), CXType_Double => TypeKind::Float(FloatKind::Double), CXType_LongDouble => TypeKind::Float(FloatKind::LongDouble), CXType_Float128 => TypeKind::Float(FloatKind::Float128), CXType_Complex => { let float_type = ty.elem_type().expect("Not able to resolve complex type?"); let float_kind = match float_type.kind() { CXType_Float => FloatKind::Float, CXType_Double => FloatKind::Double, CXType_LongDouble => FloatKind::LongDouble, CXType_Float128 => FloatKind::Float128, _ => panic!( "Non floating-type complex? {:?}, {:?}", ty, float_type, ), }; TypeKind::Complex(float_kind) } _ => return None, }; let spelling = ty.spelling(); let is_const = ty.is_const(); let layout = ty.fallible_layout(self).ok(); let 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), ); self.add_builtin_item(item); Some(id.as_type_id_unchecked()) } /// Get the current Clang translation unit that is being processed. pub fn translation_unit(&self) -> &clang::TranslationUnit { &self.translation_unit } /// Have we parsed the macro named `macro_name` already? pub fn parsed_macro(&self, macro_name: &[u8]) -> bool { self.parsed_macros.contains_key(macro_name) } /// Get the currently parsed macros. pub fn parsed_macros( &self, ) -> &StdHashMap, cexpr::expr::EvalResult> { debug_assert!(!self.in_codegen_phase()); &self.parsed_macros } /// Mark the macro named `macro_name` as parsed. pub fn note_parsed_macro( &mut self, id: Vec, value: cexpr::expr::EvalResult, ) { self.parsed_macros.insert(id, value); } /// Are we in the codegen phase? pub fn in_codegen_phase(&self) -> bool { self.in_codegen } /// Mark the type with the given `name` as replaced by the type with id /// `potential_ty`. /// /// Replacement types are declared using the `replaces="xxx"` annotation, /// and implies that the original type is hidden. pub fn replace(&mut self, name: &[String], potential_ty: ItemId) { match self.replacements.entry(name.into()) { Entry::Vacant(entry) => { debug!( "Defining replacement for {:?} as {:?}", name, potential_ty ); entry.insert(potential_ty); } Entry::Occupied(occupied) => { warn!( "Replacement for {:?} already defined as {:?}; \ ignoring duplicate replacement definition as {:?}", name, occupied.get(), potential_ty ); } } } /// Has the item with the given `name` and `id` been replaced by another /// type? pub fn is_replaced_type>( &self, path: &[String], id: Id, ) -> bool { let id = id.into(); match self.replacements.get(path) { Some(replaced_by) if *replaced_by != id => true, _ => false, } } /// Is the type with the given `name` marked as opaque? pub fn opaque_by_name(&self, path: &[String]) -> bool { debug_assert!( self.in_codegen_phase(), "You're not supposed to call this yet" ); self.options.opaque_types.matches(&path[1..].join("::")) } /// Get the options used to configure this bindgen context. pub(crate) fn options(&self) -> &BindgenOptions { &self.options } /// Tokenizes a namespace cursor in order to get the name and kind of the /// namespace. fn tokenize_namespace( &self, cursor: &clang::Cursor, ) -> (Option, 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 tokens = cursor.tokens(); let mut iter = tokens.iter(); let mut kind = ModuleKind::Normal; let mut found_namespace_keyword = false; while let Some(token) = iter.next() { match token.spelling() { b"inline" => { assert!(!found_namespace_keyword); assert!(kind != ModuleKind::Inline); kind = ModuleKind::Inline; } // The double colon allows us to handle nested namespaces like // namespace foo::bar { } // // libclang still gives us two namespace cursors, which is cool, // but the tokenization of the second begins with the double // colon. That's ok, so we only need to handle the weird // tokenization here. // // Fortunately enough, inline nested namespace specifiers aren't // a thing, and are invalid C++ :) b"namespace" | b"::" => { found_namespace_keyword = true; } b"{" => { assert!(found_namespace_keyword); break; } name if found_namespace_keyword => { if module_name.is_none() { module_name = Some(String::from_utf8_lossy(name).into_owned()); } break; } spelling if !found_namespace_keyword => { // This is _likely_, but not certainly, a macro that's been placed just before // the namespace keyword. Unfortunately, clang tokens don't let us easily see // through the ifdef tokens, so we don't know what this token should really be. // Instead of panicking though, we warn the user that we assumed the token was // blank, and then move on. // // See also https://github.com/rust-lang/rust-bindgen/issues/1676. warn!( "Ignored unknown namespace prefix '{}' at {:?} in {:?}", String::from_utf8_lossy(spelling), token, cursor ); } spelling => { panic!( "Unknown token '{}' while processing namespace at {:?} in {:?}", String::from_utf8_lossy(spelling), token, cursor ); } } } (module_name, kind) } /// Given a CXCursor_Namespace cursor, return the item id of the /// corresponding module, or create one on the fly. pub fn module(&mut self, cursor: clang::Cursor) -> ModuleId { use clang_sys::*; assert_eq!(cursor.kind(), CXCursor_Namespace, "Be a nice person"); let cursor = cursor.canonical(); if let Some(id) = self.modules.get(&cursor) { return *id; } let (module_name, kind) = self.tokenize_namespace(&cursor); let module_id = self.next_item_id(); let module = Module::new(module_name, kind); let module = Item::new( module_id, None, None, self.current_module.into(), ItemKind::Module(module), ); let module_id = module.id().as_module_id_unchecked(); self.modules.insert(cursor, module_id); self.add_item(module, None, None); module_id } /// Start traversing the module with the given `module_id`, invoke the /// callback `cb`, and then return to traversing the original module. pub fn with_module(&mut self, module_id: ModuleId, cb: F) where F: FnOnce(&mut Self), { debug_assert!(self.resolve_item(module_id).kind().is_module(), "Wat"); let previous_id = self.current_module; self.current_module = module_id; cb(self); self.current_module = previous_id; } /// Iterate over all (explicitly or transitively) allowlisted items. /// /// If no items are explicitly allowlisted, then all items are considered /// allowlisted. pub fn allowlisted_items(&self) -> &ItemSet { assert!(self.in_codegen_phase()); assert!(self.current_module == self.root_module); self.allowlisted.as_ref().unwrap() } /// Check whether a particular blocklisted type implements a trait or not. /// Results may be cached. pub fn blocklisted_type_implements_trait( &self, item: &Item, derive_trait: DeriveTrait, ) -> CanDerive { assert!(self.in_codegen_phase()); assert!(self.current_module == self.root_module); let cb = match self.options.parse_callbacks { Some(ref cb) => cb, None => return CanDerive::No, }; *self .blocklisted_types_implement_traits .borrow_mut() .entry(derive_trait) .or_default() .entry(item.id()) .or_insert_with(|| { item.expect_type() .name() .and_then(|name| { cb.blocklisted_type_implements_trait(name, derive_trait) }) .unwrap_or(CanDerive::No) }) } /// Get a reference to the set of items we should generate. pub fn codegen_items(&self) -> &ItemSet { assert!(self.in_codegen_phase()); 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() { 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; } let name = item.path_for_allowlisting(self)[1..].join("::"); debug!("allowlisted_items: testing {:?}", name); match *item.kind() { ItemKind::Module(..) => true, ItemKind::Function(_) => { self.options().allowlisted_functions.matches(&name) } ItemKind::Var(_) => { self.options().allowlisted_vars.matches(&name) } ItemKind::Type(ref ty) => { if self.options().allowlisted_types.matches(&name) { return true; } // Auto-allowlist types that don't need code // generation if not allowlisting recursively, to // make the #[derive] analysis not be lame. if !self.options().allowlist_recursively { match *ty.kind() { TypeKind::Void | TypeKind::NullPtr | TypeKind::Int(..) | TypeKind::Float(..) | TypeKind::Complex(..) | TypeKind::Array(..) | TypeKind::Vector(..) | TypeKind::Pointer(..) | TypeKind::Reference(..) | TypeKind::Function(..) | TypeKind::ResolvedTypeRef(..) | TypeKind::Opaque | TypeKind::TypeParam => return true, _ => {} }; } // Unnamed top-level enums are special and we // allowlist them via the `allowlisted_vars` filter, // since they're effectively top-level constants, // and there's no way for them to be referenced // consistently. let parent = self.resolve_item(item.parent_id()); if !parent.is_module() { return false; } let enum_ = match *ty.kind() { TypeKind::Enum(ref e) => e, _ => return false, }; if ty.name().is_some() { return false; } let mut prefix_path = parent.path_for_allowlisting(self).clone(); enum_.variants().iter().any(|variant| { prefix_path.push( variant.name_for_allowlisting().into(), ); let name = prefix_path[1..].join("::"); prefix_path.pop().unwrap(); self.options().allowlisted_vars.matches(&name) }) } } }) .map(|(id, _)| id) .collect::>(); // 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.clone(), 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() { warn!("unused option: --allowlist-function {}", item); } for item in self.options().allowlisted_vars.unmatched_items() { warn!("unused option: --allowlist-var {}", item); } for item in self.options().allowlisted_types.unmatched_items() { warn!("unused option: --allowlist-type {}", item); } } /// Convenient method for getting the prefix to use for most traits in /// codegen depending on the `use_core` option. pub fn trait_prefix(&self) -> Ident { if self.options().use_core { self.rust_ident_raw("core") } else { self.rust_ident_raw("std") } } /// Call if a bindgen complex is generated pub fn generated_bindgen_complex(&self) { self.generated_bindgen_complex.set(true) } /// Whether we need to generate the bindgen complex type pub fn need_bindgen_complex_type(&self) -> bool { self.generated_bindgen_complex.get() } /// Compute whether we can derive debug. fn compute_cannot_derive_debug(&mut self) { let _t = self.timer("compute_cannot_derive_debug"); assert!(self.cannot_derive_debug.is_none()); if self.options.derive_debug { self.cannot_derive_debug = Some(as_cannot_derive_set(analyze::(( self, DeriveTrait::Debug, )))); } } /// Look up whether the item with `id` can /// derive debug or not. pub 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 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 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 fn lookup_can_derive_partialeq_or_partialord>( &self, id: Id, ) -> CanDerive { let id = id.into(); assert!( self.in_codegen_phase(), "We only compute can_derive_partialeq_or_partialord when we enter codegen" ); // Look up the computed value for whether the item with `id` can // derive partialeq or not. self.cannot_derive_partialeq_or_partialord .as_ref() .unwrap() .get(&id) .cloned() .unwrap_or(CanDerive::Yes) } /// Look up whether the item with `id` can derive `Copy` or not. pub fn lookup_can_derive_copy>(&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 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 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 fn no_partialeq_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); self.options().no_partialeq_types.matches(&name) } /// Check if `--no-copy` flag is enabled for this item. pub fn no_copy_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); self.options().no_copy_types.matches(&name) } /// Check if `--no-debug` flag is enabled for this item. pub fn no_debug_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); self.options().no_debug_types.matches(&name) } /// Check if `--no-default` flag is enabled for this item. pub fn no_default_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); self.options().no_default_types.matches(&name) } /// Check if `--no-hash` flag is enabled for this item. pub fn no_hash_by_name(&self, item: &Item) -> bool { let name = item.path_for_allowlisting(self)[1..].join("::"); self.options().no_hash_types.matches(&name) } } /// A builder struct for configuring item resolution options. #[derive(Debug, Copy, Clone)] pub struct ItemResolver { id: ItemId, through_type_refs: bool, through_type_aliases: bool, } impl ItemId { /// Create an `ItemResolver` from this item id. pub fn into_resolver(self) -> ItemResolver { self.into() } } impl 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 fn new>(id: Id) -> ItemResolver { let id = id.into(); ItemResolver { id: id, through_type_refs: false, through_type_aliases: false, } } /// Keep resolving through `Type::TypeRef` items. pub fn through_type_refs(mut self) -> ItemResolver { self.through_type_refs = true; self } /// Keep resolving through `Type::Alias` items. pub fn through_type_aliases(mut self) -> ItemResolver { self.through_type_aliases = true; self } /// Finish configuring and perform the actual item resolution. pub fn resolve(self, ctx: &BindgenContext) -> &Item { assert!(ctx.collected_typerefs()); let mut id = self.id; loop { let item = ctx.resolve_item(id); let ty_kind = item.as_type().map(|t| t.kind()); match ty_kind { Some(&TypeKind::ResolvedTypeRef(next_id)) if self.through_type_refs => { id = next_id.into(); } // We intentionally ignore template aliases here, as they are // more complicated, and don't represent a simple renaming of // some type. Some(&TypeKind::Alias(next_id)) if self.through_type_aliases => { id = next_id.into(); } _ => return item, } } } } /// A type that we are in the middle of parsing. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct PartialType { decl: Cursor, // Just an ItemId, and not a TypeId, because we haven't finished this type // yet, so there's still time for things to go wrong. id: ItemId, } impl PartialType { /// Construct a new `PartialType`. pub fn new(decl: Cursor, id: ItemId) -> PartialType { // assert!(decl == decl.canonical()); PartialType { decl: decl, id: id } } /// The cursor pointing to this partial type's declaration location. pub fn decl(&self) -> &Cursor { &self.decl } /// The item ID allocated for this type. This is *NOT* a key for an entry in /// the context's item set yet! pub fn id(&self) -> ItemId { self.id } } impl TemplateParameters for PartialType { fn self_template_params(&self, _ctx: &BindgenContext) -> Vec { // 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, } } } bindgen-0.59.1/src/ir/derive.rs000064400000000000000000000077650000000000000143470ustar 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 trait CanDeriveDebug { /// Return `true` if `Debug` can be derived for this thing, `false` /// otherwise. fn can_derive_debug(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can derive `Copy` /// for a given thing. pub trait CanDeriveCopy { /// Return `true` if `Copy` can be derived for this thing, `false` /// otherwise. fn can_derive_copy(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can derive /// `Default` for a given thing. pub trait CanDeriveDefault { /// Return `true` if `Default` can be derived for this thing, `false` /// otherwise. fn can_derive_default(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can derive `Hash` /// for a given thing. pub trait CanDeriveHash { /// Return `true` if `Hash` can be derived for this thing, `false` /// otherwise. fn can_derive_hash(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can derive /// `PartialEq` for a given thing. pub trait CanDerivePartialEq { /// Return `true` if `PartialEq` can be derived for this thing, `false` /// otherwise. fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can derive /// `PartialOrd` for a given thing. pub trait CanDerivePartialOrd { /// Return `true` if `PartialOrd` can be derived for this thing, `false` /// otherwise. fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can derive `Eq` /// for a given thing. pub trait CanDeriveEq { /// Return `true` if `Eq` can be derived for this thing, `false` otherwise. fn can_derive_eq(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can derive `Ord` /// for a given thing. pub trait CanDeriveOrd { /// Return `true` if `Ord` can be derived for this thing, `false` otherwise. fn can_derive_ord(&self, ctx: &BindgenContext) -> bool; } /// Whether it is possible or not to automatically derive trait for an item. /// /// ```ignore /// No /// ^ /// | /// Manually /// ^ /// | /// Yes /// ``` /// /// Initially we assume that we can derive trait for all types and then /// update our understanding as we learn more about each type. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum CanDerive { /// Yes, we can derive automatically. Yes, /// The only thing that stops us from automatically deriving is that /// array with more than maximum number of elements is used. /// /// This means we probably can "manually" implement such trait. Manually, /// No, we cannot. No, } impl Default for CanDerive { fn default() -> CanDerive { CanDerive::Yes } } impl CanDerive { /// Take the least upper bound of `self` and `rhs`. pub fn join(self, rhs: Self) -> Self { cmp::max(self, rhs) } } impl ops::BitOr for CanDerive { type Output = Self; fn bitor(self, rhs: Self) -> Self::Output { self.join(rhs) } } impl ops::BitOrAssign for CanDerive { fn bitor_assign(&mut self, rhs: Self) { *self = self.join(rhs) } } bindgen-0.59.1/src/ir/dot.rs000064400000000000000000000045760000000000000136540ustar 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 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: io::Write; } /// Write a graphviz dot file containing our IR. pub 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={:?}, color={}];", id.as_usize(), sub_id.as_usize(), edge_kind, if is_allowlisted { "black" } else { "gray" } ) { Ok(_) => {} Err(e) => err = Some(Err(e)), } }, &(), ); if let Some(err) = err { return err; } if let Some(module) = item.as_module() { for child in module.children() { writeln!( &mut dot_file, "{} -> {} [style=dotted, color=gray]", item.id().as_usize(), child.as_usize() )?; } } } writeln!(&mut dot_file, "}}")?; Ok(()) } bindgen-0.59.1/src/ir/enum_ty.rs000064400000000000000000000227010000000000000145340ustar 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::{ClangItemParser, ParseError}; use crate::regex_set::RegexSet; /// An enum representing custom handling that can be given to a variant. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum EnumVariantCustomBehavior { /// This variant will be a module containing constants. ModuleConstify, /// This variant will be constified, that is, forced to generate a constant. Constify, /// This variant will be hidden entirely from the resulting enum. Hide, } /// A C/C++ enumeration. #[derive(Debug)] pub struct Enum { /// The representation used for this enum; it should be an `IntKind` type or /// an alias to one. /// /// It's `None` if the enum is a forward declaration and isn't defined /// anywhere else, see `tests/headers/func_ptr_in_struct.h`. repr: Option, /// The different variants, with explicit values. variants: Vec, } impl Enum { /// Construct a new `Enum` with the given representation and variants. pub fn new(repr: Option, variants: Vec) -> Self { Enum { repr, variants } } /// Get this enumeration's representation. pub fn repr(&self) -> Option { self.repr } /// Get this enumeration's variants. pub fn variants(&self) -> &[EnumVariant] { &self.variants } /// Construct an enumeration from the given Clang type. pub fn from_ty( ty: &clang::Type, ctx: &mut BindgenContext, ) -> Result { use clang_sys::*; debug!("Enum::from_ty {:?}", ty); if ty.kind() != CXType_Enum { return Err(ParseError::Continue); } let declaration = ty.declaration().canonical(); let repr = declaration .enum_type() .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok()); let mut variants = vec![]; let variant_ty = repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx)); let is_bool = variant_ty.map_or(false, Type::is_bool); // Assume signedness since the default type by the C standard is an int. let is_signed = variant_ty.map_or(true, |ty| match *ty.kind() { TypeKind::Int(ref int_kind) => int_kind.is_signed(), ref other => { panic!("Since when enums can be non-integers? {:?}", other) } }); let type_name = ty.spelling(); let type_name = if type_name.is_empty() { None } else { Some(type_name) }; let type_name = type_name.as_ref().map(String::as_str); let definition = declaration.definition().unwrap_or(declaration); definition.visit(|cursor| { if cursor.kind() == CXCursor_EnumConstantDecl { let value = if is_bool { cursor.enum_val_boolean().map(EnumVariantValue::Boolean) } else if is_signed { cursor.enum_val_signed().map(EnumVariantValue::Signed) } else { cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned) }; if let Some(val) = value { let name = cursor.spelling(); let annotations = Annotations::new(&cursor); let custom_behavior = ctx .parse_callbacks() .and_then(|callbacks| { callbacks .enum_variant_behavior(type_name, &name, val) }) .or_else(|| { let annotations = annotations.as_ref()?; if annotations.hide() { Some(EnumVariantCustomBehavior::Hide) } else if annotations.constify_enum_variant() { Some(EnumVariantCustomBehavior::Constify) } else { None } }); let new_name = ctx .parse_callbacks() .and_then(|callbacks| { callbacks.enum_variant_name(type_name, &name, val) }) .or_else(|| { annotations .as_ref()? .use_instead_of()? .last() .cloned() }) .unwrap_or_else(|| name.clone()); let comment = cursor.raw_comment(); variants.push(EnumVariant::new( new_name, name, comment, val, custom_behavior, )); } } CXChildVisit_Continue }); Ok(Enum::new(repr, variants)) } fn is_matching_enum( &self, ctx: &BindgenContext, enums: &RegexSet, item: &Item, ) -> bool { let path = item.path_for_allowlisting(ctx); let enum_ty = item.expect_type(); if enums.matches(&path[1..].join("::")) { return true; } // Test the variants if the enum is anonymous. if enum_ty.name().is_some() { return false; } self.variants().iter().any(|v| enums.matches(&v.name())) } /// Returns the final representation of the enum. pub fn computed_enum_variation( &self, ctx: &BindgenContext, item: &Item, ) -> EnumVariation { // ModuleConsts has higher precedence before Rust in order to avoid // problems with overlapping match patterns. if self.is_matching_enum( ctx, &ctx.options().constified_enum_modules, item, ) { EnumVariation::ModuleConsts } else if self.is_matching_enum( ctx, &ctx.options().bitfield_enums, item, ) { EnumVariation::NewType { is_bitfield: true } } else if self.is_matching_enum(ctx, &ctx.options().newtype_enums, item) { EnumVariation::NewType { is_bitfield: false } } else if self.is_matching_enum( ctx, &ctx.options().rustified_enums, item, ) { EnumVariation::Rust { non_exhaustive: false, } } else if self.is_matching_enum( ctx, &ctx.options().rustified_non_exhaustive_enums, item, ) { EnumVariation::Rust { non_exhaustive: true, } } else if self.is_matching_enum( ctx, &ctx.options().constified_enums, item, ) { EnumVariation::Consts } else { ctx.options().default_enum_style } } } /// A single enum variant, to be contained only in an enum. #[derive(Debug)] pub struct EnumVariant { /// The name of the variant. name: String, /// The original name of the variant (without user mangling) name_for_allowlisting: String, /// An optional doc comment. comment: Option, /// 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 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 fn name(&self) -> &str { &self.name } /// Get this variant's name. pub fn name_for_allowlisting(&self) -> &str { &self.name_for_allowlisting } /// Get this variant's value. pub fn val(&self) -> EnumVariantValue { self.val } /// Get this variant's documentation. pub fn comment(&self) -> Option<&str> { self.comment.as_ref().map(|s| &**s) } /// Returns whether this variant should be enforced to be a constant by code /// generation. pub fn force_constification(&self) -> bool { self.custom_behavior .map_or(false, |b| b == EnumVariantCustomBehavior::Constify) } /// Returns whether the current variant should be hidden completely from the /// resulting rust enum. pub fn hidden(&self) -> bool { self.custom_behavior .map_or(false, |b| b == EnumVariantCustomBehavior::Hide) } } bindgen-0.59.1/src/ir/function.rs000064400000000000000000000514200000000000000147010ustar 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::clang; use crate::parse::{ ClangItemParser, ClangSubItemParser, ParseError, ParseResult, }; use clang_sys::{self, CXCallingConv}; use proc_macro2; use quote; use quote::TokenStreamExt; use std::io; const RUST_DERIVE_FUNPTR_LIMIT: usize = 12; /// What kind of a function are we looking at? #[derive(Debug, Copy, Clone, PartialEq)] pub enum FunctionKind { /// A plain, free function. Function, /// A method of some kind. Method(MethodKind), } impl FunctionKind { /// Given a clang cursor, return the kind of function it represents, or /// `None` otherwise. pub fn from_cursor(cursor: &clang::Cursor) -> Option { // FIXME(emilio): Deduplicate logic with `ir::comp`. Some(match cursor.kind() { clang_sys::CXCursor_FunctionDecl => FunctionKind::Function, clang_sys::CXCursor_Constructor => { FunctionKind::Method(MethodKind::Constructor) } clang_sys::CXCursor_Destructor => { FunctionKind::Method(if cursor.method_is_virtual() { MethodKind::VirtualDestructor { pure_virtual: cursor.method_is_pure_virtual(), } } else { MethodKind::Destructor }) } clang_sys::CXCursor_CXXMethod => { if cursor.method_is_virtual() { FunctionKind::Method(MethodKind::Virtual { pure_virtual: cursor.method_is_pure_virtual(), }) } else if cursor.method_is_static() { FunctionKind::Method(MethodKind::Static) } else { FunctionKind::Method(MethodKind::Normal) } } _ => return None, }) } } /// The style of linkage #[derive(Debug, Clone, Copy)] pub enum Linkage { /// Externally visible and can be linked against External, /// Not exposed externally. 'static inline' functions will have this kind of linkage Internal, } /// A function declaration, with a signature, arguments, and argument names. /// /// The argument names vector must be the same length as the ones in the /// signature. #[derive(Debug)] pub struct Function { /// The name of this function. name: String, /// The mangled name, that is, the symbol. mangled_name: Option, /// The id pointing to the current function signature. signature: TypeId, /// The doc comment on the function, if any. comment: Option, /// The kind of function this is. kind: FunctionKind, /// The linkage of the function. linkage: Linkage, } impl Function { /// Construct a new function. pub fn new( name: String, mangled_name: Option, signature: TypeId, comment: Option, kind: FunctionKind, linkage: Linkage, ) -> Self { Function { name, mangled_name, signature, comment, kind, linkage, } } /// Get this function's name. pub fn name(&self) -> &str { &self.name } /// Get this function's name. pub fn mangled_name(&self) -> Option<&str> { self.mangled_name.as_ref().map(|n| &**n) } /// Get this function's signature type. pub fn signature(&self) -> TypeId { self.signature } /// Get this function's kind. pub fn kind(&self) -> FunctionKind { self.kind } /// Get this function's linkage. pub fn linkage(&self) -> Linkage { self.linkage } } impl DotAttributes for Function { fn dot_attributes( &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(()) } } /// An ABI extracted from a clang cursor. #[derive(Debug, Copy, Clone)] pub enum Abi { /// The default C ABI. C, /// The "stdcall" ABI. Stdcall, /// The "fastcall" ABI. Fastcall, /// The "thiscall" ABI. ThisCall, /// The "aapcs" ABI. Aapcs, /// The "win64" ABI. Win64, /// An unknown or invalid ABI. Unknown(CXCallingConv), } impl Abi { /// Returns whether this Abi is known or not. fn is_unknown(&self) -> bool { match *self { Abi::Unknown(..) => true, _ => false, } } } impl quote::ToTokens for Abi { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { tokens.append_all(match *self { Abi::C => quote! { "C" }, Abi::Stdcall => quote! { "stdcall" }, Abi::Fastcall => quote! { "fastcall" }, Abi::ThisCall => quote! { "thiscall" }, Abi::Aapcs => quote! { "aapcs" }, Abi::Win64 => quote! { "win64" }, Abi::Unknown(cc) => panic!( "Cannot turn unknown calling convention to tokens: {:?}", cc ), }); } } /// A function signature. #[derive(Debug)] pub struct FunctionSig { /// The return type of the function. return_type: TypeId, /// The type of the arguments, optionally with the name of the argument when /// declared. argument_types: Vec<(Option, TypeId)>, /// Whether this function is variadic. is_variadic: bool, /// Whether this function's return value must be used. must_use: bool, /// The ABI of this function. abi: Abi, } fn get_abi(cc: CXCallingConv) -> Abi { use clang_sys::*; match cc { CXCallingConv_Default => Abi::C, CXCallingConv_C => Abi::C, CXCallingConv_X86StdCall => Abi::Stdcall, CXCallingConv_X86FastCall => Abi::Fastcall, CXCallingConv_X86ThisCall => Abi::ThisCall, CXCallingConv_AAPCS => Abi::Aapcs, CXCallingConv_X86_64Win64 => Abi::Win64, other => Abi::Unknown(other), } } /// Get the mangled name for the cursor's referent. pub fn cursor_mangling( ctx: &BindgenContext, cursor: &clang::Cursor, ) -> Option { if !ctx.options().enable_mangling { return None; } // We early return here because libclang may crash in some case // if we pass in a variable inside a partial specialized template. // See rust-lang/rust-bindgen#67, and rust-lang/rust-bindgen#462. if cursor.is_in_non_fully_specialized_template() { return None; } let is_destructor = cursor.kind() == clang_sys::CXCursor_Destructor; if let Ok(mut manglings) = cursor.cxx_manglings() { while let Some(m) = manglings.pop() { // Only generate the destructor group 1, see below. if is_destructor && !m.ends_with("D1Ev") { continue; } return Some(m); } } let mut mangling = cursor.mangling(); if mangling.is_empty() { return None; } if is_destructor { // With old (3.8-) libclang versions, and the Itanium ABI, clang returns // the "destructor group 0" symbol, which means that it'll try to free // memory, which definitely isn't what we want. // // Explicitly force the destructor group 1 symbol. // // See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special // for the reference, and http://stackoverflow.com/a/6614369/1091587 for // a more friendly explanation. // // We don't need to do this for constructors since clang seems to always // have returned the C1 constructor. // // FIXME(emilio): Can a legit symbol in other ABIs end with this string? // I don't think so, but if it can this would become a linker error // anyway, not an invalid free at runtime. // // TODO(emilio, #611): Use cpp_demangle if this becomes nastier with // time. if mangling.ends_with("D0Ev") { let new_len = mangling.len() - 4; mangling.truncate(new_len); mangling.push_str("D1Ev"); } } Some(mangling) } fn args_from_ty_and_cursor( ty: &clang::Type, cursor: &clang::Cursor, ctx: &mut BindgenContext, ) -> Vec<(Option, 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(cursor.cur_type()); (name, Item::from_ty_or_ref(ty, cursor, None, ctx)) }) .collect() } impl FunctionSig { /// Construct a new function signature. pub fn new( return_type: TypeId, argument_types: Vec<(Option, TypeId)>, is_variadic: bool, must_use: bool, abi: Abi, ) -> Self { FunctionSig { return_type, argument_types, is_variadic, must_use, abi: abi, } } /// Construct a new function signature from the given Clang type. pub fn from_ty( ty: &clang::Type, cursor: &clang::Cursor, ctx: &mut BindgenContext, ) -> Result { 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 = ctx.options().enable_function_attribute_detection && cursor.has_warn_unused_result_attr(); let is_method = kind == CXCursor_CXXMethod; let is_constructor = kind == CXCursor_Constructor; let is_destructor = kind == CXCursor_Destructor; if (is_constructor || is_destructor || is_method) && cursor.lexical_parent() != cursor.semantic_parent() { // Only parse constructors once. return Err(ParseError::Continue); } if is_method || is_constructor || is_destructor { let is_const = is_method && cursor.method_is_const(); let is_virtual = is_method && cursor.method_is_virtual(); let is_static = is_method && cursor.method_is_static(); if !is_static && !is_virtual { let parent = cursor.semantic_parent(); let class = Item::parse(parent, None, ctx) .expect("Expected to parse the class"); // The `class` most likely is not finished parsing yet, so use // the unchecked variant. let class = class.as_type_id_unchecked(); let class = if is_const { let const_class_id = ctx.next_item_id(); ctx.build_const_wrapper( const_class_id, class, None, &parent.cur_type(), ) } else { class }; let ptr = Item::builtin_type(TypeKind::Pointer(class), false, ctx); args.insert(0, (Some("this".into()), ptr)); } else if is_virtual { let void = Item::builtin_type(TypeKind::Void, false, ctx); let ptr = Item::builtin_type(TypeKind::Pointer(void), false, ctx); args.insert(0, (Some("this".into()), ptr)); } } let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl || kind == CXCursor_ObjCClassMethodDecl { ty.ret_type() .or_else(|| cursor.ret_type()) .ok_or(ParseError::Continue)? } else { ty.ret_type().ok_or(ParseError::Continue)? }; let ret = if is_constructor && ctx.is_target_wasm32() { // Constructors in Clang wasm32 target return a pointer to the object // being constructed. let void = Item::builtin_type(TypeKind::Void, false, ctx); Item::builtin_type(TypeKind::Pointer(void), false, ctx) } else { Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx) }; // Clang plays with us at "find the calling convention", see #549 and // co. This seems to be a better fix than that commit. let mut call_conv = ty.call_conv(); if let Some(ty) = cursor.cur_type().canonical_type().pointee_type() { let cursor_call_conv = ty.call_conv(); if cursor_call_conv != CXCallingConv_Invalid { call_conv = cursor_call_conv; } } let abi = get_abi(call_conv); if abi.is_unknown() { warn!("Unknown calling convention: {:?}", call_conv); } Ok(Self::new(ret.into(), args, ty.is_variadic(), must_use, abi)) } /// Get this function signature's return type. pub fn return_type(&self) -> TypeId { self.return_type } /// Get this function signature's argument (name, type) pairs. pub fn argument_types(&self) -> &[(Option, TypeId)] { &self.argument_types } /// Get this function signature's ABI. pub fn abi(&self) -> Abi { self.abi } /// Is this function signature variadic? pub fn is_variadic(&self) -> bool { // Clang reports some functions as variadic when they *might* be // variadic. We do the argument check because rust doesn't codegen well // variadic functions without an initial argument. self.is_variadic && !self.argument_types.is_empty() } /// Must this function's return value be used? pub fn must_use(&self) -> bool { self.must_use } /// Are function pointers with this signature able to derive Rust traits? /// Rust only supports deriving traits for function pointers with a limited /// number of parameters and a couple ABIs. /// /// For more details, see: /// /// * https://github.com/rust-lang/rust-bindgen/issues/547, /// * https://github.com/rust-lang/rust/issues/38848, /// * and https://github.com/rust-lang/rust/issues/40158 pub fn function_pointers_can_derive(&self) -> bool { if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT { return false; } match self.abi { Abi::C | Abi::Unknown(..) => true, _ => false, } } } 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); } if cursor.is_inlined_function() { if !context.options().generate_inline_functions { return Err(ParseError::Continue); } if cursor.is_deleted_function() { return Err(ParseError::Continue); } } let linkage = cursor.linkage(); let linkage = match linkage { CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External, CXLinkage_Internal => Linkage::Internal, _ => return Err(ParseError::Continue), }; // Grab the signature using Item::from_ty. let sig = Item::from_ty(&cursor.cur_type(), cursor, None, context)?; let mut name = cursor.spelling(); assert!(!name.is_empty(), "Empty function name?"); if cursor.kind() == CXCursor_Destructor { // Remove the leading `~`. The alternative to this is special-casing // code-generation for destructor functions, which seems less than // ideal. if name.starts_with('~') { name.remove(0); } // Add a suffix to avoid colliding with constructors. This would be // technically fine (since we handle duplicated functions/methods), // but seems easy enough to handle it here. name.push_str("_destructor"); } let mangled_name = cursor_mangling(context, &cursor); let comment = cursor.raw_comment(); let function = Self::new(name, mangled_name, sig, comment, kind, linkage); Ok(ParseResult::New(function, Some(cursor))) } } impl Trace for FunctionSig { type Extra = (); fn trace(&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.59.1/src/ir/int.rs000064400000000000000000000055310000000000000136500ustar 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, /// An `wchar_t`. WChar, /// A platform-dependent `char` type, with the signedness support. Char { /// Whether the char is signed for the target platform. is_signed: bool, }, /// A `short`. Short, /// An `unsigned short`. UShort, /// An `int`. Int, /// An `unsigned int`. UInt, /// A `long`. Long, /// An `unsigned long`. ULong, /// A `long long`. LongLong, /// An `unsigned long long`. ULongLong, /// A 8-bit signed integer. I8, /// A 8-bit unsigned integer. U8, /// A 16-bit signed integer. I16, /// Either a `char16_t` or a `wchar_t`. U16, /// A 32-bit signed integer. I32, /// A 32-bit unsigned integer. U32, /// A 64-bit signed integer. I64, /// A 64-bit unsigned integer. U64, /// An `int128_t` I128, /// A `uint128_t`. U128, /// A custom integer type, used to allow custom macro types depending on /// range. Custom { /// The name of the type, which would be used without modification. name: &'static str, /// Whether the type is signed or not. is_signed: bool, }, } impl IntKind { /// Is this integral type signed? pub fn is_signed(&self) -> bool { use self::IntKind::*; match *self { // TODO(emilio): wchar_t can in theory be signed, but we have no way // to know whether it is or not right now (unlike char, there's no // WChar_S / WChar_U). Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 | WChar | U32 | U64 | U128 => false, SChar | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 | I128 => true, Char { is_signed } => is_signed, Custom { is_signed, .. } => is_signed, } } /// If this type has a known size, return it (in bytes). This is to /// alleviate libclang sometimes not giving us a layout (like in the case /// when an enum is defined inside a class with template parameters). pub fn known_size(&self) -> Option { use self::IntKind::*; Some(match *self { Bool | UChar | SChar | U8 | I8 | Char { .. } => 1, U16 | I16 => 2, U32 | I32 => 4, U64 | I64 => 8, I128 | U128 => 16, _ => return None, }) } /// Whether this type's signedness matches the value. pub fn signedness_matches(&self, val: i64) -> bool { val >= 0 || self.is_signed() } } bindgen-0.59.1/src/ir/item.rs000064400000000000000000001770120000000000000140200ustar 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::comment; use super::comp::{CompKind, MethodKind}; use super::context::{BindgenContext, ItemId, PartialType, TypeId}; use super::derive::{ CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq, CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd, }; use super::dot::DotAttributes; use super::function::{Function, FunctionKind}; use super::item_kind::ItemKind; use super::layout::Opaque; use super::module::Module; use super::template::{AsTemplateParam, TemplateParameters}; use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::{Type, TypeKind}; use crate::clang; use crate::parse::{ ClangItemParser, ClangSubItemParser, ParseError, ParseResult, }; use clang_sys; use lazycell::LazyCell; use regex; use std::cell::Cell; use std::collections::BTreeSet; use std::fmt::Write; use std::io; use std::iter; /// A trait to get the canonical name from an item. /// /// This is the trait that will eventually isolate all the logic related to name /// mangling and that kind of stuff. /// /// This assumes no nested paths, at some point I'll have to make it a more /// complex thing. /// /// This name is required to be safe for Rust, that is, is not expected to /// return any rust keyword from here. pub trait ItemCanonicalName { /// Get the canonical name for this item. fn canonical_name(&self, ctx: &BindgenContext) -> String; } /// The same, but specifies the path that needs to be followed to reach an item. /// /// To contrast with canonical_name, here's an example: /// /// ```c++ /// namespace foo { /// const BAR = 3; /// } /// ``` /// /// For bar, the canonical path is `vec!["foo", "BAR"]`, while the canonical /// name is just `"BAR"`. pub trait ItemCanonicalPath { /// Get the namespace-aware canonical path for this item. This means that if /// namespaces are disabled, you'll get a single item, and otherwise you get /// the whole path. fn namespace_aware_canonical_path( &self, ctx: &BindgenContext, ) -> Vec; /// 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 trait IsOpaque { /// Extra context the IR thing needs to determine if it is opaque or not. type Extra; /// Returns `true` if the thing is opaque, and `false` otherwise. /// /// May only be called when `ctx` is in the codegen phase. fn is_opaque(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool; } /// A trait for determining if some IR thing has type parameter in array or not. pub trait HasTypeParamInArray { /// Returns `true` if the thing has Array, and `false` otherwise. fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool; } /// A trait for determining if some IR thing has float or not. pub trait HasFloat { /// Returns `true` if the thing has float, and `false` otherwise. fn has_float(&self, ctx: &BindgenContext) -> bool; } /// A trait for iterating over an item and its parents and up its ancestor chain /// up to (but not including) the implicit root module. pub trait ItemAncestors { /// Get an iterable over this item's ancestors. fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a>; } #[cfg(testing_only_extra_assertions)] type DebugOnlyItemSet = ItemSet; #[cfg(not(testing_only_extra_assertions))] struct DebugOnlyItemSet; #[cfg(not(testing_only_extra_assertions))] impl DebugOnlyItemSet { fn new() -> Self { DebugOnlyItemSet } fn contains(&self, _id: &ItemId) -> bool { false } fn insert(&mut self, _id: ItemId) {} } /// An iterator over an item and its ancestors. pub struct ItemAncestorsIter<'a> { item: ItemId, ctx: &'a BindgenContext, seen: DebugOnlyItemSet, } impl<'a> ItemAncestorsIter<'a> { fn new>(ctx: &'a BindgenContext, id: Id) -> Self { ItemAncestorsIter { item: id.into(), ctx, seen: DebugOnlyItemSet::new(), } } } impl<'a> Iterator for ItemAncestorsIter<'a> { type Item = ItemId; fn next(&mut self) -> Option { 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 struct Item { /// This item's id. id: ItemId, /// The item's local id, unique only amongst its siblings. Only used for /// anonymous items. /// /// Lazily initialized in local_id(). /// /// Note that only structs, unions, and enums get a local type id. In any /// case this is an implementation detail. local_id: LazyCell, /// 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: LazyCell, /// The path to use for allowlisting and other name-based checks, as /// returned by `path_for_allowlisting`, lazily constructed. path_for_allowlisting: LazyCell>, /// 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, } impl AsRef for Item { fn as_ref(&self) -> &ItemId { &self.id } } impl Item { /// Construct a new `Item`. pub fn new( id: ItemId, comment: Option, annotations: Option, parent_id: ItemId, kind: ItemKind, ) -> Self { debug_assert!(id != parent_id || kind.is_module()); Item { id: id, local_id: LazyCell::new(), next_child_local_id: Cell::new(1), canonical_name: LazyCell::new(), path_for_allowlisting: LazyCell::new(), parent_id: parent_id, comment: comment, annotations: annotations.unwrap_or_default(), kind: kind, } } /// Construct a new opaque item type. pub fn new_opaque_type( with_id: ItemId, ty: &clang::Type, ctx: &mut BindgenContext, ) -> TypeId { 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), None, None); with_id.as_type_id_unchecked() } /// Get this `Item`'s identifier. pub fn id(&self) -> ItemId { self.id } /// Get this `Item`'s parent's identifier. /// /// For the root module, the parent's ID is its own ID. pub fn parent_id(&self) -> ItemId { self.parent_id } /// Set this item's parent id. /// /// This is only used so replacements get generated in the proper module. pub fn set_parent_for_replacement>(&mut self, id: Id) { self.parent_id = id.into(); } /// Returns the depth this item is indented to. /// /// FIXME(emilio): This may need fixes for the enums within modules stuff. pub fn codegen_depth(&self, ctx: &BindgenContext) -> usize { if !ctx.options().enable_cxx_namespaces { return 0; } self.ancestors(ctx) .filter(|id| { ctx.resolve_item(*id).as_module().map_or(false, |module| { !module.is_inline() || ctx.options().conservative_inline_namespaces }) }) .count() + 1 } /// Get this `Item`'s comment, if it has any, already preprocessed and with /// the right indentation. pub fn comment(&self, ctx: &BindgenContext) -> Option { if !ctx.options().generate_comments { return None; } self.comment.as_ref().map(|comment| { comment::preprocess(comment, self.codegen_depth(ctx)) }) } /// What kind of item is this? pub fn kind(&self) -> &ItemKind { &self.kind } /// Get a mutable reference to this item's kind. pub fn kind_mut(&mut self) -> &mut ItemKind { &mut self.kind } /// Get an identifier that differentiates this item from its siblings. /// /// This should stay relatively stable in the face of code motion outside or /// below this item's lexical scope, meaning that this can be useful for /// generating relatively stable identifiers within a scope. pub fn local_id(&self, ctx: &BindgenContext) -> usize { *self.local_id.borrow_with(|| { let parent = ctx.resolve_item(self.parent_id); parent.next_child_local_id() }) } /// Get an identifier that differentiates a child of this item of other /// related items. /// /// This is currently used for anonymous items, and template instantiation /// tests, in both cases in order to reduce noise when system headers are at /// place. pub fn next_child_local_id(&self) -> usize { let local_id = self.next_child_local_id.get(); self.next_child_local_id.set(local_id + 1); local_id } /// Returns whether this item is a top-level item, from the point of view of /// bindgen. /// /// This point of view changes depending on whether namespaces are enabled /// or not. That way, in the following example: /// /// ```c++ /// namespace foo { /// static int var; /// } /// ``` /// /// `var` would be a toplevel item if namespaces are disabled, but won't if /// they aren't. /// /// This function is used to determine when the codegen phase should call /// `codegen` on an item, since any item that is not top-level will be /// generated by its parent. pub fn is_toplevel(&self, ctx: &BindgenContext) -> bool { // FIXME: Workaround for some types falling behind when parsing weird // stl classes, for example. if ctx.options().enable_cxx_namespaces && self.kind().is_module() && self.id() != ctx.root_module() { return false; } let mut parent = self.parent_id; loop { let parent_item = match ctx.resolve_item_fallible(parent) { Some(item) => item, None => return false, }; if parent_item.id() == ctx.root_module() { return true; } else if ctx.options().enable_cxx_namespaces || !parent_item.kind().is_module() { return false; } parent = parent_item.parent_id(); } } /// Get a reference to this item's underlying `Type`. Panic if this is some /// other kind of item. pub fn expect_type(&self) -> &Type { self.kind().expect_type() } /// Get a reference to this item's underlying `Type`, or `None` if this is /// some other kind of item. pub fn as_type(&self) -> Option<&Type> { self.kind().as_type() } /// Get a reference to this item's underlying `Function`. Panic if this is /// some other kind of item. pub fn expect_function(&self) -> &Function { self.kind().expect_function() } /// Is this item a module? pub fn is_module(&self) -> bool { match self.kind { ItemKind::Module(..) => true, _ => false, } } /// Get this item's annotations. pub fn annotations(&self) -> &Annotations { &self.annotations } /// Whether this item should be blocklisted. /// /// This may be due to either annotations or to other kind of configuration. pub fn is_blocklisted(&self, ctx: &BindgenContext) -> bool { debug_assert!( ctx.in_codegen_phase(), "You're not supposed to call this yet" ); if self.annotations.hide() { return true; } let path = self.path_for_allowlisting(ctx); let name = path[1..].join("::"); ctx.options().blocklisted_items.matches(&name) || match self.kind { ItemKind::Type(..) => { ctx.options().blocklisted_types.matches(&name) || ctx.is_replaced_type(&path, self.id) } ItemKind::Function(..) => { ctx.options().blocklisted_functions.matches(&name) } // TODO: Add constant / namespace blocklisting? ItemKind::Var(..) | ItemKind::Module(..) => false, } } /// Is this a reference to another type? pub fn is_type_ref(&self) -> bool { self.as_type().map_or(false, |ty| ty.is_type_ref()) } /// Is this item a var type? pub fn is_var(&self) -> bool { match *self.kind() { ItemKind::Var(..) => true, _ => false, } } /// Take out item NameOptions pub fn name<'a>(&'a self, ctx: &'a BindgenContext) -> NameOptions<'a> { NameOptions::new(self, ctx) } /// Get the target item id for name generation. fn name_target(&self, ctx: &BindgenContext) -> ItemId { let mut targets_seen = DebugOnlyItemSet::new(); let mut item = self; loop { extra_assert!(!targets_seen.contains(&item.id())); targets_seen.insert(item.id()); if self.annotations().use_instead_of().is_some() { return self.id(); } match *item.kind() { ItemKind::Type(ref ty) => match *ty.kind() { TypeKind::ResolvedTypeRef(inner) => { item = ctx.resolve_item(inner); } TypeKind::TemplateInstantiation(ref inst) => { item = ctx.resolve_item(inst.template_definition()); } _ => return item.id(), }, _ => return item.id(), } } } /// Create a fully disambiguated name for an item, including template /// parameters if it is a type pub fn full_disambiguated_name(&self, ctx: &BindgenContext) -> String { let mut s = String::new(); let level = 0; self.push_disambiguated_name(ctx, &mut s, level); s } /// Helper function for full_disambiguated_name fn push_disambiguated_name( &self, ctx: &BindgenContext, to: &mut String, level: u8, ) { to.push_str(&self.canonical_name(ctx)); if let ItemKind::Type(ref ty) = *self.kind() { if let TypeKind::TemplateInstantiation(ref inst) = *ty.kind() { to.push_str(&format!("_open{}_", level)); for arg in inst.template_arguments() { arg.into_resolver() .through_type_refs() .resolve(ctx) .push_disambiguated_name(ctx, to, level + 1); to.push_str("_"); } 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(ToOwned::to_owned).unwrap_or_else(|| { format!("_bindgen_mod_{}", self.exposed_id(ctx)) }) } ItemKind::Type(ref ty) => { ty.sanitized_name(ctx).map(Into::into).unwrap_or_else(|| { format!("_bindgen_ty_{}", self.exposed_id(ctx)) }) } ItemKind::Function(ref fun) => { let mut name = fun.name().to_owned(); if let Some(idx) = self.overload_index(ctx) { if idx > 0 { write!(&mut name, "{}", idx).unwrap(); } } name } } } fn is_anon(&self) -> bool { match self.kind() { ItemKind::Module(module) => module.name().is_none(), ItemKind::Type(ty) => ty.name().is_none(), ItemKind::Function(_) => false, ItemKind::Var(_) => false, } } /// Get the canonical name without taking into account the replaces /// annotation. /// /// This is the base logic used to implement hiding and replacing via /// annotations, and also to implement proper name mangling. /// /// The idea is that each generated type in the same "level" (read: module /// or namespace) has a unique canonical name. /// /// This name should be derived from the immutable state contained in the /// type and the parent chain, since it should be consistent. /// /// If `BindgenOptions::disable_nested_struct_naming` is true then returned /// name is the inner most non-anonymous name plus all the anonymous base names /// that follows. pub fn real_canonical_name( &self, ctx: &BindgenContext, opt: &NameOptions, ) -> String { let target = ctx.resolve_item(self.name_target(ctx)); // Short-circuit if the target has an override, and just use that. if let Some(path) = target.annotations.use_instead_of() { if ctx.options().enable_cxx_namespaces { return path.last().unwrap().clone(); } return path.join("_").to_owned(); } 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() { while let Some(id) = ids_iter.next() { ids.push(id); if !ctx.resolve_item(id).is_anon() { break; } } } ids } else { ids_iter.collect() }; // Concatenate this item's ancestors' names together. let mut names: Vec<_> = ids .into_iter() .map(|id| { let item = ctx.resolve_item(id); let target = ctx.resolve_item(item.name_target(ctx)); target.base_name(ctx) }) .filter(|name| !name.is_empty()) .collect(); names.reverse(); if !base_name.is_empty() { names.push(base_name); } if ctx.options().c_naming { if let Some(prefix) = self.c_naming_prefix() { names.insert(0, prefix.to_string()); } } let name = names.join("_"); let name = if opt.user_mangled == UserMangled::Yes { ctx.parse_callbacks() .and_then(|callbacks| callbacks.item_name(&name)) .unwrap_or(name) } else { name }; ctx.rust_mangle(&name).into_owned() } /// The exposed id that represents an unique id among the siblings of a /// given item. pub fn exposed_id(&self, ctx: &BindgenContext) -> String { // Only use local ids for enums, classes, structs and union types. All // other items use their global id. let ty_kind = self.kind().as_type().map(|t| t.kind()); if let Some(ty_kind) = ty_kind { match *ty_kind { TypeKind::Comp(..) | TypeKind::TemplateInstantiation(..) | TypeKind::Enum(..) => return self.local_id(ctx).to_string(), _ => {} } } // Note that this `id_` prefix prevents (really unlikely) collisions // between the global id and the local id of an item with the same // parent. format!("id_{}", self.id().as_usize()) } /// Get a reference to this item's `Module`, or `None` if this is not a /// `Module` item. pub fn as_module(&self) -> Option<&Module> { match self.kind { ItemKind::Module(ref module) => Some(module), _ => None, } } /// Get a mutable reference to this item's `Module`, or `None` if this is /// not a `Module` item. pub fn as_module_mut(&mut self) -> Option<&mut Module> { match self.kind { ItemKind::Module(ref mut module) => Some(module), _ => None, } } /// Returns whether the item is a constified module enum fn is_constified_enum_module(&self, ctx: &BindgenContext) -> bool { // Do not jump through aliases, except for aliases that point to a type // with the same name, since we dont generate coe for them. let item = self.id.into_resolver().through_type_refs().resolve(ctx); let type_ = match *item.kind() { ItemKind::Type(ref type_) => type_, _ => return false, }; match *type_.kind() { TypeKind::Enum(ref enum_) => { enum_.computed_enum_variation(ctx, self) == EnumVariation::ModuleConsts } TypeKind::Alias(inner_id) => { // TODO(emilio): Make this "hop through type aliases that aren't // really generated" an option in `ItemResolver`? let inner_item = ctx.resolve_item(inner_id); let name = item.canonical_name(ctx); if inner_item.canonical_name(ctx) == name { inner_item.is_constified_enum_module(ctx) } else { false } } _ => false, } } /// Is this item of a kind that is enabled for code generation? pub fn is_enabled_for_codegen(&self, ctx: &BindgenContext) -> bool { let cc = &ctx.options().codegen_config; match *self.kind() { ItemKind::Module(..) => true, ItemKind::Var(_) => cc.vars(), ItemKind::Type(_) => cc.types(), ItemKind::Function(ref f) => match f.kind() { FunctionKind::Function => cc.functions(), FunctionKind::Method(MethodKind::Constructor) => { cc.constructors() } FunctionKind::Method(MethodKind::Destructor) | FunctionKind::Method(MethodKind::VirtualDestructor { .. }) => cc.destructors(), FunctionKind::Method(MethodKind::Static) | FunctionKind::Method(MethodKind::Normal) | FunctionKind::Method(MethodKind::Virtual { .. }) => { cc.methods() } }, } } /// Returns the path we should use for allowlisting / blocklisting, which /// doesn't include user-mangling. pub fn path_for_allowlisting(&self, ctx: &BindgenContext) -> &Vec { self.path_for_allowlisting .borrow_with(|| 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().map_or(false, |module| { !module.is_inline() || ctx.options().conservative_inline_namespaces }) }) .map(|item| { ctx.resolve_item(item.name_target(ctx)) .name(ctx) .within_namespaces() .user_mangled(mangled) .get() }) .collect(); path.reverse(); path } /// Returns a prefix for the canonical name when C naming is enabled. fn c_naming_prefix(&self) -> Option<&str> { let ty = match self.kind { ItemKind::Type(ref ty) => ty, _ => return None, }; Some(match ty.kind() { TypeKind::Comp(ref ci) => match ci.kind() { CompKind::Struct => "struct", CompKind::Union => "union", }, TypeKind::Enum(..) => "enum", _ => return None, }) } } 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().map_or(false, |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) .map_or(false, |id| match ctx.lookup_has_vtable(id) { HasVtableResult::No => false, _ => true, }) } fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool { let id: ItemId = (*self).into(); id.as_type_id(ctx) .map_or(false, |id| match ctx.lookup_has_vtable(id) { HasVtableResult::SelfHasVtable => true, _ => false, }) } } 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()) } } impl HasFloat for T where T: Copy + Into, { fn has_float(&self, ctx: &BindgenContext) -> bool { debug_assert!( ctx.in_codegen_phase(), "You're not supposed to call this yet" ); ctx.lookup_has_float(*self) } } impl HasFloat for Item { fn has_float(&self, ctx: &BindgenContext) -> bool { debug_assert!( ctx.in_codegen_phase(), "You're not supposed to call this yet" ); ctx.lookup_has_float(self.id()) } } /// A set of items. pub type ItemSet = BTreeSet; 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 ClangItemParser for Item { fn builtin_type( kind: TypeKind, is_const: bool, ctx: &mut BindgenContext, ) -> TypeId { // Feel free to add more here, I'm just lazy. match kind { TypeKind::Void | TypeKind::Int(..) | TypeKind::Pointer(..) | TypeKind::Float(..) => {} _ => panic!("Unsupported builtin type"), } let ty = Type::new(None, None, kind, is_const); let id = ctx.next_item_id(); let module = ctx.root_module().into(); ctx.add_item( Item::new(id, None, None, module, ItemKind::Type(ty)), None, None, ); id.as_type_id_unchecked() } 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); 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), ), 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(ctx.current_module().into()) } None => relevant_parent_id, }; match Item::from_ty( &applicable_cursor.cur_type(), applicable_cursor, Some(relevant_parent_id), ctx, ) { Ok(ty) => return Ok(ty.into()), Err(ParseError::Recurse) => return Err(ParseError::Recurse), Err(ParseError::Continue) => {} } } // Guess how does clang treat extern "C" blocks? if cursor.kind() == CXCursor_UnexposedDecl { Err(ParseError::Recurse) } else { // We allowlist cursors here known to be unhandled, to prevent being // too noisy about this. match cursor.kind() { CXCursor_MacroDefinition | CXCursor_MacroExpansion | CXCursor_UsingDeclaration | CXCursor_UsingDirective | CXCursor_StaticAssert | CXCursor_FunctionTemplate => { debug!( "Unhandled cursor kind {:?}: {:?}", cursor.kind(), cursor ); } CXCursor_InclusionDirective => { let file = cursor.get_included_file_name(); match file { None => { warn!( "Inclusion of a nameless file in {:?}", cursor ); } Some(filename) => { ctx.include_file(filename); } } } _ => { // ignore toplevel operator overloads let spelling = cursor.spelling(); if !spelling.starts_with("operator") { warn!( "Unhandled cursor kind {:?}: {:?}", cursor.kind(), cursor ); } } } Err(ParseError::Continue) } } fn from_ty_or_ref( ty: clang::Type, location: clang::Cursor, parent_id: Option, ctx: &mut BindgenContext, ) -> TypeId { let id = ctx.next_item_id(); Self::from_ty_or_ref_with_id(id, ty, location, parent_id, ctx) } /// Parse a C++ type. If we find a reference to a type that has not been /// defined yet, use `UnresolvedTypeRef` as a placeholder. /// /// This logic is needed to avoid parsing items with the incorrect parent /// and it's sort of complex to explain, so I'll just point to /// `tests/headers/typeref.hpp` to see the kind of constructs that forced /// this. /// /// Typerefs are resolved once parsing is completely done, see /// `BindgenContext::resolve_typerefs`. fn from_ty_or_ref_with_id( potential_id: ItemId, ty: clang::Type, location: clang::Cursor, parent_id: Option, ctx: &mut BindgenContext, ) -> TypeId { debug!( "from_ty_or_ref_with_id: {:?} {:?}, {:?}, {:?}", potential_id, ty, location, parent_id ); if ctx.collected_typerefs() { debug!("refs already collected, resolving directly"); return Item::from_ty_with_id( potential_id, &ty, location, parent_id, ctx, ) .unwrap_or_else(|_| Item::new_opaque_type(potential_id, &ty, ctx)); } if let Some(ty) = ctx.builtin_or_resolved_ty( potential_id, parent_id, &ty, Some(location), ) { debug!("{:?} already resolved: {:?}", ty, location); return ty; } debug!("New unresolved type reference: {:?}, {:?}", ty, location); let is_const = ty.is_const(); let kind = TypeKind::UnresolvedTypeRef(ty, location, parent_id); let current_module = ctx.current_module(); ctx.add_item( Item::new( potential_id, None, None, parent_id.unwrap_or(current_module.into()), ItemKind::Type(Type::new(None, None, kind, is_const)), ), None, None, ); potential_id.as_type_id_unchecked() } 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. 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: {:?}\n\ \tty = {:?},\n\ \tlocation = {:?}", id, ty, location ); if ty.kind() == clang_sys::CXType_Unexposed || location.cur_type().kind() == clang_sys::CXType_Unexposed { if ty.is_associated_type() || location.cur_type().is_associated_type() { return Ok(Item::new_opaque_type(id, ty, ctx)); } if let Some(param_id) = Item::type_param(None, location, ctx) { return Ok(ctx.build_ty_wrapper(id, param_id, None, ty)); } } // Treat all types that are declared inside functions as opaque. The Rust binding // won't be able to do anything with them anyway. // // (If we don't do this check here, we can have subtle logic bugs because we generally // ignore function bodies. See issue #2036.) if let Some(ref parent) = ty.declaration().fallible_semantic_parent() { if FunctionKind::from_cursor(parent).is_some() { debug!("Skipping type declared inside function: {:?}", ty); return Ok(Item::new_opaque_type(id, ty, ctx)); } } let decl = { let decl = ty.declaration(); decl.definition().unwrap_or(decl) }; let comment = decl.raw_comment().or_else(|| location.raw_comment()); let annotations = Annotations::new(&decl).or_else(|| Annotations::new(&location)); if let Some(ref annotations) = annotations { if let Some(ref 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), ), declaration, Some(location), ); Ok(id.as_type_id_unchecked()) } Err(ParseError::Continue) => Err(ParseError::Continue), Err(ParseError::Recurse) => { debug!("Item::from_ty recursing in the ast"); let mut result = Err(ParseError::Recurse); // Need to pop here, otherwise we'll get stuck. // // TODO: Find a nicer interface, really. Also, the // declaration_to_look_for suspiciously shares a lot of // logic with ir::context, so we should refactor that. if valid_decl { let finished = ctx.finish_parsing(); assert_eq!(*finished.decl(), declaration_to_look_for); } location.visit(|cur| { visit_child(cur, id, ty, parent_id, ctx, &mut result) }); if valid_decl { let partial_ty = PartialType::new(declaration_to_look_for, id); ctx.begin_parsing(partial_ty); } // If we have recursed into the AST all we know, and we still // haven't found what we've got, let's just try and make a named // type. // // This is what happens with some template members, for example. if let Err(ParseError::Recurse) = result { warn!( "Unknown type, assuming named template type: \ id = {:?}; spelling = {}", id, ty.spelling() ); Item::type_param(Some(id), location, ctx) .map(Ok) .unwrap_or(Err(ParseError::Recurse)) } else { result } } }; if valid_decl { let partial_ty = ctx.finish_parsing(); assert_eq!(*partial_ty.decl(), declaration_to_look_for); } ret } /// A named type is a template parameter, e.g., the "T" in Foo. They're /// always local so it's the only exception when there's no declaration for /// a type. 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 { lazy_static! { static ref ANON_TYPE_PARAM_RE: regex::Regex = regex::Regex::new(r"^type\-parameter\-\d+\-\d+$").unwrap(); } if refd.kind() != clang_sys::CXCursor_TemplateTypeParameter { return false; } let refd_spelling = refd.spelling(); refd_spelling == spelling || // Allow for anonymous template parameters. (refd_spelling.is_empty() && ANON_TYPE_PARAM_RE.is_match(spelling.as_ref())) } let definition = if is_template_with_spelling(&location, &ty_spelling) { // Situation (1) location } else if location.kind() == clang_sys::CXCursor_TypeRef { // Situation (2) match location.referenced() { Some(refd) if is_template_with_spelling(&refd, &ty_spelling) => { refd } _ => return None, } } else { // Situation (3) let mut definition = None; location.visit(|child| { let child_ty = child.cur_type(); if child_ty.kind() == clang_sys::CXCursor_TypeRef && child_ty.spelling() == ty_spelling { match child.referenced() { Some(refd) if is_template_with_spelling( &refd, &ty_spelling, ) => { definition = Some(refd); return clang_sys::CXChildVisit_Break; } _ => {} } } clang_sys::CXChildVisit_Continue }); if let Some(def) = definition { def } else { return None; } }; 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)), ); ctx.add_type_param(item, definition); Some(id.as_type_id_unchecked()) } } impl ItemCanonicalName for Item { fn canonical_name(&self, ctx: &BindgenContext) -> String { debug_assert!( ctx.in_codegen_phase(), "You're not supposed to call this yet" ); self.canonical_name .borrow_with(|| { let in_namespace = ctx.options().enable_cxx_namespaces || ctx.options().disable_name_namespacing; if in_namespace { self.name(ctx).within_namespaces().get() } else { self.name(ctx).get() } }) .clone() } } impl ItemCanonicalPath for Item { fn namespace_aware_canonical_path( &self, ctx: &BindgenContext, ) -> Vec { 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()); } return 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 struct NameOptions<'a> { item: &'a Item, ctx: &'a BindgenContext, within_namespaces: bool, user_mangled: UserMangled, } impl<'a> NameOptions<'a> { /// Construct a new `NameOptions` pub fn new(item: &'a Item, ctx: &'a BindgenContext) -> Self { NameOptions { item: item, ctx: ctx, within_namespaces: false, user_mangled: UserMangled::Yes, } } /// Construct the name without the item's containing C++ namespaces mangled /// into it. In other words, the item's name within the item's namespace. pub fn within_namespaces(&mut self) -> &mut Self { self.within_namespaces = true; self } fn user_mangled(&mut self, user_mangled: UserMangled) -> &mut Self { self.user_mangled = user_mangled; self } /// Construct a name `String` pub fn get(&self) -> String { self.item.real_canonical_name(self.ctx, self) } } bindgen-0.59.1/src/ir/item_kind.rs000064400000000000000000000101370000000000000150170ustar 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 enum ItemKind { /// A module, created implicitly once (the root module), or via C++ /// namespaces. Module(Module), /// A type declared in any of the multiple ways it can be declared. Type(Type), /// A function or method declaration. Function(Function), /// A variable declaration, most likely a static. Var(Var), } impl ItemKind { /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it /// is some other kind. pub fn as_module(&self) -> Option<&Module> { match *self { ItemKind::Module(ref module) => Some(module), _ => None, } } /// Transform our `ItemKind` into a string. pub fn kind_name(&self) -> &'static str { match *self { ItemKind::Module(..) => "Module", ItemKind::Type(..) => "Type", ItemKind::Function(..) => "Function", ItemKind::Var(..) => "Var", } } /// Is this a module? pub fn is_module(&self) -> bool { self.as_module().is_some() } /// Get a reference to this `ItemKind`'s underying `Module`, or panic if it /// is some other kind. pub fn expect_module(&self) -> &Module { self.as_module().expect("Not a module") } /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if /// it is some other kind. pub fn as_function(&self) -> Option<&Function> { match *self { ItemKind::Function(ref func) => Some(func), _ => None, } } /// Is this a function? pub fn is_function(&self) -> bool { self.as_function().is_some() } /// Get a reference to this `ItemKind`'s underying `Function`, or panic if /// it is some other kind. pub fn expect_function(&self) -> &Function { self.as_function().expect("Not a function") } /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if /// it is some other kind. pub fn as_type(&self) -> Option<&Type> { match *self { ItemKind::Type(ref ty) => Some(ty), _ => None, } } /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None` /// if it is some other kind. pub fn as_type_mut(&mut self) -> Option<&mut Type> { match *self { ItemKind::Type(ref mut ty) => Some(ty), _ => None, } } /// Is this a type? pub fn is_type(&self) -> bool { self.as_type().is_some() } /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is /// some other kind. pub fn expect_type(&self) -> &Type { self.as_type().expect("Not a type") } /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is /// some other kind. pub fn as_var(&self) -> Option<&Var> { match *self { ItemKind::Var(ref v) => Some(v), _ => None, } } /// Is this a variable? pub fn is_var(&self) -> bool { self.as_var().is_some() } /// Get a reference to this `ItemKind`'s underying `Var`, or panic if it is /// some other kind. pub fn expect_var(&self) -> &Var { self.as_var().expect("Not a var") } } impl DotAttributes for ItemKind { fn dot_attributes( &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.59.1/src/ir/layout.rs000064400000000000000000000101210000000000000143620ustar 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)] pub struct Layout { /// The size (in bytes) of this layout. pub size: usize, /// The alignment (in bytes) of this layout. pub align: usize, /// Whether this layout's members are packed or not. pub packed: bool, } #[test] fn test_layout_for_size() { use std::mem; let ptr_size = mem::size_of::<*mut ()>(); assert_eq!( Layout::for_size_internal(ptr_size, ptr_size), Layout::new(ptr_size, ptr_size) ); assert_eq!( Layout::for_size_internal(ptr_size, 3 * ptr_size), Layout::new(3 * ptr_size, ptr_size) ); } impl Layout { /// Gets the integer type name for a given known size. pub fn known_type_for_size( ctx: &BindgenContext, size: usize, ) -> Option<&'static str> { Some(match size { 16 if ctx.options().rust_features.i128_and_u128 => "u128", 8 => "u64", 4 => "u32", 2 => "u16", 1 => "u8", _ => return None, }) } /// Construct a new `Layout` with the given `size` and `align`. It is not /// packed. pub fn new(size: usize, align: usize) -> Self { Layout { size, align, packed: false, } } fn for_size_internal(ptr_size: usize, size: usize) -> Self { let mut next_align = 2; while size % next_align == 0 && next_align <= ptr_size { next_align *= 2; } Layout { size: size, align: next_align / 2, packed: false, } } /// Creates a non-packed layout for a given size, trying to use the maximum /// alignment possible. pub fn for_size(ctx: &BindgenContext, size: usize) -> Self { Self::for_size_internal(ctx.target_pointer_size(), size) } /// Is this a zero-sized layout? pub fn is_zero(&self) -> bool { self.size == 0 && self.align == 0 } /// Construct a zero-sized layout. pub fn zero() -> Self { Self::new(0, 0) } /// Get this layout as an opaque type. pub fn opaque(&self) -> Opaque { Opaque(*self) } } /// When we are treating a type as opaque, it is just a blob with a `Layout`. #[derive(Clone, Debug, PartialEq)] pub struct Opaque(pub Layout); impl Opaque { /// Construct a new opaque type from the given clang type. pub fn from_clang_ty(ty: &clang::Type, ctx: &BindgenContext) -> Type { let layout = Layout::new(ty.size(ctx), ty.align(ctx)); let ty_kind = TypeKind::Opaque; let is_const = ty.is_const(); Type::new(None, Some(layout), ty_kind, is_const) } /// Return the known rust type we should use to create a correctly-aligned /// field with this layout. pub fn known_rust_type_for_array( &self, ctx: &BindgenContext, ) -> Option<&'static str> { Layout::known_type_for_size(ctx, self.0.align) } /// Return the array size that an opaque type for this layout should have if /// we know the correct type for it, or `None` otherwise. pub fn array_size(&self, ctx: &BindgenContext) -> Option { if self.known_rust_type_for_array(ctx).is_some() { Some(self.0.size / cmp::max(self.0.align, 1)) } else { None } } /// Return `true` if this opaque layout's array size will fit within the /// maximum number of array elements that Rust allows deriving traits /// with. Return `false` otherwise. pub fn array_size_within_derive_limit( &self, ctx: &BindgenContext, ) -> CanDerive { if self .array_size(ctx) .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) { CanDerive::Yes } else { CanDerive::Manually } } } bindgen-0.59.1/src/ir/mod.rs000064400000000000000000000007240000000000000136340ustar 00000000000000//! The ir module defines bindgen's intermediate representation. //! //! Parsing C/C++ generates the IR, while code generation outputs Rust code from //! the IR. pub mod analysis; pub mod annotations; pub mod comment; pub mod comp; pub mod context; pub mod derive; pub mod dot; pub mod enum_ty; pub mod function; pub mod int; pub mod item; pub mod item_kind; pub mod layout; pub mod module; pub mod objc; pub mod template; pub mod traversal; pub mod ty; pub mod var; bindgen-0.59.1/src/ir/module.rs000064400000000000000000000047050000000000000143450ustar 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 enum ModuleKind { /// This module is not inline. Normal, /// This module is inline, as in `inline namespace foo {}`. Inline, } /// A module, as in, a C++ namespace. #[derive(Clone, Debug)] pub struct Module { /// The name of the module, or none if it's anonymous. name: Option, /// The kind of module this is. kind: ModuleKind, /// The children of this module, just here for convenience. children: ItemSet, } impl Module { /// Construct a new `Module`. pub fn new(name: Option, kind: ModuleKind) -> Self { Module { name: name, kind: kind, children: ItemSet::new(), } } /// Get this module's name. pub fn name(&self) -> Option<&str> { self.name.as_ref().map(|n| &**n) } /// Get a mutable reference to this module's children. pub fn children_mut(&mut self) -> &mut ItemSet { &mut self.children } /// Get this module's children. pub fn children(&self) -> &ItemSet { &self.children } /// Whether this namespace is inline. pub fn is_inline(&self) -> bool { self.kind == ModuleKind::Inline } } impl DotAttributes for Module { fn dot_attributes( &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(|cursor| { parse_one(ctx, cursor, Some(module_id.into())) }) }); Ok(ParseResult::AlreadyResolved(module_id.into())) } _ => Err(ParseError::Continue), } } } bindgen-0.59.1/src/ir/objc.rs000064400000000000000000000232100000000000000137650ustar 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 crate::parse::ClangItemParser; use clang_sys::CXChildVisit_Continue; use clang_sys::CXCursor_ObjCCategoryDecl; use clang_sys::CXCursor_ObjCClassMethodDecl; use clang_sys::CXCursor_ObjCClassRef; use clang_sys::CXCursor_ObjCInstanceMethodDecl; use clang_sys::CXCursor_ObjCProtocolDecl; use clang_sys::CXCursor_ObjCProtocolRef; use clang_sys::CXCursor_ObjCSuperClassRef; use clang_sys::CXCursor_TemplateTypeParameter; use proc_macro2::{Ident, Span, TokenStream}; /// Objective C interface as used in TypeKind /// /// Also protocols and categories are parsed as this type #[derive(Debug)] pub struct ObjCInterface { /// The name /// like, NSObject name: String, category: Option, is_protocol: bool, /// The list of template names almost always, ObjectType or KeyType pub template_names: Vec, /// The list of protocols that this interface conforms to. pub conforms_to: Vec, /// The direct parent for this interface. pub parent_class: Option, /// List of the methods defined in this interfae methods: Vec, class_methods: Vec, } /// The objective c methods #[derive(Debug)] pub struct ObjCMethod { /// The original method selector name /// like, dataWithBytes:length: name: String, /// Method name as converted to rust /// like, dataWithBytes_length_ rust_name: String, signature: FunctionSig, /// Is class method? is_class_method: bool, } impl ObjCInterface { fn new(name: &str) -> ObjCInterface { ObjCInterface { name: name.to_owned(), category: None, is_protocol: false, template_names: Vec::new(), parent_class: None, conforms_to: Vec::new(), methods: Vec::new(), class_methods: Vec::new(), } } /// The name /// like, NSObject pub fn name(&self) -> &str { self.name.as_ref() } /// Formats the name for rust /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods /// and protocols are like PNSObject pub fn rust_name(&self) -> String { if let Some(ref cat) = self.category { format!("{}_{}", self.name(), cat) } else { if self.is_protocol { format!("P{}", self.name()) } else { format!("I{}", self.name().to_owned()) } } } /// Is this a template interface? pub fn is_template(&self) -> bool { !self.template_names.is_empty() } /// List of the methods defined in this interface pub fn methods(&self) -> &Vec { &self.methods } /// Is this a protocol? pub fn is_protocol(&self) -> bool { self.is_protocol } /// Is this a category? pub fn is_category(&self) -> bool { self.category.is_some() } /// List of the class methods defined in this interface pub fn class_methods(&self) -> &Vec { &self.class_methods } /// Parses the Objective C interface from the cursor pub 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 approriately interface.name = c.spelling(); interface.category = Some(cursor.spelling()); } } CXCursor_ObjCProtocolRef => { // Gather protocols this interface conforms to let needle = format!("P{}", c.spelling()); let items_map = ctx.items(); debug!("Interface {} conforms to {}, find the item", interface.name, needle); for (id, item) in items_map { if let Some(ty) = item.as_type() { match *ty.kind() { TypeKind::ObjCInterface(ref protocol) => { 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: rust_name.to_owned(), signature, is_class_method, } } /// The original method selector name /// like, dataWithBytes:length: pub fn name(&self) -> &str { self.name.as_ref() } /// Method name as converted to rust /// like, dataWithBytes_length_ pub fn rust_name(&self) -> &str { self.rust_name.as_ref() } /// Returns the methods signature as FunctionSig pub fn signature(&self) -> &FunctionSig { &self.signature } /// Is this a class method? pub fn is_class_method(&self) -> bool { self.is_class_method } /// Formats the method call pub fn format_method_call(&self, args: &[TokenStream]) -> TokenStream { let split_name: Vec> = self .name .split(':') .map(|name| { if name.is_empty() { None } else { Some(Ident::new(name, Span::call_site())) } }) .collect(); // No arguments if args.len() == 0 && split_name.len() == 1 { let name = &split_name[0]; return quote! { #name }; } // Check right amount of arguments if args.len() != split_name.len() - 1 { panic!( "Incorrect method name or arguments for objc method, {:?} vs {:?}", args, split_name, ); } // Get arguments without type signatures to pass to `msg_send!` let mut args_without_types = vec![]; for arg in args.iter() { let arg = arg.to_string(); let name_and_sig: Vec<&str> = arg.split(' ').collect(); let name = name_and_sig[0]; args_without_types.push(Ident::new(name, Span::call_site())) } let args = split_name.into_iter().zip(args_without_types).map( |(arg, arg_val)| { if let Some(arg) = arg { quote! { #arg: #arg_val } } else { quote! { #arg_val: #arg_val } } }, ); quote! { #( #args )* } } } impl Trace for ObjCInterface { type Extra = (); fn trace(&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.59.1/src/ir/template.rs000064400000000000000000000271350000000000000146750ustar 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; use crate::parse::ClangItemParser; /// Template declaration (and such declaration's template parameters) related /// methods. /// /// This trait's methods distinguish between `None` and `Some([])` for /// declarations that are not templates and template declarations with zero /// parameters, in general. /// /// Consider this example: /// /// ```c++ /// template /// 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 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 ancestors: Vec<_> = self.ancestors(ctx).collect(); ancestors .into_iter() .rev() .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 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 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 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 fn template_definition(&self) -> TypeId { self.definition } /// Get the concrete template arguments used in this instantiation. pub fn template_arguments(&self) -> &[TypeId] { &self.args[..] } /// Parse a `TemplateInstantiation` from a clang `Type`. pub fn from_ty( ty: &clang::Type, ctx: &mut BindgenContext, ) -> Option { use clang_sys::*; let template_args = ty.template_args().map_or(vec![], |args| match ty .canonical_type() .template_args() { Some(canonical_args) => { let arg_count = args.len(); args.chain(canonical_args.skip(arg_count)) .filter(|t| t.kind() != CXType_Invalid) .map(|t| { Item::from_ty_or_ref(t, t.declaration(), None, ctx) }) .collect() } None => args .filter(|t| t.kind() != CXType_Invalid) .map(|t| Item::from_ty_or_ref(t, t.declaration(), None, ctx)) .collect(), }); let declaration = ty.declaration(); let definition = if declaration.kind() == CXCursor_TypeAliasTemplateDecl { Some(declaration) } else { declaration.specialized().or_else(|| { let mut template_ref = None; ty.declaration().visit(|child| { if child.kind() == CXCursor_TemplateRef { template_ref = Some(child); return CXVisit_Break; } // Instantiations of template aliases might have the // TemplateRef to the template alias definition arbitrarily // deep, so we need to recurse here and not only visit // direct children. CXChildVisit_Recurse }); template_ref.and_then(|cur| cur.referenced()) }) }; let definition = match definition { Some(def) => def, None => { if !ty.declaration().is_builtin() { warn!( "Could not find template definition for template \ instantiation" ); } return None; } }; let template_definition = Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx); Some(TemplateInstantiation::new( template_definition, template_args, )) } } impl IsOpaque for TemplateInstantiation { type Extra = Item; /// Is this an opaque template instantiation? fn is_opaque(&self, ctx: &BindgenContext, item: &Item) -> bool { if self.template_definition().is_opaque(ctx, &()) { return true; } // TODO(#774): This doesn't properly handle opaque instantiations where // an argument is itself an instantiation because `canonical_name` does // not insert the template arguments into the name, ie it for nested // template arguments it creates "Foo" instead of "Foo". 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.59.1/src/ir/traversal.rs000064400000000000000000000347010000000000000150620ustar 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 struct Edge { to: ItemId, kind: EdgeKind, } impl Edge { /// Construct a new edge whose referent is `to` and is of the given `kind`. pub fn new(to: ItemId, kind: EdgeKind) -> Edge { Edge { to, kind } } } impl Into for Edge { fn into(self) -> ItemId { self.to } } /// The kind of edge reference. This is useful when we wish to only consider /// certain kinds of edges for a particular traversal or analysis. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum EdgeKind { /// A generic, catch-all edge. Generic, /// An edge from a template declaration, to the definition of a named type /// parameter. For example, the edge from `Foo` 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. pub trait TraversalPredicate { /// Should the traversal follow this edge, and visit everything that is /// reachable through it? fn should_follow(&self, ctx: &BindgenContext, edge: Edge) -> bool; } impl TraversalPredicate for for<'a> fn(&'a BindgenContext, Edge) -> bool { fn should_follow(&self, ctx: &BindgenContext, edge: Edge) -> bool { (*self)(ctx, edge) } } /// A `TraversalPredicate` implementation that follows all edges, and therefore /// traversals using this predicate will see the whole IR graph reachable from /// the traversal's roots. pub fn all_edges(_: &BindgenContext, _: Edge) -> bool { true } /// A `TraversalPredicate` implementation that only follows /// `EdgeKind::InnerType` edges, and therefore traversals using this predicate /// will only visit the traversal's roots and their inner types. This is used /// in no-recursive-allowlist mode, where inner types such as anonymous /// structs/unions still need to be processed. pub fn only_inner_type_edges(_: &BindgenContext, edge: Edge) -> bool { edge.kind == EdgeKind::InnerType } /// A `TraversalPredicate` implementation that only follows edges to items that /// are enabled for code generation. This lets us skip considering items for /// which are not reachable from code generation. pub fn codegen_edges(ctx: &BindgenContext, edge: Edge) -> bool { let cc = &ctx.options().codegen_config; match edge.kind { EdgeKind::Generic => { ctx.resolve_item(edge.to).is_enabled_for_codegen(ctx) } // We statically know the kind of item that non-generic edges can point // to, so we don't need to actually resolve the item and check // `Item::is_enabled_for_codegen`. EdgeKind::TemplateParameterDefinition | EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration | EdgeKind::BaseMember | EdgeKind::Field | EdgeKind::InnerType | EdgeKind::FunctionReturn | EdgeKind::FunctionParameter | EdgeKind::VarType | EdgeKind::TypeReference => cc.types(), EdgeKind::InnerVar => cc.vars(), EdgeKind::Method => cc.methods(), EdgeKind::Constructor => cc.constructors(), EdgeKind::Destructor => cc.destructors(), } } /// The storage for the set of items that have been seen (although their /// outgoing edges might not have been fully traversed yet) in an active /// traversal. pub trait TraversalStorage<'ctx> { /// Construct a new instance of this TraversalStorage, for a new traversal. fn new(ctx: &'ctx BindgenContext) -> Self; /// Add the given item to the storage. If the item has never been seen /// before, return `true`. Otherwise, return `false`. /// /// The `from` item is the item from which we discovered this item, or is /// `None` if this item is a root. fn add(&mut self, from: Option, 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 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 = {:?}\nvia path = {:?}", item, path ); } newly_discovered } } /// The queue of seen-but-not-yet-traversed items. /// /// Using a FIFO queue with a traversal will yield a breadth-first traversal, /// while using a LIFO queue will result in a depth-first traversal of the IR /// graph. pub trait TraversalQueue: Default { /// Add a newly discovered item to the queue. fn push(&mut self, item: ItemId); /// Pop the next item to traverse, if any. fn next(&mut self) -> Option; } 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 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 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 struct ItemTraversal<'ctx, Storage, Queue, Predicate> where Storage: TraversalStorage<'ctx>, Queue: TraversalQueue, Predicate: TraversalPredicate, { 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: Predicate, /// The item we are currently traversing. currently_traversing: Option, } impl<'ctx, Storage, Queue, Predicate> ItemTraversal<'ctx, Storage, Queue, Predicate> where Storage: TraversalStorage<'ctx>, Queue: TraversalQueue, Predicate: TraversalPredicate, { /// Begin a new traversal, starting from the given roots. pub fn new( ctx: &'ctx BindgenContext, roots: R, predicate: Predicate, ) -> ItemTraversal<'ctx, Storage, Queue, Predicate> 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: ctx, seen: seen, queue: queue, predicate: predicate, currently_traversing: None, } } } impl<'ctx, Storage, Queue, Predicate> Tracer for ItemTraversal<'ctx, Storage, Queue, Predicate> where Storage: TraversalStorage<'ctx>, Queue: TraversalQueue, Predicate: TraversalPredicate, { fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { let edge = Edge::new(item, kind); if !self.predicate.should_follow(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, Predicate> Iterator for ItemTraversal<'ctx, Storage, Queue, Predicate> where Storage: TraversalStorage<'ctx>, Queue: TraversalQueue, Predicate: TraversalPredicate, { 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 type AssertNoDanglingItemsTraversal<'ctx> = ItemTraversal< 'ctx, Paths<'ctx>, VecDeque, for<'a> fn(&'a BindgenContext, Edge) -> bool, >; #[cfg(test)] mod tests { use super::*; #[test] #[allow(dead_code)] fn traversal_predicate_is_object_safe() { // This should compile only if TraversalPredicate is object safe. fn takes_by_trait_object(_: &dyn TraversalPredicate) {} } } bindgen-0.59.1/src/ir/ty.rs000064400000000000000000001330250000000000000135120ustar 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::int::IntKind; use super::item::{IsOpaque, Item}; use super::layout::{Layout, Opaque}; use super::objc::ObjCInterface; use super::template::{ AsTemplateParam, TemplateInstantiation, TemplateParameters, }; use super::traversal::{EdgeKind, Trace, Tracer}; use crate::clang::{self, Cursor}; use crate::parse::{ClangItemParser, ParseError, ParseResult}; use std::borrow::Cow; use std::io; /// The base representation of a type in bindgen. /// /// A type has an optional name, which if present cannot be empty, a `layout` /// (size, alignment and packedness) if known, a `Kind`, which determines which /// kind of type it is, and whether the type is const. #[derive(Debug)] pub struct Type { /// The name of the type, or None if it was an unnamed struct or union. name: Option, /// 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 const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32; impl Type { /// Get the underlying `CompInfo` for this type, or `None` if this is some /// other kind of type. pub fn as_comp(&self) -> Option<&CompInfo> { match self.kind { TypeKind::Comp(ref ci) => Some(ci), _ => None, } } /// Get the underlying `CompInfo` for this type as a mutable reference, or /// `None` if this is some other kind of type. pub fn as_comp_mut(&mut self) -> Option<&mut CompInfo> { match self.kind { TypeKind::Comp(ref mut ci) => Some(ci), _ => None, } } /// Construct a new `Type`. pub fn new( name: Option, layout: Option, kind: TypeKind, is_const: bool, ) -> Self { Type { name, layout, kind, is_const, } } /// Which kind of type is this? pub fn kind(&self) -> &TypeKind { &self.kind } /// Get a mutable reference to this type's kind. pub fn kind_mut(&mut self) -> &mut TypeKind { &mut self.kind } /// Get this type's name. pub fn name(&self) -> Option<&str> { self.name.as_ref().map(|name| &**name) } /// Whether this is a block pointer type. pub fn is_block_pointer(&self) -> bool { match self.kind { TypeKind::BlockPointer(..) => true, _ => false, } } /// Is this a compound type? pub fn is_comp(&self) -> bool { match self.kind { TypeKind::Comp(..) => true, _ => false, } } /// Is this a union? pub fn is_union(&self) -> bool { match self.kind { TypeKind::Comp(ref comp) => comp.is_union(), _ => false, } } /// Is this type of kind `TypeKind::TypeParam`? pub fn is_type_param(&self) -> bool { match self.kind { TypeKind::TypeParam => true, _ => false, } } /// Is this a template instantiation type? pub fn is_template_instantiation(&self) -> bool { match self.kind { TypeKind::TemplateInstantiation(..) => true, _ => false, } } /// Is this a template alias type? pub fn is_template_alias(&self) -> bool { match self.kind { TypeKind::TemplateAlias(..) => true, _ => false, } } /// Is this a function type? pub fn is_function(&self) -> bool { match self.kind { TypeKind::Function(..) => true, _ => false, } } /// Is this an enum type? pub fn is_enum(&self) -> bool { match self.kind { TypeKind::Enum(..) => true, _ => false, } } /// Is this either a builtin or named type? pub fn is_builtin_or_type_param(&self) -> bool { match self.kind { TypeKind::Void | TypeKind::NullPtr | TypeKind::Function(..) | TypeKind::Array(..) | TypeKind::Reference(..) | TypeKind::Pointer(..) | TypeKind::Int(..) | TypeKind::Float(..) | TypeKind::TypeParam => true, _ => false, } } /// Creates a new named type, with name `name`. pub fn named(name: String) -> Self { let name = if name.is_empty() { None } else { Some(name) }; Self::new(name, None, TypeKind::TypeParam, false) } /// Is this a floating point type? pub fn is_float(&self) -> bool { match self.kind { TypeKind::Float(..) => true, _ => false, } } /// Is this a boolean type? pub fn is_bool(&self) -> bool { match self.kind { TypeKind::Int(IntKind::Bool) => true, _ => false, } } /// Is this an integer type? pub fn is_integer(&self) -> bool { match self.kind { TypeKind::Int(..) => true, _ => false, } } /// Cast this type to an integer kind, or `None` if it is not an integer /// type. pub fn as_integer(&self) -> Option { match self.kind { TypeKind::Int(int_kind) => Some(int_kind), _ => None, } } /// Is this a `const` qualified type? pub fn is_const(&self) -> bool { self.is_const } /// Is this a reference to another type? pub fn is_type_ref(&self) -> bool { match self.kind { TypeKind::ResolvedTypeRef(_) | TypeKind::UnresolvedTypeRef(_, _, _) => true, _ => false, } } /// Is this an unresolved reference? pub fn is_unresolved_ref(&self) -> bool { match self.kind { TypeKind::UnresolvedTypeRef(_, _, _) => true, _ => false, } } /// Is this a incomplete array type? pub 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 fn layout(&self, ctx: &BindgenContext) -> Option { self.layout.or_else(|| { match self.kind { TypeKind::Comp(ref ci) => ci.layout(ctx), TypeKind::Array(inner, length) if length == 0 => Some( Layout::new(0, ctx.resolve_type(inner).layout(ctx)?.align), ), // FIXME(emilio): This is a hack for anonymous union templates. // Use the actual pointer size! TypeKind::Pointer(..) => Some(Layout::new( ctx.target_pointer_size(), ctx.target_pointer_size(), )), TypeKind::ResolvedTypeRef(inner) => { ctx.resolve_type(inner).layout(ctx) } _ => None, } }) } /// Whether this named type is an invalid C++ identifier. This is done to /// avoid generating invalid code with some cases we can't handle, see: /// /// tests/headers/381-decltype-alias.hpp pub fn is_invalid_type_param(&self) -> bool { match self.kind { TypeKind::TypeParam => { let name = self.name().expect("Unnamed named type?"); !clang::is_valid_identifier(&name) } _ => false, } } /// Takes `name`, and returns a suitable identifier representation for it. fn sanitize_name<'a>(name: &'a str) -> Cow<'a, str> { if clang::is_valid_identifier(name) { return Cow::Borrowed(name); } let name = name.replace(|c| c == ' ' || c == ':' || c == '.', "_"); Cow::Owned(name) } /// Get this type's santizied name. pub fn sanitized_name<'a>( &'a self, ctx: &BindgenContext, ) -> Option> { let name_info = match *self.kind() { TypeKind::Pointer(inner) => { Some((inner.into(), Cow::Borrowed("ptr"))) } TypeKind::Reference(inner) => { Some((inner.into(), Cow::Borrowed("ref"))) } TypeKind::Array(inner, length) => { Some((inner, format!("array{}", length).into())) } _ => None, }; if let Some((inner, prefix)) = name_info { ctx.resolve_item(inner) .expect_type() .sanitized_name(ctx) .map(|name| format!("{}_{}", prefix, name).into()) } else { self.name().map(Self::sanitize_name) } } /// See safe_canonical_type. pub fn canonical_type<'tr>( &'tr self, ctx: &'tr BindgenContext, ) -> &'tr Type { self.safe_canonical_type(ctx) .expect("Should have been resolved after parsing!") } /// Returns the canonical type of this type, that is, the "inner type". /// /// For example, for a `typedef`, the canonical type would be the /// `typedef`ed type, for a template instantiation, would be the template /// its specializing, and so on. Return None if the type is unresolved. pub fn safe_canonical_type<'tr>( &'tr self, ctx: &'tr BindgenContext, ) -> Option<&'tr Type> { match self.kind { TypeKind::TypeParam | TypeKind::Array(..) | TypeKind::Vector(..) | TypeKind::Comp(..) | TypeKind::Opaque | TypeKind::Int(..) | TypeKind::Float(..) | TypeKind::Complex(..) | TypeKind::Function(..) | TypeKind::Enum(..) | TypeKind::Reference(..) | TypeKind::Void | TypeKind::NullPtr | TypeKind::Pointer(..) | TypeKind::BlockPointer(..) | TypeKind::ObjCId | TypeKind::ObjCSel | TypeKind::ObjCInterface(..) => Some(self), TypeKind::ResolvedTypeRef(inner) | TypeKind::Alias(inner) | TypeKind::TemplateAlias(inner, _) => { ctx.resolve_type(inner).safe_canonical_type(ctx) } TypeKind::TemplateInstantiation(ref inst) => ctx .resolve_type(inst.template_definition()) .safe_canonical_type(ctx), TypeKind::UnresolvedTypeRef(..) => None, } } /// There are some types we don't want to stop at when finding an opaque /// item, so we can arrive to the proper item that needs to be generated. pub fn should_be_traced_unconditionally(&self) -> bool { match self.kind { TypeKind::Comp(..) | TypeKind::Function(..) | TypeKind::Pointer(..) | TypeKind::Array(..) | TypeKind::Reference(..) | TypeKind::TemplateInstantiation(..) | TypeKind::ResolvedTypeRef(..) => true, _ => false, } } } 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_remaing() { let ty = Type::new(Some("foo-".into()), None, TypeKind::TypeParam, false); assert!(ty.is_invalid_type_param()) } #[test] #[should_panic] fn is_invalid_type_param_unnamed() { let ty = Type::new(None, None, TypeKind::TypeParam, false); assert!(ty.is_invalid_type_param()) } #[test] fn is_invalid_type_param_empty_name() { let ty = Type::new(Some("".into()), None, TypeKind::TypeParam, false); assert!(ty.is_invalid_type_param()) } impl TemplateParameters for Type { fn self_template_params(&self, ctx: &BindgenContext) -> Vec { 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)] pub enum FloatKind { /// A `float`. Float, /// A `double`. Double, /// A `long double`. LongDouble, /// A `__float128`. Float128, } /// The different kinds of types that we can parse. #[derive(Debug)] pub enum TypeKind { /// The void type. Void, /// The `nullptr_t` type. NullPtr, /// A compound type, that is, a class, struct, or union. Comp(CompInfo), /// An opaque type that we just don't understand. All usage of this shoulf /// result in an opaque blob of bytes generated from the containing type's /// layout. Opaque, /// An integer type, of a given kind. `bool` and `char` are also considered /// integers. Int(IntKind), /// A floating point type. Float(FloatKind), /// A complex floating point type. Complex(FloatKind), /// A type alias, with a name, that points to another type. Alias(TypeId), /// A templated alias, pointing to an inner type, just as `Alias`, but with /// template parameters. TemplateAlias(TypeId, Vec), /// A packed vector type: element type, number of elements Vector(TypeId, usize), /// An array of a type and a length. Array(TypeId, usize), /// A function type, with a given signature. Function(FunctionSig), /// An `enum` type. Enum(Enum), /// A pointer to a type. The bool field represents whether it's const or /// not. Pointer(TypeId), /// A pointer to an Apple block. BlockPointer(TypeId), /// A reference to a type, as in: int& foo(). Reference(TypeId), /// An instantiation of an abstract template definition with a set of /// concrete template arguments. TemplateInstantiation(TemplateInstantiation), /// A reference to a yet-to-resolve type. This stores the clang cursor /// itself, and postpones its resolution. /// /// These are gone in a phase after parsing where these are mapped to /// already known types, and are converted to ResolvedTypeRef. /// /// see tests/headers/typeref.hpp to see somewhere where this is a problem. UnresolvedTypeRef( clang::Type, clang::Cursor, /* parent_id */ Option, ), /// An indirection to another type. /// /// These are generated after we resolve a forward declaration, or when we /// replace one type with another. ResolvedTypeRef(TypeId), /// A named type, that is, a template parameter. TypeParam, /// Objective C interface. Always referenced through a pointer ObjCInterface(ObjCInterface), /// Objective C 'id' type, points to any object ObjCId, /// Objective C selector type ObjCSel, } impl Type { /// This is another of the nasty methods. This one is the one that takes /// care of the core logic of converting a clang type to a `Type`. /// /// It's sort of nasty and full of special-casing, but hopefully the /// comments in every special case justify why they're there. pub fn from_clang_ty( potential_id: ItemId, ty: &clang::Type, location: Cursor, parent_id: Option, 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!("{:?} already resolved: {:?}", ty, location); return Ok(ParseResult::AlreadyResolved(ty.into())); } } let layout = ty.fallible_layout(ctx).ok(); let cursor = ty.declaration(); let mut name = cursor.spelling(); debug!( "from_clang_ty: {:?}, ty: {:?}, loc: {:?}", potential_id, ty, location ); debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types()); let canonical_ty = ty.canonical_type(); // Parse objc protocols as if they were interfaces let mut ty_kind = ty.kind(); match location.kind() { CXCursor_ObjCProtocolDecl | CXCursor_ObjCCategoryDecl => { ty_kind = CXType_ObjCInterface } _ => {} } // Objective C template type parameter // FIXME: This is probably wrong, we are attempting to find the // objc template params, which seem to manifest as a typedef. // We are rewriting them as id to suppress multiple conflicting // typedefs at root level if ty_kind == CXType_Typedef { let is_template_type_param = ty.declaration().kind() == CXCursor_TemplateTypeParameter; let is_canonical_objcpointer = canonical_ty.kind() == CXType_ObjCObjectPointer; // We have found a template type for objc interface if is_canonical_objcpointer && is_template_type_param { // Objective-C generics are just ids with fancy name. // To keep it simple, just name them ids name = "id".to_owned(); } } if location.kind() == CXCursor_ClassTemplatePartialSpecialization { // Sorry! (Not sorry) warn!( "Found a partial template specialization; bindgen does not \ support partial template specialization! Constructing \ opaque type instead." ); return Ok(ParseResult::New( Opaque::from_clang_ty(&canonical_ty, ctx), None, )); } let kind = if location.kind() == CXCursor_TemplateRef || (ty.template_args().is_some() && ty_kind != CXType_Typedef) { // This is a template instantiation. match TemplateInstantiation::from_ty(&ty, ctx) { Some(inst) => TypeKind::TemplateInstantiation(inst), None => TypeKind::Opaque, } } else { match ty_kind { CXType_Unexposed if *ty != canonical_ty && canonical_ty.kind() != CXType_Invalid && ty.ret_type().is_none() && // Sometime clang desugars some types more than // what we need, specially with function // pointers. // // We should also try the solution of inverting // those checks instead of doing this, that is, // something like: // // CXType_Unexposed if ty.ret_type().is_some() // => { ... } // // etc. !canonical_ty.spelling().contains("type-parameter") => { debug!("Looking for canonical type: {:?}", canonical_ty); return Self::from_clang_ty( potential_id, &canonical_ty, location, parent_id, ctx, ); } CXType_Unexposed | CXType_Invalid => { // For some reason Clang doesn't give us any hint in some // situations where we should generate a function pointer (see // tests/headers/func_ptr_in_struct.h), so we do a guess here // trying to see if it has a valid return type. if ty.ret_type().is_some() { let signature = FunctionSig::from_ty(ty, &location, ctx)?; TypeKind::Function(signature) // Same here, with template specialisations we can safely // assume this is a Comp(..) } else if ty.is_fully_instantiated_template() { debug!( "Template specialization: {:?}, {:?} {:?}", ty, location, canonical_ty ); let complex = CompInfo::from_ty( potential_id, ty, Some(location), ctx, ) .expect("C'mon"); TypeKind::Comp(complex) } else { match location.kind() { CXCursor_CXXBaseSpecifier | CXCursor_ClassTemplate => { if location.kind() == CXCursor_CXXBaseSpecifier { // In the case we're parsing a base specifier // inside an unexposed or invalid type, it means // that we're parsing one of two things: // // * A template parameter. // * A complex class that isn't exposed. // // This means, unfortunately, that there's no // good way to differentiate between them. // // Probably we could try to look at the // declaration and complicate more this logic, // but we'll keep it simple... if it's a valid // C++ identifier, we'll consider it as a // template parameter. // // This is because: // // * We expect every other base that is a // proper identifier (that is, a simple // struct/union declaration), to be exposed, // so this path can't be reached in that // case. // // * Quite conveniently, complex base // specifiers preserve their full names (that // is: Foo instead of Foo). We can take // advantage of this. // // If we find some edge case where this doesn't // work (which I guess is unlikely, see the // different test cases[1][2][3][4]), we'd need // to find more creative ways of differentiating // these two cases. // // [1]: inherit_named.hpp // [2]: forward-inherit-struct-with-fields.hpp // [3]: forward-inherit-struct.hpp // [4]: inherit-namespaced.hpp if location.spelling().chars().all(|c| { c.is_alphanumeric() || c == '_' }) { return Err(ParseError::Recurse); } } else { name = location.spelling(); } let complex = CompInfo::from_ty( potential_id, ty, Some(location), ctx, ); match complex { Ok(complex) => TypeKind::Comp(complex), Err(_) => { warn!( "Could not create complex type \ from class template or base \ specifier, using opaque blob" ); let opaque = Opaque::from_clang_ty(ty, ctx); return Ok(ParseResult::New( opaque, None, )); } } } CXCursor_TypeAliasTemplateDecl => { debug!("TypeAliasTemplateDecl"); // We need to manually unwind this one. let mut inner = Err(ParseError::Continue); let mut args = vec![]; location.visit(|cur| { match cur.kind() { CXCursor_TypeAliasDecl => { let current = cur.cur_type(); debug_assert_eq!( current.kind(), CXType_Typedef ); name = current.spelling(); let inner_ty = cur .typedef_type() .expect("Not valid Type?"); inner = Ok(Item::from_ty_or_ref( inner_ty, cur, Some(potential_id), ctx, )); } CXCursor_TemplateTypeParameter => { let param = Item::type_param( None, cur, ctx, ) .expect( "Item::type_param shouldn't \ ever fail if we are looking \ at a TemplateTypeParameter", ); args.push(param); } _ => {} } CXChildVisit_Continue }); let inner_type = match inner { Ok(inner) => inner, Err(..) => { warn!( "Failed to parse template alias \ {:?}", location ); return Err(ParseError::Continue); } }; TypeKind::TemplateAlias(inner_type, args) } CXCursor_TemplateRef => { let referenced = location.referenced().unwrap(); let referenced_ty = referenced.cur_type(); debug!( "TemplateRef: location = {:?}; referenced = \ {:?}; referenced_ty = {:?}", location, referenced, referenced_ty ); return Self::from_clang_ty( potential_id, &referenced_ty, referenced, parent_id, ctx, ); } CXCursor_TypeRef => { let referenced = location.referenced().unwrap(); let referenced_ty = referenced.cur_type(); let declaration = referenced_ty.declaration(); debug!( "TypeRef: location = {:?}; referenced = \ {:?}; referenced_ty = {:?}", location, referenced, referenced_ty ); let id = Item::from_ty_or_ref_with_id( potential_id, referenced_ty, declaration, parent_id, ctx, ); return Ok(ParseResult::AlreadyResolved( id.into(), )); } CXCursor_NamespaceRef => { return Err(ParseError::Continue); } _ => { if ty.kind() == CXType_Unexposed { warn!( "Unexposed type {:?}, recursing inside, \ loc: {:?}", ty, location ); return Err(ParseError::Recurse); } warn!("invalid type {:?}", ty); return Err(ParseError::Continue); } } } } CXType_Auto => { if canonical_ty == *ty { debug!("Couldn't find deduced type: {:?}", ty); return Err(ParseError::Continue); } return Self::from_clang_ty( potential_id, &canonical_ty, location, parent_id, ctx, ); } // NOTE: We don't resolve pointers eagerly because the pointee type // might not have been parsed, and if it contains templates or // something else we might get confused, see the comment inside // TypeRef. // // We might need to, though, if the context is already in the // process of resolving them. CXType_ObjCObjectPointer | CXType_MemberPointer | CXType_Pointer => { let pointee = ty.pointee_type().unwrap(); let inner = Item::from_ty_or_ref(pointee, location, None, ctx); TypeKind::Pointer(inner) } CXType_BlockPointer => { let pointee = ty.pointee_type().expect("Not valid Type?"); let inner = Item::from_ty_or_ref(pointee, location, None, ctx); TypeKind::BlockPointer(inner) } // XXX: RValueReference is most likely wrong, but I don't think we // can even add bindings for that, so huh. CXType_RValueReference | CXType_LValueReference => { let inner = Item::from_ty_or_ref( ty.pointee_type().unwrap(), location, None, ctx, ); TypeKind::Reference(inner) } // XXX DependentSizedArray is wrong CXType_VariableArray | CXType_DependentSizedArray => { let inner = Item::from_ty( ty.elem_type().as_ref().unwrap(), location, None, ctx, ) .expect("Not able to resolve array element?"); TypeKind::Pointer(inner) } CXType_IncompleteArray => { let inner = Item::from_ty( ty.elem_type().as_ref().unwrap(), location, None, ctx, ) .expect("Not able to resolve array element?"); TypeKind::Array(inner, 0) } CXType_FunctionNoProto | CXType_FunctionProto => { let signature = FunctionSig::from_ty(ty, &location, ctx)?; TypeKind::Function(signature) } CXType_Typedef => { let inner = cursor.typedef_type().expect("Not valid Type?"); let inner = Item::from_ty_or_ref(inner, location, None, ctx); TypeKind::Alias(inner) } CXType_Enum => { let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?"); if name.is_empty() { let pretty_name = ty.spelling(); if clang::is_valid_identifier(&pretty_name) { name = pretty_name; } } TypeKind::Enum(enum_) } CXType_Record => { let complex = CompInfo::from_ty( potential_id, ty, Some(location), ctx, ) .expect("Not a complex type?"); if name.is_empty() { // The pretty-printed name may contain typedefed name, // but may also be "struct (anonymous at .h:1)" let pretty_name = ty.spelling(); if clang::is_valid_identifier(&pretty_name) { name = pretty_name; } } TypeKind::Comp(complex) } CXType_Vector => { let inner = Item::from_ty( ty.elem_type().as_ref().unwrap(), location, None, ctx, ) .expect("Not able to resolve vector element?"); TypeKind::Vector(inner, ty.num_elements().unwrap()) } CXType_ConstantArray => { let inner = Item::from_ty( ty.elem_type().as_ref().unwrap(), location, None, ctx, ) .expect("Not able to resolve array element?"); TypeKind::Array(inner, ty.num_elements().unwrap()) } CXType_Elaborated => { return Self::from_clang_ty( potential_id, &ty.named(), location, parent_id, ctx, ); } CXType_ObjCId => TypeKind::ObjCId, CXType_ObjCSel => TypeKind::ObjCSel, CXType_ObjCClass | CXType_ObjCInterface => { let interface = ObjCInterface::from_ty(&location, ctx) .expect("Not a valid objc interface?"); name = interface.rust_name(); TypeKind::ObjCInterface(interface) } CXType_Dependent => { return Err(ParseError::Continue); } _ => { warn!( "unsupported type: kind = {:?}; ty = {:?}; at {:?}", ty.kind(), ty, location ); return Err(ParseError::Continue); } } }; let name = if name.is_empty() { None } else { Some(name) }; let is_const = ty.is_const() || (ty.kind() == CXType_ConstantArray && ty.elem_type() .map_or(false, |element| element.is_const())); let ty = Type::new(name, layout, kind, is_const); // TODO: maybe declaration.canonical()? Ok(ParseResult::New(ty, Some(cursor.canonical()))) } } impl Trace for Type { type Extra = Item; fn trace(&self, context: &BindgenContext, tracer: &mut T, item: &Item) where T: Tracer, { 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.59.1/src/ir/var.rs000064400000000000000000000354200000000000000136460ustar 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::MacroParsingBehavior; use crate::clang; use crate::clang::ClangToken; use crate::parse::{ ClangItemParser, ClangSubItemParser, ParseError, ParseResult, }; use cexpr; use std::io; use std::num::Wrapping; /// The type for a constant variable. #[derive(Debug)] pub enum VarType { /// A boolean. Bool(bool), /// An integer. Int(i64), /// A floating point number. Float(f64), /// A character. Char(u8), /// A string, not necessarily well-formed utf-8. String(Vec), } /// A `Var` is our intermediate representation of a variable. #[derive(Debug)] pub struct Var { /// The name of the variable. name: String, /// The mangled name of the variable. mangled_name: Option, /// 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 fn new( name: String, mangled_name: Option, ty: TypeId, val: Option, is_const: bool, ) -> Var { assert!(!name.is_empty()); Var { name, mangled_name, ty, val, is_const, } } /// Is this variable `const` qualified? pub fn is_const(&self) -> bool { self.is_const } /// The value of this constant variable, if any. pub fn val(&self) -> Option<&VarType> { self.val.as_ref() } /// Get this variable's type. pub fn ty(&self) -> TypeId { self.ty } /// Get this variable's name. pub fn name(&self) -> &str { &self.name } /// Get this variable's mangled name. pub fn mangled_name(&self) -> Option<&str> { self.mangled_name.as_ref().map(|n| &**n) } } 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 < i32::min_value() as i64 || value > i32::max_value() as i64 { IntKind::I64 } else if !ctx.options().fit_macro_constants || value < i16::min_value() as i64 || value > i16::max_value() as i64 { IntKind::I32 } else if value < i8::min_value() as i64 || value > i8::max_value() as i64 { IntKind::I16 } else { IntKind::I8 } } else if value > u32::max_value() as i64 { IntKind::U64 } else if !ctx.options().fit_macro_constants || value > u16::max_value() as i64 { IntKind::U32 } else if value > u8::max_value() as i64 { IntKind::U16 } else { IntKind::U8 } } /// Determines whether a set of tokens from a CXCursor_MacroDefinition /// represent a function-like macro. If so, calls the func_macro callback /// and returns `Err(ParseError::Continue)` to signal to skip further /// processing. If conversion to UTF-8 fails (it is performed only where it /// should be infallible), then `Err(ParseError::Continue)` is returned as well. fn handle_function_macro( cursor: &clang::Cursor, tokens: &[ClangToken], callbacks: &dyn crate::callbacks::ParseCallbacks, ) -> Result<(), ParseError> { // TODO: Hoist the `is_macro_function_like` check into this function's // caller, and thus avoid allocating the `tokens` vector for non-functional // macros. let is_functional_macro = cursor.is_macro_function_like(); if !is_functional_macro { return Ok(()); } let is_closing_paren = |t: &ClangToken| { // Test cheap token kind before comparing exact spellings. t.kind == clang_sys::CXToken_Punctuation && t.spelling() == b")" }; let 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.ok_or(ParseError::Continue)? + 1); let left = left.collect::>().concat(); let left = String::from_utf8(left).map_err(|_| ParseError::Continue)?; let right = spelled; // Drop last token with LLVM < 4.0, due to an LLVM bug. // // See: // https://bugs.llvm.org//show_bug.cgi?id=9069 let len = match (right.len(), crate::clang_version().parsed) { (len, Some((v, _))) if len > 0 && v < 4 => len - 1, (len, _) => len, }; let right: Vec<_> = right.take(len).collect(); callbacks.func_macro(&left, &right); // We handled the macro, skip future macro processing. Err(ParseError::Continue) } 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 => { let tokens: Vec<_> = cursor.tokens().iter().collect(); if let Some(callbacks) = ctx.parse_callbacks() { match callbacks.will_parse_macro(&cursor.spelling()) { MacroParsingBehavior::Ignore => { return Err(ParseError::Continue); } MacroParsingBehavior::Default => {} } handle_function_macro(&cursor, &tokens, callbacks)?; } let value = parse_macro(ctx, &tokens); let (id, value) = match value { Some(v) => v, None => return Err(ParseError::Continue), }; assert!(!id.is_empty(), "Empty macro name?"); let previously_defined = ctx.parsed_macro(&id); // NB: It's important to "note" the macro even if the result is // not an integer, otherwise we might loose other kind of // derived macros. ctx.note_parsed_macro(id.clone(), value.clone()); if previously_defined { let name = String::from_utf8(id).unwrap(); warn!("Duplicated macro definition: {}", name); return Err(ParseError::Continue); } // NOTE: Unwrapping, here and above, is safe, because the // identifier of a token comes straight from clang, and we // enforce utf8 there, so we should have already panicked at // this point. let name = String::from_utf8(id).unwrap(); let (type_kind, val) = match value { EvalResult::Invalid => return Err(ParseError::Continue), EvalResult::Float(f) => { (TypeKind::Float(FloatKind::Double), VarType::Float(f)) } EvalResult::Char(c) => { let c = match c { CChar::Char(c) => { assert_eq!(c.len_utf8(), 1); c as u8 } CChar::Raw(c) => { assert!(c <= ::std::u8::MAX as u64); c as u8 } }; (TypeKind::Int(IntKind::U8), VarType::Char(c)) } EvalResult::Str(val) => { let char_ty = Item::builtin_type( TypeKind::Int(IntKind::U8), true, ctx, ); if let Some(callbacks) = ctx.parse_callbacks() { callbacks.str_macro(&name, &val); } (TypeKind::Pointer(char_ty), VarType::String(val)) } EvalResult::Int(Wrapping(value)) => { let kind = ctx .parse_callbacks() .and_then(|c| c.int_macro(&name, value)) .unwrap_or_else(|| { default_macro_constant_type(&ctx, value) }); (TypeKind::Int(kind), VarType::Int(value)) } }; let ty = Item::builtin_type(type_kind, true, ctx); Ok(ParseResult::New( Var::new(name, None, ty, Some(val), true), Some(cursor), )) } CXCursor_VarDecl => { let name = cursor.spelling(); if name.is_empty() { warn!("Empty constant name?"); return Err(ParseError::Continue); } let ty = cursor.cur_type(); // TODO(emilio): do we have to special-case constant arrays in // some other places? let is_const = ty.is_const() || (ty.kind() == CXType_ConstantArray && ty.elem_type() .map_or(false, |element| element.is_const())); let ty = match Item::from_ty(&ty, cursor, None, ctx) { Ok(ty) => ty, Err(e) => { assert_eq!( ty.kind(), CXType_Auto, "Couldn't resolve constant type, and it \ wasn't an nondeductible auto type!" ); return Err(e); } }; // Note: Ty might not be totally resolved yet, see // tests/headers/inner_const.hpp // // That's fine because in that case we know it's not a literal. let canonical_ty = ctx .safe_resolve_type(ty) .and_then(|t| t.safe_canonical_type(ctx)); let is_integer = canonical_ty.map_or(false, |t| t.is_integer()); let is_float = canonical_ty.map_or(false, |t| t.is_float()); // TODO: We could handle `char` more gracefully. // TODO: Strings, though the lookup is a bit more hard (we need // to look at the canonical type of the pointee too, and check // is char, u8, or i8 I guess). let value = if is_integer { let kind = match *canonical_ty.unwrap().kind() { TypeKind::Int(kind) => kind, _ => unreachable!(), }; let mut val = cursor.evaluate().and_then(|v| v.as_int()); if val.is_none() || !kind.signedness_matches(val.unwrap()) { let tu = ctx.translation_unit(); val = get_integer_literal_from_cursor(&cursor, tu); } val.map(|val| { if kind == IntKind::Bool { VarType::Bool(val != 0) } else { VarType::Int(val) } }) } else if is_float { cursor .evaluate() .and_then(|v| v.as_double()) .map(VarType::Float) } else { cursor .evaluate() .and_then(|v| v.as_literal_string()) .map(VarType::String) }; let mangling = cursor_mangling(ctx, &cursor); let var = Var::new(name, mangling, ty, value, is_const); Ok(ParseResult::New(var, Some(cursor))) } _ => { /* TODO */ Err(ParseError::Continue) } } } } /// Try and parse a macro using all the macros parsed until now. fn parse_macro( ctx: &BindgenContext, tokens: &[ClangToken], ) -> Option<(Vec, cexpr::expr::EvalResult)> { use cexpr::expr; let mut cexpr_tokens: Vec<_> = tokens .iter() .filter_map(ClangToken::as_cexpr_token) .collect(); let parser = expr::IdentifierParser::new(ctx.parsed_macros()); match parser.macro_definition(&cexpr_tokens) { Ok((_, (id, val))) => { return Some((id.into(), val)); } _ => {} } // Try without the last token, to workaround a libclang bug in versions // previous to 4.0. // // See: // https://bugs.llvm.org//show_bug.cgi?id=9069 // https://reviews.llvm.org/D26446 cexpr_tokens.pop()?; match parser.macro_definition(&cexpr_tokens) { Ok((_, (id, val))) => Some((id.into(), val)), _ => None, } } 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, unit: &clang::TranslationUnit, ) -> 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, unit); } _ => (), } if value.is_some() { CXChildVisit_Break } else { CXChildVisit_Continue } }); value } bindgen-0.59.1/src/lib.rs000064400000000000000000002650100000000000000132120ustar 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)] // To avoid rather annoying warnings when matching with CXCursor_xxx as a // constant. #![allow(non_upper_case_globals)] // `quote!` nests quite deeply. #![recursion_limit = "128"] #[macro_use] extern crate bitflags; #[macro_use] extern crate lazy_static; #[macro_use] extern crate quote; #[cfg(feature = "logging")] #[macro_use] extern crate log; #[cfg(not(feature = "logging"))] #[macro_use] mod log_stubs; #[macro_use] mod extra_assertions; // A macro to declare an internal module for which we *must* provide // documentation for. If we are building with the "testing_only_docs" feature, // then the module is declared public, and our `#![deny(missing_docs)]` pragma // applies to it. This feature is used in CI, so we won't let anything slip by // undocumented. Normal builds, however, will leave the module private, so that // we don't expose internals to library consumers. macro_rules! doc_mod { ($m:ident, $doc_mod_name:ident) => { #[cfg(feature = "testing_only_docs")] pub mod $doc_mod_name { //! Autogenerated documentation module. pub use super::$m::*; } }; } mod clang; mod codegen; mod deps; mod features; mod ir; mod parse; mod regex_set; mod time; pub mod callbacks; doc_mod!(clang, clang_docs); doc_mod!(features, features_docs); doc_mod!(ir, ir_docs); doc_mod!(parse, parse_docs); doc_mod!(regex_set, regex_set_docs); pub use crate::codegen::{AliasVariation, EnumVariation, MacroTypeVariation}; use crate::features::RustFeatures; pub use crate::features::{ RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS, }; use crate::ir::context::{BindgenContext, ItemId}; use crate::ir::item::Item; use crate::parse::{ClangItemParser, ParseError}; use crate::regex_set::RegexSet; use std::borrow::Cow; use std::fs::{File, OpenOptions}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::{env, iter}; // Some convenient typedefs for a fast hash map and hash set. type HashMap = ::rustc_hash::FxHashMap; type HashSet = ::rustc_hash::FxHashSet; pub(crate) use std::collections::hash_map::Entry; /// Default prefix for the anon fields. pub const DEFAULT_ANON_FIELDS_PREFIX: &'static str = "__bindgen_anon_"; fn file_is_cpp(name_file: &str) -> bool { name_file.ends_with(".hpp") || name_file.ends_with(".hxx") || name_file.ends_with(".hh") || name_file.ends_with(".h++") } fn args_are_cpp(clang_args: &[String]) -> bool { for w in clang_args.windows(2) { if w[0] == "-xc++" || w[1] == "-xc++" { return true; } if w[0] == "-x" && w[1] == "c++" { return true; } if w[0] == "-include" && file_is_cpp(&w[1]) { return true; } } false } bitflags! { /// A type used to indicate which kind of items we have to generate. pub struct CodegenConfig: u32 { /// Whether to generate functions. const FUNCTIONS = 1 << 0; /// Whether to generate types. const TYPES = 1 << 1; /// Whether to generate constants. const VARS = 1 << 2; /// Whether to generate methods. const METHODS = 1 << 3; /// Whether to generate constructors const CONSTRUCTORS = 1 << 4; /// Whether to generate destructors. const DESTRUCTORS = 1 << 5; } } impl CodegenConfig { /// Returns true if functions should be generated. pub fn functions(self) -> bool { self.contains(CodegenConfig::FUNCTIONS) } /// Returns true if types should be generated. pub fn types(self) -> bool { self.contains(CodegenConfig::TYPES) } /// Returns true if constants should be generated. pub fn vars(self) -> bool { self.contains(CodegenConfig::VARS) } /// Returns true if methds should be generated. pub fn methods(self) -> bool { self.contains(CodegenConfig::METHODS) } /// Returns true if constructors should be generated. pub fn constructors(self) -> bool { self.contains(CodegenConfig::CONSTRUCTORS) } /// Returns true if destructors should be generated. pub fn destructors(self) -> bool { self.contains(CodegenConfig::DESTRUCTORS) } } impl Default for CodegenConfig { fn default() -> Self { CodegenConfig::all() } } /// Configure and generate Rust bindings for a C/C++ header. /// /// This is the main entry point to the library. /// /// ```ignore /// use bindgen::builder; /// /// // Configure and generate bindings. /// let bindings = builder().header("path/to/input/header") /// .allowlist_type("SomeCoolClass") /// .allowlist_function("do_some_cool_thing") /// .generate()?; /// /// // Write the generated bindings to an output file. /// bindings.write_to_file("path/to/output.rs")?; /// ``` /// /// # Enums /// /// Bindgen can map C/C++ enums into Rust in different ways. The way bindgen maps enums depends on /// the pattern passed to several methods: /// /// 1. [`constified_enum_module()`](#method.constified_enum_module) /// 2. [`bitfield_enum()`](#method.bitfield_enum) /// 3. [`newtype_enum()`](#method.newtype_enum) /// 4. [`rustified_enum()`](#method.rustified_enum) /// /// For each C enum, bindgen tries to match the pattern in the following order: /// /// 1. Constified enum module /// 2. Bitfield enum /// 3. Newtype enum /// 4. Rustified enum /// /// If none of the above patterns match, then bindgen will generate a set of Rust constants. /// /// # Clang arguments /// /// Extra arguments can be passed to with clang: /// 1. [`clang_arg()`](#method.clang_arg): takes a single argument /// 2. [`clang_args()`](#method.clang_args): takes an iterator of arguments /// 3. `BINDGEN_EXTRA_CLANG_ARGS` environment variable: whitespace separate /// environment variable of arguments /// /// Clang arguments specific to your crate should be added via the /// `clang_arg()`/`clang_args()` methods. /// /// End-users of the crate may need to set the `BINDGEN_EXTRA_CLANG_ARGS` environment variable to /// add additional arguments. For example, to build against a different sysroot a user could set /// `BINDGEN_EXTRA_CLANG_ARGS` to `--sysroot=/path/to/sysroot`. #[derive(Debug, Default)] pub struct Builder { options: BindgenOptions, input_headers: Vec, // Tuples of unsaved file contents of the form (name, contents). input_header_contents: Vec<(String, String)>, } /// Construct a new [`Builder`](./struct.Builder.html). pub fn builder() -> Builder { Default::default() } impl Builder { /// Generates the command line flags use for creating `Builder`. pub fn command_line_flags(&self) -> Vec { let mut output_vector: Vec = Vec::new(); if let Some(header) = self.input_headers.last().cloned() { // Positional argument 'header' output_vector.push(header); } output_vector.push("--rust-target".into()); output_vector.push(self.options.rust_target.into()); // FIXME(emilio): This is a bit hacky, maybe we should stop re-using the // RustFeatures to store the "disable_untagged_union" call, and make it // a different flag that we check elsewhere / in generate(). if !self.options.rust_features.untagged_union && RustFeatures::from(self.options.rust_target).untagged_union { output_vector.push("--disable-untagged-union".into()); } if self.options.default_enum_style != Default::default() { output_vector.push("--default-enum-style".into()); output_vector.push( match self.options.default_enum_style { codegen::EnumVariation::Rust { non_exhaustive: false, } => "rust", codegen::EnumVariation::Rust { non_exhaustive: true, } => "rust_non_exhaustive", codegen::EnumVariation::NewType { is_bitfield: true } => { "bitfield" } codegen::EnumVariation::NewType { is_bitfield: false } => { "newtype" } codegen::EnumVariation::Consts => "consts", codegen::EnumVariation::ModuleConsts => "moduleconsts", } .into(), ) } if self.options.default_macro_constant_type != Default::default() { output_vector.push("--default-macro-constant-type".into()); output_vector .push(self.options.default_macro_constant_type.as_str().into()); } if self.options.default_alias_style != Default::default() { output_vector.push("--default-alias-style".into()); output_vector .push(self.options.default_alias_style.as_str().into()); } let regex_sets = &[ (&self.options.bitfield_enums, "--bitfield-enum"), (&self.options.newtype_enums, "--newtype-enum"), (&self.options.rustified_enums, "--rustified-enum"), ( &self.options.rustified_non_exhaustive_enums, "--rustified-enum-non-exhaustive", ), ( &self.options.constified_enum_modules, "--constified-enum-module", ), (&self.options.constified_enums, "--constified-enum"), (&self.options.type_alias, "--type-alias"), (&self.options.new_type_alias, "--new-type-alias"), (&self.options.new_type_alias_deref, "--new-type-alias-deref"), (&self.options.blocklisted_types, "--blocklist-type"), (&self.options.blocklisted_functions, "--blocklist-function"), (&self.options.blocklisted_items, "--blocklist-item"), (&self.options.opaque_types, "--opaque-type"), (&self.options.allowlisted_functions, "--allowlist-function"), (&self.options.allowlisted_types, "--allowlist-type"), (&self.options.allowlisted_vars, "--allowlist-var"), (&self.options.no_partialeq_types, "--no-partialeq"), (&self.options.no_copy_types, "--no-copy"), (&self.options.no_debug_types, "--no-debug"), (&self.options.no_default_types, "--no-default"), (&self.options.no_hash_types, "--no-hash"), ]; for (set, flag) in regex_sets { for item in set.get_items() { output_vector.push((*flag).to_owned()); output_vector.push(item.to_owned()); } } if !self.options.layout_tests { output_vector.push("--no-layout-tests".into()); } if self.options.impl_debug { output_vector.push("--impl-debug".into()); } if self.options.impl_partialeq { output_vector.push("--impl-partialeq".into()); } if !self.options.derive_copy { output_vector.push("--no-derive-copy".into()); } if !self.options.derive_debug { output_vector.push("--no-derive-debug".into()); } if !self.options.derive_default { output_vector.push("--no-derive-default".into()); } else { output_vector.push("--with-derive-default".into()); } if self.options.derive_hash { output_vector.push("--with-derive-hash".into()); } if self.options.derive_partialord { output_vector.push("--with-derive-partialord".into()); } if self.options.derive_ord { output_vector.push("--with-derive-ord".into()); } if self.options.derive_partialeq { output_vector.push("--with-derive-partialeq".into()); } if self.options.derive_eq { output_vector.push("--with-derive-eq".into()); } if self.options.time_phases { output_vector.push("--time-phases".into()); } if !self.options.generate_comments { output_vector.push("--no-doc-comments".into()); } if !self.options.allowlist_recursively { output_vector.push("--no-recursive-allowlist".into()); } if self.options.objc_extern_crate { output_vector.push("--objc-extern-crate".into()); } if self.options.generate_block { output_vector.push("--generate-block".into()); } if self.options.block_extern_crate { output_vector.push("--block-extern-crate".into()); } if self.options.builtins { output_vector.push("--builtins".into()); } if let Some(ref prefix) = self.options.ctypes_prefix { output_vector.push("--ctypes-prefix".into()); output_vector.push(prefix.clone()); } if self.options.anon_fields_prefix != DEFAULT_ANON_FIELDS_PREFIX { output_vector.push("--anon-fields-prefix".into()); output_vector.push(self.options.anon_fields_prefix.clone()); } if self.options.emit_ast { output_vector.push("--emit-clang-ast".into()); } if self.options.emit_ir { output_vector.push("--emit-ir".into()); } if let Some(ref graph) = self.options.emit_ir_graphviz { output_vector.push("--emit-ir-graphviz".into()); output_vector.push(graph.clone()) } if self.options.enable_cxx_namespaces { output_vector.push("--enable-cxx-namespaces".into()); } if self.options.enable_function_attribute_detection { output_vector.push("--enable-function-attribute-detection".into()); } if self.options.disable_name_namespacing { output_vector.push("--disable-name-namespacing".into()); } if self.options.disable_nested_struct_naming { output_vector.push("--disable-nested-struct-naming".into()); } if self.options.disable_header_comment { output_vector.push("--disable-header-comment".into()); } if !self.options.codegen_config.functions() { output_vector.push("--ignore-functions".into()); } output_vector.push("--generate".into()); //Temporary placeholder for below 4 options let mut options: Vec = Vec::new(); if self.options.codegen_config.functions() { options.push("functions".into()); } if self.options.codegen_config.types() { options.push("types".into()); } if self.options.codegen_config.vars() { options.push("vars".into()); } if self.options.codegen_config.methods() { options.push("methods".into()); } if self.options.codegen_config.constructors() { options.push("constructors".into()); } if self.options.codegen_config.destructors() { options.push("destructors".into()); } output_vector.push(options.join(",")); if !self.options.codegen_config.methods() { output_vector.push("--ignore-methods".into()); } if !self.options.convert_floats { output_vector.push("--no-convert-floats".into()); } if !self.options.prepend_enum_name { output_vector.push("--no-prepend-enum-name".into()); } if self.options.fit_macro_constants { output_vector.push("--fit-macro-constant-types".into()); } if self.options.array_pointers_in_arguments { output_vector.push("--use-array-pointers-in-arguments".into()); } if let Some(ref wasm_import_module_name) = self.options.wasm_import_module_name { output_vector.push("--wasm-import-module-name".into()); output_vector.push(wasm_import_module_name.clone()); } for line in &self.options.raw_lines { output_vector.push("--raw-line".into()); output_vector.push(line.clone()); } for (module, lines) in &self.options.module_lines { for line in lines.iter() { output_vector.push("--module-raw-line".into()); output_vector.push(module.clone()); output_vector.push(line.clone()); } } if self.options.use_core { output_vector.push("--use-core".into()); } if self.options.conservative_inline_namespaces { output_vector.push("--conservative-inline-namespaces".into()); } if self.options.generate_inline_functions { output_vector.push("--generate-inline-functions".into()); } if !self.options.record_matches { output_vector.push("--no-record-matches".into()); } if self.options.size_t_is_usize { output_vector.push("--size_t-is-usize".into()); } if !self.options.rustfmt_bindings { output_vector.push("--no-rustfmt-bindings".into()); } if let Some(path) = self .options .rustfmt_configuration_file .as_ref() .and_then(|f| f.to_str()) { output_vector.push("--rustfmt-configuration-file".into()); output_vector.push(path.into()); } if let Some(ref name) = self.options.dynamic_library_name { output_vector.push("--dynamic-loading".into()); output_vector.push(name.clone()); } if self.options.dynamic_link_require_all { output_vector.push("--dynamic-link-require-all".into()); } if self.options.respect_cxx_access_specs { output_vector.push("--respect-cxx-access-specs".into()); } if self.options.translate_enum_integer_types { output_vector.push("--translate-enum-integer-types".into()); } if self.options.c_naming { output_vector.push("--c-naming".into()); } if self.options.force_explicit_padding { output_vector.push("--explicit-padding".into()); } // Add clang arguments output_vector.push("--".into()); if !self.options.clang_args.is_empty() { output_vector.extend(self.options.clang_args.iter().cloned()); } if self.input_headers.len() > 1 { // To pass more than one header, we need to pass all but the last // header via the `-include` clang arg for header in &self.input_headers[..self.input_headers.len() - 1] { output_vector.push("-include".to_string()); output_vector.push(header.clone()); } } output_vector } /// Add an input C/C++ header to generate bindings for. /// /// This can be used to generate bindings to a single header: /// /// ```ignore /// let bindings = bindgen::Builder::default() /// .header("input.h") /// .generate() /// .unwrap(); /// ``` /// /// Or you can invoke it multiple times to generate bindings to multiple /// headers: /// /// ```ignore /// let bindings = bindgen::Builder::default() /// .header("first.h") /// .header("second.h") /// .header("third.h") /// .generate() /// .unwrap(); /// ``` pub fn header>(mut self, header: T) -> Builder { self.input_headers.push(header.into()); self } /// Add a depfile output which will be written alongside the generated bindings. pub fn depfile, D: Into>( mut self, output_module: H, depfile: D, ) -> Builder { self.options.depfile = Some(deps::DepfileSpec { output_module: output_module.into(), depfile_path: depfile.into(), }); self } /// Add `contents` as an input C/C++ header named `name`. /// /// The file `name` will be added to the clang arguments. pub fn header_contents(mut self, name: &str, contents: &str) -> Builder { // Apparently clang relies on having virtual FS correspondent to // the real one, so we need absolute paths here let absolute_path = env::current_dir() .expect("Cannot retrieve current directory") .join(name) .to_str() .expect("Cannot convert current directory name to string") .to_owned(); self.input_header_contents .push((absolute_path, contents.into())); self } /// Specify the rust target /// /// The default is the latest stable Rust version pub fn rust_target(mut self, rust_target: RustTarget) -> Self { self.options.set_rust_target(rust_target); self } /// Disable support for native Rust unions, if supported. pub fn disable_untagged_union(mut self) -> Self { self.options.rust_features.untagged_union = false; self } /// Disable insertion of bindgen's version identifier into generated /// bindings. pub fn disable_header_comment(mut self) -> Self { self.options.disable_header_comment = true; self } /// Set the output graphviz file. pub fn emit_ir_graphviz>(mut self, path: T) -> Builder { let path = path.into(); self.options.emit_ir_graphviz = Some(path); self } /// Whether the generated bindings should contain documentation comments /// (docstrings) or not. This is set to true by default. /// /// Note that clang by default excludes comments from system headers, pass /// `-fretain-comments-from-system-headers` as /// [`clang_arg`][Builder::clang_arg] to include them. It can also be told /// to process all comments (not just documentation ones) using the /// `-fparse-all-comments` flag. See [slides on clang comment parsing]( /// https://llvm.org/devmtg/2012-11/Gribenko_CommentParsing.pdf) for /// background and examples. pub fn generate_comments(mut self, doit: bool) -> Self { self.options.generate_comments = doit; self } /// Whether to allowlist recursively or not. Defaults to true. /// /// Given that we have explicitly allowlisted the "initiate_dance_party" /// function in this C header: /// /// ```c /// typedef struct MoonBoots { /// int bouncy_level; /// } MoonBoots; /// /// void initiate_dance_party(MoonBoots* boots); /// ``` /// /// We would normally generate bindings to both the `initiate_dance_party` /// function and the `MoonBoots` struct that it transitively references. By /// configuring with `allowlist_recursively(false)`, `bindgen` will not emit /// bindings for anything except the explicitly allowlisted items, and there /// would be no emitted struct definition for `MoonBoots`. However, the /// `initiate_dance_party` function would still reference `MoonBoots`! /// /// **Disabling this feature will almost certainly cause `bindgen` to emit /// bindings that will not compile!** If you disable this feature, then it /// is *your* responsibility to provide definitions for every type that is /// referenced from an explicitly allowlisted item. One way to provide the /// definitions is by using the [`Builder::raw_line`](#method.raw_line) /// method, another would be to define them in Rust and then `include!(...)` /// the bindings immediately afterwards. pub fn allowlist_recursively(mut self, doit: bool) -> Self { self.options.allowlist_recursively = doit; self } /// Deprecated alias for allowlist_recursively. #[deprecated(note = "Use allowlist_recursively instead")] pub fn whitelist_recursively(self, doit: bool) -> Self { self.allowlist_recursively(doit) } /// Generate `#[macro_use] extern crate objc;` instead of `use objc;` /// in the prologue of the files generated from objective-c files pub fn objc_extern_crate(mut self, doit: bool) -> Self { self.options.objc_extern_crate = doit; self } /// Generate proper block signatures instead of void pointers. pub fn generate_block(mut self, doit: bool) -> Self { self.options.generate_block = doit; self } /// Generate `#[macro_use] extern crate block;` instead of `use block;` /// in the prologue of the files generated from apple block files pub fn block_extern_crate(mut self, doit: bool) -> Self { self.options.block_extern_crate = doit; self } /// Whether to use the clang-provided name mangling. This is true by default /// and probably needed for C++ features. /// /// However, some old libclang versions seem to return incorrect results in /// some cases for non-mangled functions, see [1], so we allow disabling it. /// /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528 pub fn trust_clang_mangling(mut self, doit: bool) -> Self { self.options.enable_mangling = doit; self } /// Hide the given type from the generated bindings. Regular expressions are /// supported. #[deprecated(note = "Use blocklist_type instead")] pub fn hide_type>(self, arg: T) -> Builder { self.blocklist_type(arg) } /// Hide the given type from the generated bindings. Regular expressions are /// supported. #[deprecated(note = "Use blocklist_type instead")] pub fn blacklist_type>(self, arg: T) -> Builder { self.blocklist_type(arg) } /// Hide the given type from the generated bindings. Regular expressions are /// supported. /// /// To blocklist types prefixed with "mylib" use `"mylib_.*"`. /// For more complicated expressions check /// [regex](https://docs.rs/regex/*/regex/) docs pub fn blocklist_type>(mut self, arg: T) -> Builder { self.options.blocklisted_types.insert(arg); self } /// Hide the given function from the generated bindings. Regular expressions /// are supported. #[deprecated(note = "Use blocklist_function instead")] pub fn blacklist_function>(self, arg: T) -> Builder { self.blocklist_function(arg) } /// Hide the given function from the generated bindings. Regular expressions /// are supported. /// /// To blocklist functions prefixed with "mylib" use `"mylib_.*"`. /// For more complicated expressions check /// [regex](https://docs.rs/regex/*/regex/) docs pub fn blocklist_function>(mut self, arg: T) -> Builder { self.options.blocklisted_functions.insert(arg); self } /// Hide the given item from the generated bindings, regardless of /// whether it's a type, function, module, etc. Regular /// expressions are supported. #[deprecated(note = "Use blocklist_item instead")] pub fn blacklist_item>(mut self, arg: T) -> Builder { self.options.blocklisted_items.insert(arg); self } /// Hide the given item from the generated bindings, regardless of /// whether it's a type, function, module, etc. Regular /// expressions are supported. /// /// To blocklist items prefixed with "mylib" use `"mylib_.*"`. /// For more complicated expressions check /// [regex](https://docs.rs/regex/*/regex/) docs pub fn blocklist_item>(mut self, arg: T) -> Builder { self.options.blocklisted_items.insert(arg); self } /// Treat the given type as opaque in the generated bindings. Regular /// expressions are supported. /// /// To change types prefixed with "mylib" into opaque, use `"mylib_.*"`. /// For more complicated expressions check /// [regex](https://docs.rs/regex/*/regex/) docs pub fn opaque_type>(mut self, arg: T) -> Builder { self.options.opaque_types.insert(arg); self } /// Allowlist the given type so that it (and all types that it transitively /// refers to) appears in the generated bindings. Regular expressions are /// supported. #[deprecated(note = "use allowlist_type instead")] pub fn whitelisted_type>(self, arg: T) -> Builder { self.allowlist_type(arg) } /// Allowlist the given type so that it (and all types that it transitively /// refers to) appears in the generated bindings. Regular expressions are /// supported. #[deprecated(note = "use allowlist_type instead")] pub fn whitelist_type>(self, arg: T) -> Builder { self.allowlist_type(arg) } /// Allowlist the given type so that it (and all types that it transitively /// refers to) appears in the generated bindings. Regular expressions are /// supported. /// /// To allowlist types prefixed with "mylib" use `"mylib_.*"`. /// For more complicated expressions check /// [regex](https://docs.rs/regex/*/regex/) docs pub fn allowlist_type>(mut self, arg: T) -> Builder { self.options.allowlisted_types.insert(arg); self } /// Allowlist the given function so that it (and all types that it /// transitively refers to) appears in the generated bindings. Regular /// expressions are supported. /// /// To allowlist functions prefixed with "mylib" use `"mylib_.*"`. /// For more complicated expressions check /// [regex](https://docs.rs/regex/*/regex/) docs pub fn allowlist_function>(mut self, arg: T) -> Builder { self.options.allowlisted_functions.insert(arg); self } /// Allowlist the given function. /// /// Deprecated: use allowlist_function instead. #[deprecated(note = "use allowlist_function instead")] pub fn whitelist_function>(self, arg: T) -> Builder { self.allowlist_function(arg) } /// Allowlist the given function. /// /// Deprecated: use allowlist_function instead. #[deprecated(note = "use allowlist_function instead")] pub fn whitelisted_function>(self, arg: T) -> Builder { self.allowlist_function(arg) } /// Allowlist the given variable so that it (and all types that it /// transitively refers to) appears in the generated bindings. Regular /// expressions are supported. /// /// To allowlist variables prefixed with "mylib" use `"mylib_.*"`. /// For more complicated expressions check /// [regex](https://docs.rs/regex/*/regex/) docs pub fn allowlist_var>(mut self, arg: T) -> Builder { self.options.allowlisted_vars.insert(arg); self } /// Deprecated: use allowlist_var instead. #[deprecated(note = "use allowlist_var instead")] pub fn whitelist_var>(self, arg: T) -> Builder { self.allowlist_var(arg) } /// Allowlist the given variable. /// /// Deprecated: use allowlist_var instead. #[deprecated(note = "use allowlist_var instead")] pub fn whitelisted_var>(self, arg: T) -> Builder { self.allowlist_var(arg) } /// Set the default style of code to generate for enums pub fn default_enum_style( mut self, arg: codegen::EnumVariation, ) -> Builder { self.options.default_enum_style = arg; self } /// Mark the given enum (or set of enums, if using a pattern) as being /// bitfield-like. Regular expressions are supported. /// /// This makes bindgen generate a type that isn't a rust `enum`. Regular /// expressions are supported. /// /// This is similar to the newtype enum style, but with the bitwise /// operators implemented. pub fn bitfield_enum>(mut self, arg: T) -> Builder { self.options.bitfield_enums.insert(arg); self } /// Mark the given enum (or set of enums, if using a pattern) as a newtype. /// Regular expressions are supported. /// /// This makes bindgen generate a type that isn't a Rust `enum`. Regular /// expressions are supported. pub fn newtype_enum>(mut self, arg: T) -> Builder { self.options.newtype_enums.insert(arg); self } /// Mark the given enum (or set of enums, if using a pattern) as a Rust /// enum. /// /// This makes bindgen generate enums instead of constants. Regular /// expressions are supported. /// /// **Use this with caution**, creating this in unsafe code /// (including FFI) with an invalid value will invoke undefined behaviour. /// You may want to use the newtype enum style instead. pub fn rustified_enum>(mut self, arg: T) -> Builder { self.options.rustified_enums.insert(arg); self } /// Mark the given enum (or set of enums, if using a pattern) as a Rust /// enum with the `#[non_exhaustive]` attribute. /// /// This makes bindgen generate enums instead of constants. Regular /// expressions are supported. /// /// **Use this with caution**, creating this in unsafe code /// (including FFI) with an invalid value will invoke undefined behaviour. /// You may want to use the newtype enum style instead. pub fn rustified_non_exhaustive_enum>( mut self, arg: T, ) -> Builder { self.options.rustified_non_exhaustive_enums.insert(arg); self } /// Mark the given enum (or set of enums, if using a pattern) as a set of /// constants that are not to be put into a module. pub fn constified_enum>(mut self, arg: T) -> Builder { self.options.constified_enums.insert(arg); self } /// Mark the given enum (or set of enums, if using a pattern) as a set of /// constants that should be put into a module. /// /// This makes bindgen generate modules containing constants instead of /// just constants. Regular expressions are supported. pub fn constified_enum_module>(mut self, arg: T) -> Builder { self.options.constified_enum_modules.insert(arg); self } /// Set the default type for macro constants pub fn default_macro_constant_type( mut self, arg: codegen::MacroTypeVariation, ) -> Builder { self.options.default_macro_constant_type = arg; self } /// Set the default style of code to generate for typedefs pub fn default_alias_style( mut self, arg: codegen::AliasVariation, ) -> Builder { self.options.default_alias_style = arg; self } /// Mark the given typedef alias (or set of aliases, if using a pattern) to /// use regular Rust type aliasing. /// /// This is the default behavior and should be used if `default_alias_style` /// was set to NewType or NewTypeDeref and you want to override it for a /// set of typedefs. pub fn type_alias>(mut self, arg: T) -> Builder { self.options.type_alias.insert(arg); self } /// Mark the given typedef alias (or set of aliases, if using a pattern) to /// be generated as a new type by having the aliased type be wrapped in a /// #[repr(transparent)] struct. /// /// Used to enforce stricter type checking. pub fn new_type_alias>(mut self, arg: T) -> Builder { self.options.new_type_alias.insert(arg); self } /// Mark the given typedef alias (or set of aliases, if using a pattern) to /// be generated as a new type by having the aliased type be wrapped in a /// #[repr(transparent)] struct and also have an automatically generated /// impl's of `Deref` and `DerefMut` to their aliased type. pub fn new_type_alias_deref>(mut self, arg: T) -> Builder { self.options.new_type_alias_deref.insert(arg); self } /// Add a string to prepend to 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()); self } /// Add a given line to the beginning of module `mod`. pub fn module_raw_line(mut self, mod_: T, line: U) -> Self where T: Into, U: Into, { self.options .module_lines .entry(mod_.into()) .or_insert_with(Vec::new) .push(line.into()); self } /// Add a given set of lines to the beginning of module `mod`. pub fn module_raw_lines(mut self, mod_: T, lines: I) -> Self where T: Into, I: IntoIterator, I::Item: Into, { self.options .module_lines .entry(mod_.into()) .or_insert_with(Vec::new) .extend(lines.into_iter().map(Into::into)); self } /// Add an argument to be passed straight through to clang. pub fn clang_arg>(mut self, arg: T) -> Builder { self.options.clang_args.push(arg.into()); self } /// Add arguments to be passed straight through to clang. pub fn clang_args(mut self, iter: I) -> Builder where I: IntoIterator, I::Item: AsRef, { for arg in iter { self = self.clang_arg(arg.as_ref()) } self } /// Emit bindings for builtin definitions (for example `__builtin_va_list`) /// in the generated Rust. pub fn emit_builtins(mut self) -> Builder { self.options.builtins = true; self } /// Avoid converting floats to `f32`/`f64` by default. pub fn no_convert_floats(mut self) -> Self { self.options.convert_floats = false; self } /// Set whether layout tests should be generated. pub fn layout_tests(mut self, doit: bool) -> Self { self.options.layout_tests = doit; self } /// Set whether `Debug` should be implemented, if it can not be derived automatically. pub fn impl_debug(mut self, doit: bool) -> Self { self.options.impl_debug = doit; self } /// Set whether `PartialEq` should be implemented, if it can not be derived automatically. pub fn impl_partialeq(mut self, doit: bool) -> Self { self.options.impl_partialeq = doit; self } /// Set whether `Copy` should be derived by default. pub fn derive_copy(mut self, doit: bool) -> Self { self.options.derive_copy = doit; self } /// Set whether `Debug` should be derived by default. pub fn derive_debug(mut self, doit: bool) -> Self { self.options.derive_debug = doit; self } /// Set whether `Default` should be derived by default. pub fn derive_default(mut self, doit: bool) -> Self { self.options.derive_default = doit; self } /// Set whether `Hash` should be derived by default. pub fn derive_hash(mut self, doit: bool) -> Self { self.options.derive_hash = doit; self } /// Set whether `PartialOrd` should be derived by default. /// If we don't compute partialord, we also cannot compute /// ord. Set the derive_ord to `false` when doit is `false`. pub fn derive_partialord(mut self, doit: bool) -> Self { self.options.derive_partialord = doit; if !doit { self.options.derive_ord = false; } self } /// Set whether `Ord` should be derived by default. /// We can't compute `Ord` without computing `PartialOrd`, /// so we set the same option to derive_partialord. pub fn derive_ord(mut self, doit: bool) -> Self { self.options.derive_ord = doit; self.options.derive_partialord = doit; self } /// Set whether `PartialEq` should be derived by default. /// /// If we don't derive `PartialEq`, we also cannot derive `Eq`, so deriving /// `Eq` is also disabled when `doit` is `false`. pub fn derive_partialeq(mut self, doit: bool) -> Self { self.options.derive_partialeq = doit; if !doit { self.options.derive_eq = false; } self } /// Set whether `Eq` should be derived by default. /// /// We can't derive `Eq` without also deriving `PartialEq`, so we also /// enable deriving `PartialEq` when `doit` is `true`. pub fn derive_eq(mut self, doit: bool) -> Self { self.options.derive_eq = doit; if doit { self.options.derive_partialeq = doit; } self } /// Set whether or not to time bindgen phases, and print information to /// stderr. pub fn time_phases(mut self, doit: bool) -> Self { self.options.time_phases = doit; self } /// Emit Clang AST. pub fn emit_clang_ast(mut self) -> Builder { self.options.emit_ast = true; self } /// Emit IR. pub fn emit_ir(mut self) -> Builder { self.options.emit_ir = true; self } /// Enable C++ namespaces. pub fn enable_cxx_namespaces(mut self) -> Builder { self.options.enable_cxx_namespaces = true; self } /// Enable detecting must_use attributes on C functions. /// /// This is quite slow in some cases (see #1465), so it's disabled by /// default. /// /// Note that for this to do something meaningful for now at least, the rust /// target version has to have support for `#[must_use]`. pub fn enable_function_attribute_detection(mut self) -> Self { self.options.enable_function_attribute_detection = true; self } /// Disable name auto-namespacing. /// /// By default, bindgen mangles names like `foo::bar::Baz` to look like /// `foo_bar_Baz` instead of just `Baz`. /// /// This method disables that behavior. /// /// Note that this intentionally does not change the names used for /// allowlisting and blocklisting, which should still be mangled with the /// namespaces. /// /// Note, also, that this option may cause bindgen to generate duplicate /// names. pub fn disable_name_namespacing(mut self) -> Builder { self.options.disable_name_namespacing = true; self } /// Disable nested struct naming. /// /// The following structs have different names for C and C++. In case of C /// they are visible as `foo` and `bar`. In case of C++ they are visible as /// `foo` and `foo::bar`. /// /// ```c /// struct foo { /// struct bar { /// } b; /// }; /// ``` /// /// Bindgen wants to avoid duplicate names by default so it follows C++ naming /// and it generates `foo`/`foo_bar` instead of just `foo`/`bar`. /// /// This method disables this behavior and it is indented to be used only /// for headers that were written for C. pub fn disable_nested_struct_naming(mut self) -> Builder { self.options.disable_nested_struct_naming = true; self } /// Treat inline namespaces conservatively. /// /// This is tricky, because in C++ is technically legal to override an item /// defined in an inline namespace: /// /// ```cpp /// inline namespace foo { /// using Bar = int; /// } /// using Bar = long; /// ``` /// /// Even though referencing `Bar` is a compiler error. /// /// We want to support this (arguably esoteric) use case, but we don't want /// to make the rest of bindgen users pay an usability penalty for that. /// /// To support this, we need to keep all the inline namespaces around, but /// then bindgen usage is a bit more difficult, because you cannot /// reference, e.g., `std::string` (you'd need to use the proper inline /// namespace). /// /// We could complicate a lot of the logic to detect name collisions, and if /// not detected generate a `pub use inline_ns::*` or something like that. /// /// That's probably something we can do if we see this option is needed in a /// lot of cases, to improve it's usability, but my guess is that this is /// not going to be too useful. pub fn conservative_inline_namespaces(mut self) -> Builder { self.options.conservative_inline_namespaces = true; self } /// Whether inline functions should be generated or not. /// /// Note that they will usually not work. However you can use /// `-fkeep-inline-functions` or `-fno-inline-functions` if you are /// responsible of compiling the library to make them callable. pub fn generate_inline_functions(mut self, doit: bool) -> Self { self.options.generate_inline_functions = doit; self } /// Ignore functions. pub fn ignore_functions(mut self) -> Builder { self.options.codegen_config.remove(CodegenConfig::FUNCTIONS); self } /// Ignore methods. pub fn ignore_methods(mut self) -> Builder { self.options.codegen_config.remove(CodegenConfig::METHODS); self } /// Avoid generating any unstable Rust, such as Rust unions, in the generated bindings. #[deprecated(note = "please use `rust_target` instead")] pub fn unstable_rust(self, doit: bool) -> Self { let rust_target = if doit { RustTarget::Nightly } else { LATEST_STABLE_RUST }; self.rust_target(rust_target) } /// Use core instead of libstd in the generated bindings. pub fn use_core(mut self) -> Builder { self.options.use_core = true; self } /// Use the given prefix for the raw types instead of `::std::os::raw`. pub fn ctypes_prefix>(mut self, prefix: T) -> Builder { self.options.ctypes_prefix = Some(prefix.into()); self } /// Use the given prefix for the anon fields. pub fn anon_fields_prefix>(mut self, prefix: T) -> Builder { self.options.anon_fields_prefix = prefix.into(); self } /// Allows configuring types in different situations, see the /// [`ParseCallbacks`](./callbacks/trait.ParseCallbacks.html) documentation. pub fn parse_callbacks( mut self, cb: Box, ) -> Self { self.options.parse_callbacks = Some(cb); self } /// Choose what to generate using a /// [`CodegenConfig`](./struct.CodegenConfig.html). pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self { self.options.codegen_config = config; self } /// Whether to detect include paths using clang_sys. pub fn detect_include_paths(mut self, doit: bool) -> Self { self.options.detect_include_paths = doit; self } /// Whether to try to fit macro constants to types smaller than u32/i32 pub fn fit_macro_constants(mut self, doit: bool) -> Self { self.options.fit_macro_constants = doit; self } /// Prepend the enum name to constant or newtype variants. pub fn prepend_enum_name(mut self, doit: bool) -> Self { self.options.prepend_enum_name = doit; self } /// Set whether `size_t` should be translated to `usize` automatically. pub fn size_t_is_usize(mut self, is: bool) -> Self { self.options.size_t_is_usize = is; self } /// Set whether rustfmt should format the generated bindings. pub fn rustfmt_bindings(mut self, doit: bool) -> Self { self.options.rustfmt_bindings = doit; self } /// Set whether we should record matched items in our regex sets. pub fn record_matches(mut self, doit: bool) -> Self { self.options.record_matches = doit; self } /// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt /// options are used. pub fn rustfmt_configuration_file(mut self, path: Option) -> Self { self = self.rustfmt_bindings(true); self.options.rustfmt_configuration_file = path; self } /// Sets an explicit path to rustfmt, to be used when rustfmt is enabled. pub fn with_rustfmt>(mut self, path: P) -> Self { self.options.rustfmt_path = Some(path.into()); self } /// If true, always emit explicit padding fields. /// /// If a struct needs to be serialized in its native format (padding bytes /// and all), for example writing it to a file or sending it on the network, /// then this should be enabled, as anything reading the padding bytes of /// a struct may lead to Undefined Behavior. pub fn explicit_padding(mut self, doit: bool) -> Self { self.options.force_explicit_padding = doit; self } /// Generate the Rust bindings using the options built up thus far. pub fn generate(mut self) -> Result { // Add any extra arguments from the environment to the clang command line. if let Some(extra_clang_args) = get_target_dependent_env_var("BINDGEN_EXTRA_CLANG_ARGS") { // 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) { self.options.clang_args.extend(strings); } else { self.options.clang_args.push(extra_clang_args); }; } // Transform input headers to arguments on the clang command line. self.options.input_header = self.input_headers.pop(); self.options.extra_input_headers = self.input_headers; self.options.clang_args.extend( self.options.extra_input_headers.iter().flat_map(|header| { iter::once("-include".into()) .chain(iter::once(header.to_string())) }), ); self.options.input_unsaved_files.extend( self.input_header_contents .drain(..) .map(|(name, contents)| { clang::UnsavedFile::new(&name, &contents) }), ); Bindings::generate(self.options) } /// Preprocess and dump the input header files to disk. /// /// This is useful when debugging bindgen, using C-Reduce, or when filing /// issues. The resulting file will be named something like `__bindgen.i` or /// `__bindgen.ii` pub fn dump_preprocessed_input(&self) -> io::Result<()> { let clang = clang_sys::support::Clang::find(None, &[]).ok_or_else(|| { io::Error::new( io::ErrorKind::Other, "Cannot find clang executable", ) })?; // The contents of a wrapper file that includes all the input header // files. let mut wrapper_contents = String::new(); // Whether we are working with C or C++ inputs. let mut is_cpp = args_are_cpp(&self.options.clang_args); // For each input header, add `#include "$header"`. for header in &self.input_headers { is_cpp |= file_is_cpp(header); wrapper_contents.push_str("#include \""); wrapper_contents.push_str(header); wrapper_contents.push_str("\"\n"); } // For each input header content, add a prefix line of `#line 0 "$name"` // followed by the contents. for &(ref name, ref contents) in &self.input_header_contents { is_cpp |= file_is_cpp(name); wrapper_contents.push_str("#line 0 \""); wrapper_contents.push_str(name); wrapper_contents.push_str("\"\n"); wrapper_contents.push_str(contents); } let wrapper_path = PathBuf::from(if is_cpp { "__bindgen.cpp" } else { "__bindgen.c" }); { let mut wrapper_file = File::create(&wrapper_path)?; wrapper_file.write_all(wrapper_contents.as_bytes())?; } let mut cmd = Command::new(&clang.path); cmd.arg("-save-temps") .arg("-E") .arg("-C") .arg("-c") .arg(&wrapper_path) .stdout(Stdio::piped()); for a in &self.options.clang_args { cmd.arg(a); } let mut child = cmd.spawn()?; let mut preprocessed = child.stdout.take().unwrap(); let mut file = File::create(if is_cpp { "__bindgen.ii" } else { "__bindgen.i" })?; io::copy(&mut preprocessed, &mut file)?; if child.wait()?.success() { Ok(()) } else { Err(io::Error::new( io::ErrorKind::Other, "clang exited with non-zero status", )) } } /// Don't derive `PartialEq` for a given type. Regular /// expressions are supported. pub fn no_partialeq>(mut self, arg: T) -> Builder { self.options.no_partialeq_types.insert(arg.into()); self } /// Don't derive `Copy` for a given type. Regular /// expressions are supported. pub fn no_copy>(mut self, arg: T) -> Self { self.options.no_copy_types.insert(arg.into()); self } /// Don't derive `Debug` for a given type. Regular /// expressions are supported. pub fn no_debug>(mut self, arg: T) -> Self { self.options.no_debug_types.insert(arg.into()); self } /// Don't derive/impl `Default` for a given type. Regular /// expressions are supported. pub fn no_default>(mut self, arg: T) -> Self { self.options.no_default_types.insert(arg.into()); self } /// Don't derive `Hash` for a given type. Regular /// expressions are supported. pub fn no_hash>(mut self, arg: T) -> Builder { self.options.no_hash_types.insert(arg.into()); self } /// Set whether `arr[size]` should be treated as `*mut T` or `*mut [T; size]` (same for mut) pub fn array_pointers_in_arguments(mut self, doit: bool) -> Self { self.options.array_pointers_in_arguments = doit; self } /// Set the wasm import module name pub fn wasm_import_module_name>( mut self, import_name: T, ) -> Self { self.options.wasm_import_module_name = Some(import_name.into()); self } /// Specify the dynamic library name if we are generating bindings for a shared library. pub fn dynamic_library_name>( mut self, dynamic_library_name: T, ) -> Self { self.options.dynamic_library_name = Some(dynamic_library_name.into()); self } /// Require successful linkage for all routines in a shared library. /// This allows us to optimize function calls by being able to safely assume function pointers /// are valid. pub fn dynamic_link_require_all(mut self, req: bool) -> Self { self.options.dynamic_link_require_all = req; self } /// Generate bindings as `pub` only if the bound item is publically accessible by C++. pub fn respect_cxx_access_specs(mut self, doit: bool) -> Self { self.options.respect_cxx_access_specs = doit; self } /// Always translate enum integer types to native Rust integer types. /// /// This will result in enums having types such as `u32` and `i16` instead /// of `c_uint` and `c_short`. Types for Rustified enums are always /// translated. pub fn translate_enum_integer_types(mut self, doit: bool) -> Self { self.options.translate_enum_integer_types = doit; self } /// Generate types with C style naming. /// /// This will add prefixes to the generated type names. For example instead of a struct `A` we /// will generate struct `struct_A`. Currently applies to structs, unions, and enums. pub fn c_naming(mut self, doit: bool) -> Self { self.options.c_naming = doit; self } } /// Configuration options for generated bindings. #[derive(Debug)] struct BindgenOptions { /// The set of types that have been blocklisted and should not appear /// anywhere in the generated code. blocklisted_types: RegexSet, /// The set of functions that have been blocklisted and should not appear /// in the generated code. blocklisted_functions: RegexSet, /// The set of items, regardless of item-type, that have been /// blocklisted and should not appear in the generated code. blocklisted_items: RegexSet, /// The set of types that should be treated as opaque structures in the /// generated code. opaque_types: RegexSet, /// The explicit rustfmt path. rustfmt_path: Option, /// The path to which we should write a Makefile-syntax depfile (if any). depfile: Option, /// The set of types that we should have bindings for in the generated /// code. /// /// This includes all types transitively reachable from any type in this /// set. One might think of allowlisted types/vars/functions as GC roots, /// and the generated Rust code as including everything that gets marked. allowlisted_types: RegexSet, /// Allowlisted functions. See docs for `allowlisted_types` for more. allowlisted_functions: RegexSet, /// Allowlisted variables. See docs for `allowlisted_types` for more. allowlisted_vars: RegexSet, /// The default style of code to generate for enums default_enum_style: codegen::EnumVariation, /// The enum patterns to mark an enum as a bitfield /// (newtype with bitwise operations). bitfield_enums: RegexSet, /// The enum patterns to mark an enum as a newtype. newtype_enums: RegexSet, /// The enum patterns to mark an enum as a Rust enum. rustified_enums: RegexSet, /// The enum patterns to mark an enum as a non-exhaustive Rust enum. rustified_non_exhaustive_enums: RegexSet, /// The enum patterns to mark an enum as a module of constants. constified_enum_modules: RegexSet, /// The enum patterns to mark an enum as a set of constants. constified_enums: RegexSet, /// The default type for C macro constants. default_macro_constant_type: codegen::MacroTypeVariation, /// The default style of code to generate for typedefs. default_alias_style: codegen::AliasVariation, /// Typedef patterns that will use regular type aliasing. type_alias: RegexSet, /// Typedef patterns that will be aliased by creating a new struct. new_type_alias: RegexSet, /// Typedef patterns that will be wrapped in a new struct and have /// Deref and Deref to their aliased type. new_type_alias_deref: RegexSet, /// Whether we should generate builtins or not. builtins: bool, /// True if we should dump the Clang AST for debugging purposes. emit_ast: bool, /// True if we should dump our internal IR for debugging purposes. emit_ir: bool, /// Output graphviz dot file. emit_ir_graphviz: Option, /// True if we should emulate C++ namespaces with Rust modules in the /// generated bindings. enable_cxx_namespaces: bool, /// True if we should try to find unexposed attributes in functions, in /// order to be able to generate #[must_use] attributes in Rust. enable_function_attribute_detection: bool, /// True if we should avoid mangling names with namespaces. disable_name_namespacing: bool, /// True if we should avoid generating nested struct names. disable_nested_struct_naming: bool, /// True if we should avoid embedding version identifiers into source code. disable_header_comment: bool, /// True if we should generate layout tests for generated structures. layout_tests: bool, /// True if we should implement the Debug trait for C/C++ structures and types /// that do not support automatically deriving Debug. impl_debug: bool, /// True if we should implement the PartialEq trait for C/C++ structures and types /// that do not support automatically deriving PartialEq. impl_partialeq: bool, /// True if we should derive Copy trait implementations for C/C++ structures /// and types. derive_copy: bool, /// True if we should derive Debug trait implementations for C/C++ structures /// and types. derive_debug: bool, /// True if we should derive Default trait implementations for C/C++ structures /// and types. derive_default: bool, /// True if we should derive Hash trait implementations for C/C++ structures /// and types. derive_hash: bool, /// True if we should derive PartialOrd trait implementations for C/C++ structures /// and types. derive_partialord: bool, /// True if we should derive Ord trait implementations for C/C++ structures /// and types. derive_ord: bool, /// True if we should derive PartialEq trait implementations for C/C++ structures /// and types. derive_partialeq: bool, /// True if we should derive Eq trait implementations for C/C++ structures /// and types. derive_eq: bool, /// True if we should avoid using libstd to use libcore instead. use_core: bool, /// An optional prefix for the "raw" types, like `c_int`, `c_void`... ctypes_prefix: Option, /// The prefix for the anon fields. anon_fields_prefix: String, /// Whether to time the bindgen phases. time_phases: bool, /// True if we should generate constant names that are **directly** under /// namespaces. namespaced_constants: bool, /// True if we should use MSVC name mangling rules. msvc_mangling: bool, /// Whether we should convert float types to f32/f64 types. convert_floats: bool, /// The set of raw lines to prepend to the top-level module of generated /// Rust code. raw_lines: Vec, /// The set of raw lines to prepend to each of the modules. /// /// This only makes sense if the `enable_cxx_namespaces` option is set. module_lines: HashMap>, /// The set of arguments to pass straight through to Clang. clang_args: Vec, /// The input header file. input_header: Option, /// Any additional input header files. extra_input_headers: Vec, /// Unsaved files for input. input_unsaved_files: Vec, /// A user-provided visitor to allow customizing different kinds of /// situations. parse_callbacks: Option>, /// Which kind of items should we generate? By default, we'll generate all /// of them. codegen_config: CodegenConfig, /// Whether to treat inline namespaces conservatively. /// /// See the builder method description for more details. conservative_inline_namespaces: bool, /// Whether to keep documentation comments in the generated output. See the /// documentation for more details. Defaults to true. generate_comments: bool, /// Whether to generate inline functions. Defaults to false. generate_inline_functions: bool, /// Whether to allowlist types recursively. Defaults to true. allowlist_recursively: bool, /// Instead of emitting 'use objc;' to files generated from objective c files, /// generate '#[macro_use] extern crate objc;' objc_extern_crate: bool, /// Instead of emitting 'use block;' to files generated from objective c files, /// generate '#[macro_use] extern crate block;' generate_block: bool, /// Instead of emitting 'use block;' to files generated from objective c files, /// generate '#[macro_use] extern crate block;' block_extern_crate: bool, /// Whether to use the clang-provided name mangling. This is true and /// probably needed for C++ features. /// /// However, some old libclang versions seem to return incorrect results in /// some cases for non-mangled functions, see [1], so we allow disabling it. /// /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528 enable_mangling: bool, /// Whether to detect include paths using clang_sys. detect_include_paths: bool, /// Whether to try to fit macro constants into types smaller than u32/i32 fit_macro_constants: bool, /// Whether to prepend the enum name to constant or newtype variants. prepend_enum_name: bool, /// Version of the Rust compiler to target rust_target: RustTarget, /// Features to enable, derived from `rust_target` rust_features: RustFeatures, /// Whether we should record which items in the regex sets ever matched. /// /// This may be a bit slower, but will enable reporting of unused allowlist /// items via the `error!` log. record_matches: bool, /// Whether `size_t` should be translated to `usize` automatically. size_t_is_usize: bool, /// Whether rustfmt should format the generated bindings. rustfmt_bindings: bool, /// The absolute path to the rustfmt configuration file, if None, the standard rustfmt /// options are used. rustfmt_configuration_file: Option, /// The set of types that we should not derive `PartialEq` for. no_partialeq_types: RegexSet, /// The set of types that we should not derive `Copy` for. no_copy_types: RegexSet, /// The set of types that we should not derive `Debug` for. no_debug_types: RegexSet, /// The set of types that we should not derive/impl `Default` for. no_default_types: RegexSet, /// The set of types that we should not derive `Hash` for. no_hash_types: RegexSet, /// Decide if C arrays should be regular pointers in rust or array pointers array_pointers_in_arguments: bool, /// Wasm import module name. wasm_import_module_name: Option, /// The name of the dynamic library (if we are generating bindings for a shared library). If /// this is None, no dynamic bindings are created. dynamic_library_name: Option, /// Require successful linkage for all routines in a shared library. /// This allows us to optimize function calls by being able to safely assume function pointers /// are valid. No effect if `dynamic_library_name` is None. dynamic_link_require_all: bool, /// Only make generated bindings `pub` if the items would be publically accessible /// by C++. respect_cxx_access_specs: bool, /// Always translate enum integer types to native Rust integer types. translate_enum_integer_types: bool, /// Generate types with C style naming. c_naming: bool, /// Always output explicit padding fields force_explicit_padding: bool, } /// TODO(emilio): This is sort of a lie (see the error message that results from /// removing this), but since we don't share references across panic boundaries /// it's ok. impl ::std::panic::UnwindSafe for BindgenOptions {} impl BindgenOptions { fn build(&mut self) { let mut regex_sets = [ &mut self.allowlisted_vars, &mut self.allowlisted_types, &mut self.allowlisted_functions, &mut self.blocklisted_types, &mut self.blocklisted_functions, &mut self.blocklisted_items, &mut self.opaque_types, &mut self.bitfield_enums, &mut self.constified_enums, &mut self.constified_enum_modules, &mut self.newtype_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.no_partialeq_types, &mut self.no_copy_types, &mut self.no_debug_types, &mut self.no_default_types, &mut self.no_hash_types, ]; let record_matches = self.record_matches; for regex_set in &mut regex_sets { regex_set.build(record_matches); } } /// Update rust target version pub fn set_rust_target(&mut self, rust_target: RustTarget) { self.rust_target = rust_target; // Keep rust_features synced with rust_target self.rust_features = rust_target.into(); } /// Get features supported by target Rust version pub fn rust_features(&self) -> RustFeatures { self.rust_features } } impl Default for BindgenOptions { fn default() -> BindgenOptions { let rust_target = RustTarget::default(); BindgenOptions { rust_target, rust_features: rust_target.into(), blocklisted_types: Default::default(), blocklisted_functions: Default::default(), blocklisted_items: Default::default(), opaque_types: Default::default(), rustfmt_path: Default::default(), depfile: Default::default(), allowlisted_types: Default::default(), allowlisted_functions: Default::default(), allowlisted_vars: Default::default(), default_enum_style: Default::default(), bitfield_enums: Default::default(), newtype_enums: Default::default(), rustified_enums: Default::default(), rustified_non_exhaustive_enums: Default::default(), constified_enums: Default::default(), constified_enum_modules: Default::default(), default_macro_constant_type: Default::default(), default_alias_style: Default::default(), type_alias: Default::default(), new_type_alias: Default::default(), new_type_alias_deref: Default::default(), builtins: false, emit_ast: false, emit_ir: false, emit_ir_graphviz: None, layout_tests: true, impl_debug: false, impl_partialeq: false, derive_copy: true, derive_debug: true, derive_default: false, derive_hash: false, derive_partialord: false, derive_ord: false, derive_partialeq: false, derive_eq: false, enable_cxx_namespaces: false, enable_function_attribute_detection: false, disable_name_namespacing: false, disable_nested_struct_naming: false, disable_header_comment: false, use_core: false, ctypes_prefix: None, anon_fields_prefix: DEFAULT_ANON_FIELDS_PREFIX.into(), namespaced_constants: true, msvc_mangling: false, convert_floats: true, raw_lines: vec![], module_lines: HashMap::default(), clang_args: vec![], input_header: None, extra_input_headers: vec![], input_unsaved_files: vec![], parse_callbacks: None, codegen_config: CodegenConfig::all(), conservative_inline_namespaces: false, generate_comments: true, generate_inline_functions: false, allowlist_recursively: true, generate_block: false, objc_extern_crate: false, block_extern_crate: false, enable_mangling: true, detect_include_paths: true, fit_macro_constants: false, prepend_enum_name: true, time_phases: false, record_matches: true, rustfmt_bindings: true, size_t_is_usize: false, rustfmt_configuration_file: None, no_partialeq_types: Default::default(), no_copy_types: Default::default(), no_debug_types: Default::default(), no_default_types: Default::default(), no_hash_types: Default::default(), array_pointers_in_arguments: false, wasm_import_module_name: None, dynamic_library_name: None, dynamic_link_require_all: false, respect_cxx_access_specs: false, translate_enum_integer_types: false, c_naming: false, force_explicit_padding: false, } } } #[cfg(feature = "runtime")] fn ensure_libclang_is_loaded() { if clang_sys::is_loaded() { return; } // XXX (issue #350): Ensure that our dynamically loaded `libclang` // doesn't get dropped prematurely, nor is loaded multiple times // across different threads. lazy_static! { static ref LIBCLANG: std::sync::Arc = { clang_sys::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() {} /// Generated Rust bindings. #[derive(Debug)] pub struct Bindings { options: BindgenOptions, module: proc_macro2::TokenStream, } pub(crate) const HOST_TARGET: &'static str = include_str!(concat!(env!("OUT_DIR"), "/host-target.txt")); // Some architecture triplets are different between rust and libclang, see #1211 // and duplicates. fn rust_to_clang_target(rust_target: &str) -> String { if rust_target.starts_with("aarch64-apple-") { let mut clang_target = "arm64-apple-".to_owned(); clang_target.push_str(&rust_target["aarch64-apple-".len()..]); return clang_target; } rust_target.to_owned() } /// Returns the effective target, and whether it was explicitly specified on the /// clang flags. fn find_effective_target(clang_args: &[String]) -> (String, bool) { let mut args = clang_args.iter(); while let Some(opt) = args.next() { if opt.starts_with("--target=") { let mut split = opt.split('='); split.next(); return (split.next().unwrap().to_owned(), true); } if opt == "-target" { if let Some(target) = args.next() { return (target.clone(), true); } } } // If we're running from a build script, try to find the cargo target. if let Ok(t) = env::var("TARGET") { return (rust_to_clang_target(&t), false); } (rust_to_clang_target(HOST_TARGET), false) } impl Bindings { /// Generate bindings for the given options. pub(crate) fn generate( mut options: BindgenOptions, ) -> Result { ensure_libclang_is_loaded(); #[cfg(feature = "runtime")] debug!( "Generating bindings, libclang at {}", clang_sys::get_library().unwrap().path().display() ); #[cfg(not(feature = "runtime"))] debug!("Generating bindings, libclang linked"); options.build(); let (effective_target, explicit_target) = find_effective_target(&options.clang_args); let is_host_build = rust_to_clang_target(HOST_TARGET) == effective_target; // NOTE: The is_host_build check wouldn't be sound normally in some // cases if we were to call a binary (if you have a 32-bit clang and are // building on a 64-bit system for example). But since we rely on // opening libclang.so, it has to be the same architecture and thus the // check is fine. if !explicit_target && !is_host_build { options .clang_args .insert(0, format!("--target={}", effective_target)); }; fn detect_include_paths(options: &mut BindgenOptions) { if !options.detect_include_paths { return; } // Filter out include paths and similar stuff, so we don't incorrectly // promote them to `-isystem`. let clang_args_for_clang_sys = { let mut last_was_include_prefix = false; options .clang_args .iter() .filter(|arg| { if last_was_include_prefix { last_was_include_prefix = false; return false; } let arg = &**arg; // https://clang.llvm.org/docs/ClangCommandLineReference.html // -isystem and -isystem-after are harmless. if arg == "-I" || arg == "--include-directory" { last_was_include_prefix = true; return false; } if arg.starts_with("-I") || arg.starts_with("--include-directory=") { return false; } true }) .cloned() .collect::>() }; debug!( "Trying to find clang with flags: {:?}", clang_args_for_clang_sys ); let clang = match clang_sys::support::Clang::find( None, &clang_args_for_clang_sys, ) { None => return, Some(clang) => clang, }; debug!("Found clang: {:?}", clang); // Whether we are working with C or C++ inputs. let is_cpp = args_are_cpp(&options.clang_args) || options .input_header .as_ref() .map_or(false, |i| file_is_cpp(&i)); let search_paths = if is_cpp { clang.cpp_search_paths } else { clang.c_search_paths }; if let Some(search_paths) = search_paths { for path in search_paths.into_iter() { if let Ok(path) = path.into_os_string().into_string() { options.clang_args.push("-isystem".to_owned()); options.clang_args.push(path); } } } } detect_include_paths(&mut options); #[cfg(unix)] fn can_read(perms: &std::fs::Permissions) -> bool { use std::os::unix::fs::PermissionsExt; perms.mode() & 0o444 > 0 } #[cfg(not(unix))] fn can_read(_: &std::fs::Permissions) -> bool { true } if let Some(h) = options.input_header.as_ref() { if let Ok(md) = std::fs::metadata(h) { if md.is_dir() { eprintln!("error: '{}' is a folder", h); return Err(()); } if !can_read(&md.permissions()) { eprintln!( "error: insufficient permissions to read '{}'", h ); return Err(()); } options.clang_args.push(h.clone()) } else { eprintln!("error: header '{}' does not exist.", h); return Err(()); } } for (idx, f) in options.input_unsaved_files.iter().enumerate() { if idx != 0 || options.input_header.is_some() { options.clang_args.push("-include".to_owned()); } options.clang_args.push(f.name.to_str().unwrap().to_owned()) } debug!("Fixed-up options: {:?}", options); let time_phases = options.time_phases; let mut context = BindgenContext::new(options); if is_host_build { debug_assert_eq!( context.target_pointer_size(), std::mem::size_of::<*mut ()>(), "{:?} {:?}", effective_target, HOST_TARGET ); } { let _t = time::Timer::new("parse").with_output(time_phases); parse(&mut context)?; } let (items, options) = codegen::codegen(context); Ok(Bindings { options, module: quote! { #( #items )* }, }) } /// Convert these bindings into source text (with raw lines prepended). pub fn to_string(&self) -> String { let mut bytes = vec![]; self.write(Box::new(&mut bytes) as Box) .expect("writing to a vec cannot fail"); String::from_utf8(bytes) .expect("we should only write bindings that are valid utf-8") } /// 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<()> { if !self.options.disable_header_comment { let version = option_env!("CARGO_PKG_VERSION"); let header = format!( "/* automatically generated by rust-bindgen {} */\n\n", version.unwrap_or("(unknown version)") ); writer.write_all(header.as_bytes())?; } for line in self.options.raw_lines.iter() { writer.write_all(line.as_bytes())?; writer.write_all("\n".as_bytes())?; } if !self.options.raw_lines.is_empty() { writer.write_all("\n".as_bytes())?; } let bindings = self.module.to_string(); match self.rustfmt_generated_string(&bindings) { Ok(rustfmt_bindings) => { writer.write_all(rustfmt_bindings.as_bytes())?; } Err(err) => { eprintln!( "Failed to run rustfmt: {} (non-fatal, continuing)", err ); writer.write_all(bindings.as_bytes())?; } } Ok(()) } /// Gets the rustfmt path to rustfmt the generated bindings. fn rustfmt_path<'a>(&'a self) -> io::Result> { debug_assert!(self.options.rustfmt_bindings); if let Some(ref p) = self.options.rustfmt_path { return Ok(Cow::Borrowed(p)); } if let Ok(rustfmt) = env::var("RUSTFMT") { return Ok(Cow::Owned(rustfmt.into())); } #[cfg(feature = "which-rustfmt")] match which::which("rustfmt") { Ok(p) => Ok(Cow::Owned(p)), Err(e) => { Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))) } } #[cfg(not(feature = "which-rustfmt"))] // No rustfmt binary was specified, so assume that the binary is called // "rustfmt" and that it is in the user's PATH. Ok(Cow::Owned("rustfmt".into())) } /// Checks if rustfmt_bindings is set and runs rustfmt on the string fn rustfmt_generated_string<'a>( &self, source: &'a str, ) -> io::Result> { let _t = time::Timer::new("rustfmt_generated_string") .with_output(self.options.time_phases); if !self.options.rustfmt_bindings { return Ok(Cow::Borrowed(source)); } let rustfmt = self.rustfmt_path()?; let mut cmd = Command::new(&*rustfmt); cmd.stdin(Stdio::piped()).stdout(Stdio::piped()); if let Some(path) = self .options .rustfmt_configuration_file .as_ref() .and_then(|f| f.to_str()) { cmd.args(&["--config-path", path]); } let mut child = cmd.spawn()?; let mut child_stdin = child.stdin.take().unwrap(); let mut child_stdout = child.stdout.take().unwrap(); let source = source.to_owned(); // Write to stdin in a new thread, so that we can read from stdout on this // thread. This keeps the child from blocking on writing to its stdout which // might block us from writing to its stdin. let stdin_handle = ::std::thread::spawn(move || { let _ = child_stdin.write_all(source.as_bytes()); source }); let mut output = vec![]; io::copy(&mut child_stdout, &mut output)?; let status = child.wait()?; let source = stdin_handle.join().expect( "The thread writing to rustfmt's stdin doesn't do \ anything that could panic", ); match String::from_utf8(output) { Ok(bindings) => match status.code() { Some(0) => Ok(Cow::Owned(bindings)), Some(2) => Err(io::Error::new( io::ErrorKind::Other, "Rustfmt parsing errors.".to_string(), )), Some(3) => { warn!("Rustfmt could not format some lines."); Ok(Cow::Owned(bindings)) } _ => Err(io::Error::new( io::ErrorKind::Other, "Internal rustfmt error".to_string(), )), }, _ => Ok(Cow::Owned(source)), } } } /// 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, ) -> clang_sys::CXChildVisitResult { if !filter_builtins(ctx, &cursor) { return CXChildVisit_Continue; } use clang_sys::CXChildVisit_Continue; match Item::parse(cursor, parent, ctx) { Ok(..) => {} Err(ParseError::Continue) => {} Err(ParseError::Recurse) => { cursor.visit(|child| parse_one(ctx, child, parent)); } } CXChildVisit_Continue } /// Parse the Clang AST into our `Item` internal representation. fn parse(context: &mut BindgenContext) -> Result<(), ()> { use clang_sys::*; let mut any_error = false; for d in context.translation_unit().diags().iter() { let msg = d.format(); let is_err = d.severity() >= CXDiagnostic_Error; eprintln!("{}, err: {}", msg, is_err); any_error |= is_err; } if any_error { return Err(()); } let cursor = context.translation_unit().cursor(); if context.options().emit_ast { fn dump_if_not_builtin(cur: &clang::Cursor) -> CXChildVisitResult { if !cur.is_builtin() { clang::ast_dump(&cur, 0) } else { CXChildVisit_Continue } } cursor.visit(|cur| dump_if_not_builtin(&cur)); } let root = context.root_module(); context.with_module(root, |context| { cursor.visit(|cursor| parse_one(context, cursor, None)) }); assert!( context.current_module() == context.root_module(), "How did this happen?" ); Ok(()) } /// Extracted Clang version data #[derive(Debug)] pub struct ClangVersion { /// Major and minor semver, if parsing was successful pub parsed: Option<(u32, u32)>, /// full version string pub full: String, } /// Get the major and the minor semver numbers of Clang's version pub fn clang_version() -> ClangVersion { ensure_libclang_is_loaded(); //Debian clang version 11.0.1-2 let raw_v: String = clang::extract_clang_version(); let split_v: Option> = raw_v .split_whitespace() .filter(|t| t.chars().next().map_or(false, |v| v.is_ascii_digit())) .next() .map(|v| v.split('.').collect()); match split_v { Some(v) => { if v.len() >= 2 { let maybe_major = v[0].parse::(); let maybe_minor = v[1].parse::(); match (maybe_major, maybe_minor) { (Ok(major), Ok(minor)) => { return ClangVersion { parsed: Some((major, minor)), full: raw_v.clone(), } } _ => {} } } } None => {} }; ClangVersion { parsed: None, full: raw_v.clone(), } } /// Looks for the env var `var_${TARGET}`, and falls back to just `var` when it is not found. fn get_target_dependent_env_var(var: &str) -> Option { if let Ok(target) = env::var("TARGET") { if let Ok(v) = env::var(&format!("{}_{}", var, target)) { return Some(v); } if let Ok(v) = env::var(&format!("{}_{}", var, target.replace("-", "_"))) { return Some(v); } } env::var(var).ok() } /// A ParseCallbacks implementation that will act on file includes by echoing a rerun-if-changed /// line /// /// When running in side a `build.rs` script, this can be used to make cargo invalidate the /// generated bindings whenever any of the files included from the header change: /// ``` /// use bindgen::builder; /// let bindings = builder() /// .header("path/to/input/header") /// .parse_callbacks(Box::new(bindgen::CargoCallbacks)) /// .generate(); /// ``` #[derive(Debug)] pub struct CargoCallbacks; impl callbacks::ParseCallbacks for CargoCallbacks { fn include_file(&self, filename: &str) { println!("cargo:rerun-if-changed={}", filename); } } /// Test command_line_flag function. #[test] fn commandline_flag_unit_test_function() { //Test 1 let bindings = crate::builder(); let command_line_flags = bindings.command_line_flags(); let test_cases = vec![ "--rust-target", "--no-derive-default", "--generate", "functions,types,vars,methods,constructors,destructors", ] .iter() .map(|&x| x.into()) .collect::>(); assert!(test_cases .iter() .all(|ref x| command_line_flags.contains(x),)); //Test 2 let bindings = crate::builder() .header("input_header") .allowlist_type("Distinct_Type") .allowlist_function("safe_function"); let command_line_flags = bindings.command_line_flags(); let test_cases = vec![ "--rust-target", "input_header", "--no-derive-default", "--generate", "functions,types,vars,methods,constructors,destructors", "--allowlist-type", "Distinct_Type", "--allowlist-function", "safe_function", ] .iter() .map(|&x| x.into()) .collect::>(); println!("{:?}", command_line_flags); assert!(test_cases .iter() .all(|ref x| command_line_flags.contains(x),)); } #[test] fn test_rust_to_clang_target() { assert_eq!(rust_to_clang_target("aarch64-apple-ios"), "arm64-apple-ios"); } bindgen-0.59.1/src/log_stubs.rs000064400000000000000000000017230000000000000144440ustar 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, $($arg)*); }; ($($arg:tt)*) => { log!("", $($arg)*); }; } macro_rules! warn { (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }; ($($arg:tt)*) => { log!("", $($arg)*); }; } macro_rules! info { (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }; ($($arg:tt)*) => { log!("", $($arg)*); }; } macro_rules! debug { (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }; ($($arg:tt)*) => { log!("", $($arg)*); }; } macro_rules! trace { (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }; ($($arg:tt)*) => { log!("", $($arg)*); }; } bindgen-0.59.1/src/main.rs000064400000000000000000000063060000000000000133710ustar 00000000000000extern crate bindgen; #[cfg(feature = "logging")] extern crate env_logger; #[macro_use] #[cfg(feature = "logging")] extern crate log; extern crate clap; use bindgen::clang_version; use std::env; use std::panic; #[macro_use] #[cfg(not(feature = "logging"))] mod log_stubs; mod options; use crate::options::builder_from_flags; fn clang_version_check() { let version = clang_version(); let expected_version = if cfg!(feature = "testing_only_libclang_9") { Some((9, 0)) } else if cfg!(feature = "testing_only_libclang_5") { Some((5, 0)) } else if cfg!(feature = "testing_only_libclang_4") { Some((4, 0)) } else if cfg!(feature = "testing_only_libclang_3_9") { Some((3, 9)) } else { None }; info!( "Clang Version: {}, parsed: {:?}", version.full, version.parsed ); if expected_version.is_some() { assert_eq!(version.parsed, version.parsed); } } pub fn main() { #[cfg(feature = "logging")] env_logger::init(); let bind_args: Vec<_> = env::args().collect(); match builder_from_flags(bind_args.into_iter()) { Ok((builder, output, verbose)) => { clang_version_check(); let builder_result = panic::catch_unwind(|| { builder.generate().expect("Unable to generate bindings") }); if builder_result.is_err() { if verbose { print_verbose_err(); } std::process::exit(1); } let bindings = builder_result.unwrap(); bindings.write(output).expect("Unable to write output"); } Err(error) => { println!("{}", error); std::process::exit(1); } }; } fn print_verbose_err() { println!("Bindgen unexpectedly panicked"); println!( "This may be caused by one of the known-unsupported \ things (https://rust-lang.github.io/rust-bindgen/cpp.html), \ please modify the bindgen flags to work around it as \ described in https://rust-lang.github.io/rust-bindgen/cpp.html" ); println!( "Otherwise, please file an issue at \ https://github.com/rust-lang/rust-bindgen/issues/new" ); } #[cfg(test)] mod test { fn build_flags_output_helper(builder: &bindgen::Builder) { let mut command_line_flags = builder.command_line_flags(); command_line_flags.insert(0, "bindgen".to_string()); let flags_quoted: Vec = command_line_flags .iter() .map(|x| format!("{}", shlex::quote(x))) .collect(); let flags_str = flags_quoted.join(" "); println!("{}", flags_str); let (builder, _output, _verbose) = crate::options::builder_from_flags(command_line_flags.into_iter()) .unwrap(); builder.generate().expect("failed to generate bindings"); } #[test] fn commandline_multiple_headers() { let bindings = bindgen::Builder::default() .header("tests/headers/char.h") .header("tests/headers/func_ptr.h") .header("tests/headers/16-byte-alignment.h"); build_flags_output_helper(&bindings); } } bindgen-0.59.1/src/options.rs000064400000000000000000001102200000000000000141270ustar 00000000000000use bindgen::{ builder, AliasVariation, Builder, CodegenConfig, EnumVariation, MacroTypeVariation, RustTarget, DEFAULT_ANON_FIELDS_PREFIX, RUST_TARGET_STRINGS, }; use clap::{App, Arg}; use std::fs::File; use std::io::{self, stderr, Error, ErrorKind, Write}; use std::path::PathBuf; use std::str::FromStr; /// Construct a new [`Builder`](./struct.Builder.html) from command line flags. pub fn builder_from_flags( args: I, ) -> Result<(Builder, Box, bool), io::Error> where I: Iterator, { let rust_target_help = format!( "Version of the Rust compiler to target. Valid options are: {:?}. Defaults to {:?}.", RUST_TARGET_STRINGS, String::from(RustTarget::default()) ); let matches = App::new("bindgen") .version(option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")) .about("Generates Rust bindings from C/C++ headers.") .usage("bindgen [FLAGS] [OPTIONS]
-- ...") .args(&[ Arg::with_name("header") .help("C or C++ header file") .required(true), Arg::with_name("depfile") .long("depfile") .takes_value(true) .help("Path to write depfile to"), Arg::with_name("default-enum-style") .long("default-enum-style") .help("The default style of code used to generate enums.") .value_name("variant") .default_value("consts") .possible_values(&[ "consts", "moduleconsts", "bitfield", "newtype", "rust", "rust_non_exhaustive", ]) .multiple(false), Arg::with_name("bitfield-enum") .long("bitfield-enum") .help( "Mark any enum whose name matches as a set of \ bitfield flags.", ) .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("newtype-enum") .long("newtype-enum") .help("Mark any enum whose name matches as a newtype.") .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("rustified-enum") .long("rustified-enum") .help("Mark any enum whose name matches as a Rust enum.") .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("constified-enum") .long("constified-enum") .help( "Mark any enum whose name matches as a series of \ constants.", ) .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("constified-enum-module") .long("constified-enum-module") .help( "Mark any enum whose name matches as a module of \ constants.", ) .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("default-macro-constant-type") .long("default-macro-constant-type") .help("The default signed/unsigned type for C macro constants.") .value_name("variant") .default_value("unsigned") .possible_values(&["signed", "unsigned"]) .multiple(false), Arg::with_name("default-alias-style") .long("default-alias-style") .help("The default style of code used to generate typedefs.") .value_name("variant") .default_value("type_alias") .possible_values(&[ "type_alias", "new_type", "new_type_deref", ]) .multiple(false), Arg::with_name("normal-alias") .long("normal-alias") .help( "Mark any typedef alias whose name matches to use \ normal type aliasing.", ) .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("new-type-alias") .long("new-type-alias") .help( "Mark any typedef alias whose name matches to have \ a new type generated for it.", ) .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("new-type-alias-deref") .long("new-type-alias-deref") .help( "Mark any typedef alias whose name matches to have \ a new type with Deref and DerefMut to the inner type.", ) .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("blocklist-type") .alias("blacklist-type") .long("blocklist-type") .help("Mark as hidden.") .value_name("type") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("blocklist-function") .alias("blacklist-function") .long("blocklist-function") .help("Mark as hidden.") .value_name("function") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("blocklist-item") .alias("blacklist-item") .long("blocklist-item") .help("Mark as hidden.") .value_name("item") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("no-layout-tests") .long("no-layout-tests") .help("Avoid generating layout tests for any type."), Arg::with_name("no-derive-copy") .long("no-derive-copy") .help("Avoid deriving Copy on any type."), Arg::with_name("no-derive-debug") .long("no-derive-debug") .help("Avoid deriving Debug on any type."), Arg::with_name("no-derive-default") .long("no-derive-default") .hidden(true) .help("Avoid deriving Default on any type."), Arg::with_name("impl-debug").long("impl-debug").help( "Create Debug implementation, if it can not be derived \ automatically.", ), Arg::with_name("impl-partialeq") .long("impl-partialeq") .help( "Create PartialEq implementation, if it can not be derived \ automatically.", ), Arg::with_name("with-derive-default") .long("with-derive-default") .help("Derive Default on any type."), Arg::with_name("with-derive-hash") .long("with-derive-hash") .help("Derive hash on any type."), Arg::with_name("with-derive-partialeq") .long("with-derive-partialeq") .help("Derive partialeq on any type."), Arg::with_name("with-derive-partialord") .long("with-derive-partialord") .help("Derive partialord on any type."), Arg::with_name("with-derive-eq") .long("with-derive-eq") .help( "Derive eq on any type. Enable this option also \ enables --with-derive-partialeq", ), Arg::with_name("with-derive-ord") .long("with-derive-ord") .help( "Derive ord on any type. Enable this option also \ enables --with-derive-partialord", ), Arg::with_name("no-doc-comments") .long("no-doc-comments") .help( "Avoid including doc comments in the output, see: \ https://github.com/rust-lang/rust-bindgen/issues/426", ), Arg::with_name("no-recursive-allowlist") .long("no-recursive-allowlist") .alias("no-recursive-whitelist") .help( "Disable allowlisting types recursively. This will cause \ bindgen to emit Rust code that won't compile! See the \ `bindgen::Builder::allowlist_recursively` method's \ documentation for details.", ), Arg::with_name("objc-extern-crate") .long("objc-extern-crate") .help("Use extern crate instead of use for objc."), Arg::with_name("generate-block") .long("generate-block") .help("Generate block signatures instead of void pointers."), Arg::with_name("block-extern-crate") .long("block-extern-crate") .help("Use extern crate instead of use for block."), Arg::with_name("distrust-clang-mangling") .long("distrust-clang-mangling") .help("Do not trust the libclang-provided mangling"), Arg::with_name("builtins").long("builtins").help( "Output bindings for builtin definitions, e.g. \ __builtin_va_list.", ), Arg::with_name("ctypes-prefix") .long("ctypes-prefix") .help( "Use the given prefix before raw types instead of \ ::std::os::raw.", ) .value_name("prefix") .takes_value(true), Arg::with_name("anon-fields-prefix") .long("anon-fields-prefix") .help("Use the given prefix for the anon fields.") .value_name("prefix") .default_value(DEFAULT_ANON_FIELDS_PREFIX) .takes_value(true), Arg::with_name("time-phases") .long("time-phases") .help("Time the different bindgen phases and print to stderr"), // All positional arguments after the end of options marker, `--` Arg::with_name("clang-args").last(true).multiple(true), Arg::with_name("emit-clang-ast") .long("emit-clang-ast") .help("Output the Clang AST for debugging purposes."), Arg::with_name("emit-ir") .long("emit-ir") .help("Output our internal IR for debugging purposes."), Arg::with_name("emit-ir-graphviz") .long("emit-ir-graphviz") .help("Dump graphviz dot file.") .value_name("path") .takes_value(true), Arg::with_name("enable-cxx-namespaces") .long("enable-cxx-namespaces") .help("Enable support for C++ namespaces."), Arg::with_name("disable-name-namespacing") .long("disable-name-namespacing") .help( "Disable namespacing via mangling, causing bindgen to \ generate names like \"Baz\" instead of \"foo_bar_Baz\" \ for an input name \"foo::bar::Baz\".", ), Arg::with_name("disable-nested-struct-naming") .long("disable-nested-struct-naming") .help( "Disable nested struct naming, causing bindgen to generate \ names like \"bar\" instead of \"foo_bar\" for a nested \ definition \"struct foo { struct bar { } b; };\"." ), Arg::with_name("disable-untagged-union") .long("disable-untagged-union") .help( "Disable support for native Rust unions.", ), Arg::with_name("disable-header-comment") .long("disable-header-comment") .help("Suppress insertion of bindgen's version identifier into generated bindings.") .multiple(true), Arg::with_name("ignore-functions") .long("ignore-functions") .help( "Do not generate bindings for functions or methods. This \ is useful when you only care about struct layouts.", ), Arg::with_name("generate") .long("generate") .help( "Generate only given items, split by commas. \ Valid values are \"functions\",\"types\", \"vars\", \ \"methods\", \"constructors\" and \"destructors\".", ) .takes_value(true), Arg::with_name("ignore-methods") .long("ignore-methods") .help("Do not generate bindings for methods."), Arg::with_name("no-convert-floats") .long("no-convert-floats") .help("Do not automatically convert floats to f32/f64."), Arg::with_name("no-prepend-enum-name") .long("no-prepend-enum-name") .help("Do not prepend the enum name to constant or newtype variants."), Arg::with_name("no-include-path-detection") .long("no-include-path-detection") .help("Do not try to detect default include paths"), Arg::with_name("fit-macro-constant-types") .long("fit-macro-constant-types") .help("Try to fit macro constants into types smaller than u32/i32"), Arg::with_name("unstable-rust") .long("unstable-rust") .help("Generate unstable Rust code (deprecated; use --rust-target instead).") .multiple(true), // FIXME: Pass legacy test suite Arg::with_name("opaque-type") .long("opaque-type") .help("Mark as opaque.") .value_name("type") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("output") .short("o") .long("output") .help("Write Rust bindings to .") .takes_value(true), Arg::with_name("raw-line") .long("raw-line") .help("Add a raw line of Rust code at the beginning of output.") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("module-raw-line") .long("module-raw-line") .help("Add a raw line of Rust code to a given module.") .takes_value(true) .multiple(true) .number_of_values(2) .value_names(&["module-name", "raw-line"]), Arg::with_name("rust-target") .long("rust-target") .help(&rust_target_help) .takes_value(true), Arg::with_name("use-core") .long("use-core") .help("Use types from Rust core instead of std."), Arg::with_name("conservative-inline-namespaces") .long("conservative-inline-namespaces") .help( "Conservatively generate inline namespaces to avoid name \ conflicts.", ), Arg::with_name("use-msvc-mangling") .long("use-msvc-mangling") .help("MSVC C++ ABI mangling. DEPRECATED: Has no effect."), Arg::with_name("allowlist-function") .long("allowlist-function") .alias("whitelist-function") .help( "Allowlist all the free-standing functions matching \ . Other non-allowlisted functions will not be \ generated.", ) .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("generate-inline-functions") .long("generate-inline-functions") .help("Generate inline functions."), Arg::with_name("allowlist-type") .long("allowlist-type") .alias("whitelist-type") .help( "Only generate types matching . Other non-allowlisted types will \ not be generated.", ) .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("allowlist-var") .long("allowlist-var") .alias("whitelist-var") .help( "Allowlist all the free-standing variables matching \ . Other non-allowlisted variables will not be \ generated.", ) .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("verbose") .long("verbose") .help("Print verbose error messages."), Arg::with_name("dump-preprocessed-input") .long("dump-preprocessed-input") .help( "Preprocess and dump the input header files to disk. \ Useful when debugging bindgen, using C-Reduce, or when \ filing issues. The resulting file will be named \ something like `__bindgen.i` or `__bindgen.ii`.", ), Arg::with_name("no-record-matches") .long("no-record-matches") .help( "Do not record matching items in the regex sets. \ This disables reporting of unused items.", ), Arg::with_name("size_t-is-usize") .long("size_t-is-usize") .help("Translate size_t to usize."), Arg::with_name("no-rustfmt-bindings") .long("no-rustfmt-bindings") .help("Do not format the generated bindings with rustfmt."), Arg::with_name("rustfmt-bindings") .long("rustfmt-bindings") .help( "Format the generated bindings with rustfmt. DEPRECATED: \ --rustfmt-bindings is now enabled by default. Disable \ with --no-rustfmt-bindings.", ), Arg::with_name("rustfmt-configuration-file") .long("rustfmt-configuration-file") .help( "The absolute path to the rustfmt configuration file. \ The configuration file will be used for formatting the bindings. \ This parameter is incompatible with --no-rustfmt-bindings.", ) .value_name("path") .takes_value(true) .multiple(false) .number_of_values(1), Arg::with_name("no-partialeq") .long("no-partialeq") .help("Avoid deriving PartialEq for types matching .") .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("no-copy") .long("no-copy") .help("Avoid deriving Copy for types matching .") .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("no-debug") .long("no-debug") .help("Avoid deriving Debug for types matching .") .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("no-default") .long("no-default") .help("Avoid deriving/implement Default for types matching .") .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("no-hash") .long("no-hash") .help("Avoid deriving Hash for types matching .") .value_name("regex") .takes_value(true) .multiple(true) .number_of_values(1), Arg::with_name("enable-function-attribute-detection") .long("enable-function-attribute-detection") .help( "Enables detecting unexposed attributes in functions (slow). Used to generate #[must_use] annotations.", ), Arg::with_name("use-array-pointers-in-arguments") .long("use-array-pointers-in-arguments") .help("Use `*const [T; size]` instead of `*const T` for C arrays"), Arg::with_name("wasm-import-module-name") .long("wasm-import-module-name") .value_name("name") .takes_value(true) .help("The name to be used in a #[link(wasm_import_module = ...)] statement"), Arg::with_name("dynamic-loading") .long("dynamic-loading") .takes_value(true) .help("Use dynamic loading mode with the given library name."), Arg::with_name("dynamic-link-require-all") .long("dynamic-link-require-all") .help("Require successful linkage to all functions in the library."), Arg::with_name("respect-cxx-access-specs") .long("respect-cxx-access-specs") .help("Makes generated bindings `pub` only for items if the items are publically accessible in C++."), Arg::with_name("translate-enum-integer-types") .long("translate-enum-integer-types") .help("Always translate enum integer types to native Rust integer types."), Arg::with_name("c-naming") .long("c-naming") .help("Generate types with C style naming."), Arg::with_name("explicit-padding") .long("explicit-padding") .help("Always output explicit padding fields."), ]) // .args() .get_matches_from(args); let mut builder = builder(); if let Some(header) = matches.value_of("header") { builder = builder.header(header); } else { return Err(Error::new(ErrorKind::Other, "Header not found")); } if matches.is_present("unstable-rust") { builder = builder.rust_target(RustTarget::Nightly); writeln!( &mut stderr(), "warning: the `--unstable-rust` option is deprecated" ) .expect("Unable to write error message"); } if let Some(rust_target) = matches.value_of("rust-target") { builder = builder.rust_target(RustTarget::from_str(rust_target)?); } if let Some(variant) = matches.value_of("default-enum-style") { builder = builder.default_enum_style(EnumVariation::from_str(variant)?) } if let Some(bitfields) = matches.values_of("bitfield-enum") { for regex in bitfields { builder = builder.bitfield_enum(regex); } } if let Some(newtypes) = matches.values_of("newtype-enum") { for regex in newtypes { builder = builder.newtype_enum(regex); } } if let Some(rustifieds) = matches.values_of("rustified-enum") { for regex in rustifieds { builder = builder.rustified_enum(regex); } } if let Some(const_enums) = matches.values_of("constified-enum") { for regex in const_enums { builder = builder.constified_enum(regex); } } if let Some(constified_mods) = matches.values_of("constified-enum-module") { for regex in constified_mods { builder = builder.constified_enum_module(regex); } } if let Some(variant) = matches.value_of("default-macro-constant-type") { builder = builder .default_macro_constant_type(MacroTypeVariation::from_str(variant)?) } if let Some(variant) = matches.value_of("default-alias-style") { builder = builder.default_alias_style(AliasVariation::from_str(variant)?); } if let Some(type_alias) = matches.values_of("normal-alias") { for regex in type_alias { builder = builder.type_alias(regex); } } if let Some(new_type) = matches.values_of("new-type-alias") { for regex in new_type { builder = builder.new_type_alias(regex); } } if let Some(new_type_deref) = matches.values_of("new-type-alias-deref") { for regex in new_type_deref { builder = builder.new_type_alias_deref(regex); } } if let Some(hidden_types) = matches.values_of("blocklist-type") { for ty in hidden_types { builder = builder.blocklist_type(ty); } } if let Some(hidden_functions) = matches.values_of("blocklist-function") { for fun in hidden_functions { builder = builder.blocklist_function(fun); } } if let Some(hidden_identifiers) = matches.values_of("blocklist-item") { for id in hidden_identifiers { builder = builder.blocklist_item(id); } } if matches.is_present("builtins") { builder = builder.emit_builtins(); } if matches.is_present("no-layout-tests") { builder = builder.layout_tests(false); } if matches.is_present("no-derive-copy") { builder = builder.derive_copy(false); } if matches.is_present("no-derive-debug") { builder = builder.derive_debug(false); } if matches.is_present("impl-debug") { builder = builder.impl_debug(true); } if matches.is_present("impl-partialeq") { builder = builder.impl_partialeq(true); } if matches.is_present("with-derive-default") { builder = builder.derive_default(true); } if matches.is_present("with-derive-hash") { builder = builder.derive_hash(true); } if matches.is_present("with-derive-partialeq") { builder = builder.derive_partialeq(true); } if matches.is_present("with-derive-partialord") { builder = builder.derive_partialord(true); } if matches.is_present("with-derive-eq") { builder = builder.derive_eq(true); } if matches.is_present("with-derive-ord") { builder = builder.derive_ord(true); } if matches.is_present("no-derive-default") { builder = builder.derive_default(false); } if matches.is_present("no-prepend-enum-name") { builder = builder.prepend_enum_name(false); } if matches.is_present("no-include-path-detection") { builder = builder.detect_include_paths(false); } if matches.is_present("fit-macro-constant-types") { builder = builder.fit_macro_constants(true); } if matches.is_present("time-phases") { builder = builder.time_phases(true); } if matches.is_present("use-array-pointers-in-arguments") { builder = builder.array_pointers_in_arguments(true); } if let Some(wasm_import_name) = matches.value_of("wasm-import-module-name") { builder = builder.wasm_import_module_name(wasm_import_name); } if let Some(prefix) = matches.value_of("ctypes-prefix") { builder = builder.ctypes_prefix(prefix); } if let Some(prefix) = matches.value_of("anon-fields-prefix") { builder = builder.anon_fields_prefix(prefix); } if let Some(what_to_generate) = matches.value_of("generate") { let mut config = CodegenConfig::empty(); for what in what_to_generate.split(",") { match what { "functions" => config.insert(CodegenConfig::FUNCTIONS), "types" => config.insert(CodegenConfig::TYPES), "vars" => config.insert(CodegenConfig::VARS), "methods" => config.insert(CodegenConfig::METHODS), "constructors" => config.insert(CodegenConfig::CONSTRUCTORS), "destructors" => config.insert(CodegenConfig::DESTRUCTORS), otherwise => { return Err(Error::new( ErrorKind::Other, format!("Unknown generate item: {}", otherwise), )); } } } builder = builder.with_codegen_config(config); } if matches.is_present("emit-clang-ast") { builder = builder.emit_clang_ast(); } if matches.is_present("emit-ir") { builder = builder.emit_ir(); } if let Some(path) = matches.value_of("emit-ir-graphviz") { builder = builder.emit_ir_graphviz(path); } if matches.is_present("enable-cxx-namespaces") { builder = builder.enable_cxx_namespaces(); } if matches.is_present("enable-function-attribute-detection") { builder = builder.enable_function_attribute_detection(); } if matches.is_present("disable-name-namespacing") { builder = builder.disable_name_namespacing(); } if matches.is_present("disable-nested-struct-naming") { builder = builder.disable_nested_struct_naming(); } if matches.is_present("disable-untagged-union") { builder = builder.disable_untagged_union(); } if matches.is_present("disable-header-comment") { builder = builder.disable_header_comment(); } if matches.is_present("ignore-functions") { builder = builder.ignore_functions(); } if matches.is_present("ignore-methods") { builder = builder.ignore_methods(); } if matches.is_present("no-convert-floats") { builder = builder.no_convert_floats(); } if matches.is_present("no-doc-comments") { builder = builder.generate_comments(false); } if matches.is_present("no-recursive-allowlist") { builder = builder.allowlist_recursively(false); } if matches.is_present("objc-extern-crate") { builder = builder.objc_extern_crate(true); } if matches.is_present("generate-block") { builder = builder.generate_block(true); } if matches.is_present("block-extern-crate") { builder = builder.block_extern_crate(true); } if let Some(opaque_types) = matches.values_of("opaque-type") { for ty in opaque_types { builder = builder.opaque_type(ty); } } if let Some(lines) = matches.values_of("raw-line") { for line in lines { builder = builder.raw_line(line); } } if let Some(mut values) = matches.values_of("module-raw-line") { while let Some(module) = values.next() { let line = values.next().unwrap(); builder = builder.module_raw_line(module, line); } } if matches.is_present("use-core") { builder = builder.use_core(); } if matches.is_present("distrust-clang-mangling") { builder = builder.trust_clang_mangling(false); } if matches.is_present("conservative-inline-namespaces") { builder = builder.conservative_inline_namespaces(); } if matches.is_present("generate-inline-functions") { builder = builder.generate_inline_functions(true); } if let Some(allowlist) = matches.values_of("allowlist-function") { for regex in allowlist { builder = builder.allowlist_function(regex); } } if let Some(allowlist) = matches.values_of("allowlist-type") { for regex in allowlist { builder = builder.allowlist_type(regex); } } if let Some(allowlist) = matches.values_of("allowlist-var") { for regex in allowlist { builder = builder.allowlist_var(regex); } } if let Some(args) = matches.values_of("clang-args") { for arg in args { builder = builder.clang_arg(arg); } } let output = if let Some(path) = matches.value_of("output") { let file = File::create(path)?; if let Some(depfile) = matches.value_of("depfile") { builder = builder.depfile(path, depfile); } Box::new(io::BufWriter::new(file)) as Box } else { if let Some(depfile) = matches.value_of("depfile") { builder = builder.depfile("-", depfile); } Box::new(io::BufWriter::new(io::stdout())) as Box }; if matches.is_present("dump-preprocessed-input") { builder.dump_preprocessed_input()?; } if matches.is_present("no-record-matches") { builder = builder.record_matches(false); } if matches.is_present("size_t-is-usize") { builder = builder.size_t_is_usize(true); } let no_rustfmt_bindings = matches.is_present("no-rustfmt-bindings"); if no_rustfmt_bindings { builder = builder.rustfmt_bindings(false); } if let Some(path_str) = matches.value_of("rustfmt-configuration-file") { let path = PathBuf::from(path_str); if no_rustfmt_bindings { return Err(Error::new( ErrorKind::Other, "Cannot supply both --rustfmt-configuration-file and --no-rustfmt-bindings", )); } if !path.is_absolute() { return Err(Error::new( ErrorKind::Other, "--rustfmt-configuration--file needs to be an absolute path!", )); } if path.to_str().is_none() { return Err(Error::new( ErrorKind::Other, "--rustfmt-configuration-file contains non-valid UTF8 characters.", )); } builder = builder.rustfmt_configuration_file(Some(path)); } if let Some(no_partialeq) = matches.values_of("no-partialeq") { for regex in no_partialeq { builder = builder.no_partialeq(regex); } } if let Some(no_copy) = matches.values_of("no-copy") { for regex in no_copy { builder = builder.no_copy(regex); } } if let Some(no_debug) = matches.values_of("no-debug") { for regex in no_debug { builder = builder.no_debug(regex); } } if let Some(no_default) = matches.values_of("no-default") { for regex in no_default { builder = builder.no_default(regex); } } if let Some(no_hash) = matches.values_of("no-hash") { for regex in no_hash { builder = builder.no_hash(regex); } } if let Some(dynamic_library_name) = matches.value_of("dynamic-loading") { builder = builder.dynamic_library_name(dynamic_library_name); } if matches.is_present("dynamic-link-require-all") { builder = builder.dynamic_link_require_all(true); } if matches.is_present("respect-cxx-access-specs") { builder = builder.respect_cxx_access_specs(true); } if matches.is_present("translate-enum-integer-types") { builder = builder.translate_enum_integer_types(true); } if matches.is_present("c-naming") { builder = builder.c_naming(true); } if matches.is_present("explicit-padding") { builder = builder.explicit_padding(true); } let verbose = matches.is_present("verbose"); Ok((builder, output, verbose)) } bindgen-0.59.1/src/parse.rs000064400000000000000000000064120000000000000135550ustar 00000000000000//! Common traits and types related to parsing our IR from Clang cursors. use crate::clang; use crate::ir::context::{BindgenContext, ItemId, TypeId}; use crate::ir::ty::TypeKind; /// Not so much an error in the traditional sense, but a control flow message /// when walking over Clang's AST with a cursor. #[derive(Debug)] pub enum ParseError { /// Recurse down the current AST node's children. Recurse, /// Continue on to the next sibling AST node, or back up to the parent's /// siblings if we've exhausted all of this node's siblings (and so on). Continue, } /// The result of parsing a Clang AST node. #[derive(Debug)] pub enum ParseResult { /// 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 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>; } /// An intermediate representation item that can be parsed from a Clang cursor. pub trait ClangItemParser: Sized { /// Parse this item from the given Clang cursor. fn parse( cursor: clang::Cursor, parent: Option, context: &mut BindgenContext, ) -> Result; /// Parse this item from the given Clang type. fn from_ty( ty: &clang::Type, location: clang::Cursor, parent: Option, ctx: &mut BindgenContext, ) -> Result; /// Identical to `from_ty`, but use the given `id` as the `ItemId` for the /// newly parsed item. fn from_ty_with_id( id: ItemId, ty: &clang::Type, location: clang::Cursor, parent: Option, ctx: &mut BindgenContext, ) -> Result; /// Parse this item from the given Clang type, or if we haven't resolved all /// the other items this one depends on, an unresolved reference. fn from_ty_or_ref( ty: clang::Type, location: clang::Cursor, parent_id: Option, context: &mut BindgenContext, ) -> TypeId; /// Identical to `from_ty_or_ref`, but use the given `potential_id` as the /// `ItemId` for the newly parsed item. fn from_ty_or_ref_with_id( potential_id: ItemId, ty: clang::Type, location: clang::Cursor, parent_id: Option, context: &mut BindgenContext, ) -> TypeId; /// Create a named template type. fn type_param( with_id: Option, location: clang::Cursor, ctx: &mut BindgenContext, ) -> Option; /// Create a builtin type. fn builtin_type( kind: TypeKind, is_const: bool, context: &mut BindgenContext, ) -> TypeId; } bindgen-0.59.1/src/regex_set.rs000064400000000000000000000050160000000000000144270ustar 00000000000000//! A type that represents the union of a set of regular expressions. use regex::RegexSet as RxSet; use std::cell::Cell; /// A dynamic set of regular expressions. #[derive(Debug, Default)] pub 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 fn is_empty(&self) -> bool { self.items.is_empty() } /// Insert a new regex into this set. pub fn insert(&mut self, string: S) where S: AsRef, { self.items.push(string.as_ref().to_owned()); self.matched.push(Cell::new(false)); self.set = None; } /// Returns slice of String from its field 'items' pub fn get_items(&self) -> &[String] { &self.items[..] } /// Returns an iterator over regexes in the set which didn't match any /// strings yet. pub fn unmatched_items(&self) -> impl Iterator { self.items.iter().enumerate().filter_map(move |(i, item)| { if !self.record_matches || self.matched[i].get() { return None; } Some(item) }) } /// Construct a RegexSet from the set of entries we've accumulated. /// /// Must be called before calling `matches()`, or it will always return /// false. pub fn build(&mut self, record_matches: bool) { let items = self.items.iter().map(|item| format!("^{}$", item)); self.record_matches = record_matches; self.set = match RxSet::new(items) { Ok(x) => Some(x), Err(e) => { warn!("Invalid regex in {:?}: {:?}", self.items, e); None } } } /// Does the given `string` match any of the regexes in this set? pub fn matches(&self, string: S) -> bool where S: AsRef, { let s = string.as_ref(); let set = match self.set { Some(ref set) => set, None => return false, }; if !self.record_matches { return set.is_match(s); } let matches = set.matches(s); if !matches.matched_any() { return false; } for i in matches.iter() { self.matched[i].set(true); } true } } bindgen-0.59.1/src/time.rs000064400000000000000000000025740000000000000134060ustar 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 + (elapsed.subsec_nanos() as f64) / 1e6; let stderr = io::stderr(); // Arbitrary output format, subject to change. writeln!(stderr.lock(), " time: {:>9.3} ms.\t{}", time, self.name) .expect("timer write should not fail"); } } } impl<'a> Drop for Timer<'a> { fn drop(&mut self) { self.print_elapsed(); } }