summaryrefslogtreecommitdiffstats
path: root/third_party/rust/bindgen
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/bindgen
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/bindgen')
-rw-r--r--third_party/rust/bindgen/.cargo-checksum.json1
-rw-r--r--third_party/rust/bindgen/Cargo.toml151
-rw-r--r--third_party/rust/bindgen/LICENSE29
-rw-r--r--third_party/rust/bindgen/README.md89
-rw-r--r--third_party/rust/bindgen/build.rs29
-rw-r--r--third_party/rust/bindgen/callbacks.rs213
-rw-r--r--third_party/rust/bindgen/clang.rs2347
-rw-r--r--third_party/rust/bindgen/codegen/bitfield_unit.rs102
-rw-r--r--third_party/rust/bindgen/codegen/bitfield_unit_tests.rs260
-rw-r--r--third_party/rust/bindgen/codegen/dyngen.rs201
-rw-r--r--third_party/rust/bindgen/codegen/error.rs53
-rw-r--r--third_party/rust/bindgen/codegen/helpers.rs355
-rw-r--r--third_party/rust/bindgen/codegen/impl_debug.rs245
-rw-r--r--third_party/rust/bindgen/codegen/impl_partialeq.rs142
-rw-r--r--third_party/rust/bindgen/codegen/mod.rs5473
-rw-r--r--third_party/rust/bindgen/codegen/postprocessing/merge_extern_blocks.rs72
-rw-r--r--third_party/rust/bindgen/codegen/postprocessing/mod.rs57
-rw-r--r--third_party/rust/bindgen/codegen/postprocessing/sort_semantically.rs46
-rw-r--r--third_party/rust/bindgen/codegen/serialize.rs444
-rw-r--r--third_party/rust/bindgen/codegen/struct_layout.rs451
-rw-r--r--third_party/rust/bindgen/deps.rs61
-rw-r--r--third_party/rust/bindgen/diagnostics.rs189
-rw-r--r--third_party/rust/bindgen/extra_assertions.rs17
-rw-r--r--third_party/rust/bindgen/features.rs296
-rw-r--r--third_party/rust/bindgen/ir/analysis/derive.rs732
-rw-r--r--third_party/rust/bindgen/ir/analysis/has_destructor.rs176
-rw-r--r--third_party/rust/bindgen/ir/analysis/has_float.rs252
-rw-r--r--third_party/rust/bindgen/ir/analysis/has_type_param_in_array.rs252
-rw-r--r--third_party/rust/bindgen/ir/analysis/has_vtable.rs240
-rw-r--r--third_party/rust/bindgen/ir/analysis/mod.rs400
-rw-r--r--third_party/rust/bindgen/ir/analysis/sizedness.rs361
-rw-r--r--third_party/rust/bindgen/ir/analysis/template_params.rs607
-rw-r--r--third_party/rust/bindgen/ir/annotations.rs256
-rw-r--r--third_party/rust/bindgen/ir/comment.rs100
-rw-r--r--third_party/rust/bindgen/ir/comp.rs1896
-rw-r--r--third_party/rust/bindgen/ir/context.rs3038
-rw-r--r--third_party/rust/bindgen/ir/derive.rs135
-rw-r--r--third_party/rust/bindgen/ir/dot.rs86
-rw-r--r--third_party/rust/bindgen/ir/enum_ty.rs323
-rw-r--r--third_party/rust/bindgen/ir/function.rs839
-rw-r--r--third_party/rust/bindgen/ir/int.rs127
-rw-r--r--third_party/rust/bindgen/ir/item.rs2034
-rw-r--r--third_party/rust/bindgen/ir/item_kind.rs135
-rw-r--r--third_party/rust/bindgen/ir/layout.rs138
-rw-r--r--third_party/rust/bindgen/ir/mod.rs25
-rw-r--r--third_party/rust/bindgen/ir/module.rs96
-rw-r--r--third_party/rust/bindgen/ir/objc.rs354
-rw-r--r--third_party/rust/bindgen/ir/template.rs342
-rw-r--r--third_party/rust/bindgen/ir/traversal.rs479
-rw-r--r--third_party/rust/bindgen/ir/ty.rs1281
-rw-r--r--third_party/rust/bindgen/ir/var.rs488
-rw-r--r--third_party/rust/bindgen/lib.rs1380
-rw-r--r--third_party/rust/bindgen/log_stubs.rs32
-rw-r--r--third_party/rust/bindgen/options/as_args.rs52
-rw-r--r--third_party/rust/bindgen/options/helpers.rs43
-rw-r--r--third_party/rust/bindgen/options/mod.rs2079
-rw-r--r--third_party/rust/bindgen/parse.rs41
-rw-r--r--third_party/rust/bindgen/regex_set.rs204
-rw-r--r--third_party/rust/bindgen/time.rs52
59 files changed, 30398 insertions, 0 deletions
diff --git a/third_party/rust/bindgen/.cargo-checksum.json b/third_party/rust/bindgen/.cargo-checksum.json
new file mode 100644
index 0000000000..24fa58273e
--- /dev/null
+++ b/third_party/rust/bindgen/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"bebb685bfd8df63474c92bfb7f787573ef78eb70920aceb38a8a746968380f96","LICENSE":"c23953d9deb0a3312dbeaf6c128a657f3591acee45067612fa68405eaa4525db","README.md":"b2334e4077a9bc329516e3e0c7f89887c4f073647d95fb71b6917edf4c310ba3","build.rs":"4a9c4ac3759572e17de312a9d3f4ced3b6fd3c71811729e5a8d06bfbd1ac8f82","callbacks.rs":"cd5a1b0fc665b034d97615d0b6817cbef299dbf5276254c7e63f1c29674993ad","clang.rs":"278ca0d89251df8a6b40bdccd27827e310d16872ff86fa23b60d581615607630","codegen/bitfield_unit.rs":"fddeaeab5859f4e82081865595b7705f5c0774d997df95fa5c655b81b9cae125","codegen/bitfield_unit_tests.rs":"9df86490de5e9d66ccea583dcb686dd440375dc1a3c3cf89a89d5de3883bf28a","codegen/dyngen.rs":"6d8bed53c6de66bc658b3186041c2b75549f49b0f0363ff18b87c8dcf2f5a05b","codegen/error.rs":"0c3d198f4866ccbbcd8b1136fc5cfd2507a9eca5ab85934af29a7e2a7d8d8c2a","codegen/helpers.rs":"443a2c3495185ced2a9d68c02204bebfa8c4186f4275bf9ed3af90c3a3e159d7","codegen/impl_debug.rs":"80df6136327b1ca8c7d1c2961290b5ab00b85b49b22c02f26a590bc68fb230af","codegen/impl_partialeq.rs":"db739d7ba6f5ba4033d6bf62c276f35217c20eab27230cf07dadf59e8b2f71bb","codegen/mod.rs":"206e4e2c14cec17c13d11e568557332b51ce1e41ce8128182de44dab69221662","codegen/postprocessing/merge_extern_blocks.rs":"284457a3c75e945217bab4e5a4280fef0fcc03c31e12cc5010aab87f34c0b6c7","codegen/postprocessing/mod.rs":"160a6d6701cabf2514e23570df1bd1b648c909cc27b7c583f21d98fe0c16722e","codegen/postprocessing/sort_semantically.rs":"f465d1e8cc119082eb79c164b5cd780a370821e8bf56585b287dd3b51fc4a542","codegen/serialize.rs":"1f1eb8b04fec9655dc302442451f9622ad6365eb37bf588a119a60e79f37002c","codegen/struct_layout.rs":"922cc71fb309716879aeea4775bbc29751ca5d431083ca83d7beb0a90862a302","deps.rs":"af3dd24a7808b5abf0c4ed4b10bbceb8eef32be980ff085b8a766d8f089af1a4","diagnostics.rs":"dc40cd5e9710922422c5c9420e2351f5d976e7a1d7275e4f4ce742cad9eb53f8","extra_assertions.rs":"fb4484c0e9fcbea9ec7265f5fbd01e2b33ac022b2b17e060dce7886819d57e40","features.rs":"b27adc6bb50e9aae50fd75568a7576382c6409f585b6be0047d7a9314c98d569","ir/analysis/derive.rs":"cba290e9c4ba271e90524149ad3b874f37843bfdfab12d513cc85d2665447fd5","ir/analysis/has_destructor.rs":"e7e95c3b0989b6375cd3eabaac85a36ecc2915a1fd3700c7d26fe04e8dc83ba3","ir/analysis/has_float.rs":"a56b97bf913f132c2c63dc202b45c692c416a8c9fdc6b2baeee30362fb0d4405","ir/analysis/has_type_param_in_array.rs":"788ebb4ba2cf46a22f1e4ff3005d51f38d414b72e95355f7ff4125521e2d9525","ir/analysis/has_vtable.rs":"83efa40ae89147170eabdff1387e60aba574ca4cd4cdef22692753594f09d6c6","ir/analysis/mod.rs":"9d949c27451da4ed72994b31c04ddeb89eeb342fd23ea572d3962d4ccf774841","ir/analysis/sizedness.rs":"f0a9302f3c6ad694d76cfab11dbaf5392ecaf7f04bc7b211a5a003776b963896","ir/analysis/template_params.rs":"3ff27e2198e292a348876aa1faba39cc4b1870a24a7e173feac0b3c592001e13","ir/annotations.rs":"5ed03d025862d0d21852a76c86a993772624e123fdc3752415d588a0b4e643ab","ir/comment.rs":"4c9c20b5a3da086211e92adec0822831dbc0b7ebee98fee313edcae9ae8d55ec","ir/comp.rs":"c048866353695ac8190ab03511123be82d34ca73fb865a2578cb5a2e04390431","ir/context.rs":"03175218512c42792aae7b56a764c0237a447664dda5f1a8269a42bed46d3be2","ir/derive.rs":"c21e470bb0091f20bfa366110880d48984fc3cf7071fdf36eccfa64f3eca231c","ir/dot.rs":"75bdfd83d9e754ba726f6a5529ba1d9ff46f5bf49bf237452985eb008fed0854","ir/enum_ty.rs":"f4bfa6d18ba4977fb66f5d5e4a7674eded93b761404d91cdd6fdd50029db455a","ir/function.rs":"0ecee923382b0a49265bc970ac90a73740ec5ba3c33466b2cfe8aa462df59bd5","ir/int.rs":"601736f0ad0949e40684a9ce89bafbfefa71743df6ee6c342e44888a0f141ae0","ir/item.rs":"65f2351dd3971d8a76470a78f5b6b1ebdda067ab5bae4641246aa986d9579e29","ir/item_kind.rs":"33e21104b0bb824a696a52cd520567ae56158010a1df14777e68ac5f8ad7e8fa","ir/layout.rs":"8fbafc0eeee17abb703a18613be1066e38838d4b67f5916f714bf545e545bc1a","ir/mod.rs":"a3b98b1732111a980a795c72eaf1e09101e842ef2de76b4f2d4a7857f8d4cee4","ir/module.rs":"b2961ffa4acb0c19f084c5db084b8a17bda7158066782a73b80ee7d838789bf9","ir/objc.rs":"8f57a9180d57a690449f20ed1be80209db5f8a410bb067ae8bf5e0ecab16a5e4","ir/template.rs":"3f59efa9670ca90215d4374be869c9dbecb98a8d1041e7c6e4ab69a62bb982c2","ir/traversal.rs":"a4ec73d3533d4b93386153baf6a2ca846ee51228c76ed51105229d3ddcd74466","ir/ty.rs":"fd71d11e89e085921317349e1912ab56e7335d870c2d25df9e13a8ffbd6430c9","ir/var.rs":"40d18226706de0ee5f002d0b5617dbcba35de0605edd531c75e3a76d000f0f4f","lib.rs":"7496f72a177b5965ed56a2ab9af0f64e70abbc53cc6c196a15e6760dd6235adf","log_stubs.rs":"9f974e041e35c8c7e29985d27ae5cd0858d68f8676d1dc005c6388d7d011707f","options/as_args.rs":"76efa4e662cc7f89ef1c1fe089d03a3c1c019ffe2aa0a30a4d49ed41e987d1c7","options/helpers.rs":"f4a7681e29b2dcc3be9249478c499d685b9e29d4f4ca4ae8bff7a91668cd8f15","options/mod.rs":"1805cec86c563633b29b57292287c9efd3b5c724132ec1c13acee57858942e74","parse.rs":"fce3616e0464aa7414888e5d00d4df18c83bb3034a1c807d36a07a3c586e475a","regex_set.rs":"b411d64bc803947a3f69dcedcd7d03716aacbc7b1c5148b82de1cc469d9336d9","time.rs":"8efe317e7c6b5ba8e0865ce7b49ca775ee8a02590f4241ef62f647fa3c22b68e"},"package":"a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"} \ No newline at end of file
diff --git a/third_party/rust/bindgen/Cargo.toml b/third_party/rust/bindgen/Cargo.toml
new file mode 100644
index 0000000000..c4f5f568ae
--- /dev/null
+++ b/third_party/rust/bindgen/Cargo.toml
@@ -0,0 +1,151 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+rust-version = "1.60.0"
+name = "bindgen"
+version = "0.69.4"
+authors = [
+ "Jyun-Yan You <jyyou.tw@gmail.com>",
+ "Emilio Cobos Álvarez <emilio@crisal.io>",
+ "Nick Fitzgerald <fitzgen@gmail.com>",
+ "The Servo project developers",
+]
+build = "build.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"
+
+[package.metadata.docs.rs]
+features = ["experimental"]
+
+[package.metadata.release]
+pre-release-hook = [
+ "../node_modules/doctoc/doctoc.js",
+ "../CHANGELOG.md",
+]
+release = true
+
+[[package.metadata.release.pre-release-replacements]]
+file = "../CHANGELOG.md"
+replace = """
+# Unreleased
+## Added
+## Changed
+## Removed
+## Fixed
+## Security
+
+# {{version}} ({{date}})"""
+search = "# Unreleased"
+
+[lib]
+name = "bindgen"
+path = "lib.rs"
+
+[dependencies.annotate-snippets]
+version = "0.9.1"
+features = ["color"]
+optional = true
+
+[dependencies.bitflags]
+version = "2.2.1"
+
+[dependencies.cexpr]
+version = "0.6"
+
+[dependencies.clang-sys]
+version = "1"
+features = ["clang_6_0"]
+
+[dependencies.itertools]
+version = ">=0.10,<0.13"
+default-features = false
+
+[dependencies.lazy_static]
+version = "1"
+
+[dependencies.lazycell]
+version = "1"
+
+[dependencies.log]
+version = "0.4"
+optional = true
+
+[dependencies.prettyplease]
+version = "0.2.7"
+features = ["verbatim"]
+optional = true
+
+[dependencies.proc-macro2]
+version = "1"
+default-features = false
+
+[dependencies.quote]
+version = "1"
+default-features = false
+
+[dependencies.regex]
+version = "1.5.1"
+features = [
+ "std",
+ "unicode-perl",
+]
+default-features = false
+
+[dependencies.rustc-hash]
+version = "1.0.1"
+
+[dependencies.shlex]
+version = "1"
+
+[dependencies.syn]
+version = "2.0"
+features = [
+ "full",
+ "extra-traits",
+ "visit-mut",
+]
+
+[dependencies.which]
+version = "4.2.1"
+optional = true
+default-features = false
+
+[features]
+__cli = []
+__testing_only_extra_assertions = []
+__testing_only_libclang_16 = []
+__testing_only_libclang_9 = []
+default = [
+ "logging",
+ "prettyplease",
+ "runtime",
+ "which-rustfmt",
+]
+experimental = ["dep:annotate-snippets"]
+logging = ["dep:log"]
+runtime = ["clang-sys/runtime"]
+static = ["clang-sys/static"]
+which-rustfmt = ["dep:which"]
diff --git a/third_party/rust/bindgen/LICENSE b/third_party/rust/bindgen/LICENSE
new file mode 100644
index 0000000000..62f55f45a1
--- /dev/null
+++ b/third_party/rust/bindgen/LICENSE
@@ -0,0 +1,29 @@
+BSD 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.
diff --git a/third_party/rust/bindgen/README.md b/third_party/rust/bindgen/README.md
new file mode 100644
index 0000000000..620ad0ab94
--- /dev/null
+++ b/third_party/rust/bindgen/README.md
@@ -0,0 +1,89 @@
+[![crates.io](https://img.shields.io/crates/v/bindgen.svg)](https://crates.io/crates/bindgen)
+[![docs.rs](https://docs.rs/bindgen/badge.svg)](https://docs.rs/bindgen/)
+
+# `bindgen`
+
+**`bindgen` automatically generates Rust FFI bindings to C (and some C++) libraries.**
+
+For example, given the C header `doggo.h`:
+
+```c
+typedef struct Doggo {
+ int many;
+ char wow;
+} Doggo;
+
+void eleven_out_of_ten_majestic_af(Doggo* pupper);
+```
+
+`bindgen` produces Rust FFI code allowing you to call into the `doggo` library's
+functions and use its types:
+
+```rust
+/* automatically generated by rust-bindgen 0.99.9 */
+
+#[repr(C)]
+pub struct Doggo {
+ pub many: ::std::os::raw::c_int,
+ pub wow: ::std::os::raw::c_char,
+}
+
+extern "C" {
+ pub fn eleven_out_of_ten_majestic_af(pupper: *mut Doggo);
+}
+```
+
+## Users Guide
+
+[📚 Read the `bindgen` users guide here! 📚](https://rust-lang.github.io/rust-bindgen)
+
+## MSRV
+
+The `bindgen` minimum supported Rust version is **1.60.0**.
+
+The `bindgen-cli` minimum supported Rust version is **1.64.0**.
+
+No MSRV bump policy has been established yet, so MSRV may increase in any release.
+
+The MSRV is the minimum Rust version that can be used to *compile* each crate. However, `bindgen` and `bindgen-cli` can generate bindings that are compatible with Rust versions below the current MSRV.
+
+Most of the time, the `bindgen-cli` crate will have a more recent MSRV than `bindgen` as crates such as `clap` require it.
+
+## API Reference
+
+[API reference documentation is on docs.rs](https://docs.rs/bindgen)
+
+## Environment Variables
+
+In addition to the [library API](https://docs.rs/bindgen) and [executable command-line API][bindgen-cmdline],
+`bindgen` can be controlled through environment variables.
+
+End-users should set these environment variables to modify `bindgen`'s behavior without modifying the source code of direct consumers of `bindgen`.
+
+- `BINDGEN_EXTRA_CLANG_ARGS`: extra arguments to pass to `clang`
+ - Arguments are whitespace-separated
+ - Use shell-style quoting to pass through whitespace
+ - Examples:
+ - Specify alternate sysroot: `--sysroot=/path/to/sysroot`
+ - Add include search path with spaces: `-I"/path/with spaces"`
+- `BINDGEN_EXTRA_CLANG_ARGS_<TARGET>`: 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
diff --git a/third_party/rust/bindgen/build.rs b/third_party/rust/bindgen/build.rs
new file mode 100644
index 0000000000..8407ceae8f
--- /dev/null
+++ b/third_party/rust/bindgen/build.rs
@@ -0,0 +1,29 @@
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use std::path::{Path, PathBuf};
+
+fn main() {
+ let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
+
+ let mut dst =
+ File::create(Path::new(&out_dir).join("host-target.txt")).unwrap();
+ dst.write_all(env::var("TARGET").unwrap().as_bytes())
+ .unwrap();
+
+ // On behalf of clang_sys, rebuild ourselves if important configuration
+ // variables change, to ensure that bindings get rebuilt if the
+ // underlying libclang changes.
+ println!("cargo:rerun-if-env-changed=LLVM_CONFIG_PATH");
+ println!("cargo:rerun-if-env-changed=LIBCLANG_PATH");
+ println!("cargo:rerun-if-env-changed=LIBCLANG_STATIC_PATH");
+ println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS");
+ println!(
+ "cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_{}",
+ std::env::var("TARGET").unwrap()
+ );
+ println!(
+ "cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_{}",
+ std::env::var("TARGET").unwrap().replace('-', "_")
+ );
+}
diff --git a/third_party/rust/bindgen/callbacks.rs b/third_party/rust/bindgen/callbacks.rs
new file mode 100644
index 0000000000..c22ba975dd
--- /dev/null
+++ b/third_party/rust/bindgen/callbacks.rs
@@ -0,0 +1,213 @@
+//! A public API for more fine-grained customization of bindgen behavior.
+
+pub use crate::ir::analysis::DeriveTrait;
+pub use crate::ir::derive::CanDerive as ImplementsTrait;
+pub use crate::ir::enum_ty::{EnumVariantCustomBehavior, EnumVariantValue};
+pub use crate::ir::int::IntKind;
+use std::fmt;
+
+/// An enum to allow ignoring parsing of macros.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+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 {
+ #[cfg(feature = "__cli")]
+ #[doc(hidden)]
+ fn cli_args(&self) -> Vec<String> {
+ vec![]
+ }
+
+ /// This function will be run on every macro that is identified.
+ fn will_parse_macro(&self, _name: &str) -> MacroParsingBehavior {
+ MacroParsingBehavior::Default
+ }
+
+ /// This function will run for every extern variable and function. The returned value determines
+ /// the name visible in the bindings.
+ fn generated_name_override(
+ &self,
+ _item_info: ItemInfo<'_>,
+ ) -> Option<String> {
+ None
+ }
+
+ /// This function will run for every extern variable and function. The returned value determines
+ /// the link name in the bindings.
+ fn generated_link_name_override(
+ &self,
+ _item_info: ItemInfo<'_>,
+ ) -> Option<String> {
+ None
+ }
+
+ /// The integer kind an integer macro should have, given a name and the
+ /// value of that macro, or `None` if you want the default to be chosen.
+ fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> {
+ None
+ }
+
+ /// This will be run on every string macro. The callback cannot influence the further
+ /// treatment of the macro, but may use the value to generate additional code or configuration.
+ fn str_macro(&self, _name: &str, _value: &[u8]) {}
+
+ /// This will be run on every function-like macro. The callback cannot
+ /// influence the further treatment of the macro, but may use the value to
+ /// generate additional code or configuration.
+ ///
+ /// The first parameter represents the name and argument list (including the
+ /// parentheses) of the function-like macro. The second parameter represents
+ /// the expansion of the macro as a sequence of tokens.
+ fn func_macro(&self, _name: &str, _value: &[&[u8]]) {}
+
+ /// This function should return whether, given an enum variant
+ /// name, and value, this enum variant will forcibly be a constant.
+ fn enum_variant_behavior(
+ &self,
+ _enum_name: Option<&str>,
+ _original_variant_name: &str,
+ _variant_value: EnumVariantValue,
+ ) -> Option<EnumVariantCustomBehavior> {
+ None
+ }
+
+ /// Allows to rename an enum variant, replacing `_original_variant_name`.
+ fn enum_variant_name(
+ &self,
+ _enum_name: Option<&str>,
+ _original_variant_name: &str,
+ _variant_value: EnumVariantValue,
+ ) -> Option<String> {
+ None
+ }
+
+ /// Allows to rename an item, replacing `_original_item_name`.
+ fn item_name(&self, _original_item_name: &str) -> Option<String> {
+ None
+ }
+
+ /// This will be called on every header filename passed to (`Builder::header`)[`crate::Builder::header`].
+ fn header_file(&self, _filename: &str) {}
+
+ /// This will be called on every file inclusion, with the full path of the included file.
+ fn include_file(&self, _filename: &str) {}
+
+ /// This will be called every time `bindgen` reads an environment variable whether it has any
+ /// content or not.
+ fn read_env_var(&self, _key: &str) {}
+
+ /// This will be called to determine whether a particular blocklisted type
+ /// implements a trait or not. This will be used to implement traits on
+ /// other types containing the blocklisted type.
+ ///
+ /// * `None`: use the default behavior
+ /// * `Some(ImplementsTrait::Yes)`: `_name` implements `_derive_trait`
+ /// * `Some(ImplementsTrait::Manually)`: any type including `_name` can't
+ /// derive `_derive_trait` but can implemented it manually
+ /// * `Some(ImplementsTrait::No)`: `_name` doesn't implement `_derive_trait`
+ fn blocklisted_type_implements_trait(
+ &self,
+ _name: &str,
+ _derive_trait: DeriveTrait,
+ ) -> Option<ImplementsTrait> {
+ None
+ }
+
+ /// Provide a list of custom derive attributes.
+ ///
+ /// If no additional attributes are wanted, this function should return an
+ /// empty `Vec`.
+ fn add_derives(&self, _info: &DeriveInfo<'_>) -> Vec<String> {
+ vec![]
+ }
+
+ /// Process a source code comment.
+ fn process_comment(&self, _comment: &str) -> Option<String> {
+ None
+ }
+
+ /// Potentially override the visibility of a composite type field.
+ ///
+ /// Caution: This allows overriding standard C++ visibility inferred by
+ /// `respect_cxx_access_specs`.
+ fn field_visibility(
+ &self,
+ _info: FieldInfo<'_>,
+ ) -> Option<crate::FieldVisibilityKind> {
+ None
+ }
+
+ /// Process a function name that as exactly one `va_list` argument
+ /// to be wrapped as a variadic function with the wrapped static function
+ /// feature.
+ ///
+ /// The returned string is new function name.
+ #[cfg(feature = "experimental")]
+ fn wrap_as_variadic_fn(&self, _name: &str) -> Option<String> {
+ None
+ }
+}
+
+/// Relevant information about a type to which new derive attributes will be added using
+/// [`ParseCallbacks::add_derives`].
+#[derive(Debug)]
+#[non_exhaustive]
+pub struct DeriveInfo<'a> {
+ /// The name of the type.
+ pub name: &'a str,
+ /// The kind of the type.
+ pub kind: TypeKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+/// The kind of the current type.
+pub enum TypeKind {
+ /// The type is a Rust `struct`.
+ Struct,
+ /// The type is a Rust `enum`.
+ Enum,
+ /// The type is a Rust `union`.
+ Union,
+}
+
+/// A struct providing information about the item being passed to [`ParseCallbacks::generated_name_override`].
+#[non_exhaustive]
+pub struct ItemInfo<'a> {
+ /// The name of the item
+ pub name: &'a str,
+ /// The kind of item
+ pub kind: ItemKind,
+}
+
+/// An enum indicating the kind of item for an ItemInfo.
+#[non_exhaustive]
+pub enum ItemKind {
+ /// A Function
+ Function,
+ /// A Variable
+ Var,
+}
+
+/// Relevant information about a field for which visibility can be determined using
+/// [`ParseCallbacks::field_visibility`].
+#[derive(Debug)]
+#[non_exhaustive]
+pub struct FieldInfo<'a> {
+ /// The name of the type.
+ pub type_name: &'a str,
+ /// The name of the field.
+ pub field_name: &'a str,
+}
diff --git a/third_party/rust/bindgen/clang.rs b/third_party/rust/bindgen/clang.rs
new file mode 100644
index 0000000000..4a4ed89d69
--- /dev/null
+++ b/third_party/rust/bindgen/clang.rs
@@ -0,0 +1,2347 @@
+//! A higher level Clang API built on top of the generated bindings in the
+//! `clang_sys` module.
+
+#![allow(non_upper_case_globals, dead_code)]
+#![deny(clippy::missing_docs_in_private_items)]
+
+use crate::ir::context::BindgenContext;
+use clang_sys::*;
+use std::cmp;
+
+use std::ffi::{CStr, CString};
+use std::fmt;
+use std::hash::Hash;
+use std::hash::Hasher;
+use std::os::raw::{c_char, c_int, c_longlong, c_uint, c_ulong, c_ulonglong};
+use std::{mem, ptr, slice};
+
+/// Type representing a clang attribute.
+///
+/// Values of this type can be used to check for different attributes using the `has_attrs`
+/// function.
+pub(crate) struct Attribute {
+ name: &'static [u8],
+ kind: Option<CXCursorKind>,
+ token_kind: CXTokenKind,
+}
+
+impl Attribute {
+ /// A `warn_unused_result` attribute.
+ pub(crate) const MUST_USE: Self = Self {
+ name: b"warn_unused_result",
+ // FIXME(emilio): clang-sys doesn't expose `CXCursor_WarnUnusedResultAttr` (from clang 9).
+ kind: Some(440),
+ token_kind: CXToken_Identifier,
+ };
+
+ /// A `_Noreturn` attribute.
+ pub(crate) const NO_RETURN: Self = Self {
+ name: b"_Noreturn",
+ kind: None,
+ token_kind: CXToken_Keyword,
+ };
+
+ /// A `[[noreturn]]` attribute.
+ pub(crate) const NO_RETURN_CPP: Self = Self {
+ name: b"noreturn",
+ kind: None,
+ token_kind: CXToken_Identifier,
+ };
+}
+
+/// A cursor into the Clang AST, pointing to an AST node.
+///
+/// We call the AST node pointed to by the cursor the cursor's "referent".
+#[derive(Copy, Clone)]
+pub(crate) struct Cursor {
+ x: CXCursor,
+}
+
+impl fmt::Debug for Cursor {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ fmt,
+ "Cursor({} kind: {}, loc: {}, usr: {:?})",
+ self.spelling(),
+ kind_to_str(self.kind()),
+ self.location(),
+ self.usr()
+ )
+ }
+}
+
+impl Cursor {
+ /// Get the Unified Symbol Resolution for this cursor's referent, if
+ /// available.
+ ///
+ /// The USR can be used to compare entities across translation units.
+ pub(crate) fn usr(&self) -> Option<String> {
+ let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) };
+ if s.is_empty() {
+ None
+ } else {
+ Some(s)
+ }
+ }
+
+ /// Is this cursor's referent a declaration?
+ pub(crate) fn is_declaration(&self) -> bool {
+ unsafe { clang_isDeclaration(self.kind()) != 0 }
+ }
+
+ /// Is this cursor's referent an anonymous record or so?
+ pub(crate) fn is_anonymous(&self) -> bool {
+ unsafe { clang_Cursor_isAnonymous(self.x) != 0 }
+ }
+
+ /// Get this cursor's referent's spelling.
+ pub(crate) fn spelling(&self) -> String {
+ unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) }
+ }
+
+ /// Get this cursor's referent's display name.
+ ///
+ /// This is not necessarily a valid identifier. It includes extra
+ /// information, such as parameters for a function, etc.
+ pub(crate) fn display_name(&self) -> String {
+ unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) }
+ }
+
+ /// Get the mangled name of this cursor's referent.
+ pub(crate) fn mangling(&self) -> String {
+ unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) }
+ }
+
+ /// Gets the C++ manglings for this cursor, or an error if the manglings
+ /// are not available.
+ pub(crate) fn cxx_manglings(&self) -> Result<Vec<String>, ()> {
+ use clang_sys::*;
+ unsafe {
+ let manglings = clang_Cursor_getCXXManglings(self.x);
+ if manglings.is_null() {
+ return Err(());
+ }
+ let count = (*manglings).Count as usize;
+
+ let mut result = Vec::with_capacity(count);
+ for i in 0..count {
+ let string_ptr = (*manglings).Strings.add(i);
+ result.push(cxstring_to_string_leaky(*string_ptr));
+ }
+ clang_disposeStringSet(manglings);
+ Ok(result)
+ }
+ }
+
+ /// Returns whether the cursor refers to a built-in definition.
+ pub(crate) fn is_builtin(&self) -> bool {
+ let (file, _, _, _) = self.location().location();
+ file.name().is_none()
+ }
+
+ /// Get the `Cursor` for this cursor's referent's lexical parent.
+ ///
+ /// The lexical parent is the parent of the definition. The semantic parent
+ /// is the parent of the declaration. Generally, the lexical parent doesn't
+ /// have any effect on semantics, while the semantic parent does.
+ ///
+ /// In the following snippet, the `Foo` class would be the semantic parent
+ /// of the out-of-line `method` definition, while the lexical parent is the
+ /// translation unit.
+ ///
+ /// ```c++
+ /// class Foo {
+ /// void method();
+ /// };
+ ///
+ /// void Foo::method() { /* ... */ }
+ /// ```
+ pub(crate) fn lexical_parent(&self) -> Cursor {
+ unsafe {
+ Cursor {
+ x: clang_getCursorLexicalParent(self.x),
+ }
+ }
+ }
+
+ /// Get the referent's semantic parent, if one is available.
+ ///
+ /// See documentation for `lexical_parent` for details on semantic vs
+ /// lexical parents.
+ pub(crate) fn fallible_semantic_parent(&self) -> Option<Cursor> {
+ let sp = unsafe {
+ Cursor {
+ x: clang_getCursorSemanticParent(self.x),
+ }
+ };
+ if sp == *self || !sp.is_valid() {
+ return None;
+ }
+ Some(sp)
+ }
+
+ /// Get the referent's semantic parent.
+ ///
+ /// See documentation for `lexical_parent` for details on semantic vs
+ /// lexical parents.
+ pub(crate) fn semantic_parent(&self) -> Cursor {
+ self.fallible_semantic_parent().unwrap()
+ }
+
+ /// Return the number of template arguments used by this cursor's referent,
+ /// if the referent is either a template instantiation. Returns `None`
+ /// otherwise.
+ ///
+ /// NOTE: This may not return `Some` for partial template specializations,
+ /// see #193 and #194.
+ pub(crate) fn num_template_args(&self) -> Option<u32> {
+ // XXX: `clang_Type_getNumTemplateArguments` is sort of reliable, while
+ // `clang_Cursor_getNumTemplateArguments` is totally unreliable.
+ // Therefore, try former first, and only fallback to the latter if we
+ // have to.
+ self.cur_type()
+ .num_template_args()
+ .or_else(|| {
+ let n: c_int =
+ unsafe { clang_Cursor_getNumTemplateArguments(self.x) };
+
+ if n >= 0 {
+ Some(n as u32)
+ } else {
+ debug_assert_eq!(n, -1);
+ None
+ }
+ })
+ .or_else(|| {
+ let canonical = self.canonical();
+ if canonical != *self {
+ canonical.num_template_args()
+ } else {
+ None
+ }
+ })
+ }
+
+ /// Get a cursor pointing to this referent's containing translation unit.
+ ///
+ /// Note that we shouldn't create a `TranslationUnit` struct here, because
+ /// bindgen assumes there will only be one of them alive at a time, and
+ /// disposes it on drop. That can change if this would be required, but I
+ /// think we can survive fine without it.
+ pub(crate) fn translation_unit(&self) -> Cursor {
+ assert!(self.is_valid());
+ unsafe {
+ let tu = clang_Cursor_getTranslationUnit(self.x);
+ let cursor = Cursor {
+ x: clang_getTranslationUnitCursor(tu),
+ };
+ assert!(cursor.is_valid());
+ cursor
+ }
+ }
+
+ /// Is the referent a top level construct?
+ pub(crate) fn is_toplevel(&self) -> bool {
+ let mut semantic_parent = self.fallible_semantic_parent();
+
+ while semantic_parent.is_some() &&
+ (semantic_parent.unwrap().kind() == CXCursor_Namespace ||
+ semantic_parent.unwrap().kind() ==
+ CXCursor_NamespaceAlias ||
+ semantic_parent.unwrap().kind() == CXCursor_NamespaceRef)
+ {
+ semantic_parent =
+ semantic_parent.unwrap().fallible_semantic_parent();
+ }
+
+ let tu = self.translation_unit();
+ // Yes, this can happen with, e.g., macro definitions.
+ semantic_parent == tu.fallible_semantic_parent()
+ }
+
+ /// There are a few kinds of types that we need to treat specially, mainly
+ /// not tracking the type declaration but the location of the cursor, given
+ /// clang doesn't expose a proper declaration for these types.
+ pub(crate) fn is_template_like(&self) -> bool {
+ matches!(
+ self.kind(),
+ CXCursor_ClassTemplate |
+ CXCursor_ClassTemplatePartialSpecialization |
+ CXCursor_TypeAliasTemplateDecl
+ )
+ }
+
+ /// Is this Cursor pointing to a function-like macro definition?
+ pub(crate) fn is_macro_function_like(&self) -> bool {
+ unsafe { clang_Cursor_isMacroFunctionLike(self.x) != 0 }
+ }
+
+ /// Get the kind of referent this cursor is pointing to.
+ pub(crate) fn kind(&self) -> CXCursorKind {
+ self.x.kind
+ }
+
+ /// Returns true if the cursor is a definition
+ pub(crate) fn is_definition(&self) -> bool {
+ unsafe { clang_isCursorDefinition(self.x) != 0 }
+ }
+
+ /// Is the referent a template specialization?
+ pub(crate) fn is_template_specialization(&self) -> bool {
+ self.specialized().is_some()
+ }
+
+ /// Is the referent a fully specialized template specialization without any
+ /// remaining free template arguments?
+ pub(crate) fn is_fully_specialized_template(&self) -> bool {
+ self.is_template_specialization() &&
+ self.kind() != CXCursor_ClassTemplatePartialSpecialization &&
+ self.num_template_args().unwrap_or(0) > 0
+ }
+
+ /// Is the referent a template specialization that still has remaining free
+ /// template arguments?
+ pub(crate) fn is_in_non_fully_specialized_template(&self) -> bool {
+ if self.is_toplevel() {
+ return false;
+ }
+
+ let parent = self.semantic_parent();
+ if parent.is_fully_specialized_template() {
+ return false;
+ }
+
+ if !parent.is_template_like() {
+ return parent.is_in_non_fully_specialized_template();
+ }
+
+ true
+ }
+
+ /// Is the referent any kind of template parameter?
+ pub(crate) fn is_template_parameter(&self) -> bool {
+ matches!(
+ self.kind(),
+ CXCursor_TemplateTemplateParameter |
+ CXCursor_TemplateTypeParameter |
+ CXCursor_NonTypeTemplateParameter
+ )
+ }
+
+ /// Does the referent's type or value depend on a template parameter?
+ pub(crate) fn is_dependent_on_template_parameter(&self) -> bool {
+ fn visitor(
+ found_template_parameter: &mut bool,
+ cur: Cursor,
+ ) -> CXChildVisitResult {
+ // If we found a template parameter, it is dependent.
+ if cur.is_template_parameter() {
+ *found_template_parameter = true;
+ return CXChildVisit_Break;
+ }
+
+ // Get the referent and traverse it as well.
+ if let Some(referenced) = cur.referenced() {
+ if referenced.is_template_parameter() {
+ *found_template_parameter = true;
+ return CXChildVisit_Break;
+ }
+
+ referenced
+ .visit(|next| visitor(found_template_parameter, next));
+ if *found_template_parameter {
+ return CXChildVisit_Break;
+ }
+ }
+
+ // Continue traversing the AST at the original cursor.
+ CXChildVisit_Recurse
+ }
+
+ if self.is_template_parameter() {
+ return true;
+ }
+
+ let mut found_template_parameter = false;
+ self.visit(|next| visitor(&mut found_template_parameter, next));
+
+ found_template_parameter
+ }
+
+ /// Is this cursor pointing a valid referent?
+ pub(crate) fn is_valid(&self) -> bool {
+ unsafe { clang_isInvalid(self.kind()) == 0 }
+ }
+
+ /// Get the source location for the referent.
+ pub(crate) fn location(&self) -> SourceLocation {
+ unsafe {
+ SourceLocation {
+ x: clang_getCursorLocation(self.x),
+ }
+ }
+ }
+
+ /// Get the source location range for the referent.
+ pub(crate) fn extent(&self) -> CXSourceRange {
+ unsafe { clang_getCursorExtent(self.x) }
+ }
+
+ /// Get the raw declaration comment for this referent, if one exists.
+ pub(crate) fn raw_comment(&self) -> Option<String> {
+ let s = unsafe {
+ cxstring_into_string(clang_Cursor_getRawCommentText(self.x))
+ };
+ if s.is_empty() {
+ None
+ } else {
+ Some(s)
+ }
+ }
+
+ /// Get the referent's parsed comment.
+ pub(crate) fn comment(&self) -> Comment {
+ unsafe {
+ Comment {
+ x: clang_Cursor_getParsedComment(self.x),
+ }
+ }
+ }
+
+ /// Get the referent's type.
+ pub(crate) fn cur_type(&self) -> Type {
+ unsafe {
+ Type {
+ x: clang_getCursorType(self.x),
+ }
+ }
+ }
+
+ /// Given that this cursor's referent is a reference to another type, or is
+ /// a declaration, get the cursor pointing to the referenced type or type of
+ /// the declared thing.
+ pub(crate) fn definition(&self) -> Option<Cursor> {
+ unsafe {
+ let ret = Cursor {
+ x: clang_getCursorDefinition(self.x),
+ };
+
+ if ret.is_valid() && ret.kind() != CXCursor_NoDeclFound {
+ Some(ret)
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Given that this cursor's referent is reference type, get the cursor
+ /// pointing to the referenced type.
+ pub(crate) fn referenced(&self) -> Option<Cursor> {
+ unsafe {
+ let ret = Cursor {
+ x: clang_getCursorReferenced(self.x),
+ };
+
+ if ret.is_valid() {
+ Some(ret)
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Get the canonical cursor for this referent.
+ ///
+ /// Many types can be declared multiple times before finally being properly
+ /// defined. This method allows us to get the canonical cursor for the
+ /// referent type.
+ pub(crate) fn canonical(&self) -> Cursor {
+ unsafe {
+ Cursor {
+ x: clang_getCanonicalCursor(self.x),
+ }
+ }
+ }
+
+ /// Given that this cursor points to either a template specialization or a
+ /// template instantiation, get a cursor pointing to the template definition
+ /// that is being specialized.
+ pub(crate) fn specialized(&self) -> Option<Cursor> {
+ unsafe {
+ let ret = Cursor {
+ x: clang_getSpecializedCursorTemplate(self.x),
+ };
+ if ret.is_valid() {
+ Some(ret)
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Assuming that this cursor's referent is a template declaration, get the
+ /// kind of cursor that would be generated for its specializations.
+ pub(crate) fn template_kind(&self) -> CXCursorKind {
+ unsafe { clang_getTemplateCursorKind(self.x) }
+ }
+
+ /// Traverse this cursor's referent and its children.
+ ///
+ /// Call the given function on each AST node traversed.
+ pub(crate) fn visit<Visitor>(&self, mut visitor: Visitor)
+ where
+ Visitor: FnMut(Cursor) -> CXChildVisitResult,
+ {
+ let data = &mut visitor as *mut Visitor;
+ unsafe {
+ clang_visitChildren(self.x, visit_children::<Visitor>, data.cast());
+ }
+ }
+
+ /// Traverse all of this cursor's children, sorted by where they appear in source code.
+ ///
+ /// Call the given function on each AST node traversed.
+ pub(crate) fn visit_sorted<Visitor>(
+ &self,
+ ctx: &mut BindgenContext,
+ mut visitor: Visitor,
+ ) where
+ Visitor: FnMut(&mut BindgenContext, Cursor),
+ {
+ // FIXME(#2556): The current source order stuff doesn't account well for different levels
+ // of includes, or includes that show up at the same byte offset because they are passed in
+ // via CLI.
+ const SOURCE_ORDER_ENABLED: bool = false;
+ if !SOURCE_ORDER_ENABLED {
+ return self.visit(|c| {
+ visitor(ctx, c);
+ CXChildVisit_Continue
+ });
+ }
+
+ let mut children = self.collect_children();
+ for child in &children {
+ if child.kind() == CXCursor_InclusionDirective {
+ if let Some(included_file) = child.get_included_file_name() {
+ let location = child.location();
+ let (source_file, _, _, offset) = location.location();
+
+ if let Some(source_file) = source_file.name() {
+ ctx.add_include(source_file, included_file, offset);
+ }
+ }
+ }
+ }
+ children
+ .sort_by(|child1, child2| child1.cmp_by_source_order(child2, ctx));
+ for child in children {
+ visitor(ctx, child);
+ }
+ }
+
+ /// Compare source order of two cursors, considering `#include` directives.
+ ///
+ /// Built-in items provided by the compiler (which don't have a source file),
+ /// are sorted first. Remaining files are sorted by their position in the source file.
+ /// If the items' source files differ, they are sorted by the position of the first
+ /// `#include` for their source file. If no source files are included, `None` is returned.
+ fn cmp_by_source_order(
+ &self,
+ other: &Self,
+ ctx: &BindgenContext,
+ ) -> cmp::Ordering {
+ let (file, _, _, offset) = self.location().location();
+ let (other_file, _, _, other_offset) = other.location().location();
+
+ let (file, other_file) = match (file.name(), other_file.name()) {
+ (Some(file), Some(other_file)) => (file, other_file),
+ // Built-in definitions should come first.
+ (Some(_), None) => return cmp::Ordering::Greater,
+ (None, Some(_)) => return cmp::Ordering::Less,
+ (None, None) => return cmp::Ordering::Equal,
+ };
+
+ if file == other_file {
+ // Both items are in the same source file, compare by byte offset.
+ return offset.cmp(&other_offset);
+ }
+
+ let include_location = ctx.included_file_location(&file);
+ let other_include_location = ctx.included_file_location(&other_file);
+ match (include_location, other_include_location) {
+ (Some((file2, offset2)), _) if file2 == other_file => {
+ offset2.cmp(&other_offset)
+ }
+ (Some(_), None) => cmp::Ordering::Greater,
+ (_, Some((other_file2, other_offset2))) if file == other_file2 => {
+ offset.cmp(&other_offset2)
+ }
+ (None, Some(_)) => cmp::Ordering::Less,
+ (Some((file2, offset2)), Some((other_file2, other_offset2))) => {
+ if file2 == other_file2 {
+ offset2.cmp(&other_offset2)
+ } else {
+ cmp::Ordering::Equal
+ }
+ }
+ (None, None) => cmp::Ordering::Equal,
+ }
+ }
+
+ /// Collect all of this cursor's children into a vec and return them.
+ pub(crate) fn collect_children(&self) -> Vec<Cursor> {
+ let mut children = vec![];
+ self.visit(|c| {
+ children.push(c);
+ CXChildVisit_Continue
+ });
+ children
+ }
+
+ /// Does this cursor have any children?
+ pub(crate) fn has_children(&self) -> bool {
+ let mut has_children = false;
+ self.visit(|_| {
+ has_children = true;
+ CXChildVisit_Break
+ });
+ has_children
+ }
+
+ /// Does this cursor have at least `n` children?
+ pub(crate) fn has_at_least_num_children(&self, n: usize) -> bool {
+ assert!(n > 0);
+ let mut num_left = n;
+ self.visit(|_| {
+ num_left -= 1;
+ if num_left == 0 {
+ CXChildVisit_Break
+ } else {
+ CXChildVisit_Continue
+ }
+ });
+ num_left == 0
+ }
+
+ /// Returns whether the given location contains a cursor with the given
+ /// kind in the first level of nesting underneath (doesn't look
+ /// recursively).
+ pub(crate) fn contains_cursor(&self, kind: CXCursorKind) -> bool {
+ let mut found = false;
+
+ self.visit(|c| {
+ if c.kind() == kind {
+ found = true;
+ CXChildVisit_Break
+ } else {
+ CXChildVisit_Continue
+ }
+ });
+
+ found
+ }
+
+ /// Is the referent an inlined function?
+ pub(crate) fn is_inlined_function(&self) -> bool {
+ unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 }
+ }
+
+ /// Is the referent a defaulted function?
+ pub(crate) fn is_defaulted_function(&self) -> bool {
+ unsafe { clang_CXXMethod_isDefaulted(self.x) != 0 }
+ }
+
+ /// Is the referent a deleted function?
+ pub(crate) fn is_deleted_function(&self) -> bool {
+ // Unfortunately, libclang doesn't yet have an API for checking if a
+ // member function is deleted, but the following should be a good
+ // enough approximation.
+ // Deleted functions are implicitly inline according to paragraph 4 of
+ // [dcl.fct.def.delete] in the C++ standard. Normal inline functions
+ // have a definition in the same translation unit, so if this is an
+ // inline function without a definition, and it's not a defaulted
+ // function, we can reasonably safely conclude that it's a deleted
+ // function.
+ self.is_inlined_function() &&
+ self.definition().is_none() &&
+ !self.is_defaulted_function()
+ }
+
+ /// Is the referent a bit field declaration?
+ pub(crate) fn is_bit_field(&self) -> bool {
+ unsafe { clang_Cursor_isBitField(self.x) != 0 }
+ }
+
+ /// Get a cursor to the bit field's width expression, or `None` if it's not
+ /// a bit field.
+ pub(crate) fn bit_width_expr(&self) -> Option<Cursor> {
+ if !self.is_bit_field() {
+ return None;
+ }
+
+ let mut result = None;
+ self.visit(|cur| {
+ // The first child may or may not be a TypeRef, depending on whether
+ // the field's type is builtin. Skip it.
+ if cur.kind() == CXCursor_TypeRef {
+ return CXChildVisit_Continue;
+ }
+
+ // The next expression or literal is the bit width.
+ result = Some(cur);
+
+ CXChildVisit_Break
+ });
+
+ result
+ }
+
+ /// Get the width of this cursor's referent bit field, or `None` if the
+ /// referent is not a bit field or if the width could not be evaluated.
+ pub(crate) fn bit_width(&self) -> Option<u32> {
+ // It is not safe to check the bit width without ensuring it doesn't
+ // depend on a template parameter. See
+ // https://github.com/rust-lang/rust-bindgen/issues/2239
+ if self.bit_width_expr()?.is_dependent_on_template_parameter() {
+ return None;
+ }
+
+ unsafe {
+ let w = clang_getFieldDeclBitWidth(self.x);
+ if w == -1 {
+ None
+ } else {
+ Some(w as u32)
+ }
+ }
+ }
+
+ /// Get the integer representation type used to hold this cursor's referent
+ /// enum type.
+ pub(crate) fn enum_type(&self) -> Option<Type> {
+ unsafe {
+ let t = Type {
+ x: clang_getEnumDeclIntegerType(self.x),
+ };
+ if t.is_valid() {
+ Some(t)
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Get the boolean constant value for this cursor's enum variant referent.
+ ///
+ /// Returns None if the cursor's referent is not an enum variant.
+ pub(crate) fn enum_val_boolean(&self) -> Option<bool> {
+ unsafe {
+ if self.kind() == CXCursor_EnumConstantDecl {
+ Some(clang_getEnumConstantDeclValue(self.x) != 0)
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Get the signed constant value for this cursor's enum variant referent.
+ ///
+ /// Returns None if the cursor's referent is not an enum variant.
+ pub(crate) fn enum_val_signed(&self) -> Option<i64> {
+ unsafe {
+ if self.kind() == CXCursor_EnumConstantDecl {
+ #[allow(clippy::unnecessary_cast)]
+ Some(clang_getEnumConstantDeclValue(self.x) as i64)
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Get the unsigned constant value for this cursor's enum variant referent.
+ ///
+ /// Returns None if the cursor's referent is not an enum variant.
+ pub(crate) fn enum_val_unsigned(&self) -> Option<u64> {
+ unsafe {
+ if self.kind() == CXCursor_EnumConstantDecl {
+ #[allow(clippy::unnecessary_cast)]
+ Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64)
+ } else {
+ None
+ }
+ }
+ }
+
+ /// Does this cursor have the given attributes?
+ pub(crate) fn has_attrs<const N: usize>(
+ &self,
+ attrs: &[Attribute; N],
+ ) -> [bool; N] {
+ let mut found_attrs = [false; N];
+ let mut found_count = 0;
+
+ self.visit(|cur| {
+ let kind = cur.kind();
+ for (idx, attr) in attrs.iter().enumerate() {
+ let found_attr = &mut found_attrs[idx];
+ if !*found_attr {
+ // `attr.name` and` attr.token_kind` are checked against unexposed attributes only.
+ if attr.kind.map_or(false, |k| k == kind) ||
+ (kind == CXCursor_UnexposedAttr &&
+ cur.tokens().iter().any(|t| {
+ t.kind == attr.token_kind &&
+ t.spelling() == attr.name
+ }))
+ {
+ *found_attr = true;
+ found_count += 1;
+
+ if found_count == N {
+ return CXChildVisit_Break;
+ }
+ }
+ }
+ }
+
+ CXChildVisit_Continue
+ });
+
+ found_attrs
+ }
+
+ /// Given that this cursor's referent is a `typedef`, get the `Type` that is
+ /// being aliased.
+ pub(crate) fn typedef_type(&self) -> Option<Type> {
+ let inner = Type {
+ x: unsafe { clang_getTypedefDeclUnderlyingType(self.x) },
+ };
+
+ if inner.is_valid() {
+ Some(inner)
+ } else {
+ None
+ }
+ }
+
+ /// Get the linkage kind for this cursor's referent.
+ ///
+ /// This only applies to functions and variables.
+ pub(crate) fn linkage(&self) -> CXLinkageKind {
+ unsafe { clang_getCursorLinkage(self.x) }
+ }
+
+ /// Get the visibility of this cursor's referent.
+ pub(crate) fn visibility(&self) -> CXVisibilityKind {
+ unsafe { clang_getCursorVisibility(self.x) }
+ }
+
+ /// Given that this cursor's referent is a function, return cursors to its
+ /// parameters.
+ ///
+ /// Returns None if the cursor's referent is not a function/method call or
+ /// declaration.
+ pub(crate) fn args(&self) -> Option<Vec<Cursor>> {
+ // match self.kind() {
+ // CXCursor_FunctionDecl |
+ // CXCursor_CXXMethod => {
+ self.num_args().ok().map(|num| {
+ (0..num)
+ .map(|i| Cursor {
+ x: unsafe { clang_Cursor_getArgument(self.x, i as c_uint) },
+ })
+ .collect()
+ })
+ }
+
+ /// Given that this cursor's referent is a function/method call or
+ /// declaration, return the number of arguments it takes.
+ ///
+ /// Returns Err if the cursor's referent is not a function/method call or
+ /// declaration.
+ pub(crate) fn num_args(&self) -> Result<u32, ()> {
+ unsafe {
+ let w = clang_Cursor_getNumArguments(self.x);
+ if w == -1 {
+ Err(())
+ } else {
+ Ok(w as u32)
+ }
+ }
+ }
+
+ /// Get the access specifier for this cursor's referent.
+ pub(crate) 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(crate) fn public_accessible(&self) -> bool {
+ let access = self.access_specifier();
+ access == CX_CXXPublic || access == CX_CXXInvalidAccessSpecifier
+ }
+
+ /// Is this cursor's referent a field declaration that is marked as
+ /// `mutable`?
+ pub(crate) fn is_mutable_field(&self) -> bool {
+ unsafe { clang_CXXField_isMutable(self.x) != 0 }
+ }
+
+ /// Get the offset of the field represented by the Cursor.
+ pub(crate) fn offset_of_field(&self) -> Result<usize, LayoutError> {
+ let offset = unsafe { clang_Cursor_getOffsetOfField(self.x) };
+
+ if offset < 0 {
+ Err(LayoutError::from(offset as i32))
+ } else {
+ Ok(offset as usize)
+ }
+ }
+
+ /// Is this cursor's referent a member function that is declared `static`?
+ pub(crate) fn method_is_static(&self) -> bool {
+ unsafe { clang_CXXMethod_isStatic(self.x) != 0 }
+ }
+
+ /// Is this cursor's referent a member function that is declared `const`?
+ pub(crate) fn method_is_const(&self) -> bool {
+ unsafe { clang_CXXMethod_isConst(self.x) != 0 }
+ }
+
+ /// Is this cursor's referent a member function that is virtual?
+ pub(crate) fn method_is_virtual(&self) -> bool {
+ unsafe { clang_CXXMethod_isVirtual(self.x) != 0 }
+ }
+
+ /// Is this cursor's referent a member function that is pure virtual?
+ pub(crate) fn method_is_pure_virtual(&self) -> bool {
+ unsafe { clang_CXXMethod_isPureVirtual(self.x) != 0 }
+ }
+
+ /// Is this cursor's referent a struct or class with virtual members?
+ pub(crate) fn is_virtual_base(&self) -> bool {
+ unsafe { clang_isVirtualBase(self.x) != 0 }
+ }
+
+ /// Try to evaluate this cursor.
+ pub(crate) fn evaluate(&self) -> Option<EvalResult> {
+ EvalResult::new(*self)
+ }
+
+ /// Return the result type for this cursor
+ pub(crate) fn ret_type(&self) -> Option<Type> {
+ let rt = Type {
+ x: unsafe { clang_getCursorResultType(self.x) },
+ };
+ if rt.is_valid() {
+ Some(rt)
+ } else {
+ None
+ }
+ }
+
+ /// Gets the tokens that correspond to that cursor.
+ pub(crate) fn tokens(&self) -> RawTokens {
+ RawTokens::new(self)
+ }
+
+ /// Gets the tokens that correspond to that cursor as `cexpr` tokens.
+ pub(crate) fn cexpr_tokens(self) -> Vec<cexpr::token::Token> {
+ self.tokens()
+ .iter()
+ .filter_map(|token| token.as_cexpr_token())
+ .collect()
+ }
+
+ /// Obtain the real path name of a cursor of InclusionDirective kind.
+ ///
+ /// Returns None if the cursor does not include a file, otherwise the file's full name
+ pub(crate) fn get_included_file_name(&self) -> Option<String> {
+ let file = unsafe { clang_sys::clang_getIncludedFile(self.x) };
+ if file.is_null() {
+ None
+ } else {
+ Some(unsafe {
+ cxstring_into_string(clang_sys::clang_getFileName(file))
+ })
+ }
+ }
+}
+
+/// A struct that owns the tokenizer result from a given cursor.
+pub(crate) struct RawTokens<'a> {
+ cursor: &'a Cursor,
+ tu: CXTranslationUnit,
+ tokens: *mut CXToken,
+ token_count: c_uint,
+}
+
+impl<'a> RawTokens<'a> {
+ fn new(cursor: &'a Cursor) -> Self {
+ let mut tokens = ptr::null_mut();
+ let mut token_count = 0;
+ let range = cursor.extent();
+ let tu = unsafe { clang_Cursor_getTranslationUnit(cursor.x) };
+ unsafe { clang_tokenize(tu, range, &mut tokens, &mut token_count) };
+ Self {
+ cursor,
+ tu,
+ tokens,
+ token_count,
+ }
+ }
+
+ fn as_slice(&self) -> &[CXToken] {
+ if self.tokens.is_null() {
+ return &[];
+ }
+ unsafe { slice::from_raw_parts(self.tokens, self.token_count as usize) }
+ }
+
+ /// Get an iterator over these tokens.
+ pub(crate) fn iter(&self) -> ClangTokenIterator {
+ ClangTokenIterator {
+ tu: self.tu,
+ raw: self.as_slice().iter(),
+ }
+ }
+}
+
+impl<'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(crate) struct ClangToken {
+ spelling: CXString,
+ /// The extent of the token. This is the same as the relevant member from
+ /// `CXToken`.
+ pub(crate) extent: CXSourceRange,
+ /// The kind of the token. This is the same as the relevant member from
+ /// `CXToken`.
+ pub(crate) kind: CXTokenKind,
+}
+
+impl ClangToken {
+ /// Get the token spelling, without being converted to utf-8.
+ pub(crate) fn spelling(&self) -> &[u8] {
+ let c_str = unsafe {
+ CStr::from_ptr(clang_getCString(self.spelling) as *const _)
+ };
+ c_str.to_bytes()
+ }
+
+ /// Converts a ClangToken to a `cexpr` token if possible.
+ pub(crate) fn as_cexpr_token(&self) -> Option<cexpr::token::Token> {
+ use cexpr::token;
+
+ let kind = match self.kind {
+ CXToken_Punctuation => token::Kind::Punctuation,
+ CXToken_Literal => token::Kind::Literal,
+ CXToken_Identifier => token::Kind::Identifier,
+ CXToken_Keyword => token::Kind::Keyword,
+ // NB: cexpr is not too happy about comments inside
+ // expressions, so we strip them down here.
+ CXToken_Comment => return None,
+ _ => {
+ warn!("Found unexpected token kind: {:?}", self);
+ return None;
+ }
+ };
+
+ Some(token::Token {
+ kind,
+ raw: self.spelling().to_vec().into_boxed_slice(),
+ })
+ }
+}
+
+impl Drop for ClangToken {
+ fn drop(&mut self) {
+ unsafe { clang_disposeString(self.spelling) }
+ }
+}
+
+/// An iterator over a set of Tokens.
+pub(crate) struct ClangTokenIterator<'a> {
+ tu: CXTranslationUnit,
+ raw: slice::Iter<'a, CXToken>,
+}
+
+impl<'a> Iterator for ClangTokenIterator<'a> {
+ type Item = ClangToken;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let raw = self.raw.next()?;
+ unsafe {
+ let kind = clang_getTokenKind(*raw);
+ let spelling = clang_getTokenSpelling(self.tu, *raw);
+ let extent = clang_getTokenExtent(self.tu, *raw);
+ Some(ClangToken {
+ kind,
+ extent,
+ spelling,
+ })
+ }
+ }
+}
+
+/// Checks whether the name looks like an identifier, i.e. is alphanumeric
+/// (including '_') and does not start with a digit.
+pub(crate) fn is_valid_identifier(name: &str) -> bool {
+ let mut chars = name.chars();
+ let first_valid = chars
+ .next()
+ .map(|c| c.is_alphabetic() || c == '_')
+ .unwrap_or(false);
+
+ first_valid && chars.all(|c| c.is_alphanumeric() || c == '_')
+}
+
+extern "C" fn visit_children<Visitor>(
+ cur: CXCursor,
+ _parent: CXCursor,
+ data: CXClientData,
+) -> CXChildVisitResult
+where
+ Visitor: FnMut(Cursor) -> CXChildVisitResult,
+{
+ let func: &mut Visitor = unsafe { &mut *(data as *mut Visitor) };
+ let child = Cursor { x: cur };
+
+ (*func)(child)
+}
+
+impl PartialEq for Cursor {
+ fn eq(&self, other: &Cursor) -> bool {
+ unsafe { clang_equalCursors(self.x, other.x) == 1 }
+ }
+}
+
+impl Eq for Cursor {}
+
+impl Hash for Cursor {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ unsafe { clang_hashCursor(self.x) }.hash(state)
+ }
+}
+
+/// The type of a node in clang's AST.
+#[derive(Clone, Copy)]
+pub(crate) struct Type {
+ x: CXType,
+}
+
+impl PartialEq for Type {
+ fn eq(&self, other: &Self) -> bool {
+ unsafe { clang_equalTypes(self.x, other.x) != 0 }
+ }
+}
+
+impl Eq for Type {}
+
+impl fmt::Debug for Type {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ fmt,
+ "Type({}, kind: {}, cconv: {}, decl: {:?}, canon: {:?})",
+ self.spelling(),
+ type_to_str(self.kind()),
+ self.call_conv(),
+ self.declaration(),
+ self.declaration().canonical()
+ )
+ }
+}
+
+/// An error about the layout of a struct, class, or type.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub(crate) enum LayoutError {
+ /// Asked for the layout of an invalid type.
+ Invalid,
+ /// Asked for the layout of an incomplete type.
+ Incomplete,
+ /// Asked for the layout of a dependent type.
+ Dependent,
+ /// Asked for the layout of a type that does not have constant size.
+ NotConstantSize,
+ /// Asked for the layout of a field in a type that does not have such a
+ /// field.
+ InvalidFieldName,
+ /// An unknown layout error.
+ Unknown,
+}
+
+impl ::std::convert::From<i32> for LayoutError {
+ fn from(val: i32) -> Self {
+ use self::LayoutError::*;
+
+ match val {
+ CXTypeLayoutError_Invalid => Invalid,
+ CXTypeLayoutError_Incomplete => Incomplete,
+ CXTypeLayoutError_Dependent => Dependent,
+ CXTypeLayoutError_NotConstantSize => NotConstantSize,
+ CXTypeLayoutError_InvalidFieldName => InvalidFieldName,
+ _ => Unknown,
+ }
+ }
+}
+
+impl Type {
+ /// Get this type's kind.
+ pub(crate) fn kind(&self) -> CXTypeKind {
+ self.x.kind
+ }
+
+ /// Get a cursor pointing to this type's declaration.
+ pub(crate) fn declaration(&self) -> Cursor {
+ unsafe {
+ Cursor {
+ x: clang_getTypeDeclaration(self.x),
+ }
+ }
+ }
+
+ /// Get the canonical declaration of this type, if it is available.
+ pub(crate) fn canonical_declaration(
+ &self,
+ location: Option<&Cursor>,
+ ) -> Option<CanonicalTypeDeclaration> {
+ let mut declaration = self.declaration();
+ if !declaration.is_valid() {
+ if let Some(location) = location {
+ let mut location = *location;
+ if let Some(referenced) = location.referenced() {
+ location = referenced;
+ }
+ if location.is_template_like() {
+ declaration = location;
+ }
+ }
+ }
+
+ let canonical = declaration.canonical();
+ if canonical.is_valid() && canonical.kind() != CXCursor_NoDeclFound {
+ Some(CanonicalTypeDeclaration(*self, canonical))
+ } else {
+ None
+ }
+ }
+
+ /// Get a raw display name for this type.
+ pub(crate) fn spelling(&self) -> String {
+ let s = unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) };
+ // Clang 5.0 introduced changes in the spelling API so it returned the
+ // full qualified name. Let's undo that here.
+ if s.split("::").all(is_valid_identifier) {
+ if let Some(s) = s.split("::").last() {
+ return s.to_owned();
+ }
+ }
+
+ s
+ }
+
+ /// Is this type const qualified?
+ pub(crate) fn is_const(&self) -> bool {
+ unsafe { clang_isConstQualifiedType(self.x) != 0 }
+ }
+
+ #[inline]
+ fn is_non_deductible_auto_type(&self) -> bool {
+ debug_assert_eq!(self.kind(), CXType_Auto);
+ self.canonical_type() == *self
+ }
+
+ #[inline]
+ fn clang_size_of(&self, ctx: &BindgenContext) -> c_longlong {
+ match self.kind() {
+ // Work-around https://bugs.llvm.org/show_bug.cgi?id=40975
+ CXType_RValueReference | CXType_LValueReference => {
+ ctx.target_pointer_size() as c_longlong
+ }
+ // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
+ CXType_Auto if self.is_non_deductible_auto_type() => -6,
+ _ => unsafe { clang_Type_getSizeOf(self.x) },
+ }
+ }
+
+ #[inline]
+ fn clang_align_of(&self, ctx: &BindgenContext) -> c_longlong {
+ match self.kind() {
+ // Work-around https://bugs.llvm.org/show_bug.cgi?id=40975
+ CXType_RValueReference | CXType_LValueReference => {
+ ctx.target_pointer_size() as c_longlong
+ }
+ // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
+ CXType_Auto if self.is_non_deductible_auto_type() => -6,
+ _ => unsafe { clang_Type_getAlignOf(self.x) },
+ }
+ }
+
+ /// What is the size of this type? Paper over invalid types by returning `0`
+ /// for them.
+ pub(crate) fn size(&self, ctx: &BindgenContext) -> usize {
+ let val = self.clang_size_of(ctx);
+ if val < 0 {
+ 0
+ } else {
+ val as usize
+ }
+ }
+
+ /// What is the size of this type?
+ pub(crate) fn fallible_size(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Result<usize, LayoutError> {
+ let val = self.clang_size_of(ctx);
+ if val < 0 {
+ Err(LayoutError::from(val as i32))
+ } else {
+ Ok(val as usize)
+ }
+ }
+
+ /// What is the alignment of this type? Paper over invalid types by
+ /// returning `0`.
+ pub(crate) fn align(&self, ctx: &BindgenContext) -> usize {
+ let val = self.clang_align_of(ctx);
+ if val < 0 {
+ 0
+ } else {
+ val as usize
+ }
+ }
+
+ /// What is the alignment of this type?
+ pub(crate) fn fallible_align(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Result<usize, LayoutError> {
+ let val = self.clang_align_of(ctx);
+ if val < 0 {
+ Err(LayoutError::from(val as i32))
+ } else {
+ Ok(val as usize)
+ }
+ }
+
+ /// Get the layout for this type, or an error describing why it does not
+ /// have a valid layout.
+ pub(crate) fn fallible_layout(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Result<crate::ir::layout::Layout, LayoutError> {
+ use crate::ir::layout::Layout;
+ let size = self.fallible_size(ctx)?;
+ let align = self.fallible_align(ctx)?;
+ Ok(Layout::new(size, align))
+ }
+
+ /// Get the number of template arguments this type has, or `None` if it is
+ /// not some kind of template.
+ pub(crate) fn num_template_args(&self) -> Option<u32> {
+ let n = unsafe { clang_Type_getNumTemplateArguments(self.x) };
+ if n >= 0 {
+ Some(n as u32)
+ } else {
+ debug_assert_eq!(n, -1);
+ None
+ }
+ }
+
+ /// If this type is a class template specialization, return its
+ /// template arguments. Otherwise, return None.
+ pub(crate) fn template_args(&self) -> Option<TypeTemplateArgIterator> {
+ self.num_template_args().map(|n| TypeTemplateArgIterator {
+ x: self.x,
+ length: n,
+ index: 0,
+ })
+ }
+
+ /// Given that this type is a function prototype, return the types of its parameters.
+ ///
+ /// Returns None if the type is not a function prototype.
+ pub(crate) fn args(&self) -> Option<Vec<Type>> {
+ self.num_args().ok().map(|num| {
+ (0..num)
+ .map(|i| Type {
+ x: unsafe { clang_getArgType(self.x, i as c_uint) },
+ })
+ .collect()
+ })
+ }
+
+ /// Given that this type is a function prototype, return the number of arguments it takes.
+ ///
+ /// Returns Err if the type is not a function prototype.
+ pub(crate) fn num_args(&self) -> Result<u32, ()> {
+ unsafe {
+ let w = clang_getNumArgTypes(self.x);
+ if w == -1 {
+ Err(())
+ } else {
+ Ok(w as u32)
+ }
+ }
+ }
+
+ /// Given that this type is a pointer type, return the type that it points
+ /// to.
+ pub(crate) fn pointee_type(&self) -> Option<Type> {
+ match self.kind() {
+ CXType_Pointer |
+ CXType_RValueReference |
+ CXType_LValueReference |
+ CXType_MemberPointer |
+ CXType_BlockPointer |
+ CXType_ObjCObjectPointer => {
+ let ret = Type {
+ x: unsafe { clang_getPointeeType(self.x) },
+ };
+ debug_assert!(ret.is_valid());
+ Some(ret)
+ }
+ _ => None,
+ }
+ }
+
+ /// Given that this type is an array, vector, or complex type, return the
+ /// type of its elements.
+ pub(crate) fn elem_type(&self) -> Option<Type> {
+ let current_type = Type {
+ x: unsafe { clang_getElementType(self.x) },
+ };
+ if current_type.is_valid() {
+ Some(current_type)
+ } else {
+ None
+ }
+ }
+
+ /// Given that this type is an array or vector type, return its number of
+ /// elements.
+ pub(crate) fn num_elements(&self) -> Option<usize> {
+ let num_elements_returned = unsafe { clang_getNumElements(self.x) };
+ if num_elements_returned != -1 {
+ Some(num_elements_returned as usize)
+ } else {
+ None
+ }
+ }
+
+ /// Get the canonical version of this type. This sees through `typedef`s and
+ /// aliases to get the underlying, canonical type.
+ pub(crate) fn canonical_type(&self) -> Type {
+ unsafe {
+ Type {
+ x: clang_getCanonicalType(self.x),
+ }
+ }
+ }
+
+ /// Is this type a variadic function type?
+ pub(crate) fn is_variadic(&self) -> bool {
+ unsafe { clang_isFunctionTypeVariadic(self.x) != 0 }
+ }
+
+ /// Given that this type is a function type, get the type of its return
+ /// value.
+ pub(crate) fn ret_type(&self) -> Option<Type> {
+ let rt = Type {
+ x: unsafe { clang_getResultType(self.x) },
+ };
+ if rt.is_valid() {
+ Some(rt)
+ } else {
+ None
+ }
+ }
+
+ /// Given that this type is a function type, get its calling convention. If
+ /// this is not a function type, `CXCallingConv_Invalid` is returned.
+ pub(crate) fn call_conv(&self) -> CXCallingConv {
+ unsafe { clang_getFunctionTypeCallingConv(self.x) }
+ }
+
+ /// For elaborated types (types which use `class`, `struct`, or `union` to
+ /// disambiguate types from local bindings), get the underlying type.
+ pub(crate) fn named(&self) -> Type {
+ unsafe {
+ Type {
+ x: clang_Type_getNamedType(self.x),
+ }
+ }
+ }
+
+ /// Is this a valid type?
+ pub(crate) fn is_valid(&self) -> bool {
+ self.kind() != CXType_Invalid
+ }
+
+ /// Is this a valid and exposed type?
+ pub(crate) fn is_valid_and_exposed(&self) -> bool {
+ self.is_valid() && self.kind() != CXType_Unexposed
+ }
+
+ /// Is this type a fully instantiated template?
+ pub(crate) fn is_fully_instantiated_template(&self) -> bool {
+ // Yep, the spelling of this containing type-parameter is extremely
+ // nasty... But can happen in <type_traits>. Unfortunately I couldn't
+ // reduce it enough :(
+ self.template_args().map_or(false, |args| args.len() > 0) &&
+ !matches!(
+ self.declaration().kind(),
+ CXCursor_ClassTemplatePartialSpecialization |
+ CXCursor_TypeAliasTemplateDecl |
+ CXCursor_TemplateTemplateParameter
+ )
+ }
+
+ /// Is this type an associated template type? Eg `T::Associated` in
+ /// this example:
+ ///
+ /// ```c++
+ /// template <typename T>
+ /// class Foo {
+ /// typename T::Associated member;
+ /// };
+ /// ```
+ pub(crate) fn is_associated_type(&self) -> bool {
+ // This is terrible :(
+ fn hacky_parse_associated_type<S: AsRef<str>>(spelling: S) -> bool {
+ lazy_static! {
+ static ref ASSOC_TYPE_RE: regex::Regex = regex::Regex::new(
+ r"typename type\-parameter\-\d+\-\d+::.+"
+ )
+ .unwrap();
+ }
+ ASSOC_TYPE_RE.is_match(spelling.as_ref())
+ }
+
+ self.kind() == CXType_Unexposed &&
+ (hacky_parse_associated_type(self.spelling()) ||
+ hacky_parse_associated_type(
+ self.canonical_type().spelling(),
+ ))
+ }
+}
+
+/// The `CanonicalTypeDeclaration` type exists as proof-by-construction that its
+/// cursor is the canonical declaration for its type. If you have a
+/// `CanonicalTypeDeclaration` instance, you know for sure that the type and
+/// cursor match up in a canonical declaration relationship, and it simply
+/// cannot be otherwise.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct CanonicalTypeDeclaration(Type, Cursor);
+
+impl CanonicalTypeDeclaration {
+ /// Get the type.
+ pub(crate) fn ty(&self) -> &Type {
+ &self.0
+ }
+
+ /// Get the type's canonical declaration cursor.
+ pub(crate) fn cursor(&self) -> &Cursor {
+ &self.1
+ }
+}
+
+/// An iterator for a type's template arguments.
+pub(crate) struct TypeTemplateArgIterator {
+ x: CXType,
+ length: u32,
+ index: u32,
+}
+
+impl Iterator for TypeTemplateArgIterator {
+ type Item = Type;
+ fn next(&mut self) -> Option<Type> {
+ if self.index < self.length {
+ let idx = self.index as c_uint;
+ self.index += 1;
+ Some(Type {
+ x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) },
+ })
+ } else {
+ None
+ }
+ }
+}
+
+impl ExactSizeIterator for TypeTemplateArgIterator {
+ fn len(&self) -> usize {
+ assert!(self.index <= self.length);
+ (self.length - self.index) as usize
+ }
+}
+
+/// A `SourceLocation` is a file, line, column, and byte offset location for
+/// some source text.
+pub(crate) struct SourceLocation {
+ x: CXSourceLocation,
+}
+
+impl SourceLocation {
+ /// Get the (file, line, column, byte offset) tuple for this source
+ /// location.
+ pub(crate) fn location(&self) -> (File, usize, usize, usize) {
+ unsafe {
+ let mut file = mem::zeroed();
+ let mut line = 0;
+ let mut col = 0;
+ let mut off = 0;
+ clang_getSpellingLocation(
+ self.x, &mut file, &mut line, &mut col, &mut off,
+ );
+ (File { x: file }, line as usize, col as usize, off as usize)
+ }
+ }
+}
+
+impl fmt::Display for SourceLocation {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let (file, line, col, _) = self.location();
+ if let Some(name) = file.name() {
+ write!(f, "{}:{}:{}", name, line, col)
+ } else {
+ "builtin definitions".fmt(f)
+ }
+ }
+}
+
+impl fmt::Debug for SourceLocation {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self)
+ }
+}
+
+/// A comment in the source text.
+///
+/// Comments are sort of parsed by Clang, and have a tree structure.
+pub(crate) struct Comment {
+ x: CXComment,
+}
+
+impl Comment {
+ /// What kind of comment is this?
+ pub(crate) fn kind(&self) -> CXCommentKind {
+ unsafe { clang_Comment_getKind(self.x) }
+ }
+
+ /// Get this comment's children comment
+ pub(crate) fn get_children(&self) -> CommentChildrenIterator {
+ CommentChildrenIterator {
+ parent: self.x,
+ length: unsafe { clang_Comment_getNumChildren(self.x) },
+ index: 0,
+ }
+ }
+
+ /// Given that this comment is the start or end of an HTML tag, get its tag
+ /// name.
+ pub(crate) fn get_tag_name(&self) -> String {
+ unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) }
+ }
+
+ /// Given that this comment is an HTML start tag, get its attributes.
+ pub(crate) fn get_tag_attrs(&self) -> CommentAttributesIterator {
+ CommentAttributesIterator {
+ x: self.x,
+ length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) },
+ index: 0,
+ }
+ }
+}
+
+/// An iterator for a comment's children
+pub(crate) struct CommentChildrenIterator {
+ parent: CXComment,
+ length: c_uint,
+ index: c_uint,
+}
+
+impl Iterator for CommentChildrenIterator {
+ type Item = Comment;
+ fn next(&mut self) -> Option<Comment> {
+ if self.index < self.length {
+ let idx = self.index;
+ self.index += 1;
+ Some(Comment {
+ x: unsafe { clang_Comment_getChild(self.parent, idx) },
+ })
+ } else {
+ None
+ }
+ }
+}
+
+/// An HTML start tag comment attribute
+pub(crate) struct CommentAttribute {
+ /// HTML start tag attribute name
+ pub(crate) name: String,
+ /// HTML start tag attribute value
+ pub(crate) value: String,
+}
+
+/// An iterator for a comment's attributes
+pub(crate) struct CommentAttributesIterator {
+ x: CXComment,
+ length: c_uint,
+ index: c_uint,
+}
+
+impl Iterator for CommentAttributesIterator {
+ type Item = CommentAttribute;
+ fn next(&mut self) -> Option<CommentAttribute> {
+ if self.index < self.length {
+ let idx = self.index;
+ self.index += 1;
+ Some(CommentAttribute {
+ name: unsafe {
+ cxstring_into_string(clang_HTMLStartTag_getAttrName(
+ self.x, idx,
+ ))
+ },
+ value: unsafe {
+ cxstring_into_string(clang_HTMLStartTag_getAttrValue(
+ self.x, idx,
+ ))
+ },
+ })
+ } else {
+ None
+ }
+ }
+}
+
+/// A source file.
+pub(crate) struct File {
+ x: CXFile,
+}
+
+impl File {
+ /// Get the name of this source file.
+ pub(crate) fn name(&self) -> Option<String> {
+ if self.x.is_null() {
+ return None;
+ }
+ Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) })
+ }
+}
+
+fn cxstring_to_string_leaky(s: CXString) -> String {
+ if s.data.is_null() {
+ return "".to_owned();
+ }
+ let c_str = unsafe { CStr::from_ptr(clang_getCString(s) as *const _) };
+ c_str.to_string_lossy().into_owned()
+}
+
+fn cxstring_into_string(s: CXString) -> String {
+ let ret = cxstring_to_string_leaky(s);
+ unsafe { clang_disposeString(s) };
+ ret
+}
+
+/// An `Index` is an environment for a set of translation units that will
+/// typically end up linked together in one final binary.
+pub(crate) struct Index {
+ x: CXIndex,
+}
+
+impl Index {
+ /// Construct a new `Index`.
+ ///
+ /// The `pch` parameter controls whether declarations in pre-compiled
+ /// headers are included when enumerating a translation unit's "locals".
+ ///
+ /// The `diag` parameter controls whether debugging diagnostics are enabled.
+ pub(crate) fn new(pch: bool, diag: bool) -> Index {
+ unsafe {
+ Index {
+ x: clang_createIndex(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(crate) struct TranslationUnit {
+ x: CXTranslationUnit,
+}
+
+impl fmt::Debug for TranslationUnit {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "TranslationUnit {{ }}")
+ }
+}
+
+impl TranslationUnit {
+ /// Parse a source file into a translation unit.
+ pub(crate) fn parse(
+ ix: &Index,
+ file: &str,
+ cmd_args: &[Box<str>],
+ unsaved: &[UnsavedFile],
+ opts: CXTranslationUnit_Flags,
+ ) -> Option<TranslationUnit> {
+ let fname = CString::new(file).unwrap();
+ let _c_args: Vec<CString> = cmd_args
+ .iter()
+ .map(|s| CString::new(s.as_bytes()).unwrap())
+ .collect();
+ let c_args: Vec<*const c_char> =
+ _c_args.iter().map(|s| s.as_ptr()).collect();
+ let mut c_unsaved: Vec<CXUnsavedFile> =
+ unsaved.iter().map(|f| f.x).collect();
+ let tu = unsafe {
+ clang_parseTranslationUnit(
+ ix.x,
+ fname.as_ptr(),
+ c_args.as_ptr(),
+ c_args.len() as c_int,
+ c_unsaved.as_mut_ptr(),
+ c_unsaved.len() as c_uint,
+ opts,
+ )
+ };
+ if tu.is_null() {
+ None
+ } else {
+ Some(TranslationUnit { x: tu })
+ }
+ }
+
+ /// Get the Clang diagnostic information associated with this translation
+ /// unit.
+ pub(crate) fn diags(&self) -> Vec<Diagnostic> {
+ unsafe {
+ let num = clang_getNumDiagnostics(self.x) as usize;
+ let mut diags = vec![];
+ for i in 0..num {
+ diags.push(Diagnostic {
+ x: clang_getDiagnostic(self.x, i as c_uint),
+ });
+ }
+ diags
+ }
+ }
+
+ /// Get a cursor pointing to the root of this translation unit's AST.
+ pub(crate) fn cursor(&self) -> Cursor {
+ unsafe {
+ Cursor {
+ x: clang_getTranslationUnitCursor(self.x),
+ }
+ }
+ }
+
+ /// Is this the null translation unit?
+ pub(crate) fn is_null(&self) -> bool {
+ self.x.is_null()
+ }
+}
+
+impl Drop for TranslationUnit {
+ fn drop(&mut self) {
+ unsafe {
+ clang_disposeTranslationUnit(self.x);
+ }
+ }
+}
+
+/// A diagnostic message generated while parsing a translation unit.
+pub(crate) struct Diagnostic {
+ x: CXDiagnostic,
+}
+
+impl Diagnostic {
+ /// Format this diagnostic message as a string, using the given option bit
+ /// flags.
+ pub(crate) fn format(&self) -> String {
+ unsafe {
+ let opts = clang_defaultDiagnosticDisplayOptions();
+ cxstring_into_string(clang_formatDiagnostic(self.x, opts))
+ }
+ }
+
+ /// What is the severity of this diagnostic message?
+ pub(crate) fn severity(&self) -> CXDiagnosticSeverity {
+ unsafe { clang_getDiagnosticSeverity(self.x) }
+ }
+}
+
+impl Drop for Diagnostic {
+ /// Destroy this diagnostic message.
+ fn drop(&mut self) {
+ unsafe {
+ clang_disposeDiagnostic(self.x);
+ }
+ }
+}
+
+/// A file which has not been saved to disk.
+pub(crate) struct UnsavedFile {
+ x: CXUnsavedFile,
+ /// The name of the unsaved file. Kept here to avoid leaving dangling pointers in
+ /// `CXUnsavedFile`.
+ pub(crate) name: CString,
+ contents: CString,
+}
+
+impl UnsavedFile {
+ /// Construct a new unsaved file with the given `name` and `contents`.
+ pub(crate) fn new(name: &str, contents: &str) -> UnsavedFile {
+ let name = CString::new(name.as_bytes()).unwrap();
+ let contents = CString::new(contents.as_bytes()).unwrap();
+ let x = CXUnsavedFile {
+ Filename: name.as_ptr(),
+ Contents: contents.as_ptr(),
+ Length: contents.as_bytes().len() as c_ulong,
+ };
+ UnsavedFile { x, name, contents }
+ }
+}
+
+impl fmt::Debug for UnsavedFile {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ fmt,
+ "UnsavedFile(name: {:?}, contents: {:?})",
+ self.name, self.contents
+ )
+ }
+}
+
+/// Convert a cursor kind into a static string.
+pub(crate) fn kind_to_str(x: CXCursorKind) -> String {
+ unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) }
+}
+
+/// Convert a type kind to a static string.
+pub(crate) fn type_to_str(x: CXTypeKind) -> String {
+ unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) }
+}
+
+/// Dump the Clang AST to stdout for debugging purposes.
+pub(crate) fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
+ fn print_indent<S: AsRef<str>>(depth: isize, s: S) {
+ for _ in 0..depth {
+ print!(" ");
+ }
+ println!("{}", s.as_ref());
+ }
+
+ fn print_cursor<S: AsRef<str>>(depth: isize, prefix: S, c: &Cursor) {
+ let prefix = prefix.as_ref();
+ print_indent(
+ depth,
+ format!(" {}kind = {}", prefix, kind_to_str(c.kind())),
+ );
+ print_indent(
+ depth,
+ format!(" {}spelling = \"{}\"", prefix, c.spelling()),
+ );
+ print_indent(depth, format!(" {}location = {}", prefix, c.location()));
+ print_indent(
+ depth,
+ format!(" {}is-definition? {}", prefix, c.is_definition()),
+ );
+ print_indent(
+ depth,
+ format!(" {}is-declaration? {}", prefix, c.is_declaration()),
+ );
+ print_indent(
+ depth,
+ format!(
+ " {}is-inlined-function? {}",
+ prefix,
+ c.is_inlined_function()
+ ),
+ );
+
+ let templ_kind = c.template_kind();
+ if templ_kind != CXCursor_NoDeclFound {
+ print_indent(
+ depth,
+ format!(
+ " {}template-kind = {}",
+ prefix,
+ kind_to_str(templ_kind)
+ ),
+ );
+ }
+ if let Some(usr) = c.usr() {
+ print_indent(depth, format!(" {}usr = \"{}\"", prefix, usr));
+ }
+ if let Ok(num) = c.num_args() {
+ print_indent(depth, format!(" {}number-of-args = {}", prefix, num));
+ }
+ if let Some(num) = c.num_template_args() {
+ print_indent(
+ depth,
+ format!(" {}number-of-template-args = {}", prefix, num),
+ );
+ }
+
+ if c.is_bit_field() {
+ let width = match c.bit_width() {
+ Some(w) => w.to_string(),
+ None => "<unevaluable>".to_string(),
+ };
+ print_indent(depth, format!(" {}bit-width = {}", prefix, width));
+ }
+
+ if let Some(ty) = c.enum_type() {
+ print_indent(
+ depth,
+ format!(" {}enum-type = {}", prefix, type_to_str(ty.kind())),
+ );
+ }
+ if let Some(val) = c.enum_val_signed() {
+ print_indent(depth, format!(" {}enum-val = {}", prefix, val));
+ }
+ if let Some(ty) = c.typedef_type() {
+ print_indent(
+ depth,
+ format!(" {}typedef-type = {}", prefix, type_to_str(ty.kind())),
+ );
+ }
+ if let Some(ty) = c.ret_type() {
+ print_indent(
+ depth,
+ format!(" {}ret-type = {}", prefix, type_to_str(ty.kind())),
+ );
+ }
+
+ if let Some(refd) = c.referenced() {
+ if refd != *c {
+ println!();
+ print_cursor(
+ depth,
+ String::from(prefix) + "referenced.",
+ &refd,
+ );
+ }
+ }
+
+ let canonical = c.canonical();
+ if canonical != *c {
+ println!();
+ print_cursor(
+ depth,
+ String::from(prefix) + "canonical.",
+ &canonical,
+ );
+ }
+
+ if let Some(specialized) = c.specialized() {
+ if specialized != *c {
+ println!();
+ print_cursor(
+ depth,
+ String::from(prefix) + "specialized.",
+ &specialized,
+ );
+ }
+ }
+
+ if let Some(parent) = c.fallible_semantic_parent() {
+ println!();
+ print_cursor(
+ depth,
+ String::from(prefix) + "semantic-parent.",
+ &parent,
+ );
+ }
+ }
+
+ fn print_type<S: AsRef<str>>(depth: isize, prefix: S, ty: &Type) {
+ let prefix = prefix.as_ref();
+
+ let kind = ty.kind();
+ print_indent(depth, format!(" {}kind = {}", prefix, type_to_str(kind)));
+ if kind == CXType_Invalid {
+ return;
+ }
+
+ print_indent(depth, format!(" {}cconv = {}", prefix, ty.call_conv()));
+
+ print_indent(
+ depth,
+ format!(" {}spelling = \"{}\"", prefix, ty.spelling()),
+ );
+ let num_template_args =
+ unsafe { clang_Type_getNumTemplateArguments(ty.x) };
+ if num_template_args >= 0 {
+ print_indent(
+ depth,
+ format!(
+ " {}number-of-template-args = {}",
+ prefix, num_template_args
+ ),
+ );
+ }
+ if let Some(num) = ty.num_elements() {
+ print_indent(
+ depth,
+ format!(" {}number-of-elements = {}", prefix, num),
+ );
+ }
+ print_indent(
+ depth,
+ format!(" {}is-variadic? {}", prefix, ty.is_variadic()),
+ );
+
+ let canonical = ty.canonical_type();
+ if canonical != *ty {
+ println!();
+ print_type(depth, String::from(prefix) + "canonical.", &canonical);
+ }
+
+ if let Some(pointee) = ty.pointee_type() {
+ if pointee != *ty {
+ println!();
+ print_type(depth, String::from(prefix) + "pointee.", &pointee);
+ }
+ }
+
+ if let Some(elem) = ty.elem_type() {
+ if elem != *ty {
+ println!();
+ print_type(depth, String::from(prefix) + "elements.", &elem);
+ }
+ }
+
+ if let Some(ret) = ty.ret_type() {
+ if ret != *ty {
+ println!();
+ print_type(depth, String::from(prefix) + "return.", &ret);
+ }
+ }
+
+ let named = ty.named();
+ if named != *ty && named.is_valid() {
+ println!();
+ print_type(depth, String::from(prefix) + "named.", &named);
+ }
+ }
+
+ print_indent(depth, "(");
+ print_cursor(depth, "", c);
+
+ println!();
+ let ty = c.cur_type();
+ print_type(depth, "type.", &ty);
+
+ let declaration = ty.declaration();
+ if declaration != *c && declaration.kind() != CXCursor_NoDeclFound {
+ println!();
+ print_cursor(depth, "type.declaration.", &declaration);
+ }
+
+ // Recurse.
+ let mut found_children = false;
+ c.visit(|s| {
+ if !found_children {
+ println!();
+ found_children = true;
+ }
+ ast_dump(&s, depth + 1)
+ });
+
+ print_indent(depth, ")");
+
+ CXChildVisit_Continue
+}
+
+/// Try to extract the clang version to a string
+pub(crate) fn extract_clang_version() -> String {
+ unsafe { cxstring_into_string(clang_getClangVersion()) }
+}
+
+/// A wrapper for the result of evaluating an expression.
+#[derive(Debug)]
+pub(crate) struct EvalResult {
+ x: CXEvalResult,
+ ty: Type,
+}
+
+impl EvalResult {
+ /// Evaluate `cursor` and return the result.
+ pub(crate) fn new(cursor: Cursor) -> Option<Self> {
+ // Work around https://bugs.llvm.org/show_bug.cgi?id=42532, see:
+ // * https://github.com/rust-lang/rust-bindgen/issues/283
+ // * https://github.com/rust-lang/rust-bindgen/issues/1590
+ {
+ let mut found_cant_eval = false;
+ cursor.visit(|c| {
+ if c.kind() == CXCursor_TypeRef &&
+ c.cur_type().canonical_type().kind() == CXType_Unexposed
+ {
+ found_cant_eval = true;
+ return CXChildVisit_Break;
+ }
+
+ CXChildVisit_Recurse
+ });
+
+ if found_cant_eval {
+ return None;
+ }
+ }
+ Some(EvalResult {
+ x: unsafe { clang_Cursor_Evaluate(cursor.x) },
+ ty: cursor.cur_type().canonical_type(),
+ })
+ }
+
+ fn kind(&self) -> CXEvalResultKind {
+ unsafe { clang_EvalResult_getKind(self.x) }
+ }
+
+ /// Try to get back the result as a double.
+ pub(crate) fn as_double(&self) -> Option<f64> {
+ match self.kind() {
+ CXEval_Float => {
+ Some(unsafe { clang_EvalResult_getAsDouble(self.x) })
+ }
+ _ => None,
+ }
+ }
+
+ /// Try to get back the result as an integer.
+ pub(crate) fn as_int(&self) -> Option<i64> {
+ if self.kind() != CXEval_Int {
+ return None;
+ }
+
+ if unsafe { clang_EvalResult_isUnsignedInt(self.x) } != 0 {
+ let value = unsafe { clang_EvalResult_getAsUnsigned(self.x) };
+ if value > i64::max_value() as c_ulonglong {
+ return None;
+ }
+
+ return Some(value as i64);
+ }
+
+ let value = unsafe { clang_EvalResult_getAsLongLong(self.x) };
+ if value > i64::max_value() as c_longlong {
+ return None;
+ }
+ if value < i64::min_value() as c_longlong {
+ return None;
+ }
+ #[allow(clippy::unnecessary_cast)]
+ Some(value as i64)
+ }
+
+ /// Evaluates the expression as a literal string, that may or may not be
+ /// valid utf-8.
+ pub(crate) fn as_literal_string(&self) -> Option<Vec<u8>> {
+ if self.kind() != CXEval_StrLiteral {
+ return None;
+ }
+
+ let char_ty = self.ty.pointee_type().or_else(|| self.ty.elem_type())?;
+ match char_ty.kind() {
+ CXType_Char_S | CXType_SChar | CXType_Char_U | CXType_UChar => {
+ let ret = unsafe {
+ CStr::from_ptr(clang_EvalResult_getAsStr(self.x))
+ };
+ Some(ret.to_bytes().to_vec())
+ }
+ // FIXME: Support generating these.
+ CXType_Char16 => None,
+ CXType_Char32 => None,
+ CXType_WChar => None,
+ _ => None,
+ }
+ }
+}
+
+impl Drop for EvalResult {
+ fn drop(&mut self) {
+ unsafe { clang_EvalResult_dispose(self.x) };
+ }
+}
+/// ABI kinds as defined in
+/// <https://github.com/llvm/llvm-project/blob/ddf1de20a3f7db3bca1ef6ba7e6cbb90aac5fd2d/clang/include/clang/Basic/TargetCXXABI.def>
+#[derive(Debug, Eq, PartialEq, Copy, Clone)]
+pub(crate) enum ABIKind {
+ /// All the regular targets like Linux, Mac, WASM, etc. implement the Itanium ABI
+ GenericItanium,
+ /// The ABI used when compiling for the MSVC target
+ Microsoft,
+}
+
+/// Target information obtained from libclang.
+#[derive(Debug)]
+pub(crate) struct TargetInfo {
+ /// The target triple.
+ pub(crate) triple: String,
+ /// The width of the pointer _in bits_.
+ pub(crate) pointer_width: usize,
+ /// The ABI of the target
+ pub(crate) abi: ABIKind,
+}
+
+impl TargetInfo {
+ /// Tries to obtain target information from libclang.
+ pub(crate) fn new(tu: &TranslationUnit) -> Self {
+ let triple;
+ let pointer_width;
+ unsafe {
+ let ti = clang_getTranslationUnitTargetInfo(tu.x);
+ triple = cxstring_into_string(clang_TargetInfo_getTriple(ti));
+ pointer_width = clang_TargetInfo_getPointerWidth(ti);
+ clang_TargetInfo_dispose(ti);
+ }
+ assert!(pointer_width > 0);
+ assert_eq!(pointer_width % 8, 0);
+
+ let abi = if triple.contains("msvc") {
+ ABIKind::Microsoft
+ } else {
+ ABIKind::GenericItanium
+ };
+
+ TargetInfo {
+ triple,
+ pointer_width: pointer_width as usize,
+ abi,
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/codegen/bitfield_unit.rs b/third_party/rust/bindgen/codegen/bitfield_unit.rs
new file mode 100644
index 0000000000..73ec2bd629
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/bitfield_unit.rs
@@ -0,0 +1,102 @@
+#[repr(C)]
+#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct __BindgenBitfieldUnit<Storage> {
+ storage: Storage,
+}
+
+impl<Storage> __BindgenBitfieldUnit<Storage> {
+ #[inline]
+ pub const fn new(storage: Storage) -> Self {
+ Self { storage }
+ }
+}
+
+impl<Storage> __BindgenBitfieldUnit<Storage>
+where
+ Storage: AsRef<[u8]> + AsMut<[u8]>,
+{
+ #[inline]
+ pub fn get_bit(&self, index: usize) -> bool {
+ debug_assert!(index / 8 < self.storage.as_ref().len());
+
+ let byte_index = index / 8;
+ let byte = self.storage.as_ref()[byte_index];
+
+ let bit_index = if cfg!(target_endian = "big") {
+ 7 - (index % 8)
+ } else {
+ index % 8
+ };
+
+ let mask = 1 << bit_index;
+
+ byte & mask == mask
+ }
+
+ #[inline]
+ pub fn set_bit(&mut self, index: usize, val: bool) {
+ debug_assert!(index / 8 < self.storage.as_ref().len());
+
+ let byte_index = index / 8;
+ let byte = &mut self.storage.as_mut()[byte_index];
+
+ let bit_index = if cfg!(target_endian = "big") {
+ 7 - (index % 8)
+ } else {
+ index % 8
+ };
+
+ let mask = 1 << bit_index;
+ if val {
+ *byte |= mask;
+ } else {
+ *byte &= !mask;
+ }
+ }
+
+ #[inline]
+ pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
+ debug_assert!(bit_width <= 64);
+ debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
+ debug_assert!(
+ (bit_offset + (bit_width as usize)) / 8 <=
+ self.storage.as_ref().len()
+ );
+
+ let mut val = 0;
+
+ for i in 0..(bit_width as usize) {
+ if self.get_bit(i + bit_offset) {
+ let index = if cfg!(target_endian = "big") {
+ bit_width as usize - 1 - i
+ } else {
+ i
+ };
+ val |= 1 << index;
+ }
+ }
+
+ val
+ }
+
+ #[inline]
+ pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
+ debug_assert!(bit_width <= 64);
+ debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
+ debug_assert!(
+ (bit_offset + (bit_width as usize)) / 8 <=
+ self.storage.as_ref().len()
+ );
+
+ for i in 0..(bit_width as usize) {
+ let mask = 1 << i;
+ let val_bit_is_set = val & mask == mask;
+ let index = if cfg!(target_endian = "big") {
+ bit_width as usize - 1 - i
+ } else {
+ i
+ };
+ self.set_bit(index + bit_offset, val_bit_is_set);
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/codegen/bitfield_unit_tests.rs b/third_party/rust/bindgen/codegen/bitfield_unit_tests.rs
new file mode 100644
index 0000000000..e143e4ea78
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/bitfield_unit_tests.rs
@@ -0,0 +1,260 @@
+//! Tests for `__BindgenBitfieldUnit`.
+//!
+//! Note that bit-fields are allocated right to left (least to most significant
+//! bits).
+//!
+//! From the x86 PS ABI:
+//!
+//! ```c
+//! struct {
+//! int j : 5;
+//! int k : 6;
+//! int m : 7;
+//! };
+//! ```
+//!
+//! ```ignore
+//! +------------------------------------------------------------+
+//! | | | | |
+//! | padding | m | k | j |
+//! |31 18|17 11|10 5|4 0|
+//! +------------------------------------------------------------+
+//! ```
+
+use super::bitfield_unit::__BindgenBitfieldUnit;
+
+#[test]
+fn bitfield_unit_get_bit() {
+ let unit = __BindgenBitfieldUnit::<[u8; 2]>::new([0b10011101, 0b00011101]);
+
+ let mut bits = vec![];
+ for i in 0..16 {
+ bits.push(unit.get_bit(i));
+ }
+
+ println!();
+ println!("bits = {:?}", bits);
+ assert_eq!(
+ bits,
+ &[
+ // 0b10011101
+ true, false, true, true, true, false, false, true,
+ // 0b00011101
+ true, false, true, true, true, false, false, false
+ ]
+ );
+}
+
+#[test]
+fn bitfield_unit_set_bit() {
+ let mut unit =
+ __BindgenBitfieldUnit::<[u8; 2]>::new([0b00000000, 0b00000000]);
+
+ for i in 0..16 {
+ if i % 3 == 0 {
+ unit.set_bit(i, true);
+ }
+ }
+
+ for i in 0..16 {
+ assert_eq!(unit.get_bit(i), i % 3 == 0);
+ }
+
+ let mut unit =
+ __BindgenBitfieldUnit::<[u8; 2]>::new([0b11111111, 0b11111111]);
+
+ for i in 0..16 {
+ if i % 3 == 0 {
+ unit.set_bit(i, false);
+ }
+ }
+
+ for i in 0..16 {
+ assert_eq!(unit.get_bit(i), i % 3 != 0);
+ }
+}
+
+macro_rules! bitfield_unit_get {
+ (
+ $(
+ With $storage:expr , then get($start:expr, $len:expr) is $expected:expr;
+ )*
+ ) => {
+ #[test]
+ fn bitfield_unit_get() {
+ $({
+ let expected = $expected;
+ let unit = __BindgenBitfieldUnit::<_>::new($storage);
+ let actual = unit.get($start, $len);
+
+ println!();
+ println!("expected = {:064b}", expected);
+ println!("actual = {:064b}", actual);
+
+ assert_eq!(expected, actual);
+ })*
+ }
+ }
+}
+
+bitfield_unit_get! {
+ // Let's just exhaustively test getting the bits from a single byte, since
+ // there are few enough combinations...
+
+ With [0b11100010], then get(0, 1) is 0;
+ With [0b11100010], then get(1, 1) is 1;
+ With [0b11100010], then get(2, 1) is 0;
+ With [0b11100010], then get(3, 1) is 0;
+ With [0b11100010], then get(4, 1) is 0;
+ With [0b11100010], then get(5, 1) is 1;
+ With [0b11100010], then get(6, 1) is 1;
+ With [0b11100010], then get(7, 1) is 1;
+
+ With [0b11100010], then get(0, 2) is 0b10;
+ With [0b11100010], then get(1, 2) is 0b01;
+ With [0b11100010], then get(2, 2) is 0b00;
+ With [0b11100010], then get(3, 2) is 0b00;
+ With [0b11100010], then get(4, 2) is 0b10;
+ With [0b11100010], then get(5, 2) is 0b11;
+ With [0b11100010], then get(6, 2) is 0b11;
+
+ With [0b11100010], then get(0, 3) is 0b010;
+ With [0b11100010], then get(1, 3) is 0b001;
+ With [0b11100010], then get(2, 3) is 0b000;
+ With [0b11100010], then get(3, 3) is 0b100;
+ With [0b11100010], then get(4, 3) is 0b110;
+ With [0b11100010], then get(5, 3) is 0b111;
+
+ With [0b11100010], then get(0, 4) is 0b0010;
+ With [0b11100010], then get(1, 4) is 0b0001;
+ With [0b11100010], then get(2, 4) is 0b1000;
+ With [0b11100010], then get(3, 4) is 0b1100;
+ With [0b11100010], then get(4, 4) is 0b1110;
+
+ With [0b11100010], then get(0, 5) is 0b00010;
+ With [0b11100010], then get(1, 5) is 0b10001;
+ With [0b11100010], then get(2, 5) is 0b11000;
+ With [0b11100010], then get(3, 5) is 0b11100;
+
+ With [0b11100010], then get(0, 6) is 0b100010;
+ With [0b11100010], then get(1, 6) is 0b110001;
+ With [0b11100010], then get(2, 6) is 0b111000;
+
+ With [0b11100010], then get(0, 7) is 0b1100010;
+ With [0b11100010], then get(1, 7) is 0b1110001;
+
+ With [0b11100010], then get(0, 8) is 0b11100010;
+
+ // OK. Now let's test getting bits from across byte boundaries.
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(0, 16) is 0b1111111101010101;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(1, 16) is 0b0111111110101010;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(2, 16) is 0b0011111111010101;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(3, 16) is 0b0001111111101010;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(4, 16) is 0b0000111111110101;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(5, 16) is 0b0000011111111010;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(6, 16) is 0b0000001111111101;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(7, 16) is 0b0000000111111110;
+
+ With [0b01010101, 0b11111111, 0b00000000, 0b11111111],
+ then get(8, 16) is 0b0000000011111111;
+}
+
+macro_rules! bitfield_unit_set {
+ (
+ $(
+ set($start:expr, $len:expr, $val:expr) is $expected:expr;
+ )*
+ ) => {
+ #[test]
+ fn bitfield_unit_set() {
+ $(
+ let mut unit = __BindgenBitfieldUnit::<[u8; 4]>::new([0, 0, 0, 0]);
+ unit.set($start, $len, $val);
+ let actual = unit.get(0, 32);
+
+ println!();
+ println!("set({}, {}, {:032b}", $start, $len, $val);
+ println!("expected = {:064b}", $expected);
+ println!("actual = {:064b}", actual);
+
+ assert_eq!($expected, actual);
+ )*
+ }
+ }
+}
+
+bitfield_unit_set! {
+ // Once again, let's exhaustively test single byte combinations.
+
+ set(0, 1, 0b11111111) is 0b00000001;
+ set(1, 1, 0b11111111) is 0b00000010;
+ set(2, 1, 0b11111111) is 0b00000100;
+ set(3, 1, 0b11111111) is 0b00001000;
+ set(4, 1, 0b11111111) is 0b00010000;
+ set(5, 1, 0b11111111) is 0b00100000;
+ set(6, 1, 0b11111111) is 0b01000000;
+ set(7, 1, 0b11111111) is 0b10000000;
+
+ set(0, 2, 0b11111111) is 0b00000011;
+ set(1, 2, 0b11111111) is 0b00000110;
+ set(2, 2, 0b11111111) is 0b00001100;
+ set(3, 2, 0b11111111) is 0b00011000;
+ set(4, 2, 0b11111111) is 0b00110000;
+ set(5, 2, 0b11111111) is 0b01100000;
+ set(6, 2, 0b11111111) is 0b11000000;
+
+ set(0, 3, 0b11111111) is 0b00000111;
+ set(1, 3, 0b11111111) is 0b00001110;
+ set(2, 3, 0b11111111) is 0b00011100;
+ set(3, 3, 0b11111111) is 0b00111000;
+ set(4, 3, 0b11111111) is 0b01110000;
+ set(5, 3, 0b11111111) is 0b11100000;
+
+ set(0, 4, 0b11111111) is 0b00001111;
+ set(1, 4, 0b11111111) is 0b00011110;
+ set(2, 4, 0b11111111) is 0b00111100;
+ set(3, 4, 0b11111111) is 0b01111000;
+ set(4, 4, 0b11111111) is 0b11110000;
+
+ set(0, 5, 0b11111111) is 0b00011111;
+ set(1, 5, 0b11111111) is 0b00111110;
+ set(2, 5, 0b11111111) is 0b01111100;
+ set(3, 5, 0b11111111) is 0b11111000;
+
+ set(0, 6, 0b11111111) is 0b00111111;
+ set(1, 6, 0b11111111) is 0b01111110;
+ set(2, 6, 0b11111111) is 0b11111100;
+
+ set(0, 7, 0b11111111) is 0b01111111;
+ set(1, 7, 0b11111111) is 0b11111110;
+
+ set(0, 8, 0b11111111) is 0b11111111;
+
+ // And, now let's cross byte boundaries.
+
+ set(0, 16, 0b1111111111111111) is 0b00000000000000001111111111111111;
+ set(1, 16, 0b1111111111111111) is 0b00000000000000011111111111111110;
+ set(2, 16, 0b1111111111111111) is 0b00000000000000111111111111111100;
+ set(3, 16, 0b1111111111111111) is 0b00000000000001111111111111111000;
+ set(4, 16, 0b1111111111111111) is 0b00000000000011111111111111110000;
+ set(5, 16, 0b1111111111111111) is 0b00000000000111111111111111100000;
+ set(6, 16, 0b1111111111111111) is 0b00000000001111111111111111000000;
+ set(7, 16, 0b1111111111111111) is 0b00000000011111111111111110000000;
+ set(8, 16, 0b1111111111111111) is 0b00000000111111111111111100000000;
+}
diff --git a/third_party/rust/bindgen/codegen/dyngen.rs b/third_party/rust/bindgen/codegen/dyngen.rs
new file mode 100644
index 0000000000..c067fada0e
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/dyngen.rs
@@ -0,0 +1,201 @@
+use crate::codegen;
+use crate::ir::context::BindgenContext;
+use crate::ir::function::ClangAbi;
+use proc_macro2::Ident;
+
+/// Used to build the output tokens for dynamic bindings.
+#[derive(Default)]
+pub(crate) struct DynamicItems {
+ /// Tracks the tokens that will appears inside the library struct -- e.g.:
+ /// ```ignore
+ /// struct Lib {
+ /// __library: ::libloading::Library,
+ /// pub x: Result<unsafe extern ..., ::libloading::Error>, // <- tracks these
+ /// ...
+ /// }
+ /// ```
+ struct_members: Vec<proc_macro2::TokenStream>,
+
+ /// Tracks the tokens that will appear inside the library struct's implementation, e.g.:
+ ///
+ /// ```ignore
+ /// impl Lib {
+ /// ...
+ /// pub unsafe fn foo(&self, ...) { // <- tracks these
+ /// ...
+ /// }
+ /// }
+ /// ```
+ struct_implementation: Vec<proc_macro2::TokenStream>,
+
+ /// Tracks the initialization of the fields inside the `::new` constructor of the library
+ /// struct, e.g.:
+ /// ```ignore
+ /// impl Lib {
+ ///
+ /// pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
+ /// where
+ /// P: AsRef<::std::ffi::OsStr>,
+ /// {
+ /// ...
+ /// let foo = __library.get(...) ...; // <- tracks these
+ /// ...
+ /// }
+ ///
+ /// ...
+ /// }
+ /// ```
+ constructor_inits: Vec<proc_macro2::TokenStream>,
+
+ /// Tracks the information that is passed to the library struct at the end of the `::new`
+ /// constructor, e.g.:
+ /// ```ignore
+ /// impl LibFoo {
+ /// pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
+ /// where
+ /// P: AsRef<::std::ffi::OsStr>,
+ /// {
+ /// ...
+ /// Ok(LibFoo {
+ /// __library: __library,
+ /// foo,
+ /// bar, // <- tracks these
+ /// ...
+ /// })
+ /// }
+ /// }
+ /// ```
+ init_fields: Vec<proc_macro2::TokenStream>,
+}
+
+impl DynamicItems {
+ pub(crate) fn new() -> Self {
+ Self::default()
+ }
+
+ pub(crate) fn get_tokens(
+ &self,
+ lib_ident: Ident,
+ ctx: &BindgenContext,
+ ) -> 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;
+
+ let from_library = if ctx.options().wrap_unsafe_ops {
+ quote!(unsafe { Self::from_library(library) })
+ } else {
+ quote!(Self::from_library(library))
+ };
+
+ quote! {
+ extern crate libloading;
+
+ pub struct #lib_ident {
+ __library: ::libloading::Library,
+ #(#struct_members)*
+ }
+
+ impl #lib_ident {
+ pub unsafe fn new<P>(
+ path: P
+ ) -> Result<Self, ::libloading::Error>
+ where P: AsRef<::std::ffi::OsStr> {
+ let library = ::libloading::Library::new(path)?;
+ #from_library
+ }
+
+ pub unsafe fn from_library<L>(
+ library: L
+ ) -> Result<Self, ::libloading::Error>
+ where L: Into<::libloading::Library> {
+ let __library = library.into();
+ #( #constructor_inits )*
+ Ok(#lib_ident {
+ __library,
+ #( #init_fields ),*
+ })
+ }
+
+ #( #struct_implementation )*
+ }
+ }
+ }
+
+ #[allow(clippy::too_many_arguments)]
+ pub(crate) fn push(
+ &mut self,
+ ident: Ident,
+ abi: ClangAbi,
+ is_variadic: bool,
+ is_required: bool,
+ args: Vec<proc_macro2::TokenStream>,
+ args_identifiers: Vec<proc_macro2::TokenStream>,
+ ret: proc_macro2::TokenStream,
+ ret_ty: proc_macro2::TokenStream,
+ attributes: Vec<proc_macro2::TokenStream>,
+ ctx: &BindgenContext,
+ ) {
+ if !is_variadic {
+ assert_eq!(args.len(), args_identifiers.len());
+ }
+
+ let signature = quote! { unsafe extern #abi fn ( #( #args),* ) #ret };
+ let member = if is_required {
+ signature
+ } else {
+ quote! { Result<#signature, ::libloading::Error> }
+ };
+
+ self.struct_members.push(quote! {
+ pub #ident: #member,
+ });
+
+ // N.B: If the signature was required, it won't be wrapped in a Result<...>
+ // and we can simply call it directly.
+ let fn_ = if is_required {
+ quote! { self.#ident }
+ } else {
+ quote! { self.#ident.as_ref().expect("Expected function, got error.") }
+ };
+ let call_body = if ctx.options().wrap_unsafe_ops {
+ quote!(unsafe { (#fn_)(#( #args_identifiers ),*) })
+ } else {
+ quote!((#fn_)(#( #args_identifiers ),*) )
+ };
+
+ // We can't implement variadic functions from C easily, so we allow to
+ // access the function pointer so that the user can call it just fine.
+ if !is_variadic {
+ self.struct_implementation.push(quote! {
+ #(#attributes)*
+ pub unsafe fn #ident ( &self, #( #args ),* ) #ret_ty {
+ #call_body
+ }
+ });
+ }
+
+ // N.B: Unwrap the signature upon construction if it is required to be resolved.
+ let ident_str = codegen::helpers::ast_ty::cstr_expr(ident.to_string());
+ let library_get = if ctx.options().wrap_unsafe_ops {
+ quote!(unsafe { __library.get(#ident_str) })
+ } else {
+ quote!(__library.get(#ident_str))
+ };
+
+ self.constructor_inits.push(if is_required {
+ quote! {
+ let #ident = #library_get.map(|sym| *sym)?;
+ }
+ } else {
+ quote! {
+ let #ident = #library_get.map(|sym| *sym);
+ }
+ });
+
+ self.init_fields.push(quote! {
+ #ident
+ });
+ }
+}
diff --git a/third_party/rust/bindgen/codegen/error.rs b/third_party/rust/bindgen/codegen/error.rs
new file mode 100644
index 0000000000..82e921d771
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/error.rs
@@ -0,0 +1,53 @@
+use std::error;
+use std::fmt;
+
+/// Errors that can occur during code generation.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) enum Error {
+ /// Tried to generate an opaque blob for a type that did not have a layout.
+ NoLayoutForOpaqueBlob,
+
+ /// Tried to instantiate an opaque template definition, or a template
+ /// definition that is too difficult for us to understand (like a partial
+ /// template specialization).
+ InstantiationOfOpaqueType,
+
+ /// Function ABI is not supported.
+ UnsupportedAbi(&'static str),
+
+ /// The pointer type size does not match the target's pointer size.
+ InvalidPointerSize {
+ ty_name: String,
+ ty_size: usize,
+ ptr_size: usize,
+ },
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Error::NoLayoutForOpaqueBlob => {
+ "Tried to generate an opaque blob, but had no layout.".fmt(f)
+ }
+ Error::InstantiationOfOpaqueType => {
+ "Instantiation of opaque template type or partial template specialization."
+ .fmt(f)
+ }
+ Error::UnsupportedAbi(abi) => {
+ write!(
+ f,
+ "{} ABI is not supported by the configured Rust target.",
+ abi
+ )
+ }
+ Error::InvalidPointerSize { ty_name, ty_size, ptr_size } => {
+ write!(f, "The {} pointer type has size {} but the current target's pointer size is {}.", ty_name, ty_size, ptr_size)
+ }
+ }
+ }
+}
+
+impl error::Error for Error {}
+
+/// A `Result` of `T` or an error of `bindgen::codegen::error::Error`.
+pub(crate) type Result<T> = ::std::result::Result<T, Error>;
diff --git a/third_party/rust/bindgen/codegen/helpers.rs b/third_party/rust/bindgen/codegen/helpers.rs
new file mode 100644
index 0000000000..48bfe56dde
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/helpers.rs
@@ -0,0 +1,355 @@
+//! Helpers for code generation that don't need macro expansion.
+
+use crate::ir::context::BindgenContext;
+use crate::ir::layout::Layout;
+
+pub(crate) mod attributes {
+ use proc_macro2::{Ident, Span, TokenStream};
+ use std::{borrow::Cow, str::FromStr};
+
+ pub(crate) fn repr(which: &str) -> TokenStream {
+ let which = Ident::new(which, Span::call_site());
+ quote! {
+ #[repr( #which )]
+ }
+ }
+
+ pub(crate) fn repr_list(which_ones: &[&str]) -> TokenStream {
+ let which_ones = which_ones
+ .iter()
+ .cloned()
+ .map(|one| TokenStream::from_str(one).expect("repr to be valid"));
+ quote! {
+ #[repr( #( #which_ones ),* )]
+ }
+ }
+
+ pub(crate) fn derives(which_ones: &[&str]) -> TokenStream {
+ let which_ones = which_ones
+ .iter()
+ .cloned()
+ .map(|one| TokenStream::from_str(one).expect("derive to be valid"));
+ quote! {
+ #[derive( #( #which_ones ),* )]
+ }
+ }
+
+ pub(crate) fn inline() -> TokenStream {
+ quote! {
+ #[inline]
+ }
+ }
+
+ pub(crate) fn must_use() -> TokenStream {
+ quote! {
+ #[must_use]
+ }
+ }
+
+ pub(crate) fn non_exhaustive() -> TokenStream {
+ quote! {
+ #[non_exhaustive]
+ }
+ }
+
+ pub(crate) fn doc(comment: String) -> TokenStream {
+ if comment.is_empty() {
+ quote!()
+ } else {
+ quote!(#[doc = #comment])
+ }
+ }
+
+ pub(crate) fn link_name<const MANGLE: bool>(name: &str) -> TokenStream {
+ // LLVM mangles the name by default but it's already mangled.
+ // Prefixing the name with \u{1} should tell LLVM to not mangle it.
+ let name: Cow<'_, str> = if MANGLE {
+ name.into()
+ } else {
+ format!("\u{1}{}", name).into()
+ };
+
+ quote! {
+ #[link_name = #name]
+ }
+ }
+}
+
+/// 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(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> syn::Type {
+ let opaque = layout.opaque();
+
+ // FIXME(emilio, #412): We fall back to byte alignment, but there are
+ // some things that legitimately are more than 8-byte aligned.
+ //
+ // Eventually we should be able to `unwrap` here, but...
+ let ty = match opaque.known_rust_type_for_array(ctx) {
+ Some(ty) => ty,
+ None => {
+ warn!("Found unknown alignment on code generation!");
+ syn::parse_quote! { u8 }
+ }
+ };
+
+ let data_len = opaque.array_size(ctx).unwrap_or(layout.size);
+
+ if data_len == 1 {
+ ty
+ } else {
+ syn::parse_quote! { [ #ty ; #data_len ] }
+ }
+}
+
+/// Integer type of the same size as the given `Layout`.
+pub(crate) fn integer_type(
+ ctx: &BindgenContext,
+ layout: Layout,
+) -> Option<syn::Type> {
+ Layout::known_type_for_size(ctx, layout.size)
+}
+
+/// Generates a bitfield allocation unit type for a type with the given `Layout`.
+pub(crate) fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> syn::Type {
+ let size = layout.size;
+ let ty = syn::parse_quote! { __BindgenBitfieldUnit<[u8; #size]> };
+
+ if ctx.options().enable_cxx_namespaces {
+ return syn::parse_quote! { root::#ty };
+ }
+
+ ty
+}
+
+pub(crate) mod ast_ty {
+ use crate::ir::context::BindgenContext;
+ use crate::ir::function::FunctionSig;
+ use crate::ir::layout::Layout;
+ use crate::ir::ty::{FloatKind, IntKind};
+ use proc_macro2::{self, TokenStream};
+ use std::str::FromStr;
+
+ pub(crate) fn c_void(ctx: &BindgenContext) -> syn::Type {
+ // ctypes_prefix takes precedence
+ match ctx.options().ctypes_prefix {
+ Some(ref prefix) => {
+ let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
+ syn::parse_quote! { #prefix::c_void }
+ }
+ None => {
+ if ctx.options().use_core &&
+ ctx.options().rust_features.core_ffi_c_void
+ {
+ syn::parse_quote! { ::core::ffi::c_void }
+ } else {
+ syn::parse_quote! { ::std::os::raw::c_void }
+ }
+ }
+ }
+ }
+
+ pub(crate) fn raw_type(ctx: &BindgenContext, name: &str) -> syn::Type {
+ let ident = ctx.rust_ident_raw(name);
+ match ctx.options().ctypes_prefix {
+ Some(ref prefix) => {
+ let prefix = TokenStream::from_str(prefix.as_str()).unwrap();
+ syn::parse_quote! { #prefix::#ident }
+ }
+ None => {
+ if ctx.options().use_core &&
+ ctx.options().rust_features().core_ffi_c
+ {
+ syn::parse_quote! { ::core::ffi::#ident }
+ } else {
+ syn::parse_quote! { ::std::os::raw::#ident }
+ }
+ }
+ }
+ }
+
+ pub(crate) fn int_kind_rust_type(
+ ctx: &BindgenContext,
+ ik: IntKind,
+ layout: Option<Layout>,
+ ) -> syn::Type {
+ match ik {
+ IntKind::Bool => syn::parse_quote! { bool },
+ IntKind::Char { .. } => raw_type(ctx, "c_char"),
+ IntKind::SChar => raw_type(ctx, "c_schar"),
+ IntKind::UChar => raw_type(ctx, "c_uchar"),
+ IntKind::Short => raw_type(ctx, "c_short"),
+ IntKind::UShort => raw_type(ctx, "c_ushort"),
+ IntKind::Int => raw_type(ctx, "c_int"),
+ IntKind::UInt => raw_type(ctx, "c_uint"),
+ IntKind::Long => raw_type(ctx, "c_long"),
+ IntKind::ULong => raw_type(ctx, "c_ulong"),
+ IntKind::LongLong => raw_type(ctx, "c_longlong"),
+ IntKind::ULongLong => raw_type(ctx, "c_ulonglong"),
+ IntKind::WChar => {
+ let layout =
+ layout.expect("Couldn't compute wchar_t's layout?");
+ Layout::known_type_for_size(ctx, layout.size)
+ .expect("Non-representable wchar_t?")
+ }
+
+ IntKind::I8 => syn::parse_quote! { i8 },
+ IntKind::U8 => syn::parse_quote! { u8 },
+ IntKind::I16 => syn::parse_quote! { i16 },
+ IntKind::U16 => syn::parse_quote! { u16 },
+ IntKind::I32 => syn::parse_quote! { i32 },
+ IntKind::U32 => syn::parse_quote! { u32 },
+ IntKind::I64 => syn::parse_quote! { i64 },
+ IntKind::U64 => syn::parse_quote! { u64 },
+ IntKind::Custom { name, .. } => {
+ syn::parse_str(name).expect("Invalid integer type.")
+ }
+ IntKind::U128 => {
+ if ctx.options().rust_features.i128_and_u128 {
+ syn::parse_quote! { u128 }
+ } else {
+ // Best effort thing, but wrong alignment
+ // unfortunately.
+ syn::parse_quote! { [u64; 2] }
+ }
+ }
+ IntKind::I128 => {
+ if ctx.options().rust_features.i128_and_u128 {
+ syn::parse_quote! { i128 }
+ } else {
+ syn::parse_quote! { [u64; 2] }
+ }
+ }
+ }
+ }
+
+ pub(crate) fn float_kind_rust_type(
+ ctx: &BindgenContext,
+ fk: FloatKind,
+ layout: Option<Layout>,
+ ) -> syn::Type {
+ // TODO: we probably should take the type layout into account more
+ // often?
+ //
+ // Also, maybe this one shouldn't be the default?
+ match (fk, ctx.options().convert_floats) {
+ (FloatKind::Float16, _) => {
+ // TODO: do f16 when rust lands it
+ ctx.generated_bindgen_float16();
+ if ctx.options().enable_cxx_namespaces {
+ syn::parse_quote! { root::__BindgenFloat16 }
+ } else {
+ syn::parse_quote! { __BindgenFloat16 }
+ }
+ }
+ (FloatKind::Float, true) => syn::parse_quote! { f32 },
+ (FloatKind::Double, true) => syn::parse_quote! { f64 },
+ (FloatKind::Float, false) => raw_type(ctx, "c_float"),
+ (FloatKind::Double, false) => raw_type(ctx, "c_double"),
+ (FloatKind::LongDouble, _) => {
+ match layout {
+ Some(layout) => {
+ match layout.size {
+ 4 => syn::parse_quote! { f32 },
+ 8 => syn::parse_quote! { f64 },
+ // TODO(emilio): If rust ever gains f128 we should
+ // use it here and below.
+ _ => super::integer_type(ctx, layout)
+ .unwrap_or(syn::parse_quote! { f64 }),
+ }
+ }
+ None => {
+ debug_assert!(
+ false,
+ "How didn't we know the layout for a primitive type?"
+ );
+ syn::parse_quote! { f64 }
+ }
+ }
+ }
+ (FloatKind::Float128, _) => {
+ if ctx.options().rust_features.i128_and_u128 {
+ syn::parse_quote! { u128 }
+ } else {
+ syn::parse_quote! { [u64; 2] }
+ }
+ }
+ }
+ }
+
+ pub(crate) fn int_expr(val: i64) -> TokenStream {
+ // Don't use quote! { #val } because that adds the type suffix.
+ let val = proc_macro2::Literal::i64_unsuffixed(val);
+ quote!(#val)
+ }
+
+ pub(crate) fn uint_expr(val: u64) -> TokenStream {
+ // Don't use quote! { #val } because that adds the type suffix.
+ let val = proc_macro2::Literal::u64_unsuffixed(val);
+ quote!(#val)
+ }
+
+ pub(crate) fn cstr_expr(mut string: String) -> TokenStream {
+ string.push('\0');
+ let b = proc_macro2::Literal::byte_string(string.as_bytes());
+ quote! {
+ #b
+ }
+ }
+
+ pub(crate) fn float_expr(
+ ctx: &BindgenContext,
+ f: f64,
+ ) -> Result<TokenStream, ()> {
+ if f.is_finite() {
+ let val = proc_macro2::Literal::f64_unsuffixed(f);
+
+ return Ok(quote!(#val));
+ }
+
+ let prefix = ctx.trait_prefix();
+
+ if f.is_nan() {
+ return Ok(quote! {
+ ::#prefix::f64::NAN
+ });
+ }
+
+ if f.is_infinite() {
+ return Ok(if f.is_sign_positive() {
+ quote! {
+ ::#prefix::f64::INFINITY
+ }
+ } else {
+ quote! {
+ ::#prefix::f64::NEG_INFINITY
+ }
+ });
+ }
+
+ warn!("Unknown non-finite float number: {:?}", f);
+ Err(())
+ }
+
+ pub(crate) fn arguments_from_signature(
+ signature: &FunctionSig,
+ ctx: &BindgenContext,
+ ) -> Vec<TokenStream> {
+ let mut unnamed_arguments = 0;
+ signature
+ .argument_types()
+ .iter()
+ .map(|&(ref name, _ty)| match *name {
+ Some(ref name) => {
+ let name = ctx.rust_ident(name);
+ quote! { #name }
+ }
+ None => {
+ unnamed_arguments += 1;
+ let name =
+ ctx.rust_ident(format!("arg{}", unnamed_arguments));
+ quote! { #name }
+ }
+ })
+ .collect()
+ }
+}
diff --git a/third_party/rust/bindgen/codegen/impl_debug.rs b/third_party/rust/bindgen/codegen/impl_debug.rs
new file mode 100644
index 0000000000..67ec214ee8
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/impl_debug.rs
@@ -0,0 +1,245 @@
+use crate::ir::comp::{BitfieldUnit, CompKind, Field, FieldData, FieldMethods};
+use crate::ir::context::BindgenContext;
+use crate::ir::item::{HasTypeParamInArray, IsOpaque, Item, ItemCanonicalName};
+use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
+
+pub(crate) fn gen_debug_impl(
+ ctx: &BindgenContext,
+ fields: &[Field],
+ item: &Item,
+ kind: CompKind,
+) -> proc_macro2::TokenStream {
+ let struct_name = item.canonical_name(ctx);
+ let mut format_string = format!("{} {{{{ ", struct_name);
+ let mut tokens = vec![];
+
+ if item.is_opaque(ctx, &()) {
+ format_string.push_str("opaque");
+ } else {
+ match kind {
+ CompKind::Union => {
+ format_string.push_str("union");
+ }
+ CompKind::Struct => {
+ let processed_fields = fields.iter().filter_map(|f| match f {
+ Field::DataMember(ref fd) => fd.impl_debug(ctx, ()),
+ Field::Bitfields(ref bu) => bu.impl_debug(ctx, ()),
+ });
+
+ for (i, (fstring, toks)) in processed_fields.enumerate() {
+ if i > 0 {
+ format_string.push_str(", ");
+ }
+ tokens.extend(toks);
+ format_string.push_str(&fstring);
+ }
+ }
+ }
+ }
+
+ format_string.push_str(" }}");
+ tokens.insert(0, quote! { #format_string });
+
+ let prefix = ctx.trait_prefix();
+
+ quote! {
+ fn fmt(&self, f: &mut ::#prefix::fmt::Formatter<'_>) -> ::#prefix ::fmt::Result {
+ write!(f, #( #tokens ),*)
+ }
+ }
+}
+
+/// A trait for the things which we can codegen tokens that contribute towards a
+/// generated `impl Debug`.
+pub(crate) trait ImplDebug<'a> {
+ /// Any extra parameter required by this a particular `ImplDebug` implementation.
+ type Extra;
+
+ /// Generate a format string snippet to be included in the larger `impl Debug`
+ /// format string, and the code to get the format string's interpolation values.
+ fn impl_debug(
+ &self,
+ ctx: &BindgenContext,
+ extra: Self::Extra,
+ ) -> Option<(String, Vec<proc_macro2::TokenStream>)>;
+}
+
+impl<'a> ImplDebug<'a> for FieldData {
+ type Extra = ();
+
+ fn impl_debug(
+ &self,
+ ctx: &BindgenContext,
+ _: Self::Extra,
+ ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
+ if let Some(name) = self.name() {
+ ctx.resolve_item(self.ty()).impl_debug(ctx, name)
+ } else {
+ None
+ }
+ }
+}
+
+impl<'a> ImplDebug<'a> for BitfieldUnit {
+ type Extra = ();
+
+ fn impl_debug(
+ &self,
+ ctx: &BindgenContext,
+ _: Self::Extra,
+ ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
+ let mut format_string = String::new();
+ let mut tokens = vec![];
+ for (i, bitfield) in self.bitfields().iter().enumerate() {
+ if i > 0 {
+ format_string.push_str(", ");
+ }
+
+ if let Some(bitfield_name) = bitfield.name() {
+ format_string.push_str(&format!("{} : {{:?}}", bitfield_name));
+ let getter_name = bitfield.getter_name();
+ let name_ident = ctx.rust_ident_raw(getter_name);
+ tokens.push(quote! {
+ self.#name_ident ()
+ });
+ }
+ }
+
+ Some((format_string, tokens))
+ }
+}
+
+impl<'a> ImplDebug<'a> for Item {
+ type Extra = &'a str;
+
+ fn impl_debug(
+ &self,
+ ctx: &BindgenContext,
+ name: &str,
+ ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
+ let name_ident = ctx.rust_ident(name);
+
+ // We don't know if blocklisted items `impl Debug` or not, so we can't
+ // add them to the format string we're building up.
+ if !ctx.allowlisted_items().contains(&self.id()) {
+ return None;
+ }
+
+ let ty = match self.as_type() {
+ Some(ty) => ty,
+ None => {
+ return None;
+ }
+ };
+
+ fn debug_print(
+ name: &str,
+ name_ident: proc_macro2::TokenStream,
+ ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
+ Some((
+ format!("{}: {{:?}}", name),
+ vec![quote! {
+ self.#name_ident
+ }],
+ ))
+ }
+
+ match *ty.kind() {
+ // Handle the simple cases.
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::ObjCInterface(..) |
+ TypeKind::ObjCId |
+ TypeKind::Comp(..) |
+ TypeKind::ObjCSel => debug_print(name, quote! { #name_ident }),
+
+ TypeKind::TemplateInstantiation(ref inst) => {
+ if inst.is_opaque(ctx, self) {
+ Some((format!("{}: opaque", name), vec![]))
+ } else {
+ debug_print(name, quote! { #name_ident })
+ }
+ }
+
+ // The generic is not required to implement Debug, so we can not debug print that type
+ TypeKind::TypeParam => {
+ Some((format!("{}: Non-debuggable generic", name), vec![]))
+ }
+
+ TypeKind::Array(_, len) => {
+ // Generics are not required to implement Debug
+ if self.has_type_param_in_array(ctx) {
+ Some((
+ format!("{}: Array with length {}", name, len),
+ vec![],
+ ))
+ } else if len < RUST_DERIVE_IN_ARRAY_LIMIT ||
+ ctx.options().rust_features().larger_arrays
+ {
+ // The simple case
+ debug_print(name, quote! { #name_ident })
+ } else if ctx.options().use_core {
+ // There is no String in core; reducing field visibility to avoid breaking
+ // no_std setups.
+ Some((format!("{}: [...]", name), vec![]))
+ } else {
+ // Let's implement our own print function
+ Some((
+ format!("{}: [{{}}]", name),
+ vec![quote! {
+ self.#name_ident
+ .iter()
+ .enumerate()
+ .map(|(i, v)| format!("{}{:?}", if i > 0 { ", " } else { "" }, v))
+ .collect::<String>()
+ }],
+ ))
+ }
+ }
+ TypeKind::Vector(_, len) => {
+ if ctx.options().use_core {
+ // There is no format! in core; reducing field visibility to avoid breaking
+ // no_std setups.
+ Some((format!("{}(...)", name), vec![]))
+ } else {
+ let self_ids = 0..len;
+ Some((
+ format!("{}({{}})", name),
+ vec![quote! {
+ #(format!("{:?}", self.#self_ids)),*
+ }],
+ ))
+ }
+ }
+
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) |
+ TypeKind::BlockPointer(t) => {
+ // We follow the aliases
+ ctx.resolve_item(t).impl_debug(ctx, name)
+ }
+
+ TypeKind::Pointer(inner) => {
+ let inner_type = ctx.resolve_type(inner).canonical_type(ctx);
+ match *inner_type.kind() {
+ TypeKind::Function(ref sig)
+ if !sig.function_pointers_can_derive() =>
+ {
+ Some((format!("{}: FunctionPointer", name), vec![]))
+ }
+ _ => debug_print(name, quote! { #name_ident }),
+ }
+ }
+
+ TypeKind::Opaque => None,
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/codegen/impl_partialeq.rs b/third_party/rust/bindgen/codegen/impl_partialeq.rs
new file mode 100644
index 0000000000..42fabf6ad0
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/impl_partialeq.rs
@@ -0,0 +1,142 @@
+use crate::ir::comp::{CompInfo, CompKind, Field, FieldMethods};
+use crate::ir::context::BindgenContext;
+use crate::ir::item::{IsOpaque, Item};
+use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
+
+/// Generate a manual implementation of `PartialEq` trait for the
+/// specified compound type.
+pub(crate) fn gen_partialeq_impl(
+ ctx: &BindgenContext,
+ comp_info: &CompInfo,
+ item: &Item,
+ ty_for_impl: &proc_macro2::TokenStream,
+) -> Option<proc_macro2::TokenStream> {
+ let mut tokens = vec![];
+
+ if item.is_opaque(ctx, &()) {
+ tokens.push(quote! {
+ &self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..]
+ });
+ } else if comp_info.kind() == CompKind::Union {
+ assert!(!ctx.options().untagged_union);
+ tokens.push(quote! {
+ &self.bindgen_union_field[..] == &other.bindgen_union_field[..]
+ });
+ } else {
+ for base in comp_info.base_members().iter() {
+ if !base.requires_storage(ctx) {
+ continue;
+ }
+
+ let ty_item = ctx.resolve_item(base.ty);
+ let field_name = &base.field_name;
+
+ if ty_item.is_opaque(ctx, &()) {
+ let field_name = ctx.rust_ident(field_name);
+ tokens.push(quote! {
+ &self. #field_name [..] == &other. #field_name [..]
+ });
+ } else {
+ tokens.push(gen_field(ctx, ty_item, field_name));
+ }
+ }
+
+ for field in comp_info.fields() {
+ match *field {
+ Field::DataMember(ref fd) => {
+ let ty_item = ctx.resolve_item(fd.ty());
+ let name = fd.name().unwrap();
+ tokens.push(gen_field(ctx, ty_item, name));
+ }
+ Field::Bitfields(ref bu) => {
+ for bitfield in bu.bitfields() {
+ if bitfield.name().is_some() {
+ let getter_name = bitfield.getter_name();
+ let name_ident = ctx.rust_ident_raw(getter_name);
+ tokens.push(quote! {
+ self.#name_ident () == other.#name_ident ()
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Some(quote! {
+ fn eq(&self, other: & #ty_for_impl) -> bool {
+ #( #tokens )&&*
+ }
+ })
+}
+
+fn gen_field(
+ ctx: &BindgenContext,
+ ty_item: &Item,
+ name: &str,
+) -> proc_macro2::TokenStream {
+ fn quote_equals(
+ name_ident: proc_macro2::Ident,
+ ) -> proc_macro2::TokenStream {
+ quote! { self.#name_ident == other.#name_ident }
+ }
+
+ let name_ident = ctx.rust_ident(name);
+ let ty = ty_item.expect_type();
+
+ match *ty.kind() {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Float(..) |
+ TypeKind::Enum(..) |
+ TypeKind::TypeParam |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::Reference(..) |
+ TypeKind::ObjCInterface(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel |
+ TypeKind::Comp(..) |
+ TypeKind::Pointer(_) |
+ TypeKind::Function(..) |
+ TypeKind::Opaque => quote_equals(name_ident),
+
+ TypeKind::TemplateInstantiation(ref inst) => {
+ if inst.is_opaque(ctx, ty_item) {
+ quote! {
+ &self. #name_ident [..] == &other. #name_ident [..]
+ }
+ } else {
+ quote_equals(name_ident)
+ }
+ }
+
+ TypeKind::Array(_, len) => {
+ if len <= RUST_DERIVE_IN_ARRAY_LIMIT ||
+ ctx.options().rust_features().larger_arrays
+ {
+ quote_equals(name_ident)
+ } else {
+ quote! {
+ &self. #name_ident [..] == &other. #name_ident [..]
+ }
+ }
+ }
+ TypeKind::Vector(_, len) => {
+ let self_ids = 0..len;
+ let other_ids = 0..len;
+ quote! {
+ #(self.#self_ids == other.#other_ids &&)* true
+ }
+ }
+
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) |
+ TypeKind::BlockPointer(t) => {
+ let inner_item = ctx.resolve_item(t);
+ gen_field(ctx, inner_item, name)
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/codegen/mod.rs b/third_party/rust/bindgen/codegen/mod.rs
new file mode 100644
index 0000000000..dd1486df74
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/mod.rs
@@ -0,0 +1,5473 @@
+mod dyngen;
+pub(crate) mod error;
+
+mod helpers;
+mod impl_debug;
+mod impl_partialeq;
+mod postprocessing;
+mod serialize;
+pub(crate) mod struct_layout;
+
+#[cfg(test)]
+#[allow(warnings)]
+pub(crate) mod bitfield_unit;
+#[cfg(all(test, target_endian = "little"))]
+mod bitfield_unit_tests;
+
+use self::dyngen::DynamicItems;
+use self::helpers::attributes;
+use self::struct_layout::StructLayoutTracker;
+
+use super::BindgenOptions;
+
+use crate::callbacks::{DeriveInfo, FieldInfo, TypeKind as DeriveTypeKind};
+use crate::codegen::error::Error;
+use crate::ir::analysis::{HasVtable, Sizedness};
+use crate::ir::annotations::{
+ Annotations, FieldAccessorKind, FieldVisibilityKind,
+};
+use crate::ir::comp::{
+ Bitfield, BitfieldUnit, CompInfo, CompKind, Field, FieldData, FieldMethods,
+ Method, MethodKind,
+};
+use crate::ir::context::{BindgenContext, ItemId};
+use crate::ir::derive::{
+ CanDerive, CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq,
+ CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd,
+};
+use crate::ir::dot;
+use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
+use crate::ir::function::{
+ ClangAbi, Function, FunctionKind, FunctionSig, Linkage,
+};
+use crate::ir::int::IntKind;
+use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath};
+use crate::ir::item_kind::ItemKind;
+use crate::ir::layout::Layout;
+use crate::ir::module::Module;
+use crate::ir::objc::{ObjCInterface, ObjCMethod};
+use crate::ir::template::{
+ AsTemplateParam, TemplateInstantiation, TemplateParameters,
+};
+use crate::ir::ty::{Type, TypeKind};
+use crate::ir::var::Var;
+
+use proc_macro2::{self, Ident, Span};
+use quote::TokenStreamExt;
+
+use crate::{Entry, HashMap, HashSet};
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::collections::VecDeque;
+use std::ffi::CStr;
+use std::fmt::{self, Write};
+use std::ops;
+use std::str::{self, FromStr};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum CodegenError {
+ Serialize { msg: String, loc: String },
+ Io(String),
+}
+
+impl From<std::io::Error> for CodegenError {
+ fn from(err: std::io::Error) -> Self {
+ Self::Io(err.to_string())
+ }
+}
+
+impl fmt::Display for CodegenError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::Serialize { msg, loc } => {
+ write!(f, "serialization error at {}: {}", loc, msg)
+ }
+ Self::Io(err) => err.fmt(f),
+ }
+ }
+}
+
+// Name of type defined in constified enum module
+pub(crate) static CONSTIFIED_ENUM_MODULE_REPR_NAME: &str = "Type";
+
+fn top_level_path(
+ ctx: &BindgenContext,
+ item: &Item,
+) -> Vec<proc_macro2::TokenStream> {
+ let mut path = vec![quote! { self }];
+
+ if ctx.options().enable_cxx_namespaces {
+ for _ in 0..item.codegen_depth(ctx) {
+ path.push(quote! { super });
+ }
+ }
+
+ path
+}
+
+fn root_import(
+ ctx: &BindgenContext,
+ module: &Item,
+) -> proc_macro2::TokenStream {
+ assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up");
+ assert!(module.is_module());
+
+ let mut path = top_level_path(ctx, module);
+
+ let root = ctx.root_module().canonical_name(ctx);
+ let root_ident = ctx.rust_ident(root);
+ path.push(quote! { #root_ident });
+
+ let mut tokens = quote! {};
+ tokens.append_separated(path, quote!(::));
+
+ quote! {
+ #[allow(unused_imports)]
+ use #tokens ;
+ }
+}
+
+bitflags! {
+ #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+ struct DerivableTraits: u16 {
+ const DEBUG = 1 << 0;
+ const DEFAULT = 1 << 1;
+ const COPY = 1 << 2;
+ const CLONE = 1 << 3;
+ const HASH = 1 << 4;
+ const PARTIAL_ORD = 1 << 5;
+ const ORD = 1 << 6;
+ const PARTIAL_EQ = 1 << 7;
+ const EQ = 1 << 8;
+ }
+}
+
+fn derives_of_item(
+ item: &Item,
+ ctx: &BindgenContext,
+ packed: bool,
+) -> DerivableTraits {
+ let mut derivable_traits = DerivableTraits::empty();
+
+ let all_template_params = item.all_template_params(ctx);
+
+ if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
+ derivable_traits |= DerivableTraits::COPY;
+
+ if ctx.options().rust_features().builtin_clone_impls ||
+ !all_template_params.is_empty()
+ {
+ // FIXME: This requires extra logic if you have a big array in a
+ // templated struct. The reason for this is that the magic:
+ // fn clone(&self) -> Self { *self }
+ // doesn't work for templates.
+ //
+ // It's not hard to fix though.
+ derivable_traits |= DerivableTraits::CLONE;
+ }
+ } else if packed {
+ // If the struct or union is packed, deriving from Copy is required for
+ // deriving from any other trait.
+ return derivable_traits;
+ }
+
+ if item.can_derive_debug(ctx) && !item.annotations().disallow_debug() {
+ derivable_traits |= DerivableTraits::DEBUG;
+ }
+
+ if item.can_derive_default(ctx) && !item.annotations().disallow_default() {
+ derivable_traits |= DerivableTraits::DEFAULT;
+ }
+
+ if item.can_derive_hash(ctx) {
+ derivable_traits |= DerivableTraits::HASH;
+ }
+
+ if item.can_derive_partialord(ctx) {
+ derivable_traits |= DerivableTraits::PARTIAL_ORD;
+ }
+
+ if item.can_derive_ord(ctx) {
+ derivable_traits |= DerivableTraits::ORD;
+ }
+
+ if item.can_derive_partialeq(ctx) {
+ derivable_traits |= DerivableTraits::PARTIAL_EQ;
+ }
+
+ if item.can_derive_eq(ctx) {
+ derivable_traits |= DerivableTraits::EQ;
+ }
+
+ derivable_traits
+}
+
+impl From<DerivableTraits> for Vec<&'static str> {
+ fn from(derivable_traits: DerivableTraits) -> Vec<&'static str> {
+ [
+ (DerivableTraits::DEBUG, "Debug"),
+ (DerivableTraits::DEFAULT, "Default"),
+ (DerivableTraits::COPY, "Copy"),
+ (DerivableTraits::CLONE, "Clone"),
+ (DerivableTraits::HASH, "Hash"),
+ (DerivableTraits::PARTIAL_ORD, "PartialOrd"),
+ (DerivableTraits::ORD, "Ord"),
+ (DerivableTraits::PARTIAL_EQ, "PartialEq"),
+ (DerivableTraits::EQ, "Eq"),
+ ]
+ .iter()
+ .filter_map(|&(flag, derive)| {
+ Some(derive).filter(|_| derivable_traits.contains(flag))
+ })
+ .collect()
+ }
+}
+
+struct WrapAsVariadic {
+ new_name: String,
+ idx_of_va_list_arg: usize,
+}
+
+struct CodegenResult<'a> {
+ items: Vec<proc_macro2::TokenStream>,
+ dynamic_items: DynamicItems,
+
+ /// A monotonic counter used to add stable unique ID's to stuff that doesn't
+ /// need to be referenced by anything.
+ codegen_id: &'a Cell<usize>,
+
+ /// Whether a bindgen union has been generated at least once.
+ saw_bindgen_union: bool,
+
+ /// Whether an incomplete array has been generated at least once.
+ saw_incomplete_array: bool,
+
+ /// Whether Objective C types have been seen at least once.
+ saw_objc: bool,
+
+ /// Whether Apple block types have been seen at least once.
+ saw_block: bool,
+
+ /// Whether a bitfield allocation unit has been seen at least once.
+ saw_bitfield_unit: bool,
+
+ items_seen: HashSet<ItemId>,
+ /// The set of generated function/var names, needed because in C/C++ is
+ /// legal to do something like:
+ ///
+ /// ```c++
+ /// extern "C" {
+ /// void foo();
+ /// extern int bar;
+ /// }
+ ///
+ /// extern "C" {
+ /// void foo();
+ /// extern int bar;
+ /// }
+ /// ```
+ ///
+ /// Being these two different declarations.
+ functions_seen: HashSet<String>,
+ vars_seen: HashSet<String>,
+
+ /// Used for making bindings to overloaded functions. Maps from a canonical
+ /// function name to the number of overloads we have already codegen'd for
+ /// that name. This lets us give each overload a unique suffix.
+ overload_counters: HashMap<String, u32>,
+
+ /// List of items to serialize. With optionally the argument for the wrap as
+ /// variadic transformation to be applied.
+ items_to_serialize: Vec<(ItemId, Option<WrapAsVariadic>)>,
+}
+
+impl<'a> CodegenResult<'a> {
+ fn new(codegen_id: &'a Cell<usize>) -> Self {
+ CodegenResult {
+ items: vec![],
+ dynamic_items: DynamicItems::new(),
+ saw_bindgen_union: false,
+ saw_incomplete_array: false,
+ saw_objc: false,
+ saw_block: false,
+ saw_bitfield_unit: false,
+ codegen_id,
+ items_seen: Default::default(),
+ functions_seen: Default::default(),
+ vars_seen: Default::default(),
+ overload_counters: Default::default(),
+ items_to_serialize: Default::default(),
+ }
+ }
+
+ fn dynamic_items(&mut self) -> &mut DynamicItems {
+ &mut self.dynamic_items
+ }
+
+ fn saw_bindgen_union(&mut self) {
+ self.saw_bindgen_union = true;
+ }
+
+ fn saw_incomplete_array(&mut self) {
+ self.saw_incomplete_array = true;
+ }
+
+ fn saw_objc(&mut self) {
+ self.saw_objc = true;
+ }
+
+ fn saw_block(&mut self) {
+ self.saw_block = true;
+ }
+
+ fn saw_bitfield_unit(&mut self) {
+ self.saw_bitfield_unit = true;
+ }
+
+ fn seen<Id: Into<ItemId>>(&self, item: Id) -> bool {
+ self.items_seen.contains(&item.into())
+ }
+
+ fn set_seen<Id: Into<ItemId>>(&mut self, item: Id) {
+ self.items_seen.insert(item.into());
+ }
+
+ fn seen_function(&self, name: &str) -> bool {
+ self.functions_seen.contains(name)
+ }
+
+ fn saw_function(&mut self, name: &str) {
+ self.functions_seen.insert(name.into());
+ }
+
+ /// Get the overload number for the given function name. Increments the
+ /// counter internally so the next time we ask for the overload for this
+ /// name, we get the incremented value, and so on.
+ fn overload_number(&mut self, name: &str) -> u32 {
+ let counter = self.overload_counters.entry(name.into()).or_insert(0);
+ let number = *counter;
+ *counter += 1;
+ number
+ }
+
+ fn seen_var(&self, name: &str) -> bool {
+ self.vars_seen.contains(name)
+ }
+
+ fn saw_var(&mut self, name: &str) {
+ self.vars_seen.insert(name.into());
+ }
+
+ fn inner<F>(&mut self, cb: F) -> Vec<proc_macro2::TokenStream>
+ where
+ F: FnOnce(&mut Self),
+ {
+ let mut new = Self::new(self.codegen_id);
+
+ cb(&mut new);
+
+ self.saw_incomplete_array |= new.saw_incomplete_array;
+ self.saw_objc |= new.saw_objc;
+ self.saw_block |= new.saw_block;
+ self.saw_bitfield_unit |= new.saw_bitfield_unit;
+ self.saw_bindgen_union |= new.saw_bindgen_union;
+
+ new.items
+ }
+}
+
+impl<'a> ops::Deref for CodegenResult<'a> {
+ type Target = Vec<proc_macro2::TokenStream>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.items
+ }
+}
+
+impl<'a> ops::DerefMut for CodegenResult<'a> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.items
+ }
+}
+
+/// A trait to convert a rust type into a pointer, optionally const, to the same
+/// type.
+trait ToPtr {
+ fn to_ptr(self, is_const: bool) -> syn::Type;
+}
+
+impl ToPtr for syn::Type {
+ fn to_ptr(self, is_const: bool) -> syn::Type {
+ if is_const {
+ syn::parse_quote! { *const #self }
+ } else {
+ syn::parse_quote! { *mut #self }
+ }
+ }
+}
+
+/// An extension trait for `syn::Type` that lets us append any implicit
+/// template parameters that exist for some type, if necessary.
+trait WithImplicitTemplateParams {
+ fn with_implicit_template_params(
+ self,
+ ctx: &BindgenContext,
+ item: &Item,
+ ) -> Self;
+}
+
+impl WithImplicitTemplateParams for syn::Type {
+ fn with_implicit_template_params(
+ self,
+ ctx: &BindgenContext,
+ item: &Item,
+ ) -> Self {
+ let item = item.id().into_resolver().through_type_refs().resolve(ctx);
+
+ let params = match *item.expect_type().kind() {
+ TypeKind::UnresolvedTypeRef(..) => {
+ unreachable!("already resolved unresolved type refs")
+ }
+ TypeKind::ResolvedTypeRef(..) => {
+ unreachable!("we resolved item through type refs")
+ }
+ // None of these types ever have implicit template parameters.
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Pointer(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Array(..) |
+ TypeKind::TypeParam |
+ TypeKind::Opaque |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel |
+ TypeKind::TemplateInstantiation(..) => None,
+ _ => {
+ let params = item.used_template_params(ctx);
+ if params.is_empty() {
+ None
+ } else {
+ Some(params.into_iter().map(|p| {
+ p.try_to_rust_ty(ctx, &()).expect(
+ "template params cannot fail to be a rust type",
+ )
+ }))
+ }
+ }
+ };
+
+ if let Some(params) = params {
+ syn::parse_quote! { #self<#(#params),*> }
+ } else {
+ self
+ }
+ }
+}
+
+trait CodeGenerator {
+ /// Extra information from the caller.
+ type Extra;
+
+ /// Extra information returned to the caller.
+ type Return;
+
+ fn codegen(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'_>,
+ extra: &Self::Extra,
+ ) -> Self::Return;
+}
+
+impl Item {
+ fn process_before_codegen(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult,
+ ) -> bool {
+ if !self.is_enabled_for_codegen(ctx) {
+ return false;
+ }
+
+ if self.is_blocklisted(ctx) || result.seen(self.id()) {
+ debug!(
+ "<Item as CodeGenerator>::process_before_codegen: Ignoring hidden or seen: \
+ self = {:?}",
+ self
+ );
+ return false;
+ }
+
+ if !ctx.codegen_items().contains(&self.id()) {
+ // TODO(emilio, #453): Figure out what to do when this happens
+ // legitimately, we could track the opaque stuff and disable the
+ // assertion there I guess.
+ warn!("Found non-allowlisted item in code generation: {:?}", self);
+ }
+
+ result.set_seen(self.id());
+ true
+ }
+}
+
+impl CodeGenerator for Item {
+ type Extra = ();
+ type Return = ();
+
+ fn codegen(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'_>,
+ _extra: &(),
+ ) {
+ debug!("<Item as CodeGenerator>::codegen: self = {:?}", self);
+ if !self.process_before_codegen(ctx, result) {
+ return;
+ }
+
+ match *self.kind() {
+ ItemKind::Module(ref module) => {
+ module.codegen(ctx, result, self);
+ }
+ ItemKind::Function(ref fun) => {
+ fun.codegen(ctx, result, self);
+ }
+ ItemKind::Var(ref var) => {
+ var.codegen(ctx, result, self);
+ }
+ ItemKind::Type(ref ty) => {
+ ty.codegen(ctx, result, self);
+ }
+ }
+ }
+}
+
+impl CodeGenerator for Module {
+ type Extra = Item;
+ type Return = ();
+
+ fn codegen(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'_>,
+ item: &Item,
+ ) {
+ debug!("<Module as CodeGenerator>::codegen: item = {:?}", item);
+
+ let codegen_self = |result: &mut CodegenResult,
+ found_any: &mut bool| {
+ for child in self.children() {
+ if ctx.codegen_items().contains(child) {
+ *found_any = true;
+ ctx.resolve_item(*child).codegen(ctx, result, &());
+ }
+ }
+
+ if item.id() == ctx.root_module() {
+ if result.saw_block {
+ utils::prepend_block_header(ctx, &mut *result);
+ }
+ if result.saw_bindgen_union {
+ utils::prepend_union_types(ctx, &mut *result);
+ }
+ if result.saw_incomplete_array {
+ utils::prepend_incomplete_array_types(ctx, &mut *result);
+ }
+ if ctx.need_bindgen_float16_type() {
+ utils::prepend_float16_type(&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("::")
+ .into_boxed_str();
+ if let Some(raw_lines) = ctx.options().module_lines.get(&path) {
+ for raw_line in raw_lines {
+ found_any = true;
+ result.push(
+ proc_macro2::TokenStream::from_str(raw_line).unwrap(),
+ );
+ }
+ }
+
+ codegen_self(result, &mut found_any);
+ });
+
+ // Don't bother creating an empty module.
+ if !found_any {
+ return;
+ }
+
+ let name = item.canonical_name(ctx);
+ let ident = ctx.rust_ident(name);
+ result.push(if item.id() == ctx.root_module() {
+ quote! {
+ #[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
+ pub mod #ident {
+ #( #inner_items )*
+ }
+ }
+ } else {
+ quote! {
+ pub mod #ident {
+ #( #inner_items )*
+ }
+ }
+ });
+ }
+}
+
+impl CodeGenerator for Var {
+ type Extra = Item;
+ type Return = ();
+
+ fn codegen(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'_>,
+ item: &Item,
+ ) {
+ use crate::ir::var::VarType;
+ debug!("<Var as CodeGenerator>::codegen: item = {:?}", item);
+ debug_assert!(item.is_enabled_for_codegen(ctx));
+
+ let canonical_name = item.canonical_name(ctx);
+
+ if result.seen_var(&canonical_name) {
+ return;
+ }
+ result.saw_var(&canonical_name);
+
+ let canonical_ident = ctx.rust_ident(&canonical_name);
+
+ // We can't generate bindings to static variables of templates. The
+ // number of actual variables for a single declaration are open ended
+ // and we don't know what instantiations do or don't exist.
+ if !item.all_template_params(ctx).is_empty() {
+ return;
+ }
+
+ let mut attrs = vec![];
+ if let Some(comment) = item.comment(ctx) {
+ attrs.push(attributes::doc(comment));
+ }
+
+ let var_ty = self.ty();
+ let ty = var_ty.to_rust_ty_or_opaque(ctx, &());
+
+ if let Some(val) = self.val() {
+ match *val {
+ VarType::Bool(val) => {
+ result.push(quote! {
+ #(#attrs)*
+ pub const #canonical_ident : #ty = #val ;
+ });
+ }
+ VarType::Int(val) => {
+ let int_kind = var_ty
+ .into_resolver()
+ .through_type_aliases()
+ .through_type_refs()
+ .resolve(ctx)
+ .expect_type()
+ .as_integer()
+ .unwrap();
+ let val = if int_kind.is_signed() {
+ helpers::ast_ty::int_expr(val)
+ } else {
+ helpers::ast_ty::uint_expr(val as _)
+ };
+ result.push(quote! {
+ #(#attrs)*
+ pub const #canonical_ident : #ty = #val ;
+ });
+ }
+ VarType::String(ref bytes) => {
+ let prefix = ctx.trait_prefix();
+
+ let options = ctx.options();
+ let rust_features = options.rust_features;
+
+ let mut cstr_bytes = bytes.clone();
+ cstr_bytes.push(0);
+ let len = proc_macro2::Literal::usize_unsuffixed(
+ cstr_bytes.len(),
+ );
+
+ // TODO: Here we ignore the type we just made up, probably
+ // we should refactor how the variable type and ty ID work.
+ let array_ty = quote! { [u8; #len] };
+ let cstr_ty = quote! { ::#prefix::ffi::CStr };
+
+ let bytes = proc_macro2::Literal::byte_string(&cstr_bytes);
+
+ if options.generate_cstr &&
+ rust_features.const_cstr &&
+ CStr::from_bytes_with_nul(&cstr_bytes).is_ok()
+ {
+ result.push(quote! {
+ #(#attrs)*
+ #[allow(unsafe_code)]
+ pub const #canonical_ident: &#cstr_ty = unsafe {
+ #cstr_ty::from_bytes_with_nul_unchecked(#bytes)
+ };
+ });
+ } else {
+ let lifetime = if rust_features.static_lifetime_elision
+ {
+ None
+ } else {
+ Some(quote! { 'static })
+ }
+ .into_iter();
+
+ result.push(quote! {
+ #(#attrs)*
+ pub const #canonical_ident: &#(#lifetime )*#array_ty = #bytes ;
+ });
+ }
+ }
+ VarType::Float(f) => {
+ if let Ok(expr) = helpers::ast_ty::float_expr(ctx, f) {
+ result.push(quote! {
+ #(#attrs)*
+ pub const #canonical_ident : #ty = #expr ;
+ });
+ }
+ }
+ VarType::Char(c) => {
+ result.push(quote! {
+ #(#attrs)*
+ pub const #canonical_ident : #ty = #c ;
+ });
+ }
+ }
+ } else {
+ // If necessary, apply a `#[link_name]` attribute
+ if let Some(link_name) = self.link_name() {
+ attrs.push(attributes::link_name::<false>(link_name));
+ } else {
+ let link_name =
+ self.mangled_name().unwrap_or_else(|| self.name());
+ if !utils::names_will_be_identical_after_mangling(
+ &canonical_name,
+ link_name,
+ None,
+ ) {
+ attrs.push(attributes::link_name::<false>(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(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'_>,
+ item: &Item,
+ ) {
+ debug!("<Type as CodeGenerator>::codegen: item = {:?}", item);
+ debug_assert!(item.is_enabled_for_codegen(ctx));
+
+ match *self.kind() {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Array(..) |
+ TypeKind::Vector(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Function(..) |
+ TypeKind::ResolvedTypeRef(..) |
+ TypeKind::Opaque |
+ TypeKind::TypeParam => {
+ // These items don't need code generation, they only need to be
+ // converted to rust types in fields, arguments, and such.
+ // NOTE(emilio): If you add to this list, make sure to also add
+ // it to BindgenContext::compute_allowlisted_and_codegen_items.
+ }
+ TypeKind::TemplateInstantiation(ref inst) => {
+ inst.codegen(ctx, result, item)
+ }
+ TypeKind::BlockPointer(inner) => {
+ if !ctx.options().generate_block {
+ return;
+ }
+
+ let inner_item =
+ inner.into_resolver().through_type_refs().resolve(ctx);
+ let name = item.canonical_name(ctx);
+
+ let inner_rust_type = {
+ if let TypeKind::Function(fnsig) =
+ inner_item.kind().expect_type().kind()
+ {
+ utils::fnsig_block(ctx, fnsig)
+ } else {
+ panic!("invalid block typedef: {:?}", inner_item)
+ }
+ };
+
+ let rust_name = ctx.rust_ident(name);
+
+ let mut tokens = if let Some(comment) = item.comment(ctx) {
+ attributes::doc(comment)
+ } else {
+ quote! {}
+ };
+
+ tokens.append_all(quote! {
+ pub type #rust_name = #inner_rust_type ;
+ });
+
+ result.push(tokens);
+ result.saw_block();
+ }
+ TypeKind::Comp(ref ci) => ci.codegen(ctx, result, item),
+ TypeKind::TemplateAlias(inner, _) | TypeKind::Alias(inner) => {
+ let inner_item =
+ inner.into_resolver().through_type_refs().resolve(ctx);
+ let name = item.canonical_name(ctx);
+ let path = item.canonical_path(ctx);
+
+ {
+ let through_type_aliases = inner
+ .into_resolver()
+ .through_type_refs()
+ .through_type_aliases()
+ .resolve(ctx);
+
+ // Try to catch the common pattern:
+ //
+ // typedef struct foo { ... } foo;
+ //
+ // here, and also other more complex cases like #946.
+ if through_type_aliases.canonical_path(ctx) == path {
+ return;
+ }
+ }
+
+ // If this is a known named type, disallow generating anything
+ // for it too. If size_t -> usize conversions are enabled, we
+ // need to check that these conversions are permissible, but
+ // nothing needs to be generated, still.
+ let spelling = self.name().expect("Unnamed alias?");
+ if utils::type_from_named(ctx, spelling).is_some() {
+ if let "size_t" | "ssize_t" = spelling {
+ let layout = inner_item
+ .kind()
+ .expect_type()
+ .layout(ctx)
+ .expect("No layout?");
+ assert_eq!(
+ layout.size,
+ ctx.target_pointer_size(),
+ "Target platform requires `--no-size_t-is-usize`. The size of `{}` ({}) does not match the target pointer size ({})",
+ spelling,
+ layout.size,
+ ctx.target_pointer_size(),
+ );
+ assert_eq!(
+ layout.align,
+ ctx.target_pointer_size(),
+ "Target platform requires `--no-size_t-is-usize`. The alignment of `{}` ({}) does not match the target pointer size ({})",
+ spelling,
+ layout.align,
+ ctx.target_pointer_size(),
+ );
+ }
+ return;
+ }
+
+ let mut outer_params = item.used_template_params(ctx);
+
+ let is_opaque = item.is_opaque(ctx, &());
+ let inner_rust_type = if is_opaque {
+ outer_params = vec![];
+ self.to_opaque(ctx, item)
+ } else {
+ // Its possible that we have better layout information than
+ // the inner type does, so fall back to an opaque blob based
+ // on our layout if converting the inner item fails.
+ inner_item
+ .try_to_rust_ty_or_opaque(ctx, &())
+ .unwrap_or_else(|_| self.to_opaque(ctx, item))
+ .with_implicit_template_params(ctx, inner_item)
+ };
+
+ {
+ // FIXME(emilio): This is a workaround to avoid generating
+ // incorrect type aliases because of types that we haven't
+ // been able to resolve (because, eg, they depend on a
+ // template parameter).
+ //
+ // It's kind of a shame not generating them even when they
+ // could be referenced, but we already do the same for items
+ // with invalid template parameters, and at least this way
+ // they can be replaced, instead of generating plain invalid
+ // code.
+ let inner_canon_type =
+ inner_item.expect_type().canonical_type(ctx);
+ if inner_canon_type.is_invalid_type_param() {
+ warn!(
+ "Item contained invalid named type, skipping: \
+ {:?}, {:?}",
+ item, inner_item
+ );
+ return;
+ }
+ }
+
+ let rust_name = ctx.rust_ident(&name);
+
+ let mut tokens = if let Some(comment) = item.comment(ctx) {
+ attributes::doc(comment)
+ } else {
+ quote! {}
+ };
+
+ let alias_style = if ctx.options().type_alias.matches(&name) {
+ AliasVariation::TypeAlias
+ } else if ctx.options().new_type_alias.matches(&name) {
+ AliasVariation::NewType
+ } else if ctx.options().new_type_alias_deref.matches(&name) {
+ AliasVariation::NewTypeDeref
+ } else {
+ ctx.options().default_alias_style
+ };
+
+ // We prefer using `pub use` over `pub type` because of:
+ // https://github.com/rust-lang/rust/issues/26264
+ if matches!(inner_rust_type, syn::Type::Path(_)) &&
+ outer_params.is_empty() &&
+ !is_opaque &&
+ alias_style == AliasVariation::TypeAlias &&
+ inner_item.expect_type().canonical_type(ctx).is_enum()
+ {
+ tokens.append_all(quote! {
+ pub use
+ });
+ let path = top_level_path(ctx, item);
+ tokens.append_separated(path, quote!(::));
+ tokens.append_all(quote! {
+ :: #inner_rust_type as #rust_name ;
+ });
+ result.push(tokens);
+ return;
+ }
+
+ tokens.append_all(match alias_style {
+ AliasVariation::TypeAlias => quote! {
+ pub type #rust_name
+ },
+ AliasVariation::NewType | AliasVariation::NewTypeDeref => {
+ assert!(
+ ctx.options().rust_features().repr_transparent,
+ "repr_transparent feature is required to use {:?}",
+ alias_style
+ );
+
+ let mut attributes =
+ vec![attributes::repr("transparent")];
+ let packed = false; // Types can't be packed in Rust.
+ let derivable_traits =
+ derives_of_item(item, ctx, packed);
+ if !derivable_traits.is_empty() {
+ let derives: Vec<_> = derivable_traits.into();
+ attributes.push(attributes::derives(&derives))
+ }
+
+ quote! {
+ #( #attributes )*
+ pub struct #rust_name
+ }
+ }
+ });
+
+ let params: Vec<_> = outer_params
+ .into_iter()
+ .filter_map(|p| p.as_template_param(ctx, &()))
+ .collect();
+ if params
+ .iter()
+ .any(|p| ctx.resolve_type(*p).is_invalid_type_param())
+ {
+ warn!(
+ "Item contained invalid template \
+ parameter: {:?}",
+ item
+ );
+ return;
+ }
+ let params: Vec<_> = params
+ .iter()
+ .map(|p| {
+ p.try_to_rust_ty(ctx, &()).expect(
+ "type parameters can always convert to rust ty OK",
+ )
+ })
+ .collect();
+
+ if !params.is_empty() {
+ tokens.append_all(quote! {
+ < #( #params ),* >
+ });
+ }
+
+ let access_spec =
+ access_specifier(ctx.options().default_visibility);
+ tokens.append_all(match alias_style {
+ AliasVariation::TypeAlias => quote! {
+ = #inner_rust_type ;
+ },
+ AliasVariation::NewType | AliasVariation::NewTypeDeref => {
+ quote! {
+ (#access_spec #inner_rust_type) ;
+ }
+ }
+ });
+
+ if alias_style == AliasVariation::NewTypeDeref {
+ let prefix = ctx.trait_prefix();
+ tokens.append_all(quote! {
+ impl ::#prefix::ops::Deref for #rust_name {
+ type Target = #inner_rust_type;
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ impl ::#prefix::ops::DerefMut for #rust_name {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+ }
+ });
+ }
+
+ result.push(tokens);
+ }
+ TypeKind::Enum(ref ei) => ei.codegen(ctx, result, item),
+ TypeKind::ObjCId | TypeKind::ObjCSel => {
+ result.saw_objc();
+ }
+ TypeKind::ObjCInterface(ref interface) => {
+ interface.codegen(ctx, result, item)
+ }
+ ref u @ TypeKind::UnresolvedTypeRef(..) => {
+ unreachable!("Should have been resolved after parsing {:?}!", u)
+ }
+ }
+ }
+}
+
+struct Vtable<'a> {
+ item_id: ItemId,
+ /// A reference to the originating compound object.
+ #[allow(dead_code)]
+ comp_info: &'a CompInfo,
+}
+
+impl<'a> Vtable<'a> {
+ fn new(item_id: ItemId, comp_info: &'a CompInfo) -> Self {
+ Vtable { item_id, comp_info }
+ }
+}
+
+impl<'a> CodeGenerator for Vtable<'a> {
+ type Extra = Item;
+ type Return = ();
+
+ fn codegen(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'_>,
+ item: &Item,
+ ) {
+ assert_eq!(item.id(), self.item_id);
+ debug_assert!(item.is_enabled_for_codegen(ctx));
+ let name = ctx.rust_ident(self.canonical_name(ctx));
+
+ // For now, we will only generate vtables for classes that:
+ // - do not inherit from others (compilers merge VTable from primary parent class).
+ // - do not contain a virtual destructor (requires ordering; platforms generate different vtables).
+ if ctx.options().vtable_generation &&
+ self.comp_info.base_members().is_empty() &&
+ self.comp_info.destructor().is_none()
+ {
+ let class_ident = ctx.rust_ident(self.item_id.canonical_name(ctx));
+
+ let methods = self
+ .comp_info
+ .methods()
+ .iter()
+ .filter_map(|m| {
+ if !m.is_virtual() {
+ return None;
+ }
+
+ let function_item = ctx.resolve_item(m.signature());
+ let function = function_item.expect_function();
+ let signature_item = ctx.resolve_item(function.signature());
+ let signature = match signature_item.expect_type().kind() {
+ TypeKind::Function(ref sig) => sig,
+ _ => panic!("Function signature type mismatch"),
+ };
+
+ // FIXME: Is there a canonical name without the class prepended?
+ let function_name = function_item.canonical_name(ctx);
+
+ // FIXME: Need to account for overloading with times_seen (separately from regular function path).
+ let function_name = ctx.rust_ident(function_name);
+ let mut args = utils::fnsig_arguments(ctx, signature);
+ let ret = utils::fnsig_return_ty(ctx, signature);
+
+ args[0] = if m.is_const() {
+ quote! { this: *const #class_ident }
+ } else {
+ quote! { this: *mut #class_ident }
+ };
+
+ Some(quote! {
+ pub #function_name : unsafe extern "C" fn( #( #args ),* ) #ret
+ })
+ })
+ .collect::<Vec<_>>();
+
+ result.push(quote! {
+ #[repr(C)]
+ pub struct #name {
+ #( #methods ),*
+ }
+ })
+ } else {
+ // For the cases we don't support, simply generate an empty struct.
+ let void = helpers::ast_ty::c_void(ctx);
+
+ result.push(quote! {
+ #[repr(C)]
+ pub struct #name ( #void );
+ });
+ }
+ }
+}
+
+impl<'a> ItemCanonicalName for Vtable<'a> {
+ fn canonical_name(&self, ctx: &BindgenContext) -> String {
+ format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx))
+ }
+}
+
+impl<'a> TryToRustTy for Vtable<'a> {
+ type Extra = ();
+
+ fn try_to_rust_ty(
+ &self,
+ ctx: &BindgenContext,
+ _: &(),
+ ) -> error::Result<syn::Type> {
+ let name = ctx.rust_ident(self.canonical_name(ctx));
+ Ok(syn::parse_quote! { #name })
+ }
+}
+
+impl CodeGenerator for TemplateInstantiation {
+ type Extra = Item;
+ type Return = ();
+
+ fn codegen(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'_>,
+ item: &Item,
+ ) {
+ debug_assert!(item.is_enabled_for_codegen(ctx));
+
+ // Although uses of instantiations don't need code generation, and are
+ // just converted to rust types in fields, vars, etc, we take this
+ // opportunity to generate tests for their layout here. If the
+ // instantiation is opaque, then its presumably because we don't
+ // properly understand it (maybe because of specializations), and so we
+ // shouldn't emit layout tests either.
+ if !ctx.options().layout_tests || self.is_opaque(ctx, item) {
+ return;
+ }
+
+ // If there are any unbound type parameters, then we can't generate a
+ // layout test because we aren't dealing with a concrete type with a
+ // concrete size and alignment.
+ if ctx.uses_any_template_parameters(item.id()) {
+ return;
+ }
+
+ let layout = item.kind().expect_type().layout(ctx);
+
+ if let Some(layout) = layout {
+ let size = layout.size;
+ let align = layout.align;
+
+ let name = item.full_disambiguated_name(ctx);
+ let mut fn_name =
+ format!("__bindgen_test_layout_{}_instantiation", name);
+ let times_seen = result.overload_number(&fn_name);
+ if times_seen > 0 {
+ write!(&mut fn_name, "_{}", times_seen).unwrap();
+ }
+
+ let fn_name = ctx.rust_ident_raw(fn_name);
+
+ let prefix = ctx.trait_prefix();
+ let ident = item.to_rust_ty_or_opaque(ctx, &());
+ let size_of_expr = quote! {
+ ::#prefix::mem::size_of::<#ident>()
+ };
+ let align_of_expr = quote! {
+ ::#prefix::mem::align_of::<#ident>()
+ };
+
+ let item = quote! {
+ #[test]
+ fn #fn_name() {
+ assert_eq!(#size_of_expr, #size,
+ concat!("Size of template specialization: ",
+ stringify!(#ident)));
+ assert_eq!(#align_of_expr, #align,
+ concat!("Alignment of template specialization: ",
+ stringify!(#ident)));
+ }
+ };
+
+ result.push(item);
+ }
+ }
+}
+
+/// Trait for implementing the code generation of a struct or union field.
+trait FieldCodegen<'a> {
+ type Extra;
+
+ #[allow(clippy::too_many_arguments)]
+ fn codegen<F, M>(
+ &self,
+ ctx: &BindgenContext,
+ visibility_kind: FieldVisibilityKind,
+ accessor_kind: FieldAccessorKind,
+ parent: &CompInfo,
+ parent_item: &Item,
+ result: &mut CodegenResult,
+ struct_layout: &mut StructLayoutTracker,
+ fields: &mut F,
+ methods: &mut M,
+ extra: Self::Extra,
+ ) where
+ F: Extend<proc_macro2::TokenStream>,
+ M: Extend<proc_macro2::TokenStream>;
+}
+
+impl<'a> FieldCodegen<'a> for Field {
+ type Extra = ();
+
+ fn codegen<F, M>(
+ &self,
+ ctx: &BindgenContext,
+ visibility_kind: FieldVisibilityKind,
+ accessor_kind: FieldAccessorKind,
+ parent: &CompInfo,
+ parent_item: &Item,
+ result: &mut CodegenResult,
+ struct_layout: &mut StructLayoutTracker,
+ fields: &mut F,
+ methods: &mut M,
+ _: (),
+ ) where
+ F: Extend<proc_macro2::TokenStream>,
+ M: Extend<proc_macro2::TokenStream>,
+ {
+ match *self {
+ Field::DataMember(ref data) => {
+ data.codegen(
+ ctx,
+ visibility_kind,
+ accessor_kind,
+ parent,
+ parent_item,
+ result,
+ struct_layout,
+ fields,
+ methods,
+ (),
+ );
+ }
+ Field::Bitfields(ref unit) => {
+ unit.codegen(
+ ctx,
+ visibility_kind,
+ accessor_kind,
+ parent,
+ parent_item,
+ result,
+ struct_layout,
+ fields,
+ methods,
+ (),
+ );
+ }
+ }
+ }
+}
+
+fn wrap_union_field_if_needed(
+ ctx: &BindgenContext,
+ struct_layout: &StructLayoutTracker,
+ ty: syn::Type,
+ result: &mut CodegenResult,
+) -> syn::Type {
+ if struct_layout.is_rust_union() {
+ if struct_layout.can_copy_union_fields() {
+ ty
+ } else {
+ let prefix = ctx.trait_prefix();
+ syn::parse_quote! { ::#prefix::mem::ManuallyDrop<#ty> }
+ }
+ } else {
+ result.saw_bindgen_union();
+ if ctx.options().enable_cxx_namespaces {
+ syn::parse_quote! { root::__BindgenUnionField<#ty> }
+ } else {
+ syn::parse_quote! { __BindgenUnionField<#ty> }
+ }
+ }
+}
+
+impl<'a> FieldCodegen<'a> for FieldData {
+ type Extra = ();
+
+ fn codegen<F, M>(
+ &self,
+ ctx: &BindgenContext,
+ parent_visibility_kind: FieldVisibilityKind,
+ accessor_kind: FieldAccessorKind,
+ parent: &CompInfo,
+ parent_item: &Item,
+ result: &mut CodegenResult,
+ struct_layout: &mut StructLayoutTracker,
+ fields: &mut F,
+ methods: &mut M,
+ _: (),
+ ) where
+ F: Extend<proc_macro2::TokenStream>,
+ M: Extend<proc_macro2::TokenStream>,
+ {
+ // Bitfields are handled by `FieldCodegen` implementations for
+ // `BitfieldUnit` and `Bitfield`.
+ assert!(self.bitfield_width().is_none());
+
+ let field_item =
+ self.ty().into_resolver().through_type_refs().resolve(ctx);
+ let field_ty = field_item.expect_type();
+ let ty = self
+ .ty()
+ .to_rust_ty_or_opaque(ctx, &())
+ .with_implicit_template_params(ctx, field_item);
+
+ // NB: If supported, we use proper `union` types.
+ let ty = if parent.is_union() {
+ wrap_union_field_if_needed(ctx, struct_layout, ty, result)
+ } else if let Some(item) = field_ty.is_incomplete_array(ctx) {
+ result.saw_incomplete_array();
+
+ let inner = item.to_rust_ty_or_opaque(ctx, &());
+
+ if ctx.options().enable_cxx_namespaces {
+ syn::parse_quote! { root::__IncompleteArrayField<#inner> }
+ } else {
+ syn::parse_quote! { __IncompleteArrayField<#inner> }
+ }
+ } else {
+ ty
+ };
+
+ let mut field = quote! {};
+ if ctx.options().generate_comments {
+ if let Some(raw_comment) = self.comment() {
+ let comment = ctx.options().process_comment(raw_comment);
+ field = attributes::doc(comment);
+ }
+ }
+
+ let field_name = self
+ .name()
+ .map(|name| ctx.rust_mangle(name).into_owned())
+ .expect("Each field should have a name in codegen!");
+ let field_name = field_name.as_str();
+ let field_ident = ctx.rust_ident_raw(field_name);
+
+ if let Some(padding_field) =
+ struct_layout.saw_field(field_name, field_ty, self.offset())
+ {
+ fields.extend(Some(padding_field));
+ }
+
+ let visibility = compute_visibility(
+ ctx,
+ self.is_public(),
+ ctx.options().last_callback(|cb| {
+ cb.field_visibility(FieldInfo {
+ type_name: &parent_item.canonical_name(ctx),
+ field_name,
+ })
+ }),
+ self.annotations(),
+ parent_visibility_kind,
+ );
+ let accessor_kind =
+ self.annotations().accessor_kind().unwrap_or(accessor_kind);
+
+ match visibility {
+ FieldVisibilityKind::Private => {
+ field.append_all(quote! {
+ #field_ident : #ty ,
+ });
+ }
+ FieldVisibilityKind::PublicCrate => {
+ field.append_all(quote! {
+ pub(crate) #field_ident : #ty ,
+ });
+ }
+ FieldVisibilityKind::Public => {
+ field.append_all(quote! {
+ pub #field_ident : #ty ,
+ });
+ }
+ }
+
+ fields.extend(Some(field));
+
+ // TODO: Factor the following code out, please!
+ if accessor_kind == FieldAccessorKind::None {
+ return;
+ }
+
+ let getter_name = ctx.rust_ident_raw(format!("get_{}", field_name));
+ let mutable_getter_name =
+ ctx.rust_ident_raw(format!("get_{}_mut", field_name));
+
+ methods.extend(Some(match accessor_kind {
+ FieldAccessorKind::None => unreachable!(),
+ FieldAccessorKind::Regular => {
+ quote! {
+ #[inline]
+ pub fn #getter_name(&self) -> & #ty {
+ &self.#field_ident
+ }
+
+ #[inline]
+ pub fn #mutable_getter_name(&mut self) -> &mut #ty {
+ &mut self.#field_ident
+ }
+ }
+ }
+ FieldAccessorKind::Unsafe => {
+ quote! {
+ #[inline]
+ pub unsafe fn #getter_name(&self) -> & #ty {
+ &self.#field_ident
+ }
+
+ #[inline]
+ pub unsafe fn #mutable_getter_name(&mut self) -> &mut #ty {
+ &mut self.#field_ident
+ }
+ }
+ }
+ FieldAccessorKind::Immutable => {
+ quote! {
+ #[inline]
+ pub fn #getter_name(&self) -> & #ty {
+ &self.#field_ident
+ }
+ }
+ }
+ }));
+ }
+}
+
+impl BitfieldUnit {
+ /// Get the constructor name for this bitfield unit.
+ fn ctor_name(&self) -> proc_macro2::TokenStream {
+ let ctor_name = Ident::new(
+ &format!("new_bitfield_{}", self.nth()),
+ Span::call_site(),
+ );
+ quote! {
+ #ctor_name
+ }
+ }
+}
+
+impl Bitfield {
+ /// Extend an under construction bitfield unit constructor with this
+ /// bitfield. This sets the relevant bits on the `__bindgen_bitfield_unit`
+ /// variable that's being constructed.
+ fn extend_ctor_impl(
+ &self,
+ ctx: &BindgenContext,
+ param_name: proc_macro2::TokenStream,
+ mut ctor_impl: proc_macro2::TokenStream,
+ ) -> proc_macro2::TokenStream {
+ let bitfield_ty = ctx.resolve_type(self.ty());
+ let bitfield_ty_layout = bitfield_ty
+ .layout(ctx)
+ .expect("Bitfield without layout? Gah!");
+ let bitfield_int_ty = helpers::integer_type(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(
+ visibility: FieldVisibilityKind,
+) -> proc_macro2::TokenStream {
+ match visibility {
+ FieldVisibilityKind::Private => quote! {},
+ FieldVisibilityKind::PublicCrate => quote! { pub(crate) },
+ FieldVisibilityKind::Public => quote! { pub },
+ }
+}
+
+/// Compute a fields or structs visibility based on multiple conditions.
+/// 1. If the element was declared public, and we respect such CXX accesses specs
+/// (context option) => By default Public, but this can be overruled by an `annotation`.
+///
+/// 2. If the element was declared private, and we respect such CXX accesses specs
+/// (context option) => By default Private, but this can be overruled by an `annotation`.
+///
+/// 3. If we do not respect visibility modifiers, the result depends on the `annotation`,
+/// if any, or the passed `default_kind`.
+///
+fn compute_visibility(
+ ctx: &BindgenContext,
+ is_declared_public: bool,
+ callback_override: Option<FieldVisibilityKind>,
+ annotations: &Annotations,
+ default_kind: FieldVisibilityKind,
+) -> FieldVisibilityKind {
+ callback_override
+ .or_else(|| annotations.visibility_kind())
+ .unwrap_or_else(|| {
+ match (is_declared_public, ctx.options().respect_cxx_access_specs) {
+ (true, true) => {
+ // declared as public, cxx specs are respected
+ FieldVisibilityKind::Public
+ }
+ (false, true) => {
+ // declared as private, cxx specs are respected
+ FieldVisibilityKind::Private
+ }
+ (_, false) => {
+ // cxx specs are not respected, declaration does not matter.
+ default_kind
+ }
+ }
+ })
+}
+
+impl<'a> FieldCodegen<'a> for BitfieldUnit {
+ type Extra = ();
+
+ fn codegen<F, M>(
+ &self,
+ ctx: &BindgenContext,
+ visibility_kind: FieldVisibilityKind,
+ accessor_kind: FieldAccessorKind,
+ parent: &CompInfo,
+ parent_item: &Item,
+ result: &mut CodegenResult,
+ struct_layout: &mut StructLayoutTracker,
+ fields: &mut F,
+ methods: &mut M,
+ _: (),
+ ) where
+ F: Extend<proc_macro2::TokenStream>,
+ M: Extend<proc_macro2::TokenStream>,
+ {
+ use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
+
+ result.saw_bitfield_unit();
+
+ let layout = self.layout();
+ let unit_field_ty = helpers::bitfield_unit(ctx, layout);
+ let field_ty = {
+ let unit_field_ty = unit_field_ty.clone();
+ if parent.is_union() {
+ wrap_union_field_if_needed(
+ ctx,
+ struct_layout,
+ unit_field_ty,
+ result,
+ )
+ } else {
+ unit_field_ty
+ }
+ };
+
+ {
+ let align_field_name = format!("_bitfield_align_{}", self.nth());
+ let align_field_ident = ctx.rust_ident(align_field_name);
+ let align_ty = match self.layout().align {
+ n if n >= 8 => quote! { u64 },
+ 4 => quote! { u32 },
+ 2 => quote! { u16 },
+ _ => quote! { u8 },
+ };
+ let access_spec = access_specifier(visibility_kind);
+ let align_field = quote! {
+ #access_spec #align_field_ident: [#align_ty; 0],
+ };
+ fields.extend(Some(align_field));
+ }
+
+ let unit_field_name = format!("_bitfield_{}", self.nth());
+ let unit_field_ident = ctx.rust_ident(&unit_field_name);
+
+ let ctor_name = self.ctor_name();
+ let mut ctor_params = vec![];
+ let mut ctor_impl = quote! {};
+
+ // We cannot generate any constructor if the underlying storage can't
+ // implement AsRef<[u8]> / AsMut<[u8]> / etc, or can't derive Default.
+ //
+ // We don't check `larger_arrays` here because Default does still have
+ // the 32 items limitation.
+ let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT;
+
+ let mut unit_visibility = visibility_kind;
+ 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;
+ }
+
+ let mut bitfield_representable_as_int = true;
+ let mut bitfield_visibility = visibility_kind;
+ bf.codegen(
+ ctx,
+ visibility_kind,
+ accessor_kind,
+ parent,
+ parent_item,
+ result,
+ struct_layout,
+ fields,
+ methods,
+ (
+ &unit_field_name,
+ &mut bitfield_representable_as_int,
+ &mut bitfield_visibility,
+ ),
+ );
+ if bitfield_visibility < unit_visibility {
+ unit_visibility = bitfield_visibility;
+ }
+
+ // Generating a constructor requires the bitfield to be representable as an integer.
+ if !bitfield_representable_as_int {
+ generate_ctor = false;
+ continue;
+ }
+
+ let param_name = bitfield_getter_name(ctx, bf);
+ let bitfield_ty_item = ctx.resolve_item(bf.ty());
+ let bitfield_ty = bitfield_ty_item.expect_type();
+ let bitfield_ty =
+ bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
+
+ ctor_params.push(quote! {
+ #param_name : #bitfield_ty
+ });
+ ctor_impl = bf.extend_ctor_impl(ctx, param_name, ctor_impl);
+ }
+
+ let access_spec = access_specifier(unit_visibility);
+
+ let field = quote! {
+ #access_spec #unit_field_ident : #field_ty ,
+ };
+ fields.extend(Some(field));
+
+ if generate_ctor {
+ methods.extend(Some(quote! {
+ #[inline]
+ #access_spec fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_ty {
+ let mut __bindgen_bitfield_unit: #unit_field_ty = Default::default();
+ #ctor_impl
+ __bindgen_bitfield_unit
+ }
+ }));
+ }
+
+ struct_layout.saw_bitfield_unit(layout);
+ }
+}
+
+fn bitfield_getter_name(
+ ctx: &BindgenContext,
+ bitfield: &Bitfield,
+) -> proc_macro2::TokenStream {
+ let name = bitfield.getter_name();
+ let name = ctx.rust_ident_raw(name);
+ quote! { #name }
+}
+
+fn bitfield_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, &'a mut FieldVisibilityKind);
+
+ fn codegen<F, M>(
+ &self,
+ ctx: &BindgenContext,
+ visibility_kind: FieldVisibilityKind,
+ _accessor_kind: FieldAccessorKind,
+ parent: &CompInfo,
+ parent_item: &Item,
+ _result: &mut CodegenResult,
+ struct_layout: &mut StructLayoutTracker,
+ _fields: &mut F,
+ methods: &mut M,
+ (unit_field_name, bitfield_representable_as_int, bitfield_visibility): (
+ &'a str,
+ &mut bool,
+ &'a mut FieldVisibilityKind,
+ ),
+ ) where
+ F: Extend<proc_macro2::TokenStream>,
+ M: Extend<proc_macro2::TokenStream>,
+ {
+ let prefix = ctx.trait_prefix();
+ let getter_name = bitfield_getter_name(ctx, self);
+ let setter_name = bitfield_setter_name(ctx, self);
+ let unit_field_ident = Ident::new(unit_field_name, Span::call_site());
+
+ let bitfield_ty_item = ctx.resolve_item(self.ty());
+ let bitfield_ty = bitfield_ty_item.expect_type();
+
+ let bitfield_ty_layout = bitfield_ty
+ .layout(ctx)
+ .expect("Bitfield without layout? Gah!");
+ let bitfield_int_ty =
+ match helpers::integer_type(ctx, bitfield_ty_layout) {
+ Some(int_ty) => {
+ *bitfield_representable_as_int = true;
+ int_ty
+ }
+ None => {
+ *bitfield_representable_as_int = false;
+ return;
+ }
+ };
+
+ let bitfield_ty =
+ bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item);
+
+ let offset = self.offset_into_unit();
+ let width = self.width() as u8;
+
+ let override_visibility = self.name().and_then(|field_name| {
+ ctx.options().last_callback(|cb| {
+ cb.field_visibility(FieldInfo {
+ type_name: &parent_item.canonical_name(ctx),
+ field_name,
+ })
+ })
+ });
+ *bitfield_visibility = compute_visibility(
+ ctx,
+ self.is_public(),
+ override_visibility,
+ self.annotations(),
+ visibility_kind,
+ );
+ let access_spec = access_specifier(*bitfield_visibility);
+
+ if parent.is_union() && !struct_layout.is_rust_union() {
+ methods.extend(Some(quote! {
+ #[inline]
+ #access_spec fn #getter_name(&self) -> #bitfield_ty {
+ unsafe {
+ ::#prefix::mem::transmute(
+ self.#unit_field_ident.as_ref().get(#offset, #width)
+ as #bitfield_int_ty
+ )
+ }
+ }
+
+ #[inline]
+ #access_spec fn #setter_name(&mut self, val: #bitfield_ty) {
+ unsafe {
+ let val: #bitfield_int_ty = ::#prefix::mem::transmute(val);
+ self.#unit_field_ident.as_mut().set(
+ #offset,
+ #width,
+ val as u64
+ )
+ }
+ }
+ }));
+ } 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(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'_>,
+ item: &Item,
+ ) {
+ debug!("<CompInfo as CodeGenerator>::codegen: item = {:?}", item);
+ debug_assert!(item.is_enabled_for_codegen(ctx));
+
+ // Don't output classes with template parameters that aren't types, and
+ // also don't output template specializations, neither total or partial.
+ if self.has_non_type_template_params() {
+ return;
+ }
+
+ let ty = item.expect_type();
+ let layout = ty.layout(ctx);
+ let mut packed = self.is_packed(ctx, layout.as_ref());
+
+ let canonical_name = item.canonical_name(ctx);
+ let canonical_ident = ctx.rust_ident(&canonical_name);
+
+ // Generate the vtable from the method list if appropriate.
+ //
+ // TODO: I don't know how this could play with virtual methods that are
+ // not in the list of methods found by us, we'll see. Also, could the
+ // order of the vtable pointers vary?
+ //
+ // FIXME: Once we generate proper vtables, we need to codegen the
+ // vtable, but *not* generate a field for it in the case that
+ // HasVtable::has_vtable_ptr is false but HasVtable::has_vtable is true.
+ //
+ // Also, we need to generate the vtable in such a way it "inherits" from
+ // the parent too.
+ let is_opaque = item.is_opaque(ctx, &());
+ let mut fields = vec![];
+ let visibility = item
+ .annotations()
+ .visibility_kind()
+ .unwrap_or(ctx.options().default_visibility);
+ let mut struct_layout = StructLayoutTracker::new(
+ ctx,
+ self,
+ ty,
+ &canonical_name,
+ visibility,
+ packed,
+ );
+
+ if !is_opaque {
+ if item.has_vtable_ptr(ctx) {
+ let vtable = Vtable::new(item.id(), self);
+ vtable.codegen(ctx, result, item);
+
+ let vtable_type = vtable
+ .try_to_rust_ty(ctx, &())
+ .expect("vtable to Rust type conversion is infallible")
+ .to_ptr(true);
+
+ fields.push(quote! {
+ pub vtable_: #vtable_type ,
+ });
+
+ struct_layout.saw_vtable();
+ }
+
+ for base in self.base_members() {
+ if !base.requires_storage(ctx) {
+ continue;
+ }
+
+ let inner_item = ctx.resolve_item(base.ty);
+ let inner = inner_item
+ .to_rust_ty_or_opaque(ctx, &())
+ .with_implicit_template_params(ctx, inner_item);
+ let field_name = ctx.rust_ident(&base.field_name);
+
+ struct_layout.saw_base(inner_item.expect_type());
+
+ let visibility = match (
+ base.is_public(),
+ ctx.options().respect_cxx_access_specs,
+ ) {
+ (true, true) => FieldVisibilityKind::Public,
+ (false, true) => FieldVisibilityKind::Private,
+ _ => ctx.options().default_visibility,
+ };
+
+ let access_spec = access_specifier(visibility);
+ fields.push(quote! {
+ #access_spec #field_name: #inner,
+ });
+ }
+ }
+
+ let mut methods = vec![];
+ if !is_opaque {
+ let struct_accessor_kind = item
+ .annotations()
+ .accessor_kind()
+ .unwrap_or(FieldAccessorKind::None);
+ for field in self.fields() {
+ field.codegen(
+ ctx,
+ visibility,
+ struct_accessor_kind,
+ self,
+ item,
+ 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 a type has both a "packed" attribute and an "align(N)" attribute, then check if the
+ // "packed" attr is redundant, and do not include it if so.
+ if packed &&
+ !is_opaque &&
+ !(explicit_align.is_some() &&
+ self.already_packed(ctx).unwrap_or(false))
+ {
+ let n = layout.map_or(1, |l| l.align);
+ assert!(ctx.options().rust_features().repr_packed_n || n == 1);
+ let packed_repr = if n == 1 {
+ "packed".to_string()
+ } else {
+ format!("packed({})", n)
+ };
+ attributes.push(attributes::repr_list(&["C", &packed_repr]));
+ } else {
+ attributes.push(attributes::repr("C"));
+ }
+
+ if ctx.options().rust_features().repr_align {
+ if let Some(explicit) = explicit_align {
+ // Ensure that the struct has the correct alignment even in
+ // presence of alignas.
+ let explicit = helpers::ast_ty::int_expr(explicit as i64);
+ attributes.push(quote! {
+ #[repr(align(#explicit))]
+ });
+ }
+ }
+
+ let derivable_traits = derives_of_item(item, ctx, packed);
+ if !derivable_traits.contains(DerivableTraits::DEBUG) {
+ needs_debug_impl = ctx.options().derive_debug &&
+ ctx.options().impl_debug &&
+ !ctx.no_debug_by_name(item) &&
+ !item.annotations().disallow_debug();
+ }
+
+ if !derivable_traits.contains(DerivableTraits::DEFAULT) {
+ needs_default_impl = ctx.options().derive_default &&
+ !self.is_forward_declaration() &&
+ !ctx.no_default_by_name(item) &&
+ !item.annotations().disallow_default();
+ }
+
+ let all_template_params = item.all_template_params(ctx);
+
+ if derivable_traits.contains(DerivableTraits::COPY) &&
+ !derivable_traits.contains(DerivableTraits::CLONE)
+ {
+ needs_clone_impl = true;
+ }
+
+ if !derivable_traits.contains(DerivableTraits::PARTIAL_EQ) {
+ needs_partialeq_impl = ctx.options().derive_partialeq &&
+ ctx.options().impl_partialeq &&
+ ctx.lookup_can_derive_partialeq_or_partialord(item.id()) ==
+ CanDerive::Manually;
+ }
+
+ let mut derives: Vec<_> = derivable_traits.into();
+ derives.extend(item.annotations().derives().iter().map(String::as_str));
+
+ let is_rust_union = is_union && struct_layout.is_rust_union();
+
+ // The custom derives callback may return a list of derive attributes;
+ // add them to the end of the list.
+ let custom_derives = ctx.options().all_callbacks(|cb| {
+ cb.add_derives(&DeriveInfo {
+ name: &canonical_name,
+ kind: if is_rust_union {
+ DeriveTypeKind::Union
+ } else {
+ DeriveTypeKind::Struct
+ },
+ })
+ });
+ // In most cases this will be a no-op, since custom_derives will be empty.
+ derives.extend(custom_derives.iter().map(|s| s.as_str()));
+
+ if !derives.is_empty() {
+ attributes.push(attributes::derives(&derives))
+ }
+
+ if item.must_use(ctx) {
+ attributes.push(attributes::must_use());
+ }
+
+ let mut tokens = if is_rust_union {
+ quote! {
+ #( #attributes )*
+ pub union #canonical_ident
+ }
+ } else {
+ quote! {
+ #( #attributes )*
+ pub struct #canonical_ident
+ }
+ };
+
+ tokens.append_all(quote! {
+ #generics {
+ #( #fields )*
+ }
+ });
+ result.push(tokens);
+
+ // Generate the inner types and all that stuff.
+ //
+ // TODO: In the future we might want to be smart, and use nested
+ // modules, and whatnot.
+ for ty in self.inner_types() {
+ let child_item = ctx.resolve_item(*ty);
+ // assert_eq!(child_item.parent_id(), item.id());
+ child_item.codegen(ctx, result, &());
+ }
+
+ // NOTE: Some unexposed attributes (like alignment attributes) may
+ // affect layout, so we're bad and pray to the gods for avoid sending
+ // all the tests to shit when parsing things like max_align_t.
+ if self.found_unknown_attr() {
+ warn!(
+ "Type {} 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)));
+
+ })
+ };
+
+ let should_skip_field_offset_checks = is_opaque;
+
+ let check_field_offset = if should_skip_field_offset_checks
+ {
+ vec![]
+ } else {
+ self.fields()
+ .iter()
+ .filter_map(|field| match *field {
+ Field::DataMember(ref f) if f.name().is_some() => Some(f),
+ _ => None,
+ })
+ .flat_map(|field| {
+ let name = field.name().unwrap();
+ field.offset().map(|offset| {
+ let field_offset = offset / 8;
+ let field_name = ctx.rust_ident(name);
+ quote! {
+ assert_eq!(
+ unsafe {
+ ::#prefix::ptr::addr_of!((*ptr).#field_name) as usize - ptr as usize
+ },
+ #field_offset,
+ concat!("Offset of field: ", stringify!(#canonical_ident), "::", stringify!(#field_name))
+ );
+ }
+ })
+ })
+ .collect()
+ };
+
+ let uninit_decl = if !check_field_offset.is_empty() {
+ // FIXME: When MSRV >= 1.59.0, we can use
+ // > const PTR: *const #canonical_ident = ::#prefix::mem::MaybeUninit::uninit().as_ptr();
+ Some(quote! {
+ // Use a shared MaybeUninit so that rustc with
+ // opt-level=0 doesn't take too much stack space,
+ // see #2218.
+ const UNINIT: ::#prefix::mem::MaybeUninit<#canonical_ident> = ::#prefix::mem::MaybeUninit::uninit();
+ let ptr = UNINIT.as_ptr();
+ })
+ } else {
+ None
+ };
+
+ let item = quote! {
+ #[test]
+ fn #fn_name() {
+ #uninit_decl
+ assert_eq!(#size_of_expr,
+ #size,
+ concat!("Size of: ", stringify!(#canonical_ident)));
+ #check_struct_align
+ #( #check_field_offset )*
+ }
+ };
+ result.push(item);
+ }
+ }
+
+ let mut method_names = Default::default();
+ if ctx.options().codegen_config.methods() {
+ for method in self.methods() {
+ assert!(method.kind() != MethodKind::Constructor);
+ method.codegen_method(
+ ctx,
+ &mut methods,
+ &mut method_names,
+ result,
+ self,
+ );
+ }
+ }
+
+ if ctx.options().codegen_config.constructors() {
+ for sig in self.constructors() {
+ Method::new(
+ MethodKind::Constructor,
+ *sig,
+ /* const */
+ false,
+ )
+ .codegen_method(
+ ctx,
+ &mut methods,
+ &mut method_names,
+ result,
+ self,
+ );
+ }
+ }
+
+ if ctx.options().codegen_config.destructors() {
+ if let Some((kind, destructor)) = self.destructor() {
+ debug_assert!(kind.is_destructor());
+ Method::new(kind, destructor, false).codegen_method(
+ ctx,
+ &mut methods,
+ &mut method_names,
+ result,
+ self,
+ );
+ }
+ }
+ }
+
+ // NB: We can't use to_rust_ty here since for opaque types this tries to
+ // use the specialization knowledge to generate a blob field.
+ let ty_for_impl = quote! {
+ #canonical_ident #generics
+ };
+
+ if needs_clone_impl {
+ result.push(quote! {
+ impl #generics Clone for #ty_for_impl {
+ fn clone(&self) -> Self { *self }
+ }
+ });
+ }
+
+ if needs_default_impl {
+ let prefix = ctx.trait_prefix();
+ let body = if ctx.options().rust_features().maybe_uninit {
+ quote! {
+ let mut s = ::#prefix::mem::MaybeUninit::<Self>::uninit();
+ unsafe {
+ ::#prefix::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+ s.assume_init()
+ }
+ }
+ } else {
+ quote! {
+ unsafe {
+ let mut s: Self = ::#prefix::mem::uninitialized();
+ ::#prefix::ptr::write_bytes(&mut s, 0, 1);
+ s
+ }
+ }
+ };
+ // Note we use `ptr::write_bytes()` instead of `mem::zeroed()` because the latter does
+ // not necessarily ensure padding bytes are zeroed. Some C libraries are sensitive to
+ // non-zero padding bytes, especially when forwards/backwards compatability is
+ // involved.
+ result.push(quote! {
+ impl #generics Default for #ty_for_impl {
+ fn default() -> Self {
+ #body
+ }
+ }
+ });
+ }
+
+ if needs_debug_impl {
+ let impl_ = impl_debug::gen_debug_impl(
+ ctx,
+ self.fields(),
+ item,
+ self.kind(),
+ );
+
+ let prefix = ctx.trait_prefix();
+
+ result.push(quote! {
+ impl #generics ::#prefix::fmt::Debug for #ty_for_impl {
+ #impl_
+ }
+ });
+ }
+
+ if needs_partialeq_impl {
+ if let Some(impl_) = impl_partialeq::gen_partialeq_impl(
+ ctx,
+ self,
+ item,
+ &ty_for_impl,
+ ) {
+ let partialeq_bounds = if !generic_param_names.is_empty() {
+ let bounds = generic_param_names.iter().map(|t| {
+ quote! { #t: PartialEq }
+ });
+ quote! { where #( #bounds ),* }
+ } else {
+ quote! {}
+ };
+
+ let prefix = ctx.trait_prefix();
+ result.push(quote! {
+ impl #generics ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds {
+ #impl_
+ }
+ });
+ }
+ }
+
+ if !methods.is_empty() {
+ result.push(quote! {
+ impl #generics #ty_for_impl {
+ #( #methods )*
+ }
+ });
+ }
+ }
+}
+
+impl Method {
+ fn codegen_method(
+ &self,
+ ctx: &BindgenContext,
+ methods: &mut Vec<proc_macro2::TokenStream>,
+ method_names: &mut HashSet<String>,
+ result: &mut CodegenResult<'_>,
+ _parent: &CompInfo,
+ ) {
+ assert!({
+ let cc = &ctx.options().codegen_config;
+ match self.kind() {
+ MethodKind::Constructor => cc.constructors(),
+ MethodKind::Destructor => cc.destructors(),
+ MethodKind::VirtualDestructor { .. } => cc.destructors(),
+ MethodKind::Static |
+ MethodKind::Normal |
+ MethodKind::Virtual { .. } => cc.methods(),
+ }
+ });
+
+ // TODO(emilio): We could generate final stuff at least.
+ if self.is_virtual() {
+ return; // FIXME
+ }
+
+ // First of all, output the actual function.
+ let function_item = ctx.resolve_item(self.signature());
+ if !function_item.process_before_codegen(ctx, result) {
+ return;
+ }
+ let function = function_item.expect_function();
+ let times_seen = function.codegen(ctx, result, function_item);
+ let times_seen = match times_seen {
+ Some(seen) => seen,
+ None => return,
+ };
+ let signature_item = ctx.resolve_item(function.signature());
+ let mut name = match self.kind() {
+ MethodKind::Constructor => "new".into(),
+ MethodKind::Destructor => "destruct".into(),
+ _ => function.name().to_owned(),
+ };
+
+ let signature = match *signature_item.expect_type().kind() {
+ TypeKind::Function(ref sig) => sig,
+ _ => panic!("How in the world?"),
+ };
+
+ let supported_abi = signature.abi(ctx, Some(&*name)).is_ok();
+ if !supported_abi {
+ return;
+ }
+
+ // Do not generate variadic methods, since rust does not allow
+ // implementing them, and we don't do a good job at it anyway.
+ if signature.is_variadic() {
+ return;
+ }
+
+ if method_names.contains(&name) {
+ let mut count = 1;
+ let mut new_name;
+
+ while {
+ new_name = format!("{}{}", name, count);
+ method_names.contains(&new_name)
+ } {
+ count += 1;
+ }
+
+ name = new_name;
+ }
+
+ method_names.insert(name.clone());
+
+ let mut function_name = function_item.canonical_name(ctx);
+ if times_seen > 0 {
+ write!(&mut function_name, "{}", times_seen).unwrap();
+ }
+ let function_name = ctx.rust_ident(function_name);
+ let mut args = utils::fnsig_arguments(ctx, signature);
+ let mut ret = utils::fnsig_return_ty(ctx, signature);
+
+ if !self.is_static() && !self.is_constructor() {
+ args[0] = if self.is_const() {
+ quote! { &self }
+ } else {
+ quote! { &mut self }
+ };
+ }
+
+ // If it's a constructor, we always return `Self`, and we inject the
+ // "this" parameter, so there's no need to ask the user for it.
+ //
+ // Note that constructors in Clang are represented as functions with
+ // return-type = void.
+ if self.is_constructor() {
+ args.remove(0);
+ ret = quote! { -> Self };
+ }
+
+ let mut exprs =
+ helpers::ast_ty::arguments_from_signature(signature, ctx);
+
+ let mut stmts = vec![];
+
+ // If it's a constructor, we need to insert an extra parameter with a
+ // variable called `__bindgen_tmp` we're going to create.
+ if self.is_constructor() {
+ let prefix = ctx.trait_prefix();
+ let tmp_variable_decl = if ctx
+ .options()
+ .rust_features()
+ .maybe_uninit
+ {
+ exprs[0] = quote! {
+ __bindgen_tmp.as_mut_ptr()
+ };
+ quote! {
+ let mut __bindgen_tmp = ::#prefix::mem::MaybeUninit::uninit()
+ }
+ } else {
+ exprs[0] = quote! {
+ &mut __bindgen_tmp
+ };
+ quote! {
+ let mut __bindgen_tmp = ::#prefix::mem::uninitialized()
+ }
+ };
+ stmts.push(tmp_variable_decl);
+ } else if !self.is_static() {
+ assert!(!exprs.is_empty());
+ exprs[0] = quote! {
+ self
+ };
+ };
+
+ let call = quote! {
+ #function_name (#( #exprs ),* )
+ };
+
+ stmts.push(call);
+
+ if self.is_constructor() {
+ stmts.push(if ctx.options().rust_features().maybe_uninit {
+ quote! {
+ __bindgen_tmp.assume_init()
+ }
+ } else {
+ quote! {
+ __bindgen_tmp
+ }
+ })
+ }
+
+ let block = ctx.wrap_unsafe_ops(quote! ( #( #stmts );*));
+
+ let mut attrs = vec![attributes::inline()];
+
+ if signature.must_use() &&
+ ctx.options().rust_features().must_use_function
+ {
+ attrs.push(attributes::must_use());
+ }
+
+ let name = ctx.rust_ident(&name);
+ methods.push(quote! {
+ #(#attrs)*
+ pub unsafe fn #name ( #( #args ),* ) #ret {
+ #block
+ }
+ });
+ }
+}
+
+/// A helper type that represents different enum variations.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum EnumVariation {
+ /// The code for this enum will use a Rust enum. Note that creating this in unsafe code
+ /// (including FFI) with an invalid value will invoke undefined behaviour, whether or not
+ /// its marked as non_exhaustive.
+ Rust {
+ /// Indicates whether the generated struct should be `#[non_exhaustive]`
+ non_exhaustive: bool,
+ },
+ /// The code for this enum will use a newtype
+ NewType {
+ /// Indicates whether the newtype will have bitwise operators
+ is_bitfield: bool,
+ /// Indicates whether the variants will be represented as global constants
+ is_global: bool,
+ },
+ /// The code for this enum will use consts
+ Consts,
+ /// The code for this enum will use a module containing consts
+ ModuleConsts,
+}
+
+impl EnumVariation {
+ fn is_rust(&self) -> bool {
+ matches!(*self, EnumVariation::Rust { .. })
+ }
+
+ /// Both the `Const` and `ModuleConsts` variants will cause this to return
+ /// true.
+ fn is_const(&self) -> bool {
+ matches!(*self, EnumVariation::Consts | EnumVariation::ModuleConsts)
+ }
+}
+
+impl Default for EnumVariation {
+ fn default() -> EnumVariation {
+ EnumVariation::Consts
+ }
+}
+
+impl fmt::Display for EnumVariation {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let s = match self {
+ Self::Rust {
+ non_exhaustive: false,
+ } => "rust",
+ Self::Rust {
+ non_exhaustive: true,
+ } => "rust_non_exhaustive",
+ Self::NewType {
+ is_bitfield: true, ..
+ } => "bitfield",
+ Self::NewType {
+ is_bitfield: false,
+ is_global,
+ } => {
+ if *is_global {
+ "newtype_global"
+ } else {
+ "newtype"
+ }
+ }
+ Self::Consts => "consts",
+ Self::ModuleConsts => "moduleconsts",
+ };
+ s.fmt(f)
+ }
+}
+
+impl std::str::FromStr for EnumVariation {
+ type Err = std::io::Error;
+
+ /// Create a `EnumVariation` from a string.
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "rust" => Ok(EnumVariation::Rust {
+ non_exhaustive: false,
+ }),
+ "rust_non_exhaustive" => Ok(EnumVariation::Rust {
+ non_exhaustive: true,
+ }),
+ "bitfield" => Ok(EnumVariation::NewType {
+ is_bitfield: true,
+ is_global: false,
+ }),
+ "consts" => Ok(EnumVariation::Consts),
+ "moduleconsts" => Ok(EnumVariation::ModuleConsts),
+ "newtype" => Ok(EnumVariation::NewType {
+ is_bitfield: false,
+ is_global: false,
+ }),
+ "newtype_global" => Ok(EnumVariation::NewType {
+ is_bitfield: false,
+ is_global: true,
+ }),
+ _ => Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidInput,
+ concat!(
+ "Got an invalid EnumVariation. Accepted values ",
+ "are 'rust', 'rust_non_exhaustive', 'bitfield', 'consts',",
+ "'moduleconsts', 'newtype' and 'newtype_global'."
+ ),
+ )),
+ }
+ }
+}
+
+/// A helper type to construct different enum variations.
+enum EnumBuilder<'a> {
+ Rust {
+ attrs: Vec<proc_macro2::TokenStream>,
+ ident: Ident,
+ tokens: proc_macro2::TokenStream,
+ emitted_any_variants: bool,
+ },
+ NewType {
+ canonical_name: &'a str,
+ tokens: proc_macro2::TokenStream,
+ is_bitfield: bool,
+ is_global: bool,
+ },
+ Consts {
+ variants: Vec<proc_macro2::TokenStream>,
+ },
+ ModuleConsts {
+ module_name: &'a str,
+ module_items: Vec<proc_macro2::TokenStream>,
+ },
+}
+
+impl<'a> EnumBuilder<'a> {
+ /// Returns true if the builder is for a rustified enum.
+ fn is_rust_enum(&self) -> bool {
+ matches!(*self, EnumBuilder::Rust { .. })
+ }
+
+ /// Create a new enum given an item builder, a canonical name, a name for
+ /// the representation, and which variation it should be generated as.
+ fn new(
+ name: &'a str,
+ mut attrs: Vec<proc_macro2::TokenStream>,
+ repr: syn::Type,
+ enum_variation: EnumVariation,
+ has_typedef: bool,
+ ) -> Self {
+ let ident = Ident::new(name, Span::call_site());
+
+ match enum_variation {
+ EnumVariation::NewType {
+ is_bitfield,
+ is_global,
+ } => EnumBuilder::NewType {
+ canonical_name: name,
+ tokens: quote! {
+ #( #attrs )*
+ pub struct #ident (pub #repr);
+ },
+ is_bitfield,
+ is_global,
+ },
+
+ EnumVariation::Rust { .. } => {
+ // `repr` is guaranteed to be Rustified in Enum::codegen
+ attrs.insert(0, quote! { #[repr( #repr )] });
+ let tokens = quote!();
+ EnumBuilder::Rust {
+ attrs,
+ ident,
+ tokens,
+ emitted_any_variants: false,
+ }
+ }
+
+ EnumVariation::Consts => {
+ let mut variants = Vec::new();
+
+ if !has_typedef {
+ variants.push(quote! {
+ #( #attrs )*
+ pub type #ident = #repr;
+ });
+ }
+
+ EnumBuilder::Consts { variants }
+ }
+
+ EnumVariation::ModuleConsts => {
+ let ident = Ident::new(
+ CONSTIFIED_ENUM_MODULE_REPR_NAME,
+ Span::call_site(),
+ );
+ let type_definition = quote! {
+ #( #attrs )*
+ pub type #ident = #repr;
+ };
+
+ EnumBuilder::ModuleConsts {
+ module_name: name,
+ module_items: vec![type_definition],
+ }
+ }
+ }
+ }
+
+ /// Add a variant to this enum.
+ fn with_variant(
+ self,
+ ctx: &BindgenContext,
+ variant: &EnumVariant,
+ mangling_prefix: Option<&str>,
+ rust_ty: syn::Type,
+ result: &mut CodegenResult<'_>,
+ is_ty_named: bool,
+ ) -> Self {
+ let variant_name = ctx.rust_mangle(variant.name());
+ let is_rust_enum = self.is_rust_enum();
+ let expr = match variant.val() {
+ EnumVariantValue::Boolean(v) if is_rust_enum => {
+ helpers::ast_ty::uint_expr(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 = ctx.options().process_comment(raw_comment);
+ doc = attributes::doc(comment);
+ }
+ }
+
+ match self {
+ EnumBuilder::Rust {
+ attrs,
+ ident,
+ tokens,
+ emitted_any_variants: _,
+ } => {
+ let name = ctx.rust_ident(variant_name);
+ EnumBuilder::Rust {
+ attrs,
+ ident,
+ tokens: quote! {
+ #tokens
+ #doc
+ #name = #expr,
+ },
+ emitted_any_variants: true,
+ }
+ }
+
+ EnumBuilder::NewType {
+ canonical_name,
+ is_global,
+ ..
+ } => {
+ if ctx.options().rust_features().associated_const &&
+ is_ty_named &&
+ !is_global
+ {
+ let enum_ident = ctx.rust_ident(canonical_name);
+ let variant_ident = ctx.rust_ident(variant_name);
+
+ result.push(quote! {
+ impl #enum_ident {
+ #doc
+ pub const #variant_ident : #rust_ty = #rust_ty ( #expr );
+ }
+ });
+ } else {
+ let ident = ctx.rust_ident(match mangling_prefix {
+ Some(prefix) => {
+ Cow::Owned(format!("{}_{}", prefix, variant_name))
+ }
+ None => variant_name,
+ });
+ result.push(quote! {
+ #doc
+ pub const #ident : #rust_ty = #rust_ty ( #expr );
+ });
+ }
+
+ self
+ }
+
+ EnumBuilder::Consts { .. } => {
+ let constant_name = match mangling_prefix {
+ Some(prefix) => {
+ Cow::Owned(format!("{}_{}", prefix, variant_name))
+ }
+ None => variant_name,
+ };
+
+ let ident = ctx.rust_ident(constant_name);
+ result.push(quote! {
+ #doc
+ pub const #ident : #rust_ty = #expr ;
+ });
+
+ self
+ }
+ EnumBuilder::ModuleConsts {
+ module_name,
+ mut module_items,
+ } => {
+ let name = ctx.rust_ident(variant_name);
+ let ty = ctx.rust_ident(CONSTIFIED_ENUM_MODULE_REPR_NAME);
+ module_items.push(quote! {
+ #doc
+ pub const #name : #ty = #expr ;
+ });
+
+ EnumBuilder::ModuleConsts {
+ module_name,
+ module_items,
+ }
+ }
+ }
+ }
+
+ fn build(
+ self,
+ ctx: &BindgenContext,
+ rust_ty: syn::Type,
+ result: &mut CodegenResult<'_>,
+ ) -> proc_macro2::TokenStream {
+ match self {
+ EnumBuilder::Rust {
+ attrs,
+ ident,
+ tokens,
+ emitted_any_variants,
+ ..
+ } => {
+ let variants = if !emitted_any_variants {
+ 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(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'_>,
+ item: &Item,
+ ) {
+ debug!("<Enum as CodeGenerator>::codegen: item = {:?}", item);
+ debug_assert!(item.is_enabled_for_codegen(ctx));
+
+ let name = item.canonical_name(ctx);
+ let ident = ctx.rust_ident(&name);
+ let enum_ty = item.expect_type();
+ let layout = enum_ty.layout(ctx);
+ let variation = self.computed_enum_variation(ctx, item);
+
+ let repr_translated;
+ let repr = match self.repr().map(|repr| ctx.resolve_type(repr)) {
+ Some(repr)
+ if !ctx.options().translate_enum_integer_types &&
+ !variation.is_rust() =>
+ {
+ repr
+ }
+ repr => {
+ // An enum's integer type is translated to a native Rust
+ // integer type in 3 cases:
+ // * the enum is Rustified and we need a translated type for
+ // the repr attribute
+ // * the representation couldn't be determined from the C source
+ // * it was explicitly requested as a bindgen option
+
+ let kind = match repr {
+ Some(repr) => match *repr.canonical_type(ctx).kind() {
+ TypeKind::Int(int_kind) => int_kind,
+ _ => panic!("Unexpected type as enum repr"),
+ },
+ None => {
+ warn!(
+ "Guessing type of enum! Forward declarations of enums \
+ shouldn't be legal!"
+ );
+ IntKind::Int
+ }
+ };
+
+ let signed = kind.is_signed();
+ let size = layout
+ .map(|l| l.size)
+ .or_else(|| kind.known_size())
+ .unwrap_or(0);
+
+ let translated = match (signed, size) {
+ (true, 1) => IntKind::I8,
+ (false, 1) => IntKind::U8,
+ (true, 2) => IntKind::I16,
+ (false, 2) => IntKind::U16,
+ (true, 4) => IntKind::I32,
+ (false, 4) => IntKind::U32,
+ (true, 8) => IntKind::I64,
+ (false, 8) => IntKind::U64,
+ _ => {
+ warn!(
+ "invalid enum decl: signed: {}, size: {}",
+ signed, size
+ );
+ IntKind::I32
+ }
+ };
+
+ repr_translated =
+ Type::new(None, None, TypeKind::Int(translated), false);
+ &repr_translated
+ }
+ };
+
+ let mut attrs = vec![];
+
+ // TODO(emilio): Delegate this to the builders?
+ match variation {
+ EnumVariation::Rust { non_exhaustive } => {
+ if non_exhaustive &&
+ ctx.options().rust_features().non_exhaustive
+ {
+ attrs.push(attributes::non_exhaustive());
+ } else if non_exhaustive &&
+ !ctx.options().rust_features().non_exhaustive
+ {
+ panic!("The rust target you're using doesn't seem to support non_exhaustive enums");
+ }
+ }
+ EnumVariation::NewType { .. } => {
+ if ctx.options().rust_features.repr_transparent {
+ attrs.push(attributes::repr("transparent"));
+ } else {
+ attrs.push(attributes::repr("C"));
+ }
+ }
+ _ => {}
+ };
+
+ if let Some(comment) = item.comment(ctx) {
+ attrs.push(attributes::doc(comment));
+ }
+
+ if item.must_use(ctx) {
+ attrs.push(attributes::must_use());
+ }
+
+ if !variation.is_const() {
+ let packed = false; // Enums can't be packed in Rust.
+ let mut derives = derives_of_item(item, ctx, packed);
+ // For backwards compat, enums always derive
+ // Clone/Eq/PartialEq/Hash, even if we don't generate those by
+ // default.
+ derives.insert(
+ DerivableTraits::CLONE |
+ DerivableTraits::HASH |
+ DerivableTraits::PARTIAL_EQ |
+ DerivableTraits::EQ,
+ );
+ let mut derives: Vec<_> = derives.into();
+ for derive in item.annotations().derives().iter() {
+ if !derives.contains(&derive.as_str()) {
+ derives.push(derive);
+ }
+ }
+
+ // The custom derives callback may return a list of derive attributes;
+ // add them to the end of the list.
+ let custom_derives = ctx.options().all_callbacks(|cb| {
+ cb.add_derives(&DeriveInfo {
+ name: &name,
+ kind: DeriveTypeKind::Enum,
+ })
+ });
+ // In most cases this will be a no-op, since custom_derives will be empty.
+ derives.extend(custom_derives.iter().map(|s| s.as_str()));
+
+ attrs.push(attributes::derives(&derives));
+ }
+
+ fn add_constant(
+ ctx: &BindgenContext,
+ enum_: &Type,
+ // Only to avoid recomputing every time.
+ enum_canonical_name: &Ident,
+ // May be the same as "variant" if it's because the
+ // enum is unnamed and we still haven't seen the
+ // value.
+ variant_name: &Ident,
+ referenced_name: &Ident,
+ enum_rust_ty: syn::Type,
+ result: &mut CodegenResult<'_>,
+ ) {
+ let constant_name = if enum_.name().is_some() {
+ if ctx.options().prepend_enum_name {
+ format!("{}_{}", enum_canonical_name, variant_name)
+ } else {
+ format!("{}", variant_name)
+ }
+ } else {
+ format!("{}", variant_name)
+ };
+ let constant_name = ctx.rust_ident(constant_name);
+
+ result.push(quote! {
+ pub const #constant_name : #enum_rust_ty =
+ #enum_canonical_name :: #referenced_name ;
+ });
+ }
+
+ let repr = repr.to_rust_ty_or_opaque(ctx, item);
+ let has_typedef = ctx.is_enum_typedef_combo(item.id());
+
+ let mut builder =
+ EnumBuilder::new(&name, attrs, repr, variation, has_typedef);
+
+ // A map where we keep a value -> variant relation.
+ let mut seen_values = HashMap::<_, Ident>::default();
+ let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &());
+ let is_toplevel = item.is_toplevel(ctx);
+
+ // Used to mangle the constants we generate in the unnamed-enum case.
+ let parent_canonical_name = if is_toplevel {
+ None
+ } else {
+ Some(item.parent_id().canonical_name(ctx))
+ };
+
+ let constant_mangling_prefix = if ctx.options().prepend_enum_name {
+ if enum_ty.name().is_none() {
+ parent_canonical_name.as_deref()
+ } else {
+ Some(&*name)
+ }
+ } else {
+ None
+ };
+
+ // NB: We defer the creation of constified variants, in case we find
+ // another variant with the same value (which is the common thing to
+ // do).
+ let mut constified_variants = VecDeque::new();
+
+ let mut iter = self.variants().iter().peekable();
+ while let Some(variant) =
+ iter.next().or_else(|| constified_variants.pop_front())
+ {
+ if variant.hidden() {
+ continue;
+ }
+
+ if variant.force_constification() && iter.peek().is_some() {
+ constified_variants.push_back(variant);
+ continue;
+ }
+
+ match seen_values.entry(variant.val()) {
+ Entry::Occupied(ref entry) => {
+ if variation.is_rust() {
+ let variant_name = ctx.rust_mangle(variant.name());
+ let mangled_name =
+ if is_toplevel || enum_ty.name().is_some() {
+ variant_name
+ } else {
+ let parent_name =
+ parent_canonical_name.as_ref().unwrap();
+
+ Cow::Owned(format!(
+ "{}_{}",
+ parent_name, variant_name
+ ))
+ };
+
+ let existing_variant_name = entry.get();
+ // Use associated constants for named enums.
+ if enum_ty.name().is_some() &&
+ ctx.options().rust_features().associated_const
+ {
+ let enum_canonical_name = &ident;
+ let variant_name =
+ ctx.rust_ident_raw(&*mangled_name);
+ result.push(quote! {
+ impl #enum_rust_ty {
+ pub const #variant_name : #enum_rust_ty =
+ #enum_canonical_name :: #existing_variant_name ;
+ }
+ });
+ } else {
+ add_constant(
+ ctx,
+ enum_ty,
+ &ident,
+ &Ident::new(&mangled_name, Span::call_site()),
+ existing_variant_name,
+ enum_rust_ty.clone(),
+ result,
+ );
+ }
+ } else {
+ builder = builder.with_variant(
+ ctx,
+ variant,
+ constant_mangling_prefix,
+ enum_rust_ty.clone(),
+ result,
+ enum_ty.name().is_some(),
+ );
+ }
+ }
+ Entry::Vacant(entry) => {
+ builder = builder.with_variant(
+ ctx,
+ variant,
+ constant_mangling_prefix,
+ enum_rust_ty.clone(),
+ result,
+ enum_ty.name().is_some(),
+ );
+
+ let variant_name = ctx.rust_ident(variant.name());
+
+ // If it's an unnamed enum, or constification is enforced,
+ // we also generate a constant so it can be properly
+ // accessed.
+ if (variation.is_rust() && enum_ty.name().is_none()) ||
+ variant.force_constification()
+ {
+ let mangled_name = if is_toplevel {
+ variant_name.clone()
+ } else {
+ let parent_name =
+ parent_canonical_name.as_ref().unwrap();
+
+ Ident::new(
+ &format!("{}_{}", parent_name, variant_name),
+ Span::call_site(),
+ )
+ };
+
+ add_constant(
+ ctx,
+ enum_ty,
+ &ident,
+ &mangled_name,
+ &variant_name,
+ enum_rust_ty.clone(),
+ result,
+ );
+ }
+
+ entry.insert(variant_name);
+ }
+ }
+ }
+
+ let item = builder.build(ctx, enum_rust_ty, result);
+ result.push(item);
+ }
+}
+
+/// Enum for the default type of macro constants.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum MacroTypeVariation {
+ /// Use i32 or i64
+ Signed,
+ /// Use u32 or u64
+ Unsigned,
+}
+
+impl fmt::Display for MacroTypeVariation {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let s = match self {
+ Self::Signed => "signed",
+ Self::Unsigned => "unsigned",
+ };
+ s.fmt(f)
+ }
+}
+
+impl Default for MacroTypeVariation {
+ fn default() -> MacroTypeVariation {
+ MacroTypeVariation::Unsigned
+ }
+}
+
+impl std::str::FromStr for MacroTypeVariation {
+ type Err = std::io::Error;
+
+ /// Create a `MacroTypeVariation` from a string.
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "signed" => Ok(MacroTypeVariation::Signed),
+ "unsigned" => Ok(MacroTypeVariation::Unsigned),
+ _ => Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidInput,
+ concat!(
+ "Got an invalid MacroTypeVariation. Accepted values ",
+ "are 'signed' and 'unsigned'"
+ ),
+ )),
+ }
+ }
+}
+
+/// Enum for how aliases should be translated.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum AliasVariation {
+ /// Convert to regular Rust alias
+ TypeAlias,
+ /// Create a new type by wrapping the old type in a struct and using #[repr(transparent)]
+ NewType,
+ /// Same as NewStruct but also impl Deref to be able to use the methods of the wrapped type
+ NewTypeDeref,
+}
+
+impl fmt::Display for AliasVariation {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let s = match self {
+ Self::TypeAlias => "type_alias",
+ Self::NewType => "new_type",
+ Self::NewTypeDeref => "new_type_deref",
+ };
+
+ s.fmt(f)
+ }
+}
+
+impl Default for AliasVariation {
+ fn default() -> AliasVariation {
+ AliasVariation::TypeAlias
+ }
+}
+
+impl std::str::FromStr for AliasVariation {
+ type Err = std::io::Error;
+
+ /// Create an `AliasVariation` from a string.
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "type_alias" => Ok(AliasVariation::TypeAlias),
+ "new_type" => Ok(AliasVariation::NewType),
+ "new_type_deref" => Ok(AliasVariation::NewTypeDeref),
+ _ => Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidInput,
+ concat!(
+ "Got an invalid AliasVariation. Accepted values ",
+ "are 'type_alias', 'new_type', and 'new_type_deref'"
+ ),
+ )),
+ }
+ }
+}
+
+/// Enum for how non-`Copy` `union`s should be translated.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum NonCopyUnionStyle {
+ /// Wrap members in a type generated by `bindgen`.
+ BindgenWrapper,
+ /// Wrap members in [`::core::mem::ManuallyDrop`].
+ ///
+ /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your
+ /// MSRV is lower.
+ ManuallyDrop,
+}
+
+impl fmt::Display for NonCopyUnionStyle {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let s = match self {
+ Self::BindgenWrapper => "bindgen_wrapper",
+ Self::ManuallyDrop => "manually_drop",
+ };
+
+ s.fmt(f)
+ }
+}
+
+impl Default for NonCopyUnionStyle {
+ fn default() -> Self {
+ Self::BindgenWrapper
+ }
+}
+
+impl std::str::FromStr for NonCopyUnionStyle {
+ type Err = std::io::Error;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "bindgen_wrapper" => Ok(Self::BindgenWrapper),
+ "manually_drop" => Ok(Self::ManuallyDrop),
+ _ => Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidInput,
+ concat!(
+ "Got an invalid NonCopyUnionStyle. Accepted values ",
+ "are 'bindgen_wrapper' and 'manually_drop'"
+ ),
+ )),
+ }
+ }
+}
+
+/// Fallible conversion to an opaque blob.
+///
+/// Implementors of this trait should provide the `try_get_layout` method to
+/// fallibly get this thing's layout, which the provided `try_to_opaque` trait
+/// method will use to convert the `Layout` into an opaque blob Rust type.
+pub(crate) trait TryToOpaque {
+ type Extra;
+
+ /// Get the layout for this thing, if one is available.
+ fn try_get_layout(
+ &self,
+ ctx: &BindgenContext,
+ extra: &Self::Extra,
+ ) -> error::Result<Layout>;
+
+ /// Do not override this provided trait method.
+ fn try_to_opaque(
+ &self,
+ ctx: &BindgenContext,
+ extra: &Self::Extra,
+ ) -> error::Result<syn::Type> {
+ 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.
+pub(crate) trait ToOpaque: TryToOpaque {
+ fn get_layout(&self, ctx: &BindgenContext, extra: &Self::Extra) -> Layout {
+ self.try_get_layout(ctx, extra)
+ .unwrap_or_else(|_| Layout::for_size(ctx, 1))
+ }
+
+ fn to_opaque(
+ &self,
+ ctx: &BindgenContext,
+ extra: &Self::Extra,
+ ) -> syn::Type {
+ let layout = self.get_layout(ctx, extra);
+ helpers::blob(ctx, layout)
+ }
+}
+
+impl<T> ToOpaque for T where T: TryToOpaque {}
+
+/// Fallible conversion from an IR thing to an *equivalent* Rust type.
+///
+/// If the C/C++ construct represented by the IR thing cannot (currently) be
+/// represented in Rust (for example, instantiations of templates with
+/// const-value generic parameters) then the impl should return an `Err`. It
+/// should *not* attempt to return an opaque blob with the correct size and
+/// alignment. That is the responsibility of the `TryToOpaque` trait.
+pub(crate) trait TryToRustTy {
+ type Extra;
+
+ fn try_to_rust_ty(
+ &self,
+ ctx: &BindgenContext,
+ extra: &Self::Extra,
+ ) -> error::Result<syn::Type>;
+}
+
+/// Fallible conversion to a Rust type or an opaque blob with the correct size
+/// and alignment.
+///
+/// Don't implement this directly. Instead implement `TryToRustTy` and
+/// `TryToOpaque`, and then leverage the blanket impl for this trait below.
+pub(crate) trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque {
+ type Extra;
+
+ fn try_to_rust_ty_or_opaque(
+ &self,
+ ctx: &BindgenContext,
+ extra: &<Self as TryToRustTyOrOpaque>::Extra,
+ ) -> error::Result<syn::Type>;
+}
+
+impl<E, T> TryToRustTyOrOpaque for T
+where
+ T: TryToRustTy<Extra = E> + TryToOpaque<Extra = E>,
+{
+ type Extra = E;
+
+ fn try_to_rust_ty_or_opaque(
+ &self,
+ ctx: &BindgenContext,
+ extra: &E,
+ ) -> error::Result<syn::Type> {
+ 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.
+pub(crate) trait ToRustTyOrOpaque: TryToRustTy + ToOpaque {
+ type Extra;
+
+ fn to_rust_ty_or_opaque(
+ &self,
+ ctx: &BindgenContext,
+ extra: &<Self as ToRustTyOrOpaque>::Extra,
+ ) -> syn::Type;
+}
+
+impl<E, T> ToRustTyOrOpaque for T
+where
+ T: TryToRustTy<Extra = E> + ToOpaque<Extra = E>,
+{
+ type Extra = E;
+
+ fn to_rust_ty_or_opaque(
+ &self,
+ ctx: &BindgenContext,
+ extra: &E,
+ ) -> syn::Type {
+ self.try_to_rust_ty(ctx, extra)
+ .unwrap_or_else(|_| self.to_opaque(ctx, extra))
+ }
+}
+
+impl<T> TryToOpaque for T
+where
+ T: Copy + Into<ItemId>,
+{
+ type Extra = ();
+
+ fn try_get_layout(
+ &self,
+ ctx: &BindgenContext,
+ _: &(),
+ ) -> error::Result<Layout> {
+ ctx.resolve_item((*self).into()).try_get_layout(ctx, &())
+ }
+}
+
+impl<T> TryToRustTy for T
+where
+ T: Copy + Into<ItemId>,
+{
+ type Extra = ();
+
+ fn try_to_rust_ty(
+ &self,
+ ctx: &BindgenContext,
+ _: &(),
+ ) -> error::Result<syn::Type> {
+ ctx.resolve_item((*self).into()).try_to_rust_ty(ctx, &())
+ }
+}
+
+impl TryToOpaque for Item {
+ type Extra = ();
+
+ fn try_get_layout(
+ &self,
+ ctx: &BindgenContext,
+ _: &(),
+ ) -> error::Result<Layout> {
+ self.kind().expect_type().try_get_layout(ctx, self)
+ }
+}
+
+impl TryToRustTy for Item {
+ type Extra = ();
+
+ fn try_to_rust_ty(
+ &self,
+ ctx: &BindgenContext,
+ _: &(),
+ ) -> error::Result<syn::Type> {
+ self.kind().expect_type().try_to_rust_ty(ctx, self)
+ }
+}
+
+impl TryToOpaque for Type {
+ type Extra = Item;
+
+ fn try_get_layout(
+ &self,
+ ctx: &BindgenContext,
+ _: &Item,
+ ) -> error::Result<Layout> {
+ self.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob)
+ }
+}
+
+impl TryToRustTy for Type {
+ type Extra = Item;
+
+ fn try_to_rust_ty(
+ &self,
+ ctx: &BindgenContext,
+ item: &Item,
+ ) -> error::Result<syn::Type> {
+ use self::helpers::ast_ty::*;
+
+ match *self.kind() {
+ TypeKind::Void => Ok(c_void(ctx)),
+ // TODO: we should do something smart with nullptr, or maybe *const
+ // c_void is enough?
+ TypeKind::NullPtr => Ok(c_void(ctx).to_ptr(true)),
+ TypeKind::Int(ik) => {
+ Ok(int_kind_rust_type(ctx, ik, self.layout(ctx)))
+ }
+ TypeKind::Float(fk) => {
+ Ok(float_kind_rust_type(ctx, fk, self.layout(ctx)))
+ }
+ TypeKind::Complex(fk) => {
+ let float_path =
+ float_kind_rust_type(ctx, fk, self.layout(ctx));
+
+ ctx.generated_bindgen_complex();
+ Ok(if ctx.options().enable_cxx_namespaces {
+ syn::parse_quote! { root::__BindgenComplex<#float_path> }
+ } else {
+ syn::parse_quote! { __BindgenComplex<#float_path> }
+ })
+ }
+ TypeKind::Function(ref signature) => {
+ // We can't rely on the sizeof(Option<NonZero<_>>) ==
+ // sizeof(NonZero<_>) optimization with opaque blobs (because
+ // they aren't NonZero), so don't *ever* use an or_opaque
+ // variant here.
+ let ty = signature.try_to_rust_ty(ctx, item)?;
+
+ let prefix = ctx.trait_prefix();
+ Ok(syn::parse_quote! { ::#prefix::option::Option<#ty> })
+ }
+ TypeKind::Array(item, len) | TypeKind::Vector(item, len) => {
+ let ty = item.try_to_rust_ty(ctx, &())?;
+ Ok(syn::parse_quote! { [ #ty ; #len ] })
+ }
+ TypeKind::Enum(..) => {
+ let path = item.namespace_aware_canonical_path(ctx);
+ let path = proc_macro2::TokenStream::from_str(&path.join("::"))
+ .unwrap();
+ Ok(syn::parse_quote!(#path))
+ }
+ TypeKind::TemplateInstantiation(ref inst) => {
+ inst.try_to_rust_ty(ctx, item)
+ }
+ TypeKind::ResolvedTypeRef(inner) => inner.try_to_rust_ty(ctx, &()),
+ TypeKind::TemplateAlias(..) |
+ TypeKind::Alias(..) |
+ TypeKind::BlockPointer(..) => {
+ if self.is_block_pointer() && !ctx.options().generate_block {
+ let void = c_void(ctx);
+ return Ok(void.to_ptr(/* is_const = */ false));
+ }
+
+ if item.is_opaque(ctx, &()) &&
+ item.used_template_params(ctx)
+ .into_iter()
+ .any(|param| param.is_template_param(ctx, &()))
+ {
+ self.try_to_opaque(ctx, item)
+ } else if let Some(ty) = self
+ .name()
+ .and_then(|name| utils::type_from_named(ctx, name))
+ {
+ Ok(ty)
+ } else {
+ utils::build_path(item, ctx)
+ }
+ }
+ TypeKind::Comp(ref info) => {
+ let template_params = item.all_template_params(ctx);
+ if info.has_non_type_template_params() ||
+ (item.is_opaque(ctx, &()) && !template_params.is_empty())
+ {
+ return self.try_to_opaque(ctx, item);
+ }
+
+ utils::build_path(item, ctx)
+ }
+ TypeKind::Opaque => self.try_to_opaque(ctx, item),
+ TypeKind::Pointer(inner) | TypeKind::Reference(inner) => {
+ // Check that this type has the same size as the target's pointer type.
+ let size = self.get_layout(ctx, item).size;
+ if size != ctx.target_pointer_size() {
+ return Err(Error::InvalidPointerSize {
+ ty_name: self.name().unwrap_or("unknown").into(),
+ ty_size: size,
+ ptr_size: ctx.target_pointer_size(),
+ });
+ }
+
+ let is_const = ctx.resolve_type(inner).is_const();
+
+ let inner =
+ inner.into_resolver().through_type_refs().resolve(ctx);
+ let inner_ty = inner.expect_type();
+
+ let is_objc_pointer =
+ matches!(inner_ty.kind(), TypeKind::ObjCInterface(..));
+
+ // Regardless if we can properly represent the inner type, we
+ // should always generate a proper pointer here, so use
+ // infallible conversion of the inner type.
+ let ty = inner
+ .to_rust_ty_or_opaque(ctx, &())
+ .with_implicit_template_params(ctx, inner);
+
+ // Avoid the first function pointer level, since it's already
+ // represented in Rust.
+ if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer
+ {
+ Ok(ty)
+ } else {
+ Ok(ty.to_ptr(is_const))
+ }
+ }
+ TypeKind::TypeParam => {
+ let name = item.canonical_name(ctx);
+ let ident = ctx.rust_ident(name);
+ Ok(syn::parse_quote! { #ident })
+ }
+ TypeKind::ObjCSel => Ok(syn::parse_quote! { objc::runtime::Sel }),
+ TypeKind::ObjCId => Ok(syn::parse_quote! { id }),
+ TypeKind::ObjCInterface(ref interface) => {
+ let name = ctx.rust_ident(interface.name());
+ Ok(syn::parse_quote! { #name })
+ }
+ ref u @ TypeKind::UnresolvedTypeRef(..) => {
+ unreachable!("Should have been resolved after parsing {:?}!", u)
+ }
+ }
+ }
+}
+
+impl TryToOpaque for TemplateInstantiation {
+ type Extra = Item;
+
+ fn try_get_layout(
+ &self,
+ ctx: &BindgenContext,
+ item: &Item,
+ ) -> error::Result<Layout> {
+ item.expect_type()
+ .layout(ctx)
+ .ok_or(error::Error::NoLayoutForOpaqueBlob)
+ }
+}
+
+impl TryToRustTy for TemplateInstantiation {
+ type Extra = Item;
+
+ fn try_to_rust_ty(
+ &self,
+ ctx: &BindgenContext,
+ item: &Item,
+ ) -> error::Result<syn::Type> {
+ 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 ty = arg
+ .try_to_rust_ty(ctx, &())?
+ .with_implicit_template_params(ctx, arg);
+ Ok(ty)
+ })
+ .collect::<error::Result<Vec<_>>>()?;
+
+ Ok(if template_args.is_empty() {
+ syn::parse_quote! { #ty }
+ } else {
+ syn::parse_quote! { #ty<#(#template_args),*> }
+ })
+ }
+}
+
+impl TryToRustTy for FunctionSig {
+ type Extra = Item;
+
+ fn try_to_rust_ty(
+ &self,
+ ctx: &BindgenContext,
+ item: &Item,
+ ) -> error::Result<syn::Type> {
+ // TODO: we might want to consider ignoring the reference return value.
+ let ret = utils::fnsig_return_ty(ctx, self);
+ let arguments = utils::fnsig_arguments(ctx, self);
+
+ match self.abi(ctx, None) {
+ Ok(abi) => Ok(
+ syn::parse_quote! { unsafe extern #abi fn ( #( #arguments ),* ) #ret },
+ ),
+ Err(err) => {
+ if matches!(err, error::Error::UnsupportedAbi(_)) {
+ unsupported_abi_diagnostic(
+ self.name(),
+ self.is_variadic(),
+ item.location(),
+ ctx,
+ &err,
+ );
+ }
+
+ Err(err)
+ }
+ }
+ }
+}
+
+impl CodeGenerator for Function {
+ type Extra = Item;
+
+ /// If we've actually generated the symbol, the number of times we've seen
+ /// it.
+ type Return = Option<u32>;
+
+ fn codegen(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'_>,
+ item: &Item,
+ ) -> Self::Return {
+ debug!("<Function as CodeGenerator>::codegen: item = {:?}", item);
+ debug_assert!(item.is_enabled_for_codegen(ctx));
+
+ let is_internal = matches!(self.linkage(), Linkage::Internal);
+
+ let signature_item = ctx.resolve_item(self.signature());
+ let signature = signature_item.kind().expect_type().canonical_type(ctx);
+ let signature = match *signature.kind() {
+ TypeKind::Function(ref sig) => sig,
+ _ => panic!("Signature kind is not a Function: {:?}", signature),
+ };
+
+ if is_internal {
+ if !ctx.options().wrap_static_fns {
+ // We cannot do anything with internal functions if we are not wrapping them so
+ // just avoid generating anything for them.
+ return None;
+ }
+
+ if signature.is_variadic() {
+ // We cannot generate wrappers for variadic static functions so we avoid
+ // generating any code for them.
+ variadic_fn_diagnostic(self.name(), item.location(), ctx);
+ return None;
+ }
+ }
+
+ // Pure virtual methods have no actual symbol, so we can't generate
+ // something meaningful for them.
+ let is_dynamic_function = match self.kind() {
+ FunctionKind::Method(ref method_kind)
+ if method_kind.is_pure_virtual() =>
+ {
+ return None;
+ }
+ FunctionKind::Function => {
+ ctx.options().dynamic_library_name.is_some()
+ }
+ _ => false,
+ };
+
+ // Similar to static member variables in a class template, we can't
+ // generate bindings to template functions, because the set of
+ // instantiations is open ended and we have no way of knowing which
+ // monomorphizations actually exist.
+ if !item.all_template_params(ctx).is_empty() {
+ return None;
+ }
+
+ let name = self.name();
+ let mut canonical_name = item.canonical_name(ctx);
+ let mangled_name = self.mangled_name();
+
+ {
+ let seen_symbol_name = mangled_name.unwrap_or(&canonical_name);
+
+ // TODO: Maybe warn here if there's a type/argument mismatch, or
+ // something?
+ if result.seen_function(seen_symbol_name) {
+ return None;
+ }
+ result.saw_function(seen_symbol_name);
+ }
+
+ let mut attributes = vec![];
+
+ if ctx.options().rust_features().must_use_function {
+ let must_use = signature.must_use() || {
+ let ret_ty = signature
+ .return_type()
+ .into_resolver()
+ .through_type_refs()
+ .resolve(ctx);
+ ret_ty.must_use(ctx)
+ };
+
+ if must_use {
+ attributes.push(attributes::must_use());
+ }
+ }
+
+ if let Some(comment) = item.comment(ctx) {
+ attributes.push(attributes::doc(comment));
+ }
+
+ let abi = match signature.abi(ctx, Some(name)) {
+ Err(err) => {
+ if matches!(err, error::Error::UnsupportedAbi(_)) {
+ unsupported_abi_diagnostic(
+ name,
+ signature.is_variadic(),
+ item.location(),
+ ctx,
+ &err,
+ );
+ }
+
+ return None;
+ }
+ Ok(ClangAbi::Unknown(unknown_abi)) => {
+ panic!(
+ "Invalid or unknown abi {:?} for function {:?} ({:?})",
+ unknown_abi, canonical_name, self
+ );
+ }
+ Ok(abi) => abi,
+ };
+
+ // Handle overloaded functions by giving each overload its own unique
+ // suffix.
+ let times_seen = result.overload_number(&canonical_name);
+ if times_seen > 0 {
+ write!(&mut canonical_name, "{}", times_seen).unwrap();
+ }
+
+ let mut has_link_name_attr = false;
+ if let Some(link_name) = self.link_name() {
+ attributes.push(attributes::link_name::<false>(link_name));
+ has_link_name_attr = true;
+ } else {
+ let link_name = mangled_name.unwrap_or(name);
+ if !is_dynamic_function &&
+ !utils::names_will_be_identical_after_mangling(
+ &canonical_name,
+ link_name,
+ Some(abi),
+ )
+ {
+ attributes.push(attributes::link_name::<false>(link_name));
+ has_link_name_attr = true;
+ }
+ }
+
+ // Unfortunately this can't piggyback on the `attributes` list because
+ // the #[link(wasm_import_module)] needs to happen before the `extern
+ // "C"` block. It doesn't get picked up properly otherwise
+ let wasm_link_attribute =
+ ctx.options().wasm_import_module_name.as_ref().map(|name| {
+ quote! { #[link(wasm_import_module = #name)] }
+ });
+
+ let should_wrap =
+ is_internal && ctx.options().wrap_static_fns && !has_link_name_attr;
+
+ if should_wrap {
+ let name = canonical_name.clone() + ctx.wrap_static_fns_suffix();
+ attributes.push(attributes::link_name::<true>(&name));
+ }
+
+ let wrap_as_variadic = if should_wrap && !signature.is_variadic() {
+ utils::wrap_as_variadic_fn(ctx, signature, name)
+ } else {
+ None
+ };
+
+ let (ident, args) = if let Some(WrapAsVariadic {
+ idx_of_va_list_arg,
+ new_name,
+ }) = &wrap_as_variadic
+ {
+ (
+ new_name,
+ utils::fnsig_arguments_iter(
+ ctx,
+ // Prune argument at index (idx_of_va_list_arg)
+ signature.argument_types().iter().enumerate().filter_map(
+ |(idx, t)| {
+ if idx == *idx_of_va_list_arg {
+ None
+ } else {
+ Some(t)
+ }
+ },
+ ),
+ // and replace it by a `...` (variadic symbol and the end of the signature)
+ true,
+ ),
+ )
+ } else {
+ (&canonical_name, utils::fnsig_arguments(ctx, signature))
+ };
+ let ret = utils::fnsig_return_ty(ctx, signature);
+
+ let ident = ctx.rust_ident(ident);
+ let tokens = quote! {
+ #wasm_link_attribute
+ extern #abi {
+ #(#attributes)*
+ pub fn #ident ( #( #args ),* ) #ret;
+ }
+ };
+
+ // Add the item to the serialization list if necessary
+ if should_wrap {
+ result
+ .items_to_serialize
+ .push((item.id(), wrap_as_variadic));
+ }
+
+ // If we're doing dynamic binding generation, add to the dynamic items.
+ if is_dynamic_function {
+ let args_identifiers =
+ utils::fnsig_argument_identifiers(ctx, signature);
+ let ret_ty = utils::fnsig_return_ty(ctx, signature);
+ result.dynamic_items().push(
+ ident,
+ abi,
+ signature.is_variadic(),
+ ctx.options().dynamic_link_require_all,
+ args,
+ args_identifiers,
+ ret,
+ ret_ty,
+ attributes,
+ ctx,
+ );
+ } else {
+ result.push(tokens);
+ }
+ Some(times_seen)
+ }
+}
+
+#[cfg_attr(not(feature = "experimental"), allow(unused_variables))]
+fn unsupported_abi_diagnostic(
+ fn_name: &str,
+ variadic: bool,
+ location: Option<&crate::clang::SourceLocation>,
+ ctx: &BindgenContext,
+ error: &error::Error,
+) {
+ warn!(
+ "Skipping {}function `{}` because the {}",
+ if variadic { "variadic " } else { "" },
+ fn_name,
+ error
+ );
+
+ #[cfg(feature = "experimental")]
+ if ctx.options().emit_diagnostics {
+ use crate::diagnostics::{get_line, Diagnostic, Level, Slice};
+
+ let mut diag = Diagnostic::default();
+ diag.with_title(
+ format!(
+ "Skipping {}function `{}` because the {}",
+ if variadic { "variadic " } else { "" },
+ fn_name,
+ error
+ ),
+ Level::Warn,
+ )
+ .add_annotation(
+ "No code will be generated for this function.",
+ Level::Warn,
+ )
+ .add_annotation(
+ format!(
+ "The configured Rust version is {}.",
+ ctx.options().rust_target
+ ),
+ Level::Note,
+ );
+
+ if let Some(loc) = location {
+ let (file, line, col, _) = loc.location();
+
+ if let Some(filename) = file.name() {
+ if let Ok(Some(source)) = get_line(&filename, line) {
+ let mut slice = Slice::default();
+ slice
+ .with_source(source)
+ .with_location(filename, line, col);
+ diag.add_slice(slice);
+ }
+ }
+ }
+
+ diag.display()
+ }
+}
+
+fn variadic_fn_diagnostic(
+ fn_name: &str,
+ _location: Option<&crate::clang::SourceLocation>,
+ _ctx: &BindgenContext,
+) {
+ warn!(
+ "Cannot generate wrapper for the static variadic function `{}`.",
+ fn_name,
+ );
+
+ #[cfg(feature = "experimental")]
+ if _ctx.options().emit_diagnostics {
+ use crate::diagnostics::{get_line, Diagnostic, Level, Slice};
+
+ let mut diag = Diagnostic::default();
+
+ diag.with_title(format!("Cannot generate wrapper for the static function `{}`.", fn_name), Level::Warn)
+ .add_annotation("The `--wrap-static-fns` feature does not support variadic functions.", Level::Note)
+ .add_annotation("No code will be generated for this function.", Level::Note);
+
+ if let Some(loc) = _location {
+ let (file, line, col, _) = loc.location();
+
+ if let Some(filename) = file.name() {
+ if let Ok(Some(source)) = get_line(&filename, line) {
+ let mut slice = Slice::default();
+ slice
+ .with_source(source)
+ .with_location(filename, line, col);
+ diag.add_slice(slice);
+ }
+ }
+ }
+
+ diag.display()
+ }
+}
+
+fn objc_method_codegen(
+ ctx: &BindgenContext,
+ method: &ObjCMethod,
+ methods: &mut Vec<proc_macro2::TokenStream>,
+ class_name: Option<&str>,
+ rust_class_name: &str,
+ prefix: &str,
+) {
+ // This would ideally resolve the method into an Item, and use
+ // Item::process_before_codegen; however, ObjC methods are not currently
+ // made into function items.
+ let name = format!("{}::{}{}", rust_class_name, prefix, method.rust_name());
+ if ctx.options().blocklisted_items.matches(name) {
+ return;
+ }
+
+ let signature = method.signature();
+ let fn_args = utils::fnsig_arguments(ctx, signature);
+ let fn_ret = utils::fnsig_return_ty(ctx, signature);
+
+ let sig = if method.is_class_method() {
+ quote! {
+ ( #( #fn_args ),* ) #fn_ret
+ }
+ } else {
+ let self_arr = [quote! { &self }];
+ let args = self_arr.iter().chain(fn_args.iter());
+ quote! {
+ ( #( #args ),* ) #fn_ret
+ }
+ };
+
+ let methods_and_args = method.format_method_call(&fn_args);
+
+ let body = {
+ let body = if method.is_class_method() {
+ let class_name = ctx.rust_ident(
+ class_name
+ .expect("Generating a class method without class name?"),
+ );
+ quote!(msg_send!(class!(#class_name), #methods_and_args))
+ } else {
+ quote!(msg_send!(*self, #methods_and_args))
+ };
+
+ ctx.wrap_unsafe_ops(body)
+ };
+
+ let method_name =
+ ctx.rust_ident(format!("{}{}", prefix, method.rust_name()));
+
+ methods.push(quote! {
+ unsafe fn #method_name #sig where <Self as std::ops::Deref>::Target: objc::Message + Sized {
+ #body
+ }
+ });
+}
+
+impl CodeGenerator for ObjCInterface {
+ type Extra = Item;
+ type Return = ();
+
+ fn codegen(
+ &self,
+ ctx: &BindgenContext,
+ result: &mut CodegenResult<'_>,
+ item: &Item,
+ ) {
+ debug_assert!(item.is_enabled_for_codegen(ctx));
+
+ let mut impl_items = vec![];
+ let rust_class_name = item.path_for_allowlisting(ctx)[1..].join("::");
+
+ for method in self.methods() {
+ objc_method_codegen(
+ ctx,
+ method,
+ &mut impl_items,
+ None,
+ &rust_class_name,
+ "",
+ );
+ }
+
+ for class_method in self.class_methods() {
+ let ambiquity = self
+ .methods()
+ .iter()
+ .map(|m| m.rust_name())
+ .any(|x| x == class_method.rust_name());
+ let prefix = if ambiquity { "class_" } else { "" };
+ objc_method_codegen(
+ ctx,
+ class_method,
+ &mut impl_items,
+ Some(self.name()),
+ &rust_class_name,
+ prefix,
+ );
+ }
+
+ let trait_name = ctx.rust_ident(self.rust_name());
+ let trait_constraints = quote! {
+ Sized + std::ops::Deref
+ };
+ let trait_block = if self.is_template() {
+ let template_names: Vec<Ident> = self
+ .template_names
+ .iter()
+ .map(|g| ctx.rust_ident(g))
+ .collect();
+
+ quote! {
+ pub trait #trait_name <#(#template_names:'static),*> : #trait_constraints {
+ #( #impl_items )*
+ }
+ }
+ } else {
+ quote! {
+ pub trait #trait_name : #trait_constraints {
+ #( #impl_items )*
+ }
+ }
+ };
+
+ let class_name = ctx.rust_ident(self.name());
+ if !self.is_category() && !self.is_protocol() {
+ let struct_block = quote! {
+ #[repr(transparent)]
+ #[derive(Debug, Copy, Clone)]
+ pub struct #class_name(pub id);
+ impl std::ops::Deref for #class_name {
+ type Target = objc::runtime::Object;
+ fn deref(&self) -> &Self::Target {
+ unsafe {
+ &*self.0
+ }
+ }
+ }
+ unsafe impl objc::Message for #class_name { }
+ impl #class_name {
+ pub fn alloc() -> Self {
+ Self(unsafe {
+ msg_send!(class!(#class_name), alloc)
+ })
+ }
+ }
+ };
+ result.push(struct_block);
+ let mut protocol_set: HashSet<ItemId> = Default::default();
+ for protocol_id in self.conforms_to.iter() {
+ protocol_set.insert(*protocol_id);
+ let protocol_name = ctx.rust_ident(
+ ctx.resolve_type(protocol_id.expect_type_id(ctx))
+ .name()
+ .unwrap(),
+ );
+ let impl_trait = quote! {
+ impl #protocol_name for #class_name { }
+ };
+ result.push(impl_trait);
+ }
+ let mut parent_class = self.parent_class;
+ while let Some(parent_id) = parent_class {
+ let parent = parent_id
+ .expect_type_id(ctx)
+ .into_resolver()
+ .through_type_refs()
+ .resolve(ctx)
+ .expect_type()
+ .kind();
+
+ let parent = match parent {
+ TypeKind::ObjCInterface(ref parent) => parent,
+ _ => break,
+ };
+ parent_class = parent.parent_class;
+
+ let parent_name = ctx.rust_ident(parent.rust_name());
+ let impl_trait = if parent.is_template() {
+ let template_names: Vec<Ident> = parent
+ .template_names
+ .iter()
+ .map(|g| ctx.rust_ident(g))
+ .collect();
+ quote! {
+ impl <#(#template_names :'static),*> #parent_name <#(#template_names),*> for #class_name {
+ }
+ }
+ } else {
+ quote! {
+ impl #parent_name for #class_name { }
+ }
+ };
+ result.push(impl_trait);
+ for protocol_id in parent.conforms_to.iter() {
+ if protocol_set.insert(*protocol_id) {
+ let protocol_name = ctx.rust_ident(
+ ctx.resolve_type(protocol_id.expect_type_id(ctx))
+ .name()
+ .unwrap(),
+ );
+ let impl_trait = quote! {
+ impl #protocol_name for #class_name { }
+ };
+ result.push(impl_trait);
+ }
+ }
+ if !parent.is_template() {
+ let parent_struct_name = parent.name();
+ let child_struct_name = self.name();
+ let parent_struct = ctx.rust_ident(parent_struct_name);
+ let from_block = quote! {
+ impl From<#class_name> for #parent_struct {
+ fn from(child: #class_name) -> #parent_struct {
+ #parent_struct(child.0)
+ }
+ }
+ };
+ result.push(from_block);
+
+ let error_msg = format!(
+ "This {} cannot be downcasted to {}",
+ parent_struct_name, child_struct_name
+ );
+ let try_into_block = quote! {
+ impl std::convert::TryFrom<#parent_struct> for #class_name {
+ type Error = &'static str;
+ fn try_from(parent: #parent_struct) -> Result<#class_name, Self::Error> {
+ let is_kind_of : bool = unsafe { msg_send!(parent, isKindOfClass:class!(#class_name))};
+ if is_kind_of {
+ Ok(#class_name(parent.0))
+ } else {
+ Err(#error_msg)
+ }
+ }
+ }
+ };
+ result.push(try_into_block);
+ }
+ }
+ }
+
+ if !self.is_protocol() {
+ let impl_block = if self.is_template() {
+ let template_names: Vec<Ident> = self
+ .template_names
+ .iter()
+ .map(|g| ctx.rust_ident(g))
+ .collect();
+ quote! {
+ impl <#(#template_names :'static),*> #trait_name <#(#template_names),*> for #class_name {
+ }
+ }
+ } else {
+ quote! {
+ impl #trait_name for #class_name {
+ }
+ }
+ };
+ result.push(impl_block);
+ }
+
+ result.push(trait_block);
+ result.saw_objc();
+ }
+}
+
+pub(crate) fn codegen(
+ context: BindgenContext,
+) -> Result<(proc_macro2::TokenStream, BindgenOptions), CodegenError> {
+ context.gen(|context| {
+ let _t = context.timer("codegen");
+ let counter = Cell::new(0);
+ let mut result = CodegenResult::new(&counter);
+
+ debug!("codegen: {:?}", context.options());
+
+ if context.options().emit_ir {
+ let codegen_items = context.codegen_items();
+ for (id, item) in context.items() {
+ if codegen_items.contains(&id) {
+ println!("ir: {:?} = {:#?}", id, item);
+ }
+ }
+ }
+
+ if let Some(path) = context.options().emit_ir_graphviz.as_ref() {
+ match dot::write_dot_file(context, path) {
+ Ok(()) => info!(
+ "Your dot file was generated successfully into: {}",
+ path
+ ),
+ Err(e) => warn!("{}", e),
+ }
+ }
+
+ if let Some(spec) = context.options().depfile.as_ref() {
+ match spec.write(context.deps()) {
+ Ok(()) => info!(
+ "Your depfile was generated successfully into: {}",
+ spec.depfile_path.display()
+ ),
+ Err(e) => warn!("{}", e),
+ }
+ }
+
+ context.resolve_item(context.root_module()).codegen(
+ context,
+ &mut result,
+ &(),
+ );
+
+ if let Some(ref lib_name) = context.options().dynamic_library_name {
+ let lib_ident = context.rust_ident(lib_name);
+ let dynamic_items_tokens =
+ result.dynamic_items().get_tokens(lib_ident, context);
+ result.push(dynamic_items_tokens);
+ }
+
+ utils::serialize_items(&result, context)?;
+
+ Ok(postprocessing::postprocessing(
+ result.items,
+ context.options(),
+ ))
+ })
+}
+
+pub(crate) mod utils {
+ use super::serialize::CSerialize;
+ use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque};
+ use crate::ir::context::BindgenContext;
+ use crate::ir::context::TypeId;
+ use crate::ir::function::{Abi, ClangAbi, FunctionSig};
+ use crate::ir::item::{Item, ItemCanonicalPath};
+ use crate::ir::ty::TypeKind;
+ use crate::{args_are_cpp, file_is_cpp};
+ use std::borrow::Cow;
+ use std::io::Write;
+ use std::mem;
+ use std::path::PathBuf;
+ use std::str::FromStr;
+
+ pub(super) fn serialize_items(
+ result: &CodegenResult,
+ context: &BindgenContext,
+ ) -> Result<(), CodegenError> {
+ if result.items_to_serialize.is_empty() {
+ return Ok(());
+ }
+
+ let path = context
+ .options()
+ .wrap_static_fns_path
+ .as_ref()
+ .map(PathBuf::from)
+ .unwrap_or_else(|| {
+ std::env::temp_dir().join("bindgen").join("extern")
+ });
+
+ let dir = path.parent().unwrap();
+
+ if !dir.exists() {
+ std::fs::create_dir_all(dir)?;
+ }
+
+ let is_cpp = args_are_cpp(&context.options().clang_args) ||
+ context
+ .options()
+ .input_headers
+ .iter()
+ .any(|h| file_is_cpp(h));
+
+ let source_path = path.with_extension(if is_cpp { "cpp" } else { "c" });
+
+ let mut code = Vec::new();
+
+ if !context.options().input_headers.is_empty() {
+ for header in &context.options().input_headers {
+ writeln!(code, "#include \"{}\"", header)?;
+ }
+
+ writeln!(code)?;
+ }
+
+ if !context.options().input_header_contents.is_empty() {
+ for (name, contents) in &context.options().input_header_contents {
+ writeln!(code, "// {}\n{}", name, contents)?;
+ }
+
+ writeln!(code)?;
+ }
+
+ writeln!(code, "// Static wrappers\n")?;
+
+ for (id, wrap_as_variadic) in &result.items_to_serialize {
+ let item = context.resolve_item(*id);
+ item.serialize(context, wrap_as_variadic, &mut vec![], &mut code)?;
+ }
+
+ std::fs::write(source_path, code)?;
+
+ Ok(())
+ }
+
+ pub(super) fn wrap_as_variadic_fn(
+ ctx: &BindgenContext,
+ signature: &FunctionSig,
+ name: &str,
+ ) -> Option<super::WrapAsVariadic> {
+ // Fast path, exclude because:
+ // - with 0 args: no va_list possible, so no point searching for one
+ // - with 1 args: cannot have a `va_list` and another arg (required by va_start)
+ if signature.argument_types().len() <= 1 {
+ return None;
+ }
+
+ let mut it = signature.argument_types().iter().enumerate().filter_map(
+ |(idx, (_name, mut type_id))| {
+ // Hand rolled visitor that checks for the presence of `va_list`
+ loop {
+ let ty = ctx.resolve_type(type_id);
+ if Some("__builtin_va_list") == ty.name() {
+ return Some(idx);
+ }
+ match ty.kind() {
+ TypeKind::Alias(type_id_alias) => {
+ type_id = *type_id_alias
+ }
+ TypeKind::ResolvedTypeRef(type_id_typedef) => {
+ type_id = *type_id_typedef
+ }
+ _ => break,
+ }
+ }
+ None
+ },
+ );
+
+ // Return THE idx (by checking that there is no idx after)
+ // This is done since we cannot handle multiple `va_list`
+ it.next().filter(|_| it.next().is_none()).and_then(|idx| {
+ // Call the `wrap_as_variadic_fn` callback
+ #[cfg(feature = "experimental")]
+ {
+ ctx.options()
+ .last_callback(|c| c.wrap_as_variadic_fn(name))
+ .map(|new_name| super::WrapAsVariadic {
+ new_name,
+ idx_of_va_list_arg: idx,
+ })
+ }
+ #[cfg(not(feature = "experimental"))]
+ {
+ let _ = name;
+ let _ = idx;
+ None
+ }
+ })
+ }
+
+ pub(crate) fn prepend_bitfield_unit_type(
+ ctx: &BindgenContext,
+ result: &mut Vec<proc_macro2::TokenStream>,
+ ) {
+ let bitfield_unit_src = include_str!("./bitfield_unit.rs");
+ let bitfield_unit_src = if ctx.options().rust_features().min_const_fn {
+ Cow::Borrowed(bitfield_unit_src)
+ } else {
+ Cow::Owned(bitfield_unit_src.replace("const fn ", "fn "))
+ };
+ let bitfield_unit_type =
+ proc_macro2::TokenStream::from_str(&bitfield_unit_src).unwrap();
+ let bitfield_unit_type = quote!(#bitfield_unit_type);
+
+ let items = vec![bitfield_unit_type];
+ let old_items = mem::replace(result, items);
+ result.extend(old_items);
+ }
+
+ pub(crate) fn prepend_objc_header(
+ ctx: &BindgenContext,
+ result: &mut Vec<proc_macro2::TokenStream>,
+ ) {
+ let use_objc = if ctx.options().objc_extern_crate {
+ quote! {
+ #[macro_use]
+ extern crate objc;
+ }
+ } else {
+ quote! {
+ use objc::{self, msg_send, sel, sel_impl, class};
+ }
+ };
+
+ let id_type = quote! {
+ #[allow(non_camel_case_types)]
+ pub type id = *mut objc::runtime::Object;
+ };
+
+ let items = vec![use_objc, id_type];
+ let old_items = mem::replace(result, items);
+ result.extend(old_items);
+ }
+
+ pub(crate) fn prepend_block_header(
+ ctx: &BindgenContext,
+ result: &mut Vec<proc_macro2::TokenStream>,
+ ) {
+ let use_block = if ctx.options().block_extern_crate {
+ quote! {
+ extern crate block;
+ }
+ } else {
+ quote! {
+ use block;
+ }
+ };
+
+ let items = vec![use_block];
+ let old_items = mem::replace(result, items);
+ result.extend(old_items);
+ }
+
+ pub(crate) fn prepend_union_types(
+ ctx: &BindgenContext,
+ result: &mut Vec<proc_macro2::TokenStream>,
+ ) {
+ let prefix = ctx.trait_prefix();
+
+ // If the target supports `const fn`, declare eligible functions
+ // as `const fn` else just `fn`.
+ let const_fn = if ctx.options().rust_features().min_const_fn {
+ quote! { const fn }
+ } else {
+ quote! { fn }
+ };
+
+ // TODO(emilio): The fmt::Debug impl could be way nicer with
+ // std::intrinsics::type_name, but...
+ let union_field_decl = quote! {
+ #[repr(C)]
+ pub struct __BindgenUnionField<T>(::#prefix::marker::PhantomData<T>);
+ };
+
+ let transmute =
+ ctx.wrap_unsafe_ops(quote!(::#prefix::mem::transmute(self)));
+
+ let union_field_impl = quote! {
+ impl<T> __BindgenUnionField<T> {
+ #[inline]
+ pub #const_fn new() -> Self {
+ __BindgenUnionField(::#prefix::marker::PhantomData)
+ }
+
+ #[inline]
+ pub unsafe fn as_ref(&self) -> &T {
+ #transmute
+ }
+
+ #[inline]
+ pub unsafe fn as_mut(&mut self) -> &mut T {
+ #transmute
+ }
+ }
+ };
+
+ let union_field_default_impl = quote! {
+ impl<T> ::#prefix::default::Default for __BindgenUnionField<T> {
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+ }
+ };
+
+ let union_field_clone_impl = quote! {
+ impl<T> ::#prefix::clone::Clone for __BindgenUnionField<T> {
+ #[inline]
+ fn clone(&self) -> Self {
+ *self
+ }
+ }
+ };
+
+ let union_field_copy_impl = quote! {
+ impl<T> ::#prefix::marker::Copy for __BindgenUnionField<T> {}
+ };
+
+ let union_field_debug_impl = quote! {
+ impl<T> ::#prefix::fmt::Debug for __BindgenUnionField<T> {
+ fn fmt(&self, fmt: &mut ::#prefix::fmt::Formatter<'_>)
+ -> ::#prefix::fmt::Result {
+ fmt.write_str("__BindgenUnionField")
+ }
+ }
+ };
+
+ // The actual memory of the filed will be hashed, so that's why these
+ // field doesn't do anything with the hash.
+ let union_field_hash_impl = quote! {
+ impl<T> ::#prefix::hash::Hash for __BindgenUnionField<T> {
+ fn hash<H: ::#prefix::hash::Hasher>(&self, _state: &mut H) {
+ }
+ }
+ };
+
+ let union_field_partialeq_impl = quote! {
+ impl<T> ::#prefix::cmp::PartialEq for __BindgenUnionField<T> {
+ fn eq(&self, _other: &__BindgenUnionField<T>) -> bool {
+ true
+ }
+ }
+ };
+
+ let union_field_eq_impl = quote! {
+ impl<T> ::#prefix::cmp::Eq for __BindgenUnionField<T> {
+ }
+ };
+
+ let items = vec![
+ union_field_decl,
+ union_field_impl,
+ union_field_default_impl,
+ union_field_clone_impl,
+ union_field_copy_impl,
+ union_field_debug_impl,
+ union_field_hash_impl,
+ union_field_partialeq_impl,
+ union_field_eq_impl,
+ ];
+
+ let old_items = mem::replace(result, items);
+ result.extend(old_items);
+ }
+
+ pub(crate) fn prepend_incomplete_array_types(
+ ctx: &BindgenContext,
+ result: &mut Vec<proc_macro2::TokenStream>,
+ ) {
+ let prefix = ctx.trait_prefix();
+
+ // If the target supports `const fn`, declare eligible functions
+ // as `const fn` else just `fn`.
+ let const_fn = if ctx.options().rust_features().min_const_fn {
+ quote! { const fn }
+ } else {
+ quote! { fn }
+ };
+
+ let incomplete_array_decl = quote! {
+ #[repr(C)]
+ #[derive(Default)]
+ pub struct __IncompleteArrayField<T>(
+ ::#prefix::marker::PhantomData<T>, [T; 0]);
+ };
+
+ let from_raw_parts = ctx.wrap_unsafe_ops(quote! (
+ ::#prefix::slice::from_raw_parts(self.as_ptr(), len)
+ ));
+ let from_raw_parts_mut = ctx.wrap_unsafe_ops(quote! (
+ ::#prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+ ));
+
+ let incomplete_array_impl = quote! {
+ impl<T> __IncompleteArrayField<T> {
+ #[inline]
+ pub #const_fn new() -> Self {
+ __IncompleteArrayField(::#prefix::marker::PhantomData, [])
+ }
+
+ #[inline]
+ pub fn as_ptr(&self) -> *const T {
+ self as *const _ as *const T
+ }
+
+ #[inline]
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ self as *mut _ as *mut T
+ }
+
+ #[inline]
+ pub unsafe fn as_slice(&self, len: usize) -> &[T] {
+ #from_raw_parts
+ }
+
+ #[inline]
+ pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
+ #from_raw_parts_mut
+ }
+ }
+ };
+
+ let incomplete_array_debug_impl = quote! {
+ impl<T> ::#prefix::fmt::Debug for __IncompleteArrayField<T> {
+ fn fmt(&self, fmt: &mut ::#prefix::fmt::Formatter<'_>)
+ -> ::#prefix::fmt::Result {
+ fmt.write_str("__IncompleteArrayField")
+ }
+ }
+ };
+
+ let items = vec![
+ incomplete_array_decl,
+ incomplete_array_impl,
+ incomplete_array_debug_impl,
+ ];
+
+ let old_items = mem::replace(result, items);
+ result.extend(old_items);
+ }
+
+ pub(crate) fn prepend_float16_type(
+ result: &mut Vec<proc_macro2::TokenStream>,
+ ) {
+ let float16_type = quote! {
+ #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)]
+ #[repr(transparent)]
+ pub struct __BindgenFloat16(pub u16);
+ };
+
+ let items = vec![float16_type];
+ let old_items = mem::replace(result, items);
+ result.extend(old_items);
+ }
+
+ pub(crate) fn prepend_complex_type(
+ result: &mut Vec<proc_macro2::TokenStream>,
+ ) {
+ let complex_type = quote! {
+ #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)]
+ #[repr(C)]
+ pub struct __BindgenComplex<T> {
+ pub re: T,
+ pub im: T
+ }
+ };
+
+ let items = vec![complex_type];
+ let old_items = mem::replace(result, items);
+ result.extend(old_items);
+ }
+
+ pub(crate) fn build_path(
+ item: &Item,
+ ctx: &BindgenContext,
+ ) -> error::Result<syn::Type> {
+ let path = item.namespace_aware_canonical_path(ctx);
+ let tokens =
+ proc_macro2::TokenStream::from_str(&path.join("::")).unwrap();
+
+ Ok(syn::parse_quote! { #tokens })
+ }
+
+ fn primitive_ty(ctx: &BindgenContext, name: &str) -> syn::Type {
+ let ident = ctx.rust_ident_raw(name);
+ syn::parse_quote! { #ident }
+ }
+
+ pub(crate) fn type_from_named(
+ ctx: &BindgenContext,
+ name: &str,
+ ) -> Option<syn::Type> {
+ // FIXME: We could use the inner item to check this is really a
+ // primitive type but, who the heck overrides these anyway?
+ Some(match name {
+ "int8_t" => primitive_ty(ctx, "i8"),
+ "uint8_t" => primitive_ty(ctx, "u8"),
+ "int16_t" => primitive_ty(ctx, "i16"),
+ "uint16_t" => primitive_ty(ctx, "u16"),
+ "int32_t" => primitive_ty(ctx, "i32"),
+ "uint32_t" => primitive_ty(ctx, "u32"),
+ "int64_t" => primitive_ty(ctx, "i64"),
+ "uint64_t" => primitive_ty(ctx, "u64"),
+
+ "size_t" if ctx.options().size_t_is_usize => {
+ primitive_ty(ctx, "usize")
+ }
+ "uintptr_t" => primitive_ty(ctx, "usize"),
+
+ "ssize_t" if ctx.options().size_t_is_usize => {
+ primitive_ty(ctx, "isize")
+ }
+ "intptr_t" | "ptrdiff_t" => primitive_ty(ctx, "isize"),
+ _ => return None,
+ })
+ }
+
+ fn fnsig_return_ty_internal(
+ ctx: &BindgenContext,
+ sig: &FunctionSig,
+ ) -> syn::Type {
+ if sig.is_divergent() {
+ return syn::parse_quote! { ! };
+ }
+
+ let canonical_type_kind = sig
+ .return_type()
+ .into_resolver()
+ .through_type_refs()
+ .through_type_aliases()
+ .resolve(ctx)
+ .kind()
+ .expect_type()
+ .kind();
+
+ match canonical_type_kind {
+ TypeKind::Void => syn::parse_quote! { () },
+ _ => sig.return_type().to_rust_ty_or_opaque(ctx, &()),
+ }
+ }
+
+ pub(crate) fn fnsig_return_ty(
+ ctx: &BindgenContext,
+ sig: &FunctionSig,
+ ) -> proc_macro2::TokenStream {
+ match fnsig_return_ty_internal(ctx, sig) {
+ syn::Type::Tuple(syn::TypeTuple { elems, .. })
+ if elems.is_empty() =>
+ {
+ quote! {}
+ }
+ ty => quote! { -> #ty },
+ }
+ }
+
+ pub(crate) fn fnsig_argument_type(
+ ctx: &BindgenContext,
+ ty: &TypeId,
+ ) -> syn::Type {
+ use super::ToPtr;
+
+ let arg_item = ctx.resolve_item(ty);
+ let arg_ty = arg_item.kind().expect_type();
+
+ // From the C90 standard[1]:
+ //
+ // A declaration of a parameter as "array of type" shall be
+ // adjusted to "qualified pointer to type", where the type
+ // qualifiers (if any) are those specified within the [ and ] of
+ // the array type derivation.
+ //
+ // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html
+ match *arg_ty.canonical_type(ctx).kind() {
+ TypeKind::Array(t, _) => {
+ let stream = if ctx.options().array_pointers_in_arguments {
+ arg_ty.to_rust_ty_or_opaque(ctx, arg_item)
+ } else {
+ t.to_rust_ty_or_opaque(ctx, &())
+ };
+ stream.to_ptr(ctx.resolve_type(t).is_const())
+ }
+ TypeKind::Pointer(inner) => {
+ let inner = ctx.resolve_item(inner);
+ let inner_ty = inner.expect_type();
+ if let TypeKind::ObjCInterface(ref interface) =
+ *inner_ty.canonical_type(ctx).kind()
+ {
+ let name = ctx.rust_ident(interface.name());
+ syn::parse_quote! { #name }
+ } else {
+ arg_item.to_rust_ty_or_opaque(ctx, &())
+ }
+ }
+ _ => arg_item.to_rust_ty_or_opaque(ctx, &()),
+ }
+ }
+
+ pub(crate) fn fnsig_arguments_iter<
+ 'a,
+ I: Iterator<Item = &'a (Option<String>, crate::ir::context::TypeId)>,
+ >(
+ ctx: &BindgenContext,
+ args_iter: I,
+ is_variadic: bool,
+ ) -> Vec<proc_macro2::TokenStream> {
+ let mut unnamed_arguments = 0;
+ let mut args = args_iter
+ .map(|(name, ty)| {
+ let arg_ty = fnsig_argument_type(ctx, 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 : #arg_ty
+ }
+ })
+ .collect::<Vec<_>>();
+
+ if is_variadic {
+ args.push(quote! { ... })
+ }
+
+ args
+ }
+
+ pub(crate) fn fnsig_arguments(
+ ctx: &BindgenContext,
+ sig: &FunctionSig,
+ ) -> Vec<proc_macro2::TokenStream> {
+ fnsig_arguments_iter(
+ ctx,
+ sig.argument_types().iter(),
+ sig.is_variadic(),
+ )
+ }
+
+ pub(crate) fn fnsig_argument_identifiers(
+ ctx: &BindgenContext,
+ sig: &FunctionSig,
+ ) -> Vec<proc_macro2::TokenStream> {
+ let mut unnamed_arguments = 0;
+ let args = sig
+ .argument_types()
+ .iter()
+ .map(|&(ref name, _ty)| {
+ let arg_name = match *name {
+ Some(ref name) => ctx.rust_mangle(name).into_owned(),
+ None => {
+ unnamed_arguments += 1;
+ format!("arg{}", unnamed_arguments)
+ }
+ };
+
+ assert!(!arg_name.is_empty());
+ let arg_name = ctx.rust_ident(arg_name);
+
+ quote! {
+ #arg_name
+ }
+ })
+ .collect::<Vec<_>>();
+
+ args
+ }
+
+ pub(crate) fn fnsig_block(
+ ctx: &BindgenContext,
+ sig: &FunctionSig,
+ ) -> proc_macro2::TokenStream {
+ let args = sig.argument_types().iter().map(|&(_, ty)| {
+ let arg_item = ctx.resolve_item(ty);
+
+ arg_item.to_rust_ty_or_opaque(ctx, &())
+ });
+
+ let ret_ty = fnsig_return_ty_internal(ctx, sig);
+ quote! {
+ *const ::block::Block<(#(#args,)*), #ret_ty>
+ }
+ }
+
+ // Returns true if `canonical_name` will end up as `mangled_name` at the
+ // machine code level, i.e. after LLVM has applied any target specific
+ // mangling.
+ pub(crate) fn names_will_be_identical_after_mangling(
+ canonical_name: &str,
+ mangled_name: &str,
+ call_conv: Option<ClangAbi>,
+ ) -> bool {
+ // If the mangled name and the canonical name are the same then no
+ // mangling can have happened between the two versions.
+ if canonical_name == mangled_name {
+ return true;
+ }
+
+ // Working with &[u8] makes indexing simpler than with &str
+ let canonical_name = canonical_name.as_bytes();
+ let mangled_name = mangled_name.as_bytes();
+
+ let (mangling_prefix, expect_suffix) = match call_conv {
+ Some(ClangAbi::Known(Abi::C)) |
+ // None is the case for global variables
+ None => {
+ (b'_', false)
+ }
+ Some(ClangAbi::Known(Abi::Stdcall)) => (b'_', true),
+ Some(ClangAbi::Known(Abi::Fastcall)) => (b'@', true),
+
+ // This is something we don't recognize, stay on the safe side
+ // by emitting the `#[link_name]` attribute
+ Some(_) => return false,
+ };
+
+ // Check that the mangled name is long enough to at least contain the
+ // canonical name plus the expected prefix.
+ if mangled_name.len() < canonical_name.len() + 1 {
+ return false;
+ }
+
+ // Return if the mangled name does not start with the prefix expected
+ // for the given calling convention.
+ if mangled_name[0] != mangling_prefix {
+ return false;
+ }
+
+ // Check that the mangled name contains the canonical name after the
+ // prefix
+ if &mangled_name[1..canonical_name.len() + 1] != canonical_name {
+ return false;
+ }
+
+ // If the given calling convention also prescribes a suffix, check that
+ // it exists too
+ if expect_suffix {
+ let suffix = &mangled_name[canonical_name.len() + 1..];
+
+ // The shortest suffix is "@0"
+ if suffix.len() < 2 {
+ return false;
+ }
+
+ // Check that the suffix starts with '@' and is all ASCII decimals
+ // after that.
+ if suffix[0] != b'@' || !suffix[1..].iter().all(u8::is_ascii_digit)
+ {
+ return false;
+ }
+ } else if mangled_name.len() != canonical_name.len() + 1 {
+ // If we don't expect a prefix but there is one, we need the
+ // #[link_name] attribute
+ return false;
+ }
+
+ true
+ }
+}
diff --git a/third_party/rust/bindgen/codegen/postprocessing/merge_extern_blocks.rs b/third_party/rust/bindgen/codegen/postprocessing/merge_extern_blocks.rs
new file mode 100644
index 0000000000..10fa0ec80b
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/postprocessing/merge_extern_blocks.rs
@@ -0,0 +1,72 @@
+use syn::{
+ visit_mut::{visit_file_mut, visit_item_mod_mut, VisitMut},
+ File, Item, ItemForeignMod, ItemMod,
+};
+
+pub(super) fn merge_extern_blocks(file: &mut File) {
+ Visitor.visit_file_mut(file)
+}
+
+struct Visitor;
+
+impl VisitMut for Visitor {
+ fn visit_file_mut(&mut self, file: &mut File) {
+ visit_items(&mut file.items);
+ visit_file_mut(self, file)
+ }
+
+ fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) {
+ if let Some((_, ref mut items)) = item_mod.content {
+ visit_items(items);
+ }
+ visit_item_mod_mut(self, item_mod)
+ }
+}
+
+fn visit_items(items: &mut Vec<Item>) {
+ // Keep all the extern blocks in a different `Vec` for faster search.
+ let mut extern_blocks = Vec::<ItemForeignMod>::new();
+
+ for item in std::mem::take(items) {
+ if let Item::ForeignMod(ItemForeignMod {
+ attrs,
+ abi,
+ brace_token,
+ unsafety,
+ items: extern_block_items,
+ }) = item
+ {
+ let mut exists = false;
+ for extern_block in &mut extern_blocks {
+ // Check if there is a extern block with the same ABI and
+ // attributes.
+ if extern_block.attrs == attrs && extern_block.abi == abi {
+ // Merge the items of the two blocks.
+ extern_block.items.extend_from_slice(&extern_block_items);
+ exists = true;
+ break;
+ }
+ }
+ // If no existing extern block had the same ABI and attributes, store
+ // it.
+ if !exists {
+ extern_blocks.push(ItemForeignMod {
+ attrs,
+ abi,
+ brace_token,
+ unsafety,
+ items: extern_block_items,
+ });
+ }
+ } else {
+ // If the item is not an extern block, we don't have to do anything and just
+ // push it back.
+ items.push(item);
+ }
+ }
+
+ // Move all the extern blocks alongside the rest of the items.
+ for extern_block in extern_blocks {
+ items.push(Item::ForeignMod(extern_block));
+ }
+}
diff --git a/third_party/rust/bindgen/codegen/postprocessing/mod.rs b/third_party/rust/bindgen/codegen/postprocessing/mod.rs
new file mode 100644
index 0000000000..9641698521
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/postprocessing/mod.rs
@@ -0,0 +1,57 @@
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+use syn::{parse2, File};
+
+use crate::BindgenOptions;
+
+mod merge_extern_blocks;
+mod sort_semantically;
+
+use merge_extern_blocks::merge_extern_blocks;
+use sort_semantically::sort_semantically;
+
+struct PostProcessingPass {
+ should_run: fn(&BindgenOptions) -> bool,
+ run: fn(&mut File),
+}
+
+// TODO: This can be a const fn when mutable references are allowed in const
+// context.
+macro_rules! pass {
+ ($pass:ident) => {
+ PostProcessingPass {
+ should_run: |options| options.$pass,
+ run: |file| $pass(file),
+ }
+ };
+}
+
+const PASSES: &[PostProcessingPass] =
+ &[pass!(merge_extern_blocks), pass!(sort_semantically)];
+
+pub(crate) fn postprocessing(
+ items: Vec<TokenStream>,
+ options: &BindgenOptions,
+) -> TokenStream {
+ let items = items.into_iter().collect();
+ let require_syn = PASSES.iter().any(|pass| (pass.should_run)(options));
+
+ if !require_syn {
+ return items;
+ }
+
+ // This syn business is a hack, for now. This means that we are re-parsing already
+ // generated code using `syn` (as opposed to `quote`) because `syn` provides us more
+ // control over the elements.
+ // The `unwrap` here is deliberate because bindgen should generate valid rust items at all
+ // times.
+ let mut file = parse2::<File>(items).unwrap();
+
+ for pass in PASSES {
+ if (pass.should_run)(options) {
+ (pass.run)(&mut file);
+ }
+ }
+
+ file.into_token_stream()
+}
diff --git a/third_party/rust/bindgen/codegen/postprocessing/sort_semantically.rs b/third_party/rust/bindgen/codegen/postprocessing/sort_semantically.rs
new file mode 100644
index 0000000000..be94ce69c5
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/postprocessing/sort_semantically.rs
@@ -0,0 +1,46 @@
+use syn::{
+ visit_mut::{visit_file_mut, visit_item_mod_mut, VisitMut},
+ File, Item, ItemMod,
+};
+
+pub(super) fn sort_semantically(file: &mut File) {
+ Visitor.visit_file_mut(file)
+}
+
+struct Visitor;
+
+impl VisitMut for Visitor {
+ fn visit_file_mut(&mut self, file: &mut File) {
+ visit_items(&mut file.items);
+ visit_file_mut(self, file)
+ }
+
+ fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) {
+ if let Some((_, ref mut items)) = item_mod.content {
+ visit_items(items);
+ }
+ visit_item_mod_mut(self, item_mod)
+ }
+}
+
+fn visit_items(items: &mut [Item]) {
+ items.sort_by_key(|item| match item {
+ Item::Type(_) => 0,
+ Item::Struct(_) => 1,
+ Item::Const(_) => 2,
+ Item::Fn(_) => 3,
+ Item::Enum(_) => 4,
+ Item::Union(_) => 5,
+ Item::Static(_) => 6,
+ Item::Trait(_) => 7,
+ Item::TraitAlias(_) => 8,
+ Item::Impl(_) => 9,
+ Item::Mod(_) => 10,
+ Item::Use(_) => 11,
+ Item::Verbatim(_) => 12,
+ Item::ExternCrate(_) => 13,
+ Item::ForeignMod(_) => 14,
+ Item::Macro(_) => 15,
+ _ => 18,
+ });
+}
diff --git a/third_party/rust/bindgen/codegen/serialize.rs b/third_party/rust/bindgen/codegen/serialize.rs
new file mode 100644
index 0000000000..9765a8bdf2
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/serialize.rs
@@ -0,0 +1,444 @@
+use std::io::Write;
+
+use crate::callbacks::IntKind;
+
+use crate::ir::comp::CompKind;
+use crate::ir::context::{BindgenContext, TypeId};
+use crate::ir::function::{Function, FunctionKind};
+use crate::ir::item::Item;
+use crate::ir::item::ItemCanonicalName;
+use crate::ir::item_kind::ItemKind;
+use crate::ir::ty::{FloatKind, Type, TypeKind};
+
+use super::{CodegenError, WrapAsVariadic};
+
+fn get_loc(item: &Item) -> String {
+ item.location()
+ .map(|x| x.to_string())
+ .unwrap_or_else(|| "unknown".to_owned())
+}
+
+pub(super) trait CSerialize<'a> {
+ type Extra;
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ extra: Self::Extra,
+ stack: &mut Vec<String>,
+ writer: &mut W,
+ ) -> Result<(), CodegenError>;
+}
+
+impl<'a> CSerialize<'a> for Item {
+ type Extra = &'a Option<WrapAsVariadic>;
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ extra: Self::Extra,
+ stack: &mut Vec<String>,
+ writer: &mut W,
+ ) -> Result<(), CodegenError> {
+ match self.kind() {
+ ItemKind::Function(func) => {
+ func.serialize(ctx, (self, extra), stack, writer)
+ }
+ kind => Err(CodegenError::Serialize {
+ msg: format!("Cannot serialize item kind {:?}", kind),
+ loc: get_loc(self),
+ }),
+ }
+ }
+}
+
+impl<'a> CSerialize<'a> for Function {
+ type Extra = (&'a Item, &'a Option<WrapAsVariadic>);
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ (item, wrap_as_variadic): Self::Extra,
+ stack: &mut Vec<String>,
+ writer: &mut W,
+ ) -> Result<(), CodegenError> {
+ if self.kind() != FunctionKind::Function {
+ return Err(CodegenError::Serialize {
+ msg: format!(
+ "Cannot serialize function kind {:?}",
+ self.kind(),
+ ),
+ loc: get_loc(item),
+ });
+ }
+
+ let signature = match ctx.resolve_type(self.signature()).kind() {
+ TypeKind::Function(signature) => signature,
+ _ => unreachable!(),
+ };
+
+ assert!(!signature.is_variadic());
+
+ let name = self.name();
+
+ // Function argoments stored as `(name, type_id)` tuples.
+ let args = {
+ let mut count = 0;
+
+ let idx_to_prune = wrap_as_variadic.as_ref().map(
+ |WrapAsVariadic {
+ idx_of_va_list_arg, ..
+ }| *idx_of_va_list_arg,
+ );
+
+ signature
+ .argument_types()
+ .iter()
+ .cloned()
+ .enumerate()
+ .filter_map(|(idx, (opt_name, type_id))| {
+ if Some(idx) == idx_to_prune {
+ None
+ } else {
+ Some((
+ opt_name.unwrap_or_else(|| {
+ let name = format!("arg_{}", count);
+ count += 1;
+ name
+ }),
+ type_id,
+ ))
+ }
+ })
+ .collect::<Vec<_>>()
+ };
+
+ // The name used for the wrapper self.
+ let wrap_name = format!("{}{}", name, ctx.wrap_static_fns_suffix());
+
+ // The function's return type
+ let (ret_item, ret_ty) = {
+ let type_id = signature.return_type();
+ let ret_item = ctx.resolve_item(type_id);
+ let ret_ty = ret_item.expect_type();
+
+ // Write `ret_ty`.
+ ret_ty.serialize(ctx, ret_item, stack, writer)?;
+
+ (ret_item, ret_ty)
+ };
+
+ const INDENT: &str = " ";
+
+ // Write `wrap_name(args`.
+ write!(writer, " {}(", wrap_name)?;
+ serialize_args(&args, ctx, writer)?;
+
+ if wrap_as_variadic.is_none() {
+ // Write `) { name(` if the function returns void and `) { return name(` if it does not.
+ if ret_ty.is_void() {
+ write!(writer, ") {{ {}(", name)?;
+ } else {
+ write!(writer, ") {{ return {}(", name)?;
+ }
+ } else {
+ // Write `, ...) {`
+ writeln!(writer, ", ...) {{")?;
+
+ // Declare the return type `RET_TY ret;` if their is a need to do so
+ if !ret_ty.is_void() {
+ write!(writer, "{INDENT}")?;
+ ret_ty.serialize(ctx, ret_item, stack, writer)?;
+ writeln!(writer, " ret;")?;
+ }
+
+ // Setup va_list
+ writeln!(writer, "{INDENT}va_list ap;\n")?;
+ writeln!(
+ writer,
+ "{INDENT}va_start(ap, {});",
+ args.last().unwrap().0
+ )?;
+
+ write!(writer, "{INDENT}")?;
+ // Write `ret = name(` or `name(` depending if the function returns something
+ if !ret_ty.is_void() {
+ write!(writer, "ret = ")?;
+ }
+ write!(writer, "{}(", name)?;
+ }
+
+ // Get the arguments names and insert at the right place if necessary `ap`
+ let mut args: Vec<_> = args.into_iter().map(|(name, _)| name).collect();
+ if let Some(WrapAsVariadic {
+ idx_of_va_list_arg, ..
+ }) = wrap_as_variadic
+ {
+ args.insert(*idx_of_va_list_arg, "ap".to_owned());
+ }
+
+ // Write `arg_names);`.
+ serialize_sep(", ", args.iter(), ctx, writer, |name, _, buf| {
+ write!(buf, "{}", name).map_err(From::from)
+ })?;
+ #[rustfmt::skip]
+ write!(writer, ");{}", if wrap_as_variadic.is_none() { " " } else { "\n" })?;
+
+ if wrap_as_variadic.is_some() {
+ // End va_list and return the result if their is one
+ writeln!(writer, "{INDENT}va_end(ap);")?;
+ if !ret_ty.is_void() {
+ writeln!(writer, "{INDENT}return ret;")?;
+ }
+ }
+
+ writeln!(writer, "}}")?;
+
+ Ok(())
+ }
+}
+
+impl<'a> CSerialize<'a> for TypeId {
+ type Extra = ();
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ (): Self::Extra,
+ stack: &mut Vec<String>,
+ writer: &mut W,
+ ) -> Result<(), CodegenError> {
+ let item = ctx.resolve_item(*self);
+ item.expect_type().serialize(ctx, item, stack, writer)
+ }
+}
+
+impl<'a> CSerialize<'a> for Type {
+ type Extra = &'a Item;
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ item: Self::Extra,
+ stack: &mut Vec<String>,
+ writer: &mut W,
+ ) -> Result<(), CodegenError> {
+ match self.kind() {
+ TypeKind::Void => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ write!(writer, "void")?
+ }
+ TypeKind::NullPtr => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ write!(writer, "nullptr_t")?
+ }
+ TypeKind::Int(int_kind) => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ match int_kind {
+ IntKind::Bool => write!(writer, "bool")?,
+ IntKind::SChar => write!(writer, "signed char")?,
+ IntKind::UChar => write!(writer, "unsigned char")?,
+ IntKind::WChar => write!(writer, "wchar_t")?,
+ IntKind::Short => write!(writer, "short")?,
+ IntKind::UShort => write!(writer, "unsigned short")?,
+ IntKind::Int => write!(writer, "int")?,
+ IntKind::UInt => write!(writer, "unsigned int")?,
+ IntKind::Long => write!(writer, "long")?,
+ IntKind::ULong => write!(writer, "unsigned long")?,
+ IntKind::LongLong => write!(writer, "long long")?,
+ IntKind::ULongLong => write!(writer, "unsigned long long")?,
+ IntKind::Char { .. } => write!(writer, "char")?,
+ int_kind => {
+ return Err(CodegenError::Serialize {
+ msg: format!(
+ "Cannot serialize integer kind {:?}",
+ int_kind
+ ),
+ loc: get_loc(item),
+ })
+ }
+ }
+ }
+ TypeKind::Float(float_kind) => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ match float_kind {
+ FloatKind::Float16 => write!(writer, "_Float16")?,
+ FloatKind::Float => write!(writer, "float")?,
+ FloatKind::Double => write!(writer, "double")?,
+ FloatKind::LongDouble => write!(writer, "long double")?,
+ FloatKind::Float128 => write!(writer, "__float128")?,
+ }
+ }
+ TypeKind::Complex(float_kind) => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ match float_kind {
+ FloatKind::Float16 => write!(writer, "_Float16 complex")?,
+ FloatKind::Float => write!(writer, "float complex")?,
+ FloatKind::Double => write!(writer, "double complex")?,
+ FloatKind::LongDouble => {
+ write!(writer, "long double complex")?
+ }
+ FloatKind::Float128 => write!(writer, "__complex128")?,
+ }
+ }
+ TypeKind::Alias(type_id) => {
+ if let Some(name) = self.name() {
+ if self.is_const() {
+ write!(writer, "const {}", name)?;
+ } else {
+ write!(writer, "{}", name)?;
+ }
+ } else {
+ type_id.serialize(ctx, (), stack, writer)?;
+ }
+ }
+ TypeKind::Array(type_id, length) => {
+ type_id.serialize(ctx, (), stack, writer)?;
+ write!(writer, " [{}]", length)?
+ }
+ TypeKind::Function(signature) => {
+ if self.is_const() {
+ stack.push("const ".to_string());
+ }
+
+ signature.return_type().serialize(
+ ctx,
+ (),
+ &mut vec![],
+ writer,
+ )?;
+
+ write!(writer, " (")?;
+ while let Some(item) = stack.pop() {
+ write!(writer, "{}", item)?;
+ }
+ write!(writer, ")")?;
+
+ let args = signature.argument_types();
+ if args.is_empty() {
+ write!(writer, " (void)")?;
+ } else {
+ write!(writer, " (")?;
+ serialize_sep(
+ ", ",
+ args.iter(),
+ ctx,
+ writer,
+ |(name, type_id), ctx, buf| {
+ let mut stack = vec![];
+ if let Some(name) = name {
+ stack.push(name.clone());
+ }
+ type_id.serialize(ctx, (), &mut stack, buf)
+ },
+ )?;
+ write!(writer, ")")?
+ }
+ }
+ TypeKind::ResolvedTypeRef(type_id) => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ type_id.serialize(ctx, (), stack, writer)?
+ }
+ TypeKind::Pointer(type_id) => {
+ if self.is_const() {
+ stack.push("*const ".to_owned());
+ } else {
+ stack.push("*".to_owned());
+ }
+ type_id.serialize(ctx, (), stack, writer)?
+ }
+ TypeKind::Comp(comp_info) => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+
+ let name = item.canonical_name(ctx);
+
+ match comp_info.kind() {
+ CompKind::Struct => write!(writer, "struct {}", name)?,
+ CompKind::Union => write!(writer, "union {}", name)?,
+ };
+ }
+ TypeKind::Enum(_enum_ty) => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+
+ let name = item.canonical_name(ctx);
+ write!(writer, "enum {}", name)?;
+ }
+ ty => {
+ return Err(CodegenError::Serialize {
+ msg: format!("Cannot serialize type kind {:?}", ty),
+ loc: get_loc(item),
+ })
+ }
+ };
+
+ if !stack.is_empty() {
+ write!(writer, " ")?;
+ while let Some(item) = stack.pop() {
+ write!(writer, "{}", item)?;
+ }
+ }
+
+ Ok(())
+ }
+}
+
+fn serialize_args<W: Write>(
+ args: &[(String, TypeId)],
+ ctx: &BindgenContext,
+ writer: &mut W,
+) -> Result<(), CodegenError> {
+ if args.is_empty() {
+ write!(writer, "void")?;
+ } else {
+ serialize_sep(
+ ", ",
+ args.iter(),
+ ctx,
+ writer,
+ |(name, type_id), ctx, buf| {
+ type_id.serialize(ctx, (), &mut vec![name.clone()], buf)
+ },
+ )?;
+ }
+
+ Ok(())
+}
+
+fn serialize_sep<
+ W: Write,
+ F: FnMut(I::Item, &BindgenContext, &mut W) -> Result<(), CodegenError>,
+ I: Iterator,
+>(
+ sep: &str,
+ mut iter: I,
+ ctx: &BindgenContext,
+ buf: &mut W,
+ mut f: F,
+) -> Result<(), CodegenError> {
+ if let Some(item) = iter.next() {
+ f(item, ctx, buf)?;
+ let sep = sep.as_bytes();
+ for item in iter {
+ buf.write_all(sep)?;
+ f(item, ctx, buf)?;
+ }
+ }
+
+ Ok(())
+}
diff --git a/third_party/rust/bindgen/codegen/struct_layout.rs b/third_party/rust/bindgen/codegen/struct_layout.rs
new file mode 100644
index 0000000000..f4596a1992
--- /dev/null
+++ b/third_party/rust/bindgen/codegen/struct_layout.rs
@@ -0,0 +1,451 @@
+//! Helpers for code generation that need struct layout
+
+use super::helpers;
+
+use crate::ir::comp::CompInfo;
+use crate::ir::context::BindgenContext;
+use crate::ir::layout::Layout;
+use crate::ir::ty::{Type, TypeKind};
+use crate::FieldVisibilityKind;
+use proc_macro2::{self, Ident, Span};
+use std::cmp;
+
+const MAX_GUARANTEED_ALIGN: usize = 8;
+
+/// Trace the layout of struct.
+#[derive(Debug)]
+pub(crate) struct StructLayoutTracker<'a> {
+ name: &'a str,
+ ctx: &'a BindgenContext,
+ comp: &'a CompInfo,
+ is_packed: bool,
+ known_type_layout: Option<Layout>,
+ is_rust_union: bool,
+ can_copy_union_fields: bool,
+ latest_offset: usize,
+ padding_count: usize,
+ latest_field_layout: Option<Layout>,
+ max_field_align: usize,
+ last_field_was_bitfield: bool,
+ visibility: FieldVisibilityKind,
+}
+
+/// Returns a size aligned to a given value.
+pub(crate) fn align_to(size: usize, align: usize) -> usize {
+ if align == 0 {
+ return size;
+ }
+
+ let rem = size % align;
+ if rem == 0 {
+ return size;
+ }
+
+ size + align - rem
+}
+
+/// Returns the lower power of two byte count that can hold at most n bits.
+pub(crate) fn bytes_from_bits_pow2(mut n: usize) -> usize {
+ if n == 0 {
+ return 0;
+ }
+
+ if n <= 8 {
+ return 1;
+ }
+
+ if !n.is_power_of_two() {
+ n = n.next_power_of_two();
+ }
+
+ n / 8
+}
+
+#[test]
+fn test_align_to() {
+ assert_eq!(align_to(1, 1), 1);
+ assert_eq!(align_to(1, 2), 2);
+ assert_eq!(align_to(1, 4), 4);
+ assert_eq!(align_to(5, 1), 5);
+ assert_eq!(align_to(17, 4), 20);
+}
+
+#[test]
+fn test_bytes_from_bits_pow2() {
+ assert_eq!(bytes_from_bits_pow2(0), 0);
+ for i in 1..9 {
+ assert_eq!(bytes_from_bits_pow2(i), 1);
+ }
+ for i in 9..17 {
+ assert_eq!(bytes_from_bits_pow2(i), 2);
+ }
+ for i in 17..33 {
+ assert_eq!(bytes_from_bits_pow2(i), 4);
+ }
+}
+
+impl<'a> StructLayoutTracker<'a> {
+ pub(crate) fn new(
+ ctx: &'a BindgenContext,
+ comp: &'a CompInfo,
+ ty: &'a Type,
+ name: &'a str,
+ visibility: FieldVisibilityKind,
+ is_packed: bool,
+ ) -> Self {
+ let known_type_layout = ty.layout(ctx);
+ let (is_rust_union, can_copy_union_fields) =
+ comp.is_rust_union(ctx, known_type_layout.as_ref(), name);
+ StructLayoutTracker {
+ name,
+ ctx,
+ comp,
+ visibility,
+ is_packed,
+ known_type_layout,
+ is_rust_union,
+ can_copy_union_fields,
+ latest_offset: 0,
+ padding_count: 0,
+ latest_field_layout: None,
+ max_field_align: 0,
+ last_field_was_bitfield: false,
+ }
+ }
+
+ pub(crate) fn can_copy_union_fields(&self) -> bool {
+ self.can_copy_union_fields
+ }
+
+ pub(crate) fn is_rust_union(&self) -> bool {
+ self.is_rust_union
+ }
+
+ pub(crate) fn saw_vtable(&mut self) {
+ debug!("saw vtable for {}", self.name);
+
+ let ptr_size = self.ctx.target_pointer_size();
+ self.latest_offset += ptr_size;
+ self.latest_field_layout = Some(Layout::new(ptr_size, ptr_size));
+ self.max_field_align = ptr_size;
+ }
+
+ pub(crate) fn saw_base(&mut self, base_ty: &Type) {
+ debug!("saw base for {}", self.name);
+ if let Some(layout) = base_ty.layout(self.ctx) {
+ self.align_to_latest_field(layout);
+
+ self.latest_offset += self.padding_bytes(layout) + layout.size;
+ self.latest_field_layout = Some(layout);
+ self.max_field_align = cmp::max(self.max_field_align, layout.align);
+ }
+ }
+
+ pub(crate) fn saw_bitfield_unit(&mut self, layout: Layout) {
+ debug!("saw bitfield unit for {}: {:?}", self.name, layout);
+
+ self.align_to_latest_field(layout);
+
+ self.latest_offset += layout.size;
+
+ debug!(
+ "Offset: <bitfield>: {} -> {}",
+ self.latest_offset - layout.size,
+ self.latest_offset
+ );
+
+ self.latest_field_layout = Some(layout);
+ self.last_field_was_bitfield = true;
+ self.max_field_align = cmp::max(self.max_field_align, layout.align);
+ }
+
+ /// Returns a padding field if necessary for a given new field _before_
+ /// adding that field.
+ pub(crate) fn saw_field(
+ &mut self,
+ field_name: &str,
+ field_ty: &Type,
+ field_offset: Option<usize>,
+ ) -> Option<proc_macro2::TokenStream> {
+ let mut field_layout = field_ty.layout(self.ctx)?;
+
+ if let TypeKind::Array(inner, len) =
+ *field_ty.canonical_type(self.ctx).kind()
+ {
+ // FIXME(emilio): As an _ultra_ hack, we correct the layout returned
+ // by arrays of structs that have a bigger alignment than what we
+ // can support.
+ //
+ // This means that the structs in the array are super-unsafe to
+ // access, since they won't be properly aligned, but there's not too
+ // much we can do about it.
+ if let Some(layout) = self.ctx.resolve_type(inner).layout(self.ctx)
+ {
+ if layout.align > MAX_GUARANTEED_ALIGN {
+ field_layout.size =
+ align_to(layout.size, layout.align) * len;
+ field_layout.align = MAX_GUARANTEED_ALIGN;
+ }
+ }
+ }
+ self.saw_field_with_layout(field_name, field_layout, field_offset)
+ }
+
+ pub(crate) fn saw_field_with_layout(
+ &mut self,
+ field_name: &str,
+ field_layout: Layout,
+ field_offset: Option<usize>,
+ ) -> Option<proc_macro2::TokenStream> {
+ let will_merge_with_bitfield = self.align_to_latest_field(field_layout);
+
+ let is_union = self.comp.is_union();
+ let padding_bytes = match field_offset {
+ Some(offset) if offset / 8 > self.latest_offset => {
+ offset / 8 - self.latest_offset
+ }
+ _ => {
+ if will_merge_with_bitfield ||
+ field_layout.align == 0 ||
+ is_union
+ {
+ 0
+ } else if !self.is_packed {
+ self.padding_bytes(field_layout)
+ } else if let Some(mut l) = self.known_type_layout {
+ if field_layout.align < l.align {
+ l.align = field_layout.align;
+ }
+ self.padding_bytes(l)
+ } else {
+ 0
+ }
+ }
+ };
+
+ self.latest_offset += padding_bytes;
+
+ let padding_layout = if self.is_packed || is_union {
+ None
+ } else {
+ let force_padding = self.ctx.options().force_explicit_padding;
+
+ // Otherwise the padding is useless.
+ let need_padding = force_padding ||
+ padding_bytes >= field_layout.align ||
+ field_layout.align > MAX_GUARANTEED_ALIGN;
+
+ debug!(
+ "Offset: <padding>: {} -> {}",
+ self.latest_offset - padding_bytes,
+ self.latest_offset
+ );
+
+ debug!(
+ "align field {} to {}/{} with {} padding bytes {:?}",
+ field_name,
+ self.latest_offset,
+ field_offset.unwrap_or(0) / 8,
+ padding_bytes,
+ field_layout
+ );
+
+ let padding_align = if force_padding {
+ 1
+ } else {
+ cmp::min(field_layout.align, MAX_GUARANTEED_ALIGN)
+ };
+
+ if need_padding && padding_bytes != 0 {
+ Some(Layout::new(padding_bytes, padding_align))
+ } else {
+ None
+ }
+ };
+
+ self.latest_offset += field_layout.size;
+ self.latest_field_layout = Some(field_layout);
+ self.max_field_align =
+ cmp::max(self.max_field_align, field_layout.align);
+ self.last_field_was_bitfield = false;
+
+ debug!(
+ "Offset: {}: {} -> {}",
+ field_name,
+ self.latest_offset - field_layout.size,
+ self.latest_offset
+ );
+
+ padding_layout.map(|layout| self.padding_field(layout))
+ }
+
+ pub(crate) fn add_tail_padding(
+ &mut self,
+ comp_name: &str,
+ comp_layout: Layout,
+ ) -> Option<proc_macro2::TokenStream> {
+ // Only emit an padding field at the end of a struct if the
+ // user configures explicit padding.
+ if !self.ctx.options().force_explicit_padding {
+ return None;
+ }
+
+ // Padding doesn't make sense for rust unions.
+ if self.is_rust_union {
+ return None;
+ }
+
+ if self.latest_offset == comp_layout.size {
+ // This struct does not contain tail padding.
+ return None;
+ }
+
+ trace!(
+ "need a tail padding field for {}: offset {} -> size {}",
+ comp_name,
+ self.latest_offset,
+ comp_layout.size
+ );
+ let size = comp_layout.size - self.latest_offset;
+ Some(self.padding_field(Layout::new(size, 0)))
+ }
+
+ pub(crate) fn pad_struct(
+ &mut self,
+ layout: Layout,
+ ) -> Option<proc_macro2::TokenStream> {
+ debug!(
+ "pad_struct:\n\tself = {:#?}\n\tlayout = {:#?}",
+ self, layout
+ );
+
+ if layout.size < self.latest_offset {
+ warn!(
+ "Calculated wrong layout for {}, too more {} bytes",
+ self.name,
+ self.latest_offset - layout.size
+ );
+ return None;
+ }
+
+ let padding_bytes = layout.size - self.latest_offset;
+ if padding_bytes == 0 {
+ return None;
+ }
+
+ let repr_align = self.ctx.options().rust_features().repr_align;
+
+ // We always pad to get to the correct size if the struct is one of
+ // those we can't align properly.
+ //
+ // Note that if the last field we saw was a bitfield, we may need to pad
+ // regardless, because bitfields don't respect alignment as strictly as
+ // other fields.
+ if padding_bytes >= layout.align ||
+ (self.last_field_was_bitfield &&
+ padding_bytes >= self.latest_field_layout.unwrap().align) ||
+ (!repr_align && layout.align > MAX_GUARANTEED_ALIGN)
+ {
+ let layout = if self.is_packed {
+ Layout::new(padding_bytes, 1)
+ } else if self.last_field_was_bitfield ||
+ layout.align > MAX_GUARANTEED_ALIGN
+ {
+ // We've already given up on alignment here.
+ Layout::for_size(self.ctx, padding_bytes)
+ } else {
+ Layout::new(padding_bytes, layout.align)
+ };
+
+ debug!("pad bytes to struct {}, {:?}", self.name, layout);
+
+ Some(self.padding_field(layout))
+ } else {
+ None
+ }
+ }
+
+ pub(crate) 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);
+
+ let vis = super::access_specifier(self.visibility);
+
+ quote! {
+ #vis #padding_field_name : #ty ,
+ }
+ }
+
+ /// Returns whether the new field is known to merge with a bitfield.
+ ///
+ /// This is just to avoid doing the same check also in pad_field.
+ fn align_to_latest_field(&mut self, new_field_layout: Layout) -> bool {
+ if self.is_packed {
+ // Skip to align fields when packed.
+ return false;
+ }
+
+ let layout = match self.latest_field_layout {
+ Some(l) => l,
+ None => return false,
+ };
+
+ // If it was, we may or may not need to align, depending on what the
+ // current field alignment and the bitfield size and alignment are.
+ debug!(
+ "align_to_bitfield? {}: {:?} {:?}",
+ self.last_field_was_bitfield, layout, new_field_layout
+ );
+
+ // Avoid divide-by-zero errors if align is 0.
+ let align = cmp::max(1, layout.align);
+
+ if self.last_field_was_bitfield &&
+ new_field_layout.align <= layout.size % align &&
+ new_field_layout.size <= layout.size % align
+ {
+ // The new field will be coalesced into some of the remaining bits.
+ //
+ // FIXME(emilio): I think this may not catch everything?
+ debug!("Will merge with bitfield");
+ return true;
+ }
+
+ // Else, just align the obvious way.
+ self.latest_offset += self.padding_bytes(layout);
+ false
+ }
+}
diff --git a/third_party/rust/bindgen/deps.rs b/third_party/rust/bindgen/deps.rs
new file mode 100644
index 0000000000..be31f92896
--- /dev/null
+++ b/third_party/rust/bindgen/deps.rs
@@ -0,0 +1,61 @@
+/// Generating build depfiles from parsed bindings.
+use std::{collections::BTreeSet, path::PathBuf};
+
+#[derive(Clone, Debug)]
+pub(crate) struct DepfileSpec {
+ pub output_module: String,
+ pub depfile_path: PathBuf,
+}
+
+impl DepfileSpec {
+ pub fn write(&self, deps: &BTreeSet<Box<str>>) -> std::io::Result<()> {
+ std::fs::write(&self.depfile_path, self.to_string(deps))
+ }
+
+ fn to_string(&self, deps: &BTreeSet<Box<str>>) -> String {
+ // Transforms a string by escaping spaces and backslashes.
+ let escape = |s: &str| s.replace('\\', "\\\\").replace(' ', "\\ ");
+
+ let mut buf = format!("{}:", escape(&self.output_module));
+ for file in deps {
+ buf = format!("{} {}", buf, escape(file));
+ }
+ buf
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn escaping_depfile() {
+ let spec = DepfileSpec {
+ output_module: "Mod Name".to_owned(),
+ depfile_path: PathBuf::new(),
+ };
+
+ let deps: BTreeSet<_> = vec![
+ r"/absolute/path".into(),
+ r"C:\win\absolute\path".into(),
+ r"../relative/path".into(),
+ r"..\win\relative\path".into(),
+ r"../path/with spaces/in/it".into(),
+ r"..\win\path\with spaces\in\it".into(),
+ r"path\with/mixed\separators".into(),
+ ]
+ .into_iter()
+ .collect();
+ assert_eq!(
+ spec.to_string(&deps),
+ "Mod\\ Name: \
+ ../path/with\\ spaces/in/it \
+ ../relative/path \
+ ..\\\\win\\\\path\\\\with\\ spaces\\\\in\\\\it \
+ ..\\\\win\\\\relative\\\\path \
+ /absolute/path \
+ C:\\\\win\\\\absolute\\\\path \
+ path\\\\with/mixed\\\\separators"
+ );
+ }
+}
diff --git a/third_party/rust/bindgen/diagnostics.rs b/third_party/rust/bindgen/diagnostics.rs
new file mode 100644
index 0000000000..f765afe970
--- /dev/null
+++ b/third_party/rust/bindgen/diagnostics.rs
@@ -0,0 +1,189 @@
+//! Types and function used to emit pretty diagnostics for `bindgen`.
+//!
+//! The entry point of this module is the [`Diagnostic`] type.
+
+use std::fmt::Write;
+use std::io::{self, BufRead, BufReader};
+use std::{borrow::Cow, fs::File};
+
+use annotate_snippets::{
+ display_list::{DisplayList, FormatOptions},
+ snippet::{Annotation, Slice as ExtSlice, Snippet},
+};
+
+use annotate_snippets::snippet::AnnotationType;
+
+#[derive(Clone, Copy, Debug)]
+pub(crate) enum Level {
+ Error,
+ Warn,
+ Info,
+ Note,
+ Help,
+}
+
+impl From<Level> for AnnotationType {
+ fn from(level: Level) -> Self {
+ match level {
+ Level::Error => Self::Error,
+ Level::Warn => Self::Warning,
+ Level::Info => Self::Info,
+ Level::Note => Self::Note,
+ Level::Help => Self::Help,
+ }
+ }
+}
+
+/// A `bindgen` diagnostic.
+#[derive(Default)]
+pub(crate) struct Diagnostic<'a> {
+ title: Option<(Cow<'a, str>, Level)>,
+ slices: Vec<Slice<'a>>,
+ footer: Vec<(Cow<'a, str>, Level)>,
+}
+
+impl<'a> Diagnostic<'a> {
+ /// Add a title to the diagnostic and set its type.
+ pub(crate) fn with_title(
+ &mut self,
+ title: impl Into<Cow<'a, str>>,
+ level: Level,
+ ) -> &mut Self {
+ self.title = Some((title.into(), level));
+ self
+ }
+
+ /// Add a slice of source code to the diagnostic.
+ pub(crate) fn add_slice(&mut self, slice: Slice<'a>) -> &mut Self {
+ self.slices.push(slice);
+ self
+ }
+
+ /// Add a footer annotation to the diagnostic. This annotation will have its own type.
+ pub(crate) fn add_annotation(
+ &mut self,
+ msg: impl Into<Cow<'a, str>>,
+ level: Level,
+ ) -> &mut Self {
+ self.footer.push((msg.into(), level));
+ self
+ }
+
+ /// Print this diagnostic.
+ ///
+ /// The diagnostic is printed using `cargo:warning` if `bindgen` is being invoked by a build
+ /// script or using `eprintln` otherwise.
+ pub(crate) fn display(&self) {
+ std::thread_local! {
+ static INVOKED_BY_BUILD_SCRIPT: bool = std::env::var_os("CARGO_CFG_TARGET_ARCH").is_some();
+ }
+
+ let mut title = None;
+ let mut footer = vec![];
+ let mut slices = vec![];
+ if let Some((msg, level)) = &self.title {
+ title = Some(Annotation {
+ id: Some("bindgen"),
+ label: Some(msg.as_ref()),
+ annotation_type: (*level).into(),
+ })
+ }
+
+ for (msg, level) in &self.footer {
+ footer.push(Annotation {
+ id: None,
+ label: Some(msg.as_ref()),
+ annotation_type: (*level).into(),
+ });
+ }
+
+ // add additional info that this is generated by bindgen
+ // so as to not confuse with rustc warnings
+ footer.push(Annotation {
+ id: None,
+ label: Some("This diagnostic was generated by bindgen."),
+ annotation_type: AnnotationType::Info,
+ });
+
+ for slice in &self.slices {
+ if let Some(source) = &slice.source {
+ slices.push(ExtSlice {
+ source: source.as_ref(),
+ line_start: slice.line.unwrap_or_default(),
+ origin: slice.filename.as_deref(),
+ annotations: vec![],
+ fold: false,
+ })
+ }
+ }
+
+ let snippet = Snippet {
+ title,
+ footer,
+ slices,
+ opt: FormatOptions {
+ color: true,
+ ..Default::default()
+ },
+ };
+ let dl = DisplayList::from(snippet);
+
+ if INVOKED_BY_BUILD_SCRIPT.with(Clone::clone) {
+ // This is just a hack which hides the `warning:` added by cargo at the beginning of
+ // every line. This should be fine as our diagnostics already have a colorful title.
+ // FIXME (pvdrz): Could it be that this doesn't work in other languages?
+ let hide_warning = "\r \r";
+ let string = dl.to_string();
+ for line in string.lines() {
+ println!("cargo:warning={}{}", hide_warning, line);
+ }
+ } else {
+ eprintln!("{}\n", dl);
+ }
+ }
+}
+
+/// A slice of source code.
+#[derive(Default)]
+pub(crate) struct Slice<'a> {
+ source: Option<Cow<'a, str>>,
+ filename: Option<String>,
+ line: Option<usize>,
+}
+
+impl<'a> Slice<'a> {
+ /// Set the source code.
+ pub(crate) fn with_source(
+ &mut self,
+ source: impl Into<Cow<'a, str>>,
+ ) -> &mut Self {
+ self.source = Some(source.into());
+ self
+ }
+
+ /// Set the file, line and column.
+ pub(crate) fn with_location(
+ &mut self,
+ mut name: String,
+ line: usize,
+ col: usize,
+ ) -> &mut Self {
+ write!(name, ":{}:{}", line, col)
+ .expect("Writing to a string cannot fail");
+ self.filename = Some(name);
+ self.line = Some(line);
+ self
+ }
+}
+
+pub(crate) fn get_line(
+ filename: &str,
+ line: usize,
+) -> io::Result<Option<String>> {
+ let file = BufReader::new(File::open(filename)?);
+ if let Some(line) = file.lines().nth(line.wrapping_sub(1)) {
+ return line.map(Some);
+ }
+
+ Ok(None)
+}
diff --git a/third_party/rust/bindgen/extra_assertions.rs b/third_party/rust/bindgen/extra_assertions.rs
new file mode 100644
index 0000000000..fbddad7825
--- /dev/null
+++ b/third_party/rust/bindgen/extra_assertions.rs
@@ -0,0 +1,17 @@
+//! Macros for defining extra assertions that should only be checked in testing
+//! and/or CI when the `__testing_only_extra_assertions` feature is enabled.
+
+/// Simple macro that forwards to assert! when using
+/// __testing_only_extra_assertions.
+macro_rules! extra_assert {
+ ( $cond:expr ) => {
+ if cfg!(feature = "__testing_only_extra_assertions") {
+ assert!($cond);
+ }
+ };
+ ( $cond:expr , $( $arg:tt )+ ) => {
+ if cfg!(feature = "__testing_only_extra_assertions") {
+ assert!($cond, $( $arg )* )
+ }
+ };
+}
diff --git a/third_party/rust/bindgen/features.rs b/third_party/rust/bindgen/features.rs
new file mode 100644
index 0000000000..e5e2068053
--- /dev/null
+++ b/third_party/rust/bindgen/features.rs
@@ -0,0 +1,296 @@
+//! Contains code for selecting features
+
+#![deny(unused_extern_crates)]
+#![deny(clippy::missing_docs_in_private_items)]
+#![allow(deprecated)]
+
+use std::cmp::Ordering;
+use std::io;
+use std::str::FromStr;
+
+/// This macro defines the [`RustTarget`] and [`RustFeatures`] types.
+macro_rules! define_rust_targets {
+ (
+ Nightly => {$($nightly_feature:ident $(: #$issue:literal)?),* $(,)?} $(,)?
+ $(
+ $(#[$attrs:meta])*
+ $variant:ident($minor:literal) => {$($feature:ident $(: #$pull:literal)?),* $(,)?},
+ )*
+ $(,)?
+ ) => {
+ /// 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.
+ #[allow(non_camel_case_types)]
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+ pub enum RustTarget {
+ /// Rust Nightly
+ $(#[doc = concat!(
+ "- [`", stringify!($nightly_feature), "`]",
+ "(", $("https://github.com/rust-lang/rust/pull/", stringify!($issue),)* ")",
+ )])*
+ Nightly,
+ $(
+ #[doc = concat!("Rust 1.", stringify!($minor))]
+ $(#[doc = concat!(
+ "- [`", stringify!($feature), "`]",
+ "(", $("https://github.com/rust-lang/rust/pull/", stringify!($pull),)* ")",
+ )])*
+ $(#[$attrs])*
+ $variant,
+ )*
+ }
+
+ impl RustTarget {
+ fn minor(self) -> Option<u64> {
+ match self {
+ $( Self::$variant => Some($minor),)*
+ Self::Nightly => None
+ }
+ }
+
+ const fn stable_releases() -> [(Self, u64); [$($minor,)*].len()] {
+ [$((Self::$variant, $minor),)*]
+ }
+ }
+
+ #[cfg(feature = "__cli")]
+ /// Strings of allowed `RustTarget` values
+ pub const RUST_TARGET_STRINGS: &[&str] = &[$(concat!("1.", stringify!($minor)),)*];
+
+ #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+ pub(crate) struct RustFeatures {
+ $($(pub(crate) $feature: bool,)*)*
+ $(pub(crate) $nightly_feature: bool,)*
+ }
+
+ impl From<RustTarget> for RustFeatures {
+ fn from(target: RustTarget) -> Self {
+ if target == RustTarget::Nightly {
+ return Self {
+ $($($feature: true,)*)*
+ $($nightly_feature: true,)*
+ };
+ }
+
+ let mut features = Self {
+ $($($feature: false,)*)*
+ $($nightly_feature: false,)*
+ };
+
+ $(if target >= RustTarget::$variant {
+ $(features.$feature = true;)*
+ })*
+
+ features
+ }
+ }
+ };
+}
+
+// NOTE: When adding or removing features here, make sure to add the stabilization PR
+// number for the feature if it has been stabilized or the tracking issue number if the feature is
+// not stable.
+define_rust_targets! {
+ Nightly => {
+ vectorcall_abi,
+ },
+ Stable_1_73(73) => { thiscall_abi: #42202 },
+ Stable_1_71(71) => { c_unwind_abi: #106075 },
+ Stable_1_68(68) => { abi_efiapi: #105795 },
+ Stable_1_64(64) => { core_ffi_c: #94503 },
+ Stable_1_59(59) => { const_cstr: #54745 },
+ Stable_1_47(47) => { larger_arrays: #74060 },
+ Stable_1_40(40) => { non_exhaustive: #44109 },
+ Stable_1_36(36) => { maybe_uninit: #60445 },
+ Stable_1_33(33) => { repr_packed_n: #57049 },
+ #[deprecated]
+ Stable_1_30(30) => {
+ core_ffi_c_void: #53910,
+ min_const_fn: #54835,
+ },
+ #[deprecated]
+ Stable_1_28(28) => { repr_transparent: #51562 },
+ #[deprecated]
+ Stable_1_27(27) => { must_use_function: #48925 },
+ #[deprecated]
+ Stable_1_26(26) => { i128_and_u128: #49101 },
+ #[deprecated]
+ Stable_1_25(25) => { repr_align: #47006 },
+ #[deprecated]
+ Stable_1_21(21) => { builtin_clone_impls: #43690 },
+ #[deprecated]
+ Stable_1_20(20) => { associated_const: #42809 },
+ #[deprecated]
+ Stable_1_19(19) => { untagged_union: #42068 },
+ #[deprecated]
+ Stable_1_17(17) => { static_lifetime_elision: #39265 },
+ #[deprecated]
+ Stable_1_0(0) => {},
+}
+
+/// Latest stable release of Rust
+pub const LATEST_STABLE_RUST: RustTarget = {
+ // FIXME: replace all this code by
+ // ```
+ // RustTarget::stable_releases()
+ // .into_iter()
+ // .max_by_key(|(_, m)| m)
+ // .map(|(t, _)| t)
+ // .unwrap_or(RustTarget::Nightly)
+ // ```
+ // once those operations can be used in constants.
+ let targets = RustTarget::stable_releases();
+
+ let mut i = 0;
+ let mut latest_target = None;
+ let mut latest_minor = 0;
+
+ while i < targets.len() {
+ let (target, minor) = targets[i];
+
+ if latest_minor < minor {
+ latest_minor = minor;
+ latest_target = Some(target);
+ }
+
+ i += 1;
+ }
+
+ match latest_target {
+ Some(target) => target,
+ None => unreachable!(),
+ }
+};
+
+impl Default for RustTarget {
+ fn default() -> Self {
+ LATEST_STABLE_RUST
+ }
+}
+
+impl PartialOrd for RustTarget {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for RustTarget {
+ fn cmp(&self, other: &Self) -> Ordering {
+ match (self.minor(), other.minor()) {
+ (Some(a), Some(b)) => a.cmp(&b),
+ (Some(_), None) => Ordering::Less,
+ (None, Some(_)) => Ordering::Greater,
+ (None, None) => Ordering::Equal,
+ }
+ }
+}
+
+impl FromStr for RustTarget {
+ type Err = io::Error;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ if s == "nightly" {
+ return Ok(Self::Nightly);
+ }
+
+ if let Some(("1", str_minor)) = s.split_once('.') {
+ if let Ok(minor) = str_minor.parse::<u64>() {
+ for (target, target_minor) in Self::stable_releases() {
+ if minor == target_minor {
+ return Ok(target);
+ }
+ }
+ }
+ }
+
+ Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "Got an invalid Rust target. Accepted values are of the form \"1.71\" or \"nightly\"."
+ ))
+ }
+}
+
+impl std::fmt::Display for RustTarget {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self.minor() {
+ Some(minor) => write!(f, "1.{}", minor),
+ None => "nightly".fmt(f),
+ }
+ }
+}
+
+impl Default for RustFeatures {
+ fn default() -> Self {
+ RustTarget::default().into()
+ }
+}
+
+#[cfg(test)]
+mod test {
+ #![allow(unused_imports)]
+ use super::*;
+
+ #[test]
+ fn target_features() {
+ let f_1_0 = RustFeatures::from(RustTarget::Stable_1_0);
+ assert!(
+ !f_1_0.static_lifetime_elision &&
+ !f_1_0.core_ffi_c_void &&
+ !f_1_0.untagged_union &&
+ !f_1_0.associated_const &&
+ !f_1_0.builtin_clone_impls &&
+ !f_1_0.repr_align &&
+ !f_1_0.thiscall_abi &&
+ !f_1_0.vectorcall_abi
+ );
+ let f_1_21 = RustFeatures::from(RustTarget::Stable_1_21);
+ assert!(
+ f_1_21.static_lifetime_elision &&
+ !f_1_21.core_ffi_c_void &&
+ f_1_21.untagged_union &&
+ f_1_21.associated_const &&
+ f_1_21.builtin_clone_impls &&
+ !f_1_21.repr_align &&
+ !f_1_21.thiscall_abi &&
+ !f_1_21.vectorcall_abi
+ );
+ let features = RustFeatures::from(RustTarget::Stable_1_71);
+ assert!(
+ features.c_unwind_abi &&
+ features.abi_efiapi &&
+ !features.thiscall_abi
+ );
+ let f_nightly = RustFeatures::from(RustTarget::Nightly);
+ assert!(
+ f_nightly.static_lifetime_elision &&
+ f_nightly.core_ffi_c_void &&
+ f_nightly.untagged_union &&
+ f_nightly.associated_const &&
+ f_nightly.builtin_clone_impls &&
+ f_nightly.maybe_uninit &&
+ f_nightly.repr_align &&
+ f_nightly.thiscall_abi &&
+ f_nightly.vectorcall_abi
+ );
+ }
+
+ fn test_target(target_str: &str, target: RustTarget) {
+ let target_string = target.to_string();
+ assert_eq!(target_str, target_string);
+ assert_eq!(target, RustTarget::from_str(target_str).unwrap());
+ }
+
+ #[test]
+ fn str_to_target() {
+ test_target("1.0", RustTarget::Stable_1_0);
+ test_target("1.17", RustTarget::Stable_1_17);
+ test_target("1.19", RustTarget::Stable_1_19);
+ test_target("1.21", RustTarget::Stable_1_21);
+ test_target("1.25", RustTarget::Stable_1_25);
+ test_target("1.71", RustTarget::Stable_1_71);
+ test_target("nightly", RustTarget::Nightly);
+ }
+}
diff --git a/third_party/rust/bindgen/ir/analysis/derive.rs b/third_party/rust/bindgen/ir/analysis/derive.rs
new file mode 100644
index 0000000000..d8d29ed9a8
--- /dev/null
+++ b/third_party/rust/bindgen/ir/analysis/derive.rs
@@ -0,0 +1,732 @@
+//! Determining which types for which we cannot emit `#[derive(Trait)]`.
+
+use std::fmt;
+
+use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
+use crate::ir::analysis::has_vtable::HasVtable;
+use crate::ir::comp::CompKind;
+use crate::ir::context::{BindgenContext, ItemId};
+use crate::ir::derive::CanDerive;
+use crate::ir::function::FunctionSig;
+use crate::ir::item::{IsOpaque, Item};
+use crate::ir::layout::Layout;
+use crate::ir::template::TemplateParameters;
+use crate::ir::traversal::{EdgeKind, Trace};
+use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
+use crate::ir::ty::{Type, TypeKind};
+use crate::{Entry, HashMap, HashSet};
+
+/// Which trait to consider when doing the `CannotDerive` analysis.
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub enum DeriveTrait {
+ /// The `Copy` trait.
+ Copy,
+ /// The `Debug` trait.
+ Debug,
+ /// The `Default` trait.
+ Default,
+ /// The `Hash` trait.
+ Hash,
+ /// The `PartialEq` and `PartialOrd` traits.
+ PartialEqOrPartialOrd,
+}
+
+/// An analysis that finds for each IR item whether a trait cannot be derived.
+///
+/// We use the monotone constraint function `cannot_derive`, defined as follows
+/// for type T:
+///
+/// * If T is Opaque and the layout of the type is known, get this layout as an
+/// opaquetype and check whether it can derive using trivial checks.
+///
+/// * If T is Array, a trait cannot be derived if the array is incomplete,
+/// if the length of the array is larger than the limit (unless the trait
+/// allows it), or the trait cannot be derived for the type of data the array
+/// contains.
+///
+/// * If T is Vector, a trait cannot be derived if the trait cannot be derived
+/// for the type of data the vector contains.
+///
+/// * If T is a type alias, a templated alias or an indirection to another type,
+/// the trait cannot be derived if the trait cannot be derived for type T
+/// refers to.
+///
+/// * If T is a compound type, the trait cannot be derived if the trait cannot
+/// be derived for any of its base members or fields.
+///
+/// * If T is an instantiation of an abstract template definition, the trait
+/// cannot be derived if any of the template arguments or template definition
+/// cannot derive the trait.
+///
+/// * For all other (simple) types, compiler and standard library limitations
+/// dictate whether the trait is implemented.
+#[derive(Debug, Clone)]
+pub(crate) struct CannotDerive<'ctx> {
+ ctx: &'ctx BindgenContext,
+
+ derive_trait: DeriveTrait,
+
+ // The incremental result of this analysis's computation.
+ // Contains information whether particular item can derive `derive_trait`
+ can_derive: HashMap<ItemId, CanDerive>,
+
+ // Dependencies saying that if a key ItemId has been inserted into the
+ // `cannot_derive_partialeq_or_partialord` set, then each of the ids
+ // in Vec<ItemId> need to be considered again.
+ //
+ // This is a subset of the natural IR graph with reversed edges, where we
+ // only include the edges from the IR graph that can affect whether a type
+ // can derive `derive_trait`.
+ dependencies: HashMap<ItemId, Vec<ItemId>>,
+}
+
+type EdgePredicate = fn(EdgeKind) -> bool;
+
+fn consider_edge_default(kind: EdgeKind) -> bool {
+ match kind {
+ // These are the only edges that can affect whether a type can derive
+ EdgeKind::BaseMember |
+ EdgeKind::Field |
+ EdgeKind::TypeReference |
+ EdgeKind::VarType |
+ EdgeKind::TemplateArgument |
+ EdgeKind::TemplateDeclaration |
+ EdgeKind::TemplateParameterDefinition => true,
+
+ EdgeKind::Constructor |
+ EdgeKind::Destructor |
+ EdgeKind::FunctionReturn |
+ EdgeKind::FunctionParameter |
+ EdgeKind::InnerType |
+ EdgeKind::InnerVar |
+ EdgeKind::Method |
+ EdgeKind::Generic => false,
+ }
+}
+
+impl<'ctx> CannotDerive<'ctx> {
+ fn insert<Id: Into<ItemId>>(
+ &mut self,
+ id: Id,
+ can_derive: CanDerive,
+ ) -> ConstrainResult {
+ let id = id.into();
+ trace!(
+ "inserting {:?} can_derive<{}>={:?}",
+ id,
+ self.derive_trait,
+ can_derive
+ );
+
+ if let CanDerive::Yes = can_derive {
+ return ConstrainResult::Same;
+ }
+
+ match self.can_derive.entry(id) {
+ Entry::Occupied(mut entry) => {
+ if *entry.get() < can_derive {
+ entry.insert(can_derive);
+ ConstrainResult::Changed
+ } else {
+ ConstrainResult::Same
+ }
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(can_derive);
+ ConstrainResult::Changed
+ }
+ }
+ }
+
+ fn constrain_type(&mut self, item: &Item, ty: &Type) -> CanDerive {
+ if !self.ctx.allowlisted_items().contains(&item.id()) {
+ let can_derive = self
+ .ctx
+ .blocklisted_type_implements_trait(item, self.derive_trait);
+ match can_derive {
+ CanDerive::Yes => trace!(
+ " blocklisted type explicitly implements {}",
+ self.derive_trait
+ ),
+ CanDerive::Manually => trace!(
+ " blocklisted type requires manual implementation of {}",
+ self.derive_trait
+ ),
+ CanDerive::No => trace!(
+ " cannot derive {} for blocklisted type",
+ self.derive_trait
+ ),
+ }
+ return can_derive;
+ }
+
+ if self.derive_trait.not_by_name(self.ctx, item) {
+ trace!(
+ " cannot derive {} for explicitly excluded type",
+ self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ trace!("ty: {:?}", ty);
+ if item.is_opaque(self.ctx, &()) {
+ if !self.derive_trait.can_derive_union() &&
+ ty.is_union() &&
+ self.ctx.options().untagged_union
+ {
+ trace!(
+ " cannot derive {} for Rust unions",
+ self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ let layout_can_derive =
+ ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
+ l.opaque().array_size_within_derive_limit(self.ctx)
+ });
+
+ match layout_can_derive {
+ CanDerive::Yes => {
+ trace!(
+ " we can trivially derive {} for the layout",
+ self.derive_trait
+ );
+ }
+ _ => {
+ trace!(
+ " we cannot derive {} for the layout",
+ self.derive_trait
+ );
+ }
+ };
+ return layout_can_derive;
+ }
+
+ match *ty.kind() {
+ // Handle the simple cases. These can derive traits without further
+ // information.
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Float(..) |
+ TypeKind::Enum(..) |
+ TypeKind::TypeParam |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::Reference(..) |
+ TypeKind::ObjCInterface(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel => {
+ return self.derive_trait.can_derive_simple(ty.kind());
+ }
+ TypeKind::Pointer(inner) => {
+ let inner_type =
+ self.ctx.resolve_type(inner).canonical_type(self.ctx);
+ if let TypeKind::Function(ref sig) = *inner_type.kind() {
+ self.derive_trait.can_derive_fnptr(sig)
+ } else {
+ self.derive_trait.can_derive_pointer()
+ }
+ }
+ TypeKind::Function(ref sig) => {
+ self.derive_trait.can_derive_fnptr(sig)
+ }
+
+ // Complex cases need more information
+ TypeKind::Array(t, len) => {
+ let inner_type =
+ self.can_derive.get(&t.into()).cloned().unwrap_or_default();
+ if inner_type != CanDerive::Yes {
+ trace!(
+ " arrays of T for which we cannot derive {} \
+ also cannot derive {}",
+ self.derive_trait,
+ self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ if len == 0 && !self.derive_trait.can_derive_incomplete_array()
+ {
+ trace!(
+ " cannot derive {} for incomplete arrays",
+ self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ if self.derive_trait.can_derive_large_array(self.ctx) {
+ trace!(" array can derive {}", self.derive_trait);
+ return CanDerive::Yes;
+ }
+
+ if len > RUST_DERIVE_IN_ARRAY_LIMIT {
+ trace!(
+ " array is too large to derive {}, but it may be implemented", self.derive_trait
+ );
+ return CanDerive::Manually;
+ }
+ trace!(
+ " array is small enough to derive {}",
+ self.derive_trait
+ );
+ CanDerive::Yes
+ }
+ TypeKind::Vector(t, len) => {
+ let inner_type =
+ self.can_derive.get(&t.into()).cloned().unwrap_or_default();
+ if inner_type != CanDerive::Yes {
+ trace!(
+ " vectors of T for which we cannot derive {} \
+ also cannot derive {}",
+ self.derive_trait,
+ self.derive_trait
+ );
+ return CanDerive::No;
+ }
+ assert_ne!(len, 0, "vectors cannot have zero length");
+ self.derive_trait.can_derive_vector()
+ }
+
+ TypeKind::Comp(ref info) => {
+ assert!(
+ !info.has_non_type_template_params(),
+ "The early ty.is_opaque check should have handled this case"
+ );
+
+ if !self.derive_trait.can_derive_compound_forward_decl() &&
+ info.is_forward_declaration()
+ {
+ trace!(
+ " cannot derive {} for forward decls",
+ self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ // NOTE: Take into account that while unions in C and C++ are copied by
+ // default, the may have an explicit destructor in C++, so we can't
+ // defer this check just for the union case.
+ if !self.derive_trait.can_derive_compound_with_destructor() &&
+ self.ctx.lookup_has_destructor(
+ item.id().expect_type_id(self.ctx),
+ )
+ {
+ trace!(
+ " comp has destructor which cannot derive {}",
+ self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ if info.kind() == CompKind::Union {
+ if self.derive_trait.can_derive_union() {
+ if self.ctx.options().untagged_union &&
+ // https://github.com/rust-lang/rust/issues/36640
+ (!info.self_template_params(self.ctx).is_empty() ||
+ !item.all_template_params(self.ctx).is_empty())
+ {
+ trace!(
+ " cannot derive {} for Rust union because issue 36640", self.derive_trait
+ );
+ return CanDerive::No;
+ }
+ // fall through to be same as non-union handling
+ } else {
+ if self.ctx.options().untagged_union {
+ trace!(
+ " cannot derive {} for Rust unions",
+ self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ let layout_can_derive =
+ ty.layout(self.ctx).map_or(CanDerive::Yes, |l| {
+ l.opaque()
+ .array_size_within_derive_limit(self.ctx)
+ });
+ match layout_can_derive {
+ CanDerive::Yes => {
+ trace!(
+ " union layout can trivially derive {}",
+ self.derive_trait
+ );
+ }
+ _ => {
+ trace!(
+ " union layout cannot derive {}",
+ self.derive_trait
+ );
+ }
+ };
+ return layout_can_derive;
+ }
+ }
+
+ if !self.derive_trait.can_derive_compound_with_vtable() &&
+ item.has_vtable(self.ctx)
+ {
+ trace!(
+ " cannot derive {} for comp with vtable",
+ self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ // Bitfield units are always represented as arrays of u8, but
+ // they're not traced as arrays, so we need to check here
+ // instead.
+ if !self.derive_trait.can_derive_large_array(self.ctx) &&
+ info.has_too_large_bitfield_unit() &&
+ !item.is_opaque(self.ctx, &())
+ {
+ trace!(
+ " cannot derive {} for comp with too large bitfield unit",
+ self.derive_trait
+ );
+ return CanDerive::No;
+ }
+
+ let pred = self.derive_trait.consider_edge_comp();
+ self.constrain_join(item, pred)
+ }
+
+ TypeKind::ResolvedTypeRef(..) |
+ TypeKind::TemplateAlias(..) |
+ TypeKind::Alias(..) |
+ TypeKind::BlockPointer(..) => {
+ let pred = self.derive_trait.consider_edge_typeref();
+ self.constrain_join(item, pred)
+ }
+
+ TypeKind::TemplateInstantiation(..) => {
+ let pred = self.derive_trait.consider_edge_tmpl_inst();
+ self.constrain_join(item, pred)
+ }
+
+ TypeKind::Opaque => unreachable!(
+ "The early ty.is_opaque check should have handled this case"
+ ),
+ }
+ }
+
+ fn constrain_join(
+ &mut self,
+ item: &Item,
+ consider_edge: EdgePredicate,
+ ) -> CanDerive {
+ let mut candidate = None;
+
+ item.trace(
+ self.ctx,
+ &mut |sub_id, edge_kind| {
+ // Ignore ourselves, since union with ourself is a
+ // no-op. Ignore edges that aren't relevant to the
+ // analysis.
+ if sub_id == item.id() || !consider_edge(edge_kind) {
+ return;
+ }
+
+ let can_derive = self.can_derive
+ .get(&sub_id)
+ .cloned()
+ .unwrap_or_default();
+
+ match can_derive {
+ CanDerive::Yes => trace!(" member {:?} can derive {}", sub_id, self.derive_trait),
+ CanDerive::Manually => trace!(" member {:?} cannot derive {}, but it may be implemented", sub_id, self.derive_trait),
+ CanDerive::No => trace!(" member {:?} cannot derive {}", sub_id, self.derive_trait),
+ }
+
+ *candidate.get_or_insert(CanDerive::Yes) |= can_derive;
+ },
+ &(),
+ );
+
+ if candidate.is_none() {
+ trace!(
+ " can derive {} because there are no members",
+ self.derive_trait
+ );
+ }
+ candidate.unwrap_or_default()
+ }
+}
+
+impl DeriveTrait {
+ fn not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool {
+ match self {
+ DeriveTrait::Copy => ctx.no_copy_by_name(item),
+ DeriveTrait::Debug => ctx.no_debug_by_name(item),
+ DeriveTrait::Default => ctx.no_default_by_name(item),
+ DeriveTrait::Hash => ctx.no_hash_by_name(item),
+ DeriveTrait::PartialEqOrPartialOrd => {
+ ctx.no_partialeq_by_name(item)
+ }
+ }
+ }
+
+ fn consider_edge_comp(&self) -> EdgePredicate {
+ match self {
+ DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
+ _ => |kind| matches!(kind, EdgeKind::BaseMember | EdgeKind::Field),
+ }
+ }
+
+ fn consider_edge_typeref(&self) -> EdgePredicate {
+ match self {
+ DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
+ _ => |kind| kind == EdgeKind::TypeReference,
+ }
+ }
+
+ fn consider_edge_tmpl_inst(&self) -> EdgePredicate {
+ match self {
+ DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
+ _ => |kind| {
+ matches!(
+ kind,
+ EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration
+ )
+ },
+ }
+ }
+
+ fn can_derive_large_array(&self, ctx: &BindgenContext) -> bool {
+ if ctx.options().rust_features().larger_arrays {
+ !matches!(self, DeriveTrait::Default)
+ } else {
+ matches!(self, DeriveTrait::Copy)
+ }
+ }
+
+ fn can_derive_union(&self) -> bool {
+ matches!(self, DeriveTrait::Copy)
+ }
+
+ fn can_derive_compound_with_destructor(&self) -> bool {
+ !matches!(self, DeriveTrait::Copy)
+ }
+
+ fn can_derive_compound_with_vtable(&self) -> bool {
+ !matches!(self, DeriveTrait::Default)
+ }
+
+ fn can_derive_compound_forward_decl(&self) -> bool {
+ matches!(self, DeriveTrait::Copy | DeriveTrait::Debug)
+ }
+
+ fn can_derive_incomplete_array(&self) -> bool {
+ !matches!(
+ self,
+ DeriveTrait::Copy |
+ DeriveTrait::Hash |
+ DeriveTrait::PartialEqOrPartialOrd
+ )
+ }
+
+ fn can_derive_fnptr(&self, f: &FunctionSig) -> CanDerive {
+ match (self, f.function_pointers_can_derive()) {
+ (DeriveTrait::Copy, _) | (DeriveTrait::Default, _) | (_, true) => {
+ trace!(" function pointer can derive {}", self);
+ CanDerive::Yes
+ }
+ (DeriveTrait::Debug, false) => {
+ trace!(" function pointer cannot derive {}, but it may be implemented", self);
+ CanDerive::Manually
+ }
+ (_, false) => {
+ trace!(" function pointer cannot derive {}", self);
+ CanDerive::No
+ }
+ }
+ }
+
+ fn can_derive_vector(&self) -> CanDerive {
+ match self {
+ DeriveTrait::PartialEqOrPartialOrd => {
+ // FIXME: vectors always can derive PartialEq, but they should
+ // not derive PartialOrd:
+ // https://github.com/rust-lang-nursery/packed_simd/issues/48
+ trace!(" vectors cannot derive PartialOrd");
+ CanDerive::No
+ }
+ _ => {
+ trace!(" vector can derive {}", self);
+ CanDerive::Yes
+ }
+ }
+ }
+
+ fn can_derive_pointer(&self) -> CanDerive {
+ match self {
+ DeriveTrait::Default => {
+ trace!(" pointer cannot derive Default");
+ CanDerive::No
+ }
+ _ => {
+ trace!(" pointer can derive {}", self);
+ CanDerive::Yes
+ }
+ }
+ }
+
+ fn can_derive_simple(&self, kind: &TypeKind) -> CanDerive {
+ match (self, kind) {
+ // === Default ===
+ (DeriveTrait::Default, TypeKind::Void) |
+ (DeriveTrait::Default, TypeKind::NullPtr) |
+ (DeriveTrait::Default, TypeKind::Enum(..)) |
+ (DeriveTrait::Default, TypeKind::Reference(..)) |
+ (DeriveTrait::Default, TypeKind::TypeParam) |
+ (DeriveTrait::Default, TypeKind::ObjCInterface(..)) |
+ (DeriveTrait::Default, TypeKind::ObjCId) |
+ (DeriveTrait::Default, TypeKind::ObjCSel) => {
+ trace!(" types that always cannot derive Default");
+ CanDerive::No
+ }
+ (DeriveTrait::Default, TypeKind::UnresolvedTypeRef(..)) => {
+ unreachable!(
+ "Type with unresolved type ref can't reach derive default"
+ )
+ }
+ // === Hash ===
+ (DeriveTrait::Hash, TypeKind::Float(..)) |
+ (DeriveTrait::Hash, TypeKind::Complex(..)) => {
+ trace!(" float cannot derive Hash");
+ CanDerive::No
+ }
+ // === others ===
+ _ => {
+ trace!(" simple type that can always derive {}", self);
+ CanDerive::Yes
+ }
+ }
+ }
+}
+
+impl fmt::Display for DeriveTrait {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let s = match self {
+ DeriveTrait::Copy => "Copy",
+ DeriveTrait::Debug => "Debug",
+ DeriveTrait::Default => "Default",
+ DeriveTrait::Hash => "Hash",
+ DeriveTrait::PartialEqOrPartialOrd => "PartialEq/PartialOrd",
+ };
+ s.fmt(f)
+ }
+}
+
+impl<'ctx> MonotoneFramework for CannotDerive<'ctx> {
+ type Node = ItemId;
+ type Extra = (&'ctx BindgenContext, DeriveTrait);
+ type Output = HashMap<ItemId, CanDerive>;
+
+ fn new(
+ (ctx, derive_trait): (&'ctx BindgenContext, DeriveTrait),
+ ) -> CannotDerive<'ctx> {
+ let can_derive = HashMap::default();
+ let dependencies = generate_dependencies(ctx, consider_edge_default);
+
+ CannotDerive {
+ ctx,
+ derive_trait,
+ can_derive,
+ dependencies,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<ItemId> {
+ // The transitive closure of all allowlisted items, including explicitly
+ // blocklisted items.
+ self.ctx
+ .allowlisted_items()
+ .iter()
+ .cloned()
+ .flat_map(|i| {
+ let mut reachable = vec![i];
+ i.trace(
+ self.ctx,
+ &mut |s, _| {
+ reachable.push(s);
+ },
+ &(),
+ );
+ reachable
+ })
+ .collect()
+ }
+
+ fn constrain(&mut self, id: ItemId) -> ConstrainResult {
+ trace!("constrain: {:?}", id);
+
+ if let Some(CanDerive::No) = self.can_derive.get(&id).cloned() {
+ trace!(" already know it cannot derive {}", self.derive_trait);
+ return ConstrainResult::Same;
+ }
+
+ let item = self.ctx.resolve_item(id);
+ let can_derive = match item.as_type() {
+ Some(ty) => {
+ let mut can_derive = self.constrain_type(item, ty);
+ if let CanDerive::Yes = can_derive {
+ let is_reached_limit =
+ |l: Layout| l.align > RUST_DERIVE_IN_ARRAY_LIMIT;
+ if !self.derive_trait.can_derive_large_array(self.ctx) &&
+ ty.layout(self.ctx).map_or(false, is_reached_limit)
+ {
+ // We have to be conservative: the struct *could* have enough
+ // padding that we emit an array that is longer than
+ // `RUST_DERIVE_IN_ARRAY_LIMIT`. If we moved padding calculations
+ // into the IR and computed them before this analysis, then we could
+ // be precise rather than conservative here.
+ can_derive = CanDerive::Manually;
+ }
+ }
+ can_derive
+ }
+ None => self.constrain_join(item, consider_edge_default),
+ };
+
+ self.insert(id, can_derive)
+ }
+
+ fn each_depending_on<F>(&self, id: ItemId, mut f: F)
+ where
+ F: FnMut(ItemId),
+ {
+ if let Some(edges) = self.dependencies.get(&id) {
+ for item in edges {
+ trace!("enqueue {:?} into worklist", item);
+ f(*item);
+ }
+ }
+ }
+}
+
+impl<'ctx> From<CannotDerive<'ctx>> for HashMap<ItemId, CanDerive> {
+ fn from(analysis: CannotDerive<'ctx>) -> Self {
+ extra_assert!(analysis
+ .can_derive
+ .values()
+ .all(|v| *v != CanDerive::Yes));
+
+ analysis.can_derive
+ }
+}
+
+/// Convert a `HashMap<ItemId, CanDerive>` into a `HashSet<ItemId>`.
+///
+/// Elements that are not `CanDerive::Yes` are kept in the set, so that it
+/// represents all items that cannot derive.
+pub(crate) fn as_cannot_derive_set(
+ can_derive: HashMap<ItemId, CanDerive>,
+) -> HashSet<ItemId> {
+ can_derive
+ .into_iter()
+ .filter_map(|(k, v)| if v != CanDerive::Yes { Some(k) } else { None })
+ .collect()
+}
diff --git a/third_party/rust/bindgen/ir/analysis/has_destructor.rs b/third_party/rust/bindgen/ir/analysis/has_destructor.rs
new file mode 100644
index 0000000000..cbcbe55af2
--- /dev/null
+++ b/third_party/rust/bindgen/ir/analysis/has_destructor.rs
@@ -0,0 +1,176 @@
+//! Determining which types have destructors
+
+use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
+use crate::ir::comp::{CompKind, Field, FieldMethods};
+use crate::ir::context::{BindgenContext, ItemId};
+use crate::ir::traversal::EdgeKind;
+use crate::ir::ty::TypeKind;
+use crate::{HashMap, HashSet};
+
+/// An analysis that finds for each IR item whether it has a destructor or not
+///
+/// We use the monotone function `has destructor`, defined as follows:
+///
+/// * If T is a type alias, a templated alias, or an indirection to another type,
+/// T has a destructor if the type T refers to has a destructor.
+/// * If T is a compound type, T has a destructor if we saw a destructor when parsing it,
+/// or if it's a struct, T has a destructor if any of its base members has a destructor,
+/// or if any of its fields have a destructor.
+/// * If T is an instantiation of an abstract template definition, T has
+/// a destructor if its template definition has a destructor,
+/// or if any of the template arguments has a destructor.
+/// * If T is the type of a field, that field has a destructor if it's not a bitfield,
+/// and if T has a destructor.
+#[derive(Debug, Clone)]
+pub(crate) struct HasDestructorAnalysis<'ctx> {
+ ctx: &'ctx BindgenContext,
+
+ // The incremental result of this analysis's computation. Everything in this
+ // set definitely has a destructor.
+ have_destructor: HashSet<ItemId>,
+
+ // Dependencies saying that if a key ItemId has been inserted into the
+ // `have_destructor` set, then each of the ids in Vec<ItemId> need to be
+ // considered again.
+ //
+ // This is a subset of the natural IR graph with reversed edges, where we
+ // only include the edges from the IR graph that can affect whether a type
+ // has a destructor or not.
+ dependencies: HashMap<ItemId, Vec<ItemId>>,
+}
+
+impl<'ctx> HasDestructorAnalysis<'ctx> {
+ fn consider_edge(kind: EdgeKind) -> bool {
+ // These are the only edges that can affect whether a type has a
+ // destructor or not.
+ matches!(
+ kind,
+ EdgeKind::TypeReference |
+ EdgeKind::BaseMember |
+ EdgeKind::Field |
+ EdgeKind::TemplateArgument |
+ EdgeKind::TemplateDeclaration
+ )
+ }
+
+ fn insert<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
+ let id = id.into();
+ let was_not_already_in_set = self.have_destructor.insert(id);
+ assert!(
+ was_not_already_in_set,
+ "We shouldn't try and insert {:?} twice because if it was \
+ already in the set, `constrain` should have exited early.",
+ id
+ );
+ ConstrainResult::Changed
+ }
+}
+
+impl<'ctx> MonotoneFramework for HasDestructorAnalysis<'ctx> {
+ type Node = ItemId;
+ type Extra = &'ctx BindgenContext;
+ type Output = HashSet<ItemId>;
+
+ fn new(ctx: &'ctx BindgenContext) -> Self {
+ let have_destructor = HashSet::default();
+ let dependencies = generate_dependencies(ctx, Self::consider_edge);
+
+ HasDestructorAnalysis {
+ ctx,
+ have_destructor,
+ dependencies,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<ItemId> {
+ self.ctx.allowlisted_items().iter().cloned().collect()
+ }
+
+ fn constrain(&mut self, id: ItemId) -> ConstrainResult {
+ if self.have_destructor.contains(&id) {
+ // We've already computed that this type has a destructor and that can't
+ // change.
+ return ConstrainResult::Same;
+ }
+
+ let item = self.ctx.resolve_item(id);
+ let ty = match item.as_type() {
+ None => return ConstrainResult::Same,
+ Some(ty) => ty,
+ };
+
+ match *ty.kind() {
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) |
+ TypeKind::ResolvedTypeRef(t) => {
+ if self.have_destructor.contains(&t.into()) {
+ self.insert(id)
+ } else {
+ ConstrainResult::Same
+ }
+ }
+
+ TypeKind::Comp(ref info) => {
+ if info.has_own_destructor() {
+ return self.insert(id);
+ }
+
+ match info.kind() {
+ CompKind::Union => ConstrainResult::Same,
+ CompKind::Struct => {
+ let base_or_field_destructor =
+ info.base_members().iter().any(|base| {
+ self.have_destructor.contains(&base.ty.into())
+ }) || info.fields().iter().any(
+ |field| match *field {
+ Field::DataMember(ref data) => self
+ .have_destructor
+ .contains(&data.ty().into()),
+ Field::Bitfields(_) => false,
+ },
+ );
+ if base_or_field_destructor {
+ self.insert(id)
+ } else {
+ ConstrainResult::Same
+ }
+ }
+ }
+ }
+
+ TypeKind::TemplateInstantiation(ref inst) => {
+ let definition_or_arg_destructor = self
+ .have_destructor
+ .contains(&inst.template_definition().into()) ||
+ inst.template_arguments().iter().any(|arg| {
+ self.have_destructor.contains(&arg.into())
+ });
+ if definition_or_arg_destructor {
+ self.insert(id)
+ } else {
+ ConstrainResult::Same
+ }
+ }
+
+ _ => ConstrainResult::Same,
+ }
+ }
+
+ fn each_depending_on<F>(&self, id: ItemId, mut f: F)
+ where
+ F: FnMut(ItemId),
+ {
+ if let Some(edges) = self.dependencies.get(&id) {
+ for item in edges {
+ trace!("enqueue {:?} into worklist", item);
+ f(*item);
+ }
+ }
+ }
+}
+
+impl<'ctx> From<HasDestructorAnalysis<'ctx>> for HashSet<ItemId> {
+ fn from(analysis: HasDestructorAnalysis<'ctx>) -> Self {
+ analysis.have_destructor
+ }
+}
diff --git a/third_party/rust/bindgen/ir/analysis/has_float.rs b/third_party/rust/bindgen/ir/analysis/has_float.rs
new file mode 100644
index 0000000000..219c5a5a8d
--- /dev/null
+++ b/third_party/rust/bindgen/ir/analysis/has_float.rs
@@ -0,0 +1,252 @@
+//! Determining which types has float.
+
+use super::{generate_dependencies, ConstrainResult, MonotoneFramework};
+use crate::ir::comp::Field;
+use crate::ir::comp::FieldMethods;
+use crate::ir::context::{BindgenContext, ItemId};
+use crate::ir::traversal::EdgeKind;
+use crate::ir::ty::TypeKind;
+use crate::{HashMap, HashSet};
+
+/// An analysis that finds for each IR item whether it has float or not.
+///
+/// We use the monotone constraint function `has_float`,
+/// defined as follows:
+///
+/// * If T is float or complex float, T trivially has.
+/// * If T is a type alias, a templated alias or an indirection to another type,
+/// it has float if the type T refers to has.
+/// * If T is a compound type, it has float if any of base memter or field
+/// has.
+/// * If T is an instantiation of an abstract template definition, T has
+/// float if any of the template arguments or template definition
+/// has.
+#[derive(Debug, Clone)]
+pub(crate) struct HasFloat<'ctx> {
+ ctx: &'ctx BindgenContext,
+
+ // The incremental result of this analysis's computation. Everything in this
+ // set has float.
+ has_float: HashSet<ItemId>,
+
+ // Dependencies saying that if a key ItemId has been inserted into the
+ // `has_float` set, then each of the ids in Vec<ItemId> need to be
+ // considered again.
+ //
+ // This is a subset of the natural IR graph with reversed edges, where we
+ // only include the edges from the IR graph that can affect whether a type
+ // has float or not.
+ dependencies: HashMap<ItemId, Vec<ItemId>>,
+}
+
+impl<'ctx> HasFloat<'ctx> {
+ fn consider_edge(kind: EdgeKind) -> bool {
+ match kind {
+ EdgeKind::BaseMember |
+ EdgeKind::Field |
+ EdgeKind::TypeReference |
+ EdgeKind::VarType |
+ EdgeKind::TemplateArgument |
+ EdgeKind::TemplateDeclaration |
+ EdgeKind::TemplateParameterDefinition => true,
+
+ EdgeKind::Constructor |
+ EdgeKind::Destructor |
+ EdgeKind::FunctionReturn |
+ EdgeKind::FunctionParameter |
+ EdgeKind::InnerType |
+ EdgeKind::InnerVar |
+ EdgeKind::Method => false,
+ EdgeKind::Generic => false,
+ }
+ }
+
+ fn insert<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
+ let id = id.into();
+ trace!("inserting {:?} into the has_float set", id);
+
+ let was_not_already_in_set = self.has_float.insert(id);
+ assert!(
+ was_not_already_in_set,
+ "We shouldn't try and insert {:?} twice because if it was \
+ already in the set, `constrain` should have exited early.",
+ id
+ );
+
+ ConstrainResult::Changed
+ }
+}
+
+impl<'ctx> MonotoneFramework for HasFloat<'ctx> {
+ type Node = ItemId;
+ type Extra = &'ctx BindgenContext;
+ type Output = HashSet<ItemId>;
+
+ fn new(ctx: &'ctx BindgenContext) -> HasFloat<'ctx> {
+ let has_float = HashSet::default();
+ let dependencies = generate_dependencies(ctx, Self::consider_edge);
+
+ HasFloat {
+ ctx,
+ has_float,
+ dependencies,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<ItemId> {
+ self.ctx.allowlisted_items().iter().cloned().collect()
+ }
+
+ fn constrain(&mut self, id: ItemId) -> ConstrainResult {
+ trace!("constrain: {:?}", id);
+
+ if self.has_float.contains(&id) {
+ trace!(" already know it do not have float");
+ return ConstrainResult::Same;
+ }
+
+ let item = self.ctx.resolve_item(id);
+ let ty = match item.as_type() {
+ Some(ty) => ty,
+ None => {
+ trace!(" not a type; ignoring");
+ return ConstrainResult::Same;
+ }
+ };
+
+ match *ty.kind() {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::TypeParam |
+ TypeKind::Opaque |
+ TypeKind::Pointer(..) |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::ObjCInterface(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel => {
+ trace!(" simple type that do not have float");
+ ConstrainResult::Same
+ }
+
+ TypeKind::Float(..) | TypeKind::Complex(..) => {
+ trace!(" float type has float");
+ self.insert(id)
+ }
+
+ TypeKind::Array(t, _) => {
+ if self.has_float.contains(&t.into()) {
+ trace!(
+ " Array with type T that has float also has float"
+ );
+ return self.insert(id);
+ }
+ trace!(" Array with type T that do not have float also do not have float");
+ ConstrainResult::Same
+ }
+ TypeKind::Vector(t, _) => {
+ if self.has_float.contains(&t.into()) {
+ trace!(
+ " Vector with type T that has float also has float"
+ );
+ return self.insert(id);
+ }
+ trace!(" Vector with type T that do not have float also do not have float");
+ ConstrainResult::Same
+ }
+
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) |
+ TypeKind::BlockPointer(t) => {
+ if self.has_float.contains(&t.into()) {
+ trace!(
+ " aliases and type refs to T which have float \
+ also have float"
+ );
+ self.insert(id)
+ } else {
+ trace!(" aliases and type refs to T which do not have float \
+ also do not have floaarrayt");
+ ConstrainResult::Same
+ }
+ }
+
+ TypeKind::Comp(ref info) => {
+ let bases_have = info
+ .base_members()
+ .iter()
+ .any(|base| self.has_float.contains(&base.ty.into()));
+ if bases_have {
+ trace!(" bases have float, so we also have");
+ return self.insert(id);
+ }
+ let fields_have = info.fields().iter().any(|f| match *f {
+ Field::DataMember(ref data) => {
+ self.has_float.contains(&data.ty().into())
+ }
+ Field::Bitfields(ref bfu) => bfu
+ .bitfields()
+ .iter()
+ .any(|b| self.has_float.contains(&b.ty().into())),
+ });
+ if fields_have {
+ trace!(" fields have float, so we also have");
+ return self.insert(id);
+ }
+
+ trace!(" comp doesn't have float");
+ ConstrainResult::Same
+ }
+
+ TypeKind::TemplateInstantiation(ref template) => {
+ let args_have = template
+ .template_arguments()
+ .iter()
+ .any(|arg| self.has_float.contains(&arg.into()));
+ if args_have {
+ trace!(
+ " template args have float, so \
+ insantiation also has float"
+ );
+ return self.insert(id);
+ }
+
+ let def_has = self
+ .has_float
+ .contains(&template.template_definition().into());
+ if def_has {
+ trace!(
+ " template definition has float, so \
+ insantiation also has"
+ );
+ return self.insert(id);
+ }
+
+ trace!(" template instantiation do not have float");
+ ConstrainResult::Same
+ }
+ }
+ }
+
+ fn each_depending_on<F>(&self, id: ItemId, mut f: F)
+ where
+ F: FnMut(ItemId),
+ {
+ if let Some(edges) = self.dependencies.get(&id) {
+ for item in edges {
+ trace!("enqueue {:?} into worklist", item);
+ f(*item);
+ }
+ }
+ }
+}
+
+impl<'ctx> From<HasFloat<'ctx>> for HashSet<ItemId> {
+ fn from(analysis: HasFloat<'ctx>) -> Self {
+ analysis.has_float
+ }
+}
diff --git a/third_party/rust/bindgen/ir/analysis/has_type_param_in_array.rs b/third_party/rust/bindgen/ir/analysis/has_type_param_in_array.rs
new file mode 100644
index 0000000000..088c08f542
--- /dev/null
+++ b/third_party/rust/bindgen/ir/analysis/has_type_param_in_array.rs
@@ -0,0 +1,252 @@
+//! 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(crate) struct HasTypeParameterInArray<'ctx> {
+ ctx: &'ctx BindgenContext,
+
+ // The incremental result of this analysis's computation. Everything in this
+ // set has array.
+ has_type_parameter_in_array: HashSet<ItemId>,
+
+ // Dependencies saying that if a key ItemId has been inserted into the
+ // `has_type_parameter_in_array` set, then each of the ids in Vec<ItemId> need to be
+ // considered again.
+ //
+ // This is a subset of the natural IR graph with reversed edges, where we
+ // only include the edges from the IR graph that can affect whether a type
+ // has array or not.
+ dependencies: HashMap<ItemId, Vec<ItemId>>,
+}
+
+impl<'ctx> HasTypeParameterInArray<'ctx> {
+ fn consider_edge(kind: EdgeKind) -> bool {
+ match kind {
+ // These are the only edges that can affect whether a type has type parameter
+ // in array or not.
+ EdgeKind::BaseMember |
+ EdgeKind::Field |
+ EdgeKind::TypeReference |
+ EdgeKind::VarType |
+ EdgeKind::TemplateArgument |
+ EdgeKind::TemplateDeclaration |
+ EdgeKind::TemplateParameterDefinition => true,
+
+ EdgeKind::Constructor |
+ EdgeKind::Destructor |
+ EdgeKind::FunctionReturn |
+ EdgeKind::FunctionParameter |
+ EdgeKind::InnerType |
+ EdgeKind::InnerVar |
+ EdgeKind::Method => false,
+ EdgeKind::Generic => false,
+ }
+ }
+
+ fn insert<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
+ let id = id.into();
+ trace!(
+ "inserting {:?} into the has_type_parameter_in_array set",
+ id
+ );
+
+ let was_not_already_in_set =
+ self.has_type_parameter_in_array.insert(id);
+ assert!(
+ was_not_already_in_set,
+ "We shouldn't try and insert {:?} twice because if it was \
+ already in the set, `constrain` should have exited early.",
+ id
+ );
+
+ ConstrainResult::Changed
+ }
+}
+
+impl<'ctx> MonotoneFramework for HasTypeParameterInArray<'ctx> {
+ type Node = ItemId;
+ type Extra = &'ctx BindgenContext;
+ type Output = HashSet<ItemId>;
+
+ fn new(ctx: &'ctx BindgenContext) -> HasTypeParameterInArray<'ctx> {
+ let has_type_parameter_in_array = HashSet::default();
+ let dependencies = generate_dependencies(ctx, Self::consider_edge);
+
+ HasTypeParameterInArray {
+ ctx,
+ has_type_parameter_in_array,
+ dependencies,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<ItemId> {
+ self.ctx.allowlisted_items().iter().cloned().collect()
+ }
+
+ fn constrain(&mut self, id: ItemId) -> ConstrainResult {
+ trace!("constrain: {:?}", id);
+
+ if self.has_type_parameter_in_array.contains(&id) {
+ trace!(" already know it do not have array");
+ return ConstrainResult::Same;
+ }
+
+ let item = self.ctx.resolve_item(id);
+ let ty = match item.as_type() {
+ Some(ty) => ty,
+ None => {
+ trace!(" not a type; ignoring");
+ return ConstrainResult::Same;
+ }
+ };
+
+ match *ty.kind() {
+ // Handle the simple cases. These cannot have array in type parameter
+ // without further information.
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Vector(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::TypeParam |
+ TypeKind::Opaque |
+ TypeKind::Pointer(..) |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::ObjCInterface(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel => {
+ trace!(" simple type that do not have array");
+ ConstrainResult::Same
+ }
+
+ TypeKind::Array(t, _) => {
+ let inner_ty =
+ self.ctx.resolve_type(t).canonical_type(self.ctx);
+ match *inner_ty.kind() {
+ TypeKind::TypeParam => {
+ trace!(" Array with Named type has type parameter");
+ self.insert(id)
+ }
+ _ => {
+ trace!(
+ " Array without Named type does have type parameter"
+ );
+ ConstrainResult::Same
+ }
+ }
+ }
+
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) |
+ TypeKind::BlockPointer(t) => {
+ if self.has_type_parameter_in_array.contains(&t.into()) {
+ trace!(
+ " aliases and type refs to T which have array \
+ also have array"
+ );
+ self.insert(id)
+ } else {
+ trace!(
+ " aliases and type refs to T which do not have array \
+ also do not have array"
+ );
+ ConstrainResult::Same
+ }
+ }
+
+ TypeKind::Comp(ref info) => {
+ let bases_have = info.base_members().iter().any(|base| {
+ self.has_type_parameter_in_array.contains(&base.ty.into())
+ });
+ if bases_have {
+ trace!(" bases have array, so we also have");
+ return self.insert(id);
+ }
+ let fields_have = info.fields().iter().any(|f| match *f {
+ Field::DataMember(ref data) => self
+ .has_type_parameter_in_array
+ .contains(&data.ty().into()),
+ Field::Bitfields(..) => false,
+ });
+ if fields_have {
+ trace!(" fields have array, so we also have");
+ return self.insert(id);
+ }
+
+ trace!(" comp doesn't have array");
+ ConstrainResult::Same
+ }
+
+ TypeKind::TemplateInstantiation(ref template) => {
+ let args_have =
+ template.template_arguments().iter().any(|arg| {
+ self.has_type_parameter_in_array.contains(&arg.into())
+ });
+ if args_have {
+ trace!(
+ " template args have array, so \
+ insantiation also has array"
+ );
+ return self.insert(id);
+ }
+
+ let def_has = self
+ .has_type_parameter_in_array
+ .contains(&template.template_definition().into());
+ if def_has {
+ trace!(
+ " template definition has array, so \
+ insantiation also has"
+ );
+ return self.insert(id);
+ }
+
+ trace!(" template instantiation do not have array");
+ ConstrainResult::Same
+ }
+ }
+ }
+
+ fn each_depending_on<F>(&self, id: ItemId, mut f: F)
+ where
+ F: FnMut(ItemId),
+ {
+ if let Some(edges) = self.dependencies.get(&id) {
+ for item in edges {
+ trace!("enqueue {:?} into worklist", item);
+ f(*item);
+ }
+ }
+ }
+}
+
+impl<'ctx> From<HasTypeParameterInArray<'ctx>> for HashSet<ItemId> {
+ fn from(analysis: HasTypeParameterInArray<'ctx>) -> Self {
+ analysis.has_type_parameter_in_array
+ }
+}
diff --git a/third_party/rust/bindgen/ir/analysis/has_vtable.rs b/third_party/rust/bindgen/ir/analysis/has_vtable.rs
new file mode 100644
index 0000000000..980a551b88
--- /dev/null
+++ b/third_party/rust/bindgen/ir/analysis/has_vtable.rs
@@ -0,0 +1,240 @@
+//! 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(crate) 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(crate) fn join(self, rhs: Self) -> Self {
+ cmp::max(self, rhs)
+ }
+}
+
+impl ops::BitOr for HasVtableResult {
+ type Output = Self;
+
+ fn bitor(self, rhs: HasVtableResult) -> Self::Output {
+ self.join(rhs)
+ }
+}
+
+impl ops::BitOrAssign for HasVtableResult {
+ fn bitor_assign(&mut self, rhs: HasVtableResult) {
+ *self = self.join(rhs)
+ }
+}
+
+/// An analysis that finds for each IR item whether it has vtable or not
+///
+/// We use the monotone function `has vtable`, defined as follows:
+///
+/// * If T is a type alias, a templated alias, an indirection to another type,
+/// or a reference of a type, T has vtable if the type T refers to has vtable.
+/// * If T is a compound type, T has vtable if we saw a virtual function when
+/// parsing it or any of its base member has vtable.
+/// * If T is an instantiation of an abstract template definition, T has
+/// vtable if template definition has vtable
+#[derive(Debug, Clone)]
+pub(crate) struct HasVtableAnalysis<'ctx> {
+ ctx: &'ctx BindgenContext,
+
+ // The incremental result of this analysis's computation. Everything in this
+ // set definitely has a vtable.
+ have_vtable: HashMap<ItemId, HasVtableResult>,
+
+ // Dependencies saying that if a key ItemId has been inserted into the
+ // `have_vtable` set, then each of the ids in Vec<ItemId> need to be
+ // considered again.
+ //
+ // This is a subset of the natural IR graph with reversed edges, where we
+ // only include the edges from the IR graph that can affect whether a type
+ // has a vtable or not.
+ dependencies: HashMap<ItemId, Vec<ItemId>>,
+}
+
+impl<'ctx> HasVtableAnalysis<'ctx> {
+ fn consider_edge(kind: EdgeKind) -> bool {
+ // These are the only edges that can affect whether a type has a
+ // vtable or not.
+ matches!(
+ kind,
+ EdgeKind::TypeReference |
+ EdgeKind::BaseMember |
+ EdgeKind::TemplateDeclaration
+ )
+ }
+
+ fn insert<Id: Into<ItemId>>(
+ &mut self,
+ id: Id,
+ result: HasVtableResult,
+ ) -> ConstrainResult {
+ if let HasVtableResult::No = result {
+ return ConstrainResult::Same;
+ }
+
+ let id = id.into();
+ match self.have_vtable.entry(id) {
+ Entry::Occupied(mut entry) => {
+ if *entry.get() < result {
+ entry.insert(result);
+ ConstrainResult::Changed
+ } else {
+ ConstrainResult::Same
+ }
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(result);
+ ConstrainResult::Changed
+ }
+ }
+ }
+
+ fn forward<Id1, Id2>(&mut self, from: Id1, to: Id2) -> ConstrainResult
+ where
+ Id1: Into<ItemId>,
+ Id2: Into<ItemId>,
+ {
+ let from = from.into();
+ let to = to.into();
+
+ match self.have_vtable.get(&from).cloned() {
+ None => ConstrainResult::Same,
+ Some(r) => self.insert(to, r),
+ }
+ }
+}
+
+impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> {
+ type Node = ItemId;
+ type Extra = &'ctx BindgenContext;
+ type Output = HashMap<ItemId, HasVtableResult>;
+
+ fn new(ctx: &'ctx BindgenContext) -> HasVtableAnalysis<'ctx> {
+ let have_vtable = HashMap::default();
+ let dependencies = generate_dependencies(ctx, Self::consider_edge);
+
+ HasVtableAnalysis {
+ ctx,
+ have_vtable,
+ dependencies,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<ItemId> {
+ self.ctx.allowlisted_items().iter().cloned().collect()
+ }
+
+ fn constrain(&mut self, id: ItemId) -> ConstrainResult {
+ trace!("constrain {:?}", id);
+
+ let item = self.ctx.resolve_item(id);
+ let ty = match item.as_type() {
+ None => return ConstrainResult::Same,
+ Some(ty) => ty,
+ };
+
+ // TODO #851: figure out a way to handle deriving from template type parameters.
+ match *ty.kind() {
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) |
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Reference(t) => {
+ trace!(
+ " aliases and references forward to their inner type"
+ );
+ self.forward(t, id)
+ }
+
+ TypeKind::Comp(ref info) => {
+ trace!(" comp considers its own methods and bases");
+ let mut result = HasVtableResult::No;
+
+ if info.has_own_virtual_method() {
+ trace!(" comp has its own virtual method");
+ result |= HasVtableResult::SelfHasVtable;
+ }
+
+ let bases_has_vtable = info.base_members().iter().any(|base| {
+ trace!(" comp has a base with a vtable: {:?}", base);
+ self.have_vtable.contains_key(&base.ty.into())
+ });
+ if bases_has_vtable {
+ result |= HasVtableResult::BaseHasVtable;
+ }
+
+ self.insert(id, result)
+ }
+
+ TypeKind::TemplateInstantiation(ref inst) => {
+ self.forward(inst.template_definition(), id)
+ }
+
+ _ => ConstrainResult::Same,
+ }
+ }
+
+ fn each_depending_on<F>(&self, id: ItemId, mut f: F)
+ where
+ F: FnMut(ItemId),
+ {
+ if let Some(edges) = self.dependencies.get(&id) {
+ for item in edges {
+ trace!("enqueue {:?} into worklist", item);
+ f(*item);
+ }
+ }
+ }
+}
+
+impl<'ctx> From<HasVtableAnalysis<'ctx>> for HashMap<ItemId, HasVtableResult> {
+ fn from(analysis: HasVtableAnalysis<'ctx>) -> Self {
+ // We let the lack of an entry mean "No" to save space.
+ extra_assert!(analysis
+ .have_vtable
+ .values()
+ .all(|v| { *v != HasVtableResult::No }));
+
+ analysis.have_vtable
+ }
+}
+
+/// A convenience trait for the things for which we might wonder if they have a
+/// vtable during codegen.
+///
+/// This is not for _computing_ whether the thing has a vtable, it is for
+/// looking up the results of the HasVtableAnalysis's computations for a
+/// specific thing.
+pub(crate) trait HasVtable {
+ /// Return `true` if this thing has vtable, `false` otherwise.
+ fn has_vtable(&self, ctx: &BindgenContext) -> bool;
+
+ /// Return `true` if this thing has an actual vtable pointer in itself, as
+ /// opposed to transitively in a base member.
+ fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool;
+}
diff --git a/third_party/rust/bindgen/ir/analysis/mod.rs b/third_party/rust/bindgen/ir/analysis/mod.rs
new file mode 100644
index 0000000000..443384a487
--- /dev/null
+++ b/third_party/rust/bindgen/ir/analysis/mod.rs
@@ -0,0 +1,400 @@
+//! Fix-point analyses on the IR using the "monotone framework".
+//!
+//! A lattice is a set with a partial ordering between elements, where there is
+//! a single least upper bound and a single greatest least bound for every
+//! subset. We are dealing with finite lattices, which means that it has a
+//! finite number of elements, and it follows that there exists a single top and
+//! a single bottom member of the lattice. For example, the power set of a
+//! finite set forms a finite lattice where partial ordering is defined by set
+//! inclusion, that is `a <= b` if `a` is a subset of `b`. Here is the finite
+//! lattice constructed from the set {0,1,2}:
+//!
+//! ```text
+//! .----- Top = {0,1,2} -----.
+//! / | \
+//! / | \
+//! / | \
+//! {0,1} -------. {0,2} .--------- {1,2}
+//! | \ / \ / |
+//! | / \ |
+//! | / \ / \ |
+//! {0} --------' {1} `---------- {2}
+//! \ | /
+//! \ | /
+//! \ | /
+//! `------ Bottom = {} ------'
+//! ```
+//!
+//! A monotone function `f` is a function where if `x <= y`, then it holds that
+//! `f(x) <= f(y)`. It should be clear that running a monotone function to a
+//! fix-point on a finite lattice will always terminate: `f` can only "move"
+//! along the lattice in a single direction, and therefore can only either find
+//! a fix-point in the middle of the lattice or continue to the top or bottom
+//! depending if it is ascending or descending the lattice respectively.
+//!
+//! For a deeper introduction to the general form of this kind of analysis, see
+//! [Static Program Analysis by Anders Møller and Michael I. Schwartzbach][spa].
+//!
+//! [spa]: https://cs.au.dk/~amoeller/spa/spa.pdf
+
+// Re-export individual analyses.
+mod template_params;
+pub(crate) use self::template_params::UsedTemplateParameters;
+mod derive;
+pub use self::derive::DeriveTrait;
+pub(crate) use self::derive::{as_cannot_derive_set, CannotDerive};
+mod has_vtable;
+pub(crate) use self::has_vtable::{
+ HasVtable, HasVtableAnalysis, HasVtableResult,
+};
+mod has_destructor;
+pub(crate) use self::has_destructor::HasDestructorAnalysis;
+mod has_type_param_in_array;
+pub(crate) use self::has_type_param_in_array::HasTypeParameterInArray;
+mod has_float;
+pub(crate) use self::has_float::HasFloat;
+mod sizedness;
+pub(crate) use self::sizedness::{
+ Sizedness, SizednessAnalysis, SizednessResult,
+};
+
+use crate::ir::context::{BindgenContext, ItemId};
+
+use crate::ir::traversal::{EdgeKind, Trace};
+use crate::HashMap;
+use std::fmt;
+use std::ops;
+
+/// An analysis in the monotone framework.
+///
+/// Implementors of this trait must maintain the following two invariants:
+///
+/// 1. The concrete data must be a member of a finite-height lattice.
+/// 2. The concrete `constrain` method must be monotone: that is,
+/// if `x <= y`, then `constrain(x) <= constrain(y)`.
+///
+/// If these invariants do not hold, iteration to a fix-point might never
+/// complete.
+///
+/// For a simple example analysis, see the `ReachableFrom` type in the `tests`
+/// module below.
+pub(crate) trait MonotoneFramework: Sized + fmt::Debug {
+ /// The type of node in our dependency graph.
+ ///
+ /// This is just generic (and not `ItemId`) so that we can easily unit test
+ /// without constructing real `Item`s and their `ItemId`s.
+ type Node: Copy;
+
+ /// Any extra data that is needed during computation.
+ ///
+ /// Again, this is just generic (and not `&BindgenContext`) so that we can
+ /// easily unit test without constructing real `BindgenContext`s full of
+ /// real `Item`s and real `ItemId`s.
+ type Extra: Sized;
+
+ /// The final output of this analysis. Once we have reached a fix-point, we
+ /// convert `self` into this type, and return it as the final result of the
+ /// analysis.
+ type Output: From<Self> + fmt::Debug;
+
+ /// Construct a new instance of this analysis.
+ fn new(extra: Self::Extra) -> Self;
+
+ /// Get the initial set of nodes from which to start the analysis. Unless
+ /// you are sure of some domain-specific knowledge, this should be the
+ /// complete set of nodes.
+ fn initial_worklist(&self) -> Vec<Self::Node>;
+
+ /// Update the analysis for the given node.
+ ///
+ /// If this results in changing our internal state (ie, we discovered that
+ /// we have not reached a fix-point and iteration should continue), return
+ /// `ConstrainResult::Changed`. Otherwise, return `ConstrainResult::Same`.
+ /// When `constrain` returns `ConstrainResult::Same` for all nodes in the
+ /// set, we have reached a fix-point and the analysis is complete.
+ fn constrain(&mut self, node: Self::Node) -> ConstrainResult;
+
+ /// For each node `d` that depends on the given `node`'s current answer when
+ /// running `constrain(d)`, call `f(d)`. This informs us which new nodes to
+ /// queue up in the worklist when `constrain(node)` reports updated
+ /// information.
+ fn each_depending_on<F>(&self, node: Self::Node, f: F)
+ where
+ F: FnMut(Self::Node);
+}
+
+/// Whether an analysis's `constrain` function modified the incremental results
+/// or not.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub(crate) 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(crate) fn analyze<Analysis>(extra: Analysis::Extra) -> Analysis::Output
+where
+ Analysis: MonotoneFramework,
+{
+ let mut analysis = Analysis::new(extra);
+ let mut worklist = analysis.initial_worklist();
+
+ while let Some(node) = worklist.pop() {
+ if let ConstrainResult::Changed = analysis.constrain(node) {
+ analysis.each_depending_on(node, |needs_work| {
+ worklist.push(needs_work);
+ });
+ }
+ }
+
+ analysis.into()
+}
+
+/// Generate the dependency map for analysis
+pub(crate) fn generate_dependencies<F>(
+ ctx: &BindgenContext,
+ consider_edge: F,
+) -> HashMap<ItemId, Vec<ItemId>>
+where
+ F: Fn(EdgeKind) -> bool,
+{
+ let mut dependencies = HashMap::default();
+
+ for &item in ctx.allowlisted_items() {
+ dependencies.entry(item).or_insert_with(Vec::new);
+
+ {
+ // We reverse our natural IR graph edges to find dependencies
+ // between nodes.
+ item.trace(
+ ctx,
+ &mut |sub_item: ItemId, edge_kind| {
+ if ctx.allowlisted_items().contains(&sub_item) &&
+ consider_edge(edge_kind)
+ {
+ dependencies
+ .entry(sub_item)
+ .or_insert_with(Vec::new)
+ .push(item);
+ }
+ },
+ &(),
+ );
+ }
+ }
+ dependencies
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::{HashMap, HashSet};
+
+ // Here we find the set of nodes that are reachable from any given
+ // node. This is a lattice mapping nodes to subsets of all nodes. Our join
+ // function is set union.
+ //
+ // This is our test graph:
+ //
+ // +---+ +---+
+ // | | | |
+ // | 1 | .----| 2 |
+ // | | | | |
+ // +---+ | +---+
+ // | | ^
+ // | | |
+ // | +---+ '------'
+ // '----->| |
+ // | 3 |
+ // .------| |------.
+ // | +---+ |
+ // | ^ |
+ // v | v
+ // +---+ | +---+ +---+
+ // | | | | | | |
+ // | 4 | | | 5 |--->| 6 |
+ // | | | | | | |
+ // +---+ | +---+ +---+
+ // | | | |
+ // | | | v
+ // | +---+ | +---+
+ // | | | | | |
+ // '----->| 7 |<-----' | 8 |
+ // | | | |
+ // +---+ +---+
+ //
+ // And here is the mapping from a node to the set of nodes that are
+ // reachable from it within the test graph:
+ //
+ // 1: {3,4,5,6,7,8}
+ // 2: {2}
+ // 3: {3,4,5,6,7,8}
+ // 4: {3,4,5,6,7,8}
+ // 5: {3,4,5,6,7,8}
+ // 6: {8}
+ // 7: {3,4,5,6,7,8}
+ // 8: {}
+
+ #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
+ struct Node(usize);
+
+ #[derive(Clone, Debug, Default, PartialEq, Eq)]
+ struct Graph(HashMap<Node, Vec<Node>>);
+
+ impl Graph {
+ fn make_test_graph() -> Graph {
+ let mut g = Graph::default();
+ g.0.insert(Node(1), vec![Node(3)]);
+ g.0.insert(Node(2), vec![Node(2)]);
+ g.0.insert(Node(3), vec![Node(4), Node(5)]);
+ g.0.insert(Node(4), vec![Node(7)]);
+ g.0.insert(Node(5), vec![Node(6), Node(7)]);
+ g.0.insert(Node(6), vec![Node(8)]);
+ g.0.insert(Node(7), vec![Node(3)]);
+ g.0.insert(Node(8), vec![]);
+ g
+ }
+
+ fn reverse(&self) -> Graph {
+ let mut reversed = Graph::default();
+ for (node, edges) in self.0.iter() {
+ reversed.0.entry(*node).or_insert_with(Vec::new);
+ for referent in edges.iter() {
+ reversed
+ .0
+ .entry(*referent)
+ .or_insert_with(Vec::new)
+ .push(*node);
+ }
+ }
+ reversed
+ }
+ }
+
+ #[derive(Clone, Debug, PartialEq, Eq)]
+ struct ReachableFrom<'a> {
+ reachable: HashMap<Node, HashSet<Node>>,
+ graph: &'a Graph,
+ reversed: Graph,
+ }
+
+ impl<'a> MonotoneFramework for ReachableFrom<'a> {
+ type Node = Node;
+ type Extra = &'a Graph;
+ type Output = HashMap<Node, HashSet<Node>>;
+
+ fn new(graph: &'a Graph) -> ReachableFrom {
+ let reversed = graph.reverse();
+ ReachableFrom {
+ reachable: Default::default(),
+ graph,
+ reversed,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<Node> {
+ self.graph.0.keys().cloned().collect()
+ }
+
+ fn constrain(&mut self, node: Node) -> ConstrainResult {
+ // The set of nodes reachable from a node `x` is
+ //
+ // reachable(x) = s_0 U s_1 U ... U reachable(s_0) U reachable(s_1) U ...
+ //
+ // where there exist edges from `x` to each of `s_0, s_1, ...`.
+ //
+ // Yes, what follows is a **terribly** inefficient set union
+ // implementation. Don't copy this code outside of this test!
+
+ let original_size = self.reachable.entry(node).or_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_default().clone();
+
+ for transitive in sub_reachable {
+ self.reachable.get_mut(&node).unwrap().insert(transitive);
+ }
+ }
+
+ let new_size = self.reachable[&node].len();
+ if original_size != new_size {
+ ConstrainResult::Changed
+ } else {
+ ConstrainResult::Same
+ }
+ }
+
+ fn each_depending_on<F>(&self, node: Node, mut f: F)
+ where
+ F: FnMut(Node),
+ {
+ for dep in self.reversed.0[&node].iter() {
+ f(*dep);
+ }
+ }
+ }
+
+ impl<'a> From<ReachableFrom<'a>> for HashMap<Node, HashSet<Node>> {
+ fn from(reachable: ReachableFrom<'a>) -> Self {
+ reachable.reachable
+ }
+ }
+
+ #[test]
+ fn monotone() {
+ let g = Graph::make_test_graph();
+ let reachable = analyze::<ReachableFrom>(&g);
+ println!("reachable = {:#?}", reachable);
+
+ fn nodes<A>(nodes: A) -> HashSet<Node>
+ where
+ A: AsRef<[usize]>,
+ {
+ nodes.as_ref().iter().cloned().map(Node).collect()
+ }
+
+ let mut expected = HashMap::default();
+ expected.insert(Node(1), nodes([3, 4, 5, 6, 7, 8]));
+ expected.insert(Node(2), nodes([2]));
+ expected.insert(Node(3), nodes([3, 4, 5, 6, 7, 8]));
+ expected.insert(Node(4), nodes([3, 4, 5, 6, 7, 8]));
+ expected.insert(Node(5), nodes([3, 4, 5, 6, 7, 8]));
+ expected.insert(Node(6), nodes([8]));
+ expected.insert(Node(7), nodes([3, 4, 5, 6, 7, 8]));
+ expected.insert(Node(8), nodes([]));
+ println!("expected = {:#?}", expected);
+
+ assert_eq!(reachable, expected);
+ }
+}
diff --git a/third_party/rust/bindgen/ir/analysis/sizedness.rs b/third_party/rust/bindgen/ir/analysis/sizedness.rs
new file mode 100644
index 0000000000..995d700794
--- /dev/null
+++ b/third_party/rust/bindgen/ir/analysis/sizedness.rs
@@ -0,0 +1,361 @@
+//! 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(crate) enum SizednessResult {
+ /// The type is zero-sized.
+ ///
+ /// This means that if it is a C++ type, and is not being used as a base
+ /// member, then we must add an `_address` byte to enforce the
+ /// unique-address-per-distinct-object-instance rule.
+ ZeroSized,
+
+ /// Whether this type is zero-sized or not depends on whether a type
+ /// parameter is zero-sized or not.
+ ///
+ /// For example, given these definitions:
+ ///
+ /// ```c++
+ /// template<class T>
+ /// class Flongo : public T {};
+ ///
+ /// class Empty {};
+ ///
+ /// class NonEmpty { int x; };
+ /// ```
+ ///
+ /// Then `Flongo<Empty>` is zero-sized, and needs an `_address` byte
+ /// inserted, while `Flongo<NonEmpty>` is *not* zero-sized, and should *not*
+ /// have an `_address` byte inserted.
+ ///
+ /// We don't properly handle this situation correctly right now:
+ /// <https://github.com/rust-lang/rust-bindgen/issues/586>
+ DependsOnTypeParam,
+
+ /// Has some size that is known to be greater than zero. That doesn't mean
+ /// it has a static size, but it is not zero sized for sure. In other words,
+ /// it might contain an incomplete array or some other dynamically sized
+ /// type.
+ NonZeroSized,
+}
+
+impl Default for SizednessResult {
+ fn default() -> Self {
+ SizednessResult::ZeroSized
+ }
+}
+
+impl SizednessResult {
+ /// Take the least upper bound of `self` and `rhs`.
+ pub(crate) fn join(self, rhs: Self) -> Self {
+ cmp::max(self, rhs)
+ }
+}
+
+impl ops::BitOr for SizednessResult {
+ type Output = Self;
+
+ fn bitor(self, rhs: SizednessResult) -> Self::Output {
+ self.join(rhs)
+ }
+}
+
+impl ops::BitOrAssign for SizednessResult {
+ fn bitor_assign(&mut self, rhs: SizednessResult) {
+ *self = self.join(rhs)
+ }
+}
+
+/// An analysis that computes the sizedness of all types.
+///
+/// * For types with known sizes -- for example pointers, scalars, etc... --
+/// they are assigned `NonZeroSized`.
+///
+/// * For compound structure types with one or more fields, they are assigned
+/// `NonZeroSized`.
+///
+/// * For compound structure types without any fields, the results of the bases
+/// are `join`ed.
+///
+/// * For type parameters, `DependsOnTypeParam` is assigned.
+#[derive(Debug)]
+pub(crate) struct SizednessAnalysis<'ctx> {
+ ctx: &'ctx BindgenContext,
+ dependencies: HashMap<TypeId, Vec<TypeId>>,
+ // Incremental results of the analysis. Missing entries are implicitly
+ // considered `ZeroSized`.
+ sized: HashMap<TypeId, SizednessResult>,
+}
+
+impl<'ctx> SizednessAnalysis<'ctx> {
+ fn consider_edge(kind: EdgeKind) -> bool {
+ // These are the only edges that can affect whether a type is
+ // zero-sized or not.
+ matches!(
+ kind,
+ EdgeKind::TemplateArgument |
+ EdgeKind::TemplateParameterDefinition |
+ EdgeKind::TemplateDeclaration |
+ EdgeKind::TypeReference |
+ EdgeKind::BaseMember |
+ EdgeKind::Field
+ )
+ }
+
+ /// Insert an incremental result, and return whether this updated our
+ /// knowledge of types and we should continue the analysis.
+ fn insert(
+ &mut self,
+ id: TypeId,
+ result: SizednessResult,
+ ) -> ConstrainResult {
+ trace!("inserting {:?} for {:?}", result, id);
+
+ if let SizednessResult::ZeroSized = result {
+ return ConstrainResult::Same;
+ }
+
+ match self.sized.entry(id) {
+ Entry::Occupied(mut entry) => {
+ if *entry.get() < result {
+ entry.insert(result);
+ ConstrainResult::Changed
+ } else {
+ ConstrainResult::Same
+ }
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(result);
+ ConstrainResult::Changed
+ }
+ }
+ }
+
+ fn forward(&mut self, from: TypeId, to: TypeId) -> ConstrainResult {
+ match self.sized.get(&from).cloned() {
+ None => ConstrainResult::Same,
+ Some(r) => self.insert(to, r),
+ }
+ }
+}
+
+impl<'ctx> MonotoneFramework for SizednessAnalysis<'ctx> {
+ type Node = TypeId;
+ type Extra = &'ctx BindgenContext;
+ type Output = HashMap<TypeId, SizednessResult>;
+
+ fn new(ctx: &'ctx BindgenContext) -> SizednessAnalysis<'ctx> {
+ let dependencies = generate_dependencies(ctx, Self::consider_edge)
+ .into_iter()
+ .filter_map(|(id, sub_ids)| {
+ id.as_type_id(ctx).map(|id| {
+ (
+ id,
+ sub_ids
+ .into_iter()
+ .filter_map(|s| s.as_type_id(ctx))
+ .collect::<Vec<_>>(),
+ )
+ })
+ })
+ .collect();
+
+ let sized = HashMap::default();
+
+ SizednessAnalysis {
+ ctx,
+ dependencies,
+ sized,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<TypeId> {
+ self.ctx
+ .allowlisted_items()
+ .iter()
+ .cloned()
+ .filter_map(|id| id.as_type_id(self.ctx))
+ .collect()
+ }
+
+ fn constrain(&mut self, id: TypeId) -> ConstrainResult {
+ trace!("constrain {:?}", id);
+
+ if let Some(SizednessResult::NonZeroSized) =
+ self.sized.get(&id).cloned()
+ {
+ trace!(" already know it is not zero-sized");
+ return ConstrainResult::Same;
+ }
+
+ if id.has_vtable_ptr(self.ctx) {
+ trace!(" has an explicit vtable pointer, therefore is not zero-sized");
+ return self.insert(id, SizednessResult::NonZeroSized);
+ }
+
+ let ty = self.ctx.resolve_type(id);
+
+ if id.is_opaque(self.ctx, &()) {
+ trace!(" type is opaque; checking layout...");
+ let result =
+ ty.layout(self.ctx).map_or(SizednessResult::ZeroSized, |l| {
+ if l.size == 0 {
+ trace!(" ...layout has size == 0");
+ SizednessResult::ZeroSized
+ } else {
+ trace!(" ...layout has size > 0");
+ SizednessResult::NonZeroSized
+ }
+ });
+ return self.insert(id, result);
+ }
+
+ match *ty.kind() {
+ TypeKind::Void => {
+ trace!(" void is zero-sized");
+ self.insert(id, SizednessResult::ZeroSized)
+ }
+
+ TypeKind::TypeParam => {
+ trace!(
+ " type params sizedness depends on what they're \
+ instantiated as"
+ );
+ self.insert(id, SizednessResult::DependsOnTypeParam)
+ }
+
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::NullPtr |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel |
+ TypeKind::Pointer(..) => {
+ trace!(" {:?} is known not to be zero-sized", ty.kind());
+ self.insert(id, SizednessResult::NonZeroSized)
+ }
+
+ TypeKind::ObjCInterface(..) => {
+ trace!(" obj-c interfaces always have at least the `isa` pointer");
+ self.insert(id, SizednessResult::NonZeroSized)
+ }
+
+ TypeKind::TemplateAlias(t, _) |
+ TypeKind::Alias(t) |
+ TypeKind::BlockPointer(t) |
+ TypeKind::ResolvedTypeRef(t) => {
+ trace!(" aliases and type refs forward to their inner type");
+ self.forward(t, id)
+ }
+
+ TypeKind::TemplateInstantiation(ref inst) => {
+ trace!(
+ " template instantiations are zero-sized if their \
+ definition is zero-sized"
+ );
+ self.forward(inst.template_definition(), id)
+ }
+
+ TypeKind::Array(_, 0) => {
+ trace!(" arrays of zero elements are zero-sized");
+ self.insert(id, SizednessResult::ZeroSized)
+ }
+ TypeKind::Array(..) => {
+ trace!(" arrays of > 0 elements are not zero-sized");
+ self.insert(id, SizednessResult::NonZeroSized)
+ }
+ TypeKind::Vector(..) => {
+ trace!(" vectors are not zero-sized");
+ self.insert(id, SizednessResult::NonZeroSized)
+ }
+
+ TypeKind::Comp(ref info) => {
+ trace!(" comp considers its own fields and bases");
+
+ if !info.fields().is_empty() {
+ return self.insert(id, SizednessResult::NonZeroSized);
+ }
+
+ let result = info
+ .base_members()
+ .iter()
+ .filter_map(|base| self.sized.get(&base.ty))
+ .fold(SizednessResult::ZeroSized, |a, b| a.join(*b));
+
+ self.insert(id, result)
+ }
+
+ TypeKind::Opaque => {
+ unreachable!("covered by the .is_opaque() check above")
+ }
+
+ TypeKind::UnresolvedTypeRef(..) => {
+ unreachable!("Should have been resolved after parsing!");
+ }
+ }
+ }
+
+ fn each_depending_on<F>(&self, id: TypeId, mut f: F)
+ where
+ F: FnMut(TypeId),
+ {
+ if let Some(edges) = self.dependencies.get(&id) {
+ for ty in edges {
+ trace!("enqueue {:?} into worklist", ty);
+ f(*ty);
+ }
+ }
+ }
+}
+
+impl<'ctx> From<SizednessAnalysis<'ctx>> for HashMap<TypeId, SizednessResult> {
+ fn from(analysis: SizednessAnalysis<'ctx>) -> Self {
+ // We let the lack of an entry mean "ZeroSized" to save space.
+ extra_assert!(analysis
+ .sized
+ .values()
+ .all(|v| { *v != SizednessResult::ZeroSized }));
+
+ analysis.sized
+ }
+}
+
+/// A convenience trait for querying whether some type or ID is sized.
+///
+/// This is not for _computing_ whether the thing is sized, it is for looking up
+/// the results of the `Sizedness` analysis's computations for a specific thing.
+pub(crate) trait Sizedness {
+ /// Get the sizedness of this type.
+ fn sizedness(&self, ctx: &BindgenContext) -> SizednessResult;
+
+ /// Is the sizedness for this type `SizednessResult::ZeroSized`?
+ fn is_zero_sized(&self, ctx: &BindgenContext) -> bool {
+ self.sizedness(ctx) == SizednessResult::ZeroSized
+ }
+}
diff --git a/third_party/rust/bindgen/ir/analysis/template_params.rs b/third_party/rust/bindgen/ir/analysis/template_params.rs
new file mode 100644
index 0000000000..e4261cf675
--- /dev/null
+++ b/third_party/rust/bindgen/ir/analysis/template_params.rs
@@ -0,0 +1,607 @@
+//! Discover which template type parameters are actually used.
+//!
+//! ### Why do we care?
+//!
+//! C++ allows ignoring template parameters, while Rust does not. Usually we can
+//! blindly stick a `PhantomData<T>` inside a generic Rust struct to make up for
+//! this. That doesn't work for templated type aliases, however:
+//!
+//! ```C++
+//! template <typename T>
+//! using Fml = int;
+//! ```
+//!
+//! If we generate the naive Rust code for this alias, we get:
+//!
+//! ```ignore
+//! pub(crate) type Fml<T> = ::std::os::raw::int;
+//! ```
+//!
+//! And this is rejected by `rustc` due to the unused type parameter.
+//!
+//! (Aside: in these simple cases, `libclang` will often just give us the
+//! aliased type directly, and we will never even know we were dealing with
+//! aliases, let alone templated aliases. It's the more convoluted scenarios
+//! where we get to have some fun...)
+//!
+//! For such problematic template aliases, we could generate a tuple whose
+//! second member is a `PhantomData<T>`. Or, if we wanted to go the extra mile,
+//! we could even generate some smarter wrapper that implements `Deref`,
+//! `DerefMut`, `From`, `Into`, `AsRef`, and `AsMut` to the actually aliased
+//! type. However, this is still lackluster:
+//!
+//! 1. Even with a billion conversion-trait implementations, using the generated
+//! bindings is rather un-ergonomic.
+//! 2. With either of these solutions, we need to keep track of which aliases
+//! we've transformed like this in order to generate correct uses of the
+//! wrapped type.
+//!
+//! Given that we have to properly track which template parameters ended up used
+//! for (2), we might as well leverage that information to make ergonomic
+//! bindings that don't contain any unused type parameters at all, and
+//! completely avoid the pain of (1).
+//!
+//! ### How do we determine which template parameters are used?
+//!
+//! Determining which template parameters are actually used is a trickier
+//! problem than it might seem at a glance. On the one hand, trivial uses are
+//! easy to detect:
+//!
+//! ```C++
+//! template <typename T>
+//! class Foo {
+//! T trivial_use_of_t;
+//! };
+//! ```
+//!
+//! It gets harder when determining if one template parameter is used depends on
+//! determining if another template parameter is used. In this example, whether
+//! `U` is used depends on whether `T` is used.
+//!
+//! ```C++
+//! template <typename T>
+//! class DoesntUseT {
+//! int x;
+//! };
+//!
+//! template <typename U>
+//! class Fml {
+//! DoesntUseT<U> lololol;
+//! };
+//! ```
+//!
+//! We can express the set of used template parameters as a constraint solving
+//! problem (where the set of template parameters used by a given IR item is the
+//! union of its sub-item's used template parameters) and iterate to a
+//! fixed-point.
+//!
+//! We use the `ir::analysis::MonotoneFramework` infrastructure for this
+//! fix-point analysis, where our lattice is the mapping from each IR item to
+//! the powerset of the template parameters that appear in the input C++ header,
+//! our join function is set union. The set of template parameters appearing in
+//! the program is finite, as is the number of IR items. We start at our
+//! lattice's bottom element: every item mapping to an empty set of template
+//! parameters. Our analysis only adds members to each item's set of used
+//! template parameters, never removes them, so it is monotone. Because our
+//! lattice is finite and our constraint function is monotone, iteration to a
+//! fix-point will terminate.
+//!
+//! See `src/ir/analysis.rs` for more.
+
+use super::{ConstrainResult, MonotoneFramework};
+use crate::ir::context::{BindgenContext, ItemId};
+use crate::ir::item::{Item, ItemSet};
+use crate::ir::template::{TemplateInstantiation, TemplateParameters};
+use crate::ir::traversal::{EdgeKind, Trace};
+use crate::ir::ty::TypeKind;
+use crate::{HashMap, HashSet};
+
+/// An analysis that finds for each IR item its set of template parameters that
+/// it uses.
+///
+/// We use the monotone constraint function `template_param_usage`, defined as
+/// follows:
+///
+/// * If `T` is a named template type parameter, it trivially uses itself:
+///
+/// ```ignore
+/// template_param_usage(T) = { T }
+/// ```
+///
+/// * If `inst` is a template instantiation, `inst.args` are the template
+/// instantiation's template arguments, `inst.def` is the template definition
+/// being instantiated, and `inst.def.params` is the template definition's
+/// template parameters, then the instantiation's usage is the union of each
+/// of its arguments' usages *if* the corresponding template parameter is in
+/// turn used by the template definition:
+///
+/// ```ignore
+/// template_param_usage(inst) = union(
+/// template_param_usage(inst.args[i])
+/// for i in 0..length(inst.args.length)
+/// if inst.def.params[i] in template_param_usage(inst.def)
+/// )
+/// ```
+///
+/// * Finally, for all other IR item kinds, we use our lattice's `join`
+/// operation: set union with each successor of the given item's template
+/// parameter usage:
+///
+/// ```ignore
+/// template_param_usage(v) =
+/// union(template_param_usage(w) for w in successors(v))
+/// ```
+///
+/// Note that we ignore certain edges in the graph, such as edges from a
+/// template declaration to its template parameters' definitions for this
+/// analysis. If we didn't, then we would mistakenly determine that ever
+/// template parameter is always used.
+///
+/// The final wrinkle is handling of blocklisted types. Normally, we say that
+/// the set of allowlisted items is the transitive closure of items explicitly
+/// called out for allowlisting, *without* any items explicitly called out as
+/// blocklisted. However, for the purposes of this analysis's correctness, we
+/// simplify and consider run the analysis on the full transitive closure of
+/// allowlisted items. We do, however, treat instantiations of blocklisted items
+/// specially; see `constrain_instantiation_of_blocklisted_template` and its
+/// documentation for details.
+#[derive(Debug, Clone)]
+pub(crate) struct UsedTemplateParameters<'ctx> {
+ ctx: &'ctx BindgenContext,
+
+ // The Option is only there for temporary moves out of the hash map. See the
+ // comments in `UsedTemplateParameters::constrain` below.
+ used: HashMap<ItemId, Option<ItemSet>>,
+
+ dependencies: HashMap<ItemId, Vec<ItemId>>,
+
+ // The set of allowlisted items, without any blocklisted items reachable
+ // from the allowlisted items which would otherwise be considered
+ // allowlisted as well.
+ allowlisted_items: HashSet<ItemId>,
+}
+
+impl<'ctx> UsedTemplateParameters<'ctx> {
+ fn consider_edge(kind: EdgeKind) -> bool {
+ match kind {
+ // For each of these kinds of edges, if the referent uses a template
+ // parameter, then it should be considered that the origin of the
+ // edge also uses the template parameter.
+ EdgeKind::TemplateArgument |
+ EdgeKind::BaseMember |
+ EdgeKind::Field |
+ EdgeKind::Constructor |
+ EdgeKind::Destructor |
+ EdgeKind::VarType |
+ EdgeKind::FunctionReturn |
+ EdgeKind::FunctionParameter |
+ EdgeKind::TypeReference => true,
+
+ // An inner var or type using a template parameter is orthogonal
+ // from whether we use it. See template-param-usage-{6,11}.hpp.
+ EdgeKind::InnerVar | EdgeKind::InnerType => false,
+
+ // We can't emit machine code for new monomorphizations of class
+ // templates' methods (and don't detect explicit instantiations) so
+ // we must ignore template parameters that are only used by
+ // methods. This doesn't apply to a function type's return or
+ // parameter types, however, because of type aliases of function
+ // pointers that use template parameters, eg
+ // tests/headers/struct_with_typedef_template_arg.hpp
+ EdgeKind::Method => false,
+
+ // If we considered these edges, we would end up mistakenly claiming
+ // that every template parameter always used.
+ EdgeKind::TemplateDeclaration |
+ EdgeKind::TemplateParameterDefinition => false,
+
+ // Since we have to be careful about which edges we consider for
+ // this analysis to be correct, we ignore generic edges. We also
+ // avoid a `_` wild card to force authors of new edge kinds to
+ // determine whether they need to be considered by this analysis.
+ EdgeKind::Generic => false,
+ }
+ }
+
+ fn take_this_id_usage_set<Id: Into<ItemId>>(
+ &mut self,
+ this_id: Id,
+ ) -> ItemSet {
+ let this_id = this_id.into();
+ self.used
+ .get_mut(&this_id)
+ .expect(
+ "Should have a set of used template params for every item \
+ id",
+ )
+ .take()
+ .expect(
+ "Should maintain the invariant that all used template param \
+ sets are `Some` upon entry of `constrain`",
+ )
+ }
+
+ /// We say that blocklisted items use all of their template parameters. The
+ /// blocklisted type is most likely implemented explicitly by the user,
+ /// since it won't be in the generated bindings, and we don't know exactly
+ /// what they'll to with template parameters, but we can push the issue down
+ /// the line to them.
+ fn constrain_instantiation_of_blocklisted_template(
+ &self,
+ this_id: ItemId,
+ used_by_this_id: &mut ItemSet,
+ instantiation: &TemplateInstantiation,
+ ) {
+ trace!(
+ " instantiation of blocklisted template, uses all template \
+ arguments"
+ );
+
+ let args = instantiation
+ .template_arguments()
+ .iter()
+ .map(|a| {
+ a.into_resolver()
+ .through_type_refs()
+ .through_type_aliases()
+ .resolve(self.ctx)
+ .id()
+ })
+ .filter(|a| *a != this_id)
+ .flat_map(|a| {
+ self.used
+ .get(&a)
+ .expect("Should have a used entry for the template arg")
+ .as_ref()
+ .expect(
+ "Because a != this_id, and all used template \
+ param sets other than this_id's are `Some`, \
+ a's used template param set should be `Some`",
+ )
+ .iter()
+ .cloned()
+ });
+
+ used_by_this_id.extend(args);
+ }
+
+ /// A template instantiation's concrete template argument is only used if
+ /// the template definition uses the corresponding template parameter.
+ fn constrain_instantiation(
+ &self,
+ this_id: ItemId,
+ used_by_this_id: &mut ItemSet,
+ instantiation: &TemplateInstantiation,
+ ) {
+ trace!(" template instantiation");
+
+ let decl = self.ctx.resolve_type(instantiation.template_definition());
+ let args = instantiation.template_arguments();
+
+ let params = decl.self_template_params(self.ctx);
+
+ debug_assert!(this_id != instantiation.template_definition());
+ let used_by_def = self.used
+ .get(&instantiation.template_definition().into())
+ .expect("Should have a used entry for instantiation's template definition")
+ .as_ref()
+ .expect("And it should be Some because only this_id's set is None, and an \
+ instantiation's template definition should never be the \
+ instantiation itself");
+
+ for (arg, param) in args.iter().zip(params.iter()) {
+ trace!(
+ " instantiation's argument {:?} is used if definition's \
+ parameter {:?} is used",
+ arg,
+ param
+ );
+
+ if used_by_def.contains(&param.into()) {
+ trace!(" param is used by template definition");
+
+ let arg = arg
+ .into_resolver()
+ .through_type_refs()
+ .through_type_aliases()
+ .resolve(self.ctx)
+ .id();
+
+ if arg == this_id {
+ continue;
+ }
+
+ let used_by_arg = self
+ .used
+ .get(&arg)
+ .expect("Should have a used entry for the template arg")
+ .as_ref()
+ .expect(
+ "Because arg != this_id, and all used template \
+ param sets other than this_id's are `Some`, \
+ arg's used template param set should be \
+ `Some`",
+ )
+ .iter()
+ .cloned();
+ used_by_this_id.extend(used_by_arg);
+ }
+ }
+ }
+
+ /// The join operation on our lattice: the set union of all of this ID's
+ /// successors.
+ fn constrain_join(&self, used_by_this_id: &mut ItemSet, item: &Item) {
+ trace!(" other item: join with successors' usage");
+
+ item.trace(
+ self.ctx,
+ &mut |sub_id, edge_kind| {
+ // Ignore ourselves, since union with ourself is a
+ // no-op. Ignore edges that aren't relevant to the
+ // analysis.
+ if sub_id == item.id() || !Self::consider_edge(edge_kind) {
+ return;
+ }
+
+ let used_by_sub_id = self
+ .used
+ .get(&sub_id)
+ .expect("Should have a used set for the sub_id successor")
+ .as_ref()
+ .expect(
+ "Because sub_id != id, and all used template \
+ param sets other than id's are `Some`, \
+ sub_id's used template param set should be \
+ `Some`",
+ )
+ .iter()
+ .cloned();
+
+ trace!(
+ " union with {:?}'s usage: {:?}",
+ sub_id,
+ used_by_sub_id.clone().collect::<Vec<_>>()
+ );
+
+ used_by_this_id.extend(used_by_sub_id);
+ },
+ &(),
+ );
+ }
+}
+
+impl<'ctx> MonotoneFramework for UsedTemplateParameters<'ctx> {
+ type Node = ItemId;
+ type Extra = &'ctx BindgenContext;
+ type Output = HashMap<ItemId, ItemSet>;
+
+ fn new(ctx: &'ctx BindgenContext) -> UsedTemplateParameters<'ctx> {
+ let mut used = HashMap::default();
+ let mut dependencies = HashMap::default();
+ let allowlisted_items: HashSet<_> =
+ ctx.allowlisted_items().iter().cloned().collect();
+
+ let allowlisted_and_blocklisted_items: ItemSet = allowlisted_items
+ .iter()
+ .cloned()
+ .flat_map(|i| {
+ let mut reachable = vec![i];
+ i.trace(
+ ctx,
+ &mut |s, _| {
+ reachable.push(s);
+ },
+ &(),
+ );
+ reachable
+ })
+ .collect();
+
+ for item in allowlisted_and_blocklisted_items {
+ dependencies.entry(item).or_insert_with(Vec::new);
+ used.entry(item).or_insert_with(|| Some(ItemSet::new()));
+
+ {
+ // We reverse our natural IR graph edges to find dependencies
+ // between nodes.
+ item.trace(
+ ctx,
+ &mut |sub_item: ItemId, _| {
+ used.entry(sub_item)
+ .or_insert_with(|| Some(ItemSet::new()));
+ dependencies
+ .entry(sub_item)
+ .or_insert_with(Vec::new)
+ .push(item);
+ },
+ &(),
+ );
+ }
+
+ // Additionally, whether a template instantiation's template
+ // arguments are used depends on whether the template declaration's
+ // generic template parameters are used.
+ let item_kind =
+ ctx.resolve_item(item).as_type().map(|ty| ty.kind());
+ if let Some(TypeKind::TemplateInstantiation(inst)) = item_kind {
+ let decl = ctx.resolve_type(inst.template_definition());
+ let args = inst.template_arguments();
+
+ // Although template definitions should always have
+ // template parameters, there is a single exception:
+ // opaque templates. Hence the unwrap_or.
+ let params = decl.self_template_params(ctx);
+
+ for (arg, param) in args.iter().zip(params.iter()) {
+ let arg = arg
+ .into_resolver()
+ .through_type_aliases()
+ .through_type_refs()
+ .resolve(ctx)
+ .id();
+
+ let param = param
+ .into_resolver()
+ .through_type_aliases()
+ .through_type_refs()
+ .resolve(ctx)
+ .id();
+
+ used.entry(arg).or_insert_with(|| Some(ItemSet::new()));
+ used.entry(param).or_insert_with(|| Some(ItemSet::new()));
+
+ dependencies
+ .entry(arg)
+ .or_insert_with(Vec::new)
+ .push(param);
+ }
+ }
+ }
+
+ if cfg!(feature = "__testing_only_extra_assertions") {
+ // Invariant: The `used` map has an entry for every allowlisted
+ // item, as well as all explicitly blocklisted items that are
+ // reachable from allowlisted items.
+ //
+ // Invariant: the `dependencies` map has an entry for every
+ // allowlisted item.
+ //
+ // (This is so that every item we call `constrain` on is guaranteed
+ // to have a set of template parameters, and we can allow
+ // blocklisted templates to use all of their parameters).
+ for item in allowlisted_items.iter() {
+ extra_assert!(used.contains_key(item));
+ extra_assert!(dependencies.contains_key(item));
+ item.trace(
+ ctx,
+ &mut |sub_item, _| {
+ extra_assert!(used.contains_key(&sub_item));
+ extra_assert!(dependencies.contains_key(&sub_item));
+ },
+ &(),
+ )
+ }
+ }
+
+ UsedTemplateParameters {
+ ctx,
+ used,
+ dependencies,
+ allowlisted_items,
+ }
+ }
+
+ fn initial_worklist(&self) -> Vec<ItemId> {
+ // The transitive closure of all allowlisted items, including explicitly
+ // blocklisted items.
+ self.ctx
+ .allowlisted_items()
+ .iter()
+ .cloned()
+ .flat_map(|i| {
+ let mut reachable = vec![i];
+ i.trace(
+ self.ctx,
+ &mut |s, _| {
+ reachable.push(s);
+ },
+ &(),
+ );
+ reachable
+ })
+ .collect()
+ }
+
+ fn constrain(&mut self, id: ItemId) -> ConstrainResult {
+ // Invariant: all hash map entries' values are `Some` upon entering and
+ // exiting this method.
+ extra_assert!(self.used.values().all(|v| v.is_some()));
+
+ // Take the set for this ID out of the hash map while we mutate it based
+ // on other hash map entries. We *must* put it back into the hash map at
+ // the end of this method. This allows us to side-step HashMap's lack of
+ // an analog to slice::split_at_mut.
+ let mut used_by_this_id = self.take_this_id_usage_set(id);
+
+ trace!("constrain {:?}", id);
+ trace!(" initially, used set is {:?}", used_by_this_id);
+
+ let original_len = used_by_this_id.len();
+
+ let item = self.ctx.resolve_item(id);
+ let ty_kind = item.as_type().map(|ty| ty.kind());
+ match ty_kind {
+ // Named template type parameters trivially use themselves.
+ Some(&TypeKind::TypeParam) => {
+ trace!(" named type, trivially uses itself");
+ used_by_this_id.insert(id);
+ }
+ // Template instantiations only use their template arguments if the
+ // template definition uses the corresponding template parameter.
+ Some(TypeKind::TemplateInstantiation(inst)) => {
+ if self
+ .allowlisted_items
+ .contains(&inst.template_definition().into())
+ {
+ self.constrain_instantiation(
+ id,
+ &mut used_by_this_id,
+ inst,
+ );
+ } else {
+ self.constrain_instantiation_of_blocklisted_template(
+ id,
+ &mut used_by_this_id,
+ inst,
+ );
+ }
+ }
+ // Otherwise, add the union of each of its referent item's template
+ // parameter usage.
+ _ => self.constrain_join(&mut used_by_this_id, item),
+ }
+
+ trace!(" finally, used set is {:?}", used_by_this_id);
+
+ let new_len = used_by_this_id.len();
+ assert!(
+ new_len >= original_len,
+ "This is the property that ensures this function is monotone -- \
+ if it doesn't hold, the analysis might never terminate!"
+ );
+
+ // Put the set back in the hash map and restore our invariant.
+ debug_assert!(self.used[&id].is_none());
+ self.used.insert(id, Some(used_by_this_id));
+ extra_assert!(self.used.values().all(|v| v.is_some()));
+
+ if new_len != original_len {
+ ConstrainResult::Changed
+ } else {
+ ConstrainResult::Same
+ }
+ }
+
+ fn each_depending_on<F>(&self, item: ItemId, mut f: F)
+ where
+ F: FnMut(ItemId),
+ {
+ if let Some(edges) = self.dependencies.get(&item) {
+ for item in edges {
+ trace!("enqueue {:?} into worklist", item);
+ f(*item);
+ }
+ }
+ }
+}
+
+impl<'ctx> From<UsedTemplateParameters<'ctx>> for HashMap<ItemId, ItemSet> {
+ fn from(used_templ_params: UsedTemplateParameters<'ctx>) -> Self {
+ used_templ_params
+ .used
+ .into_iter()
+ .map(|(k, v)| (k, v.unwrap()))
+ .collect()
+ }
+}
diff --git a/third_party/rust/bindgen/ir/annotations.rs b/third_party/rust/bindgen/ir/annotations.rs
new file mode 100644
index 0000000000..d085f5c574
--- /dev/null
+++ b/third_party/rust/bindgen/ir/annotations.rs
@@ -0,0 +1,256 @@
+//! Types and functions related to bindgen annotation comments.
+//!
+//! Users can add annotations in doc comments to types that they would like to
+//! replace other types with, mark as opaque, etc. This module deals with all of
+//! that stuff.
+
+use std::str::FromStr;
+
+use crate::clang;
+
+/// What kind of visibility modifer should be used for a struct or field?
+#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
+pub enum FieldVisibilityKind {
+ /// Fields are marked as private, i.e., struct Foo {bar: bool}
+ Private,
+ /// Fields are marked as crate public, i.e., struct Foo {pub(crate) bar: bool}
+ PublicCrate,
+ /// Fields are marked as public, i.e., struct Foo {pub bar: bool}
+ Public,
+}
+
+impl FromStr for FieldVisibilityKind {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "private" => Ok(Self::Private),
+ "crate" => Ok(Self::PublicCrate),
+ "public" => Ok(Self::Public),
+ _ => Err(format!("Invalid visibility kind: `{}`", s)),
+ }
+ }
+}
+
+impl std::fmt::Display for FieldVisibilityKind {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let s = match self {
+ FieldVisibilityKind::Private => "private",
+ FieldVisibilityKind::PublicCrate => "crate",
+ FieldVisibilityKind::Public => "public",
+ };
+
+ s.fmt(f)
+ }
+}
+
+impl Default for FieldVisibilityKind {
+ fn default() -> Self {
+ FieldVisibilityKind::Public
+ }
+}
+
+/// What kind of accessor should we provide for a field?
+#[derive(Copy, PartialEq, Eq, Clone, Debug)]
+pub(crate) enum FieldAccessorKind {
+ /// No accessor.
+ None,
+ /// Plain accessor.
+ Regular,
+ /// Unsafe accessor.
+ Unsafe,
+ /// Immutable accessor.
+ Immutable,
+}
+
+/// Annotations for a given item, or a field.
+///
+/// You can see the kind of comments that are accepted in the [Doxygen documentation](https://www.doxygen.nl/manual/docblocks.html).
+#[derive(Default, Clone, PartialEq, Eq, Debug)]
+pub(crate) struct Annotations {
+ /// Whether this item is marked as opaque. Only applies to types.
+ opaque: bool,
+ /// Whether this item should be hidden from the output. Only applies to
+ /// types, or enum variants.
+ hide: bool,
+ /// Whether this type should be replaced by another. The name is a
+ /// namespace-aware path.
+ use_instead_of: Option<Vec<String>>,
+ /// Manually disable deriving copy/clone on this type. Only applies to
+ /// struct or union types.
+ disallow_copy: bool,
+ /// Manually disable deriving debug on this type.
+ disallow_debug: bool,
+ /// Manually disable deriving/implement default on this type.
+ disallow_default: bool,
+ /// Whether to add a `#[must_use]` annotation to this type.
+ must_use_type: bool,
+ /// Visibility of struct fields. You can set this on
+ /// structs (it will apply to all the fields), or individual fields.
+ visibility_kind: Option<FieldVisibilityKind>,
+ /// The kind of accessor this field will have. Also can be applied to
+ /// structs so all the fields inside share it by default.
+ accessor_kind: Option<FieldAccessorKind>,
+ /// Whether this enum variant should be constified.
+ ///
+ /// This is controlled by the `constant` attribute, this way:
+ ///
+ /// ```cpp
+ /// enum Foo {
+ /// Bar = 0, /**< <div rustbindgen constant></div> */
+ /// Baz = 0,
+ /// };
+ /// ```
+ ///
+ /// In that case, bindgen will generate a constant for `Bar` instead of
+ /// `Baz`.
+ constify_enum_variant: bool,
+ /// List of explicit derives for this type.
+ derives: Vec<String>,
+}
+
+fn parse_accessor(s: &str) -> FieldAccessorKind {
+ match s {
+ "false" => FieldAccessorKind::None,
+ "unsafe" => FieldAccessorKind::Unsafe,
+ "immutable" => FieldAccessorKind::Immutable,
+ _ => FieldAccessorKind::Regular,
+ }
+}
+
+impl Annotations {
+ /// Construct new annotations for the given cursor and its bindgen comments
+ /// (if any).
+ pub(crate) fn new(cursor: &clang::Cursor) -> Option<Annotations> {
+ let mut anno = Annotations::default();
+ let mut matched_one = false;
+ anno.parse(&cursor.comment(), &mut matched_one);
+
+ if matched_one {
+ Some(anno)
+ } else {
+ None
+ }
+ }
+
+ /// Should this type be hidden?
+ pub(crate) fn hide(&self) -> bool {
+ self.hide
+ }
+
+ /// Should this type be opaque?
+ pub(crate) fn opaque(&self) -> bool {
+ self.opaque
+ }
+
+ /// For a given type, indicates the type it should replace.
+ ///
+ /// For example, in the following code:
+ ///
+ /// ```cpp
+ ///
+ /// /** <div rustbindgen replaces="Bar"></div> */
+ /// struct Foo { int x; };
+ ///
+ /// struct Bar { char foo; };
+ /// ```
+ ///
+ /// the generated code would look something like:
+ ///
+ /// ```
+ /// /** <div rustbindgen replaces="Bar"></div> */
+ /// struct Bar {
+ /// x: ::std::os::raw::c_int,
+ /// };
+ /// ```
+ ///
+ /// That is, code for `Foo` is used to generate `Bar`.
+ pub(crate) fn use_instead_of(&self) -> Option<&[String]> {
+ self.use_instead_of.as_deref()
+ }
+
+ /// The list of derives that have been specified in this annotation.
+ pub(crate) fn derives(&self) -> &[String] {
+ &self.derives
+ }
+
+ /// Should we avoid implementing the `Copy` trait?
+ pub(crate) fn disallow_copy(&self) -> bool {
+ self.disallow_copy
+ }
+
+ /// Should we avoid implementing the `Debug` trait?
+ pub(crate) fn disallow_debug(&self) -> bool {
+ self.disallow_debug
+ }
+
+ /// Should we avoid implementing the `Default` trait?
+ pub(crate) fn disallow_default(&self) -> bool {
+ self.disallow_default
+ }
+
+ /// Should this type get a `#[must_use]` annotation?
+ pub(crate) fn must_use_type(&self) -> bool {
+ self.must_use_type
+ }
+
+ /// What kind of accessors should we provide for this type's fields?
+ pub(crate) fn visibility_kind(&self) -> Option<FieldVisibilityKind> {
+ self.visibility_kind
+ }
+
+ /// What kind of accessors should we provide for this type's fields?
+ pub(crate) fn accessor_kind(&self) -> Option<FieldAccessorKind> {
+ self.accessor_kind
+ }
+
+ fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) {
+ use clang_sys::CXComment_HTMLStartTag;
+ if comment.kind() == CXComment_HTMLStartTag &&
+ comment.get_tag_name() == "div" &&
+ comment
+ .get_tag_attrs()
+ .next()
+ .map_or(false, |attr| attr.name == "rustbindgen")
+ {
+ *matched = true;
+ for attr in comment.get_tag_attrs() {
+ match attr.name.as_str() {
+ "opaque" => self.opaque = true,
+ "hide" => self.hide = true,
+ "nocopy" => self.disallow_copy = true,
+ "nodebug" => self.disallow_debug = true,
+ "nodefault" => self.disallow_default = true,
+ "mustusetype" => self.must_use_type = true,
+ "replaces" => {
+ self.use_instead_of = Some(
+ attr.value.split("::").map(Into::into).collect(),
+ )
+ }
+ "derive" => self.derives.push(attr.value),
+ "private" => {
+ self.visibility_kind = if attr.value != "false" {
+ Some(FieldVisibilityKind::Private)
+ } else {
+ Some(FieldVisibilityKind::Public)
+ };
+ }
+ "accessor" => {
+ self.accessor_kind = Some(parse_accessor(&attr.value))
+ }
+ "constant" => self.constify_enum_variant = true,
+ _ => {}
+ }
+ }
+ }
+
+ for child in comment.get_children() {
+ self.parse(&child, matched);
+ }
+ }
+
+ /// Returns whether we've parsed a "constant" attribute.
+ pub(crate) fn constify_enum_variant(&self) -> bool {
+ self.constify_enum_variant
+ }
+}
diff --git a/third_party/rust/bindgen/ir/comment.rs b/third_party/rust/bindgen/ir/comment.rs
new file mode 100644
index 0000000000..7b6f105a4d
--- /dev/null
+++ b/third_party/rust/bindgen/ir/comment.rs
@@ -0,0 +1,100 @@
+//! Utilities for manipulating C/C++ comments.
+
+/// The type of a comment.
+#[derive(Debug, PartialEq, Eq)]
+enum Kind {
+ /// A `///` comment, or something of the like.
+ /// All lines in a comment should start with the same symbol.
+ SingleLines,
+ /// A `/**` comment, where each other line can start with `*` and the
+ /// entire block ends with `*/`.
+ MultiLine,
+}
+
+/// Preprocesses a C/C++ comment so that it is a valid Rust comment.
+pub(crate) fn preprocess(comment: &str) -> String {
+ match self::kind(comment) {
+ Some(Kind::SingleLines) => preprocess_single_lines(comment),
+ Some(Kind::MultiLine) => preprocess_multi_line(comment),
+ None => comment.to_owned(),
+ }
+}
+
+/// Gets the kind of the doc comment, if it is one.
+fn kind(comment: &str) -> Option<Kind> {
+ if comment.starts_with("/*") {
+ Some(Kind::MultiLine)
+ } else if comment.starts_with("//") {
+ Some(Kind::SingleLines)
+ } else {
+ None
+ }
+}
+
+/// Preprocesses multiple single line comments.
+///
+/// Handles lines starting with both `//` and `///`.
+fn preprocess_single_lines(comment: &str) -> String {
+ debug_assert!(comment.starts_with("//"), "comment is not single line");
+
+ let lines: Vec<_> = comment
+ .lines()
+ .map(|l| l.trim().trim_start_matches('/'))
+ .collect();
+ lines.join("\n")
+}
+
+fn preprocess_multi_line(comment: &str) -> String {
+ let comment = comment
+ .trim_start_matches('/')
+ .trim_end_matches('/')
+ .trim_end_matches('*');
+
+ // Strip any potential `*` characters preceding each line.
+ let mut lines: Vec<_> = comment
+ .lines()
+ .map(|line| line.trim().trim_start_matches('*').trim_start_matches('!'))
+ .skip_while(|line| line.trim().is_empty()) // Skip the first empty lines.
+ .collect();
+
+ // Remove the trailing line corresponding to the `*/`.
+ if lines.last().map_or(false, |l| l.trim().is_empty()) {
+ lines.pop();
+ }
+
+ lines.join("\n")
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn picks_up_single_and_multi_line_doc_comments() {
+ assert_eq!(kind("/// hello"), Some(Kind::SingleLines));
+ assert_eq!(kind("/** world */"), Some(Kind::MultiLine));
+ }
+
+ #[test]
+ fn processes_single_lines_correctly() {
+ assert_eq!(preprocess("///"), "");
+ assert_eq!(preprocess("/// hello"), " hello");
+ assert_eq!(preprocess("// hello"), " hello");
+ assert_eq!(preprocess("// hello"), " hello");
+ }
+
+ #[test]
+ fn processes_multi_lines_correctly() {
+ assert_eq!(preprocess("/**/"), "");
+
+ assert_eq!(
+ preprocess("/** hello \n * world \n * foo \n */"),
+ " hello\n world\n foo"
+ );
+
+ assert_eq!(
+ preprocess("/**\nhello\n*world\n*foo\n*/"),
+ "hello\nworld\nfoo"
+ );
+ }
+}
diff --git a/third_party/rust/bindgen/ir/comp.rs b/third_party/rust/bindgen/ir/comp.rs
new file mode 100644
index 0000000000..fed6ba8ac8
--- /dev/null
+++ b/third_party/rust/bindgen/ir/comp.rs
@@ -0,0 +1,1896 @@
+//! Compound types (unions and structs) in our intermediate representation.
+
+use itertools::Itertools;
+
+use super::analysis::Sizedness;
+use super::annotations::Annotations;
+use super::context::{BindgenContext, FunctionId, ItemId, TypeId, VarId};
+use super::dot::DotAttributes;
+use super::item::{IsOpaque, Item};
+use super::layout::Layout;
+use super::template::TemplateParameters;
+use super::traversal::{EdgeKind, Trace, Tracer};
+use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
+use crate::clang;
+use crate::codegen::struct_layout::{align_to, bytes_from_bits_pow2};
+use crate::ir::derive::CanDeriveCopy;
+use crate::parse::ParseError;
+use crate::HashMap;
+use crate::NonCopyUnionStyle;
+use std::cmp;
+use std::io;
+use std::mem;
+
+/// The kind of compound type.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub(crate) enum CompKind {
+ /// A struct.
+ Struct,
+ /// A union.
+ Union,
+}
+
+/// The kind of C++ method.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub(crate) enum MethodKind {
+ /// A constructor. We represent it as method for convenience, to avoid code
+ /// duplication.
+ Constructor,
+ /// A destructor.
+ Destructor,
+ /// A virtual destructor.
+ VirtualDestructor {
+ /// Whether it's pure virtual.
+ pure_virtual: bool,
+ },
+ /// A static method.
+ Static,
+ /// A normal method.
+ Normal,
+ /// A virtual method.
+ Virtual {
+ /// Whether it's pure virtual.
+ pure_virtual: bool,
+ },
+}
+
+impl MethodKind {
+ /// Is this a destructor method?
+ pub(crate) fn is_destructor(&self) -> bool {
+ matches!(
+ *self,
+ MethodKind::Destructor | MethodKind::VirtualDestructor { .. }
+ )
+ }
+
+ /// Is this a pure virtual method?
+ pub(crate) fn is_pure_virtual(&self) -> bool {
+ match *self {
+ MethodKind::Virtual { pure_virtual } |
+ MethodKind::VirtualDestructor { pure_virtual } => pure_virtual,
+ _ => false,
+ }
+ }
+}
+
+/// A struct representing a C++ method, either static, normal, or virtual.
+#[derive(Debug)]
+pub(crate) struct Method {
+ kind: MethodKind,
+ /// The signature of the method. Take into account this is not a `Type`
+ /// item, but a `Function` one.
+ ///
+ /// This is tricky and probably this field should be renamed.
+ signature: FunctionId,
+ is_const: bool,
+}
+
+impl Method {
+ /// Construct a new `Method`.
+ pub(crate) fn new(
+ kind: MethodKind,
+ signature: FunctionId,
+ is_const: bool,
+ ) -> Self {
+ Method {
+ kind,
+ signature,
+ is_const,
+ }
+ }
+
+ /// What kind of method is this?
+ pub(crate) fn kind(&self) -> MethodKind {
+ self.kind
+ }
+
+ /// Is this a constructor?
+ pub(crate) fn is_constructor(&self) -> bool {
+ self.kind == MethodKind::Constructor
+ }
+
+ /// Is this a virtual method?
+ pub(crate) fn is_virtual(&self) -> bool {
+ matches!(
+ self.kind,
+ MethodKind::Virtual { .. } | MethodKind::VirtualDestructor { .. }
+ )
+ }
+
+ /// Is this a static method?
+ pub(crate) fn is_static(&self) -> bool {
+ self.kind == MethodKind::Static
+ }
+
+ /// Get the ID for the `Function` signature for this method.
+ pub(crate) fn signature(&self) -> FunctionId {
+ self.signature
+ }
+
+ /// Is this a const qualified method?
+ pub(crate) fn is_const(&self) -> bool {
+ self.is_const
+ }
+}
+
+/// Methods common to the various field types.
+pub(crate) trait FieldMethods {
+ /// Get the name of this field.
+ fn name(&self) -> Option<&str>;
+
+ /// Get the type of this field.
+ fn ty(&self) -> TypeId;
+
+ /// Get the comment for this field.
+ fn comment(&self) -> Option<&str>;
+
+ /// If this is a bitfield, how many bits does it need?
+ fn bitfield_width(&self) -> Option<u32>;
+
+ /// Is this feild declared public?
+ fn is_public(&self) -> bool;
+
+ /// Get the annotations for this field.
+ fn annotations(&self) -> &Annotations;
+
+ /// The offset of the field (in bits)
+ fn offset(&self) -> Option<usize>;
+}
+
+/// A contiguous set of logical bitfields that live within the same physical
+/// allocation unit. See 9.2.4 [class.bit] in the C++ standard and [section
+/// 2.4.II.1 in the Itanium C++
+/// ABI](http://itanium-cxx-abi.github.io/cxx-abi/abi.html#class-types).
+#[derive(Debug)]
+pub(crate) struct BitfieldUnit {
+ nth: usize,
+ layout: Layout,
+ bitfields: Vec<Bitfield>,
+}
+
+impl BitfieldUnit {
+ /// Get the 1-based index of this bitfield unit within its containing
+ /// struct. Useful for generating a Rust struct's field name for this unit
+ /// of bitfields.
+ pub(crate) fn nth(&self) -> usize {
+ self.nth
+ }
+
+ /// Get the layout within which these bitfields reside.
+ pub(crate) fn layout(&self) -> Layout {
+ self.layout
+ }
+
+ /// Get the bitfields within this unit.
+ pub(crate) fn bitfields(&self) -> &[Bitfield] {
+ &self.bitfields
+ }
+}
+
+/// A struct representing a C++ field.
+#[derive(Debug)]
+pub(crate) enum Field {
+ /// A normal data member.
+ DataMember(FieldData),
+
+ /// A physical allocation unit containing many logical bitfields.
+ Bitfields(BitfieldUnit),
+}
+
+impl Field {
+ /// Get this field's layout.
+ pub(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
+ match *self {
+ Field::Bitfields(BitfieldUnit { layout, .. }) => Some(layout),
+ Field::DataMember(ref data) => {
+ ctx.resolve_type(data.ty).layout(ctx)
+ }
+ }
+ }
+}
+
+impl Trace for Field {
+ type Extra = ();
+
+ fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
+ where
+ T: Tracer,
+ {
+ match *self {
+ Field::DataMember(ref data) => {
+ tracer.visit_kind(data.ty.into(), EdgeKind::Field);
+ }
+ Field::Bitfields(BitfieldUnit { ref bitfields, .. }) => {
+ for bf in bitfields {
+ tracer.visit_kind(bf.ty().into(), EdgeKind::Field);
+ }
+ }
+ }
+ }
+}
+
+impl DotAttributes for Field {
+ fn dot_attributes<W>(
+ &self,
+ ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ match *self {
+ Field::DataMember(ref data) => data.dot_attributes(ctx, out),
+ Field::Bitfields(BitfieldUnit {
+ layout,
+ ref bitfields,
+ ..
+ }) => {
+ writeln!(
+ out,
+ r#"<tr>
+ <td>bitfield unit</td>
+ <td>
+ <table border="0">
+ <tr>
+ <td>unit.size</td><td>{}</td>
+ </tr>
+ <tr>
+ <td>unit.align</td><td>{}</td>
+ </tr>
+ "#,
+ layout.size, layout.align
+ )?;
+ for bf in bitfields {
+ bf.dot_attributes(ctx, out)?;
+ }
+ writeln!(out, "</table></td></tr>")
+ }
+ }
+ }
+}
+
+impl DotAttributes for FieldData {
+ fn dot_attributes<W>(
+ &self,
+ _ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ writeln!(
+ out,
+ "<tr><td>{}</td><td>{:?}</td></tr>",
+ self.name().unwrap_or("(anonymous)"),
+ self.ty()
+ )
+ }
+}
+
+impl DotAttributes for Bitfield {
+ fn dot_attributes<W>(
+ &self,
+ _ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ writeln!(
+ out,
+ "<tr><td>{} : {}</td><td>{:?}</td></tr>",
+ self.name().unwrap_or("(anonymous)"),
+ self.width(),
+ self.ty()
+ )
+ }
+}
+
+/// A logical bitfield within some physical bitfield allocation unit.
+#[derive(Debug)]
+pub(crate) struct Bitfield {
+ /// Index of the bit within this bitfield's allocation unit where this
+ /// bitfield's bits begin.
+ offset_into_unit: usize,
+
+ /// The field data for this bitfield.
+ data: FieldData,
+
+ /// Name of the generated Rust getter for this bitfield.
+ ///
+ /// Should be assigned before codegen.
+ getter_name: Option<String>,
+
+ /// Name of the generated Rust setter for this bitfield.
+ ///
+ /// Should be assigned before codegen.
+ setter_name: Option<String>,
+}
+
+impl Bitfield {
+ /// Construct a new bitfield.
+ fn new(offset_into_unit: usize, raw: RawField) -> Bitfield {
+ assert!(raw.bitfield_width().is_some());
+
+ Bitfield {
+ offset_into_unit,
+ data: raw.0,
+ getter_name: None,
+ setter_name: None,
+ }
+ }
+
+ /// Get the index of the bit within this bitfield's allocation unit where
+ /// this bitfield begins.
+ pub(crate) fn offset_into_unit(&self) -> usize {
+ self.offset_into_unit
+ }
+
+ /// Get the bit width of this bitfield.
+ pub(crate) fn width(&self) -> u32 {
+ self.data.bitfield_width().unwrap()
+ }
+
+ /// Name of the generated Rust getter for this bitfield.
+ ///
+ /// Panics if called before assigning bitfield accessor names or if
+ /// this bitfield have no name.
+ pub(crate) fn getter_name(&self) -> &str {
+ assert!(
+ self.name().is_some(),
+ "`Bitfield::getter_name` called on anonymous field"
+ );
+ self.getter_name.as_ref().expect(
+ "`Bitfield::getter_name` should only be called after\
+ assigning bitfield accessor names",
+ )
+ }
+
+ /// Name of the generated Rust setter for this bitfield.
+ ///
+ /// Panics if called before assigning bitfield accessor names or if
+ /// this bitfield have no name.
+ pub(crate) fn setter_name(&self) -> &str {
+ assert!(
+ self.name().is_some(),
+ "`Bitfield::setter_name` called on anonymous field"
+ );
+ self.setter_name.as_ref().expect(
+ "`Bitfield::setter_name` should only be called\
+ after assigning bitfield accessor names",
+ )
+ }
+}
+
+impl FieldMethods for Bitfield {
+ fn name(&self) -> Option<&str> {
+ self.data.name()
+ }
+
+ fn ty(&self) -> TypeId {
+ self.data.ty()
+ }
+
+ fn comment(&self) -> Option<&str> {
+ self.data.comment()
+ }
+
+ fn bitfield_width(&self) -> Option<u32> {
+ self.data.bitfield_width()
+ }
+
+ fn is_public(&self) -> bool {
+ self.data.is_public()
+ }
+
+ fn annotations(&self) -> &Annotations {
+ self.data.annotations()
+ }
+
+ fn offset(&self) -> Option<usize> {
+ self.data.offset()
+ }
+}
+
+/// A raw field might be either of a plain data member or a bitfield within a
+/// bitfield allocation unit, but we haven't processed it and determined which
+/// yet (which would involve allocating it into a bitfield unit if it is a
+/// bitfield).
+#[derive(Debug)]
+struct RawField(FieldData);
+
+impl RawField {
+ /// Construct a new `RawField`.
+ fn new(
+ name: Option<String>,
+ ty: TypeId,
+ comment: Option<String>,
+ annotations: Option<Annotations>,
+ bitfield_width: Option<u32>,
+ public: bool,
+ offset: Option<usize>,
+ ) -> RawField {
+ RawField(FieldData {
+ name,
+ ty,
+ comment,
+ annotations: annotations.unwrap_or_default(),
+ bitfield_width,
+ public,
+ offset,
+ })
+ }
+}
+
+impl FieldMethods for RawField {
+ fn name(&self) -> Option<&str> {
+ self.0.name()
+ }
+
+ fn ty(&self) -> TypeId {
+ self.0.ty()
+ }
+
+ fn comment(&self) -> Option<&str> {
+ self.0.comment()
+ }
+
+ fn bitfield_width(&self) -> Option<u32> {
+ self.0.bitfield_width()
+ }
+
+ fn is_public(&self) -> bool {
+ self.0.is_public()
+ }
+
+ fn annotations(&self) -> &Annotations {
+ self.0.annotations()
+ }
+
+ fn offset(&self) -> Option<usize> {
+ self.0.offset()
+ }
+}
+
+/// Convert the given ordered set of raw fields into a list of either plain data
+/// members, and/or bitfield units containing multiple bitfields.
+///
+/// If we do not have the layout for a bitfield's type, then we can't reliably
+/// compute its allocation unit. In such cases, we return an error.
+fn raw_fields_to_fields_and_bitfield_units<I>(
+ ctx: &BindgenContext,
+ raw_fields: I,
+ packed: bool,
+) -> Result<(Vec<Field>, bool), ()>
+where
+ I: IntoIterator<Item = RawField>,
+{
+ let mut raw_fields = raw_fields.into_iter().fuse().peekable();
+ let mut fields = vec![];
+ let mut bitfield_unit_count = 0;
+
+ loop {
+ // While we have plain old data members, just keep adding them to our
+ // resulting fields. We introduce a scope here so that we can use
+ // `raw_fields` again after the `by_ref` iterator adaptor is dropped.
+ {
+ let non_bitfields = raw_fields
+ .by_ref()
+ .peeking_take_while(|f| f.bitfield_width().is_none())
+ .map(|f| Field::DataMember(f.0));
+ fields.extend(non_bitfields);
+ }
+
+ // Now gather all the consecutive bitfields. Only consecutive bitfields
+ // may potentially share a bitfield allocation unit with each other in
+ // the Itanium C++ ABI.
+ let mut bitfields = raw_fields
+ .by_ref()
+ .peeking_take_while(|f| f.bitfield_width().is_some())
+ .peekable();
+
+ if bitfields.peek().is_none() {
+ break;
+ }
+
+ bitfields_to_allocation_units(
+ ctx,
+ &mut bitfield_unit_count,
+ &mut fields,
+ bitfields,
+ packed,
+ )?;
+ }
+
+ assert!(
+ raw_fields.next().is_none(),
+ "The above loop should consume all items in `raw_fields`"
+ );
+
+ Ok((fields, bitfield_unit_count != 0))
+}
+
+/// Given a set of contiguous raw bitfields, group and allocate them into
+/// (potentially multiple) bitfield units.
+fn bitfields_to_allocation_units<E, I>(
+ ctx: &BindgenContext,
+ bitfield_unit_count: &mut usize,
+ fields: &mut E,
+ raw_bitfields: I,
+ packed: bool,
+) -> Result<(), ()>
+where
+ E: Extend<Field>,
+ I: IntoIterator<Item = RawField>,
+{
+ assert!(ctx.collected_typerefs());
+
+ // NOTE: What follows is reverse-engineered from LLVM's
+ // lib/AST/RecordLayoutBuilder.cpp
+ //
+ // FIXME(emilio): There are some differences between Microsoft and the
+ // Itanium ABI, but we'll ignore those and stick to Itanium for now.
+ //
+ // Also, we need to handle packed bitfields and stuff.
+ //
+ // TODO(emilio): Take into account C++'s wide bitfields, and
+ // packing, sigh.
+
+ fn flush_allocation_unit<E>(
+ fields: &mut E,
+ bitfield_unit_count: &mut usize,
+ unit_size_in_bits: usize,
+ unit_align_in_bits: usize,
+ bitfields: Vec<Bitfield>,
+ packed: bool,
+ ) where
+ E: Extend<Field>,
+ {
+ *bitfield_unit_count += 1;
+ let align = if packed {
+ 1
+ } else {
+ bytes_from_bits_pow2(unit_align_in_bits)
+ };
+ let size = align_to(unit_size_in_bits, 8) / 8;
+ let layout = Layout::new(size, align);
+ fields.extend(Some(Field::Bitfields(BitfieldUnit {
+ nth: *bitfield_unit_count,
+ layout,
+ bitfields,
+ })));
+ }
+
+ let mut max_align = 0;
+ let mut unfilled_bits_in_unit = 0;
+ let mut unit_size_in_bits = 0;
+ let mut unit_align = 0;
+ let mut bitfields_in_unit = vec![];
+
+ // TODO(emilio): Determine this from attributes or pragma ms_struct
+ // directives. Also, perhaps we should check if the target is MSVC?
+ const is_ms_struct: bool = false;
+
+ for bitfield in raw_bitfields {
+ let bitfield_width = bitfield.bitfield_width().unwrap() as usize;
+ let bitfield_layout =
+ ctx.resolve_type(bitfield.ty()).layout(ctx).ok_or(())?;
+ let bitfield_size = bitfield_layout.size;
+ let bitfield_align = bitfield_layout.align;
+
+ let mut offset = unit_size_in_bits;
+ if !packed {
+ if is_ms_struct {
+ if unit_size_in_bits != 0 &&
+ (bitfield_width == 0 ||
+ bitfield_width > unfilled_bits_in_unit)
+ {
+ // We've reached the end of this allocation unit, so flush it
+ // and its bitfields.
+ unit_size_in_bits =
+ align_to(unit_size_in_bits, unit_align * 8);
+ flush_allocation_unit(
+ fields,
+ bitfield_unit_count,
+ unit_size_in_bits,
+ unit_align,
+ mem::take(&mut bitfields_in_unit),
+ packed,
+ );
+
+ // Now we're working on a fresh bitfield allocation unit, so reset
+ // the current unit size and alignment.
+ offset = 0;
+ unit_align = 0;
+ }
+ } else if offset != 0 &&
+ (bitfield_width == 0 ||
+ (offset & (bitfield_align * 8 - 1)) + bitfield_width >
+ bitfield_size * 8)
+ {
+ offset = align_to(offset, bitfield_align * 8);
+ }
+ }
+
+ // According to the x86[-64] ABI spec: "Unnamed bit-fields’ types do not
+ // affect the alignment of a structure or union". This makes sense: such
+ // bit-fields are only used for padding, and we can't perform an
+ // un-aligned read of something we can't read because we can't even name
+ // it.
+ if bitfield.name().is_some() {
+ max_align = cmp::max(max_align, bitfield_align);
+
+ // NB: The `bitfield_width` here is completely, absolutely
+ // intentional. Alignment of the allocation unit is based on the
+ // maximum bitfield width, not (directly) on the bitfields' types'
+ // alignment.
+ unit_align = cmp::max(unit_align, bitfield_width);
+ }
+
+ // Always keep all bitfields around. While unnamed bitifields are used
+ // for padding (and usually not needed hereafter), large unnamed
+ // bitfields over their types size cause weird allocation size behavior from clang.
+ // Therefore, all bitfields needed to be kept around in order to check for this
+ // and make the struct opaque in this case
+ bitfields_in_unit.push(Bitfield::new(offset, bitfield));
+
+ unit_size_in_bits = offset + bitfield_width;
+
+ // Compute what the physical unit's final size would be given what we
+ // have seen so far, and use that to compute how many bits are still
+ // available in the unit.
+ let data_size = align_to(unit_size_in_bits, bitfield_align * 8);
+ unfilled_bits_in_unit = data_size - unit_size_in_bits;
+ }
+
+ if unit_size_in_bits != 0 {
+ // Flush the last allocation unit and its bitfields.
+ flush_allocation_unit(
+ fields,
+ bitfield_unit_count,
+ unit_size_in_bits,
+ unit_align,
+ bitfields_in_unit,
+ packed,
+ );
+ }
+
+ Ok(())
+}
+
+/// A compound structure's fields are initially raw, and have bitfields that
+/// have not been grouped into allocation units. During this time, the fields
+/// are mutable and we build them up during parsing.
+///
+/// Then, once resolving typerefs is completed, we compute all structs' fields'
+/// bitfield allocation units, and they remain frozen and immutable forever
+/// after.
+#[derive(Debug)]
+enum CompFields {
+ Before(Vec<RawField>),
+ After {
+ fields: Vec<Field>,
+ has_bitfield_units: bool,
+ },
+ Error,
+}
+
+impl Default for CompFields {
+ fn default() -> CompFields {
+ CompFields::Before(vec![])
+ }
+}
+
+impl CompFields {
+ fn append_raw_field(&mut self, raw: RawField) {
+ match *self {
+ CompFields::Before(ref mut raws) => {
+ raws.push(raw);
+ }
+ _ => {
+ panic!(
+ "Must not append new fields after computing bitfield allocation units"
+ );
+ }
+ }
+ }
+
+ fn compute_bitfield_units(&mut self, ctx: &BindgenContext, packed: bool) {
+ let raws = match *self {
+ CompFields::Before(ref mut raws) => mem::take(raws),
+ _ => {
+ panic!("Already computed bitfield units");
+ }
+ };
+
+ let result = raw_fields_to_fields_and_bitfield_units(ctx, raws, packed);
+
+ match result {
+ Ok((fields, has_bitfield_units)) => {
+ *self = CompFields::After {
+ fields,
+ has_bitfield_units,
+ };
+ }
+ Err(()) => {
+ *self = CompFields::Error;
+ }
+ }
+ }
+
+ fn deanonymize_fields(&mut self, ctx: &BindgenContext, methods: &[Method]) {
+ let fields = match *self {
+ CompFields::After { ref mut fields, .. } => fields,
+ // Nothing to do here.
+ CompFields::Error => return,
+ CompFields::Before(_) => {
+ panic!("Not yet computed bitfield units.");
+ }
+ };
+
+ fn has_method(
+ methods: &[Method],
+ ctx: &BindgenContext,
+ name: &str,
+ ) -> bool {
+ methods.iter().any(|method| {
+ let method_name = ctx.resolve_func(method.signature()).name();
+ method_name == name || ctx.rust_mangle(method_name) == name
+ })
+ }
+
+ struct AccessorNamesPair {
+ getter: String,
+ setter: String,
+ }
+
+ let mut accessor_names: HashMap<String, AccessorNamesPair> = fields
+ .iter()
+ .flat_map(|field| match *field {
+ Field::Bitfields(ref bu) => &*bu.bitfields,
+ Field::DataMember(_) => &[],
+ })
+ .filter_map(|bitfield| bitfield.name())
+ .map(|bitfield_name| {
+ let bitfield_name = bitfield_name.to_string();
+ let getter = {
+ let mut getter =
+ ctx.rust_mangle(&bitfield_name).to_string();
+ if has_method(methods, ctx, &getter) {
+ getter.push_str("_bindgen_bitfield");
+ }
+ getter
+ };
+ let setter = {
+ let setter = format!("set_{}", bitfield_name);
+ let mut setter = ctx.rust_mangle(&setter).to_string();
+ if has_method(methods, ctx, &setter) {
+ setter.push_str("_bindgen_bitfield");
+ }
+ setter
+ };
+ (bitfield_name, AccessorNamesPair { getter, setter })
+ })
+ .collect();
+
+ let mut anon_field_counter = 0;
+ for field in fields.iter_mut() {
+ match *field {
+ Field::DataMember(FieldData { ref mut name, .. }) => {
+ if name.is_some() {
+ continue;
+ }
+
+ anon_field_counter += 1;
+ *name = Some(format!(
+ "{}{}",
+ ctx.options().anon_fields_prefix,
+ anon_field_counter
+ ));
+ }
+ Field::Bitfields(ref mut bu) => {
+ for bitfield in &mut bu.bitfields {
+ if bitfield.name().is_none() {
+ continue;
+ }
+
+ if let Some(AccessorNamesPair { getter, setter }) =
+ accessor_names.remove(bitfield.name().unwrap())
+ {
+ bitfield.getter_name = Some(getter);
+ bitfield.setter_name = Some(setter);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+impl Trace for CompFields {
+ type Extra = ();
+
+ fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, _: &())
+ where
+ T: Tracer,
+ {
+ match *self {
+ CompFields::Error => {}
+ CompFields::Before(ref fields) => {
+ for f in fields {
+ tracer.visit_kind(f.ty().into(), EdgeKind::Field);
+ }
+ }
+ CompFields::After { ref fields, .. } => {
+ for f in fields {
+ f.trace(context, tracer, &());
+ }
+ }
+ }
+ }
+}
+
+/// Common data shared across different field types.
+#[derive(Clone, Debug)]
+pub(crate) struct FieldData {
+ /// The name of the field, empty if it's an unnamed bitfield width.
+ name: Option<String>,
+
+ /// The inner type.
+ ty: TypeId,
+
+ /// The doc comment on the field if any.
+ comment: Option<String>,
+
+ /// Annotations for this field, or the default.
+ annotations: Annotations,
+
+ /// If this field is a bitfield, and how many bits does it contain if it is.
+ bitfield_width: Option<u32>,
+
+ /// If the C++ field is declared `public`
+ public: bool,
+
+ /// The offset of the field (in bits)
+ offset: Option<usize>,
+}
+
+impl FieldMethods for FieldData {
+ fn name(&self) -> Option<&str> {
+ self.name.as_deref()
+ }
+
+ fn ty(&self) -> TypeId {
+ self.ty
+ }
+
+ fn comment(&self) -> Option<&str> {
+ self.comment.as_deref()
+ }
+
+ fn bitfield_width(&self) -> Option<u32> {
+ self.bitfield_width
+ }
+
+ fn is_public(&self) -> bool {
+ self.public
+ }
+
+ fn annotations(&self) -> &Annotations {
+ &self.annotations
+ }
+
+ fn offset(&self) -> Option<usize> {
+ self.offset
+ }
+}
+
+/// The kind of inheritance a base class is using.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) enum BaseKind {
+ /// Normal inheritance, like:
+ ///
+ /// ```cpp
+ /// class A : public B {};
+ /// ```
+ Normal,
+ /// Virtual inheritance, like:
+ ///
+ /// ```cpp
+ /// class A: public virtual B {};
+ /// ```
+ Virtual,
+}
+
+/// A base class.
+#[derive(Clone, Debug)]
+pub(crate) struct Base {
+ /// The type of this base class.
+ pub(crate) ty: TypeId,
+ /// The kind of inheritance we're doing.
+ pub(crate) kind: BaseKind,
+ /// Name of the field in which this base should be stored.
+ pub(crate) field_name: String,
+ /// Whether this base is inherited from publically.
+ pub(crate) is_pub: bool,
+}
+
+impl Base {
+ /// Whether this base class is inheriting virtually.
+ pub(crate) fn is_virtual(&self) -> bool {
+ self.kind == BaseKind::Virtual
+ }
+
+ /// Whether this base class should have it's own field for storage.
+ pub(crate) fn requires_storage(&self, ctx: &BindgenContext) -> bool {
+ // Virtual bases are already taken into account by the vtable
+ // pointer.
+ //
+ // FIXME(emilio): Is this always right?
+ if self.is_virtual() {
+ return false;
+ }
+
+ // NB: We won't include zero-sized types in our base chain because they
+ // would contribute to our size given the dummy field we insert for
+ // zero-sized types.
+ if self.ty.is_zero_sized(ctx) {
+ return false;
+ }
+
+ true
+ }
+
+ /// Whether this base is inherited from publically.
+ pub(crate) fn is_public(&self) -> bool {
+ self.is_pub
+ }
+}
+
+/// A compound type.
+///
+/// Either a struct or union, a compound type is built up from the combination
+/// of fields which also are associated with their own (potentially compound)
+/// type.
+#[derive(Debug)]
+pub(crate) struct CompInfo {
+ /// Whether this is a struct or a union.
+ kind: CompKind,
+
+ /// The members of this struct or union.
+ fields: CompFields,
+
+ /// The abstract template parameters of this class. Note that these are NOT
+ /// concrete template arguments, and should always be a
+ /// `Type(TypeKind::TypeParam(name))`. For concrete template arguments, see
+ /// `TypeKind::TemplateInstantiation`.
+ template_params: Vec<TypeId>,
+
+ /// The method declarations inside this class, if in C++ mode.
+ methods: Vec<Method>,
+
+ /// The different constructors this struct or class contains.
+ constructors: Vec<FunctionId>,
+
+ /// The destructor of this type. The bool represents whether this destructor
+ /// is virtual.
+ destructor: Option<(MethodKind, FunctionId)>,
+
+ /// Vector of classes this one inherits from.
+ base_members: Vec<Base>,
+
+ /// The inner types that were declared inside this class, in something like:
+ ///
+ /// class Foo {
+ /// typedef int FooTy;
+ /// struct Bar {
+ /// int baz;
+ /// };
+ /// }
+ ///
+ /// static Foo::Bar const = {3};
+ inner_types: Vec<TypeId>,
+
+ /// Set of static constants declared inside this class.
+ inner_vars: Vec<VarId>,
+
+ /// Whether this type should generate an vtable (TODO: Should be able to
+ /// look at the virtual methods and ditch this field).
+ has_own_virtual_method: bool,
+
+ /// Whether this type has destructor.
+ has_destructor: bool,
+
+ /// Whether this type has a base type with more than one member.
+ ///
+ /// TODO: We should be able to compute this.
+ has_nonempty_base: bool,
+
+ /// If this type has a template parameter which is not a type (e.g.: a
+ /// size_t)
+ has_non_type_template_params: bool,
+
+ /// Whether this type has a bit field member whose width couldn't be
+ /// evaluated (e.g. if it depends on a template parameter). We generate an
+ /// opaque type in this case.
+ has_unevaluable_bit_field_width: bool,
+
+ /// Whether we saw `__attribute__((packed))` on or within this type.
+ packed_attr: bool,
+
+ /// Used to know if we've found an opaque attribute that could cause us to
+ /// generate a type with invalid layout. This is explicitly used to avoid us
+ /// generating bad alignments when parsing types like max_align_t.
+ ///
+ /// It's not clear what the behavior should be here, if generating the item
+ /// and pray, or behave as an opaque type.
+ found_unknown_attr: bool,
+
+ /// Used to indicate when a struct has been forward declared. Usually used
+ /// in headers so that APIs can't modify them directly.
+ is_forward_declaration: bool,
+}
+
+impl CompInfo {
+ /// Construct a new compound type.
+ pub(crate) fn new(kind: CompKind) -> Self {
+ CompInfo {
+ kind,
+ fields: CompFields::default(),
+ template_params: vec![],
+ methods: vec![],
+ constructors: vec![],
+ destructor: None,
+ base_members: vec![],
+ inner_types: vec![],
+ inner_vars: vec![],
+ has_own_virtual_method: false,
+ has_destructor: false,
+ has_nonempty_base: false,
+ has_non_type_template_params: false,
+ has_unevaluable_bit_field_width: false,
+ packed_attr: false,
+ found_unknown_attr: false,
+ is_forward_declaration: false,
+ }
+ }
+
+ /// Compute the layout of this type.
+ ///
+ /// This is called as a fallback under some circumstances where LLVM doesn't
+ /// give us the correct layout.
+ ///
+ /// If we're a union without known layout, we try to compute it from our
+ /// members. This is not ideal, but clang fails to report the size for these
+ /// kind of unions, see test/headers/template_union.hpp
+ pub(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
+ // We can't do better than clang here, sorry.
+ if self.kind == CompKind::Struct {
+ return None;
+ }
+
+ // By definition, we don't have the right layout information here if
+ // we're a forward declaration.
+ if self.is_forward_declaration() {
+ return None;
+ }
+
+ // empty union case
+ if !self.has_fields() {
+ return None;
+ }
+
+ let mut max_size = 0;
+ // Don't allow align(0)
+ let mut max_align = 1;
+ self.each_known_field_layout(ctx, |layout| {
+ max_size = cmp::max(max_size, layout.size);
+ max_align = cmp::max(max_align, layout.align);
+ });
+
+ Some(Layout::new(max_size, max_align))
+ }
+
+ /// Get this type's set of fields.
+ pub(crate) fn fields(&self) -> &[Field] {
+ match self.fields {
+ CompFields::Error => &[],
+ CompFields::After { ref fields, .. } => fields,
+ CompFields::Before(..) => {
+ panic!("Should always have computed bitfield units first");
+ }
+ }
+ }
+
+ fn has_fields(&self) -> bool {
+ match self.fields {
+ CompFields::Error => false,
+ CompFields::After { ref fields, .. } => !fields.is_empty(),
+ CompFields::Before(ref raw_fields) => !raw_fields.is_empty(),
+ }
+ }
+
+ fn each_known_field_layout(
+ &self,
+ ctx: &BindgenContext,
+ mut callback: impl FnMut(Layout),
+ ) {
+ match self.fields {
+ CompFields::Error => {}
+ CompFields::After { ref fields, .. } => {
+ for field in fields.iter() {
+ if let Some(layout) = field.layout(ctx) {
+ callback(layout);
+ }
+ }
+ }
+ CompFields::Before(ref raw_fields) => {
+ for field in raw_fields.iter() {
+ let field_ty = ctx.resolve_type(field.0.ty);
+ if let Some(layout) = field_ty.layout(ctx) {
+ callback(layout);
+ }
+ }
+ }
+ }
+ }
+
+ fn has_bitfields(&self) -> bool {
+ match self.fields {
+ CompFields::Error => false,
+ CompFields::After {
+ has_bitfield_units, ..
+ } => has_bitfield_units,
+ CompFields::Before(_) => {
+ panic!("Should always have computed bitfield units first");
+ }
+ }
+ }
+
+ /// Returns whether we have a too large bitfield unit, in which case we may
+ /// not be able to derive some of the things we should be able to normally
+ /// derive.
+ pub(crate) fn has_too_large_bitfield_unit(&self) -> bool {
+ if !self.has_bitfields() {
+ return false;
+ }
+ self.fields().iter().any(|field| match *field {
+ Field::DataMember(..) => false,
+ Field::Bitfields(ref unit) => {
+ unit.layout.size > RUST_DERIVE_IN_ARRAY_LIMIT
+ }
+ })
+ }
+
+ /// Does this type have any template parameters that aren't types
+ /// (e.g. int)?
+ pub(crate) fn has_non_type_template_params(&self) -> bool {
+ self.has_non_type_template_params
+ }
+
+ /// Do we see a virtual function during parsing?
+ /// Get the has_own_virtual_method boolean.
+ pub(crate) fn has_own_virtual_method(&self) -> bool {
+ self.has_own_virtual_method
+ }
+
+ /// Did we see a destructor when parsing this type?
+ pub(crate) fn has_own_destructor(&self) -> bool {
+ self.has_destructor
+ }
+
+ /// Get this type's set of methods.
+ pub(crate) fn methods(&self) -> &[Method] {
+ &self.methods
+ }
+
+ /// Get this type's set of constructors.
+ pub(crate) fn constructors(&self) -> &[FunctionId] {
+ &self.constructors
+ }
+
+ /// Get this type's destructor.
+ pub(crate) fn destructor(&self) -> Option<(MethodKind, FunctionId)> {
+ self.destructor
+ }
+
+ /// What kind of compound type is this?
+ pub(crate) fn kind(&self) -> CompKind {
+ self.kind
+ }
+
+ /// Is this a union?
+ pub(crate) fn is_union(&self) -> bool {
+ self.kind() == CompKind::Union
+ }
+
+ /// The set of types that this one inherits from.
+ pub(crate) fn base_members(&self) -> &[Base] {
+ &self.base_members
+ }
+
+ /// Construct a new compound type from a Clang type.
+ pub(crate) fn from_ty(
+ potential_id: ItemId,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ ctx: &mut BindgenContext,
+ ) -> Result<Self, ParseError> {
+ use clang_sys::*;
+ assert!(
+ ty.template_args().is_none(),
+ "We handle template instantiations elsewhere"
+ );
+
+ let mut cursor = ty.declaration();
+ let mut kind = Self::kind_from_cursor(&cursor);
+ if kind.is_err() {
+ if let Some(location) = location {
+ kind = Self::kind_from_cursor(&location);
+ cursor = location;
+ }
+ }
+
+ let kind = kind?;
+
+ debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor);
+
+ let mut ci = CompInfo::new(kind);
+ ci.is_forward_declaration =
+ location.map_or(true, |cur| match cur.kind() {
+ CXCursor_ParmDecl => true,
+ CXCursor_StructDecl | CXCursor_UnionDecl |
+ CXCursor_ClassDecl => !cur.is_definition(),
+ _ => false,
+ });
+
+ let mut maybe_anonymous_struct_field = None;
+ cursor.visit(|cur| {
+ if cur.kind() != CXCursor_FieldDecl {
+ if let Some((ty, clang_ty, public, offset)) =
+ maybe_anonymous_struct_field.take()
+ {
+ if cur.kind() == CXCursor_TypedefDecl &&
+ cur.typedef_type().unwrap().canonical_type() ==
+ clang_ty
+ {
+ // Typedefs of anonymous structs appear later in the ast
+ // than the struct itself, that would otherwise be an
+ // anonymous field. Detect that case here, and do
+ // nothing.
+ } else {
+ let field = RawField::new(
+ None, ty, None, None, None, public, offset,
+ );
+ ci.fields.append_raw_field(field);
+ }
+ }
+ }
+
+ match cur.kind() {
+ CXCursor_FieldDecl => {
+ if let Some((ty, clang_ty, public, offset)) =
+ maybe_anonymous_struct_field.take()
+ {
+ let mut used = false;
+ cur.visit(|child| {
+ if child.cur_type() == clang_ty {
+ used = true;
+ }
+ CXChildVisit_Continue
+ });
+
+ if !used {
+ let field = RawField::new(
+ None, ty, None, None, None, public, offset,
+ );
+ ci.fields.append_raw_field(field);
+ }
+ }
+
+ let bit_width = if cur.is_bit_field() {
+ let width = cur.bit_width();
+
+ // Make opaque type if the bit width couldn't be
+ // evaluated.
+ if width.is_none() {
+ ci.has_unevaluable_bit_field_width = true;
+ return CXChildVisit_Break;
+ }
+
+ width
+ } else {
+ None
+ };
+
+ let field_type = Item::from_ty_or_ref(
+ cur.cur_type(),
+ cur,
+ Some(potential_id),
+ ctx,
+ );
+
+ let comment = cur.raw_comment();
+ let annotations = Annotations::new(&cur);
+ let name = cur.spelling();
+ let is_public = cur.public_accessible();
+ let offset = cur.offset_of_field().ok();
+
+ // Name can be empty if there are bitfields, for example,
+ // see tests/headers/struct_with_bitfields.h
+ assert!(
+ !name.is_empty() || bit_width.is_some(),
+ "Empty field name?"
+ );
+
+ let name = if name.is_empty() { None } else { Some(name) };
+
+ let field = RawField::new(
+ name,
+ field_type,
+ comment,
+ annotations,
+ bit_width,
+ is_public,
+ offset,
+ );
+ ci.fields.append_raw_field(field);
+
+ // No we look for things like attributes and stuff.
+ cur.visit(|cur| {
+ if cur.kind() == CXCursor_UnexposedAttr {
+ ci.found_unknown_attr = true;
+ }
+ CXChildVisit_Continue
+ });
+ }
+ CXCursor_UnexposedAttr => {
+ ci.found_unknown_attr = true;
+ }
+ CXCursor_EnumDecl |
+ CXCursor_TypeAliasDecl |
+ CXCursor_TypeAliasTemplateDecl |
+ CXCursor_TypedefDecl |
+ CXCursor_StructDecl |
+ CXCursor_UnionDecl |
+ CXCursor_ClassTemplate |
+ CXCursor_ClassDecl => {
+ // We can find non-semantic children here, clang uses a
+ // StructDecl to note incomplete structs that haven't been
+ // forward-declared before, see [1].
+ //
+ // Also, clang seems to scope struct definitions inside
+ // unions, and other named struct definitions inside other
+ // structs to the whole translation unit.
+ //
+ // Let's just assume that if the cursor we've found is a
+ // definition, it's a valid inner type.
+ //
+ // [1]: https://github.com/rust-lang/rust-bindgen/issues/482
+ let is_inner_struct =
+ cur.semantic_parent() == cursor || cur.is_definition();
+ if !is_inner_struct {
+ return CXChildVisit_Continue;
+ }
+
+ // Even if this is a definition, we may not be the semantic
+ // parent, see #1281.
+ let inner = Item::parse(cur, Some(potential_id), ctx)
+ .expect("Inner ClassDecl");
+
+ // If we avoided recursion parsing this type (in
+ // `Item::from_ty_with_id()`), then this might not be a
+ // valid type ID, so check and gracefully handle this.
+ if ctx.resolve_item_fallible(inner).is_some() {
+ let inner = inner.expect_type_id(ctx);
+
+ ci.inner_types.push(inner);
+
+ // A declaration of an union or a struct without name
+ // could also be an unnamed field, unfortunately.
+ if cur.is_anonymous() && cur.kind() != CXCursor_EnumDecl
+ {
+ let ty = cur.cur_type();
+ let public = cur.public_accessible();
+ let offset = cur.offset_of_field().ok();
+
+ maybe_anonymous_struct_field =
+ Some((inner, ty, public, offset));
+ }
+ }
+ }
+ CXCursor_PackedAttr => {
+ ci.packed_attr = true;
+ }
+ CXCursor_TemplateTypeParameter => {
+ let param = Item::type_param(None, cur, ctx).expect(
+ "Item::type_param should't fail when pointing \
+ at a TemplateTypeParameter",
+ );
+ ci.template_params.push(param);
+ }
+ CXCursor_CXXBaseSpecifier => {
+ let is_virtual_base = cur.is_virtual_base();
+ ci.has_own_virtual_method |= is_virtual_base;
+
+ let kind = if is_virtual_base {
+ BaseKind::Virtual
+ } else {
+ BaseKind::Normal
+ };
+
+ let field_name = match ci.base_members.len() {
+ 0 => "_base".into(),
+ n => format!("_base_{}", n),
+ };
+ let type_id =
+ Item::from_ty_or_ref(cur.cur_type(), cur, None, ctx);
+ ci.base_members.push(Base {
+ ty: type_id,
+ kind,
+ field_name,
+ is_pub: cur.access_specifier() ==
+ clang_sys::CX_CXXPublic,
+ });
+ }
+ CXCursor_Constructor | CXCursor_Destructor |
+ CXCursor_CXXMethod => {
+ let is_virtual = cur.method_is_virtual();
+ let is_static = cur.method_is_static();
+ debug_assert!(!(is_static && is_virtual), "How?");
+
+ ci.has_destructor |= cur.kind() == CXCursor_Destructor;
+ ci.has_own_virtual_method |= is_virtual;
+
+ // This used to not be here, but then I tried generating
+ // stylo bindings with this (without path filters), and
+ // cried a lot with a method in gfx/Point.h
+ // (ToUnknownPoint), that somehow was causing the same type
+ // to be inserted in the map two times.
+ //
+ // I couldn't make a reduced test case, but anyway...
+ // Methods of template functions not only used to be inlined,
+ // but also instantiated, and we wouldn't be able to call
+ // them, so just bail out.
+ if !ci.template_params.is_empty() {
+ return CXChildVisit_Continue;
+ }
+
+ // NB: This gets us an owned `Function`, not a
+ // `FunctionSig`.
+ let signature =
+ match Item::parse(cur, Some(potential_id), ctx) {
+ Ok(item)
+ if ctx
+ .resolve_item(item)
+ .kind()
+ .is_function() =>
+ {
+ item
+ }
+ _ => return CXChildVisit_Continue,
+ };
+
+ let signature = signature.expect_function_id(ctx);
+
+ match cur.kind() {
+ CXCursor_Constructor => {
+ ci.constructors.push(signature);
+ }
+ CXCursor_Destructor => {
+ let kind = if is_virtual {
+ MethodKind::VirtualDestructor {
+ pure_virtual: cur.method_is_pure_virtual(),
+ }
+ } else {
+ MethodKind::Destructor
+ };
+ ci.destructor = Some((kind, signature));
+ }
+ CXCursor_CXXMethod => {
+ let is_const = cur.method_is_const();
+ let method_kind = if is_static {
+ MethodKind::Static
+ } else if is_virtual {
+ MethodKind::Virtual {
+ pure_virtual: cur.method_is_pure_virtual(),
+ }
+ } else {
+ MethodKind::Normal
+ };
+
+ let method =
+ Method::new(method_kind, signature, is_const);
+
+ ci.methods.push(method);
+ }
+ _ => unreachable!("How can we see this here?"),
+ }
+ }
+ CXCursor_NonTypeTemplateParameter => {
+ ci.has_non_type_template_params = true;
+ }
+ CXCursor_VarDecl => {
+ let linkage = cur.linkage();
+ if linkage != CXLinkage_External &&
+ linkage != CXLinkage_UniqueExternal
+ {
+ return CXChildVisit_Continue;
+ }
+
+ let visibility = cur.visibility();
+ if visibility != CXVisibility_Default {
+ return CXChildVisit_Continue;
+ }
+
+ if let Ok(item) = Item::parse(cur, Some(potential_id), ctx)
+ {
+ ci.inner_vars.push(item.as_var_id_unchecked());
+ }
+ }
+ // Intentionally not handled
+ CXCursor_CXXAccessSpecifier |
+ CXCursor_CXXFinalAttr |
+ CXCursor_FunctionTemplate |
+ CXCursor_ConversionFunction => {}
+ _ => {
+ warn!(
+ "unhandled comp member `{}` (kind {:?}) in `{}` ({})",
+ cur.spelling(),
+ clang::kind_to_str(cur.kind()),
+ cursor.spelling(),
+ cur.location()
+ );
+ }
+ }
+ CXChildVisit_Continue
+ });
+
+ if let Some((ty, _, public, offset)) = maybe_anonymous_struct_field {
+ let field =
+ RawField::new(None, ty, None, None, None, public, offset);
+ ci.fields.append_raw_field(field);
+ }
+
+ Ok(ci)
+ }
+
+ fn kind_from_cursor(
+ cursor: &clang::Cursor,
+ ) -> Result<CompKind, ParseError> {
+ use clang_sys::*;
+ Ok(match cursor.kind() {
+ CXCursor_UnionDecl => CompKind::Union,
+ CXCursor_ClassDecl | CXCursor_StructDecl => CompKind::Struct,
+ CXCursor_CXXBaseSpecifier |
+ CXCursor_ClassTemplatePartialSpecialization |
+ CXCursor_ClassTemplate => match cursor.template_kind() {
+ CXCursor_UnionDecl => CompKind::Union,
+ _ => CompKind::Struct,
+ },
+ _ => {
+ warn!("Unknown kind for comp type: {:?}", cursor);
+ return Err(ParseError::Continue);
+ }
+ })
+ }
+
+ /// Get the set of types that were declared within this compound type
+ /// (e.g. nested class definitions).
+ pub(crate) fn inner_types(&self) -> &[TypeId] {
+ &self.inner_types
+ }
+
+ /// Get the set of static variables declared within this compound type.
+ pub(crate) fn inner_vars(&self) -> &[VarId] {
+ &self.inner_vars
+ }
+
+ /// Have we found a field with an opaque type that could potentially mess up
+ /// the layout of this compound type?
+ pub(crate) fn found_unknown_attr(&self) -> bool {
+ self.found_unknown_attr
+ }
+
+ /// Is this compound type packed?
+ pub(crate) fn is_packed(
+ &self,
+ ctx: &BindgenContext,
+ layout: Option<&Layout>,
+ ) -> bool {
+ if self.packed_attr {
+ return true;
+ }
+
+ // Even though `libclang` doesn't expose `#pragma packed(...)`, we can
+ // detect it through its effects.
+ if let Some(parent_layout) = layout {
+ let mut packed = false;
+ self.each_known_field_layout(ctx, |layout| {
+ packed = packed || layout.align > parent_layout.align;
+ });
+ if packed {
+ info!("Found a struct that was defined within `#pragma packed(...)`");
+ return true;
+ }
+
+ if self.has_own_virtual_method && parent_layout.align == 1 {
+ return true;
+ }
+ }
+
+ false
+ }
+
+ /// Return true if a compound type is "naturally packed". This means we can exclude the
+ /// "packed" attribute without changing the layout.
+ /// This is useful for types that need an "align(N)" attribute since rustc won't compile
+ /// structs that have both of those attributes.
+ pub(crate) fn already_packed(&self, ctx: &BindgenContext) -> Option<bool> {
+ let mut total_size: usize = 0;
+
+ for field in self.fields().iter() {
+ let layout = field.layout(ctx)?;
+
+ if layout.align != 0 && total_size % layout.align != 0 {
+ return Some(false);
+ }
+
+ total_size += layout.size;
+ }
+
+ Some(true)
+ }
+
+ /// Returns true if compound type has been forward declared
+ pub(crate) fn is_forward_declaration(&self) -> bool {
+ self.is_forward_declaration
+ }
+
+ /// Compute this compound structure's bitfield allocation units.
+ pub(crate) fn compute_bitfield_units(
+ &mut self,
+ ctx: &BindgenContext,
+ layout: Option<&Layout>,
+ ) {
+ let packed = self.is_packed(ctx, layout);
+ self.fields.compute_bitfield_units(ctx, packed)
+ }
+
+ /// Assign for each anonymous field a generated name.
+ pub(crate) fn deanonymize_fields(&mut self, ctx: &BindgenContext) {
+ self.fields.deanonymize_fields(ctx, &self.methods);
+ }
+
+ /// Returns whether the current union can be represented as a Rust `union`
+ ///
+ /// Requirements:
+ /// 1. Current RustTarget allows for `untagged_union`
+ /// 2. Each field can derive `Copy` or we use ManuallyDrop.
+ /// 3. It's not zero-sized.
+ ///
+ /// Second boolean returns whether all fields can be copied (and thus
+ /// ManuallyDrop is not needed).
+ pub(crate) fn is_rust_union(
+ &self,
+ ctx: &BindgenContext,
+ layout: Option<&Layout>,
+ name: &str,
+ ) -> (bool, bool) {
+ if !self.is_union() {
+ return (false, false);
+ }
+
+ if !ctx.options().untagged_union {
+ return (false, false);
+ }
+
+ if self.is_forward_declaration() {
+ return (false, false);
+ }
+
+ let union_style = if ctx.options().bindgen_wrapper_union.matches(name) {
+ NonCopyUnionStyle::BindgenWrapper
+ } else if ctx.options().manually_drop_union.matches(name) {
+ NonCopyUnionStyle::ManuallyDrop
+ } else {
+ ctx.options().default_non_copy_union_style
+ };
+
+ let all_can_copy = self.fields().iter().all(|f| match *f {
+ Field::DataMember(ref field_data) => {
+ field_data.ty().can_derive_copy(ctx)
+ }
+ Field::Bitfields(_) => true,
+ });
+
+ if !all_can_copy && union_style == NonCopyUnionStyle::BindgenWrapper {
+ return (false, false);
+ }
+
+ if layout.map_or(false, |l| l.size == 0) {
+ return (false, false);
+ }
+
+ (true, all_can_copy)
+ }
+}
+
+impl DotAttributes for CompInfo {
+ fn dot_attributes<W>(
+ &self,
+ ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ writeln!(out, "<tr><td>CompKind</td><td>{:?}</td></tr>", self.kind)?;
+
+ if self.has_own_virtual_method {
+ writeln!(out, "<tr><td>has_vtable</td><td>true</td></tr>")?;
+ }
+
+ if self.has_destructor {
+ writeln!(out, "<tr><td>has_destructor</td><td>true</td></tr>")?;
+ }
+
+ if self.has_nonempty_base {
+ writeln!(out, "<tr><td>has_nonempty_base</td><td>true</td></tr>")?;
+ }
+
+ if self.has_non_type_template_params {
+ writeln!(
+ out,
+ "<tr><td>has_non_type_template_params</td><td>true</td></tr>"
+ )?;
+ }
+
+ if self.packed_attr {
+ writeln!(out, "<tr><td>packed_attr</td><td>true</td></tr>")?;
+ }
+
+ if self.is_forward_declaration {
+ writeln!(
+ out,
+ "<tr><td>is_forward_declaration</td><td>true</td></tr>"
+ )?;
+ }
+
+ if !self.fields().is_empty() {
+ writeln!(out, r#"<tr><td>fields</td><td><table border="0">"#)?;
+ for field in self.fields() {
+ field.dot_attributes(ctx, out)?;
+ }
+ writeln!(out, "</table></td></tr>")?;
+ }
+
+ Ok(())
+ }
+}
+
+impl IsOpaque for CompInfo {
+ type Extra = Option<Layout>;
+
+ fn is_opaque(&self, ctx: &BindgenContext, layout: &Option<Layout>) -> bool {
+ if self.has_non_type_template_params ||
+ self.has_unevaluable_bit_field_width
+ {
+ return true;
+ }
+
+ // When we do not have the layout for a bitfield's type (for example, it
+ // is a type parameter), then we can't compute bitfield units. We are
+ // left with no choice but to make the whole struct opaque, or else we
+ // might generate structs with incorrect sizes and alignments.
+ if let CompFields::Error = self.fields {
+ return true;
+ }
+
+ // Bitfields with a width that is larger than their unit's width have
+ // some strange things going on, and the best we can do is make the
+ // whole struct opaque.
+ if self.fields().iter().any(|f| match *f {
+ Field::DataMember(_) => false,
+ Field::Bitfields(ref unit) => unit.bitfields().iter().any(|bf| {
+ let bitfield_layout = ctx
+ .resolve_type(bf.ty())
+ .layout(ctx)
+ .expect("Bitfield without layout? Gah!");
+ bf.width() / 8 > bitfield_layout.size as u32
+ }),
+ }) {
+ return true;
+ }
+
+ if !ctx.options().rust_features().repr_packed_n {
+ // If we don't have `#[repr(packed(N)]`, the best we can
+ // do is make this struct opaque.
+ //
+ // See https://github.com/rust-lang/rust-bindgen/issues/537 and
+ // https://github.com/rust-lang/rust/issues/33158
+ if self.is_packed(ctx, layout.as_ref()) &&
+ layout.map_or(false, |l| l.align > 1)
+ {
+ warn!("Found a type that is both packed and aligned to greater than \
+ 1; Rust before version 1.33 doesn't have `#[repr(packed(N))]`, so we \
+ are treating it as opaque. You may wish to set bindgen's rust target \
+ version to 1.33 or later to enable `#[repr(packed(N))]` support.");
+ return true;
+ }
+ }
+
+ false
+ }
+}
+
+impl TemplateParameters for CompInfo {
+ fn self_template_params(&self, _ctx: &BindgenContext) -> Vec<TypeId> {
+ self.template_params.clone()
+ }
+}
+
+impl Trace for CompInfo {
+ type Extra = Item;
+
+ fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
+ where
+ T: Tracer,
+ {
+ for p in item.all_template_params(context) {
+ tracer.visit_kind(p.into(), EdgeKind::TemplateParameterDefinition);
+ }
+
+ for ty in self.inner_types() {
+ tracer.visit_kind(ty.into(), EdgeKind::InnerType);
+ }
+
+ for &var in self.inner_vars() {
+ tracer.visit_kind(var.into(), EdgeKind::InnerVar);
+ }
+
+ for method in self.methods() {
+ tracer.visit_kind(method.signature.into(), EdgeKind::Method);
+ }
+
+ if let Some((_kind, signature)) = self.destructor() {
+ tracer.visit_kind(signature.into(), EdgeKind::Destructor);
+ }
+
+ for ctor in self.constructors() {
+ tracer.visit_kind(ctor.into(), EdgeKind::Constructor);
+ }
+
+ // Base members and fields are not generated for opaque types (but all
+ // of the above things are) so stop here.
+ if item.is_opaque(context, &()) {
+ return;
+ }
+
+ for base in self.base_members() {
+ tracer.visit_kind(base.ty.into(), EdgeKind::BaseMember);
+ }
+
+ self.fields.trace(context, tracer, &());
+ }
+}
diff --git a/third_party/rust/bindgen/ir/context.rs b/third_party/rust/bindgen/ir/context.rs
new file mode 100644
index 0000000000..517d3365b6
--- /dev/null
+++ b/third_party/rust/bindgen/ir/context.rs
@@ -0,0 +1,3038 @@
+//! Common context that is passed around during parsing and codegen.
+
+use super::super::time::Timer;
+use super::analysis::{
+ analyze, as_cannot_derive_set, CannotDerive, DeriveTrait,
+ HasDestructorAnalysis, HasFloat, HasTypeParameterInArray,
+ HasVtableAnalysis, HasVtableResult, SizednessAnalysis, SizednessResult,
+ UsedTemplateParameters,
+};
+use super::derive::{
+ CanDerive, CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq,
+ CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd,
+};
+use super::function::Function;
+use super::int::IntKind;
+use super::item::{IsOpaque, Item, ItemAncestors, ItemSet};
+use super::item_kind::ItemKind;
+use super::module::{Module, ModuleKind};
+use super::template::{TemplateInstantiation, TemplateParameters};
+use super::traversal::{self, Edge, ItemTraversal};
+use super::ty::{FloatKind, Type, TypeKind};
+use crate::clang::{self, ABIKind, Cursor};
+use crate::codegen::CodegenError;
+use crate::BindgenOptions;
+use crate::{Entry, HashMap, HashSet};
+
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::ToTokens;
+use std::borrow::Cow;
+use std::cell::{Cell, RefCell};
+use std::collections::{BTreeSet, HashMap as StdHashMap};
+use std::iter::IntoIterator;
+use std::mem;
+
+/// An identifier for some kind of IR item.
+#[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)]
+pub(crate) struct ItemId(usize);
+
+/// Declare a newtype around `ItemId` with convesion methods.
+macro_rules! item_id_newtype {
+ (
+ $( #[$attr:meta] )*
+ pub(crate) struct $name:ident(ItemId)
+ where
+ $( #[$checked_attr:meta] )*
+ checked = $checked:ident with $check_method:ident,
+ $( #[$expected_attr:meta] )*
+ expected = $expected:ident,
+ $( #[$unchecked_attr:meta] )*
+ unchecked = $unchecked:ident;
+ ) => {
+ $( #[$attr] )*
+ #[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)]
+ pub(crate) struct $name(ItemId);
+
+ impl $name {
+ /// Create an `ItemResolver` from this ID.
+ #[allow(dead_code)]
+ pub(crate) fn into_resolver(self) -> ItemResolver {
+ let id: ItemId = self.into();
+ id.into()
+ }
+ }
+
+ impl<T> ::std::cmp::PartialEq<T> for $name
+ where
+ T: Copy + Into<ItemId>
+ {
+ fn eq(&self, rhs: &T) -> bool {
+ let rhs: ItemId = (*rhs).into();
+ self.0 == rhs
+ }
+ }
+
+ impl From<$name> for ItemId {
+ fn from(id: $name) -> ItemId {
+ id.0
+ }
+ }
+
+ impl<'a> From<&'a $name> for ItemId {
+ fn from(id: &'a $name) -> ItemId {
+ id.0
+ }
+ }
+
+ #[allow(dead_code)]
+ impl ItemId {
+ $( #[$checked_attr] )*
+ pub(crate) fn $checked(&self, ctx: &BindgenContext) -> Option<$name> {
+ if ctx.resolve_item(*self).kind().$check_method() {
+ Some($name(*self))
+ } else {
+ None
+ }
+ }
+
+ $( #[$expected_attr] )*
+ pub(crate) fn $expected(&self, ctx: &BindgenContext) -> $name {
+ self.$checked(ctx)
+ .expect(concat!(
+ stringify!($expected),
+ " called with ItemId that points to the wrong ItemKind"
+ ))
+ }
+
+ $( #[$unchecked_attr] )*
+ pub(crate) fn $unchecked(&self) -> $name {
+ $name(*self)
+ }
+ }
+ }
+}
+
+item_id_newtype! {
+ /// An identifier for an `Item` whose `ItemKind` is known to be
+ /// `ItemKind::Type`.
+ pub(crate) struct TypeId(ItemId)
+ where
+ /// Convert this `ItemId` into a `TypeId` if its associated item is a type,
+ /// otherwise return `None`.
+ checked = as_type_id with is_type,
+
+ /// Convert this `ItemId` into a `TypeId`.
+ ///
+ /// If this `ItemId` does not point to a type, then panic.
+ expected = expect_type_id,
+
+ /// Convert this `ItemId` into a `TypeId` without actually checking whether
+ /// this ID actually points to a `Type`.
+ unchecked = as_type_id_unchecked;
+}
+
+item_id_newtype! {
+ /// An identifier for an `Item` whose `ItemKind` is known to be
+ /// `ItemKind::Module`.
+ pub(crate) struct ModuleId(ItemId)
+ where
+ /// Convert this `ItemId` into a `ModuleId` if its associated item is a
+ /// module, otherwise return `None`.
+ checked = as_module_id with is_module,
+
+ /// Convert this `ItemId` into a `ModuleId`.
+ ///
+ /// If this `ItemId` does not point to a module, then panic.
+ expected = expect_module_id,
+
+ /// Convert this `ItemId` into a `ModuleId` without actually checking
+ /// whether this ID actually points to a `Module`.
+ unchecked = as_module_id_unchecked;
+}
+
+item_id_newtype! {
+ /// An identifier for an `Item` whose `ItemKind` is known to be
+ /// `ItemKind::Var`.
+ pub(crate) struct VarId(ItemId)
+ where
+ /// Convert this `ItemId` into a `VarId` if its associated item is a var,
+ /// otherwise return `None`.
+ checked = as_var_id with is_var,
+
+ /// Convert this `ItemId` into a `VarId`.
+ ///
+ /// If this `ItemId` does not point to a var, then panic.
+ expected = expect_var_id,
+
+ /// Convert this `ItemId` into a `VarId` without actually checking whether
+ /// this ID actually points to a `Var`.
+ unchecked = as_var_id_unchecked;
+}
+
+item_id_newtype! {
+ /// An identifier for an `Item` whose `ItemKind` is known to be
+ /// `ItemKind::Function`.
+ pub(crate) struct FunctionId(ItemId)
+ where
+ /// Convert this `ItemId` into a `FunctionId` if its associated item is a function,
+ /// otherwise return `None`.
+ checked = as_function_id with is_function,
+
+ /// Convert this `ItemId` into a `FunctionId`.
+ ///
+ /// If this `ItemId` does not point to a function, then panic.
+ expected = expect_function_id,
+
+ /// Convert this `ItemId` into a `FunctionId` without actually checking whether
+ /// this ID actually points to a `Function`.
+ unchecked = as_function_id_unchecked;
+}
+
+impl From<ItemId> for usize {
+ fn from(id: ItemId) -> usize {
+ id.0
+ }
+}
+
+impl ItemId {
+ /// Get a numeric representation of this ID.
+ pub(crate) fn as_usize(&self) -> usize {
+ (*self).into()
+ }
+}
+
+impl<T> ::std::cmp::PartialEq<T> for ItemId
+where
+ T: Copy + Into<ItemId>,
+{
+ fn eq(&self, rhs: &T) -> bool {
+ let rhs: ItemId = (*rhs).into();
+ self.0 == rhs.0
+ }
+}
+
+impl<T> CanDeriveDebug for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn can_derive_debug(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_debug && ctx.lookup_can_derive_debug(*self)
+ }
+}
+
+impl<T> CanDeriveDefault for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn can_derive_default(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_default && ctx.lookup_can_derive_default(*self)
+ }
+}
+
+impl<T> CanDeriveCopy for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn can_derive_copy(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_copy && ctx.lookup_can_derive_copy(*self)
+ }
+}
+
+impl<T> CanDeriveHash for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn can_derive_hash(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_hash && ctx.lookup_can_derive_hash(*self)
+ }
+}
+
+impl<T> CanDerivePartialOrd for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_partialord &&
+ ctx.lookup_can_derive_partialeq_or_partialord(*self) ==
+ CanDerive::Yes
+ }
+}
+
+impl<T> CanDerivePartialEq for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_partialeq &&
+ ctx.lookup_can_derive_partialeq_or_partialord(*self) ==
+ CanDerive::Yes
+ }
+}
+
+impl<T> CanDeriveEq for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn can_derive_eq(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_eq &&
+ ctx.lookup_can_derive_partialeq_or_partialord(*self) ==
+ CanDerive::Yes &&
+ !ctx.lookup_has_float(*self)
+ }
+}
+
+impl<T> CanDeriveOrd for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn can_derive_ord(&self, ctx: &BindgenContext) -> bool {
+ ctx.options().derive_ord &&
+ ctx.lookup_can_derive_partialeq_or_partialord(*self) ==
+ CanDerive::Yes &&
+ !ctx.lookup_has_float(*self)
+ }
+}
+
+/// A key used to index a resolved type, so we only process it once.
+///
+/// This is almost always a USR string (an unique identifier generated by
+/// clang), but it can also be the canonical declaration if the type is unnamed,
+/// in which case clang may generate the same USR for multiple nested unnamed
+/// types.
+#[derive(Eq, PartialEq, Hash, Debug)]
+enum TypeKey {
+ Usr(String),
+ Declaration(Cursor),
+}
+
+/// A context used during parsing and generation of structs.
+#[derive(Debug)]
+pub(crate) struct BindgenContext {
+ /// The map of all the items parsed so far, keyed off ItemId.
+ items: Vec<Option<Item>>,
+
+ /// Clang USR to type map. This is needed to be able to associate types with
+ /// item ids during parsing.
+ types: HashMap<TypeKey, TypeId>,
+
+ /// Maps from a cursor to the item ID of the named template type parameter
+ /// for that cursor.
+ type_params: HashMap<clang::Cursor, TypeId>,
+
+ /// A cursor to module map. Similar reason than above.
+ modules: HashMap<Cursor, ModuleId>,
+
+ /// The root module, this is guaranteed to be an item of kind Module.
+ root_module: ModuleId,
+
+ /// Current module being traversed.
+ current_module: ModuleId,
+
+ /// A HashMap keyed on a type definition, and whose value is the parent ID
+ /// of the declaration.
+ ///
+ /// This is used to handle the cases where the semantic and the lexical
+ /// parents of the cursor differ, like when a nested class is defined
+ /// outside of the parent class.
+ semantic_parents: HashMap<clang::Cursor, ItemId>,
+
+ /// A stack with the current type declarations and types we're parsing. This
+ /// is needed to avoid infinite recursion when parsing a type like:
+ ///
+ /// struct c { struct c* next; };
+ ///
+ /// This means effectively, that a type has a potential ID before knowing if
+ /// it's a correct type. But that's not important in practice.
+ ///
+ /// We could also use the `types` HashMap, but my intention with it is that
+ /// only valid types and declarations end up there, and this could
+ /// potentially break that assumption.
+ currently_parsed_types: Vec<PartialType>,
+
+ /// A map with all the already parsed macro names. This is done to avoid
+ /// hard errors while parsing duplicated macros, as well to allow macro
+ /// expression parsing.
+ ///
+ /// This needs to be an std::HashMap because the cexpr API requires it.
+ parsed_macros: StdHashMap<Vec<u8>, cexpr::expr::EvalResult>,
+
+ /// A map with all include locations.
+ ///
+ /// This is needed so that items are created in the order they are defined in.
+ ///
+ /// The key is the included file, the value is a pair of the source file and
+ /// the position of the `#include` directive in the source file.
+ includes: StdHashMap<String, (String, usize)>,
+
+ /// A set of all the included filenames.
+ deps: BTreeSet<Box<str>>,
+
+ /// The active replacements collected from replaces="xxx" annotations.
+ replacements: HashMap<Vec<String>, ItemId>,
+
+ collected_typerefs: bool,
+
+ in_codegen: bool,
+
+ /// The translation unit for parsing.
+ translation_unit: clang::TranslationUnit,
+
+ /// Target information that can be useful for some stuff.
+ target_info: clang::TargetInfo,
+
+ /// The options given by the user via cli or other medium.
+ options: BindgenOptions,
+
+ /// Whether a bindgen complex was generated
+ generated_bindgen_complex: Cell<bool>,
+
+ /// Whether a bindgen float16 was generated
+ generated_bindgen_float16: Cell<bool>,
+
+ /// The set of `ItemId`s that are allowlisted. This the very first thing
+ /// computed after parsing our IR, and before running any of our analyses.
+ allowlisted: Option<ItemSet>,
+
+ /// Cache for calls to `ParseCallbacks::blocklisted_type_implements_trait`
+ blocklisted_types_implement_traits:
+ RefCell<HashMap<DeriveTrait, HashMap<ItemId, CanDerive>>>,
+
+ /// The set of `ItemId`s that are allowlisted for code generation _and_ that
+ /// we should generate accounting for the codegen options.
+ ///
+ /// It's computed right after computing the allowlisted items.
+ codegen_items: Option<ItemSet>,
+
+ /// Map from an item's ID to the set of template parameter items that it
+ /// uses. See `ir::named` for more details. Always `Some` during the codegen
+ /// phase.
+ used_template_parameters: Option<HashMap<ItemId, ItemSet>>,
+
+ /// The set of `TypeKind::Comp` items found during parsing that need their
+ /// bitfield allocation units computed. Drained in `compute_bitfield_units`.
+ need_bitfield_allocation: Vec<ItemId>,
+
+ /// The set of enums that are defined by a pair of `enum` and `typedef`,
+ /// which is legal in C (but not C++).
+ ///
+ /// ```c++
+ /// // in either order
+ /// enum Enum { Variants... };
+ /// typedef int16_t Enum;
+ /// ```
+ ///
+ /// The stored `ItemId` is that of the `TypeKind::Enum`, not of the
+ /// `TypeKind::Alias`.
+ ///
+ /// This is populated when we enter codegen by `compute_enum_typedef_combos`
+ /// and is always `None` before that and `Some` after.
+ enum_typedef_combos: Option<HashSet<ItemId>>,
+
+ /// The set of (`ItemId`s of) types that can't derive debug.
+ ///
+ /// This is populated when we enter codegen by `compute_cannot_derive_debug`
+ /// and is always `None` before that and `Some` after.
+ cannot_derive_debug: Option<HashSet<ItemId>>,
+
+ /// The set of (`ItemId`s of) types that can't derive default.
+ ///
+ /// This is populated when we enter codegen by `compute_cannot_derive_default`
+ /// and is always `None` before that and `Some` after.
+ cannot_derive_default: Option<HashSet<ItemId>>,
+
+ /// The set of (`ItemId`s of) types that can't derive copy.
+ ///
+ /// This is populated when we enter codegen by `compute_cannot_derive_copy`
+ /// and is always `None` before that and `Some` after.
+ cannot_derive_copy: Option<HashSet<ItemId>>,
+
+ /// The set of (`ItemId`s of) types that can't derive hash.
+ ///
+ /// This is populated when we enter codegen by `compute_can_derive_hash`
+ /// and is always `None` before that and `Some` after.
+ cannot_derive_hash: Option<HashSet<ItemId>>,
+
+ /// The map why specified `ItemId`s of) types that can't derive hash.
+ ///
+ /// This is populated when we enter codegen by
+ /// `compute_cannot_derive_partialord_partialeq_or_eq` and is always `None`
+ /// before that and `Some` after.
+ cannot_derive_partialeq_or_partialord: Option<HashMap<ItemId, CanDerive>>,
+
+ /// The sizedness of types.
+ ///
+ /// This is populated by `compute_sizedness` and is always `None` before
+ /// that function is invoked and `Some` afterwards.
+ sizedness: Option<HashMap<TypeId, SizednessResult>>,
+
+ /// The set of (`ItemId's of`) types that has vtable.
+ ///
+ /// Populated when we enter codegen by `compute_has_vtable`; always `None`
+ /// before that and `Some` after.
+ have_vtable: Option<HashMap<ItemId, HasVtableResult>>,
+
+ /// The set of (`ItemId's of`) types that has destructor.
+ ///
+ /// Populated when we enter codegen by `compute_has_destructor`; always `None`
+ /// before that and `Some` after.
+ have_destructor: Option<HashSet<ItemId>>,
+
+ /// The set of (`ItemId's of`) types that has array.
+ ///
+ /// Populated when we enter codegen by `compute_has_type_param_in_array`; always `None`
+ /// before that and `Some` after.
+ has_type_param_in_array: Option<HashSet<ItemId>>,
+
+ /// The set of (`ItemId's of`) types that has float.
+ ///
+ /// Populated when we enter codegen by `compute_has_float`; always `None`
+ /// before that and `Some` after.
+ has_float: Option<HashSet<ItemId>>,
+}
+
+/// A traversal of allowlisted items.
+struct AllowlistedItemsTraversal<'ctx> {
+ ctx: &'ctx BindgenContext,
+ traversal: ItemTraversal<'ctx, ItemSet, Vec<ItemId>>,
+}
+
+impl<'ctx> Iterator for AllowlistedItemsTraversal<'ctx> {
+ type Item = ItemId;
+
+ fn next(&mut self) -> Option<ItemId> {
+ loop {
+ let id = self.traversal.next()?;
+
+ if self.ctx.resolve_item(id).is_blocklisted(self.ctx) {
+ continue;
+ }
+
+ return Some(id);
+ }
+ }
+}
+
+impl<'ctx> AllowlistedItemsTraversal<'ctx> {
+ /// Construct a new allowlisted items traversal.
+ pub(crate) fn new<R>(
+ ctx: &'ctx BindgenContext,
+ roots: R,
+ predicate: for<'a> fn(&'a BindgenContext, Edge) -> bool,
+ ) -> Self
+ where
+ R: IntoIterator<Item = ItemId>,
+ {
+ AllowlistedItemsTraversal {
+ ctx,
+ traversal: ItemTraversal::new(ctx, roots, predicate),
+ }
+ }
+}
+
+impl BindgenContext {
+ /// Construct the context for the given `options`.
+ pub(crate) fn new(
+ options: BindgenOptions,
+ input_unsaved_files: &[clang::UnsavedFile],
+ ) -> Self {
+ // TODO(emilio): Use the CXTargetInfo here when available.
+ //
+ // see: https://reviews.llvm.org/D32389
+ let index = clang::Index::new(false, true);
+
+ let parse_options =
+ clang_sys::CXTranslationUnit_DetailedPreprocessingRecord;
+
+ let translation_unit = {
+ let _t =
+ Timer::new("translation_unit").with_output(options.time_phases);
+
+ clang::TranslationUnit::parse(
+ &index,
+ "",
+ &options.clang_args,
+ input_unsaved_files,
+ parse_options,
+ ).expect("libclang error; possible causes include:
+- Invalid flag syntax
+- Unrecognized flags
+- Invalid flag arguments
+- File I/O errors
+- Host vs. target architecture mismatch
+If you encounter an error missing from this list, please file an issue or a PR!")
+ };
+
+ let target_info = clang::TargetInfo::new(&translation_unit);
+ let root_module = Self::build_root_module(ItemId(0));
+ let root_module_id = root_module.id().as_module_id_unchecked();
+
+ // depfiles need to include the explicitly listed headers too
+ let deps = options.input_headers.iter().cloned().collect();
+
+ BindgenContext {
+ items: vec![Some(root_module)],
+ includes: Default::default(),
+ deps,
+ types: Default::default(),
+ type_params: Default::default(),
+ modules: Default::default(),
+ root_module: root_module_id,
+ current_module: root_module_id,
+ semantic_parents: Default::default(),
+ currently_parsed_types: vec![],
+ parsed_macros: Default::default(),
+ replacements: Default::default(),
+ collected_typerefs: false,
+ in_codegen: false,
+ translation_unit,
+ target_info,
+ options,
+ generated_bindgen_complex: Cell::new(false),
+ generated_bindgen_float16: Cell::new(false),
+ allowlisted: None,
+ blocklisted_types_implement_traits: Default::default(),
+ codegen_items: None,
+ used_template_parameters: None,
+ need_bitfield_allocation: Default::default(),
+ enum_typedef_combos: None,
+ cannot_derive_debug: None,
+ cannot_derive_default: None,
+ cannot_derive_copy: None,
+ cannot_derive_hash: None,
+ cannot_derive_partialeq_or_partialord: None,
+ sizedness: None,
+ have_vtable: None,
+ have_destructor: None,
+ has_type_param_in_array: None,
+ has_float: None,
+ }
+ }
+
+ /// Returns `true` if the target architecture is wasm32
+ pub(crate) fn is_target_wasm32(&self) -> bool {
+ self.target_info.triple.starts_with("wasm32-")
+ }
+
+ /// Creates a timer for the current bindgen phase. If time_phases is `true`,
+ /// the timer will print to stderr when it is dropped, otherwise it will do
+ /// nothing.
+ pub(crate) fn timer<'a>(&self, name: &'a str) -> Timer<'a> {
+ Timer::new(name).with_output(self.options.time_phases)
+ }
+
+ /// Returns the pointer width to use for the target for the current
+ /// translation.
+ pub(crate) fn target_pointer_size(&self) -> usize {
+ self.target_info.pointer_width / 8
+ }
+
+ /// Returns the ABI, which is mostly useful for determining the mangling kind.
+ pub(crate) fn abi_kind(&self) -> ABIKind {
+ self.target_info.abi
+ }
+
+ /// Get the stack of partially parsed types that we are in the middle of
+ /// parsing.
+ pub(crate) fn currently_parsed_types(&self) -> &[PartialType] {
+ &self.currently_parsed_types[..]
+ }
+
+ /// Begin parsing the given partial type, and push it onto the
+ /// `currently_parsed_types` stack so that we won't infinite recurse if we
+ /// run into a reference to it while parsing it.
+ pub(crate) fn begin_parsing(&mut self, partial_ty: PartialType) {
+ self.currently_parsed_types.push(partial_ty);
+ }
+
+ /// Finish parsing the current partial type, pop it off the
+ /// `currently_parsed_types` stack, and return it.
+ pub(crate) fn finish_parsing(&mut self) -> PartialType {
+ self.currently_parsed_types.pop().expect(
+ "should have been parsing a type, if we finished parsing a type",
+ )
+ }
+
+ /// Add the location of the `#include` directive for the `included_file`.
+ pub(crate) fn add_include(
+ &mut self,
+ source_file: String,
+ included_file: String,
+ offset: usize,
+ ) {
+ self.includes
+ .entry(included_file)
+ .or_insert((source_file, offset));
+ }
+
+ /// Get the location of the first `#include` directive for the `included_file`.
+ pub(crate) fn included_file_location(
+ &self,
+ included_file: &str,
+ ) -> Option<(String, usize)> {
+ self.includes.get(included_file).cloned()
+ }
+
+ /// Add an included file.
+ pub(crate) fn add_dep(&mut self, dep: Box<str>) {
+ self.deps.insert(dep);
+ }
+
+ /// Get any included files.
+ pub(crate) fn deps(&self) -> &BTreeSet<Box<str>> {
+ &self.deps
+ }
+
+ /// Define a new item.
+ ///
+ /// This inserts it into the internal items set, and its type into the
+ /// internal types set.
+ pub(crate) fn add_item(
+ &mut self,
+ item: Item,
+ declaration: Option<Cursor>,
+ location: Option<Cursor>,
+ ) {
+ debug!(
+ "BindgenContext::add_item({:?}, declaration: {:?}, loc: {:?}",
+ item, declaration, location
+ );
+ debug_assert!(
+ declaration.is_some() ||
+ !item.kind().is_type() ||
+ item.kind().expect_type().is_builtin_or_type_param() ||
+ item.kind().expect_type().is_opaque(self, &item) ||
+ item.kind().expect_type().is_unresolved_ref(),
+ "Adding a type without declaration?"
+ );
+
+ let id = item.id();
+ let is_type = item.kind().is_type();
+ let is_unnamed = is_type && item.expect_type().name().is_none();
+ let is_template_instantiation =
+ is_type && item.expect_type().is_template_instantiation();
+
+ if item.id() != self.root_module {
+ self.add_item_to_module(&item);
+ }
+
+ if is_type && item.expect_type().is_comp() {
+ self.need_bitfield_allocation.push(id);
+ }
+
+ let old_item = mem::replace(&mut self.items[id.0], Some(item));
+ assert!(
+ old_item.is_none(),
+ "should not have already associated an item with the given id"
+ );
+
+ // Unnamed items can have an USR, but they can't be referenced from
+ // other sites explicitly and the USR can match if the unnamed items are
+ // nested, so don't bother tracking them.
+ if !is_type || is_template_instantiation {
+ return;
+ }
+ if let Some(mut declaration) = declaration {
+ if !declaration.is_valid() {
+ if let Some(location) = location {
+ if location.is_template_like() {
+ declaration = location;
+ }
+ }
+ }
+ declaration = declaration.canonical();
+ if !declaration.is_valid() {
+ // This could happen, for example, with types like `int*` or
+ // similar.
+ //
+ // Fortunately, we don't care about those types being
+ // duplicated, so we can just ignore them.
+ debug!(
+ "Invalid declaration {:?} found for type {:?}",
+ declaration,
+ self.resolve_item_fallible(id)
+ .unwrap()
+ .kind()
+ .expect_type()
+ );
+ return;
+ }
+
+ let key = if is_unnamed {
+ TypeKey::Declaration(declaration)
+ } else if let Some(usr) = declaration.usr() {
+ TypeKey::Usr(usr)
+ } else {
+ warn!(
+ "Valid declaration with no USR: {:?}, {:?}",
+ declaration, location
+ );
+ TypeKey::Declaration(declaration)
+ };
+
+ let old = self.types.insert(key, id.as_type_id_unchecked());
+ debug_assert_eq!(old, None);
+ }
+ }
+
+ /// Ensure that every item (other than the root module) is in a module's
+ /// children list. This is to make sure that every allowlisted item get's
+ /// codegen'd, even if its parent is not allowlisted. See issue #769 for
+ /// details.
+ fn add_item_to_module(&mut self, item: &Item) {
+ assert!(item.id() != self.root_module);
+ assert!(self.resolve_item_fallible(item.id()).is_none());
+
+ if let Some(ref mut parent) = self.items[item.parent_id().0] {
+ if let Some(module) = parent.as_module_mut() {
+ debug!(
+ "add_item_to_module: adding {:?} as child of parent module {:?}",
+ item.id(),
+ item.parent_id()
+ );
+
+ module.children_mut().insert(item.id());
+ return;
+ }
+ }
+
+ debug!(
+ "add_item_to_module: adding {:?} as child of current module {:?}",
+ item.id(),
+ self.current_module
+ );
+
+ self.items[(self.current_module.0).0]
+ .as_mut()
+ .expect("Should always have an item for self.current_module")
+ .as_module_mut()
+ .expect("self.current_module should always be a module")
+ .children_mut()
+ .insert(item.id());
+ }
+
+ /// Add a new named template type parameter to this context's item set.
+ pub(crate) 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(crate) fn get_type_param(
+ &self,
+ definition: &clang::Cursor,
+ ) -> Option<TypeId> {
+ assert_eq!(
+ definition.kind(),
+ clang_sys::CXCursor_TemplateTypeParameter
+ );
+ self.type_params.get(definition).cloned()
+ }
+
+ // TODO: Move all this syntax crap to other part of the code.
+
+ /// Mangles a name so it doesn't conflict with any keyword.
+ #[rustfmt::skip]
+ pub(crate) fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> {
+ if name.contains('@') ||
+ name.contains('?') ||
+ name.contains('$') ||
+ matches!(
+ name,
+ "abstract" | "alignof" | "as" | "async" | "await" | "become" |
+ "box" | "break" | "const" | "continue" | "crate" | "do" |
+ "dyn" | "else" | "enum" | "extern" | "false" | "final" |
+ "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" |
+ "macro" | "match" | "mod" | "move" | "mut" | "offsetof" |
+ "override" | "priv" | "proc" | "pub" | "pure" | "ref" |
+ "return" | "Self" | "self" | "sizeof" | "static" |
+ "struct" | "super" | "trait" | "true" | "try" | "type" | "typeof" |
+ "unsafe" | "unsized" | "use" | "virtual" | "where" |
+ "while" | "yield" | "str" | "bool" | "f32" | "f64" |
+ "usize" | "isize" | "u128" | "i128" | "u64" | "i64" |
+ "u32" | "i32" | "u16" | "i16" | "u8" | "i8" | "_"
+ )
+ {
+ let mut s = name.to_owned();
+ s = s.replace('@', "_");
+ s = s.replace('?', "_");
+ s = s.replace('$', "_");
+ s.push('_');
+ return Cow::Owned(s);
+ }
+ Cow::Borrowed(name)
+ }
+
+ /// Returns a mangled name as a rust identifier.
+ pub(crate) fn rust_ident<S>(&self, name: S) -> Ident
+ where
+ S: AsRef<str>,
+ {
+ self.rust_ident_raw(self.rust_mangle(name.as_ref()))
+ }
+
+ /// Returns a mangled name as a rust identifier.
+ pub(crate) fn rust_ident_raw<T>(&self, name: T) -> Ident
+ where
+ T: AsRef<str>,
+ {
+ Ident::new(name.as_ref(), Span::call_site())
+ }
+
+ /// Iterate over all items that have been defined.
+ pub(crate) fn items(&self) -> impl Iterator<Item = (ItemId, &Item)> {
+ self.items.iter().enumerate().filter_map(|(index, item)| {
+ let item = item.as_ref()?;
+ Some((ItemId(index), item))
+ })
+ }
+
+ /// Have we collected all unresolved type references yet?
+ pub(crate) fn collected_typerefs(&self) -> bool {
+ self.collected_typerefs
+ }
+
+ /// Gather all the unresolved type references.
+ fn collect_typerefs(
+ &mut self,
+ ) -> Vec<(ItemId, clang::Type, clang::Cursor, Option<ItemId>)> {
+ debug_assert!(!self.collected_typerefs);
+ self.collected_typerefs = true;
+ let mut typerefs = vec![];
+
+ for (id, item) in self.items() {
+ let kind = item.kind();
+ let ty = match kind.as_type() {
+ Some(ty) => ty,
+ None => continue,
+ };
+
+ if let TypeKind::UnresolvedTypeRef(ref ty, loc, parent_id) =
+ *ty.kind()
+ {
+ typerefs.push((id, *ty, loc, parent_id));
+ };
+ }
+ typerefs
+ }
+
+ /// Collect all of our unresolved type references and resolve them.
+ fn resolve_typerefs(&mut self) {
+ let _t = self.timer("resolve_typerefs");
+
+ let typerefs = self.collect_typerefs();
+
+ for (id, ty, loc, parent_id) in typerefs {
+ let _resolved =
+ {
+ let resolved = Item::from_ty(&ty, loc, parent_id, self)
+ .unwrap_or_else(|_| {
+ warn!("Could not resolve type reference, falling back \
+ to opaque blob");
+ Item::new_opaque_type(self.next_item_id(), &ty, self)
+ });
+
+ let item = self.items[id.0].as_mut().unwrap();
+ *item.kind_mut().as_type_mut().unwrap().kind_mut() =
+ TypeKind::ResolvedTypeRef(resolved);
+ resolved
+ };
+
+ // Something in the STL is trolling me. I don't need this assertion
+ // right now, but worth investigating properly once this lands.
+ //
+ // debug_assert!(self.items.get(&resolved).is_some(), "How?");
+ //
+ // if let Some(parent_id) = parent_id {
+ // assert_eq!(self.items[&resolved].parent_id(), parent_id);
+ // }
+ }
+ }
+
+ /// Temporarily loan `Item` with the given `ItemId`. This provides means to
+ /// mutably borrow `Item` while having a reference to `BindgenContext`.
+ ///
+ /// `Item` with the given `ItemId` is removed from the context, given
+ /// closure is executed and then `Item` is placed back.
+ ///
+ /// # Panics
+ ///
+ /// Panics if attempt to resolve given `ItemId` inside the given
+ /// closure is made.
+ fn with_loaned_item<F, T>(&mut self, id: ItemId, f: F) -> T
+ where
+ F: (FnOnce(&BindgenContext, &mut Item) -> T),
+ {
+ let mut item = self.items[id.0].take().unwrap();
+
+ let result = f(self, &mut item);
+
+ let existing = mem::replace(&mut self.items[id.0], Some(item));
+ assert!(existing.is_none());
+
+ result
+ }
+
+ /// Compute the bitfield allocation units for all `TypeKind::Comp` items we
+ /// parsed.
+ fn compute_bitfield_units(&mut self) {
+ let _t = self.timer("compute_bitfield_units");
+
+ assert!(self.collected_typerefs());
+
+ let need_bitfield_allocation =
+ mem::take(&mut self.need_bitfield_allocation);
+ for id in need_bitfield_allocation {
+ self.with_loaned_item(id, |ctx, item| {
+ let ty = item.kind_mut().as_type_mut().unwrap();
+ let layout = ty.layout(ctx);
+ ty.as_comp_mut()
+ .unwrap()
+ .compute_bitfield_units(ctx, layout.as_ref());
+ });
+ }
+ }
+
+ /// Assign a new generated name for each anonymous field.
+ fn deanonymize_fields(&mut self) {
+ let _t = self.timer("deanonymize_fields");
+
+ let comp_item_ids: Vec<ItemId> = self
+ .items()
+ .filter_map(|(id, item)| {
+ if item.kind().as_type()?.is_comp() {
+ return Some(id);
+ }
+ None
+ })
+ .collect();
+
+ for id in comp_item_ids {
+ self.with_loaned_item(id, |ctx, item| {
+ item.kind_mut()
+ .as_type_mut()
+ .unwrap()
+ .as_comp_mut()
+ .unwrap()
+ .deanonymize_fields(ctx);
+ });
+ }
+ }
+
+ /// Iterate over all items and replace any item that has been named in a
+ /// `replaces="SomeType"` annotation with the replacement type.
+ fn process_replacements(&mut self) {
+ let _t = self.timer("process_replacements");
+ if self.replacements.is_empty() {
+ debug!("No replacements to process");
+ return;
+ }
+
+ // FIXME: This is linear, but the replaces="xxx" annotation was already
+ // there, and for better or worse it's useful, sigh...
+ //
+ // We leverage the ResolvedTypeRef thing, though, which is cool :P.
+
+ let mut replacements = vec![];
+
+ for (id, item) in self.items() {
+ if item.annotations().use_instead_of().is_some() {
+ continue;
+ }
+
+ // Calls to `canonical_name` are expensive, so eagerly filter out
+ // items that cannot be replaced.
+ let ty = match item.kind().as_type() {
+ Some(ty) => ty,
+ None => continue,
+ };
+
+ match *ty.kind() {
+ TypeKind::Comp(..) |
+ TypeKind::TemplateAlias(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Alias(..) => {}
+ _ => continue,
+ }
+
+ let path = item.path_for_allowlisting(self);
+ let replacement = self.replacements.get(&path[1..]);
+
+ if let Some(replacement) = replacement {
+ if *replacement != id {
+ // We set this just after parsing the annotation. It's
+ // very unlikely, but this can happen.
+ if self.resolve_item_fallible(*replacement).is_some() {
+ replacements.push((
+ id.expect_type_id(self),
+ replacement.expect_type_id(self),
+ ));
+ }
+ }
+ }
+ }
+
+ for (id, replacement_id) in replacements {
+ debug!("Replacing {:?} with {:?}", id, replacement_id);
+ let new_parent = {
+ let item_id: ItemId = id.into();
+ let item = self.items[item_id.0].as_mut().unwrap();
+ *item.kind_mut().as_type_mut().unwrap().kind_mut() =
+ TypeKind::ResolvedTypeRef(replacement_id);
+ item.parent_id()
+ };
+
+ // Relocate the replacement item from where it was declared, to
+ // where the thing it is replacing was declared.
+ //
+ // First, we'll make sure that its parent ID is correct.
+
+ let old_parent = self.resolve_item(replacement_id).parent_id();
+ if new_parent == old_parent {
+ // Same parent and therefore also same containing
+ // module. Nothing to do here.
+ continue;
+ }
+
+ let replacement_item_id: ItemId = replacement_id.into();
+ self.items[replacement_item_id.0]
+ .as_mut()
+ .unwrap()
+ .set_parent_for_replacement(new_parent);
+
+ // Second, make sure that it is in the correct module's children
+ // set.
+
+ let old_module = {
+ let immut_self = &*self;
+ old_parent
+ .ancestors(immut_self)
+ .chain(Some(immut_self.root_module.into()))
+ .find(|id| {
+ let item = immut_self.resolve_item(*id);
+ item.as_module().map_or(false, |m| {
+ m.children().contains(&replacement_id.into())
+ })
+ })
+ };
+ let old_module = old_module
+ .expect("Every replacement item should be in a module");
+
+ let new_module = {
+ let immut_self = &*self;
+ new_parent
+ .ancestors(immut_self)
+ .find(|id| immut_self.resolve_item(*id).is_module())
+ };
+ let new_module =
+ new_module.unwrap_or_else(|| self.root_module.into());
+
+ if new_module == old_module {
+ // Already in the correct module.
+ continue;
+ }
+
+ self.items[old_module.0]
+ .as_mut()
+ .unwrap()
+ .as_module_mut()
+ .unwrap()
+ .children_mut()
+ .remove(&replacement_id.into());
+
+ self.items[new_module.0]
+ .as_mut()
+ .unwrap()
+ .as_module_mut()
+ .unwrap()
+ .children_mut()
+ .insert(replacement_id.into());
+ }
+ }
+
+ /// Enter the code generation phase, invoke the given callback `cb`, and
+ /// leave the code generation phase.
+ pub(crate) fn gen<F, Out>(
+ mut self,
+ cb: F,
+ ) -> Result<(Out, BindgenOptions), CodegenError>
+ where
+ F: FnOnce(&Self) -> Result<Out, CodegenError>,
+ {
+ self.in_codegen = true;
+
+ self.resolve_typerefs();
+ self.compute_bitfield_units();
+ self.process_replacements();
+
+ self.deanonymize_fields();
+
+ self.assert_no_dangling_references();
+
+ // Compute the allowlisted set after processing replacements and
+ // resolving type refs, as those are the final mutations of the IR
+ // graph, and their completion means that the IR graph is now frozen.
+ self.compute_allowlisted_and_codegen_items();
+
+ // Make sure to do this after processing replacements, since that messes
+ // with the parentage and module children, and we want to assert that it
+ // messes with them correctly.
+ self.assert_every_item_in_a_module();
+
+ self.compute_has_vtable();
+ self.compute_sizedness();
+ self.compute_has_destructor();
+ self.find_used_template_parameters();
+ self.compute_enum_typedef_combos();
+ self.compute_cannot_derive_debug();
+ self.compute_cannot_derive_default();
+ self.compute_cannot_derive_copy();
+ self.compute_has_type_param_in_array();
+ self.compute_has_float();
+ self.compute_cannot_derive_hash();
+ self.compute_cannot_derive_partialord_partialeq_or_eq();
+
+ let ret = cb(&self)?;
+ Ok((ret, self.options))
+ }
+
+ /// When the `__testing_only_extra_assertions` feature is enabled, this
+ /// function walks the IR graph and asserts that we do not have any edges
+ /// referencing an ItemId for which we do not have an associated IR item.
+ fn assert_no_dangling_references(&self) {
+ if cfg!(feature = "__testing_only_extra_assertions") {
+ for _ in self.assert_no_dangling_item_traversal() {
+ // The iterator's next method does the asserting for us.
+ }
+ }
+ }
+
+ fn assert_no_dangling_item_traversal(
+ &self,
+ ) -> traversal::AssertNoDanglingItemsTraversal {
+ assert!(self.in_codegen_phase());
+ assert!(self.current_module == self.root_module);
+
+ let roots = self.items().map(|(id, _)| id);
+ traversal::AssertNoDanglingItemsTraversal::new(
+ self,
+ roots,
+ traversal::all_edges,
+ )
+ }
+
+ /// When the `__testing_only_extra_assertions` feature is enabled, walk over
+ /// every item and ensure that it is in the children set of one of its
+ /// module ancestors.
+ fn assert_every_item_in_a_module(&self) {
+ if cfg!(feature = "__testing_only_extra_assertions") {
+ assert!(self.in_codegen_phase());
+ assert!(self.current_module == self.root_module);
+
+ for (id, _item) in self.items() {
+ if id == self.root_module {
+ continue;
+ }
+
+ assert!(
+ {
+ let id = id
+ .into_resolver()
+ .through_type_refs()
+ .through_type_aliases()
+ .resolve(self)
+ .id();
+ id.ancestors(self)
+ .chain(Some(self.root_module.into()))
+ .any(|ancestor| {
+ debug!(
+ "Checking if {:?} is a child of {:?}",
+ id, ancestor
+ );
+ self.resolve_item(ancestor)
+ .as_module()
+ .map_or(false, |m| {
+ m.children().contains(&id)
+ })
+ })
+ },
+ "{:?} should be in some ancestor module's children set",
+ id
+ );
+ }
+ }
+ }
+
+ /// Compute for every type whether it is sized or not, and whether it is
+ /// sized or not as a base class.
+ fn compute_sizedness(&mut self) {
+ let _t = self.timer("compute_sizedness");
+ assert!(self.sizedness.is_none());
+ self.sizedness = Some(analyze::<SizednessAnalysis>(self));
+ }
+
+ /// Look up whether the type with the given ID is sized or not.
+ pub(crate) fn lookup_sizedness(&self, id: TypeId) -> SizednessResult {
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute sizedness after we've entered codegen"
+ );
+
+ self.sizedness
+ .as_ref()
+ .unwrap()
+ .get(&id)
+ .cloned()
+ .unwrap_or(SizednessResult::ZeroSized)
+ }
+
+ /// Compute whether the type has vtable.
+ fn compute_has_vtable(&mut self) {
+ let _t = self.timer("compute_has_vtable");
+ assert!(self.have_vtable.is_none());
+ self.have_vtable = Some(analyze::<HasVtableAnalysis>(self));
+ }
+
+ /// Look up whether the item with `id` has vtable or not.
+ pub(crate) fn lookup_has_vtable(&self, id: TypeId) -> HasVtableResult {
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute vtables when we enter codegen"
+ );
+
+ // Look up the computed value for whether the item with `id` has a
+ // vtable or not.
+ self.have_vtable
+ .as_ref()
+ .unwrap()
+ .get(&id.into())
+ .cloned()
+ .unwrap_or(HasVtableResult::No)
+ }
+
+ /// Compute whether the type has a destructor.
+ fn compute_has_destructor(&mut self) {
+ let _t = self.timer("compute_has_destructor");
+ assert!(self.have_destructor.is_none());
+ self.have_destructor = Some(analyze::<HasDestructorAnalysis>(self));
+ }
+
+ /// Look up whether the item with `id` has a destructor.
+ pub(crate) fn lookup_has_destructor(&self, id: TypeId) -> bool {
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute destructors when we enter codegen"
+ );
+
+ self.have_destructor.as_ref().unwrap().contains(&id.into())
+ }
+
+ fn find_used_template_parameters(&mut self) {
+ let _t = self.timer("find_used_template_parameters");
+ if self.options.allowlist_recursively {
+ let used_params = analyze::<UsedTemplateParameters>(self);
+ self.used_template_parameters = Some(used_params);
+ } else {
+ // If you aren't recursively allowlisting, then we can't really make
+ // any sense of template parameter usage, and you're on your own.
+ let mut used_params = HashMap::default();
+ for &id in self.allowlisted_items() {
+ used_params.entry(id).or_insert_with(|| {
+ id.self_template_params(self)
+ .into_iter()
+ .map(|p| p.into())
+ .collect()
+ });
+ }
+ self.used_template_parameters = Some(used_params);
+ }
+ }
+
+ /// Return `true` if `item` uses the given `template_param`, `false`
+ /// otherwise.
+ ///
+ /// This method may only be called during the codegen phase, because the
+ /// template usage information is only computed as we enter the codegen
+ /// phase.
+ ///
+ /// If the item is blocklisted, then we say that it always uses the template
+ /// parameter. This is a little subtle. The template parameter usage
+ /// analysis only considers allowlisted items, and if any blocklisted item
+ /// shows up in the generated bindings, it is the user's responsibility to
+ /// manually provide a definition for them. To give them the most
+ /// flexibility when doing that, we assume that they use every template
+ /// parameter and always pass template arguments through in instantiations.
+ pub(crate) fn uses_template_parameter(
+ &self,
+ item: ItemId,
+ template_param: TypeId,
+ ) -> bool {
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute template parameter usage as we enter codegen"
+ );
+
+ if self.resolve_item(item).is_blocklisted(self) {
+ return true;
+ }
+
+ let template_param = template_param
+ .into_resolver()
+ .through_type_refs()
+ .through_type_aliases()
+ .resolve(self)
+ .id();
+
+ self.used_template_parameters
+ .as_ref()
+ .expect("should have found template parameter usage if we're in codegen")
+ .get(&item)
+ .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(crate) fn uses_any_template_parameters(&self, item: ItemId) -> bool {
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute template parameter usage as we enter codegen"
+ );
+
+ self.used_template_parameters
+ .as_ref()
+ .expect(
+ "should have template parameter usage info in codegen phase",
+ )
+ .get(&item)
+ .map_or(false, |used| !used.is_empty())
+ }
+
+ // This deserves a comment. Builtin types don't get a valid declaration, so
+ // we can't add it to the cursor->type map.
+ //
+ // That being said, they're not generated anyway, and are few, so the
+ // duplication and special-casing is fine.
+ //
+ // If at some point we care about the memory here, probably a map TypeKind
+ // -> builtin type ItemId would be the best to improve that.
+ fn add_builtin_item(&mut self, item: Item) {
+ debug!("add_builtin_item: item = {:?}", item);
+ debug_assert!(item.kind().is_type());
+ self.add_item_to_module(&item);
+ let id = item.id();
+ let old_item = mem::replace(&mut self.items[id.0], Some(item));
+ assert!(old_item.is_none(), "Inserted type twice?");
+ }
+
+ fn build_root_module(id: ItemId) -> Item {
+ let module = Module::new(Some("root".into()), ModuleKind::Normal);
+ Item::new(id, None, None, id, ItemKind::Module(module), None)
+ }
+
+ /// Get the root module.
+ pub(crate) fn root_module(&self) -> ModuleId {
+ self.root_module
+ }
+
+ /// Resolve a type with the given ID.
+ ///
+ /// Panics if there is no item for the given `TypeId` or if the resolved
+ /// item is not a `Type`.
+ pub(crate) fn resolve_type(&self, type_id: TypeId) -> &Type {
+ self.resolve_item(type_id).kind().expect_type()
+ }
+
+ /// Resolve a function with the given ID.
+ ///
+ /// Panics if there is no item for the given `FunctionId` or if the resolved
+ /// item is not a `Function`.
+ pub(crate) fn resolve_func(&self, func_id: FunctionId) -> &Function {
+ self.resolve_item(func_id).kind().expect_function()
+ }
+
+ /// Resolve the given `ItemId` as a type, or `None` if there is no item with
+ /// the given ID.
+ ///
+ /// Panics if the ID resolves to an item that is not a type.
+ pub(crate) fn safe_resolve_type(&self, type_id: TypeId) -> Option<&Type> {
+ self.resolve_item_fallible(type_id)
+ .map(|t| t.kind().expect_type())
+ }
+
+ /// Resolve the given `ItemId` into an `Item`, or `None` if no such item
+ /// exists.
+ pub(crate) fn resolve_item_fallible<Id: Into<ItemId>>(
+ &self,
+ id: Id,
+ ) -> Option<&Item> {
+ self.items.get(id.into().0)?.as_ref()
+ }
+
+ /// Resolve the given `ItemId` into an `Item`.
+ ///
+ /// Panics if the given ID does not resolve to any item.
+ pub(crate) fn resolve_item<Id: Into<ItemId>>(&self, item_id: Id) -> &Item {
+ let item_id = item_id.into();
+ match self.resolve_item_fallible(item_id) {
+ Some(item) => item,
+ None => panic!("Not an item: {:?}", item_id),
+ }
+ }
+
+ /// Get the current module.
+ pub(crate) fn current_module(&self) -> ModuleId {
+ self.current_module
+ }
+
+ /// Add a semantic parent for a given type definition.
+ ///
+ /// We do this from the type declaration, in order to be able to find the
+ /// correct type definition afterwards.
+ ///
+ /// TODO(emilio): We could consider doing this only when
+ /// declaration.lexical_parent() != definition.lexical_parent(), but it's
+ /// not sure it's worth it.
+ pub(crate) fn add_semantic_parent(
+ &mut self,
+ definition: clang::Cursor,
+ parent_id: ItemId,
+ ) {
+ self.semantic_parents.insert(definition, parent_id);
+ }
+
+ /// Returns a known semantic parent for a given definition.
+ pub(crate) fn known_semantic_parent(
+ &self,
+ definition: clang::Cursor,
+ ) -> Option<ItemId> {
+ self.semantic_parents.get(&definition).cloned()
+ }
+
+ /// Given a cursor pointing to the location of a template instantiation,
+ /// return a tuple of the form `(declaration_cursor, declaration_id,
+ /// num_expected_template_args)`.
+ ///
+ /// Note that `declaration_id` is not guaranteed to be in the context's item
+ /// set! It is possible that it is a partial type that we are still in the
+ /// middle of parsing.
+ fn get_declaration_info_for_template_instantiation(
+ &self,
+ instantiation: &Cursor,
+ ) -> Option<(Cursor, ItemId, usize)> {
+ instantiation
+ .cur_type()
+ .canonical_declaration(Some(instantiation))
+ .and_then(|canon_decl| {
+ self.get_resolved_type(&canon_decl).and_then(
+ |template_decl_id| {
+ let num_params =
+ template_decl_id.num_self_template_params(self);
+ if num_params == 0 {
+ None
+ } else {
+ Some((
+ *canon_decl.cursor(),
+ template_decl_id.into(),
+ num_params,
+ ))
+ }
+ },
+ )
+ })
+ .or_else(|| {
+ // If we haven't already parsed the declaration of
+ // the template being instantiated, then it *must*
+ // be on the stack of types we are currently
+ // parsing. If it wasn't then clang would have
+ // already errored out before we started
+ // constructing our IR because you can't instantiate
+ // a template until it is fully defined.
+ instantiation
+ .referenced()
+ .and_then(|referenced| {
+ self.currently_parsed_types()
+ .iter()
+ .find(|partial_ty| *partial_ty.decl() == referenced)
+ .cloned()
+ })
+ .and_then(|template_decl| {
+ let num_template_params =
+ template_decl.num_self_template_params(self);
+ if num_template_params == 0 {
+ None
+ } else {
+ Some((
+ *template_decl.decl(),
+ template_decl.id(),
+ num_template_params,
+ ))
+ }
+ })
+ })
+ }
+
+ /// Parse a template instantiation, eg `Foo<int>`.
+ ///
+ /// This is surprisingly difficult to do with libclang, due to the fact that
+ /// it doesn't provide explicit template argument information, except for
+ /// function template declarations(!?!??!).
+ ///
+ /// The only way to do this is manually inspecting the AST and looking for
+ /// TypeRefs and TemplateRefs inside. This, unfortunately, doesn't work for
+ /// more complex cases, see the comment on the assertion below.
+ ///
+ /// To add insult to injury, the AST itself has structure that doesn't make
+ /// sense. Sometimes `Foo<Bar<int>>` has an AST with nesting like you might
+ /// expect: `(Foo (Bar (int)))`. Other times, the AST we get is completely
+ /// flat: `(Foo Bar int)`.
+ ///
+ /// To see an example of what this method handles:
+ ///
+ /// ```c++
+ /// template<typename T>
+ /// class Incomplete {
+ /// T p;
+ /// };
+ ///
+ /// template<typename U>
+ /// class Foo {
+ /// Incomplete<U> bar;
+ /// };
+ /// ```
+ ///
+ /// Finally, template instantiations are always children of the current
+ /// module. They use their template's definition for their name, so the
+ /// parent is only useful for ensuring that their layout tests get
+ /// codegen'd.
+ fn instantiate_template(
+ &mut self,
+ with_id: ItemId,
+ template: TypeId,
+ ty: &clang::Type,
+ location: clang::Cursor,
+ ) -> Option<TypeId> {
+ let num_expected_args =
+ self.resolve_type(template).num_self_template_params(self);
+ if num_expected_args == 0 {
+ warn!(
+ "Tried to instantiate a template for which we could not \
+ determine any template parameters"
+ );
+ return None;
+ }
+
+ let mut args = vec![];
+ let mut found_const_arg = false;
+ let mut children = location.collect_children();
+
+ if children.iter().all(|c| !c.has_children()) {
+ // This is insanity... If clang isn't giving us a properly nested
+ // AST for which template arguments belong to which template we are
+ // instantiating, we'll need to construct it ourselves. However,
+ // there is an extra `NamespaceRef, NamespaceRef, ..., TemplateRef`
+ // representing a reference to the outermost template declaration
+ // that we need to filter out of the children. We need to do this
+ // filtering because we already know which template declaration is
+ // being specialized via the `location`'s type, and if we do not
+ // filter it out, we'll add an extra layer of template instantiation
+ // on accident.
+ let idx = children
+ .iter()
+ .position(|c| c.kind() == clang_sys::CXCursor_TemplateRef);
+ if let Some(idx) = idx {
+ if children
+ .iter()
+ .take(idx)
+ .all(|c| c.kind() == clang_sys::CXCursor_NamespaceRef)
+ {
+ children = children.into_iter().skip(idx + 1).collect();
+ }
+ }
+ }
+
+ for child in children.iter().rev() {
+ match child.kind() {
+ clang_sys::CXCursor_TypeRef |
+ clang_sys::CXCursor_TypedefDecl |
+ clang_sys::CXCursor_TypeAliasDecl => {
+ // The `with_id` ID will potentially end up unused if we give up
+ // on this type (for example, because it has const value
+ // template args), so if we pass `with_id` as the parent, it is
+ // potentially a dangling reference. Instead, use the canonical
+ // template declaration as the parent. It is already parsed and
+ // has a known-resolvable `ItemId`.
+ let ty = Item::from_ty_or_ref(
+ child.cur_type(),
+ *child,
+ Some(template.into()),
+ self,
+ );
+ args.push(ty);
+ }
+ clang_sys::CXCursor_TemplateRef => {
+ let (
+ template_decl_cursor,
+ template_decl_id,
+ num_expected_template_args,
+ ) = self.get_declaration_info_for_template_instantiation(
+ child,
+ )?;
+
+ if num_expected_template_args == 0 ||
+ child.has_at_least_num_children(
+ num_expected_template_args,
+ )
+ {
+ // Do a happy little parse. See comment in the TypeRef
+ // match arm about parent IDs.
+ let ty = Item::from_ty_or_ref(
+ child.cur_type(),
+ *child,
+ Some(template.into()),
+ self,
+ );
+ args.push(ty);
+ } else {
+ // This is the case mentioned in the doc comment where
+ // clang gives us a flattened AST and we have to
+ // reconstruct which template arguments go to which
+ // instantiation :(
+ let args_len = args.len();
+ if args_len < num_expected_template_args {
+ warn!(
+ "Found a template instantiation without \
+ enough template arguments"
+ );
+ return None;
+ }
+
+ let mut sub_args: Vec<_> = args
+ .drain(args_len - num_expected_template_args..)
+ .collect();
+ sub_args.reverse();
+
+ let sub_name = Some(template_decl_cursor.spelling());
+ let sub_inst = TemplateInstantiation::new(
+ // This isn't guaranteed to be a type that we've
+ // already finished parsing yet.
+ template_decl_id.as_type_id_unchecked(),
+ sub_args,
+ );
+ let sub_kind =
+ TypeKind::TemplateInstantiation(sub_inst);
+ let sub_ty = Type::new(
+ sub_name,
+ template_decl_cursor
+ .cur_type()
+ .fallible_layout(self)
+ .ok(),
+ sub_kind,
+ false,
+ );
+ let sub_id = self.next_item_id();
+ let sub_item = Item::new(
+ sub_id,
+ None,
+ None,
+ self.current_module.into(),
+ ItemKind::Type(sub_ty),
+ Some(child.location()),
+ );
+
+ // Bypass all the validations in add_item explicitly.
+ debug!(
+ "instantiate_template: inserting nested \
+ instantiation item: {:?}",
+ sub_item
+ );
+ self.add_item_to_module(&sub_item);
+ debug_assert_eq!(sub_id, sub_item.id());
+ self.items[sub_id.0] = Some(sub_item);
+ args.push(sub_id.as_type_id_unchecked());
+ }
+ }
+ _ => {
+ warn!(
+ "Found template arg cursor we can't handle: {:?}",
+ child
+ );
+ found_const_arg = true;
+ }
+ }
+ }
+
+ if found_const_arg {
+ // This is a dependently typed template instantiation. That is, an
+ // instantiation of a template with one or more const values as
+ // template arguments, rather than only types as template
+ // arguments. For example, `Foo<true, 5>` versus `Bar<bool, int>`.
+ // We can't handle these instantiations, so just punt in this
+ // situation...
+ warn!(
+ "Found template instantiated with a const value; \
+ bindgen can't handle this kind of template instantiation!"
+ );
+ return None;
+ }
+
+ if args.len() != num_expected_args {
+ warn!(
+ "Found a template with an unexpected number of template \
+ arguments"
+ );
+ return None;
+ }
+
+ args.reverse();
+ let type_kind = TypeKind::TemplateInstantiation(
+ TemplateInstantiation::new(template, args),
+ );
+ let name = ty.spelling();
+ let name = if name.is_empty() { None } else { Some(name) };
+ let ty = Type::new(
+ name,
+ ty.fallible_layout(self).ok(),
+ type_kind,
+ ty.is_const(),
+ );
+ let item = Item::new(
+ with_id,
+ None,
+ None,
+ self.current_module.into(),
+ ItemKind::Type(ty),
+ Some(location.location()),
+ );
+
+ // Bypass all the validations in add_item explicitly.
+ debug!("instantiate_template: inserting item: {:?}", item);
+ self.add_item_to_module(&item);
+ debug_assert_eq!(with_id, item.id());
+ self.items[with_id.0] = Some(item);
+ Some(with_id.as_type_id_unchecked())
+ }
+
+ /// If we have already resolved the type for the given type declaration,
+ /// return its `ItemId`. Otherwise, return `None`.
+ pub(crate) fn get_resolved_type(
+ &self,
+ decl: &clang::CanonicalTypeDeclaration,
+ ) -> Option<TypeId> {
+ self.types
+ .get(&TypeKey::Declaration(*decl.cursor()))
+ .or_else(|| {
+ decl.cursor()
+ .usr()
+ .and_then(|usr| self.types.get(&TypeKey::Usr(usr)))
+ })
+ .cloned()
+ }
+
+ /// Looks up for an already resolved type, either because it's builtin, or
+ /// because we already have it in the map.
+ pub(crate) fn builtin_or_resolved_ty(
+ &mut self,
+ with_id: ItemId,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ ) -> Option<TypeId> {
+ use clang_sys::{CXCursor_TypeAliasTemplateDecl, CXCursor_TypeRef};
+ debug!(
+ "builtin_or_resolved_ty: {:?}, {:?}, {:?}, {:?}",
+ ty, location, with_id, parent_id
+ );
+
+ if let Some(decl) = ty.canonical_declaration(location.as_ref()) {
+ if let Some(id) = self.get_resolved_type(&decl) {
+ debug!(
+ "Already resolved ty {:?}, {:?}, {:?} {:?}",
+ id, decl, ty, location
+ );
+ // If the declaration already exists, then either:
+ //
+ // * the declaration is a template declaration of some sort,
+ // and we are looking at an instantiation or specialization
+ // of it, or
+ // * we have already parsed and resolved this type, and
+ // there's nothing left to do.
+ if let Some(location) = location {
+ if decl.cursor().is_template_like() &&
+ *ty != decl.cursor().cur_type()
+ {
+ // For specialized type aliases, there's no way to get the
+ // template parameters as of this writing (for a struct
+ // specialization we wouldn't be in this branch anyway).
+ //
+ // Explicitly return `None` if there aren't any
+ // unspecialized parameters (contains any `TypeRef`) so we
+ // resolve the canonical type if there is one and it's
+ // exposed.
+ //
+ // This is _tricky_, I know :(
+ if decl.cursor().kind() ==
+ CXCursor_TypeAliasTemplateDecl &&
+ !location.contains_cursor(CXCursor_TypeRef) &&
+ ty.canonical_type().is_valid_and_exposed()
+ {
+ return None;
+ }
+
+ return self
+ .instantiate_template(with_id, id, ty, location)
+ .or(Some(id));
+ }
+ }
+
+ return Some(self.build_ty_wrapper(with_id, id, parent_id, ty));
+ }
+ }
+
+ debug!("Not resolved, maybe builtin?");
+ self.build_builtin_ty(ty)
+ }
+
+ /// Make a new item that is a resolved type reference to the `wrapped_id`.
+ ///
+ /// This is unfortunately a lot of bloat, but is needed to properly track
+ /// constness et al.
+ ///
+ /// We should probably make the constness tracking separate, so it doesn't
+ /// bloat that much, but hey, we already bloat the heck out of builtin
+ /// types.
+ pub(crate) fn build_ty_wrapper(
+ &mut self,
+ with_id: ItemId,
+ wrapped_id: TypeId,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type,
+ ) -> TypeId {
+ self.build_wrapper(with_id, wrapped_id, parent_id, ty, ty.is_const())
+ }
+
+ /// A wrapper over a type that adds a const qualifier explicitly.
+ ///
+ /// Needed to handle const methods in C++, wrapping the type .
+ pub(crate) fn build_const_wrapper(
+ &mut self,
+ with_id: ItemId,
+ wrapped_id: TypeId,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type,
+ ) -> TypeId {
+ self.build_wrapper(
+ with_id, wrapped_id, parent_id, ty, /* is_const = */ true,
+ )
+ }
+
+ fn build_wrapper(
+ &mut self,
+ with_id: ItemId,
+ wrapped_id: TypeId,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type,
+ is_const: bool,
+ ) -> TypeId {
+ let spelling = ty.spelling();
+ let layout = ty.fallible_layout(self).ok();
+ let location = ty.declaration().location();
+ let type_kind = TypeKind::ResolvedTypeRef(wrapped_id);
+ let ty = Type::new(Some(spelling), layout, type_kind, is_const);
+ let item = Item::new(
+ with_id,
+ None,
+ None,
+ parent_id.unwrap_or_else(|| self.current_module.into()),
+ ItemKind::Type(ty),
+ Some(location),
+ );
+ self.add_builtin_item(item);
+ with_id.as_type_id_unchecked()
+ }
+
+ /// Returns the next item ID to be used for an item.
+ pub(crate) fn next_item_id(&mut self) -> ItemId {
+ let ret = ItemId(self.items.len());
+ self.items.push(None);
+ ret
+ }
+
+ fn build_builtin_ty(&mut self, ty: &clang::Type) -> Option<TypeId> {
+ use clang_sys::*;
+ let type_kind = match ty.kind() {
+ CXType_NullPtr => TypeKind::NullPtr,
+ CXType_Void => TypeKind::Void,
+ CXType_Bool => TypeKind::Int(IntKind::Bool),
+ CXType_Int => TypeKind::Int(IntKind::Int),
+ CXType_UInt => TypeKind::Int(IntKind::UInt),
+ CXType_Char_S => TypeKind::Int(IntKind::Char { is_signed: true }),
+ CXType_Char_U => TypeKind::Int(IntKind::Char { is_signed: false }),
+ CXType_SChar => TypeKind::Int(IntKind::SChar),
+ CXType_UChar => TypeKind::Int(IntKind::UChar),
+ CXType_Short => TypeKind::Int(IntKind::Short),
+ CXType_UShort => TypeKind::Int(IntKind::UShort),
+ CXType_WChar => TypeKind::Int(IntKind::WChar),
+ CXType_Char16 => TypeKind::Int(IntKind::U16),
+ CXType_Char32 => TypeKind::Int(IntKind::U32),
+ CXType_Long => TypeKind::Int(IntKind::Long),
+ CXType_ULong => TypeKind::Int(IntKind::ULong),
+ CXType_LongLong => TypeKind::Int(IntKind::LongLong),
+ CXType_ULongLong => TypeKind::Int(IntKind::ULongLong),
+ CXType_Int128 => TypeKind::Int(IntKind::I128),
+ CXType_UInt128 => TypeKind::Int(IntKind::U128),
+ CXType_Float16 | CXType_Half => TypeKind::Float(FloatKind::Float16),
+ CXType_Float => TypeKind::Float(FloatKind::Float),
+ CXType_Double => TypeKind::Float(FloatKind::Double),
+ CXType_LongDouble => TypeKind::Float(FloatKind::LongDouble),
+ CXType_Float128 => TypeKind::Float(FloatKind::Float128),
+ CXType_Complex => {
+ let float_type =
+ ty.elem_type().expect("Not able to resolve complex type?");
+ let float_kind = match float_type.kind() {
+ CXType_Float16 | CXType_Half => FloatKind::Float16,
+ CXType_Float => FloatKind::Float,
+ CXType_Double => FloatKind::Double,
+ CXType_LongDouble => FloatKind::LongDouble,
+ CXType_Float128 => FloatKind::Float128,
+ _ => panic!(
+ "Non floating-type complex? {:?}, {:?}",
+ ty, float_type,
+ ),
+ };
+ TypeKind::Complex(float_kind)
+ }
+ _ => return None,
+ };
+
+ let spelling = ty.spelling();
+ let is_const = ty.is_const();
+ let layout = ty.fallible_layout(self).ok();
+ let location = ty.declaration().location();
+ let ty = Type::new(Some(spelling), layout, type_kind, is_const);
+ let id = self.next_item_id();
+ let item = Item::new(
+ id,
+ None,
+ None,
+ self.root_module.into(),
+ ItemKind::Type(ty),
+ Some(location),
+ );
+ self.add_builtin_item(item);
+ Some(id.as_type_id_unchecked())
+ }
+
+ /// Get the current Clang translation unit that is being processed.
+ pub(crate) fn translation_unit(&self) -> &clang::TranslationUnit {
+ &self.translation_unit
+ }
+
+ /// Have we parsed the macro named `macro_name` already?
+ pub(crate) fn parsed_macro(&self, macro_name: &[u8]) -> bool {
+ self.parsed_macros.contains_key(macro_name)
+ }
+
+ /// Get the currently parsed macros.
+ pub(crate) fn parsed_macros(
+ &self,
+ ) -> &StdHashMap<Vec<u8>, cexpr::expr::EvalResult> {
+ debug_assert!(!self.in_codegen_phase());
+ &self.parsed_macros
+ }
+
+ /// Mark the macro named `macro_name` as parsed.
+ pub(crate) fn note_parsed_macro(
+ &mut self,
+ id: Vec<u8>,
+ value: cexpr::expr::EvalResult,
+ ) {
+ self.parsed_macros.insert(id, value);
+ }
+
+ /// Are we in the codegen phase?
+ pub(crate) fn in_codegen_phase(&self) -> bool {
+ self.in_codegen
+ }
+
+ /// Mark the type with the given `name` as replaced by the type with ID
+ /// `potential_ty`.
+ ///
+ /// Replacement types are declared using the `replaces="xxx"` annotation,
+ /// and implies that the original type is hidden.
+ pub(crate) fn replace(&mut self, name: &[String], potential_ty: ItemId) {
+ match self.replacements.entry(name.into()) {
+ Entry::Vacant(entry) => {
+ debug!(
+ "Defining replacement for {:?} 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(crate) fn is_replaced_type<Id: Into<ItemId>>(
+ &self,
+ path: &[String],
+ id: Id,
+ ) -> bool {
+ let id = id.into();
+ matches!(self.replacements.get(path), Some(replaced_by) if *replaced_by != id)
+ }
+
+ /// Is the type with the given `name` marked as opaque?
+ pub(crate) fn opaque_by_name(&self, path: &[String]) -> bool {
+ debug_assert!(
+ self.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ self.options.opaque_types.matches(path[1..].join("::"))
+ }
+
+ /// Get the options used to configure this bindgen context.
+ pub(crate) fn options(&self) -> &BindgenOptions {
+ &self.options
+ }
+
+ /// Tokenizes a namespace cursor in order to get the name and kind of the
+ /// namespace.
+ fn tokenize_namespace(
+ &self,
+ cursor: &clang::Cursor,
+ ) -> (Option<String>, ModuleKind) {
+ assert_eq!(
+ cursor.kind(),
+ ::clang_sys::CXCursor_Namespace,
+ "Be a nice person"
+ );
+
+ let mut module_name = None;
+ let spelling = cursor.spelling();
+ if !spelling.is_empty() {
+ module_name = Some(spelling)
+ }
+
+ let mut kind = ModuleKind::Normal;
+ let mut looking_for_name = false;
+ for token in cursor.tokens().iter() {
+ match token.spelling() {
+ b"inline" => {
+ debug_assert!(
+ kind != ModuleKind::Inline,
+ "Multiple inline keywords?"
+ );
+ kind = ModuleKind::Inline;
+ // When hitting a nested inline namespace we get a spelling
+ // that looks like ["inline", "foo"]. Deal with it properly.
+ looking_for_name = true;
+ }
+ // The double colon allows us to handle nested namespaces like
+ // namespace foo::bar { }
+ //
+ // libclang still gives us two namespace cursors, which is cool,
+ // but the tokenization of the second begins with the double
+ // colon. That's ok, so we only need to handle the weird
+ // tokenization here.
+ b"namespace" | b"::" => {
+ looking_for_name = true;
+ }
+ b"{" => {
+ // This should be an anonymous namespace.
+ assert!(looking_for_name);
+ break;
+ }
+ name => {
+ if looking_for_name {
+ if module_name.is_none() {
+ module_name = Some(
+ String::from_utf8_lossy(name).into_owned(),
+ );
+ }
+ break;
+ } else {
+ // This is _likely_, but not certainly, a macro that's
+ // been placed just before the namespace keyword.
+ // Unfortunately, clang tokens don't let us easily see
+ // through the ifdef tokens, so we don't know what this
+ // token should really be. Instead of panicking though,
+ // we warn the user that we assumed the token was blank,
+ // and then move on.
+ //
+ // See also https://github.com/rust-lang/rust-bindgen/issues/1676.
+ warn!(
+ "Ignored unknown namespace prefix '{}' at {:?} in {:?}",
+ String::from_utf8_lossy(name),
+ 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(crate) fn module(&mut self, cursor: clang::Cursor) -> ModuleId {
+ use clang_sys::*;
+ assert_eq!(cursor.kind(), CXCursor_Namespace, "Be a nice person");
+ let cursor = cursor.canonical();
+ if let Some(id) = self.modules.get(&cursor) {
+ return *id;
+ }
+
+ let (module_name, kind) = self.tokenize_namespace(&cursor);
+
+ let module_id = self.next_item_id();
+ let module = Module::new(module_name, kind);
+ let module = Item::new(
+ module_id,
+ None,
+ None,
+ self.current_module.into(),
+ ItemKind::Module(module),
+ Some(cursor.location()),
+ );
+
+ let module_id = module.id().as_module_id_unchecked();
+ self.modules.insert(cursor, module_id);
+
+ self.add_item(module, None, None);
+
+ module_id
+ }
+
+ /// Start traversing the module with the given `module_id`, invoke the
+ /// callback `cb`, and then return to traversing the original module.
+ pub(crate) fn with_module<F>(&mut self, module_id: ModuleId, cb: F)
+ where
+ F: FnOnce(&mut Self),
+ {
+ debug_assert!(self.resolve_item(module_id).kind().is_module(), "Wat");
+
+ let previous_id = self.current_module;
+ self.current_module = module_id;
+
+ cb(self);
+
+ self.current_module = previous_id;
+ }
+
+ /// Iterate over all (explicitly or transitively) allowlisted items.
+ ///
+ /// If no items are explicitly allowlisted, then all items are considered
+ /// allowlisted.
+ pub(crate) fn allowlisted_items(&self) -> &ItemSet {
+ assert!(self.in_codegen_phase());
+ assert!(self.current_module == self.root_module);
+
+ self.allowlisted.as_ref().unwrap()
+ }
+
+ /// Check whether a particular blocklisted type implements a trait or not.
+ /// Results may be cached.
+ pub(crate) fn blocklisted_type_implements_trait(
+ &self,
+ item: &Item,
+ derive_trait: DeriveTrait,
+ ) -> CanDerive {
+ assert!(self.in_codegen_phase());
+ assert!(self.current_module == self.root_module);
+
+ *self
+ .blocklisted_types_implement_traits
+ .borrow_mut()
+ .entry(derive_trait)
+ .or_default()
+ .entry(item.id())
+ .or_insert_with(|| {
+ item.expect_type()
+ .name()
+ .and_then(|name| {
+ if self.options.parse_callbacks.is_empty() {
+ // Sized integer types from <stdint.h> get mapped to Rust primitive
+ // types regardless of whether they are blocklisted, so ensure that
+ // standard traits are considered derivable for them too.
+ if self.is_stdint_type(name) {
+ Some(CanDerive::Yes)
+ } else {
+ Some(CanDerive::No)
+ }
+ } else {
+ self.options.last_callback(|cb| {
+ cb.blocklisted_type_implements_trait(
+ name,
+ derive_trait,
+ )
+ })
+ }
+ })
+ .unwrap_or(CanDerive::No)
+ })
+ }
+
+ /// Is the given type a type from <stdint.h> that corresponds to a Rust primitive type?
+ pub(crate) fn is_stdint_type(&self, name: &str) -> bool {
+ match name {
+ "int8_t" | "uint8_t" | "int16_t" | "uint16_t" | "int32_t" |
+ "uint32_t" | "int64_t" | "uint64_t" | "uintptr_t" |
+ "intptr_t" | "ptrdiff_t" => true,
+ "size_t" | "ssize_t" => self.options.size_t_is_usize,
+ _ => false,
+ }
+ }
+
+ /// Get a reference to the set of items we should generate.
+ pub(crate) fn codegen_items(&self) -> &ItemSet {
+ assert!(self.in_codegen_phase());
+ assert!(self.current_module == self.root_module);
+ self.codegen_items.as_ref().unwrap()
+ }
+
+ /// Compute the allowlisted items set and populate `self.allowlisted`.
+ fn compute_allowlisted_and_codegen_items(&mut self) {
+ assert!(self.in_codegen_phase());
+ assert!(self.current_module == self.root_module);
+ assert!(self.allowlisted.is_none());
+ let _t = self.timer("compute_allowlisted_and_codegen_items");
+
+ let roots = {
+ let mut roots = self
+ .items()
+ // Only consider roots that are enabled for codegen.
+ .filter(|&(_, item)| item.is_enabled_for_codegen(self))
+ .filter(|&(_, item)| {
+ // If nothing is explicitly allowlisted, then everything is fair
+ // game.
+ if self.options().allowlisted_types.is_empty() &&
+ self.options().allowlisted_functions.is_empty() &&
+ self.options().allowlisted_vars.is_empty() &&
+ self.options().allowlisted_files.is_empty() &&
+ self.options().allowlisted_items.is_empty()
+ {
+ return true;
+ }
+
+ // If this is a type that explicitly replaces another, we assume
+ // you know what you're doing.
+ if item.annotations().use_instead_of().is_some() {
+ return true;
+ }
+
+ // Items with a source location in an explicitly allowlisted file
+ // are always included.
+ if !self.options().allowlisted_files.is_empty() {
+ if let Some(location) = item.location() {
+ let (file, _, _, _) = location.location();
+ if let Some(filename) = file.name() {
+ if self
+ .options()
+ .allowlisted_files
+ .matches(filename)
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ let name = item.path_for_allowlisting(self)[1..].join("::");
+ debug!("allowlisted_items: testing {:?}", name);
+
+ if self.options().allowlisted_items.matches(&name) {
+ return true;
+ }
+
+ match *item.kind() {
+ ItemKind::Module(..) => true,
+ ItemKind::Function(_) => {
+ self.options().allowlisted_functions.matches(&name)
+ }
+ ItemKind::Var(_) => {
+ self.options().allowlisted_vars.matches(&name)
+ }
+ ItemKind::Type(ref ty) => {
+ if self.options().allowlisted_types.matches(&name) {
+ return true;
+ }
+
+ // Auto-allowlist types that don't need code
+ // generation if not allowlisting recursively, to
+ // make the #[derive] analysis not be lame.
+ if !self.options().allowlist_recursively {
+ match *ty.kind() {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Array(..) |
+ TypeKind::Vector(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Function(..) |
+ TypeKind::ResolvedTypeRef(..) |
+ TypeKind::Opaque |
+ TypeKind::TypeParam => return true,
+ _ => {}
+ }
+ if self.is_stdint_type(&name) {
+ return true;
+ }
+ }
+
+ // Unnamed top-level enums are special and we
+ // allowlist them via the `allowlisted_vars` filter,
+ // since they're effectively top-level constants,
+ // and there's no way for them to be referenced
+ // consistently.
+ let parent = self.resolve_item(item.parent_id());
+ if !parent.is_module() {
+ return false;
+ }
+
+ let enum_ = match *ty.kind() {
+ TypeKind::Enum(ref e) => e,
+ _ => return false,
+ };
+
+ if ty.name().is_some() {
+ return false;
+ }
+
+ let mut prefix_path =
+ parent.path_for_allowlisting(self).clone();
+ enum_.variants().iter().any(|variant| {
+ prefix_path.push(
+ variant.name_for_allowlisting().into(),
+ );
+ let name = prefix_path[1..].join("::");
+ prefix_path.pop().unwrap();
+ self.options().allowlisted_vars.matches(name)
+ })
+ }
+ }
+ })
+ .map(|(id, _)| id)
+ .collect::<Vec<_>>();
+
+ // The reversal preserves the expected ordering of traversal,
+ // resulting in more stable-ish bindgen-generated names for
+ // anonymous types (like unions).
+ roots.reverse();
+ roots
+ };
+
+ let allowlisted_items_predicate =
+ if self.options().allowlist_recursively {
+ traversal::all_edges
+ } else {
+ // Only follow InnerType edges from the allowlisted roots.
+ // Such inner types (e.g. anonymous structs/unions) are
+ // always emitted by codegen, and they need to be allowlisted
+ // to make sure they are processed by e.g. the derive analysis.
+ traversal::only_inner_type_edges
+ };
+
+ let allowlisted = AllowlistedItemsTraversal::new(
+ self,
+ roots.clone(),
+ allowlisted_items_predicate,
+ )
+ .collect::<ItemSet>();
+
+ let codegen_items = if self.options().allowlist_recursively {
+ AllowlistedItemsTraversal::new(
+ self,
+ roots,
+ traversal::codegen_edges,
+ )
+ .collect::<ItemSet>()
+ } else {
+ allowlisted.clone()
+ };
+
+ self.allowlisted = Some(allowlisted);
+ self.codegen_items = Some(codegen_items);
+
+ for item in self.options().allowlisted_functions.unmatched_items() {
+ unused_regex_diagnostic(item, "--allowlist-function", self);
+ }
+
+ for item in self.options().allowlisted_vars.unmatched_items() {
+ unused_regex_diagnostic(item, "--allowlist-var", self);
+ }
+
+ for item in self.options().allowlisted_types.unmatched_items() {
+ unused_regex_diagnostic(item, "--allowlist-type", self);
+ }
+
+ for item in self.options().allowlisted_items.unmatched_items() {
+ unused_regex_diagnostic(item, "--allowlist-items", self);
+ }
+ }
+
+ /// Convenient method for getting the prefix to use for most traits in
+ /// codegen depending on the `use_core` option.
+ pub(crate) fn trait_prefix(&self) -> Ident {
+ if self.options().use_core {
+ self.rust_ident_raw("core")
+ } else {
+ self.rust_ident_raw("std")
+ }
+ }
+
+ /// Call if a bindgen complex is generated
+ pub(crate) fn generated_bindgen_complex(&self) {
+ self.generated_bindgen_complex.set(true)
+ }
+
+ /// Whether we need to generate the bindgen complex type
+ pub(crate) fn need_bindgen_complex_type(&self) -> bool {
+ self.generated_bindgen_complex.get()
+ }
+
+ /// Call if a bindgen float16 is generated
+ pub(crate) fn generated_bindgen_float16(&self) {
+ self.generated_bindgen_float16.set(true)
+ }
+
+ /// Whether we need to generate the bindgen float16 type
+ pub(crate) fn need_bindgen_float16_type(&self) -> bool {
+ self.generated_bindgen_float16.get()
+ }
+
+ /// Compute which `enum`s have an associated `typedef` definition.
+ fn compute_enum_typedef_combos(&mut self) {
+ let _t = self.timer("compute_enum_typedef_combos");
+ assert!(self.enum_typedef_combos.is_none());
+
+ let mut enum_typedef_combos = HashSet::default();
+ for item in &self.items {
+ if let Some(ItemKind::Module(module)) =
+ item.as_ref().map(Item::kind)
+ {
+ // Find typedefs in this module, and build set of their names.
+ let mut names_of_typedefs = HashSet::default();
+ for child_id in module.children() {
+ if let Some(ItemKind::Type(ty)) =
+ self.items[child_id.0].as_ref().map(Item::kind)
+ {
+ if let (Some(name), TypeKind::Alias(type_id)) =
+ (ty.name(), ty.kind())
+ {
+ // We disregard aliases that refer to the enum
+ // itself, such as in `typedef enum { ... } Enum;`.
+ if type_id
+ .into_resolver()
+ .through_type_refs()
+ .through_type_aliases()
+ .resolve(self)
+ .expect_type()
+ .is_int()
+ {
+ names_of_typedefs.insert(name);
+ }
+ }
+ }
+ }
+
+ // Find enums in this module, and record the ID of each one that
+ // has a typedef.
+ for child_id in module.children() {
+ if let Some(ItemKind::Type(ty)) =
+ self.items[child_id.0].as_ref().map(Item::kind)
+ {
+ if let (Some(name), true) = (ty.name(), ty.is_enum()) {
+ if names_of_typedefs.contains(name) {
+ enum_typedef_combos.insert(*child_id);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ self.enum_typedef_combos = Some(enum_typedef_combos);
+ }
+
+ /// Look up whether `id` refers to an `enum` whose underlying type is
+ /// defined by a `typedef`.
+ pub(crate) fn is_enum_typedef_combo(&self, id: ItemId) -> bool {
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute enum_typedef_combos when we enter codegen",
+ );
+ self.enum_typedef_combos.as_ref().unwrap().contains(&id)
+ }
+
+ /// Compute whether we can derive debug.
+ fn compute_cannot_derive_debug(&mut self) {
+ let _t = self.timer("compute_cannot_derive_debug");
+ assert!(self.cannot_derive_debug.is_none());
+ if self.options.derive_debug {
+ self.cannot_derive_debug =
+ Some(as_cannot_derive_set(analyze::<CannotDerive>((
+ self,
+ DeriveTrait::Debug,
+ ))));
+ }
+ }
+
+ /// Look up whether the item with `id` can
+ /// derive debug or not.
+ pub(crate) fn lookup_can_derive_debug<Id: Into<ItemId>>(
+ &self,
+ id: Id,
+ ) -> bool {
+ let id = id.into();
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute can_derive_debug when we enter codegen"
+ );
+
+ // Look up the computed value for whether the item with `id` can
+ // derive debug or not.
+ !self.cannot_derive_debug.as_ref().unwrap().contains(&id)
+ }
+
+ /// Compute whether we can derive default.
+ fn compute_cannot_derive_default(&mut self) {
+ let _t = self.timer("compute_cannot_derive_default");
+ assert!(self.cannot_derive_default.is_none());
+ if self.options.derive_default {
+ self.cannot_derive_default =
+ Some(as_cannot_derive_set(analyze::<CannotDerive>((
+ self,
+ DeriveTrait::Default,
+ ))));
+ }
+ }
+
+ /// Look up whether the item with `id` can
+ /// derive default or not.
+ pub(crate) fn lookup_can_derive_default<Id: Into<ItemId>>(
+ &self,
+ id: Id,
+ ) -> bool {
+ let id = id.into();
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute can_derive_default when we enter codegen"
+ );
+
+ // Look up the computed value for whether the item with `id` can
+ // derive default or not.
+ !self.cannot_derive_default.as_ref().unwrap().contains(&id)
+ }
+
+ /// Compute whether we can derive copy.
+ fn compute_cannot_derive_copy(&mut self) {
+ let _t = self.timer("compute_cannot_derive_copy");
+ assert!(self.cannot_derive_copy.is_none());
+ self.cannot_derive_copy =
+ Some(as_cannot_derive_set(analyze::<CannotDerive>((
+ self,
+ DeriveTrait::Copy,
+ ))));
+ }
+
+ /// Compute whether we can derive hash.
+ fn compute_cannot_derive_hash(&mut self) {
+ let _t = self.timer("compute_cannot_derive_hash");
+ assert!(self.cannot_derive_hash.is_none());
+ if self.options.derive_hash {
+ self.cannot_derive_hash =
+ Some(as_cannot_derive_set(analyze::<CannotDerive>((
+ self,
+ DeriveTrait::Hash,
+ ))));
+ }
+ }
+
+ /// Look up whether the item with `id` can
+ /// derive hash or not.
+ pub(crate) fn lookup_can_derive_hash<Id: Into<ItemId>>(
+ &self,
+ id: Id,
+ ) -> bool {
+ let id = id.into();
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute can_derive_debug when we enter codegen"
+ );
+
+ // Look up the computed value for whether the item with `id` can
+ // derive hash or not.
+ !self.cannot_derive_hash.as_ref().unwrap().contains(&id)
+ }
+
+ /// Compute whether we can derive PartialOrd, PartialEq or Eq.
+ fn compute_cannot_derive_partialord_partialeq_or_eq(&mut self) {
+ let _t = self.timer("compute_cannot_derive_partialord_partialeq_or_eq");
+ assert!(self.cannot_derive_partialeq_or_partialord.is_none());
+ if self.options.derive_partialord ||
+ self.options.derive_partialeq ||
+ self.options.derive_eq
+ {
+ self.cannot_derive_partialeq_or_partialord =
+ Some(analyze::<CannotDerive>((
+ self,
+ DeriveTrait::PartialEqOrPartialOrd,
+ )));
+ }
+ }
+
+ /// Look up whether the item with `id` can derive `Partial{Eq,Ord}`.
+ pub(crate) fn lookup_can_derive_partialeq_or_partialord<
+ Id: Into<ItemId>,
+ >(
+ &self,
+ id: Id,
+ ) -> CanDerive {
+ let id = id.into();
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute can_derive_partialeq_or_partialord when we enter codegen"
+ );
+
+ // Look up the computed value for whether the item with `id` can
+ // derive partialeq or not.
+ self.cannot_derive_partialeq_or_partialord
+ .as_ref()
+ .unwrap()
+ .get(&id)
+ .cloned()
+ .unwrap_or(CanDerive::Yes)
+ }
+
+ /// Look up whether the item with `id` can derive `Copy` or not.
+ pub(crate) fn lookup_can_derive_copy<Id: Into<ItemId>>(
+ &self,
+ id: Id,
+ ) -> bool {
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute can_derive_debug when we enter codegen"
+ );
+
+ // Look up the computed value for whether the item with `id` can
+ // derive `Copy` or not.
+ let id = id.into();
+
+ !self.lookup_has_type_param_in_array(id) &&
+ !self.cannot_derive_copy.as_ref().unwrap().contains(&id)
+ }
+
+ /// Compute whether the type has type parameter in array.
+ fn compute_has_type_param_in_array(&mut self) {
+ let _t = self.timer("compute_has_type_param_in_array");
+ assert!(self.has_type_param_in_array.is_none());
+ self.has_type_param_in_array =
+ Some(analyze::<HasTypeParameterInArray>(self));
+ }
+
+ /// Look up whether the item with `id` has type parameter in array or not.
+ pub(crate) fn lookup_has_type_param_in_array<Id: Into<ItemId>>(
+ &self,
+ id: Id,
+ ) -> bool {
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute has array when we enter codegen"
+ );
+
+ // Look up the computed value for whether the item with `id` has
+ // type parameter in array or not.
+ self.has_type_param_in_array
+ .as_ref()
+ .unwrap()
+ .contains(&id.into())
+ }
+
+ /// Compute whether the type has float.
+ fn compute_has_float(&mut self) {
+ let _t = self.timer("compute_has_float");
+ assert!(self.has_float.is_none());
+ if self.options.derive_eq || self.options.derive_ord {
+ self.has_float = Some(analyze::<HasFloat>(self));
+ }
+ }
+
+ /// Look up whether the item with `id` has array or not.
+ pub(crate) fn lookup_has_float<Id: Into<ItemId>>(&self, id: Id) -> bool {
+ assert!(
+ self.in_codegen_phase(),
+ "We only compute has float when we enter codegen"
+ );
+
+ // Look up the computed value for whether the item with `id` has
+ // float or not.
+ self.has_float.as_ref().unwrap().contains(&id.into())
+ }
+
+ /// Check if `--no-partialeq` flag is enabled for this item.
+ pub(crate) fn no_partialeq_by_name(&self, item: &Item) -> bool {
+ let name = item.path_for_allowlisting(self)[1..].join("::");
+ self.options().no_partialeq_types.matches(name)
+ }
+
+ /// Check if `--no-copy` flag is enabled for this item.
+ pub(crate) fn no_copy_by_name(&self, item: &Item) -> bool {
+ let name = item.path_for_allowlisting(self)[1..].join("::");
+ self.options().no_copy_types.matches(name)
+ }
+
+ /// Check if `--no-debug` flag is enabled for this item.
+ pub(crate) fn no_debug_by_name(&self, item: &Item) -> bool {
+ let name = item.path_for_allowlisting(self)[1..].join("::");
+ self.options().no_debug_types.matches(name)
+ }
+
+ /// Check if `--no-default` flag is enabled for this item.
+ pub(crate) fn no_default_by_name(&self, item: &Item) -> bool {
+ let name = item.path_for_allowlisting(self)[1..].join("::");
+ self.options().no_default_types.matches(name)
+ }
+
+ /// Check if `--no-hash` flag is enabled for this item.
+ pub(crate) fn no_hash_by_name(&self, item: &Item) -> bool {
+ let name = item.path_for_allowlisting(self)[1..].join("::");
+ self.options().no_hash_types.matches(name)
+ }
+
+ /// Check if `--must-use-type` flag is enabled for this item.
+ pub(crate) fn must_use_type_by_name(&self, item: &Item) -> bool {
+ let name = item.path_for_allowlisting(self)[1..].join("::");
+ self.options().must_use_types.matches(name)
+ }
+
+ /// Wrap some tokens in an `unsafe` block if the `--wrap-unsafe-ops` option is enabled.
+ pub(crate) fn wrap_unsafe_ops(&self, tokens: impl ToTokens) -> TokenStream {
+ if self.options.wrap_unsafe_ops {
+ quote!(unsafe { #tokens })
+ } else {
+ tokens.into_token_stream()
+ }
+ }
+
+ /// Get the suffix to be added to `static` functions if the `--wrap-static-fns` option is
+ /// enabled.
+ pub(crate) fn wrap_static_fns_suffix(&self) -> &str {
+ self.options()
+ .wrap_static_fns_suffix
+ .as_deref()
+ .unwrap_or(crate::DEFAULT_NON_EXTERN_FNS_SUFFIX)
+ }
+}
+
+/// A builder struct for configuring item resolution options.
+#[derive(Debug, Copy, Clone)]
+pub(crate) struct ItemResolver {
+ id: ItemId,
+ through_type_refs: bool,
+ through_type_aliases: bool,
+}
+
+impl ItemId {
+ /// Create an `ItemResolver` from this item ID.
+ pub(crate) fn into_resolver(self) -> ItemResolver {
+ self.into()
+ }
+}
+
+impl<T> From<T> for ItemResolver
+where
+ T: Into<ItemId>,
+{
+ fn from(id: T) -> ItemResolver {
+ ItemResolver::new(id)
+ }
+}
+
+impl ItemResolver {
+ /// Construct a new `ItemResolver` from the given ID.
+ pub(crate) fn new<Id: Into<ItemId>>(id: Id) -> ItemResolver {
+ let id = id.into();
+ ItemResolver {
+ id,
+ through_type_refs: false,
+ through_type_aliases: false,
+ }
+ }
+
+ /// Keep resolving through `Type::TypeRef` items.
+ pub(crate) fn through_type_refs(mut self) -> ItemResolver {
+ self.through_type_refs = true;
+ self
+ }
+
+ /// Keep resolving through `Type::Alias` items.
+ pub(crate) fn through_type_aliases(mut self) -> ItemResolver {
+ self.through_type_aliases = true;
+ self
+ }
+
+ /// Finish configuring and perform the actual item resolution.
+ pub(crate) fn resolve(self, ctx: &BindgenContext) -> &Item {
+ assert!(ctx.collected_typerefs());
+
+ let mut id = self.id;
+ let mut seen_ids = HashSet::default();
+ loop {
+ let item = ctx.resolve_item(id);
+
+ // Detect cycles and bail out. These can happen in certain cases
+ // involving incomplete qualified dependent types (#2085).
+ if !seen_ids.insert(id) {
+ return item;
+ }
+
+ let ty_kind = item.as_type().map(|t| t.kind());
+ match ty_kind {
+ Some(&TypeKind::ResolvedTypeRef(next_id))
+ if self.through_type_refs =>
+ {
+ id = next_id.into();
+ }
+ // We intentionally ignore template aliases here, as they are
+ // more complicated, and don't represent a simple renaming of
+ // some type.
+ Some(&TypeKind::Alias(next_id))
+ if self.through_type_aliases =>
+ {
+ id = next_id.into();
+ }
+ _ => return item,
+ }
+ }
+ }
+}
+
+/// A type that we are in the middle of parsing.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub(crate) struct PartialType {
+ decl: Cursor,
+ // Just an ItemId, and not a TypeId, because we haven't finished this type
+ // yet, so there's still time for things to go wrong.
+ id: ItemId,
+}
+
+impl PartialType {
+ /// Construct a new `PartialType`.
+ pub(crate) fn new(decl: Cursor, id: ItemId) -> PartialType {
+ // assert!(decl == decl.canonical());
+ PartialType { decl, id }
+ }
+
+ /// The cursor pointing to this partial type's declaration location.
+ pub(crate) fn decl(&self) -> &Cursor {
+ &self.decl
+ }
+
+ /// The item ID allocated for this type. This is *NOT* a key for an entry in
+ /// the context's item set yet!
+ pub(crate) fn id(&self) -> ItemId {
+ self.id
+ }
+}
+
+impl TemplateParameters for PartialType {
+ fn self_template_params(&self, _ctx: &BindgenContext) -> Vec<TypeId> {
+ // Maybe at some point we will eagerly parse named types, but for now we
+ // don't and this information is unavailable.
+ vec![]
+ }
+
+ fn num_self_template_params(&self, _ctx: &BindgenContext) -> usize {
+ // Wouldn't it be nice if libclang would reliably give us this
+ // information‽
+ match self.decl().kind() {
+ clang_sys::CXCursor_ClassTemplate |
+ clang_sys::CXCursor_FunctionTemplate |
+ clang_sys::CXCursor_TypeAliasTemplateDecl => {
+ let mut num_params = 0;
+ self.decl().visit(|c| {
+ match c.kind() {
+ clang_sys::CXCursor_TemplateTypeParameter |
+ clang_sys::CXCursor_TemplateTemplateParameter |
+ clang_sys::CXCursor_NonTypeTemplateParameter => {
+ num_params += 1;
+ }
+ _ => {}
+ };
+ clang_sys::CXChildVisit_Continue
+ });
+ num_params
+ }
+ _ => 0,
+ }
+ }
+}
+
+fn unused_regex_diagnostic(item: &str, name: &str, _ctx: &BindgenContext) {
+ warn!("unused option: {} {}", name, item);
+
+ #[cfg(feature = "experimental")]
+ if _ctx.options().emit_diagnostics {
+ use crate::diagnostics::{Diagnostic, Level};
+
+ Diagnostic::default()
+ .with_title(
+ format!("Unused regular expression: `{}`.", item),
+ Level::Warn,
+ )
+ .add_annotation(
+ format!("This regular expression was passed to `{}`.", name),
+ Level::Note,
+ )
+ .display();
+ }
+}
diff --git a/third_party/rust/bindgen/ir/derive.rs b/third_party/rust/bindgen/ir/derive.rs
new file mode 100644
index 0000000000..3877b42f8f
--- /dev/null
+++ b/third_party/rust/bindgen/ir/derive.rs
@@ -0,0 +1,135 @@
+//! Traits for determining whether we can derive traits for a thing or not.
+//!
+//! These traits tend to come in pairs:
+//!
+//! 1. A "trivial" version, whose implementations aren't allowed to recursively
+//! look at other types or the results of fix point analyses.
+//!
+//! 2. A "normal" version, whose implementations simply query the results of a
+//! fix point analysis.
+//!
+//! The former is used by the analyses when creating the results queried by the
+//! second.
+
+use super::context::BindgenContext;
+
+use std::cmp;
+use std::ops;
+
+/// A trait that encapsulates the logic for whether or not we can derive `Debug`
+/// for a given thing.
+pub(crate) trait CanDeriveDebug {
+ /// Return `true` if `Debug` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_derive_debug(&self, ctx: &BindgenContext) -> bool;
+}
+
+/// A trait that encapsulates the logic for whether or not we can derive `Copy`
+/// for a given thing.
+pub(crate) trait CanDeriveCopy {
+ /// Return `true` if `Copy` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_derive_copy(&self, ctx: &BindgenContext) -> bool;
+}
+
+/// A trait that encapsulates the logic for whether or not we can derive
+/// `Default` for a given thing.
+pub(crate) trait CanDeriveDefault {
+ /// Return `true` if `Default` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_derive_default(&self, ctx: &BindgenContext) -> bool;
+}
+
+/// A trait that encapsulates the logic for whether or not we can derive `Hash`
+/// for a given thing.
+pub(crate) trait CanDeriveHash {
+ /// Return `true` if `Hash` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_derive_hash(&self, ctx: &BindgenContext) -> bool;
+}
+
+/// A trait that encapsulates the logic for whether or not we can derive
+/// `PartialEq` for a given thing.
+pub(crate) trait CanDerivePartialEq {
+ /// Return `true` if `PartialEq` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool;
+}
+
+/// A trait that encapsulates the logic for whether or not we can derive
+/// `PartialOrd` for a given thing.
+pub(crate) trait CanDerivePartialOrd {
+ /// Return `true` if `PartialOrd` can be derived for this thing, `false`
+ /// otherwise.
+ fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool;
+}
+
+/// A trait that encapsulates the logic for whether or not we can derive `Eq`
+/// for a given thing.
+pub(crate) trait CanDeriveEq {
+ /// Return `true` if `Eq` can be derived for this thing, `false` otherwise.
+ fn can_derive_eq(&self, ctx: &BindgenContext) -> bool;
+}
+
+/// A trait that encapsulates the logic for whether or not we can derive `Ord`
+/// for a given thing.
+pub(crate) trait CanDeriveOrd {
+ /// Return `true` if `Ord` can be derived for this thing, `false` otherwise.
+ fn can_derive_ord(&self, ctx: &BindgenContext) -> bool;
+}
+
+/// Whether it is possible or not to automatically derive trait for an item.
+///
+/// ```ignore
+/// No
+/// ^
+/// |
+/// Manually
+/// ^
+/// |
+/// Yes
+/// ```
+///
+/// Initially we assume that we can derive trait for all types and then
+/// update our understanding as we learn more about each type.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+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(crate) fn join(self, rhs: Self) -> Self {
+ cmp::max(self, rhs)
+ }
+}
+
+impl ops::BitOr for CanDerive {
+ type Output = Self;
+
+ fn bitor(self, rhs: Self) -> Self::Output {
+ self.join(rhs)
+ }
+}
+
+impl ops::BitOrAssign for CanDerive {
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = self.join(rhs)
+ }
+}
diff --git a/third_party/rust/bindgen/ir/dot.rs b/third_party/rust/bindgen/ir/dot.rs
new file mode 100644
index 0000000000..d5c1a42fdc
--- /dev/null
+++ b/third_party/rust/bindgen/ir/dot.rs
@@ -0,0 +1,86 @@
+//! Generating Graphviz `dot` files from our IR.
+
+use super::context::{BindgenContext, ItemId};
+use super::traversal::Trace;
+use std::fs::File;
+use std::io::{self, Write};
+use std::path::Path;
+
+/// A trait for anything that can write attributes as `<table>` rows to a dot
+/// file.
+pub(crate) trait DotAttributes {
+ /// Write this thing's attributes to the given output. Each attribute must
+ /// be its own `<tr>...</tr>`.
+ fn dot_attributes<W>(
+ &self,
+ ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write;
+}
+
+/// Write a graphviz dot file containing our IR.
+pub(crate) fn write_dot_file<P>(ctx: &BindgenContext, path: P) -> io::Result<()>
+where
+ P: AsRef<Path>,
+{
+ let file = File::create(path)?;
+ let mut dot_file = io::BufWriter::new(file);
+ writeln!(&mut dot_file, "digraph {{")?;
+
+ let mut err: Option<io::Result<_>> = None;
+
+ for (id, item) in ctx.items() {
+ let is_allowlisted = ctx.allowlisted_items().contains(&id);
+
+ writeln!(
+ &mut dot_file,
+ r#"{} [fontname="courier", color={}, label=< <table border="0" align="left">"#,
+ id.as_usize(),
+ if is_allowlisted { "black" } else { "gray" }
+ )?;
+ item.dot_attributes(ctx, &mut dot_file)?;
+ writeln!(&mut dot_file, r#"</table> >];"#)?;
+
+ item.trace(
+ ctx,
+ &mut |sub_id: ItemId, edge_kind| {
+ if err.is_some() {
+ return;
+ }
+
+ match writeln!(
+ &mut dot_file,
+ "{} -> {} [label={:?}, color={}];",
+ id.as_usize(),
+ sub_id.as_usize(),
+ edge_kind,
+ if is_allowlisted { "black" } else { "gray" }
+ ) {
+ Ok(_) => {}
+ Err(e) => err = Some(Err(e)),
+ }
+ },
+ &(),
+ );
+
+ if let Some(err) = err {
+ return err;
+ }
+
+ if let Some(module) = item.as_module() {
+ for child in module.children() {
+ writeln!(
+ &mut dot_file,
+ "{} -> {} [style=dotted, color=gray]",
+ item.id().as_usize(),
+ child.as_usize()
+ )?;
+ }
+ }
+ }
+
+ writeln!(&mut dot_file, "}}")?;
+ Ok(())
+}
diff --git a/third_party/rust/bindgen/ir/enum_ty.rs b/third_party/rust/bindgen/ir/enum_ty.rs
new file mode 100644
index 0000000000..70cf0eae88
--- /dev/null
+++ b/third_party/rust/bindgen/ir/enum_ty.rs
@@ -0,0 +1,323 @@
+//! Intermediate representation for C/C++ enumerations.
+
+use super::super::codegen::EnumVariation;
+use super::context::{BindgenContext, TypeId};
+use super::item::Item;
+use super::ty::{Type, TypeKind};
+use crate::clang;
+use crate::ir::annotations::Annotations;
+use crate::parse::ParseError;
+use crate::regex_set::RegexSet;
+
+/// An enum representing custom handling that can be given to a variant.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum EnumVariantCustomBehavior {
+ /// This variant will be a module containing constants.
+ ModuleConstify,
+ /// This variant will be constified, that is, forced to generate a constant.
+ Constify,
+ /// This variant will be hidden entirely from the resulting enum.
+ Hide,
+}
+
+/// A C/C++ enumeration.
+#[derive(Debug)]
+pub(crate) struct Enum {
+ /// The representation used for this enum; it should be an `IntKind` type or
+ /// an alias to one.
+ ///
+ /// It's `None` if the enum is a forward declaration and isn't defined
+ /// anywhere else, see `tests/headers/func_ptr_in_struct.h`.
+ repr: Option<TypeId>,
+
+ /// The different variants, with explicit values.
+ variants: Vec<EnumVariant>,
+}
+
+impl Enum {
+ /// Construct a new `Enum` with the given representation and variants.
+ pub(crate) fn new(
+ repr: Option<TypeId>,
+ variants: Vec<EnumVariant>,
+ ) -> Self {
+ Enum { repr, variants }
+ }
+
+ /// Get this enumeration's representation.
+ pub(crate) fn repr(&self) -> Option<TypeId> {
+ self.repr
+ }
+
+ /// Get this enumeration's variants.
+ pub(crate) fn variants(&self) -> &[EnumVariant] {
+ &self.variants
+ }
+
+ /// Construct an enumeration from the given Clang type.
+ pub(crate) fn from_ty(
+ ty: &clang::Type,
+ ctx: &mut BindgenContext,
+ ) -> Result<Self, ParseError> {
+ use clang_sys::*;
+ debug!("Enum::from_ty {:?}", ty);
+
+ if ty.kind() != CXType_Enum {
+ return Err(ParseError::Continue);
+ }
+
+ let declaration = ty.declaration().canonical();
+ let repr = declaration
+ .enum_type()
+ .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok());
+ let mut variants = vec![];
+
+ let variant_ty =
+ repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx));
+ let is_bool = variant_ty.map_or(false, Type::is_bool);
+
+ // Assume signedness since the default type by the C standard is an int.
+ let is_signed = variant_ty.map_or(true, |ty| match *ty.kind() {
+ TypeKind::Int(ref int_kind) => int_kind.is_signed(),
+ ref other => {
+ panic!("Since when enums can be non-integers? {:?}", other)
+ }
+ });
+
+ let type_name = ty.spelling();
+ let type_name = if type_name.is_empty() {
+ None
+ } else {
+ Some(type_name)
+ };
+ let type_name = type_name.as_deref();
+
+ let definition = declaration.definition().unwrap_or(declaration);
+ definition.visit(|cursor| {
+ if cursor.kind() == CXCursor_EnumConstantDecl {
+ let value = if is_bool {
+ cursor.enum_val_boolean().map(EnumVariantValue::Boolean)
+ } else if is_signed {
+ cursor.enum_val_signed().map(EnumVariantValue::Signed)
+ } else {
+ cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned)
+ };
+ if let Some(val) = value {
+ let name = cursor.spelling();
+ let annotations = Annotations::new(&cursor);
+ let custom_behavior = ctx
+ .options()
+ .last_callback(|callbacks| {
+ callbacks
+ .enum_variant_behavior(type_name, &name, val)
+ })
+ .or_else(|| {
+ let annotations = annotations.as_ref()?;
+ if annotations.hide() {
+ Some(EnumVariantCustomBehavior::Hide)
+ } else if annotations.constify_enum_variant() {
+ Some(EnumVariantCustomBehavior::Constify)
+ } else {
+ None
+ }
+ });
+
+ let new_name = ctx
+ .options()
+ .last_callback(|callbacks| {
+ callbacks.enum_variant_name(type_name, &name, val)
+ })
+ .or_else(|| {
+ annotations
+ .as_ref()?
+ .use_instead_of()?
+ .last()
+ .cloned()
+ })
+ .unwrap_or_else(|| name.clone());
+
+ let comment = cursor.raw_comment();
+ variants.push(EnumVariant::new(
+ new_name,
+ name,
+ comment,
+ val,
+ custom_behavior,
+ ));
+ }
+ }
+ CXChildVisit_Continue
+ });
+ Ok(Enum::new(repr, variants))
+ }
+
+ fn is_matching_enum(
+ &self,
+ ctx: &BindgenContext,
+ enums: &RegexSet,
+ item: &Item,
+ ) -> bool {
+ let path = item.path_for_allowlisting(ctx);
+ let enum_ty = item.expect_type();
+
+ if enums.matches(path[1..].join("::")) {
+ return true;
+ }
+
+ // Test the variants if the enum is anonymous.
+ if enum_ty.name().is_some() {
+ return false;
+ }
+
+ self.variants().iter().any(|v| enums.matches(v.name()))
+ }
+
+ /// Returns the final representation of the enum.
+ pub(crate) fn computed_enum_variation(
+ &self,
+ ctx: &BindgenContext,
+ item: &Item,
+ ) -> EnumVariation {
+ // ModuleConsts has higher precedence before Rust in order to avoid
+ // problems with overlapping match patterns.
+ if self.is_matching_enum(
+ ctx,
+ &ctx.options().constified_enum_modules,
+ item,
+ ) {
+ EnumVariation::ModuleConsts
+ } else if self.is_matching_enum(
+ ctx,
+ &ctx.options().bitfield_enums,
+ item,
+ ) {
+ EnumVariation::NewType {
+ is_bitfield: true,
+ is_global: false,
+ }
+ } else if self.is_matching_enum(ctx, &ctx.options().newtype_enums, item)
+ {
+ EnumVariation::NewType {
+ is_bitfield: false,
+ is_global: false,
+ }
+ } else if self.is_matching_enum(
+ ctx,
+ &ctx.options().newtype_global_enums,
+ item,
+ ) {
+ EnumVariation::NewType {
+ is_bitfield: false,
+ is_global: true,
+ }
+ } else if self.is_matching_enum(
+ ctx,
+ &ctx.options().rustified_enums,
+ item,
+ ) {
+ EnumVariation::Rust {
+ non_exhaustive: false,
+ }
+ } else if self.is_matching_enum(
+ ctx,
+ &ctx.options().rustified_non_exhaustive_enums,
+ item,
+ ) {
+ EnumVariation::Rust {
+ non_exhaustive: true,
+ }
+ } else if self.is_matching_enum(
+ ctx,
+ &ctx.options().constified_enums,
+ item,
+ ) {
+ EnumVariation::Consts
+ } else {
+ ctx.options().default_enum_style
+ }
+ }
+}
+
+/// A single enum variant, to be contained only in an enum.
+#[derive(Debug)]
+pub(crate) struct EnumVariant {
+ /// The name of the variant.
+ name: String,
+
+ /// The original name of the variant (without user mangling)
+ name_for_allowlisting: String,
+
+ /// An optional doc comment.
+ comment: Option<String>,
+
+ /// The integer value of the variant.
+ val: EnumVariantValue,
+
+ /// The custom behavior this variant may have, if any.
+ custom_behavior: Option<EnumVariantCustomBehavior>,
+}
+
+/// A constant value assigned to an enumeration variant.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum EnumVariantValue {
+ /// A boolean constant.
+ Boolean(bool),
+
+ /// A signed constant.
+ Signed(i64),
+
+ /// An unsigned constant.
+ Unsigned(u64),
+}
+
+impl EnumVariant {
+ /// Construct a new enumeration variant from the given parts.
+ pub(crate) fn new(
+ name: String,
+ name_for_allowlisting: String,
+ comment: Option<String>,
+ val: EnumVariantValue,
+ custom_behavior: Option<EnumVariantCustomBehavior>,
+ ) -> Self {
+ EnumVariant {
+ name,
+ name_for_allowlisting,
+ comment,
+ val,
+ custom_behavior,
+ }
+ }
+
+ /// Get this variant's name.
+ pub(crate) fn name(&self) -> &str {
+ &self.name
+ }
+
+ /// Get this variant's name.
+ pub(crate) fn name_for_allowlisting(&self) -> &str {
+ &self.name_for_allowlisting
+ }
+
+ /// Get this variant's value.
+ pub(crate) fn val(&self) -> EnumVariantValue {
+ self.val
+ }
+
+ /// Get this variant's documentation.
+ pub(crate) fn comment(&self) -> Option<&str> {
+ self.comment.as_deref()
+ }
+
+ /// Returns whether this variant should be enforced to be a constant by code
+ /// generation.
+ pub(crate) fn force_constification(&self) -> bool {
+ self.custom_behavior
+ .map_or(false, |b| b == EnumVariantCustomBehavior::Constify)
+ }
+
+ /// Returns whether the current variant should be hidden completely from the
+ /// resulting rust enum.
+ pub(crate) fn hidden(&self) -> bool {
+ self.custom_behavior
+ .map_or(false, |b| b == EnumVariantCustomBehavior::Hide)
+ }
+}
diff --git a/third_party/rust/bindgen/ir/function.rs b/third_party/rust/bindgen/ir/function.rs
new file mode 100644
index 0000000000..448bcd22ea
--- /dev/null
+++ b/third_party/rust/bindgen/ir/function.rs
@@ -0,0 +1,839 @@
+//! Intermediate representation for C/C++ functions and methods.
+
+use super::comp::MethodKind;
+use super::context::{BindgenContext, TypeId};
+use super::dot::DotAttributes;
+use super::item::Item;
+use super::traversal::{EdgeKind, Trace, Tracer};
+use super::ty::TypeKind;
+use crate::callbacks::{ItemInfo, ItemKind};
+use crate::clang::{self, ABIKind, Attribute};
+use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
+use clang_sys::{self, CXCallingConv};
+
+use quote::TokenStreamExt;
+use std::io;
+use std::str::FromStr;
+
+const RUST_DERIVE_FUNPTR_LIMIT: usize = 12;
+
+/// What kind of a function are we looking at?
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub(crate) enum FunctionKind {
+ /// A plain, free function.
+ Function,
+ /// A method of some kind.
+ Method(MethodKind),
+}
+
+impl FunctionKind {
+ /// Given a clang cursor, return the kind of function it represents, or
+ /// `None` otherwise.
+ pub(crate) fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> {
+ // FIXME(emilio): Deduplicate logic with `ir::comp`.
+ Some(match cursor.kind() {
+ clang_sys::CXCursor_FunctionDecl => FunctionKind::Function,
+ clang_sys::CXCursor_Constructor => {
+ FunctionKind::Method(MethodKind::Constructor)
+ }
+ clang_sys::CXCursor_Destructor => {
+ FunctionKind::Method(if cursor.method_is_virtual() {
+ MethodKind::VirtualDestructor {
+ pure_virtual: cursor.method_is_pure_virtual(),
+ }
+ } else {
+ MethodKind::Destructor
+ })
+ }
+ clang_sys::CXCursor_CXXMethod => {
+ if cursor.method_is_virtual() {
+ FunctionKind::Method(MethodKind::Virtual {
+ pure_virtual: cursor.method_is_pure_virtual(),
+ })
+ } else if cursor.method_is_static() {
+ FunctionKind::Method(MethodKind::Static)
+ } else {
+ FunctionKind::Method(MethodKind::Normal)
+ }
+ }
+ _ => return None,
+ })
+ }
+}
+
+/// The style of linkage
+#[derive(Debug, Clone, Copy)]
+pub(crate) enum Linkage {
+ /// Externally visible and can be linked against
+ External,
+ /// Not exposed externally. 'static inline' functions will have this kind of linkage
+ Internal,
+}
+
+/// A function declaration, with a signature, arguments, and argument names.
+///
+/// The argument names vector must be the same length as the ones in the
+/// signature.
+#[derive(Debug)]
+pub(crate) struct Function {
+ /// The name of this function.
+ name: String,
+
+ /// The mangled name, that is, the symbol.
+ mangled_name: Option<String>,
+
+ /// The link name. If specified, overwrite mangled_name.
+ link_name: Option<String>,
+
+ /// The ID pointing to the current function signature.
+ signature: TypeId,
+
+ /// The kind of function this is.
+ kind: FunctionKind,
+
+ /// The linkage of the function.
+ linkage: Linkage,
+}
+
+impl Function {
+ /// Construct a new function.
+ pub(crate) fn new(
+ name: String,
+ mangled_name: Option<String>,
+ link_name: Option<String>,
+ signature: TypeId,
+ kind: FunctionKind,
+ linkage: Linkage,
+ ) -> Self {
+ Function {
+ name,
+ mangled_name,
+ link_name,
+ signature,
+ kind,
+ linkage,
+ }
+ }
+
+ /// Get this function's name.
+ pub(crate) fn name(&self) -> &str {
+ &self.name
+ }
+
+ /// Get this function's name.
+ pub(crate) fn mangled_name(&self) -> Option<&str> {
+ self.mangled_name.as_deref()
+ }
+
+ /// Get this function's link name.
+ pub fn link_name(&self) -> Option<&str> {
+ self.link_name.as_deref()
+ }
+
+ /// Get this function's signature type.
+ pub(crate) fn signature(&self) -> TypeId {
+ self.signature
+ }
+
+ /// Get this function's kind.
+ pub(crate) fn kind(&self) -> FunctionKind {
+ self.kind
+ }
+
+ /// Get this function's linkage.
+ pub(crate) fn linkage(&self) -> Linkage {
+ self.linkage
+ }
+}
+
+impl DotAttributes for Function {
+ fn dot_attributes<W>(
+ &self,
+ _ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ if let Some(ref mangled) = self.mangled_name {
+ let mangled: String =
+ mangled.chars().flat_map(|c| c.escape_default()).collect();
+ writeln!(
+ out,
+ "<tr><td>mangled name</td><td>{}</td></tr>",
+ mangled
+ )?;
+ }
+
+ Ok(())
+ }
+}
+
+/// A valid rust ABI.
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
+pub enum Abi {
+ /// The default C ABI.
+ C,
+ /// The "stdcall" ABI.
+ Stdcall,
+ /// The "efiapi" ABI.
+ EfiApi,
+ /// The "fastcall" ABI.
+ Fastcall,
+ /// The "thiscall" ABI.
+ ThisCall,
+ /// The "vectorcall" ABI.
+ Vectorcall,
+ /// The "aapcs" ABI.
+ Aapcs,
+ /// The "win64" ABI.
+ Win64,
+ /// The "C-unwind" ABI.
+ CUnwind,
+ /// The "system" ABI.
+ System,
+}
+
+impl FromStr for Abi {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "C" => Ok(Self::C),
+ "stdcall" => Ok(Self::Stdcall),
+ "efiapi" => Ok(Self::EfiApi),
+ "fastcall" => Ok(Self::Fastcall),
+ "thiscall" => Ok(Self::ThisCall),
+ "vectorcall" => Ok(Self::Vectorcall),
+ "aapcs" => Ok(Self::Aapcs),
+ "win64" => Ok(Self::Win64),
+ "C-unwind" => Ok(Self::CUnwind),
+ "system" => Ok(Self::System),
+ _ => Err(format!("Invalid or unknown ABI {:?}", s)),
+ }
+ }
+}
+
+impl std::fmt::Display for Abi {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let s = match *self {
+ Self::C => "C",
+ Self::Stdcall => "stdcall",
+ Self::EfiApi => "efiapi",
+ Self::Fastcall => "fastcall",
+ Self::ThisCall => "thiscall",
+ Self::Vectorcall => "vectorcall",
+ Self::Aapcs => "aapcs",
+ Self::Win64 => "win64",
+ Self::CUnwind => "C-unwind",
+ Abi::System => "system",
+ };
+
+ s.fmt(f)
+ }
+}
+
+impl quote::ToTokens for Abi {
+ fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
+ let abi = self.to_string();
+ tokens.append_all(quote! { #abi });
+ }
+}
+
+/// An ABI extracted from a clang cursor.
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum ClangAbi {
+ /// An ABI known by Rust.
+ Known(Abi),
+ /// An unknown or invalid ABI.
+ Unknown(CXCallingConv),
+}
+
+impl ClangAbi {
+ /// Returns whether this Abi is known or not.
+ fn is_unknown(&self) -> bool {
+ matches!(*self, ClangAbi::Unknown(..))
+ }
+}
+
+impl quote::ToTokens for ClangAbi {
+ fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
+ match *self {
+ Self::Known(abi) => abi.to_tokens(tokens),
+ Self::Unknown(cc) => panic!(
+ "Cannot turn unknown calling convention to tokens: {:?}",
+ cc
+ ),
+ }
+ }
+}
+
+/// A function signature.
+#[derive(Debug)]
+pub(crate) struct FunctionSig {
+ /// The name of this function signature.
+ name: String,
+
+ /// The return type of the function.
+ return_type: TypeId,
+
+ /// The type of the arguments, optionally with the name of the argument when
+ /// declared.
+ argument_types: Vec<(Option<String>, TypeId)>,
+
+ /// Whether this function is variadic.
+ is_variadic: bool,
+ is_divergent: bool,
+
+ /// Whether this function's return value must be used.
+ must_use: bool,
+
+ /// The ABI of this function.
+ abi: ClangAbi,
+}
+
+fn get_abi(cc: CXCallingConv) -> ClangAbi {
+ use clang_sys::*;
+ match cc {
+ CXCallingConv_Default => ClangAbi::Known(Abi::C),
+ CXCallingConv_C => ClangAbi::Known(Abi::C),
+ CXCallingConv_X86StdCall => ClangAbi::Known(Abi::Stdcall),
+ CXCallingConv_X86FastCall => ClangAbi::Known(Abi::Fastcall),
+ CXCallingConv_X86ThisCall => ClangAbi::Known(Abi::ThisCall),
+ CXCallingConv_X86VectorCall => ClangAbi::Known(Abi::Vectorcall),
+ CXCallingConv_AAPCS => ClangAbi::Known(Abi::Aapcs),
+ CXCallingConv_X86_64Win64 => ClangAbi::Known(Abi::Win64),
+ CXCallingConv_AArch64VectorCall => ClangAbi::Known(Abi::Vectorcall),
+ other => ClangAbi::Unknown(other),
+ }
+}
+
+/// Get the mangled name for the cursor's referent.
+pub(crate) fn cursor_mangling(
+ ctx: &BindgenContext,
+ cursor: &clang::Cursor,
+) -> Option<String> {
+ if !ctx.options().enable_mangling {
+ return None;
+ }
+
+ // We early return here because libclang may crash in some case
+ // if we pass in a variable inside a partial specialized template.
+ // See rust-lang/rust-bindgen#67, and rust-lang/rust-bindgen#462.
+ if cursor.is_in_non_fully_specialized_template() {
+ return None;
+ }
+
+ let is_itanium_abi = ctx.abi_kind() == ABIKind::GenericItanium;
+ let is_destructor = cursor.kind() == clang_sys::CXCursor_Destructor;
+ if let Ok(mut manglings) = cursor.cxx_manglings() {
+ while let Some(m) = manglings.pop() {
+ // Only generate the destructor group 1, see below.
+ if is_itanium_abi && is_destructor && !m.ends_with("D1Ev") {
+ continue;
+ }
+
+ return Some(m);
+ }
+ }
+
+ let mut mangling = cursor.mangling();
+ if mangling.is_empty() {
+ return None;
+ }
+
+ if is_itanium_abi && is_destructor {
+ // With old (3.8-) libclang versions, and the Itanium ABI, clang returns
+ // the "destructor group 0" symbol, which means that it'll try to free
+ // memory, which definitely isn't what we want.
+ //
+ // Explicitly force the destructor group 1 symbol.
+ //
+ // See http://refspecs.linuxbase.org/cxxabi-1.83.html#mangling-special
+ // for the reference, and http://stackoverflow.com/a/6614369/1091587 for
+ // a more friendly explanation.
+ //
+ // We don't need to do this for constructors since clang seems to always
+ // have returned the C1 constructor.
+ //
+ // FIXME(emilio): Can a legit symbol in other ABIs end with this string?
+ // I don't think so, but if it can this would become a linker error
+ // anyway, not an invalid free at runtime.
+ //
+ // TODO(emilio, #611): Use cpp_demangle if this becomes nastier with
+ // time.
+ if mangling.ends_with("D0Ev") {
+ let new_len = mangling.len() - 4;
+ mangling.truncate(new_len);
+ mangling.push_str("D1Ev");
+ }
+ }
+
+ Some(mangling)
+}
+
+fn args_from_ty_and_cursor(
+ ty: &clang::Type,
+ cursor: &clang::Cursor,
+ ctx: &mut BindgenContext,
+) -> Vec<(Option<String>, TypeId)> {
+ let cursor_args = cursor.args().unwrap_or_default().into_iter();
+ let type_args = ty.args().unwrap_or_default().into_iter();
+
+ // Argument types can be found in either the cursor or the type, but argument names may only be
+ // found on the cursor. We often have access to both a type and a cursor for each argument, but
+ // in some cases we may only have one.
+ //
+ // Prefer using the type as the source of truth for the argument's type, but fall back to
+ // inspecting the cursor (this happens for Objective C interfaces).
+ //
+ // Prefer using the cursor for the argument's type, but fall back to using the parent's cursor
+ // (this happens for function pointer return types).
+ cursor_args
+ .map(Some)
+ .chain(std::iter::repeat(None))
+ .zip(type_args.map(Some).chain(std::iter::repeat(None)))
+ .take_while(|(cur, ty)| cur.is_some() || ty.is_some())
+ .map(|(arg_cur, arg_ty)| {
+ let name = arg_cur.map(|a| a.spelling()).and_then(|name| {
+ if name.is_empty() {
+ None
+ } else {
+ Some(name)
+ }
+ });
+
+ let cursor = arg_cur.unwrap_or(*cursor);
+ let ty = arg_ty.unwrap_or_else(|| cursor.cur_type());
+ (name, Item::from_ty_or_ref(ty, cursor, None, ctx))
+ })
+ .collect()
+}
+
+impl FunctionSig {
+ /// Get the function name.
+ pub(crate) fn name(&self) -> &str {
+ &self.name
+ }
+
+ /// Construct a new function signature from the given Clang type.
+ pub(crate) fn from_ty(
+ ty: &clang::Type,
+ cursor: &clang::Cursor,
+ ctx: &mut BindgenContext,
+ ) -> Result<Self, ParseError> {
+ use clang_sys::*;
+ debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor);
+
+ // Skip function templates
+ let kind = cursor.kind();
+ if kind == CXCursor_FunctionTemplate {
+ return Err(ParseError::Continue);
+ }
+
+ let spelling = cursor.spelling();
+
+ // Don't parse operatorxx functions in C++
+ let is_operator = |spelling: &str| {
+ spelling.starts_with("operator") &&
+ !clang::is_valid_identifier(spelling)
+ };
+ if is_operator(&spelling) {
+ return Err(ParseError::Continue);
+ }
+
+ // Constructors of non-type template parameter classes for some reason
+ // include the template parameter in their name. Just skip them, since
+ // we don't handle well non-type template parameters anyway.
+ if (kind == CXCursor_Constructor || kind == CXCursor_Destructor) &&
+ spelling.contains('<')
+ {
+ return Err(ParseError::Continue);
+ }
+
+ let cursor = if cursor.is_valid() {
+ *cursor
+ } else {
+ ty.declaration()
+ };
+
+ let mut args = match kind {
+ CXCursor_FunctionDecl |
+ CXCursor_Constructor |
+ CXCursor_CXXMethod |
+ CXCursor_ObjCInstanceMethodDecl |
+ CXCursor_ObjCClassMethodDecl => {
+ args_from_ty_and_cursor(ty, &cursor, ctx)
+ }
+ _ => {
+ // For non-CXCursor_FunctionDecl, visiting the cursor's children
+ // is the only reliable way to get parameter names.
+ let mut args = vec![];
+ cursor.visit(|c| {
+ if c.kind() == CXCursor_ParmDecl {
+ let ty =
+ Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
+ let name = c.spelling();
+ let name =
+ if name.is_empty() { None } else { Some(name) };
+ args.push((name, ty));
+ }
+ CXChildVisit_Continue
+ });
+
+ if args.is_empty() {
+ // FIXME(emilio): Sometimes libclang doesn't expose the
+ // right AST for functions tagged as stdcall and such...
+ //
+ // https://bugs.llvm.org/show_bug.cgi?id=45919
+ args_from_ty_and_cursor(ty, &cursor, ctx)
+ } else {
+ args
+ }
+ }
+ };
+
+ let (must_use, mut is_divergent) =
+ if ctx.options().enable_function_attribute_detection {
+ let [must_use, no_return, no_return_cpp] = cursor.has_attrs(&[
+ Attribute::MUST_USE,
+ Attribute::NO_RETURN,
+ Attribute::NO_RETURN_CPP,
+ ]);
+ (must_use, no_return || no_return_cpp)
+ } else {
+ Default::default()
+ };
+
+ // Check if the type contains __attribute__((noreturn)) outside of parentheses. This is
+ // somewhat fragile, but it seems to be the only way to get at this information as of
+ // libclang 9.
+ let ty_spelling = ty.spelling();
+ let has_attribute_noreturn = ty_spelling
+ .match_indices("__attribute__((noreturn))")
+ .any(|(i, _)| {
+ let depth = ty_spelling[..i]
+ .bytes()
+ .filter_map(|ch| match ch {
+ b'(' => Some(1),
+ b')' => Some(-1),
+ _ => None,
+ })
+ .sum::<isize>();
+ depth == 0
+ });
+ is_divergent = is_divergent || has_attribute_noreturn;
+
+ let is_method = kind == CXCursor_CXXMethod;
+ let is_constructor = kind == CXCursor_Constructor;
+ let is_destructor = kind == CXCursor_Destructor;
+ if (is_constructor || is_destructor || is_method) &&
+ cursor.lexical_parent() != cursor.semantic_parent()
+ {
+ // Only parse constructors once.
+ return Err(ParseError::Continue);
+ }
+
+ if is_method || is_constructor || is_destructor {
+ let is_const = is_method && cursor.method_is_const();
+ let is_virtual = is_method && cursor.method_is_virtual();
+ let is_static = is_method && cursor.method_is_static();
+ if !is_static && !is_virtual {
+ let parent = cursor.semantic_parent();
+ let class = Item::parse(parent, None, ctx)
+ .expect("Expected to parse the class");
+ // The `class` most likely is not finished parsing yet, so use
+ // the unchecked variant.
+ let class = class.as_type_id_unchecked();
+
+ let class = if is_const {
+ let const_class_id = ctx.next_item_id();
+ ctx.build_const_wrapper(
+ const_class_id,
+ class,
+ None,
+ &parent.cur_type(),
+ )
+ } else {
+ class
+ };
+
+ let ptr =
+ Item::builtin_type(TypeKind::Pointer(class), false, ctx);
+ args.insert(0, (Some("this".into()), ptr));
+ } else if is_virtual {
+ let void = Item::builtin_type(TypeKind::Void, false, ctx);
+ let ptr =
+ Item::builtin_type(TypeKind::Pointer(void), false, ctx);
+ args.insert(0, (Some("this".into()), ptr));
+ }
+ }
+
+ let ty_ret_type = if kind == CXCursor_ObjCInstanceMethodDecl ||
+ kind == CXCursor_ObjCClassMethodDecl
+ {
+ ty.ret_type()
+ .or_else(|| cursor.ret_type())
+ .ok_or(ParseError::Continue)?
+ } else {
+ ty.ret_type().ok_or(ParseError::Continue)?
+ };
+
+ let ret = if is_constructor && ctx.is_target_wasm32() {
+ // Constructors in Clang wasm32 target return a pointer to the object
+ // being constructed.
+ let void = Item::builtin_type(TypeKind::Void, false, ctx);
+ Item::builtin_type(TypeKind::Pointer(void), false, ctx)
+ } else {
+ Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx)
+ };
+
+ // Clang plays with us at "find the calling convention", see #549 and
+ // co. This seems to be a better fix than that commit.
+ let mut call_conv = ty.call_conv();
+ if let Some(ty) = cursor.cur_type().canonical_type().pointee_type() {
+ let cursor_call_conv = ty.call_conv();
+ if cursor_call_conv != CXCallingConv_Invalid {
+ call_conv = cursor_call_conv;
+ }
+ }
+
+ let abi = get_abi(call_conv);
+
+ if abi.is_unknown() {
+ warn!("Unknown calling convention: {:?}", call_conv);
+ }
+
+ Ok(Self {
+ name: spelling,
+ return_type: ret,
+ argument_types: args,
+ is_variadic: ty.is_variadic(),
+ is_divergent,
+ must_use,
+ abi,
+ })
+ }
+
+ /// Get this function signature's return type.
+ pub(crate) fn return_type(&self) -> TypeId {
+ self.return_type
+ }
+
+ /// Get this function signature's argument (name, type) pairs.
+ pub(crate) fn argument_types(&self) -> &[(Option<String>, TypeId)] {
+ &self.argument_types
+ }
+
+ /// Get this function signature's ABI.
+ pub(crate) fn abi(
+ &self,
+ ctx: &BindgenContext,
+ name: Option<&str>,
+ ) -> crate::codegen::error::Result<ClangAbi> {
+ // FIXME (pvdrz): Try to do this check lazily instead. Maybe store the ABI inside `ctx`
+ // instead?.
+ let abi = if let Some(name) = name {
+ if let Some((abi, _)) = ctx
+ .options()
+ .abi_overrides
+ .iter()
+ .find(|(_, regex_set)| regex_set.matches(name))
+ {
+ ClangAbi::Known(*abi)
+ } else {
+ self.abi
+ }
+ } else if let Some((abi, _)) = ctx
+ .options()
+ .abi_overrides
+ .iter()
+ .find(|(_, regex_set)| regex_set.matches(&self.name))
+ {
+ ClangAbi::Known(*abi)
+ } else {
+ self.abi
+ };
+
+ match abi {
+ ClangAbi::Known(Abi::ThisCall)
+ if !ctx.options().rust_features().thiscall_abi =>
+ {
+ Err(crate::codegen::error::Error::UnsupportedAbi("thiscall"))
+ }
+ ClangAbi::Known(Abi::Vectorcall)
+ if !ctx.options().rust_features().vectorcall_abi =>
+ {
+ Err(crate::codegen::error::Error::UnsupportedAbi("vectorcall"))
+ }
+ ClangAbi::Known(Abi::CUnwind)
+ if !ctx.options().rust_features().c_unwind_abi =>
+ {
+ Err(crate::codegen::error::Error::UnsupportedAbi("C-unwind"))
+ }
+ ClangAbi::Known(Abi::EfiApi)
+ if !ctx.options().rust_features().abi_efiapi =>
+ {
+ Err(crate::codegen::error::Error::UnsupportedAbi("efiapi"))
+ }
+ ClangAbi::Known(Abi::Win64) if self.is_variadic() => {
+ Err(crate::codegen::error::Error::UnsupportedAbi("Win64"))
+ }
+ abi => Ok(abi),
+ }
+ }
+
+ /// Is this function signature variadic?
+ pub(crate) fn is_variadic(&self) -> bool {
+ // Clang reports some functions as variadic when they *might* be
+ // variadic. We do the argument check because rust doesn't codegen well
+ // variadic functions without an initial argument.
+ self.is_variadic && !self.argument_types.is_empty()
+ }
+
+ /// Must this function's return value be used?
+ pub(crate) fn must_use(&self) -> bool {
+ self.must_use
+ }
+
+ /// Are function pointers with this signature able to derive Rust traits?
+ /// Rust only supports deriving traits for function pointers with a limited
+ /// number of parameters and a couple ABIs.
+ ///
+ /// For more details, see:
+ ///
+ /// * <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(crate) fn function_pointers_can_derive(&self) -> bool {
+ if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT {
+ return false;
+ }
+
+ matches!(self.abi, ClangAbi::Known(Abi::C) | ClangAbi::Unknown(..))
+ }
+
+ /// Whether this function has attributes marking it as divergent.
+ pub(crate) fn is_divergent(&self) -> bool {
+ self.is_divergent
+ }
+}
+
+impl ClangSubItemParser for Function {
+ fn parse(
+ cursor: clang::Cursor,
+ context: &mut BindgenContext,
+ ) -> Result<ParseResult<Self>, ParseError> {
+ use clang_sys::*;
+
+ let kind = match FunctionKind::from_cursor(&cursor) {
+ None => return Err(ParseError::Continue),
+ Some(k) => k,
+ };
+
+ debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());
+ let visibility = cursor.visibility();
+ if visibility != CXVisibility_Default {
+ return Err(ParseError::Continue);
+ }
+
+ if cursor.access_specifier() == CX_CXXPrivate {
+ return Err(ParseError::Continue);
+ }
+
+ let linkage = cursor.linkage();
+ let linkage = match linkage {
+ CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External,
+ CXLinkage_Internal => Linkage::Internal,
+ _ => return Err(ParseError::Continue),
+ };
+
+ if cursor.is_inlined_function() ||
+ cursor
+ .definition()
+ .map_or(false, |x| x.is_inlined_function())
+ {
+ if !context.options().generate_inline_functions &&
+ !context.options().wrap_static_fns
+ {
+ return Err(ParseError::Continue);
+ }
+
+ if cursor.is_deleted_function() {
+ return Err(ParseError::Continue);
+ }
+
+ // We cannot handle `inline` functions that are not `static`.
+ if context.options().wrap_static_fns &&
+ cursor.is_inlined_function() &&
+ matches!(linkage, Linkage::External)
+ {
+ return Err(ParseError::Continue);
+ }
+ }
+
+ // Grab the signature using Item::from_ty.
+ let sig = Item::from_ty(&cursor.cur_type(), cursor, None, context)?;
+
+ let mut name = cursor.spelling();
+ assert!(!name.is_empty(), "Empty function name?");
+
+ if cursor.kind() == CXCursor_Destructor {
+ // Remove the leading `~`. The alternative to this is special-casing
+ // code-generation for destructor functions, which seems less than
+ // ideal.
+ if name.starts_with('~') {
+ name.remove(0);
+ }
+
+ // Add a suffix to avoid colliding with constructors. This would be
+ // technically fine (since we handle duplicated functions/methods),
+ // but seems easy enough to handle it here.
+ name.push_str("_destructor");
+ }
+ if let Some(nm) = context.options().last_callback(|callbacks| {
+ callbacks.generated_name_override(ItemInfo {
+ name: name.as_str(),
+ kind: ItemKind::Function,
+ })
+ }) {
+ name = nm;
+ }
+ assert!(!name.is_empty(), "Empty function name.");
+
+ let mangled_name = cursor_mangling(context, &cursor);
+
+ let link_name = context.options().last_callback(|callbacks| {
+ callbacks.generated_link_name_override(ItemInfo {
+ name: name.as_str(),
+ kind: ItemKind::Function,
+ })
+ });
+
+ let function = Self::new(
+ name.clone(),
+ mangled_name,
+ link_name,
+ sig,
+ kind,
+ linkage,
+ );
+
+ Ok(ParseResult::New(function, Some(cursor)))
+ }
+}
+
+impl Trace for FunctionSig {
+ type Extra = ();
+
+ fn trace<T>(&self, _: &BindgenContext, tracer: &mut T, _: &())
+ where
+ T: Tracer,
+ {
+ tracer.visit_kind(self.return_type().into(), EdgeKind::FunctionReturn);
+
+ for &(_, ty) in self.argument_types() {
+ tracer.visit_kind(ty.into(), EdgeKind::FunctionParameter);
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/ir/int.rs b/third_party/rust/bindgen/ir/int.rs
new file mode 100644
index 0000000000..4251b3753a
--- /dev/null
+++ b/third_party/rust/bindgen/ir/int.rs
@@ -0,0 +1,127 @@
+//! Intermediate representation for integral types.
+
+/// Which integral type are we dealing with?
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum IntKind {
+ /// A `bool`.
+ Bool,
+
+ /// A `signed char`.
+ SChar,
+
+ /// An `unsigned char`.
+ UChar,
+
+ /// A `wchar_t`.
+ WChar,
+
+ /// A platform-dependent `char` type, with the signedness support.
+ Char {
+ /// Whether the char is signed for the target platform.
+ is_signed: bool,
+ },
+
+ /// A `short`.
+ Short,
+
+ /// An `unsigned short`.
+ UShort,
+
+ /// An `int`.
+ Int,
+
+ /// An `unsigned int`.
+ UInt,
+
+ /// A `long`.
+ Long,
+
+ /// An `unsigned long`.
+ ULong,
+
+ /// A `long long`.
+ LongLong,
+
+ /// An `unsigned long long`.
+ ULongLong,
+
+ /// A 8-bit signed integer.
+ I8,
+
+ /// A 8-bit unsigned integer.
+ U8,
+
+ /// A 16-bit signed integer.
+ I16,
+
+ /// Either a `char16_t` or a `wchar_t`.
+ U16,
+
+ /// A 32-bit signed integer.
+ I32,
+
+ /// A 32-bit unsigned integer.
+ U32,
+
+ /// A 64-bit signed integer.
+ I64,
+
+ /// A 64-bit unsigned integer.
+ U64,
+
+ /// An `int128_t`
+ I128,
+
+ /// A `uint128_t`.
+ U128,
+
+ /// A custom integer type, used to allow custom macro types depending on
+ /// range.
+ Custom {
+ /// The name of the type, which would be used without modification.
+ name: &'static str,
+ /// Whether the type is signed or not.
+ is_signed: bool,
+ },
+}
+
+impl IntKind {
+ /// Is this integral type signed?
+ pub(crate) fn is_signed(&self) -> bool {
+ use self::IntKind::*;
+ match *self {
+ // TODO(emilio): wchar_t can in theory be signed, but we have no way
+ // to know whether it is or not right now (unlike char, there's no
+ // WChar_S / WChar_U).
+ Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 |
+ WChar | U32 | U64 | U128 => false,
+
+ SChar | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 |
+ I128 => true,
+
+ Char { is_signed } => is_signed,
+
+ Custom { is_signed, .. } => is_signed,
+ }
+ }
+
+ /// If this type has a known size, return it (in bytes). This is to
+ /// alleviate libclang sometimes not giving us a layout (like in the case
+ /// when an enum is defined inside a class with template parameters).
+ pub(crate) fn known_size(&self) -> Option<usize> {
+ use self::IntKind::*;
+ Some(match *self {
+ Bool | UChar | SChar | U8 | I8 | Char { .. } => 1,
+ U16 | I16 => 2,
+ U32 | I32 => 4,
+ U64 | I64 => 8,
+ I128 | U128 => 16,
+ _ => return None,
+ })
+ }
+
+ /// Whether this type's signedness matches the value.
+ pub(crate) fn signedness_matches(&self, val: i64) -> bool {
+ val >= 0 || self.is_signed()
+ }
+}
diff --git a/third_party/rust/bindgen/ir/item.rs b/third_party/rust/bindgen/ir/item.rs
new file mode 100644
index 0000000000..2941eb81e2
--- /dev/null
+++ b/third_party/rust/bindgen/ir/item.rs
@@ -0,0 +1,2034 @@
+//! Bindgen's core intermediate representation type.
+
+use super::super::codegen::{EnumVariation, CONSTIFIED_ENUM_MODULE_REPR_NAME};
+use super::analysis::{HasVtable, HasVtableResult, Sizedness, SizednessResult};
+use super::annotations::Annotations;
+use super::comp::{CompKind, MethodKind};
+use super::context::{BindgenContext, ItemId, PartialType, TypeId};
+use super::derive::{
+ CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq,
+ CanDeriveHash, CanDeriveOrd, CanDerivePartialEq, CanDerivePartialOrd,
+};
+use super::dot::DotAttributes;
+use super::function::{Function, FunctionKind};
+use super::item_kind::ItemKind;
+use super::layout::Opaque;
+use super::module::Module;
+use super::template::{AsTemplateParam, TemplateParameters};
+use super::traversal::{EdgeKind, Trace, Tracer};
+use super::ty::{Type, TypeKind};
+use crate::clang;
+use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
+
+use lazycell::LazyCell;
+
+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(crate) trait ItemCanonicalName {
+ /// Get the canonical name for this item.
+ fn canonical_name(&self, ctx: &BindgenContext) -> String;
+}
+
+/// The same, but specifies the path that needs to be followed to reach an item.
+///
+/// To contrast with canonical_name, here's an example:
+///
+/// ```c++
+/// namespace foo {
+/// const BAR = 3;
+/// }
+/// ```
+///
+/// For bar, the canonical path is `vec!["foo", "BAR"]`, while the canonical
+/// name is just `"BAR"`.
+pub(crate) trait ItemCanonicalPath {
+ /// Get the namespace-aware canonical path for this item. This means that if
+ /// namespaces are disabled, you'll get a single item, and otherwise you get
+ /// the whole path.
+ fn namespace_aware_canonical_path(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Vec<String>;
+
+ /// Get the canonical path for this item.
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String>;
+}
+
+/// A trait for determining if some IR thing is opaque or not.
+pub(crate) trait IsOpaque {
+ /// Extra context the IR thing needs to determine if it is opaque or not.
+ type Extra;
+
+ /// Returns `true` if the thing is opaque, and `false` otherwise.
+ ///
+ /// May only be called when `ctx` is in the codegen phase.
+ fn is_opaque(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool;
+}
+
+/// A trait for determining if some IR thing has type parameter in array or not.
+pub(crate) trait HasTypeParamInArray {
+ /// Returns `true` if the thing has Array, and `false` otherwise.
+ fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool;
+}
+
+/// A trait for determining if some IR thing has float or not.
+pub(crate) 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(crate) trait ItemAncestors {
+ /// Get an iterable over this item's ancestors.
+ fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a>;
+}
+
+#[cfg(feature = "__testing_only_extra_assertions")]
+type DebugOnlyItemSet = ItemSet;
+
+#[cfg(not(feature = "__testing_only_extra_assertions"))]
+struct DebugOnlyItemSet;
+
+#[cfg(not(feature = "__testing_only_extra_assertions"))]
+impl DebugOnlyItemSet {
+ fn new() -> Self {
+ DebugOnlyItemSet
+ }
+
+ fn contains(&self, _id: &ItemId) -> bool {
+ false
+ }
+
+ fn insert(&mut self, _id: ItemId) {}
+}
+
+/// An iterator over an item and its ancestors.
+pub(crate) struct ItemAncestorsIter<'a> {
+ item: ItemId,
+ ctx: &'a BindgenContext,
+ seen: DebugOnlyItemSet,
+}
+
+impl<'a> ItemAncestorsIter<'a> {
+ fn new<Id: Into<ItemId>>(ctx: &'a BindgenContext, id: Id) -> Self {
+ ItemAncestorsIter {
+ item: id.into(),
+ ctx,
+ seen: DebugOnlyItemSet::new(),
+ }
+ }
+}
+
+impl<'a> Iterator for ItemAncestorsIter<'a> {
+ type Item = ItemId;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let item = self.ctx.resolve_item(self.item);
+
+ if item.parent_id() == self.item {
+ None
+ } else {
+ self.item = item.parent_id();
+
+ extra_assert!(!self.seen.contains(&item.id()));
+ self.seen.insert(item.id());
+
+ Some(item.id())
+ }
+ }
+}
+
+impl<T> AsTemplateParam for T
+where
+ T: Copy + Into<ItemId>,
+{
+ type Extra = ();
+
+ fn as_template_param(
+ &self,
+ ctx: &BindgenContext,
+ _: &(),
+ ) -> Option<TypeId> {
+ ctx.resolve_item((*self).into()).as_template_param(ctx, &())
+ }
+}
+
+impl AsTemplateParam for Item {
+ type Extra = ();
+
+ fn as_template_param(
+ &self,
+ ctx: &BindgenContext,
+ _: &(),
+ ) -> Option<TypeId> {
+ self.kind.as_template_param(ctx, self)
+ }
+}
+
+impl AsTemplateParam for ItemKind {
+ type Extra = Item;
+
+ fn as_template_param(
+ &self,
+ ctx: &BindgenContext,
+ item: &Item,
+ ) -> Option<TypeId> {
+ match *self {
+ ItemKind::Type(ref ty) => ty.as_template_param(ctx, item),
+ ItemKind::Module(..) |
+ ItemKind::Function(..) |
+ ItemKind::Var(..) => None,
+ }
+ }
+}
+
+impl<T> ItemCanonicalName for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn canonical_name(&self, ctx: &BindgenContext) -> String {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.resolve_item(*self).canonical_name(ctx)
+ }
+}
+
+impl<T> ItemCanonicalPath for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn namespace_aware_canonical_path(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Vec<String> {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.resolve_item(*self).namespace_aware_canonical_path(ctx)
+ }
+
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.resolve_item(*self).canonical_path(ctx)
+ }
+}
+
+impl<T> ItemAncestors for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a> {
+ ItemAncestorsIter::new(ctx, *self)
+ }
+}
+
+impl ItemAncestors for Item {
+ fn ancestors<'a>(&self, ctx: &'a BindgenContext) -> ItemAncestorsIter<'a> {
+ self.id().ancestors(ctx)
+ }
+}
+
+impl<Id> Trace for Id
+where
+ Id: Copy + Into<ItemId>,
+{
+ type Extra = ();
+
+ fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, extra: &())
+ where
+ T: Tracer,
+ {
+ ctx.resolve_item(*self).trace(ctx, tracer, extra);
+ }
+}
+
+impl Trace for Item {
+ type Extra = ();
+
+ fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, _extra: &())
+ where
+ T: Tracer,
+ {
+ // Even if this item is blocklisted/hidden, we want to trace it. It is
+ // traversal iterators' consumers' responsibility to filter items as
+ // needed. Generally, this filtering happens in the implementation of
+ // `Iterator` for `allowlistedItems`. Fully tracing blocklisted items is
+ // necessary for things like the template parameter usage analysis to
+ // function correctly.
+
+ match *self.kind() {
+ ItemKind::Type(ref ty) => {
+ // There are some types, like resolved type references, where we
+ // don't want to stop collecting types even though they may be
+ // opaque.
+ if ty.should_be_traced_unconditionally() ||
+ !self.is_opaque(ctx, &())
+ {
+ ty.trace(ctx, tracer, self);
+ }
+ }
+ ItemKind::Function(ref fun) => {
+ // Just the same way, it has not real meaning for a function to
+ // be opaque, so we trace across it.
+ tracer.visit(fun.signature().into());
+ }
+ ItemKind::Var(ref var) => {
+ tracer.visit_kind(var.ty().into(), EdgeKind::VarType);
+ }
+ ItemKind::Module(_) => {
+ // Module -> children edges are "weak", and we do not want to
+ // trace them. If we did, then allowlisting wouldn't work as
+ // expected: everything in every module would end up
+ // allowlisted.
+ //
+ // TODO: make a new edge kind for module -> children edges and
+ // filter them during allowlisting traversals.
+ }
+ }
+ }
+}
+
+impl CanDeriveDebug for Item {
+ fn can_derive_debug(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_debug(ctx)
+ }
+}
+
+impl CanDeriveDefault for Item {
+ fn can_derive_default(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_default(ctx)
+ }
+}
+
+impl CanDeriveCopy for Item {
+ fn can_derive_copy(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_copy(ctx)
+ }
+}
+
+impl CanDeriveHash for Item {
+ fn can_derive_hash(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_hash(ctx)
+ }
+}
+
+impl CanDerivePartialOrd for Item {
+ fn can_derive_partialord(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_partialord(ctx)
+ }
+}
+
+impl CanDerivePartialEq for Item {
+ fn can_derive_partialeq(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_partialeq(ctx)
+ }
+}
+
+impl CanDeriveEq for Item {
+ fn can_derive_eq(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_eq(ctx)
+ }
+}
+
+impl CanDeriveOrd for Item {
+ fn can_derive_ord(&self, ctx: &BindgenContext) -> bool {
+ self.id().can_derive_ord(ctx)
+ }
+}
+
+/// An item is the base of the bindgen representation, it can be either a
+/// module, a type, a function, or a variable (see `ItemKind` for more
+/// information).
+///
+/// Items refer to each other by `ItemId`. Every item has its parent's
+/// ID. Depending on the kind of item this is, it may also refer to other items,
+/// such as a compound type item referring to other types. Collectively, these
+/// references form a graph.
+///
+/// The entry-point to this graph is the "root module": a meta-item used to hold
+/// all top-level items.
+///
+/// An item may have a comment, and annotations (see the `annotations` module).
+///
+/// Note that even though we parse all the types of annotations in comments, not
+/// all of them apply to every item. Those rules are described in the
+/// `annotations` module.
+#[derive(Debug)]
+pub(crate) struct Item {
+ /// This item's ID.
+ id: ItemId,
+
+ /// The item's local ID, unique only amongst its siblings. Only used for
+ /// anonymous items.
+ ///
+ /// Lazily initialized in local_id().
+ ///
+ /// Note that only structs, unions, and enums get a local type ID. In any
+ /// case this is an implementation detail.
+ local_id: LazyCell<usize>,
+
+ /// The next local ID to use for a child or template instantiation.
+ next_child_local_id: Cell<usize>,
+
+ /// A cached copy of the canonical name, as returned by `canonical_name`.
+ ///
+ /// This is a fairly used operation during codegen so this makes bindgen
+ /// considerably faster in those cases.
+ canonical_name: LazyCell<String>,
+
+ /// The path to use for allowlisting and other name-based checks, as
+ /// returned by `path_for_allowlisting`, lazily constructed.
+ path_for_allowlisting: LazyCell<Vec<String>>,
+
+ /// A doc comment over the item, if any.
+ comment: Option<String>,
+ /// Annotations extracted from the doc comment, or the default ones
+ /// otherwise.
+ annotations: Annotations,
+ /// An item's parent ID. This will most likely be a class where this item
+ /// was declared, or a module, etc.
+ ///
+ /// All the items have a parent, except the root module, in which case the
+ /// parent ID is its own ID.
+ parent_id: ItemId,
+ /// The item kind.
+ kind: ItemKind,
+ /// The source location of the item.
+ location: Option<clang::SourceLocation>,
+}
+
+impl AsRef<ItemId> for Item {
+ fn as_ref(&self) -> &ItemId {
+ &self.id
+ }
+}
+
+impl Item {
+ /// Construct a new `Item`.
+ pub(crate) fn new(
+ id: ItemId,
+ comment: Option<String>,
+ annotations: Option<Annotations>,
+ parent_id: ItemId,
+ kind: ItemKind,
+ location: Option<clang::SourceLocation>,
+ ) -> Self {
+ debug_assert!(id != parent_id || kind.is_module());
+ Item {
+ id,
+ local_id: LazyCell::new(),
+ next_child_local_id: Cell::new(1),
+ canonical_name: LazyCell::new(),
+ path_for_allowlisting: LazyCell::new(),
+ parent_id,
+ comment,
+ annotations: annotations.unwrap_or_default(),
+ kind,
+ location,
+ }
+ }
+
+ /// Construct a new opaque item type.
+ pub(crate) fn new_opaque_type(
+ with_id: ItemId,
+ ty: &clang::Type,
+ ctx: &mut BindgenContext,
+ ) -> TypeId {
+ let location = ty.declaration().location();
+ let ty = Opaque::from_clang_ty(ty, ctx);
+ let kind = ItemKind::Type(ty);
+ let parent = ctx.root_module().into();
+ ctx.add_item(
+ Item::new(with_id, None, None, parent, kind, Some(location)),
+ None,
+ None,
+ );
+ with_id.as_type_id_unchecked()
+ }
+
+ /// Get this `Item`'s identifier.
+ pub(crate) fn id(&self) -> ItemId {
+ self.id
+ }
+
+ /// Get this `Item`'s parent's identifier.
+ ///
+ /// For the root module, the parent's ID is its own ID.
+ pub(crate) fn parent_id(&self) -> ItemId {
+ self.parent_id
+ }
+
+ /// Set this item's parent ID.
+ ///
+ /// This is only used so replacements get generated in the proper module.
+ pub(crate) fn set_parent_for_replacement<Id: Into<ItemId>>(
+ &mut self,
+ id: Id,
+ ) {
+ self.parent_id = id.into();
+ }
+
+ /// Returns the depth this item is indented to.
+ ///
+ /// FIXME(emilio): This may need fixes for the enums within modules stuff.
+ pub(crate) fn codegen_depth(&self, ctx: &BindgenContext) -> usize {
+ if !ctx.options().enable_cxx_namespaces {
+ return 0;
+ }
+
+ self.ancestors(ctx)
+ .filter(|id| {
+ ctx.resolve_item(*id).as_module().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(crate) fn comment(&self, ctx: &BindgenContext) -> Option<String> {
+ if !ctx.options().generate_comments {
+ return None;
+ }
+
+ self.comment
+ .as_ref()
+ .map(|comment| ctx.options().process_comment(comment))
+ }
+
+ /// What kind of item is this?
+ pub(crate) fn kind(&self) -> &ItemKind {
+ &self.kind
+ }
+
+ /// Get a mutable reference to this item's kind.
+ pub(crate) fn kind_mut(&mut self) -> &mut ItemKind {
+ &mut self.kind
+ }
+
+ /// Where in the source is this item located?
+ pub(crate) fn location(&self) -> Option<&clang::SourceLocation> {
+ self.location.as_ref()
+ }
+
+ /// Get an identifier that differentiates this item from its siblings.
+ ///
+ /// This should stay relatively stable in the face of code motion outside or
+ /// below this item's lexical scope, meaning that this can be useful for
+ /// generating relatively stable identifiers within a scope.
+ pub(crate) fn local_id(&self, ctx: &BindgenContext) -> usize {
+ *self.local_id.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(crate) fn next_child_local_id(&self) -> usize {
+ let local_id = self.next_child_local_id.get();
+ self.next_child_local_id.set(local_id + 1);
+ local_id
+ }
+
+ /// Returns whether this item is a top-level item, from the point of view of
+ /// bindgen.
+ ///
+ /// This point of view changes depending on whether namespaces are enabled
+ /// or not. That way, in the following example:
+ ///
+ /// ```c++
+ /// namespace foo {
+ /// static int var;
+ /// }
+ /// ```
+ ///
+ /// `var` would be a toplevel item if namespaces are disabled, but won't if
+ /// they aren't.
+ ///
+ /// This function is used to determine when the codegen phase should call
+ /// `codegen` on an item, since any item that is not top-level will be
+ /// generated by its parent.
+ pub(crate) fn is_toplevel(&self, ctx: &BindgenContext) -> bool {
+ // FIXME: Workaround for some types falling behind when parsing weird
+ // stl classes, for example.
+ if ctx.options().enable_cxx_namespaces &&
+ self.kind().is_module() &&
+ self.id() != ctx.root_module()
+ {
+ return false;
+ }
+
+ let mut parent = self.parent_id;
+ loop {
+ let 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(crate) fn expect_type(&self) -> &Type {
+ self.kind().expect_type()
+ }
+
+ /// Get a reference to this item's underlying `Type`, or `None` if this is
+ /// some other kind of item.
+ pub(crate) fn as_type(&self) -> Option<&Type> {
+ self.kind().as_type()
+ }
+
+ /// Get a reference to this item's underlying `Function`. Panic if this is
+ /// some other kind of item.
+ pub(crate) fn expect_function(&self) -> &Function {
+ self.kind().expect_function()
+ }
+
+ /// Is this item a module?
+ pub(crate) fn is_module(&self) -> bool {
+ matches!(self.kind, ItemKind::Module(..))
+ }
+
+ /// Get this item's annotations.
+ pub(crate) fn annotations(&self) -> &Annotations {
+ &self.annotations
+ }
+
+ /// Whether this item should be blocklisted.
+ ///
+ /// This may be due to either annotations or to other kind of configuration.
+ pub(crate) fn is_blocklisted(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ if self.annotations.hide() {
+ return true;
+ }
+
+ if !ctx.options().blocklisted_files.is_empty() {
+ if let Some(location) = &self.location {
+ let (file, _, _, _) = location.location();
+ if let Some(filename) = file.name() {
+ if ctx.options().blocklisted_files.matches(filename) {
+ return true;
+ }
+ }
+ }
+ }
+
+ let path = self.path_for_allowlisting(ctx);
+ let name = path[1..].join("::");
+ ctx.options().blocklisted_items.matches(&name) ||
+ match self.kind {
+ ItemKind::Type(..) => {
+ ctx.options().blocklisted_types.matches(&name) ||
+ ctx.is_replaced_type(path, self.id)
+ }
+ ItemKind::Function(..) => {
+ ctx.options().blocklisted_functions.matches(&name)
+ }
+ ItemKind::Var(..) => {
+ ctx.options().blocklisted_vars.matches(&name)
+ }
+ // TODO: Add namespace blocklisting?
+ ItemKind::Module(..) => false,
+ }
+ }
+
+ /// Take out item NameOptions
+ pub(crate) fn name<'a>(
+ &'a self,
+ ctx: &'a BindgenContext,
+ ) -> NameOptions<'a> {
+ NameOptions::new(self, ctx)
+ }
+
+ /// Get the target item ID for name generation.
+ fn name_target(&self, ctx: &BindgenContext) -> ItemId {
+ let mut targets_seen = DebugOnlyItemSet::new();
+ let mut item = self;
+
+ loop {
+ extra_assert!(!targets_seen.contains(&item.id()));
+ targets_seen.insert(item.id());
+
+ if self.annotations().use_instead_of().is_some() {
+ return self.id();
+ }
+
+ match *item.kind() {
+ ItemKind::Type(ref ty) => match *ty.kind() {
+ TypeKind::ResolvedTypeRef(inner) => {
+ item = ctx.resolve_item(inner);
+ }
+ TypeKind::TemplateInstantiation(ref inst) => {
+ item = ctx.resolve_item(inst.template_definition());
+ }
+ _ => return item.id(),
+ },
+ _ => return item.id(),
+ }
+ }
+ }
+
+ /// Create a fully disambiguated name for an item, including template
+ /// parameters if it is a type
+ pub(crate) fn full_disambiguated_name(
+ &self,
+ ctx: &BindgenContext,
+ ) -> String {
+ let mut s = String::new();
+ let level = 0;
+ self.push_disambiguated_name(ctx, &mut s, level);
+ s
+ }
+
+ /// Helper function for full_disambiguated_name
+ fn push_disambiguated_name(
+ &self,
+ ctx: &BindgenContext,
+ to: &mut String,
+ level: u8,
+ ) {
+ to.push_str(&self.canonical_name(ctx));
+ if let ItemKind::Type(ref ty) = *self.kind() {
+ if let TypeKind::TemplateInstantiation(ref inst) = *ty.kind() {
+ to.push_str(&format!("_open{}_", level));
+ for arg in inst.template_arguments() {
+ arg.into_resolver()
+ .through_type_refs()
+ .resolve(ctx)
+ .push_disambiguated_name(ctx, to, level + 1);
+ to.push('_');
+ }
+ to.push_str(&format!("close{}", level));
+ }
+ }
+ }
+
+ /// Get this function item's name, or `None` if this item is not a function.
+ fn func_name(&self) -> Option<&str> {
+ match *self.kind() {
+ ItemKind::Function(ref func) => Some(func.name()),
+ _ => None,
+ }
+ }
+
+ /// Get the overload index for this method. If this is not a method, return
+ /// `None`.
+ fn overload_index(&self, ctx: &BindgenContext) -> Option<usize> {
+ self.func_name().and_then(|func_name| {
+ let parent = ctx.resolve_item(self.parent_id());
+ if let ItemKind::Type(ref ty) = *parent.kind() {
+ if let TypeKind::Comp(ref ci) = *ty.kind() {
+ // All the constructors have the same name, so no need to
+ // resolve and check.
+ return ci
+ .constructors()
+ .iter()
+ .position(|c| *c == self.id())
+ .or_else(|| {
+ ci.methods()
+ .iter()
+ .filter(|m| {
+ let item = ctx.resolve_item(m.signature());
+ let func = item.expect_function();
+ func.name() == func_name
+ })
+ .position(|m| m.signature() == self.id())
+ });
+ }
+ }
+
+ None
+ })
+ }
+
+ /// Get this item's base name (aka non-namespaced name).
+ fn base_name(&self, ctx: &BindgenContext) -> String {
+ if let Some(path) = self.annotations().use_instead_of() {
+ return path.last().unwrap().clone();
+ }
+
+ match *self.kind() {
+ ItemKind::Var(ref var) => var.name().to_owned(),
+ ItemKind::Module(ref module) => {
+ module.name().map(ToOwned::to_owned).unwrap_or_else(|| {
+ format!("_bindgen_mod_{}", self.exposed_id(ctx))
+ })
+ }
+ ItemKind::Type(ref ty) => {
+ ty.sanitized_name(ctx).map(Into::into).unwrap_or_else(|| {
+ format!("_bindgen_ty_{}", self.exposed_id(ctx))
+ })
+ }
+ ItemKind::Function(ref fun) => {
+ let mut name = fun.name().to_owned();
+
+ if let Some(idx) = self.overload_index(ctx) {
+ if idx > 0 {
+ write!(&mut name, "{}", idx).unwrap();
+ }
+ }
+
+ name
+ }
+ }
+ }
+
+ fn is_anon(&self) -> bool {
+ match self.kind() {
+ ItemKind::Module(module) => module.name().is_none(),
+ ItemKind::Type(ty) => ty.name().is_none(),
+ ItemKind::Function(_) => false,
+ ItemKind::Var(_) => false,
+ }
+ }
+
+ /// Get the canonical name without taking into account the replaces
+ /// annotation.
+ ///
+ /// This is the base logic used to implement hiding and replacing via
+ /// annotations, and also to implement proper name mangling.
+ ///
+ /// The idea is that each generated type in the same "level" (read: module
+ /// or namespace) has a unique canonical name.
+ ///
+ /// This name should be derived from the immutable state contained in the
+ /// type and the parent chain, since it should be consistent.
+ ///
+ /// If `BindgenOptions::disable_nested_struct_naming` is true then returned
+ /// name is the inner most non-anonymous name plus all the anonymous base names
+ /// that follows.
+ pub(crate) fn real_canonical_name(
+ &self,
+ ctx: &BindgenContext,
+ opt: &NameOptions,
+ ) -> String {
+ let target = ctx.resolve_item(self.name_target(ctx));
+
+ // Short-circuit if the target has an override, and just use that.
+ if let Some(path) = target.annotations.use_instead_of() {
+ if ctx.options().enable_cxx_namespaces {
+ return path.last().unwrap().clone();
+ }
+ return path.join("_");
+ }
+
+ let base_name = target.base_name(ctx);
+
+ // Named template type arguments are never namespaced, and never
+ // mangled.
+ if target.is_template_param(ctx, &()) {
+ return base_name;
+ }
+
+ // Ancestors' ID iter
+ let mut ids_iter = target
+ .parent_id()
+ .ancestors(ctx)
+ .filter(|id| *id != ctx.root_module())
+ .take_while(|id| {
+ // Stop iterating ancestors once we reach a non-inline namespace
+ // when opt.within_namespaces is set.
+ !opt.within_namespaces || !ctx.resolve_item(*id).is_module()
+ })
+ .filter(|id| {
+ if !ctx.options().conservative_inline_namespaces {
+ if let ItemKind::Module(ref module) =
+ *ctx.resolve_item(*id).kind()
+ {
+ return !module.is_inline();
+ }
+ }
+
+ true
+ });
+
+ let ids: Vec<_> = if ctx.options().disable_nested_struct_naming {
+ let mut ids = Vec::new();
+
+ // If target is anonymous we need find its first named ancestor.
+ if target.is_anon() {
+ for id in ids_iter.by_ref() {
+ ids.push(id);
+
+ if !ctx.resolve_item(id).is_anon() {
+ break;
+ }
+ }
+ }
+
+ ids
+ } else {
+ ids_iter.collect()
+ };
+
+ // Concatenate this item's ancestors' names together.
+ let mut names: Vec<_> = ids
+ .into_iter()
+ .map(|id| {
+ let item = ctx.resolve_item(id);
+ let target = ctx.resolve_item(item.name_target(ctx));
+ target.base_name(ctx)
+ })
+ .filter(|name| !name.is_empty())
+ .collect();
+
+ names.reverse();
+
+ if !base_name.is_empty() {
+ names.push(base_name);
+ }
+
+ if ctx.options().c_naming {
+ if let Some(prefix) = self.c_naming_prefix() {
+ names.insert(0, prefix.to_string());
+ }
+ }
+
+ let name = names.join("_");
+
+ let name = if opt.user_mangled == UserMangled::Yes {
+ ctx.options()
+ .last_callback(|callbacks| callbacks.item_name(&name))
+ .unwrap_or(name)
+ } else {
+ name
+ };
+
+ ctx.rust_mangle(&name).into_owned()
+ }
+
+ /// The exposed ID that represents an unique ID among the siblings of a
+ /// given item.
+ pub(crate) fn exposed_id(&self, ctx: &BindgenContext) -> String {
+ // Only use local ids for enums, classes, structs and union types. All
+ // other items use their global ID.
+ let ty_kind = self.kind().as_type().map(|t| t.kind());
+ if let Some(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(crate) fn as_module(&self) -> Option<&Module> {
+ match self.kind {
+ ItemKind::Module(ref module) => Some(module),
+ _ => None,
+ }
+ }
+
+ /// Get a mutable reference to this item's `Module`, or `None` if this is
+ /// not a `Module` item.
+ pub(crate) fn as_module_mut(&mut self) -> Option<&mut Module> {
+ match self.kind {
+ ItemKind::Module(ref mut module) => Some(module),
+ _ => None,
+ }
+ }
+
+ /// Returns whether the item is a constified module enum
+ fn is_constified_enum_module(&self, ctx: &BindgenContext) -> bool {
+ // Do not jump through aliases, except for aliases that point to a type
+ // with the same name, since we dont generate coe for them.
+ let item = self.id.into_resolver().through_type_refs().resolve(ctx);
+ let 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(crate) fn is_enabled_for_codegen(&self, ctx: &BindgenContext) -> bool {
+ let cc = &ctx.options().codegen_config;
+ match *self.kind() {
+ ItemKind::Module(..) => true,
+ ItemKind::Var(_) => cc.vars(),
+ ItemKind::Type(_) => cc.types(),
+ ItemKind::Function(ref f) => match f.kind() {
+ FunctionKind::Function => cc.functions(),
+ FunctionKind::Method(MethodKind::Constructor) => {
+ cc.constructors()
+ }
+ FunctionKind::Method(MethodKind::Destructor) |
+ FunctionKind::Method(MethodKind::VirtualDestructor {
+ ..
+ }) => cc.destructors(),
+ FunctionKind::Method(MethodKind::Static) |
+ FunctionKind::Method(MethodKind::Normal) |
+ FunctionKind::Method(MethodKind::Virtual { .. }) => {
+ cc.methods()
+ }
+ },
+ }
+ }
+
+ /// Returns the path we should use for allowlisting / blocklisting, which
+ /// doesn't include user-mangling.
+ pub(crate) fn path_for_allowlisting(
+ &self,
+ ctx: &BindgenContext,
+ ) -> &Vec<String> {
+ self.path_for_allowlisting
+ .borrow_with(|| self.compute_path(ctx, UserMangled::No))
+ }
+
+ fn compute_path(
+ &self,
+ ctx: &BindgenContext,
+ mangled: UserMangled,
+ ) -> Vec<String> {
+ if let Some(path) = self.annotations().use_instead_of() {
+ let mut ret =
+ vec![ctx.resolve_item(ctx.root_module()).name(ctx).get()];
+ ret.extend_from_slice(path);
+ return ret;
+ }
+
+ let target = ctx.resolve_item(self.name_target(ctx));
+ let mut path: Vec<_> = target
+ .ancestors(ctx)
+ .chain(iter::once(ctx.root_module().into()))
+ .map(|id| ctx.resolve_item(id))
+ .filter(|item| {
+ item.id() == target.id() ||
+ item.as_module().map_or(false, |module| {
+ !module.is_inline() ||
+ ctx.options().conservative_inline_namespaces
+ })
+ })
+ .map(|item| {
+ ctx.resolve_item(item.name_target(ctx))
+ .name(ctx)
+ .within_namespaces()
+ .user_mangled(mangled)
+ .get()
+ })
+ .collect();
+ path.reverse();
+ path
+ }
+
+ /// Returns a prefix for the canonical name when C naming is enabled.
+ fn c_naming_prefix(&self) -> Option<&str> {
+ let ty = match self.kind {
+ ItemKind::Type(ref ty) => ty,
+ _ => return None,
+ };
+
+ Some(match ty.kind() {
+ TypeKind::Comp(ref ci) => match ci.kind() {
+ CompKind::Struct => "struct",
+ CompKind::Union => "union",
+ },
+ TypeKind::Enum(..) => "enum",
+ _ => return None,
+ })
+ }
+
+ /// Whether this is a `#[must_use]` type.
+ pub(crate) fn must_use(&self, ctx: &BindgenContext) -> bool {
+ self.annotations().must_use_type() || ctx.must_use_type_by_name(self)
+ }
+}
+
+impl<T> IsOpaque for T
+where
+ T: Copy + Into<ItemId>,
+{
+ type Extra = ();
+
+ fn is_opaque(&self, ctx: &BindgenContext, _: &()) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.resolve_item((*self).into()).is_opaque(ctx, &())
+ }
+}
+
+impl IsOpaque for Item {
+ type Extra = ();
+
+ fn is_opaque(&self, ctx: &BindgenContext, _: &()) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ self.annotations.opaque() ||
+ self.as_type().map_or(false, |ty| ty.is_opaque(ctx, self)) ||
+ ctx.opaque_by_name(self.path_for_allowlisting(ctx))
+ }
+}
+
+impl<T> HasVtable for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn has_vtable(&self, ctx: &BindgenContext) -> bool {
+ let id: ItemId = (*self).into();
+ id.as_type_id(ctx).map_or(false, |id| {
+ !matches!(ctx.lookup_has_vtable(id), HasVtableResult::No)
+ })
+ }
+
+ fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool {
+ let id: ItemId = (*self).into();
+ id.as_type_id(ctx).map_or(false, |id| {
+ matches!(ctx.lookup_has_vtable(id), HasVtableResult::SelfHasVtable)
+ })
+ }
+}
+
+impl HasVtable for Item {
+ fn has_vtable(&self, ctx: &BindgenContext) -> bool {
+ self.id().has_vtable(ctx)
+ }
+
+ fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool {
+ self.id().has_vtable_ptr(ctx)
+ }
+}
+
+impl<T> Sizedness for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn sizedness(&self, ctx: &BindgenContext) -> SizednessResult {
+ let id: ItemId = (*self).into();
+ id.as_type_id(ctx)
+ .map_or(SizednessResult::default(), |id| ctx.lookup_sizedness(id))
+ }
+}
+
+impl Sizedness for Item {
+ fn sizedness(&self, ctx: &BindgenContext) -> SizednessResult {
+ self.id().sizedness(ctx)
+ }
+}
+
+impl<T> HasTypeParamInArray for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.lookup_has_type_param_in_array(*self)
+ }
+}
+
+impl HasTypeParamInArray for Item {
+ fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.lookup_has_type_param_in_array(self.id())
+ }
+}
+
+impl<T> HasFloat for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn has_float(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.lookup_has_float(*self)
+ }
+}
+
+impl HasFloat for Item {
+ fn has_float(&self, ctx: &BindgenContext) -> bool {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ ctx.lookup_has_float(self.id())
+ }
+}
+
+/// A set of items.
+pub(crate) type ItemSet = BTreeSet<ItemId>;
+
+impl DotAttributes for Item {
+ fn dot_attributes<W>(
+ &self,
+ ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ writeln!(
+ out,
+ "<tr><td>{:?}</td></tr>
+ <tr><td>name</td><td>{}</td></tr>",
+ self.id,
+ self.name(ctx).get()
+ )?;
+
+ if self.is_opaque(ctx, &()) {
+ writeln!(out, "<tr><td>opaque</td><td>true</td></tr>")?;
+ }
+
+ self.kind.dot_attributes(ctx, out)
+ }
+}
+
+impl<T> TemplateParameters for T
+where
+ T: Copy + Into<ItemId>,
+{
+ fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
+ ctx.resolve_item_fallible(*self)
+ .map_or(vec![], |item| item.self_template_params(ctx))
+ }
+}
+
+impl TemplateParameters for Item {
+ fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
+ self.kind.self_template_params(ctx)
+ }
+}
+
+impl TemplateParameters for ItemKind {
+ fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
+ match *self {
+ ItemKind::Type(ref ty) => ty.self_template_params(ctx),
+ // If we start emitting bindings to explicitly instantiated
+ // functions, then we'll need to check ItemKind::Function for
+ // template params.
+ ItemKind::Function(_) | ItemKind::Module(_) | ItemKind::Var(_) => {
+ vec![]
+ }
+ }
+ }
+}
+
+// An utility function to handle recursing inside nested types.
+fn visit_child(
+ cur: clang::Cursor,
+ id: ItemId,
+ ty: &clang::Type,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ result: &mut Result<TypeId, ParseError>,
+) -> clang_sys::CXChildVisitResult {
+ use clang_sys::*;
+ if result.is_ok() {
+ return CXChildVisit_Break;
+ }
+
+ *result = Item::from_ty_with_id(id, ty, cur, parent_id, ctx);
+
+ match *result {
+ Ok(..) => CXChildVisit_Break,
+ Err(ParseError::Recurse) => {
+ cur.visit(|c| visit_child(c, id, ty, parent_id, ctx, result));
+ CXChildVisit_Continue
+ }
+ Err(ParseError::Continue) => CXChildVisit_Continue,
+ }
+}
+
+impl Item {
+ /// Create a builtin type.
+ pub(crate) fn builtin_type(
+ kind: TypeKind,
+ is_const: bool,
+ ctx: &mut BindgenContext,
+ ) -> TypeId {
+ // Feel free to add more here, I'm just lazy.
+ match kind {
+ TypeKind::Void |
+ TypeKind::Int(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Float(..) => {}
+ _ => panic!("Unsupported builtin type"),
+ }
+
+ let ty = Type::new(None, None, kind, is_const);
+ let id = ctx.next_item_id();
+ let module = ctx.root_module().into();
+ ctx.add_item(
+ Item::new(id, None, None, module, ItemKind::Type(ty), None),
+ None,
+ None,
+ );
+ id.as_type_id_unchecked()
+ }
+
+ /// Parse this item from the given Clang cursor.
+ pub(crate) fn parse(
+ cursor: clang::Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ ) -> Result<ItemId, ParseError> {
+ use crate::ir::var::Var;
+ use clang_sys::*;
+
+ if !cursor.is_valid() {
+ return Err(ParseError::Continue);
+ }
+
+ let comment = cursor.raw_comment();
+ let annotations = Annotations::new(&cursor);
+
+ let current_module = ctx.current_module().into();
+ let relevant_parent_id = parent_id.unwrap_or(current_module);
+
+ #[allow(clippy::missing_docs_in_private_items)]
+ macro_rules! try_parse {
+ ($what:ident) => {
+ match $what::parse(cursor, ctx) {
+ Ok(ParseResult::New(item, declaration)) => {
+ let id = ctx.next_item_id();
+
+ ctx.add_item(
+ Item::new(
+ id,
+ comment,
+ annotations,
+ relevant_parent_id,
+ ItemKind::$what(item),
+ Some(cursor.location()),
+ ),
+ declaration,
+ Some(cursor),
+ );
+ return Ok(id);
+ }
+ Ok(ParseResult::AlreadyResolved(id)) => {
+ return Ok(id);
+ }
+ Err(ParseError::Recurse) => return Err(ParseError::Recurse),
+ Err(ParseError::Continue) => {}
+ }
+ };
+ }
+
+ try_parse!(Module);
+
+ // NOTE: Is extremely important to parse functions and vars **before**
+ // types. Otherwise we can parse a function declaration as a type
+ // (which is legal), and lose functions to generate.
+ //
+ // In general, I'm not totally confident this split between
+ // ItemKind::Function and TypeKind::FunctionSig is totally worth it, but
+ // I guess we can try.
+ try_parse!(Function);
+ try_parse!(Var);
+
+ // Types are sort of special, so to avoid parsing template classes
+ // twice, handle them separately.
+ {
+ let definition = cursor.definition();
+ let applicable_cursor = definition.unwrap_or(cursor);
+
+ let relevant_parent_id = match definition {
+ Some(definition) => {
+ if definition != cursor {
+ ctx.add_semantic_parent(definition, relevant_parent_id);
+ return Ok(Item::from_ty_or_ref(
+ applicable_cursor.cur_type(),
+ cursor,
+ parent_id,
+ ctx,
+ )
+ .into());
+ }
+ ctx.known_semantic_parent(definition)
+ .or(parent_id)
+ .unwrap_or_else(|| ctx.current_module().into())
+ }
+ None => relevant_parent_id,
+ };
+
+ match Item::from_ty(
+ &applicable_cursor.cur_type(),
+ applicable_cursor,
+ Some(relevant_parent_id),
+ ctx,
+ ) {
+ Ok(ty) => return Ok(ty.into()),
+ Err(ParseError::Recurse) => return Err(ParseError::Recurse),
+ Err(ParseError::Continue) => {}
+ }
+ }
+
+ match cursor.kind() {
+ // On Clang 18+, extern "C" is reported accurately as a LinkageSpec.
+ // Older LLVM treat it as UnexposedDecl.
+ CXCursor_LinkageSpec | CXCursor_UnexposedDecl => {
+ Err(ParseError::Recurse)
+ }
+
+ // We allowlist cursors here known to be unhandled, to prevent being
+ // too noisy about this.
+ CXCursor_MacroDefinition |
+ CXCursor_MacroExpansion |
+ CXCursor_UsingDeclaration |
+ CXCursor_UsingDirective |
+ CXCursor_StaticAssert |
+ CXCursor_FunctionTemplate => {
+ debug!(
+ "Unhandled cursor kind {:?}: {:?}",
+ cursor.kind(),
+ cursor
+ );
+ Err(ParseError::Continue)
+ }
+
+ CXCursor_InclusionDirective => {
+ let file = cursor.get_included_file_name();
+ match file {
+ None => {
+ warn!("Inclusion of a nameless file in {:?}", cursor);
+ }
+ Some(included_file) => {
+ for cb in &ctx.options().parse_callbacks {
+ cb.include_file(&included_file);
+ }
+
+ ctx.add_dep(included_file.into_boxed_str());
+ }
+ }
+ Err(ParseError::Continue)
+ }
+
+ _ => {
+ // ignore toplevel operator overloads
+ let spelling = cursor.spelling();
+ if !spelling.starts_with("operator") {
+ warn!(
+ "Unhandled cursor kind {:?}: {:?}",
+ cursor.kind(),
+ cursor
+ );
+ }
+ Err(ParseError::Continue)
+ }
+ }
+ }
+
+ /// Parse this item from the given Clang type, or if we haven't resolved all
+ /// the other items this one depends on, an unresolved reference.
+ pub(crate) fn from_ty_or_ref(
+ ty: clang::Type,
+ location: clang::Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ ) -> TypeId {
+ let id = ctx.next_item_id();
+ Self::from_ty_or_ref_with_id(id, ty, location, parent_id, ctx)
+ }
+
+ /// Parse a C++ type. If we find a reference to a type that has not been
+ /// defined yet, use `UnresolvedTypeRef` as a placeholder.
+ ///
+ /// This logic is needed to avoid parsing items with the incorrect parent
+ /// and it's sort of complex to explain, so I'll just point to
+ /// `tests/headers/typeref.hpp` to see the kind of constructs that forced
+ /// this.
+ ///
+ /// Typerefs are resolved once parsing is completely done, see
+ /// `BindgenContext::resolve_typerefs`.
+ pub(crate) fn from_ty_or_ref_with_id(
+ potential_id: ItemId,
+ ty: clang::Type,
+ location: clang::Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ ) -> TypeId {
+ debug!(
+ "from_ty_or_ref_with_id: {:?} {:?}, {:?}, {:?}",
+ potential_id, ty, location, parent_id
+ );
+
+ if ctx.collected_typerefs() {
+ debug!("refs already collected, resolving directly");
+ return Item::from_ty_with_id(
+ potential_id,
+ &ty,
+ location,
+ parent_id,
+ ctx,
+ )
+ .unwrap_or_else(|_| Item::new_opaque_type(potential_id, &ty, ctx));
+ }
+
+ if let Some(ty) = ctx.builtin_or_resolved_ty(
+ potential_id,
+ parent_id,
+ &ty,
+ Some(location),
+ ) {
+ debug!("{:?} already resolved: {:?}", ty, location);
+ return ty;
+ }
+
+ debug!("New unresolved type reference: {:?}, {:?}", ty, location);
+
+ let is_const = ty.is_const();
+ let kind = TypeKind::UnresolvedTypeRef(ty, location, parent_id);
+ let current_module = ctx.current_module();
+
+ ctx.add_item(
+ Item::new(
+ potential_id,
+ None,
+ None,
+ parent_id.unwrap_or_else(|| current_module.into()),
+ ItemKind::Type(Type::new(None, None, kind, is_const)),
+ Some(location.location()),
+ ),
+ None,
+ None,
+ );
+ potential_id.as_type_id_unchecked()
+ }
+
+ /// Parse this item from the given Clang type. See [`Item::from_ty_with_id`].
+ pub(crate) fn from_ty(
+ ty: &clang::Type,
+ location: clang::Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ ) -> Result<TypeId, ParseError> {
+ let id = ctx.next_item_id();
+ Item::from_ty_with_id(id, ty, location, parent_id, ctx)
+ }
+
+ /// This is one of the trickiest methods you'll find (probably along with
+ /// some of the ones that handle templates in `BindgenContext`).
+ ///
+ /// This method parses a type, given the potential ID of that type (if
+ /// parsing it was correct), an optional location we're scanning, which is
+ /// critical some times to obtain information, an optional parent item ID,
+ /// that will, if it's `None`, become the current module ID, and the
+ /// context.
+ pub(crate) fn from_ty_with_id(
+ id: ItemId,
+ ty: &clang::Type,
+ location: clang::Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ ) -> Result<TypeId, ParseError> {
+ use clang_sys::*;
+
+ debug!(
+ "Item::from_ty_with_id: {:?}\n\
+ \tty = {:?},\n\
+ \tlocation = {:?}",
+ id, ty, location
+ );
+
+ if ty.kind() == clang_sys::CXType_Unexposed ||
+ location.cur_type().kind() == clang_sys::CXType_Unexposed
+ {
+ if ty.is_associated_type() ||
+ location.cur_type().is_associated_type()
+ {
+ return Ok(Item::new_opaque_type(id, ty, ctx));
+ }
+
+ if let Some(param_id) = Item::type_param(None, location, ctx) {
+ return Ok(ctx.build_ty_wrapper(id, param_id, None, ty));
+ }
+ }
+
+ // Treat all types that are declared inside functions as opaque. The Rust binding
+ // won't be able to do anything with them anyway.
+ //
+ // (If we don't do this check here, we can have subtle logic bugs because we generally
+ // ignore function bodies. See issue #2036.)
+ if let Some(ref parent) = ty.declaration().fallible_semantic_parent() {
+ if FunctionKind::from_cursor(parent).is_some() {
+ debug!("Skipping type declared inside function: {:?}", ty);
+ return Ok(Item::new_opaque_type(id, ty, ctx));
+ }
+ }
+
+ let decl = {
+ let canonical_def = ty.canonical_type().declaration().definition();
+ canonical_def.unwrap_or_else(|| ty.declaration())
+ };
+
+ let comment = location
+ .raw_comment()
+ .or_else(|| decl.raw_comment())
+ .or_else(|| location.raw_comment());
+
+ let annotations =
+ Annotations::new(&decl).or_else(|| Annotations::new(&location));
+
+ if let Some(ref annotations) = annotations {
+ if let Some(replaced) = annotations.use_instead_of() {
+ ctx.replace(replaced, id);
+ }
+ }
+
+ if let Some(ty) =
+ ctx.builtin_or_resolved_ty(id, parent_id, ty, Some(location))
+ {
+ return Ok(ty);
+ }
+
+ // First, check we're not recursing.
+ let mut valid_decl = decl.kind() != CXCursor_NoDeclFound;
+ let declaration_to_look_for = if valid_decl {
+ decl.canonical()
+ } else if location.kind() == CXCursor_ClassTemplate {
+ valid_decl = true;
+ location
+ } else {
+ decl
+ };
+
+ if valid_decl {
+ if let Some(partial) = ctx
+ .currently_parsed_types()
+ .iter()
+ .find(|ty| *ty.decl() == declaration_to_look_for)
+ {
+ debug!("Avoiding recursion parsing type: {:?}", ty);
+ // Unchecked because we haven't finished this type yet.
+ return Ok(partial.id().as_type_id_unchecked());
+ }
+ }
+
+ let current_module = ctx.current_module().into();
+ let partial_ty = PartialType::new(declaration_to_look_for, id);
+ if valid_decl {
+ ctx.begin_parsing(partial_ty);
+ }
+
+ let result = Type::from_clang_ty(id, ty, location, parent_id, ctx);
+ let relevant_parent_id = parent_id.unwrap_or(current_module);
+ let ret = match result {
+ Ok(ParseResult::AlreadyResolved(ty)) => {
+ Ok(ty.as_type_id_unchecked())
+ }
+ Ok(ParseResult::New(item, declaration)) => {
+ ctx.add_item(
+ Item::new(
+ id,
+ comment,
+ annotations,
+ relevant_parent_id,
+ ItemKind::Type(item),
+ Some(location.location()),
+ ),
+ declaration,
+ Some(location),
+ );
+ Ok(id.as_type_id_unchecked())
+ }
+ Err(ParseError::Continue) => Err(ParseError::Continue),
+ Err(ParseError::Recurse) => {
+ debug!("Item::from_ty recursing in the ast");
+ let mut result = Err(ParseError::Recurse);
+
+ // Need to pop here, otherwise we'll get stuck.
+ //
+ // TODO: Find a nicer interface, really. Also, the
+ // declaration_to_look_for suspiciously shares a lot of
+ // logic with ir::context, so we should refactor that.
+ if valid_decl {
+ let finished = ctx.finish_parsing();
+ assert_eq!(*finished.decl(), declaration_to_look_for);
+ }
+
+ location.visit(|cur| {
+ visit_child(cur, id, ty, parent_id, ctx, &mut result)
+ });
+
+ if valid_decl {
+ let partial_ty =
+ PartialType::new(declaration_to_look_for, id);
+ ctx.begin_parsing(partial_ty);
+ }
+
+ // If we have recursed into the AST all we know, and we still
+ // haven't found what we've got, let's just try and make a named
+ // type.
+ //
+ // This is what happens with some template members, for example.
+ if let Err(ParseError::Recurse) = result {
+ warn!(
+ "Unknown type, assuming named template type: \
+ id = {:?}; spelling = {}",
+ id,
+ ty.spelling()
+ );
+ Item::type_param(Some(id), location, ctx)
+ .map(Ok)
+ .unwrap_or(Err(ParseError::Recurse))
+ } else {
+ result
+ }
+ }
+ };
+
+ if valid_decl {
+ let partial_ty = ctx.finish_parsing();
+ assert_eq!(*partial_ty.decl(), declaration_to_look_for);
+ }
+
+ ret
+ }
+
+ /// A named type is a template parameter, e.g., the `T` in `Foo<T>`. They're always local so
+ /// it's the only exception when there's no declaration for a type.
+ pub(crate) fn type_param(
+ with_id: Option<ItemId>,
+ location: clang::Cursor,
+ ctx: &mut BindgenContext,
+ ) -> Option<TypeId> {
+ let ty = location.cur_type();
+
+ debug!(
+ "Item::type_param:\n\
+ \twith_id = {:?},\n\
+ \tty = {} {:?},\n\
+ \tlocation: {:?}",
+ with_id,
+ ty.spelling(),
+ ty,
+ location
+ );
+
+ if ty.kind() != clang_sys::CXType_Unexposed {
+ // If the given cursor's type's kind is not Unexposed, then we
+ // aren't looking at a template parameter. This check may need to be
+ // updated in the future if they start properly exposing template
+ // type parameters.
+ return None;
+ }
+
+ let ty_spelling = ty.spelling();
+
+ // Clang does not expose any information about template type parameters
+ // via their clang::Type, nor does it give us their canonical cursors
+ // the straightforward way. However, there are three situations from
+ // which we can find the definition of the template type parameter, if
+ // the cursor is indeed looking at some kind of a template type
+ // parameter or use of one:
+ //
+ // 1. The cursor is pointing at the template type parameter's
+ // definition. This is the trivial case.
+ //
+ // (kind = TemplateTypeParameter, ...)
+ //
+ // 2. The cursor is pointing at a TypeRef whose referenced() cursor is
+ // situation (1).
+ //
+ // (kind = TypeRef,
+ // referenced = (kind = TemplateTypeParameter, ...),
+ // ...)
+ //
+ // 3. The cursor is pointing at some use of a template type parameter
+ // (for example, in a FieldDecl), and this cursor has a child cursor
+ // whose spelling is the same as the parent's type's spelling, and whose
+ // kind is a TypeRef of the situation (2) variety.
+ //
+ // (kind = FieldDecl,
+ // type = (kind = Unexposed,
+ // spelling = "T",
+ // ...),
+ // children =
+ // (kind = TypeRef,
+ // spelling = "T",
+ // referenced = (kind = TemplateTypeParameter,
+ // spelling = "T",
+ // ...),
+ // ...)
+ // ...)
+ //
+ // TODO: The alternative to this hacky pattern matching would be to
+ // maintain proper scopes of template parameters while parsing and use
+ // de Brujin indices to access template parameters, which clang exposes
+ // in the cursor's type's canonical type's spelling:
+ // "type-parameter-x-y". That is probably a better approach long-term,
+ // but maintaining these scopes properly would require more changes to
+ // the whole libclang -> IR parsing code.
+
+ fn is_template_with_spelling(
+ refd: &clang::Cursor,
+ spelling: &str,
+ ) -> bool {
+ lazy_static! {
+ static ref ANON_TYPE_PARAM_RE: regex::Regex =
+ regex::Regex::new(r"^type\-parameter\-\d+\-\d+$").unwrap();
+ }
+
+ if refd.kind() != clang_sys::CXCursor_TemplateTypeParameter {
+ return false;
+ }
+
+ let refd_spelling = refd.spelling();
+ refd_spelling == spelling ||
+ // Allow for anonymous template parameters.
+ (refd_spelling.is_empty() && ANON_TYPE_PARAM_RE.is_match(spelling.as_ref()))
+ }
+
+ let definition = if is_template_with_spelling(&location, &ty_spelling) {
+ // Situation (1)
+ location
+ } else if location.kind() == clang_sys::CXCursor_TypeRef {
+ // Situation (2)
+ match location.referenced() {
+ Some(refd)
+ if is_template_with_spelling(&refd, &ty_spelling) =>
+ {
+ refd
+ }
+ _ => return None,
+ }
+ } else {
+ // Situation (3)
+ let mut definition = None;
+
+ location.visit(|child| {
+ let child_ty = child.cur_type();
+ if child_ty.kind() == clang_sys::CXCursor_TypeRef &&
+ child_ty.spelling() == ty_spelling
+ {
+ match child.referenced() {
+ Some(refd)
+ if is_template_with_spelling(
+ &refd,
+ &ty_spelling,
+ ) =>
+ {
+ definition = Some(refd);
+ return clang_sys::CXChildVisit_Break;
+ }
+ _ => {}
+ }
+ }
+
+ clang_sys::CXChildVisit_Continue
+ });
+
+ definition?
+ };
+ assert!(is_template_with_spelling(&definition, &ty_spelling));
+
+ // Named types are always parented to the root module. They are never
+ // referenced with namespace prefixes, and they can't inherit anything
+ // from their parent either, so it is simplest to just hang them off
+ // something we know will always exist.
+ let parent = ctx.root_module().into();
+
+ if let Some(id) = ctx.get_type_param(&definition) {
+ if let Some(with_id) = with_id {
+ return Some(ctx.build_ty_wrapper(
+ with_id,
+ id,
+ Some(parent),
+ &ty,
+ ));
+ } else {
+ return Some(id);
+ }
+ }
+
+ // See tests/headers/const_tparam.hpp and
+ // tests/headers/variadic_tname.hpp.
+ let name = ty_spelling.replace("const ", "").replace('.', "");
+
+ let id = with_id.unwrap_or_else(|| ctx.next_item_id());
+ let item = Item::new(
+ id,
+ None,
+ None,
+ parent,
+ ItemKind::Type(Type::named(name)),
+ Some(location.location()),
+ );
+ ctx.add_type_param(item, definition);
+ Some(id.as_type_id_unchecked())
+ }
+}
+
+impl ItemCanonicalName for Item {
+ fn canonical_name(&self, ctx: &BindgenContext) -> String {
+ debug_assert!(
+ ctx.in_codegen_phase(),
+ "You're not supposed to call this yet"
+ );
+ self.canonical_name
+ .borrow_with(|| {
+ let in_namespace = ctx.options().enable_cxx_namespaces ||
+ ctx.options().disable_name_namespacing;
+
+ if in_namespace {
+ self.name(ctx).within_namespaces().get()
+ } else {
+ self.name(ctx).get()
+ }
+ })
+ .clone()
+ }
+}
+
+impl ItemCanonicalPath for Item {
+ fn namespace_aware_canonical_path(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Vec<String> {
+ let mut path = self.canonical_path(ctx);
+
+ // ASSUMPTION: (disable_name_namespacing && cxx_namespaces)
+ // is equivalent to
+ // disable_name_namespacing
+ if ctx.options().disable_name_namespacing {
+ // Only keep the last item in path
+ let split_idx = path.len() - 1;
+ path = path.split_off(split_idx);
+ } else if !ctx.options().enable_cxx_namespaces {
+ // Ignore first item "root"
+ path = vec![path[1..].join("_")];
+ }
+
+ if self.is_constified_enum_module(ctx) {
+ path.push(CONSTIFIED_ENUM_MODULE_REPR_NAME.into());
+ }
+
+ path
+ }
+
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
+ self.compute_path(ctx, UserMangled::Yes)
+ }
+}
+
+/// Whether to use the user-mangled name (mangled by the `item_name` callback or
+/// not.
+///
+/// Most of the callers probably want just yes, but the ones dealing with
+/// allowlisting and blocklisting don't.
+#[derive(Copy, Clone, Debug, PartialEq)]
+enum UserMangled {
+ No,
+ Yes,
+}
+
+/// Builder struct for naming variations, which hold inside different
+/// flags for naming options.
+#[derive(Debug)]
+pub(crate) struct NameOptions<'a> {
+ item: &'a Item,
+ ctx: &'a BindgenContext,
+ within_namespaces: bool,
+ user_mangled: UserMangled,
+}
+
+impl<'a> NameOptions<'a> {
+ /// Construct a new `NameOptions`
+ pub(crate) fn new(item: &'a Item, ctx: &'a BindgenContext) -> Self {
+ NameOptions {
+ item,
+ ctx,
+ within_namespaces: false,
+ user_mangled: UserMangled::Yes,
+ }
+ }
+
+ /// Construct the name without the item's containing C++ namespaces mangled
+ /// into it. In other words, the item's name within the item's namespace.
+ pub(crate) fn within_namespaces(&mut self) -> &mut Self {
+ self.within_namespaces = true;
+ self
+ }
+
+ fn user_mangled(&mut self, user_mangled: UserMangled) -> &mut Self {
+ self.user_mangled = user_mangled;
+ self
+ }
+
+ /// Construct a name `String`
+ pub(crate) fn get(&self) -> String {
+ self.item.real_canonical_name(self.ctx, self)
+ }
+}
diff --git a/third_party/rust/bindgen/ir/item_kind.rs b/third_party/rust/bindgen/ir/item_kind.rs
new file mode 100644
index 0000000000..e8618498ad
--- /dev/null
+++ b/third_party/rust/bindgen/ir/item_kind.rs
@@ -0,0 +1,135 @@
+//! Different variants of an `Item` in our intermediate representation.
+
+use super::context::BindgenContext;
+use super::dot::DotAttributes;
+use super::function::Function;
+use super::module::Module;
+use super::ty::Type;
+use super::var::Var;
+use std::io;
+
+/// A item we parse and translate.
+#[derive(Debug)]
+pub(crate) enum ItemKind {
+ /// A module, created implicitly once (the root module), or via C++
+ /// namespaces.
+ Module(Module),
+
+ /// A type declared in any of the multiple ways it can be declared.
+ Type(Type),
+
+ /// A function or method declaration.
+ Function(Function),
+
+ /// A variable declaration, most likely a static.
+ Var(Var),
+}
+
+impl ItemKind {
+ /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it
+ /// is some other kind.
+ pub(crate) fn as_module(&self) -> Option<&Module> {
+ match *self {
+ ItemKind::Module(ref module) => Some(module),
+ _ => None,
+ }
+ }
+
+ /// Transform our `ItemKind` into a string.
+ pub(crate) fn kind_name(&self) -> &'static str {
+ match *self {
+ ItemKind::Module(..) => "Module",
+ ItemKind::Type(..) => "Type",
+ ItemKind::Function(..) => "Function",
+ ItemKind::Var(..) => "Var",
+ }
+ }
+
+ /// Is this a module?
+ pub(crate) fn is_module(&self) -> bool {
+ self.as_module().is_some()
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if
+ /// it is some other kind.
+ pub(crate) fn as_function(&self) -> Option<&Function> {
+ match *self {
+ ItemKind::Function(ref func) => Some(func),
+ _ => None,
+ }
+ }
+
+ /// Is this a function?
+ pub(crate) fn is_function(&self) -> bool {
+ self.as_function().is_some()
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Function`, or panic if
+ /// it is some other kind.
+ pub(crate) fn expect_function(&self) -> &Function {
+ self.as_function().expect("Not a function")
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if
+ /// it is some other kind.
+ pub(crate) fn as_type(&self) -> Option<&Type> {
+ match *self {
+ ItemKind::Type(ref ty) => Some(ty),
+ _ => None,
+ }
+ }
+
+ /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None`
+ /// if it is some other kind.
+ pub(crate) fn as_type_mut(&mut self) -> Option<&mut Type> {
+ match *self {
+ ItemKind::Type(ref mut ty) => Some(ty),
+ _ => None,
+ }
+ }
+
+ /// Is this a type?
+ pub(crate) fn is_type(&self) -> bool {
+ self.as_type().is_some()
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is
+ /// some other kind.
+ pub(crate) fn expect_type(&self) -> &Type {
+ self.as_type().expect("Not a type")
+ }
+
+ /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is
+ /// some other kind.
+ pub(crate) fn as_var(&self) -> Option<&Var> {
+ match *self {
+ ItemKind::Var(ref v) => Some(v),
+ _ => None,
+ }
+ }
+
+ /// Is this a variable?
+ pub(crate) fn is_var(&self) -> bool {
+ self.as_var().is_some()
+ }
+}
+
+impl DotAttributes for ItemKind {
+ fn dot_attributes<W>(
+ &self,
+ ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ writeln!(out, "<tr><td>kind</td><td>{}</td></tr>", self.kind_name())?;
+
+ match *self {
+ ItemKind::Module(ref module) => module.dot_attributes(ctx, out),
+ ItemKind::Type(ref ty) => ty.dot_attributes(ctx, out),
+ ItemKind::Function(ref func) => func.dot_attributes(ctx, out),
+ ItemKind::Var(ref var) => var.dot_attributes(ctx, out),
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/ir/layout.rs b/third_party/rust/bindgen/ir/layout.rs
new file mode 100644
index 0000000000..85a553da31
--- /dev/null
+++ b/third_party/rust/bindgen/ir/layout.rs
@@ -0,0 +1,138 @@
+//! Intermediate representation for the physical layout of some type.
+
+use super::derive::CanDerive;
+use super::ty::{Type, TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
+use crate::clang;
+use crate::ir::context::BindgenContext;
+use std::cmp;
+
+/// A type that represents the struct layout of a type.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) struct Layout {
+ /// The size (in bytes) of this layout.
+ pub(crate) size: usize,
+ /// The alignment (in bytes) of this layout.
+ pub(crate) align: usize,
+ /// Whether this layout's members are packed or not.
+ pub(crate) packed: bool,
+}
+
+#[test]
+fn test_layout_for_size() {
+ use std::mem;
+
+ 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(crate) fn known_type_for_size(
+ ctx: &BindgenContext,
+ size: usize,
+ ) -> Option<syn::Type> {
+ Some(match size {
+ 16 if ctx.options().rust_features.i128_and_u128 => {
+ syn::parse_quote! { u128 }
+ }
+ 8 => syn::parse_quote! { u64 },
+ 4 => syn::parse_quote! { u32 },
+ 2 => syn::parse_quote! { u16 },
+ 1 => syn::parse_quote! { u8 },
+ _ => return None,
+ })
+ }
+
+ /// Construct a new `Layout` with the given `size` and `align`. It is not
+ /// packed.
+ pub(crate) fn new(size: usize, align: usize) -> Self {
+ Layout {
+ size,
+ align,
+ packed: false,
+ }
+ }
+
+ fn for_size_internal(ptr_size: usize, size: usize) -> Self {
+ let mut next_align = 2;
+ while size % next_align == 0 && next_align <= ptr_size {
+ next_align *= 2;
+ }
+ Layout {
+ size,
+ align: next_align / 2,
+ packed: false,
+ }
+ }
+
+ /// Creates a non-packed layout for a given size, trying to use the maximum
+ /// alignment possible.
+ pub(crate) fn for_size(ctx: &BindgenContext, size: usize) -> Self {
+ Self::for_size_internal(ctx.target_pointer_size(), size)
+ }
+
+ /// Get this layout as an opaque type.
+ pub(crate) fn opaque(&self) -> Opaque {
+ Opaque(*self)
+ }
+}
+
+/// When we are treating a type as opaque, it is just a blob with a `Layout`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) struct Opaque(pub(crate) Layout);
+
+impl Opaque {
+ /// Construct a new opaque type from the given clang type.
+ pub(crate) fn from_clang_ty(
+ ty: &clang::Type,
+ ctx: &BindgenContext,
+ ) -> Type {
+ let layout = Layout::new(ty.size(ctx), ty.align(ctx));
+ let ty_kind = TypeKind::Opaque;
+ let is_const = ty.is_const();
+ Type::new(None, Some(layout), ty_kind, is_const)
+ }
+
+ /// Return the known rust type we should use to create a correctly-aligned
+ /// field with this layout.
+ pub(crate) fn known_rust_type_for_array(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Option<syn::Type> {
+ 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(crate) fn array_size(&self, ctx: &BindgenContext) -> Option<usize> {
+ if self.known_rust_type_for_array(ctx).is_some() {
+ Some(self.0.size / cmp::max(self.0.align, 1))
+ } else {
+ None
+ }
+ }
+
+ /// Return `true` if this opaque layout's array size will fit within the
+ /// maximum number of array elements that Rust allows deriving traits
+ /// with. Return `false` otherwise.
+ pub(crate) fn array_size_within_derive_limit(
+ &self,
+ ctx: &BindgenContext,
+ ) -> CanDerive {
+ if self
+ .array_size(ctx)
+ .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT)
+ {
+ CanDerive::Yes
+ } else {
+ CanDerive::Manually
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/ir/mod.rs b/third_party/rust/bindgen/ir/mod.rs
new file mode 100644
index 0000000000..acdb4896cd
--- /dev/null
+++ b/third_party/rust/bindgen/ir/mod.rs
@@ -0,0 +1,25 @@
+//! The ir module defines bindgen's intermediate representation.
+//!
+//! Parsing C/C++ generates the IR, while code generation outputs Rust code from
+//! the IR.
+#![deny(clippy::missing_docs_in_private_items)]
+
+pub(crate) mod analysis;
+pub(crate) mod annotations;
+pub(crate) mod comment;
+pub(crate) mod comp;
+pub(crate) mod context;
+pub(crate) mod derive;
+pub(crate) mod dot;
+pub(crate) mod enum_ty;
+pub(crate) mod function;
+pub(crate) mod int;
+pub(crate) mod item;
+pub(crate) mod item_kind;
+pub(crate) mod layout;
+pub(crate) mod module;
+pub(crate) mod objc;
+pub(crate) mod template;
+pub(crate) mod traversal;
+pub(crate) mod ty;
+pub(crate) mod var;
diff --git a/third_party/rust/bindgen/ir/module.rs b/third_party/rust/bindgen/ir/module.rs
new file mode 100644
index 0000000000..5ec55e9048
--- /dev/null
+++ b/third_party/rust/bindgen/ir/module.rs
@@ -0,0 +1,96 @@
+//! Intermediate representation for modules (AKA C++ namespaces).
+
+use super::context::BindgenContext;
+use super::dot::DotAttributes;
+use super::item::ItemSet;
+use crate::clang;
+use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
+use crate::parse_one;
+
+use std::io;
+
+/// Whether this module is inline or not.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub(crate) enum ModuleKind {
+ /// This module is not inline.
+ Normal,
+ /// This module is inline, as in `inline namespace foo {}`.
+ Inline,
+}
+
+/// A module, as in, a C++ namespace.
+#[derive(Clone, Debug)]
+pub(crate) struct Module {
+ /// The name of the module, or none if it's anonymous.
+ name: Option<String>,
+ /// The kind of module this is.
+ kind: ModuleKind,
+ /// The children of this module, just here for convenience.
+ children: ItemSet,
+}
+
+impl Module {
+ /// Construct a new `Module`.
+ pub(crate) fn new(name: Option<String>, kind: ModuleKind) -> Self {
+ Module {
+ name,
+ kind,
+ children: ItemSet::new(),
+ }
+ }
+
+ /// Get this module's name.
+ pub(crate) fn name(&self) -> Option<&str> {
+ self.name.as_deref()
+ }
+
+ /// Get a mutable reference to this module's children.
+ pub(crate) fn children_mut(&mut self) -> &mut ItemSet {
+ &mut self.children
+ }
+
+ /// Get this module's children.
+ pub(crate) fn children(&self) -> &ItemSet {
+ &self.children
+ }
+
+ /// Whether this namespace is inline.
+ pub(crate) fn is_inline(&self) -> bool {
+ self.kind == ModuleKind::Inline
+ }
+}
+
+impl DotAttributes for Module {
+ fn dot_attributes<W>(
+ &self,
+ _ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ writeln!(out, "<tr><td>ModuleKind</td><td>{:?}</td></tr>", self.kind)
+ }
+}
+
+impl ClangSubItemParser for Module {
+ fn parse(
+ cursor: clang::Cursor,
+ ctx: &mut BindgenContext,
+ ) -> Result<ParseResult<Self>, ParseError> {
+ use clang_sys::*;
+ match cursor.kind() {
+ CXCursor_Namespace => {
+ let module_id = ctx.module(cursor);
+ ctx.with_module(module_id, |ctx| {
+ cursor.visit_sorted(ctx, |ctx, child| {
+ parse_one(ctx, child, Some(module_id.into()))
+ })
+ });
+
+ Ok(ParseResult::AlreadyResolved(module_id.into()))
+ }
+ _ => Err(ParseError::Continue),
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/ir/objc.rs b/third_party/rust/bindgen/ir/objc.rs
new file mode 100644
index 0000000000..93d8b3bfdf
--- /dev/null
+++ b/third_party/rust/bindgen/ir/objc.rs
@@ -0,0 +1,354 @@
+//! Objective C types
+
+use super::context::{BindgenContext, ItemId};
+use super::function::FunctionSig;
+use super::item::Item;
+use super::traversal::{Trace, Tracer};
+use super::ty::TypeKind;
+use crate::clang;
+use clang_sys::CXChildVisit_Continue;
+use clang_sys::CXCursor_ObjCCategoryDecl;
+use clang_sys::CXCursor_ObjCClassMethodDecl;
+use clang_sys::CXCursor_ObjCClassRef;
+use clang_sys::CXCursor_ObjCInstanceMethodDecl;
+use clang_sys::CXCursor_ObjCProtocolDecl;
+use clang_sys::CXCursor_ObjCProtocolRef;
+use clang_sys::CXCursor_ObjCSuperClassRef;
+use clang_sys::CXCursor_TemplateTypeParameter;
+use proc_macro2::{Ident, Span, TokenStream};
+
+/// Objective C interface as used in TypeKind
+///
+/// Also protocols and categories are parsed as this type
+#[derive(Debug)]
+pub(crate) struct ObjCInterface {
+ /// The name
+ /// like, NSObject
+ name: String,
+
+ category: Option<String>,
+
+ is_protocol: bool,
+
+ /// The list of template names almost always, ObjectType or KeyType
+ pub(crate) template_names: Vec<String>,
+
+ /// The list of protocols that this interface conforms to.
+ pub(crate) conforms_to: Vec<ItemId>,
+
+ /// The direct parent for this interface.
+ pub(crate) parent_class: Option<ItemId>,
+
+ /// List of the methods defined in this interfae
+ methods: Vec<ObjCMethod>,
+
+ class_methods: Vec<ObjCMethod>,
+}
+
+/// The objective c methods
+#[derive(Debug)]
+pub(crate) struct ObjCMethod {
+ /// The original method selector name
+ /// like, dataWithBytes:length:
+ name: String,
+
+ /// Method name as converted to rust
+ /// like, dataWithBytes_length_
+ rust_name: String,
+
+ signature: FunctionSig,
+
+ /// Is class method?
+ is_class_method: bool,
+}
+
+impl ObjCInterface {
+ fn new(name: &str) -> ObjCInterface {
+ ObjCInterface {
+ name: name.to_owned(),
+ category: None,
+ is_protocol: false,
+ template_names: Vec::new(),
+ parent_class: None,
+ conforms_to: Vec::new(),
+ methods: Vec::new(),
+ class_methods: Vec::new(),
+ }
+ }
+
+ /// The name
+ /// like, NSObject
+ pub(crate) fn name(&self) -> &str {
+ self.name.as_ref()
+ }
+
+ /// Formats the name for rust
+ /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods
+ /// and protocols are like PNSObject
+ pub(crate) fn rust_name(&self) -> String {
+ if let Some(ref cat) = self.category {
+ format!("{}_{}", 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(crate) fn is_template(&self) -> bool {
+ !self.template_names.is_empty()
+ }
+
+ /// List of the methods defined in this interface
+ pub(crate) fn methods(&self) -> &Vec<ObjCMethod> {
+ &self.methods
+ }
+
+ /// Is this a protocol?
+ pub(crate) fn is_protocol(&self) -> bool {
+ self.is_protocol
+ }
+
+ /// Is this a category?
+ pub(crate) fn is_category(&self) -> bool {
+ self.category.is_some()
+ }
+
+ /// List of the class methods defined in this interface
+ pub(crate) fn class_methods(&self) -> &Vec<ObjCMethod> {
+ &self.class_methods
+ }
+
+ /// Parses the Objective C interface from the cursor
+ pub(crate) fn from_ty(
+ cursor: &clang::Cursor,
+ ctx: &mut BindgenContext,
+ ) -> Option<Self> {
+ let name = cursor.spelling();
+ let mut interface = Self::new(&name);
+
+ if cursor.kind() == CXCursor_ObjCProtocolDecl {
+ interface.is_protocol = true;
+ }
+
+ cursor.visit(|c| {
+ match c.kind() {
+ CXCursor_ObjCClassRef => {
+ if cursor.kind() == CXCursor_ObjCCategoryDecl {
+ // We are actually a category extension, and we found the reference
+ // to the original interface, so name this interface approriately
+ interface.name = c.spelling();
+ interface.category = Some(cursor.spelling());
+ }
+ }
+ CXCursor_ObjCProtocolRef => {
+ // Gather protocols this interface conforms to
+ let needle = format!("P{}", c.spelling());
+ let items_map = ctx.items();
+ debug!(
+ "Interface {} conforms to {}, find the item",
+ interface.name, needle
+ );
+
+ for (id, item) in items_map {
+ if let Some(ty) = item.as_type() {
+ if let TypeKind::ObjCInterface(ref protocol) =
+ *ty.kind()
+ {
+ if protocol.is_protocol {
+ debug!(
+ "Checking protocol {}, ty.name {:?}",
+ protocol.name,
+ ty.name()
+ );
+ if Some(needle.as_ref()) == ty.name() {
+ debug!(
+ "Found conforming protocol {:?}",
+ item
+ );
+ interface.conforms_to.push(id);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ CXCursor_ObjCInstanceMethodDecl |
+ CXCursor_ObjCClassMethodDecl => {
+ let name = c.spelling();
+ let signature =
+ FunctionSig::from_ty(&c.cur_type(), &c, ctx)
+ .expect("Invalid function sig");
+ let is_class_method =
+ c.kind() == CXCursor_ObjCClassMethodDecl;
+ let method =
+ ObjCMethod::new(&name, signature, is_class_method);
+ interface.add_method(method);
+ }
+ CXCursor_TemplateTypeParameter => {
+ let name = c.spelling();
+ interface.template_names.push(name);
+ }
+ CXCursor_ObjCSuperClassRef => {
+ let item = Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
+ interface.parent_class = Some(item.into());
+ }
+ _ => {}
+ }
+ CXChildVisit_Continue
+ });
+ Some(interface)
+ }
+
+ fn add_method(&mut self, method: ObjCMethod) {
+ if method.is_class_method {
+ self.class_methods.push(method);
+ } else {
+ self.methods.push(method);
+ }
+ }
+}
+
+impl ObjCMethod {
+ fn new(
+ name: &str,
+ signature: FunctionSig,
+ is_class_method: bool,
+ ) -> ObjCMethod {
+ let split_name: Vec<&str> = name.split(':').collect();
+
+ let rust_name = split_name.join("_");
+
+ ObjCMethod {
+ name: name.to_owned(),
+ rust_name,
+ signature,
+ is_class_method,
+ }
+ }
+
+ /// Method name as converted to rust
+ /// like, dataWithBytes_length_
+ pub(crate) fn rust_name(&self) -> &str {
+ self.rust_name.as_ref()
+ }
+
+ /// Returns the methods signature as FunctionSig
+ pub(crate) fn signature(&self) -> &FunctionSig {
+ &self.signature
+ }
+
+ /// Is this a class method?
+ pub(crate) fn is_class_method(&self) -> bool {
+ self.is_class_method
+ }
+
+ /// Formats the method call
+ pub(crate) fn format_method_call(
+ &self,
+ args: &[TokenStream],
+ ) -> TokenStream {
+ let split_name: Vec<Option<Ident>> = self
+ .name
+ .split(':')
+ .enumerate()
+ .map(|(idx, name)| {
+ if name.is_empty() {
+ None
+ } else if idx == 0 {
+ // Try to parse the method name as an identifier. Having a keyword is ok
+ // unless it is `crate`, `self`, `super` or `Self`, so we try to add the `_`
+ // suffix to it and parse it.
+ if ["crate", "self", "super", "Self"].contains(&name) {
+ Some(Ident::new(
+ &format!("{}_", name),
+ Span::call_site(),
+ ))
+ } else {
+ Some(Ident::new(name, Span::call_site()))
+ }
+ } else {
+ // Try to parse the current joining name as an identifier. This might fail if the name
+ // is a keyword, so we try to "r#" to it and parse again, this could also fail
+ // if the name is `crate`, `self`, `super` or `Self`, so we try to add the `_`
+ // suffix to it and parse again. If this also fails, we panic with the first
+ // error.
+ Some(
+ syn::parse_str::<Ident>(name)
+ .or_else(|err| {
+ syn::parse_str::<Ident>(&format!("r#{}", name))
+ .map_err(|_| err)
+ })
+ .or_else(|err| {
+ syn::parse_str::<Ident>(&format!("{}_", name))
+ .map_err(|_| err)
+ })
+ .expect("Invalid identifier"),
+ )
+ }
+ })
+ .collect();
+
+ // No arguments
+ if args.is_empty() && split_name.len() == 1 {
+ let name = &split_name[0];
+ return quote! {
+ #name
+ };
+ }
+
+ // Check right amount of arguments
+ assert!(
+ args.len() == split_name.len() - 1,
+ "Incorrect method name or arguments for objc method, {:?} vs {:?}",
+ args,
+ split_name
+ );
+
+ // Get arguments without type signatures to pass to `msg_send!`
+ let mut args_without_types = vec![];
+ for arg in args.iter() {
+ let arg = arg.to_string();
+ let name_and_sig: Vec<&str> = arg.split(' ').collect();
+ let name = name_and_sig[0];
+ args_without_types.push(Ident::new(name, Span::call_site()))
+ }
+
+ let args = split_name.into_iter().zip(args_without_types).map(
+ |(arg, arg_val)| {
+ if let Some(arg) = arg {
+ quote! { #arg: #arg_val }
+ } else {
+ quote! { #arg_val: #arg_val }
+ }
+ },
+ );
+
+ quote! {
+ #( #args )*
+ }
+ }
+}
+
+impl Trace for ObjCInterface {
+ type Extra = ();
+
+ fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, _: &())
+ where
+ T: Tracer,
+ {
+ for method in &self.methods {
+ method.signature.trace(context, tracer, &());
+ }
+
+ for class_method in &self.class_methods {
+ class_method.signature.trace(context, tracer, &());
+ }
+
+ for protocol in &self.conforms_to {
+ tracer.visit(*protocol);
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/ir/template.rs b/third_party/rust/bindgen/ir/template.rs
new file mode 100644
index 0000000000..4dd8442c58
--- /dev/null
+++ b/third_party/rust/bindgen/ir/template.rs
@@ -0,0 +1,342 @@
+//! Template declaration and instantiation related things.
+//!
+//! The nomenclature surrounding templates is often confusing, so here are a few
+//! brief definitions:
+//!
+//! * "Template definition": a class/struct/alias/function definition that takes
+//! generic template parameters. For example:
+//!
+//! ```c++
+//! template<typename T>
+//! class List<T> {
+//! // ...
+//! };
+//! ```
+//!
+//! * "Template instantiation": an instantiation is a use of a template with
+//! concrete template arguments. For example, `List<int>`.
+//!
+//! * "Template specialization": an alternative template definition providing a
+//! custom definition for instantiations with the matching template
+//! arguments. This C++ feature is unsupported by bindgen. For example:
+//!
+//! ```c++
+//! template<>
+//! class List<int> {
+//! // Special layout for int lists...
+//! };
+//! ```
+
+use super::context::{BindgenContext, ItemId, TypeId};
+use super::item::{IsOpaque, Item, ItemAncestors};
+use super::traversal::{EdgeKind, Trace, Tracer};
+use crate::clang;
+
+/// Template declaration (and such declaration's template parameters) related
+/// methods.
+///
+/// This trait's methods distinguish between `None` and `Some([])` for
+/// declarations that are not templates and template declarations with zero
+/// parameters, in general.
+///
+/// Consider this example:
+///
+/// ```c++
+/// template <typename T, typename U>
+/// class Foo {
+/// T use_of_t;
+/// U use_of_u;
+///
+/// template <typename V>
+/// using Bar = V*;
+///
+/// class Inner {
+/// T x;
+/// U y;
+/// Bar<int> z;
+/// };
+///
+/// template <typename W>
+/// class Lol {
+/// // No use of W, but here's a use of T.
+/// T t;
+/// };
+///
+/// template <typename X>
+/// class Wtf {
+/// // X is not used because W is not used.
+/// Lol<X> lololol;
+/// };
+/// };
+///
+/// class Qux {
+/// int y;
+/// };
+/// ```
+///
+/// The following table depicts the results of each trait method when invoked on
+/// each of the declarations above:
+///
+/// +------+----------------------+--------------------------+-------------------------+----
+/// |Decl. | self_template_params | num_self_template_params | all_template_parameters | ...
+/// +------+----------------------+--------------------------+-------------------------+----
+/// |Foo | T, U | 2 | T, U | ...
+/// |Bar | V | 1 | T, U, V | ...
+/// |Inner | | 0 | T, U | ...
+/// |Lol | W | 1 | T, U, W | ...
+/// |Wtf | X | 1 | T, U, X | ...
+/// |Qux | | 0 | | ...
+/// +------+----------------------+--------------------------+------------------------+----
+///
+/// ----+------+-----+----------------------+
+/// ... |Decl. | ... | used_template_params |
+/// ----+------+-----+----------------------+
+/// ... |Foo | ... | T, U |
+/// ... |Bar | ... | V |
+/// ... |Inner | ... | |
+/// ... |Lol | ... | T |
+/// ... |Wtf | ... | T |
+/// ... |Qux | ... | |
+/// ----+------+-----+----------------------+
+pub(crate) trait TemplateParameters: Sized {
+ /// Get the set of `ItemId`s that make up this template declaration's free
+ /// template parameters.
+ ///
+ /// Note that these might *not* all be named types: C++ allows
+ /// constant-value template parameters as well as template-template
+ /// parameters. Of course, Rust does not allow generic parameters to be
+ /// anything but types, so we must treat them as opaque, and avoid
+ /// instantiating them.
+ fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>;
+
+ /// Get the number of free template parameters this template declaration
+ /// has.
+ fn num_self_template_params(&self, ctx: &BindgenContext) -> usize {
+ self.self_template_params(ctx).len()
+ }
+
+ /// Get the complete set of template parameters that can affect this
+ /// declaration.
+ ///
+ /// Note that this item doesn't need to be a template declaration itself for
+ /// `Some` to be returned here (in contrast to `self_template_params`). If
+ /// this item is a member of a template declaration, then the parent's
+ /// template parameters are included here.
+ ///
+ /// In the example above, `Inner` depends on both of the `T` and `U` type
+ /// parameters, even though it is not itself a template declaration and
+ /// therefore has no type parameters itself. Perhaps it helps to think about
+ /// how we would fully reference such a member type in C++:
+ /// `Foo<int,char>::Inner`. `Foo` *must* be instantiated with template
+ /// arguments before we can gain access to the `Inner` member type.
+ fn all_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>
+ where
+ Self: ItemAncestors,
+ {
+ let mut ancestors: Vec<_> = self.ancestors(ctx).collect();
+ ancestors.reverse();
+ ancestors
+ .into_iter()
+ .flat_map(|id| id.self_template_params(ctx).into_iter())
+ .collect()
+ }
+
+ /// Get only the set of template parameters that this item uses. This is a
+ /// subset of `all_template_params` and does not necessarily contain any of
+ /// `self_template_params`.
+ fn used_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId>
+ where
+ Self: AsRef<ItemId>,
+ {
+ assert!(
+ ctx.in_codegen_phase(),
+ "template parameter usage is not computed until codegen"
+ );
+
+ let id = *self.as_ref();
+ ctx.resolve_item(id)
+ .all_template_params(ctx)
+ .into_iter()
+ .filter(|p| ctx.uses_template_parameter(id, *p))
+ .collect()
+ }
+}
+
+/// A trait for things which may or may not be a named template type parameter.
+pub(crate) trait AsTemplateParam {
+ /// Any extra information the implementor might need to make this decision.
+ type Extra;
+
+ /// Convert this thing to the item ID of a named template type parameter.
+ fn as_template_param(
+ &self,
+ ctx: &BindgenContext,
+ extra: &Self::Extra,
+ ) -> Option<TypeId>;
+
+ /// Is this a named template type parameter?
+ fn is_template_param(
+ &self,
+ ctx: &BindgenContext,
+ extra: &Self::Extra,
+ ) -> bool {
+ self.as_template_param(ctx, extra).is_some()
+ }
+}
+
+/// A concrete instantiation of a generic template.
+#[derive(Clone, Debug)]
+pub(crate) struct TemplateInstantiation {
+ /// The template definition which this is instantiating.
+ definition: TypeId,
+ /// The concrete template arguments, which will be substituted in the
+ /// definition for the generic template parameters.
+ args: Vec<TypeId>,
+}
+
+impl TemplateInstantiation {
+ /// Construct a new template instantiation from the given parts.
+ pub(crate) fn new<I>(definition: TypeId, args: I) -> TemplateInstantiation
+ where
+ I: IntoIterator<Item = TypeId>,
+ {
+ TemplateInstantiation {
+ definition,
+ args: args.into_iter().collect(),
+ }
+ }
+
+ /// Get the template definition for this instantiation.
+ pub(crate) fn template_definition(&self) -> TypeId {
+ self.definition
+ }
+
+ /// Get the concrete template arguments used in this instantiation.
+ pub(crate) fn template_arguments(&self) -> &[TypeId] {
+ &self.args[..]
+ }
+
+ /// Parse a `TemplateInstantiation` from a clang `Type`.
+ pub(crate) fn from_ty(
+ ty: &clang::Type,
+ ctx: &mut BindgenContext,
+ ) -> Option<TemplateInstantiation> {
+ use clang_sys::*;
+
+ let template_args = ty.template_args().map_or(vec![], |args| match ty
+ .canonical_type()
+ .template_args()
+ {
+ Some(canonical_args) => {
+ let arg_count = args.len();
+ args.chain(canonical_args.skip(arg_count))
+ .filter(|t| t.kind() != CXType_Invalid)
+ .map(|t| {
+ Item::from_ty_or_ref(t, t.declaration(), None, ctx)
+ })
+ .collect()
+ }
+ None => args
+ .filter(|t| t.kind() != CXType_Invalid)
+ .map(|t| Item::from_ty_or_ref(t, t.declaration(), None, ctx))
+ .collect(),
+ });
+
+ let declaration = ty.declaration();
+ let definition = if declaration.kind() == CXCursor_TypeAliasTemplateDecl
+ {
+ Some(declaration)
+ } else {
+ declaration.specialized().or_else(|| {
+ let mut template_ref = None;
+ ty.declaration().visit(|child| {
+ if child.kind() == CXCursor_TemplateRef {
+ template_ref = Some(child);
+ return CXVisit_Break;
+ }
+
+ // Instantiations of template aliases might have the
+ // TemplateRef to the template alias definition arbitrarily
+ // deep, so we need to recurse here and not only visit
+ // direct children.
+ CXChildVisit_Recurse
+ });
+
+ template_ref.and_then(|cur| cur.referenced())
+ })
+ };
+
+ let definition = match definition {
+ Some(def) => def,
+ None => {
+ if !ty.declaration().is_builtin() {
+ warn!(
+ "Could not find template definition for template \
+ instantiation"
+ );
+ }
+ return None;
+ }
+ };
+
+ let template_definition =
+ Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx);
+
+ Some(TemplateInstantiation::new(
+ template_definition,
+ template_args,
+ ))
+ }
+}
+
+impl IsOpaque for TemplateInstantiation {
+ type Extra = Item;
+
+ /// Is this an opaque template instantiation?
+ fn is_opaque(&self, ctx: &BindgenContext, item: &Item) -> bool {
+ if self.template_definition().is_opaque(ctx, &()) {
+ return true;
+ }
+
+ // TODO(#774): This doesn't properly handle opaque instantiations where
+ // an argument is itself an instantiation because `canonical_name` does
+ // not insert the template arguments into the name, ie it for nested
+ // template arguments it creates "Foo" instead of "Foo<int>". The fully
+ // correct fix is to make `canonical_{name,path}` include template
+ // arguments properly.
+
+ let mut path = item.path_for_allowlisting(ctx).clone();
+ let args: Vec<_> = self
+ .template_arguments()
+ .iter()
+ .map(|arg| {
+ let arg_path =
+ ctx.resolve_item(*arg).path_for_allowlisting(ctx);
+ arg_path[1..].join("::")
+ })
+ .collect();
+ {
+ let last = path.last_mut().unwrap();
+ last.push('<');
+ last.push_str(&args.join(", "));
+ last.push('>');
+ }
+
+ ctx.opaque_by_name(&path)
+ }
+}
+
+impl Trace for TemplateInstantiation {
+ type Extra = ();
+
+ fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
+ where
+ T: Tracer,
+ {
+ tracer
+ .visit_kind(self.definition.into(), EdgeKind::TemplateDeclaration);
+ for arg in self.template_arguments() {
+ tracer.visit_kind(arg.into(), EdgeKind::TemplateArgument);
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/ir/traversal.rs b/third_party/rust/bindgen/ir/traversal.rs
new file mode 100644
index 0000000000..17e24f701e
--- /dev/null
+++ b/third_party/rust/bindgen/ir/traversal.rs
@@ -0,0 +1,479 @@
+//! Traversal of the graph of IR items and types.
+
+use super::context::{BindgenContext, ItemId};
+use super::item::ItemSet;
+use std::collections::{BTreeMap, VecDeque};
+
+/// An outgoing edge in the IR graph is a reference from some item to another
+/// item:
+///
+/// from --> to
+///
+/// The `from` is left implicit: it is the concrete `Trace` implementer which
+/// yielded this outgoing edge.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub(crate) struct Edge {
+ to: ItemId,
+ kind: EdgeKind,
+}
+
+impl Edge {
+ /// Construct a new edge whose referent is `to` and is of the given `kind`.
+ pub(crate) fn new(to: ItemId, kind: EdgeKind) -> Edge {
+ Edge { to, kind }
+ }
+}
+
+impl From<Edge> for ItemId {
+ fn from(val: Edge) -> Self {
+ val.to
+ }
+}
+
+/// The kind of edge reference. This is useful when we wish to only consider
+/// certain kinds of edges for a particular traversal or analysis.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub(crate) enum EdgeKind {
+ /// A generic, catch-all edge.
+ Generic,
+
+ /// An edge from a template declaration, to the definition of a named type
+ /// parameter. For example, the edge from `Foo<T>` to `T` in the following
+ /// snippet:
+ ///
+ /// ```C++
+ /// template<typename T>
+ /// class Foo { };
+ /// ```
+ TemplateParameterDefinition,
+
+ /// An edge from a template instantiation to the template declaration that
+ /// is being instantiated. For example, the edge from `Foo<int>` to
+ /// to `Foo<T>`:
+ ///
+ /// ```C++
+ /// template<typename T>
+ /// class Foo { };
+ ///
+ /// using Bar = Foo<ant>;
+ /// ```
+ TemplateDeclaration,
+
+ /// An edge from a template instantiation to its template argument. For
+ /// example, `Foo<Bar>` to `Bar`:
+ ///
+ /// ```C++
+ /// template<typename T>
+ /// class Foo { };
+ ///
+ /// class Bar { };
+ ///
+ /// using FooBar = Foo<Bar>;
+ /// ```
+ TemplateArgument,
+
+ /// An edge from a compound type to one of its base member types. For
+ /// example, the edge from `Bar` to `Foo`:
+ ///
+ /// ```C++
+ /// class Foo { };
+ ///
+ /// class Bar : public Foo { };
+ /// ```
+ BaseMember,
+
+ /// An edge from a compound type to the types of one of its fields. For
+ /// example, the edge from `Foo` to `int`:
+ ///
+ /// ```C++
+ /// class Foo {
+ /// int x;
+ /// };
+ /// ```
+ Field,
+
+ /// An edge from an class or struct type to an inner type member. For
+ /// example, the edge from `Foo` to `Foo::Bar` here:
+ ///
+ /// ```C++
+ /// class Foo {
+ /// struct Bar { };
+ /// };
+ /// ```
+ InnerType,
+
+ /// An edge from an class or struct type to an inner static variable. For
+ /// example, the edge from `Foo` to `Foo::BAR` here:
+ ///
+ /// ```C++
+ /// class Foo {
+ /// static const char* BAR;
+ /// };
+ /// ```
+ InnerVar,
+
+ /// An edge from a class or struct type to one of its method functions. For
+ /// example, the edge from `Foo` to `Foo::bar`:
+ ///
+ /// ```C++
+ /// class Foo {
+ /// bool bar(int x, int y);
+ /// };
+ /// ```
+ Method,
+
+ /// An edge from a class or struct type to one of its constructor
+ /// functions. For example, the edge from `Foo` to `Foo::Foo(int x, int y)`:
+ ///
+ /// ```C++
+ /// class Foo {
+ /// int my_x;
+ /// int my_y;
+ ///
+ /// public:
+ /// Foo(int x, int y);
+ /// };
+ /// ```
+ Constructor,
+
+ /// An edge from a class or struct type to its destructor function. For
+ /// example, the edge from `Doggo` to `Doggo::~Doggo()`:
+ ///
+ /// ```C++
+ /// struct Doggo {
+ /// char* wow;
+ ///
+ /// public:
+ /// ~Doggo();
+ /// };
+ /// ```
+ Destructor,
+
+ /// An edge from a function declaration to its return type. For example, the
+ /// edge from `foo` to `int`:
+ ///
+ /// ```C++
+ /// int foo(char* string);
+ /// ```
+ FunctionReturn,
+
+ /// An edge from a function declaration to one of its parameter types. For
+ /// example, the edge from `foo` to `char*`:
+ ///
+ /// ```C++
+ /// int foo(char* string);
+ /// ```
+ FunctionParameter,
+
+ /// An edge from a static variable to its type. For example, the edge from
+ /// `FOO` to `const char*`:
+ ///
+ /// ```C++
+ /// static const char* FOO;
+ /// ```
+ VarType,
+
+ /// An edge from a non-templated alias or typedef to the referenced type.
+ TypeReference,
+}
+
+/// A predicate to allow visiting only sub-sets of the whole IR graph by
+/// excluding certain edges from being followed by the traversal.
+///
+/// The predicate must return true if the traversal should follow this edge
+/// and visit everything that is reachable through it.
+pub(crate) type TraversalPredicate =
+ for<'a> fn(&'a BindgenContext, Edge) -> bool;
+
+/// A `TraversalPredicate` implementation that follows all edges, and therefore
+/// traversals using this predicate will see the whole IR graph reachable from
+/// the traversal's roots.
+pub(crate) fn all_edges(_: &BindgenContext, _: Edge) -> bool {
+ true
+}
+
+/// A `TraversalPredicate` implementation that only follows
+/// `EdgeKind::InnerType` edges, and therefore traversals using this predicate
+/// will only visit the traversal's roots and their inner types. This is used
+/// in no-recursive-allowlist mode, where inner types such as anonymous
+/// structs/unions still need to be processed.
+pub(crate) fn only_inner_type_edges(_: &BindgenContext, edge: Edge) -> bool {
+ edge.kind == EdgeKind::InnerType
+}
+
+/// A `TraversalPredicate` implementation that only follows edges to items that
+/// are enabled for code generation. This lets us skip considering items for
+/// which are not reachable from code generation.
+pub(crate) fn codegen_edges(ctx: &BindgenContext, edge: Edge) -> bool {
+ let cc = &ctx.options().codegen_config;
+ match edge.kind {
+ EdgeKind::Generic => {
+ ctx.resolve_item(edge.to).is_enabled_for_codegen(ctx)
+ }
+
+ // We statically know the kind of item that non-generic edges can point
+ // to, so we don't need to actually resolve the item and check
+ // `Item::is_enabled_for_codegen`.
+ EdgeKind::TemplateParameterDefinition |
+ EdgeKind::TemplateArgument |
+ EdgeKind::TemplateDeclaration |
+ EdgeKind::BaseMember |
+ EdgeKind::Field |
+ EdgeKind::InnerType |
+ EdgeKind::FunctionReturn |
+ EdgeKind::FunctionParameter |
+ EdgeKind::VarType |
+ EdgeKind::TypeReference => cc.types(),
+ EdgeKind::InnerVar => cc.vars(),
+ EdgeKind::Method => cc.methods(),
+ EdgeKind::Constructor => cc.constructors(),
+ EdgeKind::Destructor => cc.destructors(),
+ }
+}
+
+/// The storage for the set of items that have been seen (although their
+/// outgoing edges might not have been fully traversed yet) in an active
+/// traversal.
+pub(crate) trait TraversalStorage<'ctx> {
+ /// Construct a new instance of this TraversalStorage, for a new traversal.
+ fn new(ctx: &'ctx BindgenContext) -> Self;
+
+ /// Add the given item to the storage. If the item has never been seen
+ /// before, return `true`. Otherwise, return `false`.
+ ///
+ /// The `from` item is the item from which we discovered this item, or is
+ /// `None` if this item is a root.
+ fn add(&mut self, from: Option<ItemId>, item: ItemId) -> bool;
+}
+
+impl<'ctx> TraversalStorage<'ctx> for ItemSet {
+ fn new(_: &'ctx BindgenContext) -> Self {
+ ItemSet::new()
+ }
+
+ fn add(&mut self, _: Option<ItemId>, item: ItemId) -> bool {
+ self.insert(item)
+ }
+}
+
+/// A `TraversalStorage` implementation that keeps track of how we first reached
+/// each item. This is useful for providing debug assertions with meaningful
+/// diagnostic messages about dangling items.
+#[derive(Debug)]
+pub(crate) struct Paths<'ctx>(BTreeMap<ItemId, ItemId>, &'ctx BindgenContext);
+
+impl<'ctx> TraversalStorage<'ctx> for Paths<'ctx> {
+ fn new(ctx: &'ctx BindgenContext) -> Self {
+ Paths(BTreeMap::new(), ctx)
+ }
+
+ fn add(&mut self, from: Option<ItemId>, item: ItemId) -> bool {
+ let newly_discovered =
+ self.0.insert(item, from.unwrap_or(item)).is_none();
+
+ if self.1.resolve_item_fallible(item).is_none() {
+ let mut path = vec![];
+ let mut current = item;
+ loop {
+ let predecessor = *self.0.get(&current).expect(
+ "We know we found this item id, so it must have a \
+ predecessor",
+ );
+ if predecessor == current {
+ break;
+ }
+ path.push(predecessor);
+ current = predecessor;
+ }
+ path.reverse();
+ panic!(
+ "Found reference to dangling id = {:?}\nvia path = {:?}",
+ item, path
+ );
+ }
+
+ newly_discovered
+ }
+}
+
+/// The queue of seen-but-not-yet-traversed items.
+///
+/// Using a FIFO queue with a traversal will yield a breadth-first traversal,
+/// while using a LIFO queue will result in a depth-first traversal of the IR
+/// graph.
+pub(crate) trait TraversalQueue: Default {
+ /// Add a newly discovered item to the queue.
+ fn push(&mut self, item: ItemId);
+
+ /// Pop the next item to traverse, if any.
+ fn next(&mut self) -> Option<ItemId>;
+}
+
+impl TraversalQueue for Vec<ItemId> {
+ fn push(&mut self, item: ItemId) {
+ self.push(item);
+ }
+
+ fn next(&mut self) -> Option<ItemId> {
+ self.pop()
+ }
+}
+
+impl TraversalQueue for VecDeque<ItemId> {
+ fn push(&mut self, item: ItemId) {
+ self.push_back(item);
+ }
+
+ fn next(&mut self) -> Option<ItemId> {
+ self.pop_front()
+ }
+}
+
+/// Something that can receive edges from a `Trace` implementation.
+pub(crate) trait Tracer {
+ /// Note an edge between items. Called from within a `Trace` implementation.
+ fn visit_kind(&mut self, item: ItemId, kind: EdgeKind);
+
+ /// A synonym for `tracer.visit_kind(item, EdgeKind::Generic)`.
+ fn visit(&mut self, item: ItemId) {
+ self.visit_kind(item, EdgeKind::Generic);
+ }
+}
+
+impl<F> Tracer for F
+where
+ F: FnMut(ItemId, EdgeKind),
+{
+ fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) {
+ (*self)(item, kind)
+ }
+}
+
+/// Trace all of the outgoing edges to other items. Implementations should call
+/// one of `tracer.visit(edge)` or `tracer.visit_kind(edge, EdgeKind::Whatever)`
+/// for each of their outgoing edges.
+pub(crate) trait Trace {
+ /// If a particular type needs extra information beyond what it has in
+ /// `self` and `context` to find its referenced items, its implementation
+ /// can define this associated type, forcing callers to pass the needed
+ /// information through.
+ type Extra;
+
+ /// Trace all of this item's outgoing edges to other items.
+ fn trace<T>(
+ &self,
+ context: &BindgenContext,
+ tracer: &mut T,
+ extra: &Self::Extra,
+ ) where
+ T: Tracer;
+}
+
+/// An graph traversal of the transitive closure of references between items.
+///
+/// See `BindgenContext::allowlisted_items` for more information.
+pub(crate) struct ItemTraversal<'ctx, Storage, Queue>
+where
+ Storage: TraversalStorage<'ctx>,
+ Queue: TraversalQueue,
+{
+ ctx: &'ctx BindgenContext,
+
+ /// The set of items we have seen thus far in this traversal.
+ seen: Storage,
+
+ /// The set of items that we have seen, but have yet to traverse.
+ queue: Queue,
+
+ /// The predicate that determines which edges this traversal will follow.
+ predicate: TraversalPredicate,
+
+ /// The item we are currently traversing.
+ currently_traversing: Option<ItemId>,
+}
+
+impl<'ctx, Storage, Queue> ItemTraversal<'ctx, Storage, Queue>
+where
+ Storage: TraversalStorage<'ctx>,
+ Queue: TraversalQueue,
+{
+ /// Begin a new traversal, starting from the given roots.
+ pub(crate) fn new<R>(
+ ctx: &'ctx BindgenContext,
+ roots: R,
+ predicate: TraversalPredicate,
+ ) -> ItemTraversal<'ctx, Storage, Queue>
+ where
+ R: IntoIterator<Item = ItemId>,
+ {
+ let mut seen = Storage::new(ctx);
+ let mut queue = Queue::default();
+
+ for id in roots {
+ seen.add(None, id);
+ queue.push(id);
+ }
+
+ ItemTraversal {
+ ctx,
+ seen,
+ queue,
+ predicate,
+ currently_traversing: None,
+ }
+ }
+}
+
+impl<'ctx, Storage, Queue> Tracer for ItemTraversal<'ctx, Storage, Queue>
+where
+ Storage: TraversalStorage<'ctx>,
+ Queue: TraversalQueue,
+{
+ fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) {
+ let edge = Edge::new(item, kind);
+ if !(self.predicate)(self.ctx, edge) {
+ return;
+ }
+
+ let is_newly_discovered =
+ self.seen.add(self.currently_traversing, item);
+ if is_newly_discovered {
+ self.queue.push(item)
+ }
+ }
+}
+
+impl<'ctx, Storage, Queue> Iterator for ItemTraversal<'ctx, Storage, Queue>
+where
+ Storage: TraversalStorage<'ctx>,
+ Queue: TraversalQueue,
+{
+ type Item = ItemId;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let id = self.queue.next()?;
+
+ let newly_discovered = self.seen.add(None, id);
+ debug_assert!(
+ !newly_discovered,
+ "should have already seen anything we get out of our queue"
+ );
+ debug_assert!(
+ self.ctx.resolve_item_fallible(id).is_some(),
+ "should only get IDs of actual items in our context during traversal"
+ );
+
+ self.currently_traversing = Some(id);
+ id.trace(self.ctx, self, &());
+ self.currently_traversing = None;
+
+ Some(id)
+ }
+}
+
+/// An iterator to find any dangling items.
+///
+/// See `BindgenContext::assert_no_dangling_item_traversal` for more
+/// information.
+pub(crate) type AssertNoDanglingItemsTraversal<'ctx> =
+ ItemTraversal<'ctx, Paths<'ctx>, VecDeque<ItemId>>;
diff --git a/third_party/rust/bindgen/ir/ty.rs b/third_party/rust/bindgen/ir/ty.rs
new file mode 100644
index 0000000000..b7a429323e
--- /dev/null
+++ b/third_party/rust/bindgen/ir/ty.rs
@@ -0,0 +1,1281 @@
+//! Everything related to types in our intermediate representation.
+
+use super::comp::CompInfo;
+use super::context::{BindgenContext, ItemId, TypeId};
+use super::dot::DotAttributes;
+use super::enum_ty::Enum;
+use super::function::FunctionSig;
+use super::item::{IsOpaque, Item};
+use super::layout::{Layout, Opaque};
+use super::objc::ObjCInterface;
+use super::template::{
+ AsTemplateParam, TemplateInstantiation, TemplateParameters,
+};
+use super::traversal::{EdgeKind, Trace, Tracer};
+use crate::clang::{self, Cursor};
+use crate::parse::{ParseError, ParseResult};
+use std::borrow::Cow;
+use std::io;
+
+pub use super::int::IntKind;
+
+/// The base representation of a type in bindgen.
+///
+/// A type has an optional name, which if present cannot be empty, a `layout`
+/// (size, alignment and packedness) if known, a `Kind`, which determines which
+/// kind of type it is, and whether the type is const.
+#[derive(Debug)]
+pub(crate) struct Type {
+ /// The name of the type, or None if it was an unnamed struct or union.
+ name: Option<String>,
+ /// The layout of the type, if known.
+ layout: Option<Layout>,
+ /// The inner kind of the type
+ kind: TypeKind,
+ /// Whether this type is const-qualified.
+ is_const: bool,
+}
+
+/// The maximum number of items in an array for which Rust implements common
+/// traits, and so if we have a type containing an array with more than this
+/// many items, we won't be able to derive common traits on that type.
+///
+pub(crate) const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32;
+
+impl Type {
+ /// Get the underlying `CompInfo` for this type as a mutable reference, or
+ /// `None` if this is some other kind of type.
+ pub(crate) fn as_comp_mut(&mut self) -> Option<&mut CompInfo> {
+ match self.kind {
+ TypeKind::Comp(ref mut ci) => Some(ci),
+ _ => None,
+ }
+ }
+
+ /// Construct a new `Type`.
+ pub(crate) fn new(
+ name: Option<String>,
+ layout: Option<Layout>,
+ kind: TypeKind,
+ is_const: bool,
+ ) -> Self {
+ Type {
+ name,
+ layout,
+ kind,
+ is_const,
+ }
+ }
+
+ /// Which kind of type is this?
+ pub(crate) fn kind(&self) -> &TypeKind {
+ &self.kind
+ }
+
+ /// Get a mutable reference to this type's kind.
+ pub(crate) fn kind_mut(&mut self) -> &mut TypeKind {
+ &mut self.kind
+ }
+
+ /// Get this type's name.
+ pub(crate) fn name(&self) -> Option<&str> {
+ self.name.as_deref()
+ }
+
+ /// Whether this is a block pointer type.
+ pub(crate) fn is_block_pointer(&self) -> bool {
+ matches!(self.kind, TypeKind::BlockPointer(..))
+ }
+
+ /// Is this an integer type, including `bool` or `char`?
+ pub(crate) fn is_int(&self) -> bool {
+ matches!(self.kind, TypeKind::Int(_))
+ }
+
+ /// Is this a compound type?
+ pub(crate) fn is_comp(&self) -> bool {
+ matches!(self.kind, TypeKind::Comp(..))
+ }
+
+ /// Is this a union?
+ pub(crate) fn is_union(&self) -> bool {
+ match self.kind {
+ TypeKind::Comp(ref comp) => comp.is_union(),
+ _ => false,
+ }
+ }
+
+ /// Is this type of kind `TypeKind::TypeParam`?
+ pub(crate) fn is_type_param(&self) -> bool {
+ matches!(self.kind, TypeKind::TypeParam)
+ }
+
+ /// Is this a template instantiation type?
+ pub(crate) fn is_template_instantiation(&self) -> bool {
+ matches!(self.kind, TypeKind::TemplateInstantiation(..))
+ }
+
+ /// Is this a function type?
+ pub(crate) fn is_function(&self) -> bool {
+ matches!(self.kind, TypeKind::Function(..))
+ }
+
+ /// Is this an enum type?
+ pub(crate) fn is_enum(&self) -> bool {
+ matches!(self.kind, TypeKind::Enum(..))
+ }
+
+ /// Is this void?
+ pub(crate) fn is_void(&self) -> bool {
+ matches!(self.kind, TypeKind::Void)
+ }
+ /// Is this either a builtin or named type?
+ pub(crate) fn is_builtin_or_type_param(&self) -> bool {
+ matches!(
+ self.kind,
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Function(..) |
+ TypeKind::Array(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::TypeParam
+ )
+ }
+
+ /// Creates a new named type, with name `name`.
+ pub(crate) fn named(name: String) -> Self {
+ let name = if name.is_empty() { None } else { Some(name) };
+ Self::new(name, None, TypeKind::TypeParam, false)
+ }
+
+ /// Is this a floating point type?
+ pub(crate) fn is_float(&self) -> bool {
+ matches!(self.kind, TypeKind::Float(..))
+ }
+
+ /// Is this a boolean type?
+ pub(crate) fn is_bool(&self) -> bool {
+ matches!(self.kind, TypeKind::Int(IntKind::Bool))
+ }
+
+ /// Is this an integer type?
+ pub(crate) fn is_integer(&self) -> bool {
+ matches!(self.kind, TypeKind::Int(..))
+ }
+
+ /// Cast this type to an integer kind, or `None` if it is not an integer
+ /// type.
+ pub(crate) fn as_integer(&self) -> Option<IntKind> {
+ match self.kind {
+ TypeKind::Int(int_kind) => Some(int_kind),
+ _ => None,
+ }
+ }
+
+ /// Is this a `const` qualified type?
+ pub(crate) fn is_const(&self) -> bool {
+ self.is_const
+ }
+
+ /// Is this an unresolved reference?
+ pub(crate) fn is_unresolved_ref(&self) -> bool {
+ matches!(self.kind, TypeKind::UnresolvedTypeRef(_, _, _))
+ }
+
+ /// Is this a incomplete array type?
+ pub(crate) fn is_incomplete_array(
+ &self,
+ ctx: &BindgenContext,
+ ) -> Option<ItemId> {
+ match self.kind {
+ TypeKind::Array(item, len) => {
+ if len == 0 {
+ Some(item.into())
+ } else {
+ None
+ }
+ }
+ TypeKind::ResolvedTypeRef(inner) => {
+ ctx.resolve_type(inner).is_incomplete_array(ctx)
+ }
+ _ => None,
+ }
+ }
+
+ /// What is the layout of this type?
+ pub(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
+ self.layout.or_else(|| {
+ match self.kind {
+ TypeKind::Comp(ref ci) => ci.layout(ctx),
+ TypeKind::Array(inner, 0) => Some(Layout::new(
+ 0,
+ ctx.resolve_type(inner).layout(ctx)?.align,
+ )),
+ // FIXME(emilio): This is a hack for anonymous union templates.
+ // Use the actual pointer size!
+ TypeKind::Pointer(..) => Some(Layout::new(
+ ctx.target_pointer_size(),
+ ctx.target_pointer_size(),
+ )),
+ TypeKind::ResolvedTypeRef(inner) => {
+ ctx.resolve_type(inner).layout(ctx)
+ }
+ _ => None,
+ }
+ })
+ }
+
+ /// Whether this named type is an invalid C++ identifier. This is done to
+ /// avoid generating invalid code with some cases we can't handle, see:
+ ///
+ /// tests/headers/381-decltype-alias.hpp
+ pub(crate) fn is_invalid_type_param(&self) -> bool {
+ match self.kind {
+ TypeKind::TypeParam => {
+ let name = self.name().expect("Unnamed named type?");
+ !clang::is_valid_identifier(name)
+ }
+ _ => false,
+ }
+ }
+
+ /// Takes `name`, and returns a suitable identifier representation for it.
+ fn sanitize_name(name: &str) -> Cow<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(crate) fn sanitized_name<'a>(
+ &'a self,
+ ctx: &BindgenContext,
+ ) -> Option<Cow<'a, str>> {
+ let name_info = match *self.kind() {
+ TypeKind::Pointer(inner) => Some((inner, Cow::Borrowed("ptr"))),
+ TypeKind::Reference(inner) => Some((inner, Cow::Borrowed("ref"))),
+ TypeKind::Array(inner, length) => {
+ Some((inner, format!("array{}", length).into()))
+ }
+ _ => None,
+ };
+ if let Some((inner, prefix)) = name_info {
+ ctx.resolve_item(inner)
+ .expect_type()
+ .sanitized_name(ctx)
+ .map(|name| format!("{}_{}", prefix, name).into())
+ } else {
+ self.name().map(Self::sanitize_name)
+ }
+ }
+
+ /// See safe_canonical_type.
+ pub(crate) fn canonical_type<'tr>(
+ &'tr self,
+ ctx: &'tr BindgenContext,
+ ) -> &'tr Type {
+ self.safe_canonical_type(ctx)
+ .expect("Should have been resolved after parsing!")
+ }
+
+ /// Returns the canonical type of this type, that is, the "inner type".
+ ///
+ /// For example, for a `typedef`, the canonical type would be the
+ /// `typedef`ed type, for a template instantiation, would be the template
+ /// its specializing, and so on. Return None if the type is unresolved.
+ pub(crate) fn safe_canonical_type<'tr>(
+ &'tr self,
+ ctx: &'tr BindgenContext,
+ ) -> Option<&'tr Type> {
+ match self.kind {
+ TypeKind::TypeParam |
+ TypeKind::Array(..) |
+ TypeKind::Vector(..) |
+ TypeKind::Comp(..) |
+ TypeKind::Opaque |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Complex(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Pointer(..) |
+ TypeKind::BlockPointer(..) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel |
+ TypeKind::ObjCInterface(..) => Some(self),
+
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::Alias(inner) |
+ TypeKind::TemplateAlias(inner, _) => {
+ ctx.resolve_type(inner).safe_canonical_type(ctx)
+ }
+ TypeKind::TemplateInstantiation(ref inst) => ctx
+ .resolve_type(inst.template_definition())
+ .safe_canonical_type(ctx),
+
+ TypeKind::UnresolvedTypeRef(..) => None,
+ }
+ }
+
+ /// There are some types we don't want to stop at when finding an opaque
+ /// item, so we can arrive to the proper item that needs to be generated.
+ pub(crate) fn should_be_traced_unconditionally(&self) -> bool {
+ matches!(
+ self.kind,
+ TypeKind::Comp(..) |
+ TypeKind::Function(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Array(..) |
+ TypeKind::Reference(..) |
+ TypeKind::TemplateInstantiation(..) |
+ TypeKind::ResolvedTypeRef(..)
+ )
+ }
+}
+
+impl IsOpaque for Type {
+ type Extra = Item;
+
+ fn is_opaque(&self, ctx: &BindgenContext, item: &Item) -> bool {
+ match self.kind {
+ TypeKind::Opaque => true,
+ TypeKind::TemplateInstantiation(ref inst) => {
+ inst.is_opaque(ctx, item)
+ }
+ TypeKind::Comp(ref comp) => comp.is_opaque(ctx, &self.layout),
+ TypeKind::ResolvedTypeRef(to) => to.is_opaque(ctx, &()),
+ _ => false,
+ }
+ }
+}
+
+impl AsTemplateParam for Type {
+ type Extra = Item;
+
+ fn as_template_param(
+ &self,
+ ctx: &BindgenContext,
+ item: &Item,
+ ) -> Option<TypeId> {
+ self.kind.as_template_param(ctx, item)
+ }
+}
+
+impl AsTemplateParam for TypeKind {
+ type Extra = Item;
+
+ fn as_template_param(
+ &self,
+ ctx: &BindgenContext,
+ item: &Item,
+ ) -> Option<TypeId> {
+ match *self {
+ TypeKind::TypeParam => Some(item.id().expect_type_id(ctx)),
+ TypeKind::ResolvedTypeRef(id) => id.as_template_param(ctx, &()),
+ _ => None,
+ }
+ }
+}
+
+impl DotAttributes for Type {
+ fn dot_attributes<W>(
+ &self,
+ ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ if let Some(ref layout) = self.layout {
+ writeln!(
+ out,
+ "<tr><td>size</td><td>{}</td></tr>
+ <tr><td>align</td><td>{}</td></tr>",
+ layout.size, layout.align
+ )?;
+ if layout.packed {
+ writeln!(out, "<tr><td>packed</td><td>true</td></tr>")?;
+ }
+ }
+
+ if self.is_const {
+ writeln!(out, "<tr><td>const</td><td>true</td></tr>")?;
+ }
+
+ self.kind.dot_attributes(ctx, out)
+ }
+}
+
+impl DotAttributes for TypeKind {
+ fn dot_attributes<W>(
+ &self,
+ ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ writeln!(
+ out,
+ "<tr><td>type kind</td><td>{}</td></tr>",
+ self.kind_name()
+ )?;
+
+ if let TypeKind::Comp(ref comp) = *self {
+ comp.dot_attributes(ctx, out)?;
+ }
+
+ Ok(())
+ }
+}
+
+impl TypeKind {
+ fn kind_name(&self) -> &'static str {
+ match *self {
+ TypeKind::Void => "Void",
+ TypeKind::NullPtr => "NullPtr",
+ TypeKind::Comp(..) => "Comp",
+ TypeKind::Opaque => "Opaque",
+ TypeKind::Int(..) => "Int",
+ TypeKind::Float(..) => "Float",
+ TypeKind::Complex(..) => "Complex",
+ TypeKind::Alias(..) => "Alias",
+ TypeKind::TemplateAlias(..) => "TemplateAlias",
+ TypeKind::Array(..) => "Array",
+ TypeKind::Vector(..) => "Vector",
+ TypeKind::Function(..) => "Function",
+ TypeKind::Enum(..) => "Enum",
+ TypeKind::Pointer(..) => "Pointer",
+ TypeKind::BlockPointer(..) => "BlockPointer",
+ TypeKind::Reference(..) => "Reference",
+ TypeKind::TemplateInstantiation(..) => "TemplateInstantiation",
+ TypeKind::UnresolvedTypeRef(..) => "UnresolvedTypeRef",
+ TypeKind::ResolvedTypeRef(..) => "ResolvedTypeRef",
+ TypeKind::TypeParam => "TypeParam",
+ TypeKind::ObjCInterface(..) => "ObjCInterface",
+ TypeKind::ObjCId => "ObjCId",
+ TypeKind::ObjCSel => "ObjCSel",
+ }
+ }
+}
+
+#[test]
+fn is_invalid_type_param_valid() {
+ let ty = Type::new(Some("foo".into()), None, TypeKind::TypeParam, false);
+ assert!(!ty.is_invalid_type_param())
+}
+
+#[test]
+fn is_invalid_type_param_valid_underscore_and_numbers() {
+ let ty = Type::new(
+ Some("_foo123456789_".into()),
+ None,
+ TypeKind::TypeParam,
+ false,
+ );
+ assert!(!ty.is_invalid_type_param())
+}
+
+#[test]
+fn is_invalid_type_param_valid_unnamed_kind() {
+ let ty = Type::new(Some("foo".into()), None, TypeKind::Void, false);
+ assert!(!ty.is_invalid_type_param())
+}
+
+#[test]
+fn is_invalid_type_param_invalid_start() {
+ let ty = Type::new(Some("1foo".into()), None, TypeKind::TypeParam, false);
+ assert!(ty.is_invalid_type_param())
+}
+
+#[test]
+fn is_invalid_type_param_invalid_remaing() {
+ let ty = Type::new(Some("foo-".into()), None, TypeKind::TypeParam, false);
+ assert!(ty.is_invalid_type_param())
+}
+
+#[test]
+#[should_panic]
+fn is_invalid_type_param_unnamed() {
+ let ty = Type::new(None, None, TypeKind::TypeParam, false);
+ assert!(ty.is_invalid_type_param())
+}
+
+#[test]
+fn is_invalid_type_param_empty_name() {
+ let ty = Type::new(Some("".into()), None, TypeKind::TypeParam, false);
+ assert!(ty.is_invalid_type_param())
+}
+
+impl TemplateParameters for Type {
+ fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
+ self.kind.self_template_params(ctx)
+ }
+}
+
+impl TemplateParameters for TypeKind {
+ fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> {
+ match *self {
+ TypeKind::ResolvedTypeRef(id) => {
+ ctx.resolve_type(id).self_template_params(ctx)
+ }
+ TypeKind::Comp(ref comp) => comp.self_template_params(ctx),
+ TypeKind::TemplateAlias(_, ref args) => args.clone(),
+
+ TypeKind::Opaque |
+ TypeKind::TemplateInstantiation(..) |
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(_) |
+ TypeKind::Float(_) |
+ TypeKind::Complex(_) |
+ TypeKind::Array(..) |
+ TypeKind::Vector(..) |
+ TypeKind::Function(_) |
+ TypeKind::Enum(_) |
+ TypeKind::Pointer(_) |
+ TypeKind::BlockPointer(_) |
+ TypeKind::Reference(_) |
+ TypeKind::UnresolvedTypeRef(..) |
+ TypeKind::TypeParam |
+ TypeKind::Alias(_) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel |
+ TypeKind::ObjCInterface(_) => vec![],
+ }
+ }
+}
+
+/// The kind of float this type represents.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub(crate) enum FloatKind {
+ /// A half (`_Float16` or `__fp16`)
+ Float16,
+ /// A `float`.
+ Float,
+ /// A `double`.
+ Double,
+ /// A `long double`.
+ LongDouble,
+ /// A `__float128`.
+ Float128,
+}
+
+/// The different kinds of types that we can parse.
+#[derive(Debug)]
+pub(crate) enum TypeKind {
+ /// The void type.
+ Void,
+
+ /// The `nullptr_t` type.
+ NullPtr,
+
+ /// A compound type, that is, a class, struct, or union.
+ Comp(CompInfo),
+
+ /// An opaque type that we just don't understand. All usage of this shoulf
+ /// result in an opaque blob of bytes generated from the containing type's
+ /// layout.
+ Opaque,
+
+ /// An integer type, of a given kind. `bool` and `char` are also considered
+ /// integers.
+ Int(IntKind),
+
+ /// A floating point type.
+ Float(FloatKind),
+
+ /// A complex floating point type.
+ Complex(FloatKind),
+
+ /// A type alias, with a name, that points to another type.
+ Alias(TypeId),
+
+ /// A templated alias, pointing to an inner type, just as `Alias`, but with
+ /// template parameters.
+ TemplateAlias(TypeId, Vec<TypeId>),
+
+ /// A packed vector type: element type, number of elements
+ Vector(TypeId, usize),
+
+ /// An array of a type and a length.
+ Array(TypeId, usize),
+
+ /// A function type, with a given signature.
+ Function(FunctionSig),
+
+ /// An `enum` type.
+ Enum(Enum),
+
+ /// A pointer to a type. The bool field represents whether it's const or
+ /// not.
+ Pointer(TypeId),
+
+ /// A pointer to an Apple block.
+ BlockPointer(TypeId),
+
+ /// A reference to a type, as in: int& foo().
+ Reference(TypeId),
+
+ /// An instantiation of an abstract template definition with a set of
+ /// concrete template arguments.
+ TemplateInstantiation(TemplateInstantiation),
+
+ /// A reference to a yet-to-resolve type. This stores the clang cursor
+ /// itself, and postpones its resolution.
+ ///
+ /// These are gone in a phase after parsing where these are mapped to
+ /// already known types, and are converted to ResolvedTypeRef.
+ ///
+ /// see tests/headers/typeref.hpp to see somewhere where this is a problem.
+ UnresolvedTypeRef(
+ clang::Type,
+ clang::Cursor,
+ /* parent_id */
+ Option<ItemId>,
+ ),
+
+ /// An indirection to another type.
+ ///
+ /// These are generated after we resolve a forward declaration, or when we
+ /// replace one type with another.
+ ResolvedTypeRef(TypeId),
+
+ /// A named type, that is, a template parameter.
+ TypeParam,
+
+ /// Objective C interface. Always referenced through a pointer
+ ObjCInterface(ObjCInterface),
+
+ /// Objective C 'id' type, points to any object
+ ObjCId,
+
+ /// Objective C selector type
+ ObjCSel,
+}
+
+impl Type {
+ /// This is another of the nasty methods. This one is the one that takes
+ /// care of the core logic of converting a clang type to a `Type`.
+ ///
+ /// It's sort of nasty and full of special-casing, but hopefully the
+ /// comments in every special case justify why they're there.
+ pub(crate) fn from_clang_ty(
+ potential_id: ItemId,
+ ty: &clang::Type,
+ location: Cursor,
+ parent_id: Option<ItemId>,
+ ctx: &mut BindgenContext,
+ ) -> Result<ParseResult<Self>, ParseError> {
+ use clang_sys::*;
+ {
+ let already_resolved = ctx.builtin_or_resolved_ty(
+ potential_id,
+ parent_id,
+ ty,
+ Some(location),
+ );
+ if let Some(ty) = already_resolved {
+ debug!("{:?} already resolved: {:?}", ty, location);
+ return Ok(ParseResult::AlreadyResolved(ty.into()));
+ }
+ }
+
+ let layout = ty.fallible_layout(ctx).ok();
+ let cursor = ty.declaration();
+ let is_anonymous = cursor.is_anonymous();
+ let mut name = if is_anonymous {
+ None
+ } else {
+ Some(cursor.spelling()).filter(|n| !n.is_empty())
+ };
+
+ debug!(
+ "from_clang_ty: {:?}, 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 = Some("id".to_owned());
+ }
+ }
+
+ if location.kind() == CXCursor_ClassTemplatePartialSpecialization {
+ // Sorry! (Not sorry)
+ warn!(
+ "Found a partial template specialization; bindgen does not \
+ support partial template specialization! Constructing \
+ opaque type instead."
+ );
+ return Ok(ParseResult::New(
+ Opaque::from_clang_ty(&canonical_ty, ctx),
+ None,
+ ));
+ }
+
+ let kind = if location.kind() == CXCursor_TemplateRef ||
+ (ty.template_args().is_some() && ty_kind != CXType_Typedef)
+ {
+ // This is a template instantiation.
+ match TemplateInstantiation::from_ty(ty, ctx) {
+ Some(inst) => TypeKind::TemplateInstantiation(inst),
+ None => TypeKind::Opaque,
+ }
+ } else {
+ match ty_kind {
+ CXType_Unexposed
+ if *ty != canonical_ty &&
+ canonical_ty.kind() != CXType_Invalid &&
+ ty.ret_type().is_none() &&
+ // Sometime clang desugars some types more than
+ // what we need, specially with function
+ // pointers.
+ //
+ // We should also try the solution of inverting
+ // those checks instead of doing this, that is,
+ // something like:
+ //
+ // CXType_Unexposed if ty.ret_type().is_some()
+ // => { ... }
+ //
+ // etc.
+ !canonical_ty.spelling().contains("type-parameter") =>
+ {
+ debug!("Looking for canonical type: {:?}", canonical_ty);
+ return Self::from_clang_ty(
+ potential_id,
+ &canonical_ty,
+ location,
+ parent_id,
+ ctx,
+ );
+ }
+ CXType_Unexposed | CXType_Invalid => {
+ // For some reason Clang doesn't give us any hint in some
+ // situations where we should generate a function pointer (see
+ // tests/headers/func_ptr_in_struct.h), so we do a guess here
+ // trying to see if it has a valid return type.
+ if ty.ret_type().is_some() {
+ let signature =
+ FunctionSig::from_ty(ty, &location, ctx)?;
+ TypeKind::Function(signature)
+ // Same here, with template specialisations we can safely
+ // assume this is a Comp(..)
+ } else if ty.is_fully_instantiated_template() {
+ debug!(
+ "Template specialization: {:?}, {:?} {:?}",
+ ty, location, canonical_ty
+ );
+ let complex = CompInfo::from_ty(
+ potential_id,
+ ty,
+ Some(location),
+ ctx,
+ )
+ .expect("C'mon");
+ TypeKind::Comp(complex)
+ } else {
+ match location.kind() {
+ CXCursor_CXXBaseSpecifier |
+ CXCursor_ClassTemplate => {
+ if location.kind() == CXCursor_CXXBaseSpecifier
+ {
+ // In the case we're parsing a base specifier
+ // inside an unexposed or invalid type, it means
+ // that we're parsing one of two things:
+ //
+ // * A template parameter.
+ // * A complex class that isn't exposed.
+ //
+ // This means, unfortunately, that there's no
+ // good way to differentiate between them.
+ //
+ // Probably we could try to look at the
+ // declaration and complicate more this logic,
+ // but we'll keep it simple... if it's a valid
+ // C++ identifier, we'll consider it as a
+ // template parameter.
+ //
+ // This is because:
+ //
+ // * We expect every other base that is a
+ // proper identifier (that is, a simple
+ // struct/union declaration), to be exposed,
+ // so this path can't be reached in that
+ // case.
+ //
+ // * Quite conveniently, complex base
+ // specifiers preserve their full names (that
+ // is: Foo<T> instead of Foo). We can take
+ // advantage of this.
+ //
+ // If we find some edge case where this doesn't
+ // work (which I guess is unlikely, see the
+ // different test cases[1][2][3][4]), we'd need
+ // to find more creative ways of differentiating
+ // these two cases.
+ //
+ // [1]: inherit_named.hpp
+ // [2]: forward-inherit-struct-with-fields.hpp
+ // [3]: forward-inherit-struct.hpp
+ // [4]: inherit-namespaced.hpp
+ if location.spelling().chars().all(|c| {
+ c.is_alphanumeric() || c == '_'
+ }) {
+ return Err(ParseError::Recurse);
+ }
+ } else {
+ name = Some(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 = Some(location.spelling());
+
+ let inner_ty = cur
+ .typedef_type()
+ .expect("Not valid Type?");
+ inner = Ok(Item::from_ty_or_ref(
+ inner_ty,
+ cur,
+ Some(potential_id),
+ ctx,
+ ));
+ }
+ CXCursor_TemplateTypeParameter => {
+ let param = Item::type_param(
+ None, cur, ctx,
+ )
+ .expect(
+ "Item::type_param shouldn't \
+ ever fail if we are looking \
+ at a TemplateTypeParameter",
+ );
+ args.push(param);
+ }
+ _ => {}
+ }
+ CXChildVisit_Continue
+ });
+
+ let inner_type = match inner {
+ Ok(inner) => inner,
+ Err(..) => {
+ warn!(
+ "Failed to parse template alias \
+ {:?}",
+ location
+ );
+ return Err(ParseError::Continue);
+ }
+ };
+
+ TypeKind::TemplateAlias(inner_type, args)
+ }
+ CXCursor_TemplateRef => {
+ let referenced = location.referenced().unwrap();
+ let referenced_ty = referenced.cur_type();
+
+ debug!(
+ "TemplateRef: location = {:?}; referenced = \
+ {:?}; referenced_ty = {:?}",
+ location,
+ referenced,
+ referenced_ty
+ );
+
+ return Self::from_clang_ty(
+ potential_id,
+ &referenced_ty,
+ referenced,
+ parent_id,
+ ctx,
+ );
+ }
+ CXCursor_TypeRef => {
+ let referenced = location.referenced().unwrap();
+ let referenced_ty = referenced.cur_type();
+ let declaration = referenced_ty.declaration();
+
+ debug!(
+ "TypeRef: location = {:?}; referenced = \
+ {:?}; referenced_ty = {:?}",
+ location, referenced, referenced_ty
+ );
+
+ let id = Item::from_ty_or_ref_with_id(
+ potential_id,
+ referenced_ty,
+ declaration,
+ parent_id,
+ ctx,
+ );
+ return Ok(ParseResult::AlreadyResolved(
+ id.into(),
+ ));
+ }
+ CXCursor_NamespaceRef => {
+ return Err(ParseError::Continue);
+ }
+ _ => {
+ if ty.kind() == CXType_Unexposed {
+ warn!(
+ "Unexposed type {:?}, recursing inside, \
+ loc: {:?}",
+ ty,
+ location
+ );
+ return Err(ParseError::Recurse);
+ }
+
+ warn!("invalid type {:?}", ty);
+ return Err(ParseError::Continue);
+ }
+ }
+ }
+ }
+ CXType_Auto => {
+ if canonical_ty == *ty {
+ debug!("Couldn't find deduced type: {:?}", ty);
+ return Err(ParseError::Continue);
+ }
+
+ return Self::from_clang_ty(
+ potential_id,
+ &canonical_ty,
+ location,
+ parent_id,
+ ctx,
+ );
+ }
+ // NOTE: We don't resolve pointers eagerly because the pointee type
+ // might not have been parsed, and if it contains templates or
+ // something else we might get confused, see the comment inside
+ // TypeRef.
+ //
+ // We might need to, though, if the context is already in the
+ // process of resolving them.
+ CXType_ObjCObjectPointer |
+ CXType_MemberPointer |
+ CXType_Pointer => {
+ let mut pointee = ty.pointee_type().unwrap();
+ if *ty != canonical_ty {
+ let canonical_pointee =
+ canonical_ty.pointee_type().unwrap();
+ // clang sometimes loses pointee constness here, see
+ // #2244.
+ if canonical_pointee.is_const() != pointee.is_const() {
+ pointee = canonical_pointee;
+ }
+ }
+ let inner =
+ Item::from_ty_or_ref(pointee, location, None, ctx);
+ TypeKind::Pointer(inner)
+ }
+ CXType_BlockPointer => {
+ let pointee = ty.pointee_type().expect("Not valid Type?");
+ let inner =
+ Item::from_ty_or_ref(pointee, location, None, ctx);
+ TypeKind::BlockPointer(inner)
+ }
+ // XXX: RValueReference is most likely wrong, but I don't think we
+ // can even add bindings for that, so huh.
+ CXType_RValueReference | CXType_LValueReference => {
+ let inner = Item::from_ty_or_ref(
+ ty.pointee_type().unwrap(),
+ location,
+ None,
+ ctx,
+ );
+ TypeKind::Reference(inner)
+ }
+ // XXX DependentSizedArray is wrong
+ CXType_VariableArray | CXType_DependentSizedArray => {
+ let inner = Item::from_ty(
+ ty.elem_type().as_ref().unwrap(),
+ location,
+ None,
+ ctx,
+ )
+ .expect("Not able to resolve array element?");
+ TypeKind::Pointer(inner)
+ }
+ CXType_IncompleteArray => {
+ let inner = Item::from_ty(
+ ty.elem_type().as_ref().unwrap(),
+ location,
+ None,
+ ctx,
+ )
+ .expect("Not able to resolve array element?");
+ TypeKind::Array(inner, 0)
+ }
+ CXType_FunctionNoProto | CXType_FunctionProto => {
+ let signature = FunctionSig::from_ty(ty, &location, ctx)?;
+ TypeKind::Function(signature)
+ }
+ CXType_Typedef => {
+ let inner = cursor.typedef_type().expect("Not valid Type?");
+ let inner_id =
+ Item::from_ty_or_ref(inner, location, None, ctx);
+ if inner_id == potential_id {
+ warn!(
+ "Generating oqaque type instead of self-referential \
+ typedef");
+ // This can happen if we bail out of recursive situations
+ // within the clang parsing.
+ TypeKind::Opaque
+ } else {
+ // Check if this type definition is an alias to a pointer of a `struct` /
+ // `union` / `enum` with the same name and add the `_ptr` suffix to it to
+ // avoid name collisions.
+ if let Some(ref mut name) = name {
+ if inner.kind() == CXType_Pointer &&
+ !ctx.options().c_naming
+ {
+ let pointee = inner.pointee_type().unwrap();
+ if pointee.kind() == CXType_Elaborated &&
+ pointee.declaration().spelling() == *name
+ {
+ *name += "_ptr";
+ }
+ }
+ }
+ TypeKind::Alias(inner_id)
+ }
+ }
+ CXType_Enum => {
+ let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
+
+ if !is_anonymous {
+ let pretty_name = ty.spelling();
+ if clang::is_valid_identifier(&pretty_name) {
+ name = Some(pretty_name);
+ }
+ }
+
+ TypeKind::Enum(enum_)
+ }
+ CXType_Record => {
+ let complex = CompInfo::from_ty(
+ potential_id,
+ ty,
+ Some(location),
+ ctx,
+ )
+ .expect("Not a complex type?");
+
+ if !is_anonymous {
+ // The pretty-printed name may contain typedefed name,
+ // but may also be "struct (anonymous at .h:1)"
+ let pretty_name = ty.spelling();
+ if clang::is_valid_identifier(&pretty_name) {
+ name = Some(pretty_name);
+ }
+ }
+
+ TypeKind::Comp(complex)
+ }
+ CXType_Vector => {
+ let inner = Item::from_ty(
+ ty.elem_type().as_ref().unwrap(),
+ location,
+ None,
+ ctx,
+ )?;
+ TypeKind::Vector(inner, ty.num_elements().unwrap())
+ }
+ CXType_ConstantArray => {
+ let inner = Item::from_ty(
+ ty.elem_type().as_ref().unwrap(),
+ location,
+ None,
+ ctx,
+ )
+ .expect("Not able to resolve array element?");
+ TypeKind::Array(inner, ty.num_elements().unwrap())
+ }
+ CXType_Elaborated => {
+ return Self::from_clang_ty(
+ potential_id,
+ &ty.named(),
+ location,
+ parent_id,
+ ctx,
+ );
+ }
+ CXType_ObjCId => TypeKind::ObjCId,
+ CXType_ObjCSel => TypeKind::ObjCSel,
+ CXType_ObjCClass | CXType_ObjCInterface => {
+ let interface = ObjCInterface::from_ty(&location, ctx)
+ .expect("Not a valid objc interface?");
+ if !is_anonymous {
+ name = Some(interface.rust_name());
+ }
+ TypeKind::ObjCInterface(interface)
+ }
+ CXType_Dependent => {
+ return Err(ParseError::Continue);
+ }
+ _ => {
+ warn!(
+ "unsupported type: kind = {:?}; ty = {:?}; at {:?}",
+ ty.kind(),
+ ty,
+ location
+ );
+ return Err(ParseError::Continue);
+ }
+ }
+ };
+
+ name = name.filter(|n| !n.is_empty());
+
+ let is_const = ty.is_const() ||
+ (ty.kind() == CXType_ConstantArray &&
+ ty.elem_type()
+ .map_or(false, |element| element.is_const()));
+
+ let ty = Type::new(name, layout, kind, is_const);
+ // TODO: maybe declaration.canonical()?
+ Ok(ParseResult::New(ty, Some(cursor.canonical())))
+ }
+}
+
+impl Trace for Type {
+ type Extra = Item;
+
+ fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item)
+ where
+ T: Tracer,
+ {
+ if self
+ .name()
+ .map_or(false, |name| context.is_stdint_type(name))
+ {
+ // These types are special-cased in codegen and don't need to be traversed.
+ return;
+ }
+ match *self.kind() {
+ TypeKind::Pointer(inner) |
+ TypeKind::Reference(inner) |
+ TypeKind::Array(inner, _) |
+ TypeKind::Vector(inner, _) |
+ TypeKind::BlockPointer(inner) |
+ TypeKind::Alias(inner) |
+ TypeKind::ResolvedTypeRef(inner) => {
+ tracer.visit_kind(inner.into(), EdgeKind::TypeReference);
+ }
+ TypeKind::TemplateAlias(inner, ref template_params) => {
+ tracer.visit_kind(inner.into(), EdgeKind::TypeReference);
+ for param in template_params {
+ tracer.visit_kind(
+ param.into(),
+ EdgeKind::TemplateParameterDefinition,
+ );
+ }
+ }
+ TypeKind::TemplateInstantiation(ref inst) => {
+ inst.trace(context, tracer, &());
+ }
+ TypeKind::Comp(ref ci) => ci.trace(context, tracer, item),
+ TypeKind::Function(ref sig) => sig.trace(context, tracer, &()),
+ TypeKind::Enum(ref en) => {
+ if let Some(repr) = en.repr() {
+ tracer.visit(repr.into());
+ }
+ }
+ TypeKind::UnresolvedTypeRef(_, _, Some(id)) => {
+ tracer.visit(id);
+ }
+
+ TypeKind::ObjCInterface(ref interface) => {
+ interface.trace(context, tracer, &());
+ }
+
+ // None of these variants have edges to other items and types.
+ TypeKind::Opaque |
+ TypeKind::UnresolvedTypeRef(_, _, None) |
+ TypeKind::TypeParam |
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Int(_) |
+ TypeKind::Float(_) |
+ TypeKind::Complex(_) |
+ TypeKind::ObjCId |
+ TypeKind::ObjCSel => {}
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/ir/var.rs b/third_party/rust/bindgen/ir/var.rs
new file mode 100644
index 0000000000..a548ec881b
--- /dev/null
+++ b/third_party/rust/bindgen/ir/var.rs
@@ -0,0 +1,488 @@
+//! Intermediate representation of variables.
+
+use super::super::codegen::MacroTypeVariation;
+use super::context::{BindgenContext, TypeId};
+use super::dot::DotAttributes;
+use super::function::cursor_mangling;
+use super::int::IntKind;
+use super::item::Item;
+use super::ty::{FloatKind, TypeKind};
+use crate::callbacks::{ItemInfo, ItemKind, MacroParsingBehavior};
+use crate::clang;
+use crate::clang::ClangToken;
+use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
+
+use std::io;
+use std::num::Wrapping;
+
+/// The type for a constant variable.
+#[derive(Debug)]
+pub(crate) enum VarType {
+ /// A boolean.
+ Bool(bool),
+ /// An integer.
+ Int(i64),
+ /// A floating point number.
+ Float(f64),
+ /// A character.
+ Char(u8),
+ /// A string, not necessarily well-formed utf-8.
+ String(Vec<u8>),
+}
+
+/// A `Var` is our intermediate representation of a variable.
+#[derive(Debug)]
+pub(crate) struct Var {
+ /// The name of the variable.
+ name: String,
+ /// The mangled name of the variable.
+ mangled_name: Option<String>,
+ /// The link name of the variable.
+ link_name: Option<String>,
+ /// The type of the variable.
+ ty: TypeId,
+ /// The value of the variable, that needs to be suitable for `ty`.
+ val: Option<VarType>,
+ /// Whether this variable is const.
+ is_const: bool,
+}
+
+impl Var {
+ /// Construct a new `Var`.
+ pub(crate) fn new(
+ name: String,
+ mangled_name: Option<String>,
+ link_name: Option<String>,
+ ty: TypeId,
+ val: Option<VarType>,
+ is_const: bool,
+ ) -> Var {
+ assert!(!name.is_empty());
+ Var {
+ name,
+ mangled_name,
+ link_name,
+ ty,
+ val,
+ is_const,
+ }
+ }
+
+ /// Is this variable `const` qualified?
+ pub(crate) fn is_const(&self) -> bool {
+ self.is_const
+ }
+
+ /// The value of this constant variable, if any.
+ pub(crate) fn val(&self) -> Option<&VarType> {
+ self.val.as_ref()
+ }
+
+ /// Get this variable's type.
+ pub(crate) fn ty(&self) -> TypeId {
+ self.ty
+ }
+
+ /// Get this variable's name.
+ pub(crate) fn name(&self) -> &str {
+ &self.name
+ }
+
+ /// Get this variable's mangled name.
+ pub(crate) fn mangled_name(&self) -> Option<&str> {
+ self.mangled_name.as_deref()
+ }
+
+ /// Get this variable's link name.
+ pub fn link_name(&self) -> Option<&str> {
+ self.link_name.as_deref()
+ }
+}
+
+impl DotAttributes for Var {
+ fn dot_attributes<W>(
+ &self,
+ _ctx: &BindgenContext,
+ out: &mut W,
+ ) -> io::Result<()>
+ where
+ W: io::Write,
+ {
+ if self.is_const {
+ writeln!(out, "<tr><td>const</td><td>true</td></tr>")?;
+ }
+
+ if let Some(ref mangled) = self.mangled_name {
+ writeln!(
+ out,
+ "<tr><td>mangled name</td><td>{}</td></tr>",
+ mangled
+ )?;
+ }
+
+ Ok(())
+ }
+}
+
+fn default_macro_constant_type(ctx: &BindgenContext, value: i64) -> IntKind {
+ if value < 0 ||
+ ctx.options().default_macro_constant_type ==
+ MacroTypeVariation::Signed
+ {
+ if value < i32::min_value() as i64 || value > i32::max_value() as i64 {
+ IntKind::I64
+ } else if !ctx.options().fit_macro_constants ||
+ value < i16::min_value() as i64 ||
+ value > i16::max_value() as i64
+ {
+ IntKind::I32
+ } else if value < i8::min_value() as i64 ||
+ value > i8::max_value() as i64
+ {
+ IntKind::I16
+ } else {
+ IntKind::I8
+ }
+ } else if value > u32::max_value() as i64 {
+ IntKind::U64
+ } else if !ctx.options().fit_macro_constants ||
+ value > u16::max_value() as i64
+ {
+ IntKind::U32
+ } else if value > u8::max_value() as i64 {
+ IntKind::U16
+ } else {
+ IntKind::U8
+ }
+}
+
+/// Parses tokens from a CXCursor_MacroDefinition pointing into a function-like
+/// macro, and calls the func_macro callback.
+fn handle_function_macro(
+ cursor: &clang::Cursor,
+ callbacks: &dyn crate::callbacks::ParseCallbacks,
+) {
+ let is_closing_paren = |t: &ClangToken| {
+ // Test cheap token kind before comparing exact spellings.
+ t.kind == clang_sys::CXToken_Punctuation && t.spelling() == b")"
+ };
+ let tokens: Vec<_> = cursor.tokens().iter().collect();
+ if let Some(boundary) = tokens.iter().position(is_closing_paren) {
+ let mut spelled = tokens.iter().map(ClangToken::spelling);
+ // Add 1, to convert index to length.
+ let left = spelled.by_ref().take(boundary + 1);
+ let left = left.collect::<Vec<_>>().concat();
+ if let Ok(left) = String::from_utf8(left) {
+ let right: Vec<_> = spelled.collect();
+ callbacks.func_macro(&left, &right);
+ }
+ }
+}
+
+impl ClangSubItemParser for Var {
+ fn parse(
+ cursor: clang::Cursor,
+ ctx: &mut BindgenContext,
+ ) -> Result<ParseResult<Self>, ParseError> {
+ use cexpr::expr::EvalResult;
+ use cexpr::literal::CChar;
+ use clang_sys::*;
+ match cursor.kind() {
+ CXCursor_MacroDefinition => {
+ for callbacks in &ctx.options().parse_callbacks {
+ match callbacks.will_parse_macro(&cursor.spelling()) {
+ MacroParsingBehavior::Ignore => {
+ return Err(ParseError::Continue);
+ }
+ MacroParsingBehavior::Default => {}
+ }
+
+ if cursor.is_macro_function_like() {
+ handle_function_macro(&cursor, callbacks.as_ref());
+ // We handled the macro, skip macro processing below.
+ return Err(ParseError::Continue);
+ }
+ }
+
+ let value = parse_macro(ctx, &cursor);
+
+ let (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();
+ duplicated_macro_diagnostic(&name, cursor.location(), ctx);
+ return Err(ParseError::Continue);
+ }
+
+ // NOTE: Unwrapping, here and above, is safe, because the
+ // identifier of a token comes straight from clang, and we
+ // enforce utf8 there, so we should have already panicked at
+ // this point.
+ let name = String::from_utf8(id).unwrap();
+ let (type_kind, val) = match value {
+ EvalResult::Invalid => return Err(ParseError::Continue),
+ EvalResult::Float(f) => {
+ (TypeKind::Float(FloatKind::Double), VarType::Float(f))
+ }
+ EvalResult::Char(c) => {
+ let c = match c {
+ CChar::Char(c) => {
+ assert_eq!(c.len_utf8(), 1);
+ c as u8
+ }
+ CChar::Raw(c) => {
+ assert!(c <= ::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,
+ );
+ for callbacks in &ctx.options().parse_callbacks {
+ callbacks.str_macro(&name, &val);
+ }
+ (TypeKind::Pointer(char_ty), VarType::String(val))
+ }
+ EvalResult::Int(Wrapping(value)) => {
+ let kind = ctx
+ .options()
+ .last_callback(|c| c.int_macro(&name, value))
+ .unwrap_or_else(|| {
+ default_macro_constant_type(ctx, value)
+ });
+
+ (TypeKind::Int(kind), VarType::Int(value))
+ }
+ };
+
+ let ty = Item::builtin_type(type_kind, true, ctx);
+
+ Ok(ParseResult::New(
+ Var::new(name, None, None, ty, Some(val), true),
+ Some(cursor),
+ ))
+ }
+ CXCursor_VarDecl => {
+ let mut name = cursor.spelling();
+ if cursor.linkage() == CXLinkage_External {
+ if let Some(nm) = ctx.options().last_callback(|callbacks| {
+ callbacks.generated_name_override(ItemInfo {
+ name: name.as_str(),
+ kind: ItemKind::Var,
+ })
+ }) {
+ name = nm;
+ }
+ }
+ // No more changes to name
+ let name = name;
+
+ if name.is_empty() {
+ warn!("Empty constant name?");
+ return Err(ParseError::Continue);
+ }
+
+ let link_name = ctx.options().last_callback(|callbacks| {
+ callbacks.generated_link_name_override(ItemInfo {
+ name: name.as_str(),
+ kind: ItemKind::Var,
+ })
+ });
+
+ let ty = cursor.cur_type();
+
+ // TODO(emilio): do we have to special-case constant arrays in
+ // some other places?
+ let is_const = ty.is_const() ||
+ ([CXType_ConstantArray, CXType_IncompleteArray]
+ .contains(&ty.kind()) &&
+ ty.elem_type()
+ .map_or(false, |element| element.is_const()));
+
+ let ty = match Item::from_ty(&ty, cursor, None, ctx) {
+ Ok(ty) => ty,
+ Err(e) => {
+ assert!(
+ matches!(ty.kind(), CXType_Auto | CXType_Unexposed),
+ "Couldn't resolve constant type, and it \
+ wasn't an nondeductible auto type or unexposed \
+ type!"
+ );
+ return Err(e);
+ }
+ };
+
+ // Note: Ty might not be totally resolved yet, see
+ // tests/headers/inner_const.hpp
+ //
+ // That's fine because in that case we know it's not a literal.
+ let canonical_ty = ctx
+ .safe_resolve_type(ty)
+ .and_then(|t| t.safe_canonical_type(ctx));
+
+ let is_integer = canonical_ty.map_or(false, |t| t.is_integer());
+ let is_float = canonical_ty.map_or(false, |t| t.is_float());
+
+ // TODO: We could handle `char` more gracefully.
+ // TODO: Strings, though the lookup is a bit more hard (we need
+ // to look at the canonical type of the pointee too, and check
+ // is char, u8, or i8 I guess).
+ let value = if is_integer {
+ let kind = match *canonical_ty.unwrap().kind() {
+ TypeKind::Int(kind) => kind,
+ _ => unreachable!(),
+ };
+
+ let mut val = cursor.evaluate().and_then(|v| v.as_int());
+ if val.is_none() || !kind.signedness_matches(val.unwrap()) {
+ val = get_integer_literal_from_cursor(&cursor);
+ }
+
+ val.map(|val| {
+ if kind == IntKind::Bool {
+ VarType::Bool(val != 0)
+ } else {
+ VarType::Int(val)
+ }
+ })
+ } else if is_float {
+ cursor
+ .evaluate()
+ .and_then(|v| v.as_double())
+ .map(VarType::Float)
+ } else {
+ cursor
+ .evaluate()
+ .and_then(|v| v.as_literal_string())
+ .map(VarType::String)
+ };
+
+ let mangling = cursor_mangling(ctx, &cursor);
+ let var =
+ Var::new(name, mangling, link_name, ty, value, is_const);
+
+ Ok(ParseResult::New(var, Some(cursor)))
+ }
+ _ => {
+ /* TODO */
+ Err(ParseError::Continue)
+ }
+ }
+ }
+}
+
+/// Try and parse a macro using all the macros parsed until now.
+fn parse_macro(
+ ctx: &BindgenContext,
+ cursor: &clang::Cursor,
+) -> Option<(Vec<u8>, cexpr::expr::EvalResult)> {
+ use cexpr::expr;
+
+ let cexpr_tokens = cursor.cexpr_tokens();
+
+ let parser = expr::IdentifierParser::new(ctx.parsed_macros());
+
+ match parser.macro_definition(&cexpr_tokens) {
+ Ok((_, (id, val))) => Some((id.into(), val)),
+ _ => None,
+ }
+}
+
+fn parse_int_literal_tokens(cursor: &clang::Cursor) -> Option<i64> {
+ use cexpr::expr;
+ use cexpr::expr::EvalResult;
+
+ let cexpr_tokens = cursor.cexpr_tokens();
+
+ // TODO(emilio): We can try to parse other kinds of literals.
+ match expr::expr(&cexpr_tokens) {
+ Ok((_, EvalResult::Int(Wrapping(val)))) => Some(val),
+ _ => None,
+ }
+}
+
+fn get_integer_literal_from_cursor(cursor: &clang::Cursor) -> Option<i64> {
+ use clang_sys::*;
+ let mut value = None;
+ cursor.visit(|c| {
+ match c.kind() {
+ CXCursor_IntegerLiteral | CXCursor_UnaryOperator => {
+ value = parse_int_literal_tokens(&c);
+ }
+ CXCursor_UnexposedExpr => {
+ value = get_integer_literal_from_cursor(&c);
+ }
+ _ => (),
+ }
+ if value.is_some() {
+ CXChildVisit_Break
+ } else {
+ CXChildVisit_Continue
+ }
+ });
+ value
+}
+
+fn duplicated_macro_diagnostic(
+ macro_name: &str,
+ _location: crate::clang::SourceLocation,
+ _ctx: &BindgenContext,
+) {
+ warn!("Duplicated macro definition: {}", macro_name);
+
+ #[cfg(feature = "experimental")]
+ // FIXME (pvdrz & amanjeev): This diagnostic message shows way too often to be actually
+ // useful. We have to change the logic where this function is called to be able to emit this
+ // message only when the duplication is an actuall issue.
+ //
+ // If I understood correctly, `bindgen` ignores all `#undef` directives. Meaning that this:
+ // ```c
+ // #define FOO 1
+ // #undef FOO
+ // #define FOO 2
+ // ```
+ //
+ // Will trigger this message even though there's nothing wrong with it.
+ #[allow(clippy::overly_complex_bool_expr)]
+ if false && _ctx.options().emit_diagnostics {
+ use crate::diagnostics::{get_line, Diagnostic, Level, Slice};
+ use std::borrow::Cow;
+
+ let mut slice = Slice::default();
+ let mut source = Cow::from(macro_name);
+
+ let (file, line, col, _) = _location.location();
+ if let Some(filename) = file.name() {
+ if let Ok(Some(code)) = get_line(&filename, line) {
+ source = code.into();
+ }
+ slice.with_location(filename, line, col);
+ }
+
+ slice.with_source(source);
+
+ Diagnostic::default()
+ .with_title("Duplicated macro definition.", Level::Warn)
+ .add_slice(slice)
+ .add_annotation("This macro had a duplicate.", Level::Note)
+ .display();
+ }
+}
diff --git a/third_party/rust/bindgen/lib.rs b/third_party/rust/bindgen/lib.rs
new file mode 100644
index 0000000000..c4ab11486c
--- /dev/null
+++ b/third_party/rust/bindgen/lib.rs
@@ -0,0 +1,1380 @@
+//! Generate Rust bindings for C and C++ libraries.
+//!
+//! Provide a C/C++ header file, receive Rust FFI code to call into C/C++
+//! functions and use types defined in the header.
+//!
+//! See the [`Builder`](./struct.Builder.html) struct for usage.
+//!
+//! See the [Users Guide](https://rust-lang.github.io/rust-bindgen/) for
+//! additional documentation.
+#![deny(missing_docs)]
+#![deny(unused_extern_crates)]
+#![deny(clippy::disallowed_methods)]
+// To avoid rather annoying warnings when matching with CXCursor_xxx as a
+// constant.
+#![allow(non_upper_case_globals)]
+// `quote!` nests quite deeply.
+#![recursion_limit = "128"]
+
+#[macro_use]
+extern crate bitflags;
+#[macro_use]
+extern crate 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;
+
+mod codegen;
+mod deps;
+mod options;
+mod time;
+
+pub mod callbacks;
+
+mod clang;
+#[cfg(feature = "experimental")]
+mod diagnostics;
+mod features;
+mod ir;
+mod parse;
+mod regex_set;
+
+pub use codegen::{
+ AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle,
+};
+#[cfg(feature = "__cli")]
+pub use features::RUST_TARGET_STRINGS;
+pub use features::{RustTarget, LATEST_STABLE_RUST};
+pub use ir::annotations::FieldVisibilityKind;
+pub use ir::function::Abi;
+pub use regex_set::RegexSet;
+
+use codegen::CodegenError;
+use features::RustFeatures;
+use ir::comment;
+use ir::context::{BindgenContext, ItemId};
+use ir::item::Item;
+use options::BindgenOptions;
+use parse::ParseError;
+
+use std::borrow::Cow;
+use std::collections::hash_map::Entry;
+use std::env;
+use std::ffi::OsStr;
+use std::fs::{File, OpenOptions};
+use std::io::{self, Write};
+use std::path::{Path, PathBuf};
+use std::process::{Command, Stdio};
+use std::rc::Rc;
+use std::str::FromStr;
+
+// Some convenient typedefs for a fast hash map and hash set.
+type HashMap<K, V> = rustc_hash::FxHashMap<K, V>;
+type HashSet<K> = rustc_hash::FxHashSet<K>;
+
+/// Default prefix for the anon fields.
+pub const DEFAULT_ANON_FIELDS_PREFIX: &str = "__bindgen_anon_";
+
+const DEFAULT_NON_EXTERN_FNS_SUFFIX: &str = "__extern";
+
+fn file_is_cpp(name_file: &str) -> bool {
+ name_file.ends_with(".hpp") ||
+ name_file.ends_with(".hxx") ||
+ name_file.ends_with(".hh") ||
+ name_file.ends_with(".h++")
+}
+
+fn args_are_cpp(clang_args: &[Box<str>]) -> bool {
+ for w in clang_args.windows(2) {
+ if w[0].as_ref() == "-xc++" || w[1].as_ref() == "-xc++" {
+ return true;
+ }
+ if w[0].as_ref() == "-x" && w[1].as_ref() == "c++" {
+ return true;
+ }
+ if w[0].as_ref() == "-include" && file_is_cpp(w[1].as_ref()) {
+ return true;
+ }
+ }
+ false
+}
+
+bitflags! {
+ /// A type used to indicate which kind of items we have to generate.
+ #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+ pub struct CodegenConfig: u32 {
+ /// Whether to generate functions.
+ const FUNCTIONS = 1 << 0;
+ /// Whether to generate types.
+ const TYPES = 1 << 1;
+ /// Whether to generate constants.
+ const VARS = 1 << 2;
+ /// Whether to generate methods.
+ const METHODS = 1 << 3;
+ /// Whether to generate constructors
+ const CONSTRUCTORS = 1 << 4;
+ /// Whether to generate destructors.
+ const DESTRUCTORS = 1 << 5;
+ }
+}
+
+impl CodegenConfig {
+ /// Returns true if functions should be generated.
+ pub fn functions(self) -> bool {
+ self.contains(CodegenConfig::FUNCTIONS)
+ }
+
+ /// Returns true if types should be generated.
+ pub fn types(self) -> bool {
+ self.contains(CodegenConfig::TYPES)
+ }
+
+ /// Returns true if constants should be generated.
+ pub fn vars(self) -> bool {
+ self.contains(CodegenConfig::VARS)
+ }
+
+ /// Returns true if 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()
+ }
+}
+
+/// Formatting tools that can be used to format the bindings
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[non_exhaustive]
+pub enum Formatter {
+ /// Do not format the bindings.
+ None,
+ /// Use `rustfmt` to format the bindings.
+ Rustfmt,
+ #[cfg(feature = "prettyplease")]
+ /// Use `prettyplease` to format the bindings.
+ Prettyplease,
+}
+
+impl Default for Formatter {
+ fn default() -> Self {
+ Self::Rustfmt
+ }
+}
+
+impl FromStr for Formatter {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "none" => Ok(Self::None),
+ "rustfmt" => Ok(Self::Rustfmt),
+ #[cfg(feature = "prettyplease")]
+ "prettyplease" => Ok(Self::Prettyplease),
+ _ => Err(format!("`{}` is not a valid formatter", s)),
+ }
+ }
+}
+
+impl std::fmt::Display for Formatter {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let s = match self {
+ Self::None => "none",
+ Self::Rustfmt => "rustfmt",
+ #[cfg(feature = "prettyplease")]
+ Self::Prettyplease => "prettyplease",
+ };
+
+ s.fmt(f)
+ }
+}
+
+/// Configure and generate Rust bindings for a C/C++ header.
+///
+/// This is the main entry point to the library.
+///
+/// ```ignore
+/// use bindgen::builder;
+///
+/// // Configure and generate bindings.
+/// let bindings = builder().header("path/to/input/header")
+/// .allowlist_type("SomeCoolClass")
+/// .allowlist_function("do_some_cool_thing")
+/// .generate()?;
+///
+/// // Write the generated bindings to an output file.
+/// bindings.write_to_file("path/to/output.rs")?;
+/// ```
+///
+/// # Enums
+///
+/// Bindgen can map C/C++ enums into Rust in different ways. The way bindgen maps enums depends on
+/// the pattern passed to several methods:
+///
+/// 1. [`constified_enum_module()`](#method.constified_enum_module)
+/// 2. [`bitfield_enum()`](#method.bitfield_enum)
+/// 3. [`newtype_enum()`](#method.newtype_enum)
+/// 4. [`rustified_enum()`](#method.rustified_enum)
+///
+/// For each C enum, bindgen tries to match the pattern in the following order:
+///
+/// 1. Constified enum module
+/// 2. Bitfield enum
+/// 3. Newtype enum
+/// 4. Rustified enum
+///
+/// If none of the above patterns match, then bindgen will generate a set of Rust constants.
+///
+/// # Clang arguments
+///
+/// Extra arguments can be passed to with clang:
+/// 1. [`clang_arg()`](#method.clang_arg): takes a single argument
+/// 2. [`clang_args()`](#method.clang_args): takes an iterator of arguments
+/// 3. `BINDGEN_EXTRA_CLANG_ARGS` environment variable: whitespace separate
+/// environment variable of arguments
+///
+/// Clang arguments specific to your crate should be added via the
+/// `clang_arg()`/`clang_args()` methods.
+///
+/// End-users of the crate may need to set the `BINDGEN_EXTRA_CLANG_ARGS` environment variable to
+/// add additional arguments. For example, to build against a different sysroot a user could set
+/// `BINDGEN_EXTRA_CLANG_ARGS` to `--sysroot=/path/to/sysroot`.
+///
+/// # Regular expression arguments
+///
+/// Some [`Builder`] methods, such as `allowlist_*` and `blocklist_*`, allow regular
+/// expressions as arguments. These regular expressions will be enclosed in parentheses and
+/// anchored with `^` and `$`. So, if the argument passed is `<regex>`, the regular expression to be
+/// stored will be `^(<regex>)$`.
+///
+/// As a consequence, regular expressions passed to `bindgen` will try to match the whole name of
+/// an item instead of a section of it, which means that to match any items with the prefix
+/// `prefix`, the `prefix.*` regular expression must be used.
+///
+/// Certain methods, like [`Builder::allowlist_function`], use regular expressions over function
+/// names. To match C++ methods, prefix the name of the type where they belong, followed by an
+/// underscore. So, if the type `Foo` has a method `bar`, it can be matched with the `Foo_bar`
+/// regular expression.
+///
+/// Additionally, Objective-C interfaces can be matched by prefixing the regular expression with
+/// `I`. For example, the `IFoo` regular expression matches the `Foo` interface, and the `IFoo_foo`
+/// regular expression matches the `foo` method of the `Foo` interface.
+///
+/// Releases of `bindgen` with a version lesser or equal to `0.62.0` used to accept the wildcard
+/// pattern `*` as a valid regular expression. This behavior has been deprecated, and the `.*`
+/// regular expression must be used instead.
+#[derive(Debug, Default, Clone)]
+pub struct Builder {
+ options: BindgenOptions,
+}
+
+/// Construct a new [`Builder`](./struct.Builder.html).
+pub fn builder() -> Builder {
+ Default::default()
+}
+
+fn get_extra_clang_args(
+ parse_callbacks: &[Rc<dyn callbacks::ParseCallbacks>],
+) -> Vec<String> {
+ // Add any extra arguments from the environment to the clang command line.
+ let extra_clang_args = match get_target_dependent_env_var(
+ parse_callbacks,
+ "BINDGEN_EXTRA_CLANG_ARGS",
+ ) {
+ None => return vec![],
+ Some(s) => s,
+ };
+
+ // Try to parse it with shell quoting. If we fail, make it one single big argument.
+ if let Some(strings) = shlex::split(&extra_clang_args) {
+ return strings;
+ }
+ vec![extra_clang_args]
+}
+
+impl Builder {
+ /// Generate the Rust bindings using the options built up thus far.
+ pub fn generate(mut self) -> Result<Bindings, BindgenError> {
+ // Add any extra arguments from the environment to the clang command line.
+ self.options.clang_args.extend(
+ get_extra_clang_args(&self.options.parse_callbacks)
+ .into_iter()
+ .map(String::into_boxed_str),
+ );
+
+ for header in &self.options.input_headers {
+ self.options
+ .for_each_callback(|cb| cb.header_file(header.as_ref()));
+ }
+
+ // Transform input headers to arguments on the clang command line.
+ self.options.clang_args.extend(
+ self.options.input_headers
+ [..self.options.input_headers.len().saturating_sub(1)]
+ .iter()
+ .flat_map(|header| ["-include".into(), header.clone()]),
+ );
+
+ let input_unsaved_files =
+ std::mem::take(&mut self.options.input_header_contents)
+ .into_iter()
+ .map(|(name, contents)| {
+ clang::UnsavedFile::new(name.as_ref(), contents.as_ref())
+ })
+ .collect::<Vec<_>>();
+
+ Bindings::generate(self.options, input_unsaved_files)
+ }
+
+ /// Preprocess and dump the input header files to disk.
+ ///
+ /// This is useful when debugging bindgen, using C-Reduce, or when filing
+ /// issues. The resulting file will be named something like `__bindgen.i` or
+ /// `__bindgen.ii`
+ pub fn dump_preprocessed_input(&self) -> io::Result<()> {
+ let clang =
+ clang_sys::support::Clang::find(None, &[]).ok_or_else(|| {
+ io::Error::new(
+ io::ErrorKind::Other,
+ "Cannot find clang executable",
+ )
+ })?;
+
+ // The contents of a wrapper file that includes all the input header
+ // files.
+ let mut wrapper_contents = String::new();
+
+ // Whether we are working with C or C++ inputs.
+ let mut is_cpp = args_are_cpp(&self.options.clang_args);
+
+ // For each input header, add `#include "$header"`.
+ for header in &self.options.input_headers {
+ is_cpp |= file_is_cpp(header);
+
+ wrapper_contents.push_str("#include \"");
+ wrapper_contents.push_str(header);
+ wrapper_contents.push_str("\"\n");
+ }
+
+ // For each input header content, add a prefix line of `#line 0 "$name"`
+ // followed by the contents.
+ for (name, contents) in &self.options.input_header_contents {
+ is_cpp |= file_is_cpp(name);
+
+ wrapper_contents.push_str("#line 0 \"");
+ wrapper_contents.push_str(name);
+ wrapper_contents.push_str("\"\n");
+ wrapper_contents.push_str(contents);
+ }
+
+ let wrapper_path = PathBuf::from(if is_cpp {
+ "__bindgen.cpp"
+ } else {
+ "__bindgen.c"
+ });
+
+ {
+ let mut wrapper_file = File::create(&wrapper_path)?;
+ wrapper_file.write_all(wrapper_contents.as_bytes())?;
+ }
+
+ let mut cmd = Command::new(clang.path);
+ cmd.arg("-save-temps")
+ .arg("-E")
+ .arg("-C")
+ .arg("-c")
+ .arg(&wrapper_path)
+ .stdout(Stdio::piped());
+
+ for a in &self.options.clang_args {
+ cmd.arg(a.as_ref());
+ }
+
+ for a in get_extra_clang_args(&self.options.parse_callbacks) {
+ cmd.arg(a);
+ }
+
+ let mut child = cmd.spawn()?;
+
+ let mut preprocessed = child.stdout.take().unwrap();
+ let mut file = File::create(if is_cpp {
+ "__bindgen.ii"
+ } else {
+ "__bindgen.i"
+ })?;
+ io::copy(&mut preprocessed, &mut file)?;
+
+ if child.wait()?.success() {
+ Ok(())
+ } else {
+ Err(io::Error::new(
+ io::ErrorKind::Other,
+ "clang exited with non-zero status",
+ ))
+ }
+ }
+}
+
+impl BindgenOptions {
+ fn build(&mut self) {
+ const REGEX_SETS_LEN: usize = 29;
+
+ let regex_sets: [_; REGEX_SETS_LEN] = [
+ &mut self.blocklisted_types,
+ &mut self.blocklisted_functions,
+ &mut self.blocklisted_items,
+ &mut self.blocklisted_files,
+ &mut self.blocklisted_vars,
+ &mut self.opaque_types,
+ &mut self.allowlisted_vars,
+ &mut self.allowlisted_types,
+ &mut self.allowlisted_functions,
+ &mut self.allowlisted_files,
+ &mut self.allowlisted_items,
+ &mut self.bitfield_enums,
+ &mut self.constified_enums,
+ &mut self.constified_enum_modules,
+ &mut self.newtype_enums,
+ &mut self.newtype_global_enums,
+ &mut self.rustified_enums,
+ &mut self.rustified_non_exhaustive_enums,
+ &mut self.type_alias,
+ &mut self.new_type_alias,
+ &mut self.new_type_alias_deref,
+ &mut self.bindgen_wrapper_union,
+ &mut self.manually_drop_union,
+ &mut self.no_partialeq_types,
+ &mut self.no_copy_types,
+ &mut self.no_debug_types,
+ &mut self.no_default_types,
+ &mut self.no_hash_types,
+ &mut self.must_use_types,
+ ];
+
+ let record_matches = self.record_matches;
+ #[cfg(feature = "experimental")]
+ {
+ let sets_len = REGEX_SETS_LEN + self.abi_overrides.len();
+ let names = if self.emit_diagnostics {
+ <[&str; REGEX_SETS_LEN]>::into_iter([
+ "--blocklist-type",
+ "--blocklist-function",
+ "--blocklist-item",
+ "--blocklist-file",
+ "--blocklist-var",
+ "--opaque-type",
+ "--allowlist-type",
+ "--allowlist-function",
+ "--allowlist-var",
+ "--allowlist-file",
+ "--allowlist-item",
+ "--bitfield-enum",
+ "--newtype-enum",
+ "--newtype-global-enum",
+ "--rustified-enum",
+ "--rustified-enum-non-exhaustive",
+ "--constified-enum-module",
+ "--constified-enum",
+ "--type-alias",
+ "--new-type-alias",
+ "--new-type-alias-deref",
+ "--bindgen-wrapper-union",
+ "--manually-drop-union",
+ "--no-partialeq",
+ "--no-copy",
+ "--no-debug",
+ "--no-default",
+ "--no-hash",
+ "--must-use",
+ ])
+ .chain((0..self.abi_overrides.len()).map(|_| "--override-abi"))
+ .map(Some)
+ .collect()
+ } else {
+ vec![None; sets_len]
+ };
+
+ for (regex_set, name) in
+ self.abi_overrides.values_mut().chain(regex_sets).zip(names)
+ {
+ regex_set.build_with_diagnostics(record_matches, name);
+ }
+ }
+ #[cfg(not(feature = "experimental"))]
+ for regex_set in self.abi_overrides.values_mut().chain(regex_sets) {
+ regex_set.build(record_matches);
+ }
+
+ let rust_target = self.rust_target;
+ #[allow(deprecated)]
+ if rust_target <= RustTarget::Stable_1_30 {
+ deprecated_target_diagnostic(rust_target, self);
+ }
+
+ // Disable `untagged_union` if the target does not support it.
+ if !self.rust_features.untagged_union {
+ self.untagged_union = false;
+ }
+ }
+
+ /// 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
+ }
+
+ fn last_callback<T>(
+ &self,
+ f: impl Fn(&dyn callbacks::ParseCallbacks) -> Option<T>,
+ ) -> Option<T> {
+ self.parse_callbacks
+ .iter()
+ .filter_map(|cb| f(cb.as_ref()))
+ .last()
+ }
+
+ fn all_callbacks<T>(
+ &self,
+ f: impl Fn(&dyn callbacks::ParseCallbacks) -> Vec<T>,
+ ) -> Vec<T> {
+ self.parse_callbacks
+ .iter()
+ .flat_map(|cb| f(cb.as_ref()))
+ .collect()
+ }
+
+ fn for_each_callback(&self, f: impl Fn(&dyn callbacks::ParseCallbacks)) {
+ self.parse_callbacks.iter().for_each(|cb| f(cb.as_ref()));
+ }
+
+ fn process_comment(&self, comment: &str) -> String {
+ let comment = comment::preprocess(comment);
+ self.parse_callbacks
+ .last()
+ .and_then(|cb| cb.process_comment(&comment))
+ .unwrap_or(comment)
+ }
+}
+
+fn deprecated_target_diagnostic(target: RustTarget, _options: &BindgenOptions) {
+ warn!("The {} Rust target is deprecated. If you have a need to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues", target);
+
+ #[cfg(feature = "experimental")]
+ if _options.emit_diagnostics {
+ use crate::diagnostics::{Diagnostic, Level};
+
+ let mut diagnostic = Diagnostic::default();
+ diagnostic.with_title(
+ format!("The {} Rust target is deprecated.", target),
+ Level::Warn,
+ );
+ diagnostic.add_annotation(
+ "This Rust target was passed to `--rust-target`",
+ Level::Info,
+ );
+ diagnostic.add_annotation("If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues", Level::Help);
+ diagnostic.display();
+ }
+}
+
+#[cfg(feature = "runtime")]
+fn ensure_libclang_is_loaded() {
+ if clang_sys::is_loaded() {
+ return;
+ }
+
+ // XXX (issue #350): Ensure that our dynamically loaded `libclang`
+ // doesn't get dropped prematurely, nor is loaded multiple times
+ // across different threads.
+
+ lazy_static! {
+ static ref LIBCLANG: std::sync::Arc<clang_sys::SharedLibrary> = {
+ clang_sys::load().expect("Unable to find libclang");
+ clang_sys::get_library().expect(
+ "We just loaded libclang and it had better still be \
+ here!",
+ )
+ };
+ }
+
+ clang_sys::set_library(Some(LIBCLANG.clone()));
+}
+
+#[cfg(not(feature = "runtime"))]
+fn ensure_libclang_is_loaded() {}
+
+/// Error type for rust-bindgen.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum BindgenError {
+ /// The header was a folder.
+ FolderAsHeader(PathBuf),
+ /// Permissions to read the header is insufficient.
+ InsufficientPermissions(PathBuf),
+ /// The header does not exist.
+ NotExist(PathBuf),
+ /// Clang diagnosed an error.
+ ClangDiagnostic(String),
+ /// Code generation reported an error.
+ Codegen(CodegenError),
+}
+
+impl std::fmt::Display for BindgenError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ BindgenError::FolderAsHeader(h) => {
+ write!(f, "'{}' is a folder", h.display())
+ }
+ BindgenError::InsufficientPermissions(h) => {
+ write!(f, "insufficient permissions to read '{}'", h.display())
+ }
+ BindgenError::NotExist(h) => {
+ write!(f, "header '{}' does not exist.", h.display())
+ }
+ BindgenError::ClangDiagnostic(message) => {
+ write!(f, "clang diagnosed error: {}", message)
+ }
+ BindgenError::Codegen(err) => {
+ write!(f, "codegen error: {}", err)
+ }
+ }
+ }
+}
+
+impl std::error::Error for BindgenError {}
+
+/// Generated Rust bindings.
+#[derive(Debug)]
+pub struct Bindings {
+ options: BindgenOptions,
+ module: proc_macro2::TokenStream,
+}
+
+pub(crate) const HOST_TARGET: &str =
+ include_str!(concat!(env!("OUT_DIR"), "/host-target.txt"));
+
+// Some architecture triplets are different between rust and libclang, see #1211
+// and duplicates.
+fn rust_to_clang_target(rust_target: &str) -> Box<str> {
+ if rust_target.starts_with("aarch64-apple-") {
+ let mut clang_target = "arm64-apple-".to_owned();
+ clang_target
+ .push_str(rust_target.strip_prefix("aarch64-apple-").unwrap());
+ return clang_target.into();
+ } else if rust_target.starts_with("riscv64gc-") {
+ let mut clang_target = "riscv64-".to_owned();
+ clang_target.push_str(rust_target.strip_prefix("riscv64gc-").unwrap());
+ return clang_target.into();
+ } else if rust_target.ends_with("-espidf") {
+ let mut clang_target =
+ rust_target.strip_suffix("-espidf").unwrap().to_owned();
+ clang_target.push_str("-elf");
+ if clang_target.starts_with("riscv32imc-") {
+ clang_target = "riscv32-".to_owned() +
+ clang_target.strip_prefix("riscv32imc-").unwrap();
+ }
+ return clang_target.into();
+ } else if rust_target.starts_with("riscv32imc-") {
+ let mut clang_target = "riscv32-".to_owned();
+ clang_target.push_str(rust_target.strip_prefix("riscv32imc-").unwrap());
+ return clang_target.into();
+ } else if rust_target.starts_with("riscv32imac-") {
+ let mut clang_target = "riscv32-".to_owned();
+ clang_target
+ .push_str(rust_target.strip_prefix("riscv32imac-").unwrap());
+ return clang_target.into();
+ }
+ rust_target.into()
+}
+
+/// Returns the effective target, and whether it was explicitly specified on the
+/// clang flags.
+fn find_effective_target(clang_args: &[Box<str>]) -> (Box<str>, bool) {
+ let mut args = clang_args.iter();
+ while let Some(opt) = args.next() {
+ if opt.starts_with("--target=") {
+ let mut split = opt.split('=');
+ split.next();
+ return (split.next().unwrap().into(), true);
+ }
+
+ if opt.as_ref() == "-target" {
+ if let Some(target) = args.next() {
+ return (target.clone(), true);
+ }
+ }
+ }
+
+ // If we're running from a build script, try to find the cargo target.
+ if let Ok(t) = env::var("TARGET") {
+ return (rust_to_clang_target(&t), false);
+ }
+
+ (rust_to_clang_target(HOST_TARGET), false)
+}
+
+impl Bindings {
+ /// Generate bindings for the given options.
+ pub(crate) fn generate(
+ mut options: BindgenOptions,
+ input_unsaved_files: Vec<clang::UnsavedFile>,
+ ) -> Result<Bindings, BindgenError> {
+ ensure_libclang_is_loaded();
+
+ #[cfg(feature = "runtime")]
+ debug!(
+ "Generating bindings, libclang at {}",
+ clang_sys::get_library().unwrap().path().display()
+ );
+ #[cfg(not(feature = "runtime"))]
+ debug!("Generating bindings, libclang linked");
+
+ options.build();
+
+ let (effective_target, explicit_target) =
+ find_effective_target(&options.clang_args);
+
+ let is_host_build =
+ rust_to_clang_target(HOST_TARGET) == effective_target;
+
+ // NOTE: The is_host_build check wouldn't be sound normally in some
+ // cases if we were to call a binary (if you have a 32-bit clang and are
+ // building on a 64-bit system for example). But since we rely on
+ // opening libclang.so, it has to be the same architecture and thus the
+ // check is fine.
+ if !explicit_target && !is_host_build {
+ options.clang_args.insert(
+ 0,
+ format!("--target={}", effective_target).into_boxed_str(),
+ );
+ };
+
+ fn detect_include_paths(options: &mut BindgenOptions) {
+ if !options.detect_include_paths {
+ return;
+ }
+
+ // Filter out include paths and similar stuff, so we don't incorrectly
+ // promote them to `-isystem`.
+ let clang_args_for_clang_sys = {
+ let mut last_was_include_prefix = false;
+ options
+ .clang_args
+ .iter()
+ .filter(|arg| {
+ if last_was_include_prefix {
+ last_was_include_prefix = false;
+ return false;
+ }
+
+ let arg = arg.as_ref();
+
+ // https://clang.llvm.org/docs/ClangCommandLineReference.html
+ // -isystem and -isystem-after are harmless.
+ if arg == "-I" || arg == "--include-directory" {
+ last_was_include_prefix = true;
+ return false;
+ }
+
+ if arg.starts_with("-I") ||
+ arg.starts_with("--include-directory=")
+ {
+ return false;
+ }
+
+ true
+ })
+ .map(|arg| arg.clone().into())
+ .collect::<Vec<_>>()
+ };
+
+ debug!(
+ "Trying to find clang with flags: {:?}",
+ clang_args_for_clang_sys
+ );
+
+ let clang = match clang_sys::support::Clang::find(
+ None,
+ &clang_args_for_clang_sys,
+ ) {
+ None => return,
+ Some(clang) => clang,
+ };
+
+ debug!("Found clang: {:?}", clang);
+
+ // Whether we are working with C or C++ inputs.
+ let is_cpp = args_are_cpp(&options.clang_args) ||
+ options.input_headers.iter().any(|h| file_is_cpp(h));
+
+ let search_paths = if is_cpp {
+ clang.cpp_search_paths
+ } else {
+ clang.c_search_paths
+ };
+
+ if let Some(search_paths) = search_paths {
+ for path in search_paths.into_iter() {
+ if let Ok(path) = path.into_os_string().into_string() {
+ options.clang_args.push("-isystem".into());
+ options.clang_args.push(path.into_boxed_str());
+ }
+ }
+ }
+ }
+
+ detect_include_paths(&mut options);
+
+ #[cfg(unix)]
+ fn can_read(perms: &std::fs::Permissions) -> bool {
+ use std::os::unix::fs::PermissionsExt;
+ perms.mode() & 0o444 > 0
+ }
+
+ #[cfg(not(unix))]
+ fn can_read(_: &std::fs::Permissions) -> bool {
+ true
+ }
+
+ if let Some(h) = options.input_headers.last() {
+ let path = Path::new(h.as_ref());
+ if let Ok(md) = std::fs::metadata(path) {
+ if md.is_dir() {
+ return Err(BindgenError::FolderAsHeader(path.into()));
+ }
+ if !can_read(&md.permissions()) {
+ return Err(BindgenError::InsufficientPermissions(
+ path.into(),
+ ));
+ }
+ options.clang_args.push(h.clone());
+ } else {
+ return Err(BindgenError::NotExist(path.into()));
+ }
+ }
+
+ for (idx, f) in input_unsaved_files.iter().enumerate() {
+ if idx != 0 || !options.input_headers.is_empty() {
+ options.clang_args.push("-include".into());
+ }
+ options.clang_args.push(f.name.to_str().unwrap().into())
+ }
+
+ debug!("Fixed-up options: {:?}", options);
+
+ let time_phases = options.time_phases;
+ let mut context = BindgenContext::new(options, &input_unsaved_files);
+
+ if is_host_build {
+ debug_assert_eq!(
+ context.target_pointer_size(),
+ std::mem::size_of::<*mut ()>(),
+ "{:?} {:?}",
+ effective_target,
+ HOST_TARGET
+ );
+ }
+
+ {
+ let _t = time::Timer::new("parse").with_output(time_phases);
+ parse(&mut context)?;
+ }
+
+ let (module, options) =
+ codegen::codegen(context).map_err(BindgenError::Codegen)?;
+
+ Ok(Bindings { options, module })
+ }
+
+ /// Write these bindings as source text to a file.
+ pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ let file = OpenOptions::new()
+ .write(true)
+ .truncate(true)
+ .create(true)
+ .open(path.as_ref())?;
+ self.write(Box::new(file))?;
+ Ok(())
+ }
+
+ /// Write these bindings as source text to the given `Write`able.
+ pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> io::Result<()> {
+ const NL: &str = if cfg!(windows) { "\r\n" } else { "\n" };
+
+ if !self.options.disable_header_comment {
+ let version =
+ option_env!("CARGO_PKG_VERSION").unwrap_or("(unknown version)");
+ writeln!(
+ writer,
+ "/* automatically generated by rust-bindgen {version} */{NL}",
+ )?;
+ }
+
+ for line in self.options.raw_lines.iter() {
+ writer.write_all(line.as_bytes())?;
+ writer.write_all(NL.as_bytes())?;
+ }
+
+ if !self.options.raw_lines.is_empty() {
+ writer.write_all(NL.as_bytes())?;
+ }
+
+ match self.format_tokens(&self.module) {
+ Ok(formatted_bindings) => {
+ writer.write_all(formatted_bindings.as_bytes())?;
+ }
+ Err(err) => {
+ eprintln!(
+ "Failed to run rustfmt: {} (non-fatal, continuing)",
+ err
+ );
+ writer.write_all(self.module.to_string().as_bytes())?;
+ }
+ }
+ Ok(())
+ }
+
+ /// Gets the rustfmt path to rustfmt the generated bindings.
+ fn rustfmt_path(&self) -> io::Result<Cow<PathBuf>> {
+ debug_assert!(matches!(self.options.formatter, Formatter::Rustfmt));
+ if let Some(ref p) = self.options.rustfmt_path {
+ return Ok(Cow::Borrowed(p));
+ }
+ if let Ok(rustfmt) = env::var("RUSTFMT") {
+ return Ok(Cow::Owned(rustfmt.into()));
+ }
+ #[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()))
+ }
+
+ /// Formats a token stream with the formatter set up in `BindgenOptions`.
+ fn format_tokens(
+ &self,
+ tokens: &proc_macro2::TokenStream,
+ ) -> io::Result<String> {
+ let _t = time::Timer::new("rustfmt_generated_string")
+ .with_output(self.options.time_phases);
+
+ match self.options.formatter {
+ Formatter::None => return Ok(tokens.to_string()),
+ #[cfg(feature = "prettyplease")]
+ Formatter::Prettyplease => {
+ return Ok(prettyplease::unparse(&syn::parse_quote!(#tokens)));
+ }
+ Formatter::Rustfmt => (),
+ }
+
+ let rustfmt = self.rustfmt_path()?;
+ let mut cmd = Command::new(&*rustfmt);
+
+ cmd.stdin(Stdio::piped()).stdout(Stdio::piped());
+
+ if let Some(path) = self
+ .options
+ .rustfmt_configuration_file
+ .as_ref()
+ .and_then(|f| f.to_str())
+ {
+ cmd.args(["--config-path", path]);
+ }
+
+ let mut child = cmd.spawn()?;
+ let mut child_stdin = child.stdin.take().unwrap();
+ let mut child_stdout = child.stdout.take().unwrap();
+
+ let source = tokens.to_string();
+
+ // Write to stdin in a new thread, so that we can read from stdout on this
+ // thread. This keeps the child from blocking on writing to its stdout which
+ // might block us from writing to its stdin.
+ let stdin_handle = ::std::thread::spawn(move || {
+ let _ = child_stdin.write_all(source.as_bytes());
+ source
+ });
+
+ let mut output = vec![];
+ io::copy(&mut child_stdout, &mut output)?;
+
+ let status = child.wait()?;
+ let source = stdin_handle.join().expect(
+ "The thread writing to rustfmt's stdin doesn't do \
+ anything that could panic",
+ );
+
+ match String::from_utf8(output) {
+ Ok(bindings) => match status.code() {
+ Some(0) => Ok(bindings),
+ Some(2) => Err(io::Error::new(
+ io::ErrorKind::Other,
+ "Rustfmt parsing errors.".to_string(),
+ )),
+ Some(3) => {
+ rustfmt_non_fatal_error_diagnostic(
+ "Rustfmt could not format some lines",
+ &self.options,
+ );
+ Ok(bindings)
+ }
+ _ => Err(io::Error::new(
+ io::ErrorKind::Other,
+ "Internal rustfmt error".to_string(),
+ )),
+ },
+ _ => Ok(source),
+ }
+ }
+}
+
+fn rustfmt_non_fatal_error_diagnostic(msg: &str, _options: &BindgenOptions) {
+ warn!("{}", msg);
+
+ #[cfg(feature = "experimental")]
+ if _options.emit_diagnostics {
+ use crate::diagnostics::{Diagnostic, Level};
+
+ Diagnostic::default()
+ .with_title(msg, Level::Warn)
+ .add_annotation(
+ "The bindings will be generated but not formatted.",
+ Level::Note,
+ )
+ .display();
+ }
+}
+
+impl std::fmt::Display for Bindings {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let mut bytes = vec![];
+ self.write(Box::new(&mut bytes) as Box<dyn Write>)
+ .expect("writing to a vec cannot fail");
+ f.write_str(
+ std::str::from_utf8(&bytes)
+ .expect("we should only write bindings that are valid utf-8"),
+ )
+ }
+}
+
+/// Determines whether the given cursor is in any of the files matched by the
+/// options.
+fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
+ ctx.options().builtins || !cursor.is_builtin()
+}
+
+/// Parse one `Item` from the Clang cursor.
+fn parse_one(
+ ctx: &mut BindgenContext,
+ cursor: clang::Cursor,
+ parent: Option<ItemId>,
+) {
+ if !filter_builtins(ctx, &cursor) {
+ return;
+ }
+
+ match Item::parse(cursor, parent, ctx) {
+ Ok(..) => {}
+ Err(ParseError::Continue) => {}
+ Err(ParseError::Recurse) => {
+ cursor
+ .visit_sorted(ctx, |ctx, child| parse_one(ctx, child, parent));
+ }
+ }
+}
+
+/// Parse the Clang AST into our `Item` internal representation.
+fn parse(context: &mut BindgenContext) -> Result<(), BindgenError> {
+ use clang_sys::*;
+
+ let mut error = None;
+ for d in context.translation_unit().diags().iter() {
+ let msg = d.format();
+ let is_err = d.severity() >= CXDiagnostic_Error;
+ if is_err {
+ let error = error.get_or_insert_with(String::new);
+ error.push_str(&msg);
+ error.push('\n');
+ } else {
+ eprintln!("clang diag: {}", msg);
+ }
+ }
+
+ if let Some(message) = error {
+ return Err(BindgenError::ClangDiagnostic(message));
+ }
+
+ let cursor = context.translation_unit().cursor();
+
+ if context.options().emit_ast {
+ fn dump_if_not_builtin(cur: &clang::Cursor) -> CXChildVisitResult {
+ if !cur.is_builtin() {
+ clang::ast_dump(cur, 0)
+ } else {
+ CXChildVisit_Continue
+ }
+ }
+ cursor.visit(|cur| dump_if_not_builtin(&cur));
+ }
+
+ let root = context.root_module();
+ context.with_module(root, |ctx| {
+ cursor.visit_sorted(ctx, |ctx, child| parse_one(ctx, child, None))
+ });
+
+ assert!(
+ context.current_module() == context.root_module(),
+ "How did this happen?"
+ );
+ Ok(())
+}
+
+/// Extracted Clang version data
+#[derive(Debug)]
+pub struct ClangVersion {
+ /// Major and minor semver, if parsing was successful
+ pub parsed: Option<(u32, u32)>,
+ /// full version string
+ pub full: String,
+}
+
+/// Get the major and the minor semver numbers of Clang's version
+pub fn clang_version() -> ClangVersion {
+ ensure_libclang_is_loaded();
+
+ //Debian clang version 11.0.1-2
+ let raw_v: String = clang::extract_clang_version();
+ let split_v: Option<Vec<&str>> = raw_v
+ .split_whitespace()
+ .find(|t| t.chars().next().map_or(false, |v| v.is_ascii_digit()))
+ .map(|v| v.split('.').collect());
+ if let Some(v) = split_v {
+ if v.len() >= 2 {
+ let maybe_major = v[0].parse::<u32>();
+ let maybe_minor = v[1].parse::<u32>();
+ if let (Ok(major), Ok(minor)) = (maybe_major, maybe_minor) {
+ return ClangVersion {
+ parsed: Some((major, minor)),
+ full: raw_v.clone(),
+ };
+ }
+ }
+ };
+ ClangVersion {
+ parsed: None,
+ full: raw_v.clone(),
+ }
+}
+
+fn env_var<K: AsRef<str> + AsRef<OsStr>>(
+ parse_callbacks: &[Rc<dyn callbacks::ParseCallbacks>],
+ key: K,
+) -> Result<String, std::env::VarError> {
+ for callback in parse_callbacks {
+ callback.read_env_var(key.as_ref());
+ }
+ std::env::var(key)
+}
+
+/// Looks for the env var `var_${TARGET}`, and falls back to just `var` when it is not found.
+fn get_target_dependent_env_var(
+ parse_callbacks: &[Rc<dyn callbacks::ParseCallbacks>],
+ var: &str,
+) -> Option<String> {
+ if let Ok(target) = env_var(parse_callbacks, "TARGET") {
+ if let Ok(v) = env_var(parse_callbacks, format!("{}_{}", var, target)) {
+ return Some(v);
+ }
+ if let Ok(v) = env_var(
+ parse_callbacks,
+ format!("{}_{}", var, target.replace('-', "_")),
+ ) {
+ return Some(v);
+ }
+ }
+
+ env_var(parse_callbacks, var).ok()
+}
+
+/// A ParseCallbacks implementation that will act on file includes by echoing a rerun-if-changed
+/// line and on env variable usage by echoing a rerun-if-env-changed line
+///
+/// When running inside a `build.rs` script, this can be used to make cargo invalidate the
+/// generated bindings whenever any of the files included from the header change:
+/// ```
+/// use bindgen::builder;
+/// let bindings = builder()
+/// .header("path/to/input/header")
+/// .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
+/// .generate();
+/// ```
+#[derive(Debug)]
+pub struct CargoCallbacks {
+ rerun_on_header_files: bool,
+}
+
+/// Create a new `CargoCallbacks` value with [`CargoCallbacks::rerun_on_header_files`] disabled.
+///
+/// This constructor has been deprecated in favor of [`CargoCallbacks::new`] where
+/// [`CargoCallbacks::rerun_on_header_files`] is enabled by default.
+#[deprecated = "Use `CargoCallbacks::new()` instead. Please, check the documentation for further information."]
+pub const CargoCallbacks: CargoCallbacks = CargoCallbacks {
+ rerun_on_header_files: false,
+};
+
+impl CargoCallbacks {
+ /// Create a new `CargoCallbacks` value.
+ pub fn new() -> Self {
+ Self {
+ rerun_on_header_files: true,
+ }
+ }
+
+ /// Whether Cargo should re-run the build script if any of the input header files has changed.
+ ///
+ /// This option is enabled by default unless the deprecated [`const@CargoCallbacks`]
+ /// constructor is used.
+ pub fn rerun_on_header_files(mut self, doit: bool) -> Self {
+ self.rerun_on_header_files = doit;
+ self
+ }
+}
+
+impl Default for CargoCallbacks {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl callbacks::ParseCallbacks for CargoCallbacks {
+ fn header_file(&self, filename: &str) {
+ if self.rerun_on_header_files {
+ println!("cargo:rerun-if-changed={}", filename);
+ }
+ }
+
+ fn include_file(&self, filename: &str) {
+ println!("cargo:rerun-if-changed={}", filename);
+ }
+
+ fn read_env_var(&self, key: &str) {
+ println!("cargo:rerun-if-env-changed={}", key);
+ }
+}
+
+/// Test command_line_flag function.
+#[test]
+fn commandline_flag_unit_test_function() {
+ //Test 1
+ let bindings = crate::builder();
+ let command_line_flags = bindings.command_line_flags();
+
+ let test_cases = [
+ "--rust-target",
+ "--no-derive-default",
+ "--generate",
+ "functions,types,vars,methods,constructors,destructors",
+ ]
+ .iter()
+ .map(|&x| x.into())
+ .collect::<Vec<String>>();
+
+ assert!(test_cases.iter().all(|x| command_line_flags.contains(x)));
+
+ //Test 2
+ let bindings = crate::builder()
+ .header("input_header")
+ .allowlist_type("Distinct_Type")
+ .allowlist_function("safe_function");
+
+ let command_line_flags = bindings.command_line_flags();
+ let test_cases = [
+ "--rust-target",
+ "input_header",
+ "--no-derive-default",
+ "--generate",
+ "functions,types,vars,methods,constructors,destructors",
+ "--allowlist-type",
+ "Distinct_Type",
+ "--allowlist-function",
+ "safe_function",
+ ]
+ .iter()
+ .map(|&x| x.into())
+ .collect::<Vec<String>>();
+ println!("{:?}", command_line_flags);
+
+ assert!(test_cases.iter().all(|x| command_line_flags.contains(x)));
+}
+
+#[test]
+fn test_rust_to_clang_target() {
+ assert_eq!(
+ rust_to_clang_target("aarch64-apple-ios").as_ref(),
+ "arm64-apple-ios"
+ );
+}
+
+#[test]
+fn test_rust_to_clang_target_riscv() {
+ assert_eq!(
+ rust_to_clang_target("riscv64gc-unknown-linux-gnu").as_ref(),
+ "riscv64-unknown-linux-gnu"
+ );
+ assert_eq!(
+ rust_to_clang_target("riscv32imc-unknown-none-elf").as_ref(),
+ "riscv32-unknown-none-elf"
+ );
+ assert_eq!(
+ rust_to_clang_target("riscv32imac-unknown-none-elf").as_ref(),
+ "riscv32-unknown-none-elf"
+ );
+}
+
+#[test]
+fn test_rust_to_clang_target_espidf() {
+ assert_eq!(
+ rust_to_clang_target("riscv32imc-esp-espidf").as_ref(),
+ "riscv32-esp-elf"
+ );
+ assert_eq!(
+ rust_to_clang_target("xtensa-esp32-espidf").as_ref(),
+ "xtensa-esp32-elf"
+ );
+}
diff --git a/third_party/rust/bindgen/log_stubs.rs b/third_party/rust/bindgen/log_stubs.rs
new file mode 100644
index 0000000000..8315983128
--- /dev/null
+++ b/third_party/rust/bindgen/log_stubs.rs
@@ -0,0 +1,32 @@
+#![allow(unused)]
+
+macro_rules! log {
+ (target: $target:expr, $lvl:expr, $($arg:tt)+) => {{
+ let _ = $target;
+ let _ = log!($lvl, $($arg)+);
+ }};
+ ($lvl:expr, $($arg:tt)+) => {{
+ let _ = $lvl;
+ let _ = format_args!($($arg)+);
+ }};
+}
+macro_rules! error {
+ (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
+ ($($arg:tt)+) => { log!("", $($arg)+) };
+}
+macro_rules! warn {
+ (target: $target:expr, $($arg:tt)*) => { log!(target: $target, "", $($arg)*) };
+ ($($arg:tt)*) => { log!("", $($arg)*) };
+}
+macro_rules! info {
+ (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
+ ($($arg:tt)+) => { log!("", $($arg)+) };
+}
+macro_rules! debug {
+ (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
+ ($($arg:tt)+) => { log!("", $($arg)+) };
+}
+macro_rules! trace {
+ (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
+ ($($arg:tt)+) => { log!("", $($arg)+) };
+}
diff --git a/third_party/rust/bindgen/options/as_args.rs b/third_party/rust/bindgen/options/as_args.rs
new file mode 100644
index 0000000000..6918ad9fec
--- /dev/null
+++ b/third_party/rust/bindgen/options/as_args.rs
@@ -0,0 +1,52 @@
+use std::path::PathBuf;
+
+use crate::RegexSet;
+
+/// Trait used to turn [`crate::BindgenOptions`] fields into CLI args.
+pub(super) trait AsArgs {
+ fn as_args(&self, args: &mut Vec<String>, flag: &str);
+}
+
+/// If the `bool` is `true`, `flag` is pushed into `args`.
+///
+/// be careful about the truth value of the field as some options, like `--no-layout-tests`, are
+/// actually negations of the fields.
+impl AsArgs for bool {
+ fn as_args(&self, args: &mut Vec<String>, flag: &str) {
+ if *self {
+ args.push(flag.to_string());
+ }
+ }
+}
+
+/// Iterate over all the items of the `RegexSet` and push `flag` followed by the item into `args`
+/// for each item.
+impl AsArgs for RegexSet {
+ fn as_args(&self, args: &mut Vec<String>, flag: &str) {
+ for item in self.get_items() {
+ args.extend_from_slice(&[flag.to_owned(), item.clone().into()]);
+ }
+ }
+}
+
+/// If the `Option` is `Some(value)`, push `flag` followed by `value`.
+impl AsArgs for Option<String> {
+ fn as_args(&self, args: &mut Vec<String>, flag: &str) {
+ if let Some(string) = self {
+ args.extend_from_slice(&[flag.to_owned(), string.clone()]);
+ }
+ }
+}
+
+/// If the `Option` is `Some(path)`, push `flag` followed by the [`std::path::Path::display`]
+/// representation of `path`.
+impl AsArgs for Option<PathBuf> {
+ fn as_args(&self, args: &mut Vec<String>, flag: &str) {
+ if let Some(path) = self {
+ args.extend_from_slice(&[
+ flag.to_owned(),
+ path.display().to_string(),
+ ]);
+ }
+ }
+}
diff --git a/third_party/rust/bindgen/options/helpers.rs b/third_party/rust/bindgen/options/helpers.rs
new file mode 100644
index 0000000000..1816c72b57
--- /dev/null
+++ b/third_party/rust/bindgen/options/helpers.rs
@@ -0,0 +1,43 @@
+/// Helper function that appends extra documentation to [`crate::Builder`] methods that support regular
+/// expressions in their input.
+macro_rules! regex_option {
+ ($(#[$attrs:meta])* pub fn $($tokens:tt)*) => {
+ $(#[$attrs])*
+ ///
+ /// Regular expressions are supported. Check the [regular expression
+ /// arguments](./struct.Builder.html#regular-expression-arguments) section and the
+ /// [regex](https://docs.rs/regex) crate documentation for further information.
+ pub fn $($tokens)*
+ };
+}
+
+/// Helper macro to set the default value of each option.
+///
+/// This macro is an internal implementation detail of the `options` macro and should not be used
+/// directly.
+macro_rules! default {
+ () => {
+ Default::default()
+ };
+ ($expr:expr) => {
+ $expr
+ };
+}
+
+/// Helper macro to set the conversion to CLI arguments for each option.
+///
+/// This macro is an internal implementation detail of the `options` macro and should not be used
+/// directly.
+macro_rules! as_args {
+ ($flag:literal) => {
+ |field, args| AsArgs::as_args(field, args, $flag)
+ };
+ ($expr:expr) => {
+ $expr
+ };
+}
+
+/// Helper function to ignore an option when converting it into CLI arguments.
+///
+/// This function is only used inside `options` and should not be used in other contexts.
+pub(super) fn ignore<T>(_: &T, _: &mut Vec<String>) {}
diff --git a/third_party/rust/bindgen/options/mod.rs b/third_party/rust/bindgen/options/mod.rs
new file mode 100644
index 0000000000..1fc2241615
--- /dev/null
+++ b/third_party/rust/bindgen/options/mod.rs
@@ -0,0 +1,2079 @@
+//! Declarations and setter methods for `bindgen` options.
+//!
+//! The main entry point of this module is the `options` macro.
+#[macro_use]
+mod helpers;
+mod as_args;
+
+use crate::callbacks::ParseCallbacks;
+use crate::codegen::{
+ AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle,
+};
+use crate::deps::DepfileSpec;
+use crate::features::{RustFeatures, RustTarget};
+use crate::regex_set::RegexSet;
+use crate::Abi;
+use crate::Builder;
+use crate::CodegenConfig;
+use crate::FieldVisibilityKind;
+use crate::Formatter;
+use crate::HashMap;
+use crate::DEFAULT_ANON_FIELDS_PREFIX;
+
+use std::env;
+#[cfg(feature = "experimental")]
+use std::path::Path;
+use std::path::PathBuf;
+use std::rc::Rc;
+
+use as_args::AsArgs;
+use helpers::ignore;
+
+/// Macro used to generate the [`BindgenOptions`] type and the [`Builder`] setter methods for each
+/// one of the fields of `BindgenOptions`.
+///
+/// The input format of this macro resembles a `struct` pattern. Each field of the `BindgenOptions`
+/// type is declared by adding the name of the field and its type using the `name: type` syntax and
+/// a block of code with the following items:
+///
+/// - `default`: The default value for the field. If this item is omitted, `Default::default()` is
+/// used instead, meaning that the type of the field must implement `Default`.
+/// - `methods`: A block of code containing methods for the `Builder` type. These methods should be
+/// related to the field being declared.
+/// - `as_args`: This item declares how the field should be converted into a valid CLI argument for
+/// `bindgen` and is used in the [`Builder::command_line_flags`] method which is used to do a
+/// roundtrip test of the CLI args in the `bindgen-test` crate. This item can take one of the
+/// following:
+/// - A string literal with the flag if the type of the field implements the [`AsArgs`] trait.
+/// - A closure with the signature `|field, args: &mut Vec<String>| -> ()` that pushes arguments
+/// into the `args` buffer based on the value of the field. This is used if the field does not
+/// implement `AsArgs` or if the implementation of the trait is not logically correct for the
+/// option and a custom behavior must be taken into account.
+/// - The `ignore` literal, which does not emit any CLI arguments for this field. This is useful
+/// if the field cannot be used from the `bindgen` CLI.
+///
+/// As an example, this would be the declaration of a `bool` field called `be_fun` whose default
+/// value is `false` (the `Default` value for `bool`):
+/// ```rust,ignore
+/// be_fun: bool {
+/// methods: {
+/// /// Ask `bindgen` to be fun. This option is disabled by default.
+/// fn be_fun(mut self) -> Self {
+/// self.options.be_fun = true;
+/// self
+/// }
+/// },
+/// as_args: "--be-fun",
+/// }
+/// ```
+///
+/// However, we could also set the `be_fun` field to `true` by default and use a `--not-fun` flag
+/// instead. This means that we have to add the `default` item and use a closure in the `as_args`
+/// item:
+/// ```rust,ignore
+/// be_fun: bool {
+/// default: true,
+/// methods: {
+/// /// Ask `bindgen` to not be fun. `bindgen` is fun by default.
+/// fn not_fun(mut self) -> Self {
+/// self.options.be_fun = false;
+/// self
+/// }
+/// },
+/// as_args: |be_fun, args| (!be_fun).as_args(args, "--not-fun"),
+/// }
+/// ```
+/// More complex examples can be found in the sole invocation of this macro.
+macro_rules! options {
+ ($(
+ $(#[doc = $docs:literal])+
+ $field:ident: $ty:ty {
+ $(default: $default:expr,)?
+ methods: {$($methods_tokens:tt)*}$(,)?
+ as_args: $as_args:expr$(,)?
+ }$(,)?
+ )*) => {
+ #[derive(Debug, Clone)]
+ pub(crate) struct BindgenOptions {
+ $($(#[doc = $docs])* pub(crate) $field: $ty,)*
+ }
+
+ impl Default for BindgenOptions {
+ fn default() -> Self {
+ Self {
+ $($field: default!($($default)*),)*
+ }
+ }
+ }
+
+ impl Builder {
+ /// Generates the command line flags used to create this [`Builder`].
+ pub fn command_line_flags(&self) -> Vec<String> {
+ let mut args = vec![];
+
+ let headers = match self.options.input_headers.split_last() {
+ Some((header, headers)) => {
+ // The last input header is passed as an argument in the first position.
+ args.push(header.clone().into());
+ headers
+ },
+ None => &[]
+ };
+
+ $({
+ let func: fn(&$ty, &mut Vec<String>) = as_args!($as_args);
+ func(&self.options.$field, &mut args);
+ })*
+
+ // Add the `--experimental` flag if `bindgen` is built with the `experimental`
+ // feature.
+ if cfg!(feature = "experimental") {
+ args.push("--experimental".to_owned());
+ }
+
+ // Add all the clang arguments.
+ args.push("--".to_owned());
+
+ if !self.options.clang_args.is_empty() {
+ args.extend(self.options.clang_args.iter().map(|s| s.clone().into()));
+ }
+
+ // We need to pass all but the last header via the `-include` clang argument.
+ for header in headers {
+ args.push("-include".to_owned());
+ args.push(header.clone().into());
+ }
+
+ args
+ }
+
+ $($($methods_tokens)*)*
+ }
+ };
+}
+
+options! {
+ /// Types that have been blocklisted and should not appear anywhere in the generated code.
+ blocklisted_types: RegexSet {
+ methods: {
+ regex_option! {
+ /// Do not generate any bindings for the given type.
+ ///
+ /// This option is not recursive, meaning that it will only block types whose names
+ /// explicitly match the argument of this method.
+ pub fn blocklist_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.blocklisted_types.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--blocklist-type",
+ },
+ /// Functions that have been blocklisted and should not appear in the generated code.
+ blocklisted_functions: RegexSet {
+ methods: {
+ regex_option! {
+ /// Do not generate any bindings for the given function.
+ ///
+ /// This option is not recursive, meaning that it will only block functions whose
+ /// names explicitly match the argument of this method.
+ pub fn blocklist_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.blocklisted_functions.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--blocklist-function",
+ },
+ /// Items that have been blocklisted and should not appear in the generated code.
+ blocklisted_items: RegexSet {
+ methods: {
+ regex_option! {
+ /// Do not generate any bindings for the given item, regardless of whether it is a
+ /// type, function, module, etc.
+ ///
+ /// This option is not recursive, meaning that it will only block items whose names
+ /// explicitly match the argument of this method.
+ pub fn blocklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.blocklisted_items.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--blocklist-item",
+ },
+ /// Files whose contents should be blocklisted and should not appear in the generated code.
+ blocklisted_files: RegexSet {
+ methods: {
+ regex_option! {
+ /// Do not generate any bindings for the contents of the given file, regardless of
+ /// whether the contents of the file are types, functions, modules, etc.
+ ///
+ /// This option is not recursive, meaning that it will only block files whose names
+ /// explicitly match the argument of this method.
+ ///
+ /// This method will use the argument to match the complete path of the file
+ /// instead of a section of it.
+ pub fn blocklist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.blocklisted_files.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--blocklist-file",
+ },
+ /// Variables that have been blocklisted and should not appear in the generated code.
+ blocklisted_vars: RegexSet {
+ methods: {
+ regex_option! {
+ /// Do not generate any bindings for the given variable.
+ ///
+ /// This option is not recursive, meaning that it will only block variables whose
+ /// names explicitly match the argument of this method.
+ pub fn blocklist_var<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.blocklisted_vars.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--blocklist-var",
+ },
+ /// Types that should be treated as opaque structures in the generated code.
+ opaque_types: RegexSet {
+ methods: {
+ regex_option! {
+ /// Treat the given type as opaque in the generated bindings.
+ ///
+ /// Opaque in this context means that none of the generated bindings will contain
+ /// information about the inner representation of the type and the type itself will
+ /// be represented as a chunk of bytes with the alignment and size of the type.
+ pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.opaque_types.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--opaque-type",
+ },
+ /// The explicit `rustfmt` path.
+ rustfmt_path: Option<PathBuf> {
+ methods: {
+ /// Set an explicit path to the `rustfmt` binary.
+ ///
+ /// This option only comes into effect if `rustfmt` is set to be the formatter used by
+ /// `bindgen`. Check the documentation of the [`Builder::formatter`] method for more
+ /// information.
+ pub fn with_rustfmt<P: Into<PathBuf>>(mut self, path: P) -> Self {
+ self.options.rustfmt_path = Some(path.into());
+ self
+ }
+ },
+ // This option cannot be set from the CLI.
+ as_args: ignore,
+ },
+ /// The path to which we should write a Makefile-syntax depfile (if any).
+ depfile: Option<DepfileSpec> {
+ methods: {
+ /// Add a depfile output which will be written alongside the generated bindings.
+ pub fn depfile<H: Into<String>, D: Into<PathBuf>>(
+ mut self,
+ output_module: H,
+ depfile: D,
+ ) -> Builder {
+ self.options.depfile = Some(DepfileSpec {
+ output_module: output_module.into(),
+ depfile_path: depfile.into(),
+ });
+ self
+ }
+ },
+ as_args: |depfile, args| {
+ if let Some(depfile) = depfile {
+ args.push("--depfile".into());
+ args.push(depfile.depfile_path.display().to_string());
+ }
+ },
+ },
+ /// Types that have been allowlisted and should appear in the generated code.
+ allowlisted_types: RegexSet {
+ methods: {
+ regex_option! {
+ /// Generate bindings for the given type.
+ ///
+ /// This option is transitive by default. Check the documentation of the
+ /// [`Builder::allowlist_recursively`] method for further information.
+ pub fn allowlist_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.allowlisted_types.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--allowlist-type",
+ },
+ /// Functions that have been allowlisted and should appear in the generated code.
+ allowlisted_functions: RegexSet {
+ methods: {
+ regex_option! {
+ /// Generate bindings for the given function.
+ ///
+ /// This option is transitive by default. Check the documentation of the
+ /// [`Builder::allowlist_recursively`] method for further information.
+ pub fn allowlist_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.allowlisted_functions.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--allowlist-function",
+ },
+ /// Variables that have been allowlisted and should appear in the generated code.
+ allowlisted_vars: RegexSet {
+ methods: {
+ regex_option! {
+ /// Generate bindings for the given variable.
+ ///
+ /// This option is transitive by default. Check the documentation of the
+ /// [`Builder::allowlist_recursively`] method for further information.
+ pub fn allowlist_var<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.allowlisted_vars.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--allowlist-var",
+ },
+ /// Files whose contents have been allowlisted and should appear in the generated code.
+ allowlisted_files: RegexSet {
+ methods: {
+ regex_option! {
+ /// Generate bindings for the content of the given file.
+ ///
+ /// This option is transitive by default. Check the documentation of the
+ /// [`Builder::allowlist_recursively`] method for further information.
+ ///
+ /// This method will use the argument to match the complete path of the file
+ /// instead of a section of it.
+ pub fn allowlist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.allowlisted_files.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--allowlist-file",
+ },
+ /// Items that have been allowlisted and should appear in the generated code.
+ allowlisted_items: RegexSet {
+ methods: {
+ regex_option! {
+ /// Generate bindings for the given item, regardless of whether it is a type,
+ /// function, module, etc.
+ ///
+ /// This option is transitive by default. Check the documentation of the
+ /// [`Builder::allowlist_recursively`] method for further information.
+ pub fn allowlist_item<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.allowlisted_items.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--allowlist-item",
+ },
+ /// The default style of for generated `enum`s.
+ default_enum_style: EnumVariation {
+ methods: {
+ /// Set the default style for generated `enum`s.
+ ///
+ /// If this method is not called, the [`EnumVariation::Consts`] style will be used by
+ /// default.
+ ///
+ /// To set the style for individual `enum`s, use [`Builder::bitfield_enum`],
+ /// [`Builder::newtype_enum`], [`Builder::newtype_global_enum`],
+ /// [`Builder::rustified_enum`], [`Builder::rustified_non_exhaustive_enum`],
+ /// [`Builder::constified_enum_module`] or [`Builder::constified_enum`].
+ pub fn default_enum_style(
+ mut self,
+ arg: EnumVariation,
+ ) -> Builder {
+ self.options.default_enum_style = arg;
+ self
+ }
+ },
+ as_args: |variation, args| {
+ if *variation != Default::default() {
+ args.push("--default-enum-style".to_owned());
+ args.push(variation.to_string());
+ }
+ },
+ },
+ /// `enum`s marked as bitfield-like. This is, newtypes with bitwise operations.
+ bitfield_enums: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `enum` as being bitfield-like.
+ ///
+ /// This is similar to the [`Builder::newtype_enum`] style, but with the bitwise
+ /// operators implemented.
+ pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.bitfield_enums.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--bitfield-enum",
+ },
+ /// `enum`s marked as newtypes.
+ newtype_enums: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `enum` as a newtype.
+ ///
+ /// This means that an integer newtype will be declared to represent the `enum`
+ /// type and its variants will be represented as constants inside of this type's
+ /// `impl` block.
+ pub fn newtype_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.newtype_enums.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--newtype-enum",
+ },
+ /// `enum`s marked as global newtypes .
+ newtype_global_enums: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `enum` as a global newtype.
+ ///
+ /// This is similar to the [`Builder::newtype_enum`] style, but the constants for
+ /// each variant are free constants instead of being declared inside an `impl`
+ /// block for the newtype.
+ pub fn newtype_global_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.newtype_global_enums.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--newtype-global-enum",
+ },
+ /// `enum`s marked as Rust `enum`s.
+ rustified_enums: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `enum` as a Rust `enum`.
+ ///
+ /// This means that each variant of the `enum` will be represented as a Rust `enum`
+ /// variant.
+ ///
+ /// **Use this with caution**, creating an instance of a Rust `enum` with an
+ /// invalid value will cause undefined behaviour. To avoid this, use the
+ /// [`Builder::newtype_enum`] style instead.
+ pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.rustified_enums.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--rustified-enum",
+ },
+ /// `enum`s marked as non-exhaustive Rust `enum`s.
+ rustified_non_exhaustive_enums: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `enum` as a non-exhaustive Rust `enum`.
+ ///
+ /// This is similar to the [`Builder::rustified_enum`] style, but the `enum` is
+ /// tagged with the `#[non_exhaustive]` attribute.
+ pub fn rustified_non_exhaustive_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.rustified_non_exhaustive_enums.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--rustified-non-exhaustive-enums",
+ },
+ /// `enum`s marked as modules of constants.
+ constified_enum_modules: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `enum` as a module with a set of integer constants.
+ pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.constified_enum_modules.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--constified-enum-module",
+ },
+ /// `enum`s marked as a set of constants.
+ constified_enums: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `enum` as a set o integer constants.
+ ///
+ /// This is similar to the [`Builder::constified_enum_module`] style, but the
+ /// constants are generated in the current module instead of in a new module.
+ pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.constified_enums.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--constified-enum",
+ },
+ /// The default type signedness for C macro constants.
+ default_macro_constant_type: MacroTypeVariation {
+ methods: {
+ /// Set the default type signedness to be used for macro constants.
+ ///
+ /// If this method is not called, [`MacroTypeVariation::Unsigned`] is used by default.
+ ///
+ /// To set the type for individual macro constants, use the
+ /// [`ParseCallbacks::int_macro`] method.
+ pub fn default_macro_constant_type(mut self, arg: MacroTypeVariation) -> Builder {
+ self.options.default_macro_constant_type = arg;
+ self
+ }
+
+ },
+ as_args: |variation, args| {
+ if *variation != Default::default() {
+ args.push("--default-macro-constant-type".to_owned());
+ args.push(variation.to_string());
+ }
+ },
+ },
+ /// The default style of code generation for `typedef`s.
+ default_alias_style: AliasVariation {
+ methods: {
+ /// Set the default style of code generation for `typedef`s.
+ ///
+ /// If this method is not called, the [`AliasVariation::TypeAlias`] style is used by
+ /// default.
+ ///
+ /// To set the style for individual `typedefs`s, use [`Builder::type_alias`],
+ /// [`Builder::new_type_alias`] or [`Builder::new_type_alias_deref`].
+ pub fn default_alias_style(
+ mut self,
+ arg: AliasVariation,
+ ) -> Builder {
+ self.options.default_alias_style = arg;
+ self
+ }
+ },
+ as_args: |variation, args| {
+ if *variation != Default::default() {
+ args.push("--default-alias-style".to_owned());
+ args.push(variation.to_string());
+ }
+ },
+ },
+ /// `typedef` patterns that will use regular type aliasing.
+ type_alias: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `typedef` as a regular Rust `type` alias.
+ ///
+ /// This is the default behavior, meaning that this method only comes into effect
+ /// if a style different from [`AliasVariation::TypeAlias`] was passed to the
+ /// [`Builder::default_alias_style`] method.
+ pub fn type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.type_alias.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--type-alias",
+ },
+ /// `typedef` patterns that will be aliased by creating a newtype.
+ new_type_alias: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `typedef` as a Rust newtype by having the aliased
+ /// type be wrapped in a `struct` with `#[repr(transparent)]`.
+ ///
+ /// This method can be used to enforce stricter type checking.
+ pub fn new_type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.new_type_alias.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--new-type-alias",
+ },
+ /// `typedef` patterns that will be wrapped in a newtype implementing `Deref` and `DerefMut`.
+ new_type_alias_deref: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `typedef` to be generated as a newtype that can be dereferenced.
+ ///
+ /// This is similar to the [`Builder::new_type_alias`] style, but the newtype
+ /// implements `Deref` and `DerefMut` with the aliased type as a target.
+ pub fn new_type_alias_deref<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.new_type_alias_deref.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--new-type-alias-deref",
+ },
+ /// The default style of code to generate for `union`s containing non-`Copy` members.
+ default_non_copy_union_style: NonCopyUnionStyle {
+ methods: {
+ /// Set the default style of code to generate for `union`s with non-`Copy` members.
+ ///
+ /// If this method is not called, the [`NonCopyUnionStyle::BindgenWrapper`] style is
+ /// used by default.
+ ///
+ /// To set the style for individual `union`s, use [`Builder::bindgen_wrapper_union`] or
+ /// [`Builder::manually_drop_union`].
+ pub fn default_non_copy_union_style(mut self, arg: NonCopyUnionStyle) -> Self {
+ self.options.default_non_copy_union_style = arg;
+ self
+ }
+ },
+ as_args: |style, args| {
+ if *style != Default::default() {
+ args.push("--default-non-copy-union-style".to_owned());
+ args.push(style.to_string());
+ }
+ },
+ },
+ /// The patterns marking non-`Copy` `union`s as using the `bindgen` generated wrapper.
+ bindgen_wrapper_union: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `union` to use a `bindgen`-generated wrapper for its members if at
+ /// least one them is not `Copy`.
+ ///
+ /// This is the default behavior, meaning that this method only comes into effect
+ /// if a style different from [`NonCopyUnionStyle::BindgenWrapper`] was passed to
+ /// the [`Builder::default_non_copy_union_style`] method.
+ pub fn bindgen_wrapper_union<T: AsRef<str>>(mut self, arg: T) -> Self {
+ self.options.bindgen_wrapper_union.insert(arg);
+ self
+ }
+ }
+ },
+ as_args: "--bindgen-wrapper-union",
+ },
+ /// The patterns marking non-`Copy` `union`s as using the `ManuallyDrop` wrapper.
+ manually_drop_union: RegexSet {
+ methods: {
+ regex_option! {
+ /// Mark the given `union` to use [`::core::mem::ManuallyDrop`] for its members if
+ /// at least one of them is not `Copy`.
+ ///
+ /// The `ManuallyDrop` type was stabilized in Rust 1.20.0, do not use this option
+ /// if your target version is lower than this.
+ pub fn manually_drop_union<T: AsRef<str>>(mut self, arg: T) -> Self {
+ self.options.manually_drop_union.insert(arg);
+ self
+ }
+ }
+
+ },
+ as_args: "--manually-drop-union",
+ },
+
+
+ /// Whether we should generate built-in definitions.
+ builtins: bool {
+ methods: {
+ /// Generate Rust bindings for built-in definitions (for example `__builtin_va_list`).
+ ///
+ /// Bindings for built-in definitions are not emitted by default.
+ pub fn emit_builtins(mut self) -> Builder {
+ self.options.builtins = true;
+ self
+ }
+ },
+ as_args: "--builtins",
+ },
+ /// Whether we should dump the Clang AST for debugging purposes.
+ emit_ast: bool {
+ methods: {
+ /// Emit the Clang AST to `stdout` for debugging purposes.
+ ///
+ /// The Clang AST is not emitted by default.
+ pub fn emit_clang_ast(mut self) -> Builder {
+ self.options.emit_ast = true;
+ self
+ }
+ },
+ as_args: "--emit-clang-ast",
+ },
+ /// Whether we should dump our IR for debugging purposes.
+ emit_ir: bool {
+ methods: {
+ /// Emit the `bindgen` internal representation to `stdout` for debugging purposes.
+ ///
+ /// This internal representation is not emitted by default.
+ pub fn emit_ir(mut self) -> Builder {
+ self.options.emit_ir = true;
+ self
+ }
+ },
+ as_args: "--emit-ir",
+ },
+ /// Output path for the `graphviz` DOT file.
+ emit_ir_graphviz: Option<String> {
+ methods: {
+ /// Set the path for the file where the`bindgen` internal representation will be
+ /// emitted as a graph using the `graphviz` DOT language.
+ ///
+ /// This graph representation is not emitted by default.
+ pub fn emit_ir_graphviz<T: Into<String>>(mut self, path: T) -> Builder {
+ let path = path.into();
+ self.options.emit_ir_graphviz = Some(path);
+ self
+ }
+ },
+ as_args: "--emit-ir-graphviz",
+ },
+
+ /// Whether we should emulate C++ namespaces with Rust modules.
+ enable_cxx_namespaces: bool {
+ methods: {
+ /// Emulate C++ namespaces using Rust modules in the generated bindings.
+ ///
+ /// C++ namespaces are not emulated by default.
+ pub fn enable_cxx_namespaces(mut self) -> Builder {
+ self.options.enable_cxx_namespaces = true;
+ self
+ }
+ },
+ as_args: "--enable-cxx-namespaces",
+ },
+ /// Whether we should try to find unexposed attributes in functions.
+ enable_function_attribute_detection: bool {
+ methods: {
+ /// Enable detecting function attributes on C functions.
+ ///
+ /// This enables the following features:
+ /// - Add `#[must_use]` attributes to Rust items whose C counterparts are marked as so.
+ /// This feature also requires that the Rust target version supports the attribute.
+ /// - Set `!` as the return type for Rust functions whose C counterparts are marked as
+ /// diverging.
+ ///
+ /// This option can be quite slow in some cases (check [#1465]), so it is disabled by
+ /// default.
+ ///
+ /// [#1465]: https://github.com/rust-lang/rust-bindgen/issues/1465
+ pub fn enable_function_attribute_detection(mut self) -> Self {
+ self.options.enable_function_attribute_detection = true;
+ self
+ }
+
+ },
+ as_args: "--enable-function-attribute-detection",
+ },
+ /// Whether we should avoid mangling names with namespaces.
+ disable_name_namespacing: bool {
+ methods: {
+ /// Disable name auto-namespacing.
+ ///
+ /// By default, `bindgen` mangles names like `foo::bar::Baz` to look like `foo_bar_Baz`
+ /// instead of just `Baz`. This method disables that behavior.
+ ///
+ /// Note that this does not change the names used for allowlisting and blocklisting,
+ /// which should still be mangled with the namespaces. Additionally, this option may
+ /// cause `bindgen` to generate duplicate names.
+ pub fn disable_name_namespacing(mut self) -> Builder {
+ self.options.disable_name_namespacing = true;
+ self
+ }
+ },
+ as_args: "--disable-name-namespacing",
+ },
+ /// Whether we should avoid generating nested `struct` names.
+ disable_nested_struct_naming: bool {
+ methods: {
+ /// Disable nested `struct` naming.
+ ///
+ /// The following `struct`s have different names for C and C++. In C, they are visible
+ /// as `foo` and `bar`. In C++, they are visible as `foo` and `foo::bar`.
+ ///
+ /// ```c
+ /// struct foo {
+ /// struct bar {
+ /// } b;
+ /// };
+ /// ```
+ ///
+ /// `bindgen` tries to avoid duplicate names by default, so it follows the C++ naming
+ /// convention and it generates `foo` and `foo_bar` instead of just `foo` and `bar`.
+ ///
+ /// This method disables this behavior and it is indented to be used only for headers
+ /// that were written in C.
+ pub fn disable_nested_struct_naming(mut self) -> Builder {
+ self.options.disable_nested_struct_naming = true;
+ self
+ }
+ },
+ as_args: "--disable-nested-struct-naming",
+ },
+ /// Whether we should avoid embedding version identifiers into source code.
+ disable_header_comment: bool {
+ methods: {
+ /// Do not insert the `bindgen` version identifier into the generated bindings.
+ ///
+ /// This identifier is inserted by default.
+ pub fn disable_header_comment(mut self) -> Self {
+ self.options.disable_header_comment = true;
+ self
+ }
+
+ },
+ as_args: "--disable-header-comment",
+ },
+ /// Whether we should generate layout tests for generated `struct`s.
+ layout_tests: bool {
+ default: true,
+ methods: {
+ /// Set whether layout tests should be generated.
+ ///
+ /// Layout tests are generated by default.
+ pub fn layout_tests(mut self, doit: bool) -> Self {
+ self.options.layout_tests = doit;
+ self
+ }
+ },
+ as_args: |value, args| (!value).as_args(args, "--no-layout-tests"),
+ },
+ /// Whether we should implement `Debug` for types that cannot derive it.
+ impl_debug: bool {
+ methods: {
+ /// Set whether `Debug` should be implemented for types that cannot derive it.
+ ///
+ /// This option is disabled by default.
+ pub fn impl_debug(mut self, doit: bool) -> Self {
+ self.options.impl_debug = doit;
+ self
+ }
+
+ },
+ as_args: "--impl-debug",
+ },
+ /// Whether we should implement `PartialEq` types that cannot derive it.
+ impl_partialeq: bool {
+ methods: {
+ /// Set whether `PartialEq` should be implemented for types that cannot derive it.
+ ///
+ /// This option is disabled by default.
+ pub fn impl_partialeq(mut self, doit: bool) -> Self {
+ self.options.impl_partialeq = doit;
+ self
+ }
+ },
+ as_args: "--impl-partialeq",
+ },
+ /// Whether we should derive `Copy` when possible.
+ derive_copy: bool {
+ default: true,
+ methods: {
+ /// Set whether the `Copy` trait should be derived when possible.
+ ///
+ /// `Copy` is derived by default.
+ pub fn derive_copy(mut self, doit: bool) -> Self {
+ self.options.derive_copy = doit;
+ self
+ }
+ },
+ as_args: |value, args| (!value).as_args(args, "--no-derive-copy"),
+ },
+
+ /// Whether we should derive `Debug` when possible.
+ derive_debug: bool {
+ default: true,
+ methods: {
+ /// Set whether the `Debug` trait should be derived when possible.
+ ///
+ /// The [`Builder::impl_debug`] method can be used to implement `Debug` for types that
+ /// cannot derive it.
+ ///
+ /// `Debug` is derived by default.
+ pub fn derive_debug(mut self, doit: bool) -> Self {
+ self.options.derive_debug = doit;
+ self
+ }
+ },
+ as_args: |value, args| (!value).as_args(args, "--no-derive-debug"),
+ },
+
+ /// Whether we should derive `Default` when possible.
+ derive_default: bool {
+ methods: {
+ /// Set whether the `Default` trait should be derived when possible.
+ ///
+ /// `Default` is not derived by default.
+ pub fn derive_default(mut self, doit: bool) -> Self {
+ self.options.derive_default = doit;
+ self
+ }
+ },
+ as_args: |&value, args| {
+ let arg = if value {
+ "--with-derive-default"
+ } else {
+ "--no-derive-default"
+ };
+
+ args.push(arg.to_owned());
+ },
+ },
+ /// Whether we should derive `Hash` when possible.
+ derive_hash: bool {
+ methods: {
+ /// Set whether the `Hash` trait should be derived when possible.
+ ///
+ /// `Hash` is not derived by default.
+ pub fn derive_hash(mut self, doit: bool) -> Self {
+ self.options.derive_hash = doit;
+ self
+ }
+ },
+ as_args: "--with-derive-hash",
+ },
+ /// Whether we should derive `PartialOrd` when possible.
+ derive_partialord: bool {
+ methods: {
+ /// Set whether the `PartialOrd` trait should be derived when possible.
+ ///
+ /// Take into account that `Ord` cannot be derived for a type that does not implement
+ /// `PartialOrd`. For this reason, setting this method to `false` also sets
+ /// automatically [`Builder::derive_ord`] to `false`.
+ ///
+ /// `PartialOrd` is not derived by default.
+ pub fn derive_partialord(mut self, doit: bool) -> Self {
+ self.options.derive_partialord = doit;
+ if !doit {
+ self.options.derive_ord = false;
+ }
+ self
+ }
+ },
+ as_args: "--with-derive-partialord",
+ },
+ /// Whether we should derive `Ord` when possible.
+ derive_ord: bool {
+ methods: {
+ /// Set whether the `Ord` trait should be derived when possible.
+ ///
+ /// Take into account that `Ord` cannot be derived for a type that does not implement
+ /// `PartialOrd`. For this reason, the value set with this method will also be set
+ /// automatically for [`Builder::derive_partialord`].
+ ///
+ /// `Ord` is not derived by default.
+ pub fn derive_ord(mut self, doit: bool) -> Self {
+ self.options.derive_ord = doit;
+ self.options.derive_partialord = doit;
+ self
+ }
+ },
+ as_args: "--with-derive-ord",
+ },
+ /// Whether we should derive `PartialEq` when possible.
+ derive_partialeq: bool {
+ methods: {
+ /// Set whether the `PartialEq` trait should be derived when possible.
+ ///
+ /// Take into account that `Eq` cannot be derived for a type that does not implement
+ /// `PartialEq`. For this reason, setting this method to `false` also sets
+ /// automatically [`Builder::derive_eq`] to `false`.
+ ///
+ /// The [`Builder::impl_partialeq`] method can be used to implement `PartialEq` for
+ /// types that cannot derive it.
+ ///
+ /// `PartialEq` is not derived by default.
+ pub fn derive_partialeq(mut self, doit: bool) -> Self {
+ self.options.derive_partialeq = doit;
+ if !doit {
+ self.options.derive_eq = false;
+ }
+ self
+ }
+ },
+ as_args: "--with-derive-partialeq",
+ },
+ /// Whether we should derive `Eq` when possible.
+ derive_eq: bool {
+ methods: {
+ /// Set whether the `Eq` trait should be derived when possible.
+ ///
+ /// Take into account that `Eq` cannot be derived for a type that does not implement
+ /// `PartialEq`. For this reason, the value set with this method will also be set
+ /// automatically for [`Builder::derive_partialeq`].
+ ///
+ /// `Eq` is not derived by default.
+ pub fn derive_eq(mut self, doit: bool) -> Self {
+ self.options.derive_eq = doit;
+ if doit {
+ self.options.derive_partialeq = doit;
+ }
+ self
+ }
+ },
+ as_args: "--with-derive-eq",
+ },
+ /// Whether we should use `core` instead of `std`.
+ ///
+ /// If this option is enabled and the Rust target version is greater than 1.64, the prefix for
+ /// C platform-specific types will be `::core::ffi` instead of `::core::os::raw`.
+ use_core: bool {
+ methods: {
+ /// Use `core` instead of `std` in the generated bindings.
+ ///
+ /// `std` is used by default.
+ pub fn use_core(mut self) -> Builder {
+ self.options.use_core = true;
+ self
+ }
+
+ },
+ as_args: "--use-core",
+ },
+ /// An optional prefix for the C platform-specific types.
+ ctypes_prefix: Option<String> {
+ methods: {
+ /// Use the given prefix for the C platform-specific types instead of `::std::os::raw`.
+ ///
+ /// Alternatively, the [`Builder::use_core`] method can be used to set the prefix to
+ /// `::core::ffi` or `::core::os::raw`.
+ pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder {
+ self.options.ctypes_prefix = Some(prefix.into());
+ self
+ }
+ },
+ as_args: "--ctypes-prefix",
+ },
+ /// The prefix for anonymous fields.
+ anon_fields_prefix: String {
+ default: DEFAULT_ANON_FIELDS_PREFIX.into(),
+ methods: {
+ /// Use the given prefix for the anonymous fields.
+ ///
+ /// An anonymous field, is a field of a C/C++ type that does not have a name. For
+ /// example, in the following C code:
+ /// ```c
+ /// struct integer {
+ /// struct {
+ /// int inner;
+ /// };
+ /// }
+ /// ```
+ ///
+ /// The only field of the `integer` `struct` is an anonymous field and its Rust
+ /// representation will be named using this prefix followed by an integer identifier.
+ ///
+ /// The default prefix is `__bindgen_anon_`.
+ pub fn anon_fields_prefix<T: Into<String>>(mut self, prefix: T) -> Builder {
+ self.options.anon_fields_prefix = prefix.into();
+ self
+ }
+ },
+ as_args: |prefix, args| {
+ if prefix != DEFAULT_ANON_FIELDS_PREFIX {
+ args.push("--anon-fields-prefix".to_owned());
+ args.push(prefix.clone());
+ }
+ },
+ },
+ /// Whether to measure the time for each one of the `bindgen` phases.
+ time_phases: bool {
+ methods: {
+ /// Set whether to measure the elapsed time for each one of the `bindgen` phases. This
+ /// information is printed to `stderr`.
+ ///
+ /// The elapsed time is not measured by default.
+ pub fn time_phases(mut self, doit: bool) -> Self {
+ self.options.time_phases = doit;
+ self
+ }
+ },
+ as_args: "--time-phases",
+ },
+ /// Whether to convert C float types to `f32` and `f64`.
+ convert_floats: bool {
+ default: true,
+ methods: {
+ /// Avoid converting C float types to `f32` and `f64`.
+ pub fn no_convert_floats(mut self) -> Self {
+ self.options.convert_floats = false;
+ self
+ }
+ },
+ as_args: |value, args| (!value).as_args(args, "--no-convert-floats"),
+ },
+ /// The set of raw lines to be prepended to the top-level module of the generated Rust code.
+ raw_lines: Vec<Box<str>> {
+ methods: {
+ /// Add a line of Rust code at the beginning of the generated bindings. The string is
+ /// passed through without any modification.
+ pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self {
+ self.options.raw_lines.push(arg.into().into_boxed_str());
+ self
+ }
+ },
+ as_args: |raw_lines, args| {
+ for line in raw_lines {
+ args.push("--raw-line".to_owned());
+ args.push(line.clone().into());
+ }
+ },
+ },
+ /// The set of raw lines to prepend to different modules.
+ module_lines: HashMap<Box<str>, Vec<Box<str>>> {
+ methods: {
+ /// Add a given line to the beginning of a given module.
+ ///
+ /// This option only comes into effect if the [`Builder::enable_cxx_namespaces`] method
+ /// is also being called.
+ pub fn module_raw_line<T, U>(mut self, module: T, line: U) -> Self
+ where
+ T: Into<String>,
+ U: Into<String>,
+ {
+ self.options
+ .module_lines
+ .entry(module.into().into_boxed_str())
+ .or_default()
+ .push(line.into().into_boxed_str());
+ self
+ }
+ },
+ as_args: |module_lines, args| {
+ for (module, lines) in module_lines {
+ for line in lines.iter() {
+ args.push("--module-raw-line".to_owned());
+ args.push(module.clone().into());
+ args.push(line.clone().into());
+ }
+ }
+ },
+ },
+ /// The input header files.
+ input_headers: Vec<Box<str>> {
+ methods: {
+ /// Add an input C/C++ header to generate bindings for.
+ ///
+ /// This can be used to generate bindings for a single header:
+ ///
+ /// ```ignore
+ /// let bindings = bindgen::Builder::default()
+ /// .header("input.h")
+ /// .generate()
+ /// .unwrap();
+ /// ```
+ ///
+ /// Or for multiple headers:
+ ///
+ /// ```ignore
+ /// let bindings = bindgen::Builder::default()
+ /// .header("first.h")
+ /// .header("second.h")
+ /// .header("third.h")
+ /// .generate()
+ /// .unwrap();
+ /// ```
+ pub fn header<T: Into<String>>(mut self, header: T) -> Builder {
+ self.options.input_headers.push(header.into().into_boxed_str());
+ self
+ }
+ },
+ // This field is handled specially inside the macro.
+ as_args: ignore,
+ },
+ /// The set of arguments to be passed straight through to Clang.
+ clang_args: Vec<Box<str>> {
+ methods: {
+ /// Add an argument to be passed straight through to Clang.
+ pub fn clang_arg<T: Into<String>>(self, arg: T) -> Builder {
+ self.clang_args([arg.into().into_boxed_str()])
+ }
+
+ /// Add several arguments to be passed straight through to Clang.
+ pub fn clang_args<I: IntoIterator>(mut self, args: I) -> Builder
+ where
+ I::Item: AsRef<str>,
+ {
+ for arg in args {
+ self.options.clang_args.push(arg.as_ref().to_owned().into_boxed_str());
+ }
+ self
+ }
+ },
+ // This field is handled specially inside the macro.
+ as_args: ignore,
+ },
+ /// Tuples of unsaved file contents of the form (name, contents).
+ input_header_contents: Vec<(Box<str>, Box<str>)> {
+ methods: {
+ /// Add `contents` as an input C/C++ header named `name`.
+ ///
+ /// This can be used to inject additional C/C++ code as an input without having to
+ /// create additional header files.
+ pub fn header_contents(mut self, name: &str, contents: &str) -> Builder {
+ // Apparently clang relies on having virtual FS correspondent to
+ // the real one, so we need absolute paths here
+ let absolute_path = env::current_dir()
+ .expect("Cannot retrieve current directory")
+ .join(name)
+ .to_str()
+ .expect("Cannot convert current directory name to string")
+ .into();
+ self.options
+ .input_header_contents
+ .push((absolute_path, contents.into()));
+ self
+ }
+ },
+ // Header contents cannot be added from the CLI.
+ as_args: ignore,
+ },
+ /// A user-provided visitor to allow customizing different kinds of situations.
+ parse_callbacks: Vec<Rc<dyn ParseCallbacks>> {
+ methods: {
+ /// Add a new [`ParseCallbacks`] instance to configure types in different situations.
+ pub fn parse_callbacks(mut self, cb: Box<dyn ParseCallbacks>) -> Self {
+ self.options.parse_callbacks.push(Rc::from(cb));
+ self
+ }
+ },
+ as_args: |_callbacks, _args| {
+ #[cfg(feature = "__cli")]
+ for cb in _callbacks {
+ _args.extend(cb.cli_args());
+ }
+ },
+ },
+ /// Which kind of items should we generate. We generate all of them by default.
+ codegen_config: CodegenConfig {
+ default: CodegenConfig::all(),
+ methods: {
+ /// Do not generate any functions.
+ ///
+ /// Functions are generated by default.
+ pub fn ignore_functions(mut self) -> Builder {
+ self.options.codegen_config.remove(CodegenConfig::FUNCTIONS);
+ self
+ }
+
+ /// Do not generate any methods.
+ ///
+ /// Methods are generated by default.
+ pub fn ignore_methods(mut self) -> Builder {
+ self.options.codegen_config.remove(CodegenConfig::METHODS);
+ self
+ }
+
+ /// Choose what to generate using a [`CodegenConfig`].
+ ///
+ /// This option overlaps with [`Builder::ignore_functions`] and
+ /// [`Builder::ignore_methods`].
+ ///
+ /// All the items in `CodegenConfig` are generated by default.
+ pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self {
+ self.options.codegen_config = config;
+ self
+ }
+ },
+ as_args: |codegen_config, args| {
+ if !codegen_config.functions() {
+ args.push("--ignore-functions".to_owned());
+ }
+
+ args.push("--generate".to_owned());
+
+ //Temporary placeholder for the 4 options below.
+ let mut options: Vec<String> = Vec::new();
+ if codegen_config.functions() {
+ options.push("functions".to_owned());
+ }
+
+ if codegen_config.types() {
+ options.push("types".to_owned());
+ }
+
+ if codegen_config.vars() {
+ options.push("vars".to_owned());
+ }
+
+ if codegen_config.methods() {
+ options.push("methods".to_owned());
+ }
+
+ if codegen_config.constructors() {
+ options.push("constructors".to_owned());
+ }
+
+ if codegen_config.destructors() {
+ options.push("destructors".to_owned());
+ }
+
+ args.push(options.join(","));
+
+ if !codegen_config.methods() {
+ args.push("--ignore-methods".to_owned());
+ }
+ },
+ },
+ /// Whether to treat inline namespaces conservatively.
+ conservative_inline_namespaces: bool {
+ methods: {
+ /// Treat inline namespaces conservatively.
+ ///
+ /// This is tricky, because in C++ is technically legal to override an item
+ /// defined in an inline namespace:
+ ///
+ /// ```cpp
+ /// inline namespace foo {
+ /// using Bar = int;
+ /// }
+ /// using Bar = long;
+ /// ```
+ ///
+ /// Even though referencing `Bar` is a compiler error.
+ ///
+ /// We want to support this (arguably esoteric) use case, but we do not want to make
+ /// the rest of `bindgen` users pay an usability penalty for that.
+ ///
+ /// To support this, we need to keep all the inline namespaces around, but then using
+ /// `bindgen` becomes a bit more difficult, because you cannot reference paths like
+ /// `std::string` (you'd need to use the proper inline namespace).
+ ///
+ /// We could complicate a lot of the logic to detect name collisions and, in the
+ /// absence of collisions, generate a `pub use inline_ns::*` or something like that.
+ ///
+ /// That is probably something we can do to improve the usability of this option if we
+ /// realize it is needed way more often. Our guess is that this extra logic is not
+ /// going to be very useful.
+ ///
+ /// This option is disabled by default.
+ pub fn conservative_inline_namespaces(mut self) -> Builder {
+ self.options.conservative_inline_namespaces = true;
+ self
+ }
+ },
+ as_args: "--conservative-inline-namespaces",
+ },
+ /// Whether to keep documentation comments in the generated output.
+ generate_comments: bool {
+ default: true,
+ methods: {
+ /// Set whether the generated bindings should contain documentation comments.
+ ///
+ /// Documentation comments are included by default.
+ ///
+ /// Note that clang excludes comments from system headers by default, pass
+ /// `"-fretain-comments-from-system-headers"` to the [`Builder::clang_arg`] method to
+ /// include them.
+ ///
+ /// It is also possible to process all comments and not just documentation using the
+ /// `"-fparse-all-comments"` flag. Check [these slides on clang comment parsing](
+ /// https://llvm.org/devmtg/2012-11/Gribenko_CommentParsing.pdf) for more information
+ /// and examples.
+ pub fn generate_comments(mut self, doit: bool) -> Self {
+ self.options.generate_comments = doit;
+ self
+ }
+ },
+ as_args: |value, args| (!value).as_args(args, "--no-doc-comments"),
+ },
+ /// Whether to generate inline functions.
+ generate_inline_functions: bool {
+ methods: {
+ /// Set whether to generate inline functions.
+ ///
+ /// This option is disabled by default.
+ ///
+ /// Note that they will usually not work. However you can use `-fkeep-inline-functions`
+ /// or `-fno-inline-functions` if you are responsible of compiling the library to make
+ /// them callable.
+ #[cfg_attr(
+ feature = "experimental",
+ doc = "\nCheck the [`Builder::wrap_static_fns`] method for an alternative."
+ )]
+ pub fn generate_inline_functions(mut self, doit: bool) -> Self {
+ self.options.generate_inline_functions = doit;
+ self
+ }
+ },
+ as_args: "--generate-inline-functions",
+ },
+ /// Whether to allowlist types recursively.
+ allowlist_recursively: bool {
+ default: true,
+ methods: {
+ /// Set whether to recursively allowlist items.
+ ///
+ /// Items are allowlisted recursively by default.
+ ///
+ /// Given that we have explicitly allowlisted the `initiate_dance_party` function in
+ /// this C header:
+ ///
+ /// ```c
+ /// typedef struct MoonBoots {
+ /// int bouncy_level;
+ /// } MoonBoots;
+ ///
+ /// void initiate_dance_party(MoonBoots* boots);
+ /// ```
+ ///
+ /// We would normally generate bindings to both the `initiate_dance_party` function and
+ /// the `MoonBoots` type that it transitively references. If `false` is passed to this
+ /// method, `bindgen` will not emit bindings for anything except the explicitly
+ /// allowlisted items, meaning that the definition for `MoonBoots` would not be
+ /// generated. However, the `initiate_dance_party` function would still reference
+ /// `MoonBoots`!
+ ///
+ /// **Disabling this feature will almost certainly cause `bindgen` to emit bindings
+ /// that will not compile!** If you disable this feature, then it is *your*
+ /// responsibility to provide definitions for every type that is referenced from an
+ /// explicitly allowlisted item. One way to provide the missing definitions is by using
+ /// the [`Builder::raw_line`] method, another would be to define them in Rust and then
+ /// `include!(...)` the bindings immediately afterwards.
+ pub fn allowlist_recursively(mut self, doit: bool) -> Self {
+ self.options.allowlist_recursively = doit;
+ self
+ }
+ },
+ as_args: |value, args| (!value).as_args(args, "--no-recursive-allowlist"),
+ },
+ /// Whether to emit `#[macro_use] extern crate objc;` instead of `use objc;` in the prologue of
+ /// the files generated from objective-c files.
+ objc_extern_crate: bool {
+ methods: {
+ /// Emit `#[macro_use] extern crate objc;` instead of `use objc;` in the prologue of
+ /// the files generated from objective-c files.
+ ///
+ /// `use objc;` is emitted by default.
+ pub fn objc_extern_crate(mut self, doit: bool) -> Self {
+ self.options.objc_extern_crate = doit;
+ self
+ }
+ },
+ as_args: "--objc-extern-crate",
+ },
+ /// Whether to generate proper block signatures instead of `void` pointers.
+ generate_block: bool {
+ methods: {
+ /// Generate proper block signatures instead of `void` pointers.
+ ///
+ /// `void` pointers are used by default.
+ pub fn generate_block(mut self, doit: bool) -> Self {
+ self.options.generate_block = doit;
+ self
+ }
+ },
+ as_args: "--generate-block",
+ },
+ /// Whether to generate strings as `CStr`.
+ generate_cstr: bool {
+ methods: {
+ /// Set whether string constants should be generated as `&CStr` instead of `&[u8]`.
+ ///
+ /// A minimum Rust target of 1.59 is required for this to have any effect as support
+ /// for `CStr::from_bytes_with_nul_unchecked` in `const` contexts is needed.
+ ///
+ /// This option is disabled by default but will become enabled by default in a future
+ /// release, so enabling this is recommended.
+ pub fn generate_cstr(mut self, doit: bool) -> Self {
+ self.options.generate_cstr = doit;
+ self
+ }
+ },
+ as_args: "--generate-cstr",
+ },
+ /// Whether to emit `#[macro_use] extern crate block;` instead of `use block;` in the prologue
+ /// of the files generated from apple block files.
+ block_extern_crate: bool {
+ methods: {
+ /// Emit `#[macro_use] extern crate block;` instead of `use block;` in the prologue of
+ /// the files generated from apple block files.
+ ///
+ /// `use block;` is emitted by default.
+ pub fn block_extern_crate(mut self, doit: bool) -> Self {
+ self.options.block_extern_crate = doit;
+ self
+ }
+ },
+ as_args: "--block-extern-crate",
+ },
+ /// Whether to use the clang-provided name mangling.
+ enable_mangling: bool {
+ default: true,
+ methods: {
+ /// Set whether to use the clang-provided name mangling. This is probably needed for
+ /// C++ features.
+ ///
+ /// The mangling provided by clang is used by default.
+ ///
+ /// We allow disabling this option because some old `libclang` versions seem to return
+ /// incorrect results in some cases for non-mangled functions, check [#528] for more
+ /// information.
+ ///
+ /// [#528]: https://github.com/rust-lang/rust-bindgen/issues/528
+ pub fn trust_clang_mangling(mut self, doit: bool) -> Self {
+ self.options.enable_mangling = doit;
+ self
+ }
+
+ },
+ as_args: |value, args| (!value).as_args(args, "--distrust-clang-mangling"),
+ },
+ /// Whether to detect include paths using `clang_sys`.
+ detect_include_paths: bool {
+ default: true,
+ methods: {
+ /// Set whether to detect include paths using `clang_sys`.
+ ///
+ /// `clang_sys` is used to detect include paths by default.
+ pub fn detect_include_paths(mut self, doit: bool) -> Self {
+ self.options.detect_include_paths = doit;
+ self
+ }
+ },
+ as_args: |value, args| (!value).as_args(args, "--no-include-path-detection"),
+ },
+ /// Whether we should try to fit macro constants into types smaller than `u32` and `i32`.
+ fit_macro_constants: bool {
+ methods: {
+ /// Set whether `bindgen` should try to fit macro constants into types smaller than `u32`
+ /// and `i32`.
+ ///
+ /// This option is disabled by default.
+ pub fn fit_macro_constants(mut self, doit: bool) -> Self {
+ self.options.fit_macro_constants = doit;
+ self
+ }
+ },
+ as_args: "--fit-macro-constant-types",
+ },
+ /// Whether to prepend the `enum` name to constant or newtype variants.
+ prepend_enum_name: bool {
+ default: true,
+ methods: {
+ /// Set whether to prepend the `enum` name to constant or newtype variants.
+ ///
+ /// The `enum` name is prepended by default.
+ pub fn prepend_enum_name(mut self, doit: bool) -> Self {
+ self.options.prepend_enum_name = doit;
+ self
+ }
+ },
+ as_args: |value, args| (!value).as_args(args, "--no-prepend-enum-name"),
+ },
+ /// Version of the Rust compiler to target.
+ rust_target: RustTarget {
+ methods: {
+ /// Specify the Rust target version.
+ ///
+ /// The default target is the latest stable Rust version.
+ pub fn rust_target(mut self, rust_target: RustTarget) -> Self {
+ self.options.set_rust_target(rust_target);
+ self
+ }
+ },
+ as_args: |rust_target, args| {
+ args.push("--rust-target".to_owned());
+ args.push(rust_target.to_string());
+ },
+ },
+ /// Features to be enabled. They are derived from `rust_target`.
+ rust_features: RustFeatures {
+ default: RustTarget::default().into(),
+ methods: {},
+ // This field cannot be set from the CLI,
+ as_args: ignore,
+ },
+ /// Enable support for native Rust unions if they are supported.
+ untagged_union: bool {
+ default: true,
+ methods: {
+ /// Disable support for native Rust unions, if supported.
+ ///
+ /// The default value of this option is set based on the value passed to
+ /// [`Builder::rust_target`].
+ pub fn disable_untagged_union(mut self) -> Self {
+ self.options.untagged_union = false;
+ self
+ }
+ }
+ as_args: |value, args| (!value).as_args(args, "--disable-untagged-union"),
+ },
+ /// Whether we should record which items in the regex sets did match any C items.
+ record_matches: bool {
+ default: true,
+ methods: {
+ /// Set whether we should record which items in our regex sets did match any C items.
+ ///
+ /// Matches are recorded by default.
+ pub fn record_matches(mut self, doit: bool) -> Self {
+ self.options.record_matches = doit;
+ self
+ }
+
+ },
+ as_args: |value, args| (!value).as_args(args, "--no-record-matches"),
+ },
+ /// Whether `size_t` should be translated to `usize` automatically.
+ size_t_is_usize: bool {
+ default: true,
+ methods: {
+ /// Set whether `size_t` should be translated to `usize`.
+ ///
+ /// If `size_t` is translated to `usize`, type definitions for `size_t` will not be
+ /// emitted.
+ ///
+ /// `size_t` is translated to `usize` by default.
+ pub fn size_t_is_usize(mut self, is: bool) -> Self {
+ self.options.size_t_is_usize = is;
+ self
+ }
+ },
+ as_args: |value, args| (!value).as_args(args, "--no-size_t-is-usize"),
+ },
+ /// The tool that should be used to format the generated bindings.
+ formatter: Formatter {
+ methods: {
+ /// Set whether `rustfmt` should be used to format the generated bindings.
+ ///
+ /// `rustfmt` is used by default.
+ ///
+ /// This method overlaps in functionality with the more general [`Builder::formatter`].
+ /// Thus, the latter should be preferred.
+ #[deprecated]
+ pub fn rustfmt_bindings(mut self, doit: bool) -> Self {
+ self.options.formatter = if doit {
+ Formatter::Rustfmt
+ } else {
+ Formatter::None
+ };
+ self
+ }
+
+ /// Set which tool should be used to format the generated bindings.
+ ///
+ /// The default formatter is [`Formatter::Rustfmt`].
+ ///
+ /// To be able to use `prettyplease` as a formatter, the `"prettyplease"` feature for
+ /// `bindgen` must be enabled in the Cargo manifest.
+ pub fn formatter(mut self, formatter: Formatter) -> Self {
+ self.options.formatter = formatter;
+ self
+ }
+ },
+ as_args: |formatter, args| {
+ if *formatter != Default::default() {
+ args.push("--formatter".to_owned());
+ args.push(formatter.to_string());
+ }
+ },
+ },
+ /// The absolute path to the `rustfmt` configuration file.
+ rustfmt_configuration_file: Option<PathBuf> {
+ methods: {
+ /// Set the absolute path to the `rustfmt` configuration file.
+ ///
+ /// The default `rustfmt` options are used if `None` is passed to this method or if
+ /// this method is not called at all.
+ ///
+ /// Calling this method will set the [`Builder::rustfmt_bindings`] option to `true`
+ /// and the [`Builder::formatter`] option to [`Formatter::Rustfmt`].
+ pub fn rustfmt_configuration_file(mut self, path: Option<PathBuf>) -> Self {
+ self = self.formatter(Formatter::Rustfmt);
+ self.options.rustfmt_configuration_file = path;
+ self
+ }
+ },
+ as_args: "--rustfmt-configuration-file",
+ },
+ /// Types that should not derive `PartialEq`.
+ no_partialeq_types: RegexSet {
+ methods: {
+ regex_option! {
+ /// Do not derive `PartialEq` for a given type.
+ pub fn no_partialeq<T: Into<String>>(mut self, arg: T) -> Builder {
+ self.options.no_partialeq_types.insert(arg.into());
+ self
+ }
+ }
+ },
+ as_args: "--no-partialeq",
+ },
+ /// Types that should not derive `Copy`.
+ no_copy_types: RegexSet {
+ methods: {
+ regex_option! {
+ /// Do not derive `Copy` and `Clone` for a given type.
+ pub fn no_copy<T: Into<String>>(mut self, arg: T) -> Self {
+ self.options.no_copy_types.insert(arg.into());
+ self
+ }
+ }
+ },
+ as_args: "--no-copy",
+ },
+ /// Types that should not derive `Debug`.
+ no_debug_types: RegexSet {
+ methods: {
+ regex_option! {
+ /// Do not derive `Debug` for a given type.
+ pub fn no_debug<T: Into<String>>(mut self, arg: T) -> Self {
+ self.options.no_debug_types.insert(arg.into());
+ self
+ }
+ }
+ },
+ as_args: "--no-debug",
+ },
+ /// Types that should not derive or implement `Default`.
+ no_default_types: RegexSet {
+ methods: {
+ regex_option! {
+ /// Do not derive or implement `Default` for a given type.
+ pub fn no_default<T: Into<String>>(mut self, arg: T) -> Self {
+ self.options.no_default_types.insert(arg.into());
+ self
+ }
+ }
+ },
+ as_args: "--no-default",
+ },
+ /// Types that should not derive `Hash`.
+ no_hash_types: RegexSet {
+ methods: {
+ regex_option! {
+ /// Do not derive `Hash` for a given type.
+ pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder {
+ self.options.no_hash_types.insert(arg.into());
+ self
+ }
+ }
+ },
+ as_args: "--no-hash",
+ },
+ /// Types that should be annotated with `#[must_use]`.
+ must_use_types: RegexSet {
+ methods: {
+ regex_option! {
+ /// Annotate the given type with the `#[must_use]` attribute.
+ pub fn must_use_type<T: Into<String>>(mut self, arg: T) -> Builder {
+ self.options.must_use_types.insert(arg.into());
+ self
+ }
+ }
+ },
+ as_args: "--must-use-type",
+ },
+ /// Whether C arrays should be regular pointers in rust or array pointers
+ array_pointers_in_arguments: bool {
+ methods: {
+ /// Translate arrays `T arr[size]` into array pointers `*mut [T; size]` instead of
+ /// translating them as `*mut T` which is the default.
+ ///
+ /// The same is done for `*const` pointers.
+ pub fn array_pointers_in_arguments(mut self, doit: bool) -> Self {
+ self.options.array_pointers_in_arguments = doit;
+ self
+ }
+
+ },
+ as_args: "--use-array-pointers-in-arguments",
+ },
+ /// The name of the `wasm_import_module`.
+ wasm_import_module_name: Option<String> {
+ methods: {
+ /// Adds the `#[link(wasm_import_module = import_name)]` attribute to all the `extern`
+ /// blocks generated by `bindgen`.
+ ///
+ /// This attribute is not added by default.
+ pub fn wasm_import_module_name<T: Into<String>>(
+ mut self,
+ import_name: T,
+ ) -> Self {
+ self.options.wasm_import_module_name = Some(import_name.into());
+ self
+ }
+ },
+ as_args: "--wasm-import-module-name",
+ },
+ /// The name of the dynamic library (if we are generating bindings for a shared library).
+ dynamic_library_name: Option<String> {
+ methods: {
+ /// Generate bindings for a shared library with the given name.
+ ///
+ /// This option is disabled by default.
+ pub fn dynamic_library_name<T: Into<String>>(
+ mut self,
+ dynamic_library_name: T,
+ ) -> Self {
+ self.options.dynamic_library_name = Some(dynamic_library_name.into());
+ self
+ }
+ },
+ as_args: "--dynamic-loading",
+ },
+ /// Whether to equire successful linkage for all routines in a shared library.
+ dynamic_link_require_all: bool {
+ methods: {
+ /// Set whether to require successful linkage for all routines in a shared library.
+ /// This allows us to optimize function calls by being able to safely assume function
+ /// pointers are valid.
+ ///
+ /// This option only comes into effect if the [`Builder::dynamic_library_name`] option
+ /// is set.
+ ///
+ /// This option is disabled by default.
+ pub fn dynamic_link_require_all(mut self, req: bool) -> Self {
+ self.options.dynamic_link_require_all = req;
+ self
+ }
+ },
+ as_args: "--dynamic-link-require-all",
+ },
+ /// Whether to only make generated bindings `pub` if the items would be publicly accessible by
+ /// C++.
+ respect_cxx_access_specs: bool {
+ methods: {
+ /// Set whether to respect the C++ access specifications.
+ ///
+ /// Passing `true` to this method will set the visibility of the generated Rust items
+ /// as `pub` only if the corresponding C++ items are publicly accessible instead of
+ /// marking all the items as public, which is the default.
+ pub fn respect_cxx_access_specs(mut self, doit: bool) -> Self {
+ self.options.respect_cxx_access_specs = doit;
+ self
+ }
+
+ },
+ as_args: "--respect-cxx-access-specs",
+ },
+ /// Whether to translate `enum` integer types to native Rust integer types.
+ translate_enum_integer_types: bool {
+ methods: {
+ /// Set whether to always translate `enum` integer types to native Rust integer types.
+ ///
+ /// Passing `true` to this method will result in `enum`s having types such as `u32` and
+ /// `i16` instead of `c_uint` and `c_short` which is the default. The `#[repr]` types
+ /// of Rust `enum`s are always translated to Rust integer types.
+ pub fn translate_enum_integer_types(mut self, doit: bool) -> Self {
+ self.options.translate_enum_integer_types = doit;
+ self
+ }
+ },
+ as_args: "--translate-enum-integer-types",
+ },
+ /// Whether to generate types with C style naming.
+ c_naming: bool {
+ methods: {
+ /// Set whether to generate types with C style naming.
+ ///
+ /// Passing `true` to this method will add prefixes to the generated type names. For
+ /// example, instead of a `struct` with name `A` we will generate a `struct` with
+ /// `struct_A`. Currently applies to `struct`s, `union`s, and `enum`s.
+ pub fn c_naming(mut self, doit: bool) -> Self {
+ self.options.c_naming = doit;
+ self
+ }
+ },
+ as_args: "--c-naming",
+ },
+ /// Wether to always emit explicit padding fields.
+ force_explicit_padding: bool {
+ methods: {
+ /// Set whether to always emit explicit padding fields.
+ ///
+ /// This option should be enabled if a `struct` needs to be serialized in its native
+ /// format (padding bytes and all). This could be required if such `struct` will be
+ /// written to a file or sent over the network, as anything reading the padding bytes
+ /// of a struct may cause undefined behavior.
+ ///
+ /// Padding fields are not emitted by default.
+ pub fn explicit_padding(mut self, doit: bool) -> Self {
+ self.options.force_explicit_padding = doit;
+ self
+ }
+ },
+ as_args: "--explicit-padding",
+ },
+ /// Whether to emit vtable functions.
+ vtable_generation: bool {
+ methods: {
+ /// Set whether to enable experimental support to generate virtual table functions.
+ ///
+ /// This option should mostly work, though some edge cases are likely to be broken.
+ ///
+ /// Virtual table generation is disabled by default.
+ pub fn vtable_generation(mut self, doit: bool) -> Self {
+ self.options.vtable_generation = doit;
+ self
+ }
+ },
+ as_args: "--vtable-generation",
+ },
+ /// Whether to sort the generated Rust items.
+ sort_semantically: bool {
+ methods: {
+ /// Set whether to sort the generated Rust items in a predefined manner.
+ ///
+ /// Items are not ordered by default.
+ pub fn sort_semantically(mut self, doit: bool) -> Self {
+ self.options.sort_semantically = doit;
+ self
+ }
+ },
+ as_args: "--sort-semantically",
+ },
+ /// Whether to deduplicate `extern` blocks.
+ merge_extern_blocks: bool {
+ methods: {
+ /// Merge all extern blocks under the same module into a single one.
+ ///
+ /// Extern blocks are not merged by default.
+ pub fn merge_extern_blocks(mut self, doit: bool) -> Self {
+ self.options.merge_extern_blocks = doit;
+ self
+ }
+ },
+ as_args: "--merge-extern-blocks",
+ },
+ /// Whether to wrap unsafe operations in unsafe blocks.
+ wrap_unsafe_ops: bool {
+ methods: {
+ /// Wrap all unsafe operations in unsafe blocks.
+ ///
+ /// Unsafe operations are not wrapped by default.
+ pub fn wrap_unsafe_ops(mut self, doit: bool) -> Self {
+ self.options.wrap_unsafe_ops = doit;
+ self
+ }
+ },
+ as_args: "--wrap-unsafe-ops",
+ },
+ /// Patterns for functions whose ABI should be overriden.
+ abi_overrides: HashMap<Abi, RegexSet> {
+ methods: {
+ regex_option! {
+ /// Override the ABI of a given function.
+ pub fn override_abi<T: Into<String>>(mut self, abi: Abi, arg: T) -> Self {
+ self.options
+ .abi_overrides
+ .entry(abi)
+ .or_default()
+ .insert(arg.into());
+ self
+ }
+ }
+ },
+ as_args: |overrides, args| {
+ for (abi, set) in overrides {
+ for item in set.get_items() {
+ args.push("--override-abi".to_owned());
+ args.push(format!("{}={}", item, abi));
+ }
+ }
+ },
+ },
+ /// Whether to generate wrappers for `static` functions.
+ wrap_static_fns: bool {
+ methods: {
+ #[cfg(feature = "experimental")]
+ /// Set whether to generate wrappers for `static`` functions.
+ ///
+ /// Passing `true` to this method will generate a C source file with non-`static`
+ /// functions that call the `static` functions found in the input headers and can be
+ /// called from Rust once the source file is compiled.
+ ///
+ /// The path of this source file can be set using the [`Builder::wrap_static_fns_path`]
+ /// method.
+ pub fn wrap_static_fns(mut self, doit: bool) -> Self {
+ self.options.wrap_static_fns = doit;
+ self
+ }
+ },
+ as_args: "--wrap-static-fns",
+ },
+ /// The suffix to be added to the function wrappers for `static` functions.
+ wrap_static_fns_suffix: Option<String> {
+ methods: {
+ #[cfg(feature = "experimental")]
+ /// Set the suffix added to the wrappers for `static` functions.
+ ///
+ /// This option only comes into effect if `true` is passed to the
+ /// [`Builder::wrap_static_fns`] method.
+ ///
+ /// The default suffix is `__extern`.
+ pub fn wrap_static_fns_suffix<T: AsRef<str>>(mut self, suffix: T) -> Self {
+ self.options.wrap_static_fns_suffix = Some(suffix.as_ref().to_owned());
+ self
+ }
+ },
+ as_args: "--wrap-static-fns-suffix",
+ },
+ /// The path of the file where the wrappers for `static` functions will be emitted.
+ wrap_static_fns_path: Option<PathBuf> {
+ methods: {
+ #[cfg(feature = "experimental")]
+ /// Set the path for the source code file that would be created if any wrapper
+ /// functions must be generated due to the presence of `static` functions.
+ ///
+ /// `bindgen` will automatically add the right extension to the header and source code
+ /// files.
+ ///
+ /// This option only comes into effect if `true` is passed to the
+ /// [`Builder::wrap_static_fns`] method.
+ ///
+ /// The default path is `temp_dir/bindgen/extern`, where `temp_dir` is the path
+ /// returned by [`std::env::temp_dir`] .
+ pub fn wrap_static_fns_path<T: AsRef<Path>>(mut self, path: T) -> Self {
+ self.options.wrap_static_fns_path = Some(path.as_ref().to_owned());
+ self
+ }
+ },
+ as_args: "--wrap-static-fns-path",
+ },
+ /// Default visibility of fields.
+ default_visibility: FieldVisibilityKind {
+ methods: {
+ /// Set the default visibility of fields, including bitfields and accessor methods for
+ /// bitfields.
+ ///
+ /// This option only comes into effect if the [`Builder::respect_cxx_access_specs`]
+ /// option is disabled.
+ pub fn default_visibility(
+ mut self,
+ visibility: FieldVisibilityKind,
+ ) -> Self {
+ self.options.default_visibility = visibility;
+ self
+ }
+ },
+ as_args: |visibility, args| {
+ if *visibility != Default::default() {
+ args.push("--default-visibility".to_owned());
+ args.push(visibility.to_string());
+ }
+ },
+ },
+ /// Whether to emit diagnostics or not.
+ emit_diagnostics: bool {
+ methods: {
+ #[cfg(feature = "experimental")]
+ /// Emit diagnostics.
+ ///
+ /// These diagnostics are emitted to `stderr` if you are using `bindgen-cli` or printed
+ /// using `cargo:warning=` if you are using `bindgen` as a `build-dependency`.
+ ///
+ /// Diagnostics are not emitted by default.
+ ///
+ /// The layout and contents of these diagnostic messages are not covered by versioning
+ /// and can change without notice.
+ pub fn emit_diagnostics(mut self) -> Self {
+ self.options.emit_diagnostics = true;
+ self
+ }
+ },
+ as_args: "--emit-diagnostics",
+ }
+}
diff --git a/third_party/rust/bindgen/parse.rs b/third_party/rust/bindgen/parse.rs
new file mode 100644
index 0000000000..d29b090fcb
--- /dev/null
+++ b/third_party/rust/bindgen/parse.rs
@@ -0,0 +1,41 @@
+//! Common traits and types related to parsing our IR from Clang cursors.
+#![deny(clippy::missing_docs_in_private_items)]
+
+use crate::clang;
+use crate::ir::context::{BindgenContext, ItemId};
+
+/// Not so much an error in the traditional sense, but a control flow message
+/// when walking over Clang's AST with a cursor.
+#[derive(Debug)]
+pub(crate) enum ParseError {
+ /// Recurse down the current AST node's children.
+ Recurse,
+ /// Continue on to the next sibling AST node, or back up to the parent's
+ /// siblings if we've exhausted all of this node's siblings (and so on).
+ Continue,
+}
+
+/// The result of parsing a Clang AST node.
+#[derive(Debug)]
+pub(crate) enum ParseResult<T> {
+ /// We've already resolved this item before, here is the extant `ItemId` for
+ /// it.
+ AlreadyResolved(ItemId),
+
+ /// This is a newly parsed item. If the cursor is `Some`, it points to the
+ /// AST node where the new `T` was declared.
+ New(T, Option<clang::Cursor>),
+}
+
+/// An intermediate representation "sub-item" (i.e. one of the types contained
+/// inside an `ItemKind` variant) that can be parsed from a Clang cursor.
+pub(crate) trait ClangSubItemParser: Sized {
+ /// Attempt to parse this type from the given cursor.
+ ///
+ /// The fact that is a reference guarantees it's held by the context, and
+ /// allow returning already existing types.
+ fn parse(
+ cursor: clang::Cursor,
+ context: &mut BindgenContext,
+ ) -> Result<ParseResult<Self>, ParseError>;
+}
diff --git a/third_party/rust/bindgen/regex_set.rs b/third_party/rust/bindgen/regex_set.rs
new file mode 100644
index 0000000000..b78424aae1
--- /dev/null
+++ b/third_party/rust/bindgen/regex_set.rs
@@ -0,0 +1,204 @@
+//! A type that represents the union of a set of regular expressions.
+#![deny(clippy::missing_docs_in_private_items)]
+
+use regex::RegexSet as RxSet;
+use std::cell::Cell;
+
+/// A dynamic set of regular expressions.
+#[derive(Clone, Debug, Default)]
+pub struct RegexSet {
+ items: Vec<Box<str>>,
+ /// Whether any of the items in the set was ever matched. The length of this
+ /// vector is exactly the length of `items`.
+ matched: Vec<Cell<bool>>,
+ set: Option<RxSet>,
+ /// Whether we should record matching items in the `matched` vector or not.
+ record_matches: bool,
+}
+
+impl RegexSet {
+ /// Create a new RegexSet
+ pub fn new() -> RegexSet {
+ RegexSet::default()
+ }
+
+ /// Is this set empty?
+ pub fn is_empty(&self) -> bool {
+ self.items.is_empty()
+ }
+
+ /// Insert a new regex into this set.
+ pub fn insert<S>(&mut self, string: S)
+ where
+ S: AsRef<str>,
+ {
+ self.items.push(string.as_ref().to_owned().into_boxed_str());
+ self.matched.push(Cell::new(false));
+ self.set = None;
+ }
+
+ /// Returns slice of String from its field 'items'
+ pub fn get_items(&self) -> &[Box<str>] {
+ &self.items
+ }
+
+ /// Returns an iterator over regexes in the set which didn't match any
+ /// strings yet.
+ pub fn unmatched_items(&self) -> impl Iterator<Item = &str> {
+ self.items.iter().enumerate().filter_map(move |(i, item)| {
+ if !self.record_matches || self.matched[i].get() {
+ return None;
+ }
+
+ Some(item.as_ref())
+ })
+ }
+
+ /// Construct a RegexSet from the set of entries we've accumulated.
+ ///
+ /// Must be called before calling `matches()`, or it will always return
+ /// false.
+ #[inline]
+ pub fn build(&mut self, record_matches: bool) {
+ self.build_inner(record_matches, None)
+ }
+
+ #[cfg(all(feature = "__cli", feature = "experimental"))]
+ /// Construct a RegexSet from the set of entries we've accumulated and emit diagnostics if the
+ /// name of the regex set is passed to it.
+ ///
+ /// Must be called before calling `matches()`, or it will always return
+ /// false.
+ #[inline]
+ pub fn build_with_diagnostics(
+ &mut self,
+ record_matches: bool,
+ name: Option<&'static str>,
+ ) {
+ self.build_inner(record_matches, name)
+ }
+
+ #[cfg(all(not(feature = "__cli"), feature = "experimental"))]
+ /// Construct a RegexSet from the set of entries we've accumulated and emit diagnostics if the
+ /// name of the regex set is passed to it.
+ ///
+ /// Must be called before calling `matches()`, or it will always return
+ /// false.
+ #[inline]
+ pub(crate) fn build_with_diagnostics(
+ &mut self,
+ record_matches: bool,
+ name: Option<&'static str>,
+ ) {
+ self.build_inner(record_matches, name)
+ }
+
+ fn build_inner(
+ &mut self,
+ record_matches: bool,
+ _name: Option<&'static str>,
+ ) {
+ let items = self.items.iter().map(|item| format!("^({})$", item));
+ self.record_matches = record_matches;
+ self.set = match RxSet::new(items) {
+ Ok(x) => Some(x),
+ Err(e) => {
+ warn!("Invalid regex in {:?}: {:?}", self.items, e);
+ #[cfg(feature = "experimental")]
+ if let Some(name) = _name {
+ invalid_regex_warning(self, e, name);
+ }
+ None
+ }
+ }
+ }
+
+ /// Does the given `string` match any of the regexes in this set?
+ pub fn matches<S>(&self, string: S) -> bool
+ where
+ S: AsRef<str>,
+ {
+ let s = string.as_ref();
+ let set = match self.set {
+ Some(ref set) => set,
+ None => return false,
+ };
+
+ if !self.record_matches {
+ return set.is_match(s);
+ }
+
+ let matches = set.matches(s);
+ if !matches.matched_any() {
+ return false;
+ }
+ for i in matches.iter() {
+ self.matched[i].set(true);
+ }
+
+ true
+ }
+}
+
+#[cfg(feature = "experimental")]
+fn invalid_regex_warning(
+ set: &RegexSet,
+ err: regex::Error,
+ name: &'static str,
+) {
+ use crate::diagnostics::{Diagnostic, Level, Slice};
+
+ let mut diagnostic = Diagnostic::default();
+
+ match err {
+ regex::Error::Syntax(string) => {
+ if string.starts_with("regex parse error:\n") {
+ let mut source = String::new();
+
+ let mut parsing_source = true;
+
+ for line in string.lines().skip(1) {
+ if parsing_source {
+ if line.starts_with(' ') {
+ source.push_str(line);
+ source.push('\n');
+ continue;
+ }
+ parsing_source = false;
+ }
+ let error = "error: ";
+ if line.starts_with(error) {
+ let (_, msg) = line.split_at(error.len());
+ diagnostic.add_annotation(msg.to_owned(), Level::Error);
+ } else {
+ diagnostic.add_annotation(line.to_owned(), Level::Info);
+ }
+ }
+ let mut slice = Slice::default();
+ slice.with_source(source);
+ diagnostic.add_slice(slice);
+
+ diagnostic.with_title(
+ "Error while parsing a regular expression.",
+ Level::Warn,
+ );
+ } else {
+ diagnostic.with_title(string, Level::Warn);
+ }
+ }
+ err => {
+ let err = err.to_string();
+ diagnostic.with_title(err, Level::Warn);
+ }
+ }
+
+ diagnostic.add_annotation(
+ format!("This regular expression was passed via `{}`.", name),
+ Level::Note,
+ );
+
+ if set.items.iter().any(|item| item.as_ref() == "*") {
+ diagnostic.add_annotation("Wildcard patterns \"*\" are no longer considered valid. Use \".*\" instead.", Level::Help);
+ }
+ diagnostic.display();
+}
diff --git a/third_party/rust/bindgen/time.rs b/third_party/rust/bindgen/time.rs
new file mode 100644
index 0000000000..c13a640c46
--- /dev/null
+++ b/third_party/rust/bindgen/time.rs
@@ -0,0 +1,52 @@
+use std::io::{self, Write};
+use std::time::{Duration, Instant};
+
+/// RAII timer to measure how long phases take.
+#[derive(Debug)]
+pub struct Timer<'a> {
+ output: bool,
+ name: &'a str,
+ start: Instant,
+}
+
+impl<'a> Timer<'a> {
+ /// Creates a Timer with the given name, and starts it. By default,
+ /// will print to stderr when it is `drop`'d
+ pub fn new(name: &'a str) -> Self {
+ Timer {
+ output: true,
+ name,
+ start: Instant::now(),
+ }
+ }
+
+ /// Sets whether or not the Timer will print a message
+ /// when it is dropped.
+ pub fn with_output(mut self, output: bool) -> Self {
+ self.output = output;
+ self
+ }
+
+ /// Returns the time elapsed since the timer's creation
+ pub fn elapsed(&self) -> Duration {
+ Instant::now() - self.start
+ }
+
+ fn print_elapsed(&mut self) {
+ if self.output {
+ let elapsed = self.elapsed();
+ let time = (elapsed.as_secs() as f64) * 1e3 +
+ (elapsed.subsec_nanos() as f64) / 1e6;
+ let stderr = io::stderr();
+ // Arbitrary output format, subject to change.
+ writeln!(stderr.lock(), " time: {:>9.3} ms.\t{}", time, self.name)
+ .expect("timer write should not fail");
+ }
+ }
+}
+
+impl<'a> Drop for Timer<'a> {
+ fn drop(&mut self) {
+ self.print_elapsed();
+ }
+}